]> jfr.im git - irc/unrealircd/unrealircd-webpanel.git/blob - settings/install.php
Move some PHP files from ./ to ./inc: common, connection, header, footer
[irc/unrealircd/unrealircd-webpanel.git] / settings / install.php
1 <?php
2 /* Log the user out if it was logged in.
3 * This is mostly for devs running the install screen and
4 * fater succeeding the first screen suddenly being logged in
5 * with old credentials/uid weirdness.
6 * Code from example #1 at https://www.php.net/manual/en/function.session-destroy.php
7 */
8 session_start();
9 $_SESSION = Array();
10 if (ini_get("session.use_cookies")) {
11 $params = session_get_cookie_params();
12 setcookie(session_name(), '', time() - 42000,
13 $params["path"], $params["domain"],
14 $params["secure"], $params["httponly"]
15 );
16 }
17 session_destroy();
18
19 require_once "../inc/common.php";
20
21 /* Get the base url */
22 $uri = $_SERVER['REQUEST_URI'];
23 $tok = split($uri, "/");
24 $base_url = "";
25 for ($i=0; isset($tok[$i]); $i++)
26 {
27 if ($tok[$i] == "settings" && strstr($tok[$i + 1], "install.php"))
28 {
29 if ($i)
30 {
31 for($j=0; $j < $i; $j++)
32 {
33 strcat($base_url,$tok[$j]);
34 strcat($base_url,"/");
35 }
36 }
37 }
38 }
39 if (!strlen($base_url))
40 $base_url = "/";
41 define('BASE_URL', $base_url);
42
43 $writable = (is_writable("../config/")) ? true: false;
44 ?>
45 <!DOCTYPE html>
46 <head>
47 <div class="media">
48 <div class="media-body">
49
50 <meta name="viewport" content="width=device-width, initial-scale=1">
51 <meta name="HandheldFriendly" content="true">
52
53
54
55 <!-- Latest compiled and minified CSS -->
56 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
57
58 <!-- Font Awesome JS -->
59 <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>
60 <script defer src="https://use.fontawesome.com/releases/v6.2.1/js/fontawesome.js" integrity="sha384-6OIrr52G08NpOFSZdxxz1xdNSndlD4vdcf/q2myIUVO0VsqaGHJsB0RaBE01VTOY" crossorigin="anonymous"></script>
61
62 <!-- Font Awesome icons -->
63 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css">
64 <script src="../js/unrealircd-admin.js"></script>
65 <title>UnrealIRCd Panel</title>
66 <link rel="icon" type="image/x-icon" href="<?php echo get_config("base_url"); ?>img/favicon.ico">
67
68 <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
69 <!-- Popper.JS -->
70 <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>
71 <!-- Bootstrap JS -->
72 <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js" integrity="sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt/6v9KI65qnm" crossorigin="anonymous"></script>
73 </div></div>
74 </head>
75
76 <body role="document">
77
78 <div class="container mt-4"><div class="row justify-content-center"><img src="../img/unreal.jpg" width="35px" height="35px" style="margin-right: 15px"><h3>UnrealIRCd Admin Panel Configuration and Setup</h3></div></div>
79 <?php
80
81 if (file_exists("../config/config.php"))
82 {
83 ?><br><div class="container"><?php Message::Fail("You're already configured!"); ?>
84 <br>
85 <a class="text-center btn btn-primary" href="<?php echo BASE_URL; ?>">Take me home!</a>
86 </div>
87 <?php
88 return;
89 }
90 elseif (isset($_POST) && !empty($_POST))
91 {
92 ?><br><div class="container"><?php
93 $opts = (object)$_POST;
94 /* pre-load the appropriate auth plugin */
95 $auth_method = (isset($opts->auth_method)) ? $opts->auth_method : NULL;
96 $auth_method_name = NULL;
97 switch($auth_method)
98 {
99 case "sql_auth":
100 $auth_method_name = "SQLAuth";
101 break;
102 case "file_auth":
103 $auth_method_name = "FileAuth";
104 break;
105 }
106 if ($auth_method)
107 $am = new Plugin($auth_method);
108 else
109 {
110 Message::Fail("Invalid parameters");
111 return;
112 }
113 if ($am->error)
114 {
115 Message::Fail("Couldn't load plugin \"$auth_method\": $am->error");
116 return;
117 }
118
119 $config["base_url"] = BASE_URL;
120 $config["plugins"] = Array("$auth_method");
121 if ($auth_method == "sql_auth")
122 {
123 $config["mysql"] = [
124 "host" => $opts->sql_host,
125 "database" => $opts->sql_db,
126 "username" => $opts->sql_user,
127 "password" => $opts->sql_password,
128 "table_prefix" => $opts->sql_table_prefix,
129 ];
130 }
131
132 /* First, write only the config file */
133 write_config_file();
134
135 if ($auth_method == "sql_auth")
136 if (!sql_auth::create_tables())
137 Message::Fail("Could not create SQL tables");
138
139 $user = [
140 "user_name" => $opts->account_user,
141 "user_pass" => $opts->account_password,
142 "fname" => $opts->account_fname,
143 "lname" => $opts->account_lname,
144 "user_bio" => $opts->account_bio,
145 "email" => $opts->account_email
146 ];
147
148 create_new_user($user);
149 $lkup = new PanelUser($opts->account_user);
150 if (!$lkup->id)
151 {
152 Message::Fail("Could not create user");
153 return;
154 }
155 $lkup->add_permission(PERMISSION_MANAGE_USERS);
156
157 /* Now, write all the config (config.php + settings in DB) */
158 write_config();
159 ?>
160 <br>
161 The configuration file has been written. Now, log in to the panel to proceed with the rest of the installation.<br><br>
162 <a class="text-center btn btn-primary" href="<?php echo BASE_URL; ?>">Let's go!</a></div>
163 <?php
164 return;
165 }
166
167 ?>
168 <style>
169 table tr td {
170 font-style: italic;
171 }
172 </style>
173 <?php if (!$writable) { ?>
174 <div id="page1" class="container">
175 <br>
176 The admin panel needs to be able to write the config file.<br>
177 Please run: <code>sudo chown <?php echo get_current_user(); ?> <?php echo UPATH; ?> -R</code><br>
178 And after that, refresh this webpage.<br><br>
179 If you have any questions about this, read <a href="https://www.unrealircd.org/docs/UnrealIRCd_webpanel#Permissions" target="_blank">the installation manual on permissions</a>.
180 </div>
181 <?php
182 die;
183 } ?>
184
185 <!-- Form start -->
186 <form method="post">
187 <div id="page3" class="container">
188 <h5>Authentication Backend</h5>
189 <br>
190 Which authentication backend would you like to use?
191 <br><br>
192 Please choose from the available options:
193 <div class="form-group">
194 <div class="form-check">
195 <input class="form-check-input" type="radio" name="auth_method" id="file_auth_radio" value="file_auth">
196 <label class="form-check-label" for="file_auth_radio">
197 File-based Authentication (Uses local files as a database, no setup needed)
198 </label>
199 </div>
200 <div class="form-check">
201 <input class="form-check-input" type="radio" name="auth_method" id="sql_auth_radio" value="sql_auth">
202 <label class="form-check-label" for="sql_auth_radio">
203 SQL Authentication (Requires an SQL database)
204 </label>
205 </div>
206 </div>
207 <br>
208 <div id="sql_form" style="display:none">
209 Please enter your SQL information. <div id="sql_instructions" class="ml-4 btn btn-sm btn-info">View instructions</div>
210 <div class="form-group">
211 <label for="sql_host">Hostname or IP</label>
212 <input name="sql_host" type="text" class="revalidation-needed-sql form-control" id="sql_host" aria-describedby="hostname_help" value="127.0.0.1">
213 <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>
214 </div>
215 <div class="form-group">
216 <label for="sql_db">Database name</label>
217 <input name="sql_db" type="text" class="revalidation-needed-sql form-control" id="sql_db" aria-describedby="port_help">
218 <small id="port_help" class="form-text text-muted">The name of the SQL database to write to and read from.</small>
219 </div>
220 <div class="form-group">
221 <label for="sql_username">Username</label>
222 <input name="sql_user" type="text" class="revalidation-needed-sql form-control" id="sql_user" aria-describedby="username_help">
223 <small id="username_help" class="form-text text-muted">The name of SQL user</small>
224 </div>
225 <div class="form-group">
226 <label for="sql_password">Password</label>
227 <input name="sql_password" type="password" class="revalidation-needed-sql form-control" id="sql_password">
228 </div>
229 <div class="form-group">
230 <label for="sql_table_prefix">Table prefix</label>
231 <input name="sql_table_prefix" type="text" class="revalidation-needed-sql form-control" id="sql_table_prefix" aria-describedby="sql_table_prefix_help" value="unreal_">
232 <small id="sql_table_prefix_help" class="form-text text-muted">The prefix for table names (leave blank for none)</small>
233 </div>
234 </div>
235 <div class="text-center">
236 <div id="page3_next" class="btn btn-primary ml-3">Next</div>
237 <div id="page3_test_connection" class="btn btn-primary ml-3" style="display: none">Test connection</div>
238 </div>
239 </div>
240 <div id="page4" class="container" >
241 <h5>Create your account</h5>
242 <br>
243 You need an account, let's make one.<br><br>
244 <div class="form-group">
245 <label for="account_user" id="userlabel">Pick a username</label>
246 <input name="account_user" type="text" class="form-control" id="account_user" aria-describedby="username_help">
247 <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>
248 </div>
249 <div class="form-group">
250 <label for="account_password" id="passlabel">Password</label>
251 <input name="account_password" type="password" class="form-control" id="account_password" aria-describedby="password_help">
252 <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>
253 </div>
254 <div class="form-group">
255 <label for="account_password_conf" id="passconflabel">Confirm password</label>
256 <input name="account_password_conf" type="password" class="form-control" id="account_password_conf">
257 </div>
258 <div class="form-group">
259 <label for="account_email" id="emaillabel">Email address</label>
260 <input name="account_email" type="text" class="form-control" id="account_email" aria-describedby="email_help">
261 </div>
262 <div class="form-group">
263 <label for="account_fname" id="fnamelabel">First name</label>
264 <input name="account_fname" type="text" class="form-control" id="account_fname">
265 </div>
266 <div class="form-group">
267 <label for="account_lname" id="lnamelabel">Last name</label>
268 <input name="account_lname" type="text" class="form-control" id="account_lname">
269 </div>
270 <div class="form-group">
271 <label for="account_bio" id="biolabel">Bio</label>
272 <textarea name="account_bio" type="text" class="form-control" id="account_bio"></textarea>
273 </div>
274 <div class="text-center">
275 <div id="page4_back" class="btn btn-secondary mr-3">Back</div>
276 <button id="page4_next" type="submit" class="btn btn-primary ml-3">Submit</div>
277 </div>
278 </div>
279 </form>
280 <script>
281 let BASE_URL = '<?php echo BASE_URL; ?>';
282 let chmod_help = document.getElementById('chmod_help');
283
284 if (chmod_help)
285 chmod_help.addEventListener('click', e => {
286 window.open("https://www.unrealircd.org/docs/UnrealIRCd_webpanel#Permissions");
287 });
288
289 let page3 = document.getElementById('page3');
290 let page4 = document.getElementById('page4');
291
292 let file_auth_radio = document.getElementById('file_auth_radio');
293 let sql_auth_radio = document.getElementById('sql_auth_radio');
294 let sql_form = document.getElementById('sql_form');
295 let sql_host = document.getElementById('sql_host');
296 let sql_db = document.getElementById('sql_db');
297 let sql_user = document.getElementById('sql_user');
298 let sql_pass = document.getElementById('sql_password');
299 let sql_test_conn = document.getElementById('page3_test_connection');
300 let page3_next = document.getElementById('page3_next');
301
302 let page4_back = document.getElementById('page4_back');
303 let page4_next = document.getElementById('page4_next');
304
305 page4.style.display = 'none';
306
307 revalidate_sql = document.querySelectorAll('.revalidation-needed-sql');
308 for (let i = 0; i < revalidate_sql.length; i++)
309 {
310 revalidate_sql[i].addEventListener('input', e => {
311 page3_next.style.display = 'none';
312 sql_test_conn.innerHTML = 'Test connection';
313 sql_test_conn.style.display = '';
314 sql_test_conn.classList.remove('disabled');
315 });
316 }
317
318 page3_next.addEventListener('click', e => {
319 page3.style.display = 'none';
320 page4.style.display = '';
321 });
322
323 file_auth_radio.addEventListener('click', e => {
324 if (file_auth_radio.checked){
325 sql_form.style.display = 'none';
326 sql_test_conn.style.display = 'none';
327 page3_next.style.display = '';
328 }
329 });
330
331 sql_auth_radio.addEventListener('click', e => {
332 if (!file_auth_radio.checked){
333 sql_form.style.display = '';
334 sql_test_conn.style.display = '';
335 page3_next.style.display = 'none';
336 }
337 });
338
339 sql_instructions.addEventListener('click', e => {
340 window.open("https://www.unrealircd.org/docs/UnrealIRCd_webpanel#SQL_Authentication");
341 });
342
343 sql_test_conn.addEventListener('click', e => {
344 sql_test_conn.classList.add('disabled');
345 sql_test_conn.innerHTML = "Checking...";
346 fetch(BASE_URL + 'api/installation.php?method=sql&host='+sql_host.value+'&database='+sql_db.value+'&user='+sql_user.value+'&password='+sql_pass.value)
347 .then(response => response.json())
348 .then(data => {
349 if (data.success)
350 {
351 // do something with the JSON data
352 sql_test_conn.innerHTML = "Success!";
353 setTimeout(function() {
354 sql_test_conn.style.display = 'none';
355 page3_next.style.display = '';
356 }, 2000);
357 }
358 else
359 {
360 sql_test_conn.innerHTML = "Failed!";
361 setTimeout(function() {
362 sql_test_conn.innerHTML = "Test connection";
363 sql_test_conn.classList.remove('disabled');
364 }, 2000);
365 }
366 })
367 .catch(error => {
368 sql_test_conn.innerHTML = "Failed!";
369 setTimeout(function() {
370 sql_test_conn.innerHTML = "Test connection";
371 sql_test_conn.classList.remove('disabled');
372 }, 2000);
373 });
374 });
375
376 user_name_label = document.getElementById('userlabel');
377 user_name = document.getElementById('account_user');
378 user_pass_label = document.getElementById('passlabel');
379 user_pass = document.getElementById('account_password');
380 user_pass2_label = document.getElementById('passconflabel');
381 user_pass2 = document.getElementById('account_password_conf');
382 user_email_label = document.getElementById('emaillabel');
383 user_email = document.getElementById('account_email');
384 user_fname = document.getElementById('account_fname');
385 user_lname = document.getElementById('account_lname');
386 user_bio = document.getElementById('account_bio');
387
388 page4_back.addEventListener('click', e => {
389 page4.style.display = 'none';
390 page3.style.display = '';
391 });
392
393 page4_next.addEventListener('click', e => {
394
395 /* Form validation */
396 let req_not_met = ' <small style="color:red">Does not meet requirements</small>';
397 let errs = 0;
398 const regex_username = /^[a-zA-Z\d]{3,}$/;
399 if (!regex_username.test(user_name.value))
400 {
401 user_name_label.innerHTML = 'Pick a username!' + req_not_met;
402 errs++;
403 } else
404 user_name_label.innerHTML = 'Pick a username!';
405
406 let regex_pass = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]).{8,}$/;
407 if (!regex_pass.test(user_pass.value))
408 {
409 user_pass_label.innerHTML = 'Password' + req_not_met;
410 errs++;
411 } else
412 user_pass_label.innerHTML = 'Password';
413
414 if (user_pass2.value !== user_pass.value)
415 {
416 user_pass2_label.innerHTML = 'Confirm password <small style="color:red">Passwords do not match</small>';
417 errs++;
418 } else
419 user_pass2_label.innerHTML = 'Confirm password';
420
421 const regex_email = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
422 if (!regex_email.test(user_email.value))
423 {
424 user_email_label.innerHTML = 'Email address' + req_not_met;
425 errs++;
426 }
427 else
428 user_email_label.innerHTML = 'Email address';
429
430 if (errs)
431 {
432 e.preventDefault();
433 return false;
434 }
435
436 page4.style.display = 'none';
437 });
438 </script>