|
2 | 2 | <link rel="stylesheet" href="css/app.css"> |
3 | 3 |
|
4 | 4 | <?php |
| 5 | +declare(strict_types=1); |
5 | 6 |
|
6 | | -//------------------------------------------------------------------------------ |
7 | | -// check if authenticated |
8 | | -// Be CAREFUL WHEN INCLUDING NEW PHP FILES |
9 | | -require_once $_SERVER['DOCUMENT_ROOT'] . '/php/server/db.php'; |
10 | | -require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/language/lang.php'; |
11 | | -require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php'; |
12 | | - |
13 | | -// capture the redirect to after log in query string if available |
14 | | -$redirectTo = 'devices.php'; // Default destination |
15 | | -if (!empty($_GET['next'])) { |
16 | | - $decoded = base64_decode($_GET['next']); |
17 | | - // Validate that it's a local path to prevent Open Redirect vulnerabilities |
18 | | - if (strpos($decoded, '/') === 0 && strpos($decoded, '//') !== 0) { |
19 | | - $redirectTo = $decoded; |
20 | | - } |
| 7 | +require_once $_SERVER['DOCUMENT_ROOT'].'/php/server/db.php'; |
| 8 | +require_once $_SERVER['DOCUMENT_ROOT'].'/php/templates/language/lang.php'; |
| 9 | +require_once $_SERVER['DOCUMENT_ROOT'].'/php/templates/security.php'; |
| 10 | + |
| 11 | +session_start(); |
| 12 | + |
| 13 | +const COOKIE_NAME = 'NetAlertX_SaveLogin'; |
| 14 | +const DEFAULT_REDIRECT = '/devices.php'; |
| 15 | + |
| 16 | +/* ===================================================== |
| 17 | + Helper Functions |
| 18 | +===================================================== */ |
| 19 | + |
| 20 | +function safe_redirect(string $path): void { |
| 21 | + header("Location: {$path}", true, 302); |
| 22 | + exit; |
21 | 23 | } |
22 | 24 |
|
23 | | -$CookieSaveLoginName = 'NetAlertX_SaveLogin'; |
| 25 | +function validate_local_path(?string $encoded): string { |
| 26 | + if (!$encoded) return DEFAULT_REDIRECT; |
24 | 27 |
|
25 | | -if ($nax_WebProtection != 'true') |
26 | | -{ |
| 28 | + $decoded = base64_decode($encoded, true); |
| 29 | + if ($decoded === false) return DEFAULT_REDIRECT; |
| 30 | + |
| 31 | + // strict local path check |
| 32 | + if (!preg_match('#^/[a-zA-Z0-9_\-/\.]*$#', $decoded)) { |
| 33 | + return DEFAULT_REDIRECT; |
| 34 | + } |
| 35 | + |
| 36 | + return $decoded; |
| 37 | +} |
| 38 | + |
| 39 | +function append_hash(string $url): string { |
27 | 40 | if (!empty($_POST['url_hash'])) { |
28 | | - $redirectTo .= $_POST['url_hash']; |
| 41 | + return $url . preg_replace('/[^#a-zA-Z0-9_\-]/', '', $_POST['url_hash']); |
29 | 42 | } |
30 | | - header("Location: $redirectTo"); |
31 | | - $_SESSION["login"] = 1; |
32 | | - exit; |
| 43 | + return $url; |
33 | 44 | } |
34 | 45 |
|
35 | | -// Logout |
36 | | -if (isset ($_GET["action"]) && $_GET["action"] == 'logout') |
37 | | -{ |
38 | | - setcookie($CookieSaveLoginName, '', time()+1); // reset cookie |
39 | | - $_SESSION["login"] = 0; |
40 | | - header('Location: index.php'); |
41 | | - exit; |
| 46 | +function is_authenticated(): bool { |
| 47 | + return isset($_SESSION['login']) && $_SESSION['login'] === 1; |
42 | 48 | } |
43 | 49 |
|
44 | | -// Password without Cookie check -> pass and set initial cookie |
45 | | -if (isset ($_POST["loginpassword"]) && $nax_Password === hash('sha256',$_POST["loginpassword"])) |
46 | | -{ |
47 | | - if (!empty($_POST['url_hash'])) { |
48 | | - $redirectTo .= $_POST['url_hash']; |
| 50 | +function login_user(): void { |
| 51 | + $_SESSION['login'] = 1; |
| 52 | + session_regenerate_id(true); |
| 53 | +} |
| 54 | + |
| 55 | +function logout_user(): void { |
| 56 | + $_SESSION = []; |
| 57 | + session_destroy(); |
| 58 | + |
| 59 | + setcookie(COOKIE_NAME,'',[ |
| 60 | + 'expires'=>time()-3600, |
| 61 | + 'path'=>'/', |
| 62 | + 'httponly'=>true, |
| 63 | + 'samesite'=>'Strict' |
| 64 | + ]); |
| 65 | +} |
| 66 | + |
| 67 | +/* ===================================================== |
| 68 | + Redirect Handling |
| 69 | +===================================================== */ |
| 70 | + |
| 71 | +$redirectTo = validate_local_path($_GET['next'] ?? null); |
| 72 | + |
| 73 | +/* ===================================================== |
| 74 | + Web Protection Disabled |
| 75 | +===================================================== */ |
| 76 | + |
| 77 | +if ($nax_WebProtection !== 'true') { |
| 78 | + login_user(); |
| 79 | + safe_redirect(append_hash($redirectTo)); |
| 80 | +} |
| 81 | + |
| 82 | +/* ===================================================== |
| 83 | + Logout |
| 84 | +===================================================== */ |
| 85 | + |
| 86 | +if (($_GET['action'] ?? '') === 'logout') { |
| 87 | + logout_user(); |
| 88 | + safe_redirect('/index.php'); |
| 89 | +} |
| 90 | + |
| 91 | +/* ===================================================== |
| 92 | + Login Attempt |
| 93 | +===================================================== */ |
| 94 | + |
| 95 | +if (!empty($_POST['loginpassword'])) { |
| 96 | + |
| 97 | + $incomingHash = hash('sha256', $_POST['loginpassword']); |
| 98 | + |
| 99 | + if (hash_equals($nax_Password, $incomingHash)) { |
| 100 | + |
| 101 | + login_user(); |
| 102 | + |
| 103 | + if (!empty($_POST['PWRemember'])) { |
| 104 | + $token = bin2hex(random_bytes(32)); |
| 105 | + |
| 106 | + $_SESSION['remember_token'] = hash('sha256',$token); |
| 107 | + |
| 108 | + setcookie(COOKIE_NAME,$token,[ |
| 109 | + 'expires'=>time()+604800, |
| 110 | + 'path'=>'/', |
| 111 | + 'secure'=>isset($_SERVER['HTTPS']), |
| 112 | + 'httponly'=>true, |
| 113 | + 'samesite'=>'Strict' |
| 114 | + ]); |
| 115 | + } |
| 116 | + |
| 117 | + safe_redirect(append_hash($redirectTo)); |
49 | 118 | } |
50 | | - header("Location: $redirectTo"); |
51 | | - $_SESSION["login"] = 1; |
52 | | - if (isset($_POST['PWRemember'])) {setcookie($CookieSaveLoginName, hash('sha256',$_POST["loginpassword"]), time()+604800);} |
53 | | - exit; |
54 | 119 | } |
55 | 120 |
|
56 | | -// active Session or valid cookie (cookie not extends) |
57 | | -if (( isset ($_SESSION["login"]) && ($_SESSION["login"] == 1)) || (isset ($_COOKIE[$CookieSaveLoginName]) && $nax_Password === $_COOKIE[$CookieSaveLoginName])) |
58 | | -{ |
59 | | - if (!empty($_POST['url_hash'])) { |
60 | | - $redirectTo .= $_POST['url_hash']; |
| 121 | +/* ===================================================== |
| 122 | + Remember Me Validation |
| 123 | +===================================================== */ |
| 124 | + |
| 125 | +if (!is_authenticated() && !empty($_COOKIE[COOKIE_NAME]) && !empty($_SESSION['remember_token'])) { |
| 126 | + |
| 127 | + if (hash_equals($_SESSION['remember_token'], hash('sha256',$_COOKIE[COOKIE_NAME]))) { |
| 128 | + login_user(); |
| 129 | + safe_redirect(append_hash($redirectTo)); |
61 | 130 | } |
62 | | - header("Location: $redirectTo"); |
63 | | - $_SESSION["login"] = 1; |
64 | | - if (isset($_POST['PWRemember'])) {setcookie($CookieSaveLoginName, hash('sha256',$_POST["loginpassword"]), time()+604800);} |
65 | | - exit; |
66 | 131 | } |
67 | 132 |
|
| 133 | +/* ===================================================== |
| 134 | + Already Logged In |
| 135 | +===================================================== */ |
| 136 | + |
| 137 | +if (is_authenticated()) { |
| 138 | + safe_redirect(append_hash($redirectTo)); |
| 139 | +} |
| 140 | + |
| 141 | +/* ===================================================== |
| 142 | + Login UI Variables |
| 143 | +===================================================== */ |
| 144 | + |
68 | 145 | $login_headline = lang('Login_Toggle_Info_headline'); |
69 | | -$login_info = lang('Login_Info'); |
70 | | -$login_mode = 'danger'; |
71 | | -$login_display_mode = 'display: block;'; |
72 | | -$login_icon = 'fa-info'; |
73 | | - |
74 | | -// no active session, cookie not checked |
75 | | -if (isset ($_SESSION["login"]) == FALSE || $_SESSION["login"] != 1) |
76 | | -{ |
77 | | - if ($nax_Password === '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92') |
78 | | - { |
| 146 | +$login_info = lang('Login_Info'); |
| 147 | +$login_mode = 'info'; |
| 148 | +$login_display_mode = 'display:none;'; |
| 149 | +$login_icon = 'fa-info'; |
| 150 | + |
| 151 | +if ($nax_Password === '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92') { |
79 | 152 | $login_info = lang('Login_Default_PWD'); |
80 | 153 | $login_mode = 'danger'; |
81 | | - $login_display_mode = 'display: block;'; |
| 154 | + $login_display_mode = 'display:block;'; |
82 | 155 | $login_headline = lang('Login_Toggle_Alert_headline'); |
83 | 156 | $login_icon = 'fa-ban'; |
84 | | - } |
85 | | - else |
86 | | - { |
87 | | - $login_mode = 'info'; |
88 | | - $login_display_mode = 'display: none;'; |
89 | | - $login_headline = lang('Login_Toggle_Info_headline'); |
90 | | - $login_icon = 'fa-info'; |
91 | | - } |
92 | 157 | } |
93 | | - |
94 | | -// ################################################## |
95 | | -// ## Login Processing end |
96 | | -// ################################################## |
97 | 158 | ?> |
98 | 159 |
|
99 | 160 | <!DOCTYPE html> |
|
0 commit comments