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
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"]
19 require_once "../inc/common.php";
21 /* Get the base url */
22 $uri = $_SERVER['REQUEST_URI'];
23 $tok = split($uri, "/");
25 for ($i=0; isset($tok[$i]); $i++
)
27 if ($tok[$i] == "settings" && strstr($tok[$i +
1], "install.php"))
31 for($j=0; $j < $i; $j++
)
33 strcat($base_url,$tok[$j]);
34 strcat($base_url,"/");
39 if (!strlen($base_url))
41 define('BASE_URL', $base_url);
43 $writable = (is_writable("../config/")) ? true: false;
48 <div
class="media-body">
50 <meta name
="viewport" content
="width=device-width, initial-scale=1">
51 <meta name
="HandheldFriendly" content
="true">
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">
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
>
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">
68 <script src
="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity
="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin
="anonymous"></script
>
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
>
72 <script src
="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js" integrity
="sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt/6v9KI65qnm" crossorigin
="anonymous"></script
>
76 <body role
="document">
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
>
81 if (file_exists("../config/config.php"))
83 ?><br
><div
class="container"><?php Message
::Fail("You're already configured!"); ?>
85 <a
class="text-center btn btn-primary" href
="<?php echo BASE_URL; ?>">Take me home
!</a
>
90 elseif (isset($_POST) && !empty($_POST))
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;
100 $auth_method_name = "SQLDB";
103 $auth_method_name = "FileDB";
107 $am = new Plugin($auth_method);
110 Message
::Fail("Invalid parameters");
115 Message
::Fail("Couldn't load plugin \"$auth_method\": $am->error");
119 $config["base_url"] = BASE_URL
;
120 $config["plugins"] = Array("$auth_method");
121 if ($auth_method == "sql_db
")
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,
134 /* First, write only the config file */
137 if ($auth_method == "sql_db
")
139 sql_db::delete_tables();
140 if (!sql_db::create_tables())
141 Message::Fail("Could not create SQL tables
");
142 } else if ($auth_method == "file_db
")
144 file_db::delete_db();
148 "user_name
" => $opts->account_user,
149 "user_pass
" => $opts->account_password,
150 "fname
" => $opts->account_fname,
151 "lname
" => $opts->account_lname,
152 "user_bio
" => $opts->account_bio,
153 "email
" => $opts->account_email
156 create_new_user($user);
157 $lkup = new PanelUser($opts->account_user);
160 Message::Fail("Could not create user
");
163 $lkup->add_meta('role', 'Super-Admin');
165 /* Enable lookups on HIBP by default */
166 $config['hibp'] = true;
168 /* Now, write all the config (config.php + settings in DB) */
172 The configuration file has been written. Now, log in to the panel to proceed with the rest of the installation.<br><br>
173 <a class="text
-center btn btn
-primary
" href="<?php
echo BASE_URL
; ?>">Let's go!</a></div>
184 <?php if (!$writable) { ?>
185 <div id="page1
" class="container
">
187 The admin panel needs to be able to write the config file.<br>
188 Please run: <code>sudo chown <?php echo get_current_user(); ?> <?php echo UPATH; ?> -R</code><br>
189 And after that, refresh this webpage.<br><br>
190 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>.
198 <div id
="page3" class="container">
199 <h5
>Database Backend
</h5
>
201 Which database backend would you like to
use?
203 Please choose from the available options
:
204 <div
class="form-group">
205 <div
class="form-check">
206 <input
class="form-check-input" type
="radio" name
="auth_method" id
="file_db_radio" value
="file_db">
207 <label
class="form-check-label" for="file_db_radio">
208 File
-based
database (Uses local files
as a database
, no additional setup needed
)
211 <div
class="form-check">
212 <input
class="form-check-input" type
="radio" name
="auth_method" id
="sql_db_radio" value
="sql_db">
213 <label
class="form-check-label" for="sql_db_radio">
214 SQL
Database (Requires an SQL database
)
219 <div id
="sql_form" style
="display:none">
220 Please enter your SQL information
. <div id
="sql_instructions" class="ml-4 btn btn-sm btn-info">View instructions
</div
>
221 <div
class="form-group">
222 <label
for="sql_host">Hostname
or IP
</label
>
223 <input name
="sql_host" type
="text" class="revalidation-needed-sql form-control" id
="sql_host" aria
-describedby
="hostname_help" value
="127.0.0.1">
224 <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
>
226 <div
class="form-group">
227 <label
for="sql_db">Database name
</label
>
228 <input name
="sql_db" type
="text" class="revalidation-needed-sql form-control" id
="sql_db" aria
-describedby
="port_help">
229 <small id
="port_help" class="form-text text-muted">The name of the SQL database to write to
and read from
.</small
>
231 <div
class="form-group">
232 <label
for="sql_username">Username
</label
>
233 <input name
="sql_user" type
="text" class="revalidation-needed-sql form-control" id
="sql_user" aria
-describedby
="username_help" autocomplete
="new-password">
234 <small id
="username_help" class="form-text text-muted">The name of SQL user
</small
>
236 <div
class="form-group">
237 <label
for="sql_password">Password
</label
>
238 <input name
="sql_password" type
="password" class="revalidation-needed-sql form-control" id
="sql_password" autocomplete
="new-password">
240 <div
class="form-group">
241 <label
for="sql_table_prefix">Table prefix
</label
>
242 <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_">
243 <small id
="sql_table_prefix_help" class="form-text text-muted">The prefix
for table
names (leave blank
for none
)</small
>
246 <div
class="text-center">
247 <div id
="page3_next" class="btn btn-primary ml-3">Next
</div
>
248 <div id
="page3_test_connection" class="btn btn-primary ml-3" style
="display: none">Test connection
</div
>
251 <div id
="page4" class="container" >
252 <h5
>Create your account
</h5
>
254 You need an account
, let
's make one.<br><br>
255 <div class="form-group">
256 <label for="account_user" id="userlabel">Pick a username</label>
257 <input name="account_user" type="text" class="form-control" id="account_user" aria-describedby="username_help">
258 <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
>
260 <div
class="form-group">
261 <label
for="account_password" id
="passlabel">Password
</label
>
262 <input name
="account_password" type
="password" class="form-control" id
="account_password" aria
-describedby
="password_help">
263 <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
>
265 <div
class="form-group">
266 <label
for="account_password_conf" id
="passconflabel">Confirm password
</label
>
267 <input name
="account_password_conf" type
="password" class="form-control" id
="account_password_conf">
269 <div
class="form-group">
270 <label
for="account_email" id
="emaillabel">Email address
</label
>
271 <input name
="account_email" type
="text" class="form-control" id
="account_email" aria
-describedby
="email_help">
273 <div
class="form-group">
274 <label
for="account_fname" id
="fnamelabel">First name
</label
>
275 <input name
="account_fname" type
="text" class="form-control" id
="account_fname">
277 <div
class="form-group">
278 <label
for="account_lname" id
="lnamelabel">Last name
</label
>
279 <input name
="account_lname" type
="text" class="form-control" id
="account_lname">
281 <div
class="form-group">
282 <label
for="account_bio" id
="biolabel">Bio
</label
>
283 <textarea name
="account_bio" type
="text" class="form-control" id
="account_bio"></textarea
>
285 <div
class="text-center">
286 <div id
="page4_back" class="btn btn-secondary mr-3">Back
</div
>
287 <button id
="page4_next" type
="submit" class="btn btn-primary ml-3">Submit
</div
>
292 <!-- Database overwrite prompt
-->
293 <div
class="modal fade" id
="db_overwrite_modal" tabindex
="-1" role
="dialog" aria
-labelledby
="confirmModalCenterTitle" aria
-hidden
="true">
294 <div
class="modal-dialog modal-dialog-centered" role
="document">
295 <div
class="modal-content">
296 <div
class="modal-header">
297 <h5
class="modal-title" id
="myModalLabel">Database already contains data
</h5
>
298 <button type
="button" class="close" data
-dismiss
="modal" aria
-label
="Close">
299 <span aria
-hidden
="true">×
;</span
>
302 <div
class="modal-body">
303 The database already exists
and contains data
.
304 If you
continue then this existing data will be deleted
.
306 <div
class="modal-footer">
307 <button id
="CloseButton" type
="button" class="btn btn-secondary" data
-dismiss
="modal">Cancel
</button
>
308 <button id
="ProceedButton" type
="button" class="btn btn-danger" onclick
="nextstep();">Continue</button
>
315 <!-- Database error dialog
-->
316 <div
class="modal fade" id
="db_error_modal" tabindex
="-1" role
="dialog" aria
-labelledby
="confirmModalCenterTitle" aria
-hidden
="true">
317 <div
class="modal-dialog modal-dialog-centered" role
="document">
318 <div
class="modal-content">
319 <div
class="modal-header">
320 <h5
class="modal-title" id
="myModalLabel">Database server error
</h5
>
321 <button type
="button" class="close" data
-dismiss
="modal" aria
-label
="Close">
322 <span aria
-hidden
="true">×
;</span
>
325 <div
class="modal-body" id
="db_error_text">
326 Unable to connect to the database
.
328 <div
class="modal-footer">
329 <button id
="CloseButton" type
="button" class="btn btn-primary" data
-dismiss
="modal">Ok
</button
>
337 let BASE_URL
= '<?php echo BASE_URL; ?>';
338 let chmod_help
= document
.getElementById('chmod_help');
341 chmod_help
.addEventListener('click', e
=> {
342 window
.open("https://www.unrealircd.org/docs/UnrealIRCd_webpanel#Permissions");
345 let page3
= document
.getElementById('page3');
346 let page4
= document
.getElementById('page4');
348 let file_db_radio
= document
.getElementById('file_db_radio');
349 let sql_db_radio
= document
.getElementById('sql_db_radio');
350 let sql_form
= document
.getElementById('sql_form');
351 let sql_host
= document
.getElementById('sql_host');
352 let sql_db
= document
.getElementById('sql_db');
353 let sql_user
= document
.getElementById('sql_user');
354 let sql_pass
= document
.getElementById('sql_password');
355 let sql_test_conn
= document
.getElementById('page3_test_connection');
356 let page3_next
= document
.getElementById('page3_next');
358 let page4_back
= document
.getElementById('page4_back');
359 let page4_next
= document
.getElementById('page4_next');
361 page4
.style
.display
= 'none';
363 revalidate_sql
= document
.querySelectorAll('.revalidation-needed-sql');
364 for (let i
= 0; i
< revalidate_sql
.length
; i++
)
366 revalidate_sql
[i
].addEventListener('input', e
=> {
367 page3_next
.style
.display
= 'none';
368 sql_test_conn
.innerHTML
= 'Test connection';
369 sql_test_conn
.style
.display
= '';
370 sql_test_conn
.classList
.remove('disabled');
374 page3_next
.addEventListener('click', e
=> {
375 <?php
if (file_exists(UPATH
.'/data/database.php')) { ?>
376 $
('#db_overwrite_modal').modal();
380 page3
.style
.display
= 'none';
381 page4
.style
.display
= '';
384 file_db_radio
.addEventListener('click', e
=> {
385 if (file_db_radio
.checked
){
386 sql_form
.style
.display
= 'none';
387 sql_test_conn
.style
.display
= 'none';
388 page3_next
.style
.display
= '';
392 sql_db_radio
.addEventListener('click', e
=> {
393 if (!file_db_radio
.checked
){
394 sql_form
.style
.display
= '';
395 sql_test_conn
.style
.display
= '';
396 page3_next
.style
.display
= 'none';
400 sql_instructions
.addEventListener('click', e
=> {
401 window
.open("https://www.unrealircd.org/docs/UnrealIRCd_webpanel#SQL_Authentication");
404 sql_test_conn
.addEventListener('click', e
=> {
405 sql_test_conn
.classList
.add('disabled');
406 sql_test_conn
.innerHTML
= "Checking...";
407 fetch(BASE_URL +
'api/installation.php', {
409 headers
: {'Content-Type':'application/x-www-form-urlencoded'},
411 'host='+
encodeURIComponent(sql_host
.value
)+
412 '&database='+
encodeURIComponent(sql_db
.value
)+
413 '&user='+
encodeURIComponent(sql_user
.value
)+
414 '&password='+
encodeURIComponent(sql_pass
.value
)+
415 '&table_prefix='+
encodeURIComponent(sql_table_prefix
.value
)
417 .then(response
=> response
.json())
425 $
('#db_overwrite_modal').modal();
429 sql_test_conn
.innerHTML
= "Failed!";
430 $
('#db_error_text').html(data
.error
? data
.error
: 'An error occured while connecting to the DB server');
431 $
('#db_error_modal').modal();
432 setTimeout(function() {
433 sql_test_conn
.innerHTML
= "Test connection";
434 sql_test_conn
.classList
.remove('disabled');
439 sql_test_conn
.innerHTML
= "Failed!";
440 setTimeout(function() {
441 sql_test_conn
.innerHTML
= "Test connection";
442 sql_test_conn
.classList
.remove('disabled');
447 user_name_label
= document
.getElementById('userlabel');
448 user_name
= document
.getElementById('account_user');
449 user_pass_label
= document
.getElementById('passlabel');
450 user_pass
= document
.getElementById('account_password');
451 user_pass2_label
= document
.getElementById('passconflabel');
452 user_pass2
= document
.getElementById('account_password_conf');
453 user_email_label
= document
.getElementById('emaillabel');
454 user_email
= document
.getElementById('account_email');
455 user_fname
= document
.getElementById('account_fname');
456 user_lname
= document
.getElementById('account_lname');
457 user_bio
= document
.getElementById('account_bio');
459 page4_back
.addEventListener('click', e
=> {
460 page4
.style
.display
= 'none';
461 page3
.style
.display
= '';
464 page4_next
.addEventListener('click', e
=> {
466 /* Form validation */
467 let req_not_met
= ' <small style="color:red">Does not meet requirements</small>';
469 const regex_username
= /^
[a
-zA
-Z\d
]{3,}$
/;
470 if (!regex_username
.test(user_name
.value
))
472 user_name_label
.innerHTML
= 'Pick a username!' + req_not_met
;
475 user_name_label
.innerHTML
= 'Pick a username!';
477 let regex_pass
= /^
(?=.*[a
-z
])(?=.*[A
-Z
])(?=.*\d
)(?=.*[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]).{8,}$/;
478 if (!regex_pass
.test(user_pass
.value
))
480 user_pass_label
.innerHTML
= 'Password' + req_not_met
;
483 user_pass_label
.innerHTML
= 'Password';
485 if (user_pass2
.value
!== user_pass
.value
)
487 user_pass2_label
.innerHTML
= 'Confirm password <small style="color:red">Passwords do not match</small>';
490 user_pass2_label
.innerHTML
= 'Confirm password';
492 const regex_email
= /^
[^\s
@]+
@[^\s
@]+\
.[^\s
@]+$
/;
493 if (!regex_email
.test(user_email
.value
))
495 user_email_label
.innerHTML
= 'Email address' + req_not_met
;
499 user_email_label
.innerHTML
= 'Email address';
507 page4
.style
.display
= 'none';
512 $
('#db_overwrite_modal').modal('hide');
513 page3
.style
.display
= 'none';
514 page4
.style
.display
= '';
515 window
.scrollTo(0,0);