]> jfr.im git - irc/unrealircd/unrealircd-webpanel.git/blob - settings/install.php
Add some form validation for user account
[irc/unrealircd/unrealircd-webpanel.git] / settings / install.php
1 <?php
2
3 require_once "../common.php";
4
5 $uri = $_SERVER['SCRIPT_FILENAME'];
6 define('BASE_URL', str_replace("settings/install.php","",$uri));
7
8 $writable = (is_writable("../config/")) ? true: false;
9 ?>
10 <!DOCTYPE html>
11 <head>
12 <div class="media">
13 <div class="media-body">
14
15 <meta name="viewport" content="width=device-width, initial-scale=1">
16 <meta name="HandheldFriendly" content="true">
17
18 <link href="<?php echo get_config("base_url"); ?>css/unrealircd-admin.css" rel="stylesheet">
19
20
21 <!-- Latest compiled and minified CSS -->
22 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
23
24 <!-- Font Awesome JS -->
25 <script defer src="https://use.fontawesome.com/releases/v6.2.1/js/solid.js" integrity="sha384-tzzSw1/Vo+0N5UhStP3bvwWPq+uvzCMfrN1fEFe+xBmv1C/AtVX5K0uZtmcHitFZ" crossorigin="anonymous"></script>
26 <script defer src="https://use.fontawesome.com/releases/v6.2.1/js/fontawesome.js" integrity="sha384-6OIrr52G08NpOFSZdxxz1xdNSndlD4vdcf/q2myIUVO0VsqaGHJsB0RaBE01VTOY" crossorigin="anonymous"></script>
27
28 <!-- Font Awesome icons -->
29 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css">
30 <script src="<?php echo get_config("base_url"); ?>js/unrealircd-admin.js"></script>
31 <title>UnrealIRCd Panel</title>
32 <link rel="icon" type="image/x-icon" href="<?php echo get_config("base_url"); ?>img/favicon.ico">
33
34 <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
35 <!-- Popper.JS -->
36 <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js" integrity="sha384-cs/chFZiN24E4KMATLdqdvsezGxaGsi4hLGOzlXwp5UZB1LY//20VyM2taTB4QvJ" crossorigin="anonymous"></script>
37 <!-- Bootstrap JS -->
38 <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js" integrity="sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt/6v9KI65qnm" crossorigin="anonymous"></script>
39 </div></div>
40 </head>
41
42 <body role="document">
43
44 <div class="container"><div class="row"><img src="../img/unreal.jpg" width="35px" height="35px" style="margin-right: 15px"><h3>UnrealIRCd Admin Panel Configuration and Setup</h3></div></div><?php
45
46 if (file_exists("../config/config.php"))
47 {
48 ?><br><div class="container">You're already configured!
49 <br>
50 <a class="text-center btn btn-primary" href="<?php echo BASE_URL; ?>">Take me home!</a>
51 </div>
52 <?php
53 return;
54 }
55
56 ?>
57 <div id="page1" class="container">
58 <br>
59 Welcome to the IRC admin panel setup page. This setup process will guide you through the necessary steps to configure your IRC uplink and choose your preferred authentication method.
60 <br><br>
61 The first page will ask you for your UnrealIRCd uplink credentials and will test them to ensure that the connection is successful. This step is crucial for the Admin Panel to function properly.
62 <br><br>
63 Next, you will be asked to choose your preferred authentication method between file-based and SQL. Depending on your choice, additional steps may be required. If you choose SQL, you will be given the option to set up the appropriate tables in the database.
64 <br><br>
65 After that, we'll take you through a short account creation process where you get to create your first account. Once you're setup and logged in, you'll be able to add more users and choose what they can do on your panel.
66 <br><br>
67 Finally, the last page will offer additional options that you can customize according to your preferences. Once you have completed all the necessary steps, your IRC admin panel will be fully configured and ready for use.
68 <br><br>
69 Should you wish to edit your config further, you will find it in the <code>config</code> directory called <code>config.php</code>
70 <br><br>
71 We recommend that you carefully read each page and fill in all the required information accurately to ensure a seamless setup process. Thank you for choosing UnrealIRCd Admin Panel, and we hope you find it useful for managing your server/network.
72 <br><br>
73
74 <div id="proceed_div" class="text-center"><?php echo ($writable)
75 ? '<div id="page1_proceed" class="btn btn-primary">Proceed</div>'
76 : 'Before we begin, you must let the shell user who owns the webpanel have permission to create files.<br>
77 <div id="chmod_help" class="btn btn-sm btn-info">Get info</div>'; ?>
78 </div>
79 </div>
80
81 <!-- Form start -->
82 <form>
83 <div id="page2" class="container">
84 <h5>RPC Uplink Information</h5>
85 <br>
86 First, let's get you linked with UnrealIRCd.
87 <br><br>
88 If you don't have your credentials, you will need to create them. This is done in your <code>unrealircd.conf</code> <div id="rpc_instructions" class="ml-4 btn btn-sm btn-info">View instructions</div>
89 <br><br>
90 <form>
91 <div class="form-group">
92 <label for="rpc_iphost">Hostname or IP</label>
93 <input name="rpc_iphost" type="text" class="revalidation-needed-rpc form-control" id="rpc_iphost" aria-describedby="hostname_help" placeholder="127.0.0.1">
94 <small id="hostname_help" class="form-text text-muted">The hostname or IP address of your UnrealIRCd server. You should use <code>127.0.0.1</code> for the same machine.</small>
95 </div>
96 <div class="form-group">
97 <label for="rpc_port">Server Port</label>
98 <input name="rpc_port" type="text" class="revalidation-needed-rpc form-control" id="rpc_port" aria-describedby="port_help" placeholder="8600">
99 <small id="port_help" class="form-text text-muted">The port which you designated for RPC connections in your <code>unrealircd.conf</code></small>
100 </div>
101 <div class="form-group form-check">
102 <input name="rpc_ssl" type="checkbox" class="revalidation-needed-rpc form-check-input" id="rpc_ssl">
103 <label class="form-check-label" for="rpc_ssl">My UnrealIRCd server is on a different machine, verify the TLS connection.</label>
104 </div>
105 <div class="form-group">
106 <label for="rpc_username">Username</label>
107 <input name="rpc_user" type="text" class="revalidation-needed-rpc form-control" id="rpc_user" aria-describedby="username_help" placeholder="apiuser">
108 <small id="username_help" class="form-text text-muted">The name of your <code>rpc-user</code> block as defined in your <code>unrealircd.conf</code></small>
109 </div>
110 <div class="form-group">
111 <label for="rpc_password">Password</label>
112 <input name="rpc_password" type="password" class="revalidation-needed-rpc form-control" id="rpc_password">
113 </div>
114 <div class="text-center">
115 <div id="page2_back" class="btn btn-secondary mr-3">Back</div>
116 <div id="page2_next" class="btn btn-primary ml-3" style="display: none">Next</div>
117 <div id="page2_test_connection" class="btn btn-primary ml-3">Test connection</div>
118 </div>
119 </div>
120
121
122 <div id="page3" class="container">
123 <h5>Authentication Method</h5>
124 <br>
125 Here's where you can choose which type of authentication mechanism you want to use behind the scenes.
126 <br><br>
127 Please choose from the available options:
128 <div class="form-group">
129 <div class="form-check">
130 <input class="form-check-input" type="radio" name="auth_method" id="file_auth_radio" value="file_auth">
131 <label class="form-check-label" for="file_auth_radio">
132 File-based Authentication (Uses local files as a database, no setup needed)
133 </label>
134 </div>
135 <div class="form-check">
136 <input class="form-check-input" type="radio" name="auth_method" id="sql_auth_radio" value="sql_auth">
137 <label class="form-check-label" for="sql_auth_radio">
138 SQL Authentication (Requires an SQL database)
139 </label>
140 </div>
141 </div>
142 <br>
143 <div id="sql_form" style="display:none">
144 Please enter your SQL information. <div id="sql_instructions" class="ml-4 btn btn-sm btn-info">View instructions</div>
145 <div class="form-group">
146 <label for="sql_iphost">Hostname or IP</label>
147 <input name="sql_iphost" type="text" class="revalidation-needed-sql form-control" id="sql_iphost" aria-describedby="hostname_help" placeholder="127.0.0.1">
148 <small id="hostname_help" class="form-text text-muted">The hostname or IP address of your SQL server. You should use <code>127.0.0.1</code> for the same machine.</small>
149 </div>
150 <div class="form-group">
151 <label for="sql_db">Database name</label>
152 <input name="sql_db" type="text" class="revalidation-needed-sql form-control" id="sql_db" aria-describedby="port_help">
153 <small id="port_help" class="form-text text-muted">The name of the SQL database to write to and read from.</small>
154 </div>
155 <div class="form-group">
156 <label for="sql_username">Username</label>
157 <input name="sql_user" type="text" class="revalidation-needed-sql form-control" id="sql_user" aria-describedby="username_help">
158 <small id="username_help" class="form-text text-muted">The name of SQL user</small>
159 </div>
160 <div class="form-group">
161 <label for="sql_password">Password</label>
162 <input name="sql_password" type="password" class="revalidation-needed-sql form-control" id="sql_password">
163 </div>
164 </div>
165 <div class="text-center">
166 <div id="page3_back" class="btn btn-secondary mr-3">Back</div>
167 <div id="page3_next" class="btn btn-primary ml-3">Next</div>
168 <div id="page3_test_connection" class="btn btn-primary ml-3" style="display: none">Test connection</div>
169 </div>
170 </div>
171 <div id="page4" class="container" >
172 <h5>Create your account</h5>
173 <br>
174 Great! Everything looks good so far! Just one last thing before we confirm everything and get you set up.<br>
175 You need an account! Let's make one.<br><br>
176 <div class="form-group">
177 <label for="account_user" id="userlabel">Pick a username</label>
178 <input name="account_user" type="text" class="form-control" id="account_user" aria-describedby="username_help">
179 <small id="username_help" class="form-text text-muted">Pick a username! Please make sure it's at least 3 characters long, contains no spaces, and is made of only letters and numbers.</small>
180 </div>
181 <div class="form-group">
182 <label for="account_password" id="passlabel">Password</label>
183 <input name="account_password" type="password" class="form-control" id="account_password" aria-describedby="password_help">
184 <small id="password_help" class="form-text text-muted">Please choose a password that at least 8 characters long, contains at least one uppercase letter, one lowercase letter, one number and one symbol.</small>
185 </div>
186 <div class="form-group">
187 <label for="account_password_conf" id="passconflabel">Confirm password</label>
188 <input name="account_password_conf" type="password" class="form-control" id="account_password_conf">
189 </div>
190 <div class="form-group">
191 <label for="account_email" id="emaillabel">Email address</label>
192 <input name="account_email" type="text" class="form-control" id="account_email" aria-describedby="email_help">
193 </div>
194 <div class="form-group">
195 <label for="account_fname" id="fnamelabel">First name</label>
196 <input name="account_fname" type="text" class="form-control" id="account_lname">
197 </div>
198 <div class="form-group">
199 <label for="account_lname" id="lnamelabel">Last name</label>
200 <input name="account_lname" type="text" class="form-control" id="account_lname">
201 </div>
202 <div class="form-group">
203 <label for="account_bio" id="biolabel">Bio</label>
204 <textarea name="account_bio" type="text" class="form-control" id="account_bio"></textarea>
205 </div>
206 <div class="text-center">
207 <div id="page4_back" class="btn btn-secondary mr-3">Back</div>
208 <div id="page4_next" class="btn btn-primary ml-3">Next</div>
209 </div>
210 </div>
211
212 <!-- Form end -->
213 </form>
214 <script>
215 let BASE_URL = '<?php echo BASE_URL; ?>';
216 let chmod_help = document.getElementById('chmod_help');
217
218 if (chmod_help)
219 chmod_help.addEventListener('click', e => {
220 window.open("https://www.unrealircd.org/docs/UnrealIRCd_webpanel#Permissions");
221 });
222
223 let page1 = document.getElementById('page1');
224 let page2 = document.getElementById('page2');
225 let page3 = document.getElementById('page3');
226 let rpc_instructions = document.getElementById('rpc_instructions');
227 let setup_start = document.getElementById('page1_proceed');
228
229 let rpc_host = document.getElementById('rpc_iphost');
230 let rpc_port = document.getElementById('rpc_port');
231 let rpc_user = document.getElementById('rpc_user');
232 let rpc_pass = document.getElementById('rpc_password');
233 let rpc_tls = document.getElementById('rpc_ssl');
234
235 let page2_back = document.getElementById('page2_back');
236 let page2_next = document.getElementById('page2_next');
237 let test_conn = document.getElementById('page2_test_connection');
238
239 let file_auth_radio = document.getElementById('file_auth_radio');
240 let sql_auth_radio = document.getElementById('sql_auth_radio');
241 let sql_form = document.getElementById('sql_form');
242 let sql_host = document.getElementById('sql_iphost');
243 let sql_db = document.getElementById('sql_db');
244 let sql_user = document.getElementById('sql_user');
245 let sql_pass = document.getElementById('sql_password');
246 let sql_test_conn = document.getElementById('page3_test_connection');
247 let page3_back = document.getElementById('page3_back');
248 let page3_next = document.getElementById('page3_next');
249
250
251
252 let page4_back = document.getElementById('page4_back');
253 let page4_next = document.getElementById('page4_next');
254
255 page2.style.display = 'none';
256 page3.style.display = 'none';
257
258 rpc_instructions.addEventListener('click', e => {
259 window.open("https://www.unrealircd.org/docs/UnrealIRCd_webpanel#Configuring_UnrealIRCd");
260 });
261
262 setup_start.addEventListener('click', e => {
263 page1.style.display = 'none';
264 page2.style.display = '';
265 });
266
267 page2_back.addEventListener('click', e => {
268 page2.style.display = 'none';
269 page1.style.display = '';
270 });
271 page2_next.addEventListener('click', e => {
272 page2.style.display = 'none';
273 page3.style.display = '';
274 sql_form.style.display = 'none';
275 });
276
277 revalidate_rpc = document.querySelectorAll('.revalidation-needed-rpc');
278 for (let i = 0; i < revalidate_rpc.length; i++)
279 {
280 revalidate_rpc[i].addEventListener('input', e => {
281 page2_next.style.display = 'none';
282 test_conn.innerHTML = 'Test connection';
283 test_conn.style.display = '';
284 test_conn.classList.remove('disabled');
285 });
286 }
287 revalidate_sql = document.querySelectorAll('.revalidation-needed-sql');
288 for (let i = 0; i < revalidate_sql.length; i++)
289 {
290 revalidate_sql[i].addEventListener('input', e => {
291 page3_next.style.display = 'none';
292 sql_test_conn.innerHTML = 'Test connection';
293 sql_test_conn.style.display = '';
294 sql_test_conn.classList.remove('disabled');
295 });
296 }
297 /* The RPC connection tester! */
298 test_conn.addEventListener('click', e => {
299 test_conn.classList.add('disabled');
300 test_conn.innerHTML = "Checking...";
301 fetch(BASE_URL + 'api/installation.php?method=rpc&host='+rpc_host.value+'&port='+rpc_port.value+'&user='+rpc_user.value+'&password='+rpc_pass.value+'&tls_verify='+rpc_tls.checked)
302 .then(response => response.json())
303 .then(data => {
304 if (data.success)
305 {
306 // do something with the JSON data
307 test_conn.innerHTML = "Success!";
308 setTimeout(function() {
309 test_conn.style.display = 'none';
310 page2_next.style.display = '';
311 }, 2000);
312 }
313 else
314 {
315 test_conn.innerHTML = "Failed!";
316 setTimeout(function() {
317 test_conn.innerHTML = "Test connection";
318 test_conn.classList.remove('disabled');
319 }, 2000);
320 }
321 })
322 .catch(error => {
323 test_conn.innerHTML = "Failed!";
324 setTimeout(function() {
325 test_conn.innerHTML = "Test connection";
326 test_conn.classList.remove('disabled');
327 }, 2000);
328 });
329 });
330
331
332 page3_back.addEventListener('click', e => {
333 page3.style.display = 'none';
334 page2.style.display = '';
335 });
336 page3_next.addEventListener('click', e => {
337 page3.style.display = 'none';
338 page4.style.display = '';
339 });
340
341 file_auth_radio.addEventListener('click', e => {
342 if (file_auth_radio.checked){
343 sql_form.style.display = 'none';
344 sql_test_conn.style.display = 'none';
345 page3_next.style.display = '';
346 }
347 });
348 sql_auth_radio.addEventListener('click', e => {
349 if (!file_auth_radio.checked){
350 sql_form.style.display = '';
351 sql_test_conn.style.display = '';
352 page3_next.style.display = 'none';
353 }
354 });
355
356 sql_instructions.addEventListener('click', e => {
357 window.open("https://www.unrealircd.org/docs/UnrealIRCd_webpanel#SQL_Authentication");
358 });
359
360 sql_test_conn.addEventListener('click', e => {
361 sql_test_conn.classList.add('disabled');
362 sql_test_conn.innerHTML = "Checking...";
363 fetch(BASE_URL + 'api/installation.php?method=sql&host='+sql_host.value+'&database='+sql_db.value+'&user='+sql_user.value+'&password='+sql_pass.value)
364 .then(response => response.json())
365 .then(data => {
366 if (data.success)
367 {
368 // do something with the JSON data
369 sql_test_conn.innerHTML = "Success!";
370 setTimeout(function() {
371 sql_test_conn.style.display = 'none';
372 page3_next.style.display = '';
373 }, 2000);
374 }
375 else
376 {
377 sql_test_conn.innerHTML = "Failed!";
378 setTimeout(function() {
379 sql_test_conn.innerHTML = "Test connection";
380 sql_test_conn.classList.remove('disabled');
381 }, 2000);
382 }
383 })
384 .catch(error => {
385 sql_test_conn.innerHTML = "Failed!";
386 setTimeout(function() {
387 sql_test_conn.innerHTML = "Test connection";
388 sql_test_conn.classList.remove('disabled');
389 }, 2000);
390 });
391 });
392
393 user_name_label = document.getElementById('userlabel');
394 user_name = document.getElementById('account_user');
395 user_pass_label = document.getElementById('passlabel');
396 user_pass = document.getElementById('account_password');
397 user_pass2_label = document.getElementById('passconflabel');
398 user_pass2 = document.getElementById('account_password_conf');
399 user_email_label = document.getElementById('emaillabel');
400 user_email = document.getElementById('account_email');
401
402 page4_back.addEventListener('click', e => {
403 page4.style.display = 'none';
404 page3.style.display = '';
405 });
406
407 page4_next.addEventListener('click', e => {
408
409 /* Form validation */
410 let req_not_met = ' <small style="color:red">Does not meet requirements</small>';
411 let errs = 0;
412 const regex_username = /^[a-zA-Z\d]{3,}$/;
413 if (!regex_username.test(user_name.value))
414 {
415 user_name_label.innerHTML = 'Pick a username!' + req_not_met;
416 errs++;
417 } else
418 user_name_label.innerHTML = 'Pick a username!';
419
420 let regex_pass = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]).{8,}$/;
421 if (!regex_pass.test(user_pass.value))
422 {
423 user_pass_label.innerHTML = 'Password' + req_not_met;
424 errs++;
425 } else
426 user_pass_label.innerHTML = 'Password';
427
428 if (user_pass2.value !== user_pass.value)
429 {
430 user_pass2_label.innerHTML = 'Confirm password <small style="color:red">Passwords do not match</small>';
431 errs++;
432 } else
433 user_pass2_label.innerHTML = 'Confirm password';
434
435 const regex_email = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
436 console.log(user_email.value);
437 if (!regex_email.test(user_email.value))
438 {
439 user_email_label.innerHTML = 'Email address' + req_not_met;
440 errs++;
441 }
442 else
443 user_email_label.innerHTML = 'Email address';
444
445 if (errs)
446 return;
447
448
449 page4.style.display = 'none';
450 page5.style.display = '';
451 });
452
453
454
455 </script>