Single-sign-on and self-serve account management. https://netsyms.biz/apps/accounthub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.php 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. <?php
  2. /*
  3. * This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. */
  7. require_once __DIR__ . "/../required.php";
  8. if (empty($_GET['code']) || empty($_GET['redirect'])) {
  9. die("Bad request.");
  10. }
  11. // Delete old keys to keep the table small and tidy
  12. $database->delete("userloginkeys", ["expires[<]" => date("Y-m-d H:i:s")]);
  13. if (!$database->has("userloginkeys", ["AND" => ["key" => $_GET["code"]], "expires[>]" => date("Y-m-d H:i:s"), "uid" => null])) {
  14. header("Location: $_GET[redirect]");
  15. die("Invalid auth code.");
  16. }
  17. $APPINFO = $database->get("userloginkeys", ["appname", "appicon"], ["key" => $_GET["code"]]);
  18. $APPNAME = $APPINFO["appname"];
  19. $APPICON = $APPINFO["appicon"];
  20. if (empty($_SESSION['thisstep'])) {
  21. $_SESSION['thisstep'] = "username";
  22. }
  23. if (!empty($_GET['reset'])) {
  24. $_SESSION['thisstep'] = "username";
  25. $_SESSION['check'] = "";
  26. header("Location: ./?code=$_GET[code]&redirect=$_GET[redirect]");
  27. }
  28. $error = "";
  29. function sendUserBack($code, $url, $uid) {
  30. global $database;
  31. $_SESSION['check'] = null;
  32. $_SESSION['thisstep'] = null;
  33. $_SESSION['login_uid'] = null;
  34. $_SESSION['login_pwd'] = null;
  35. $database->update("userloginkeys", ["uid" => $uid], ["key" => $code]);
  36. Log::insert(LogType::LOGIN_OK, $uid);
  37. header("Location: $url");
  38. die("<a href=\"" . htmlspecialchars($url) . "\">Click here</a>");
  39. }
  40. if (!empty($_SESSION['check'])) {
  41. switch ($_SESSION['check']) {
  42. case "username":
  43. if (empty($_POST['username'])) {
  44. $_SESSION['thisstep'] = "username";
  45. break;
  46. }
  47. $user = User::byUsername($_POST['username']);
  48. if ($user->exists()) {
  49. $_SESSION['login_uid'] = $user->getUID();
  50. switch ($user->getStatus()->get()) {
  51. case AccountStatus::LOCKED_OR_DISABLED:
  52. $error = $Strings->get("account locked", false);
  53. break;
  54. case AccountStatus::TERMINATED:
  55. $error = $Strings->get("account terminated", false);
  56. break;
  57. case AccountStatus::ALERT_ON_ACCESS:
  58. $mail_resp = $user->sendAlertEmail();
  59. case AccountStatus::NORMAL:
  60. $_SESSION['thisstep'] = "password";
  61. break;
  62. case AccountStatus::CHANGE_PASSWORD:
  63. $_SESSION['thisstep'] = "change_password";
  64. break;
  65. }
  66. } else {
  67. $error = $Strings->get("Username not found.", false);
  68. Log::insert(LogType::LOGIN_FAILED, null, "Username: " . $user->getUsername());
  69. }
  70. break;
  71. case "password":
  72. if (empty($_POST['password'])) {
  73. $_SESSION['thisstep'] = "password";
  74. break;
  75. }
  76. if (empty($_SESSION['login_uid'])) {
  77. $_SESSION['thisstep'] = "username";
  78. break;
  79. }
  80. $user = new User($_SESSION['login_uid']);
  81. if ($user->checkPassword($_POST['password'])) {
  82. $_SESSION['login_pwd'] = true;
  83. if ($user->has2fa()) {
  84. $_SESSION['thisstep'] = "totp";
  85. } else {
  86. sendUserBack($_GET['code'], $_GET['redirect'], $_SESSION['login_uid']);
  87. }
  88. } else {
  89. $error = $Strings->get("Password incorrect.", false);
  90. if ($user->checkAppPassword($_POST['password'])) {
  91. $error = $Strings->get("App passwords are not allowed here.", false);
  92. }
  93. Log::insert(LogType::LOGIN_FAILED, $user);
  94. }
  95. break;
  96. case "change_password":
  97. if (empty($_POST['oldpassword']) || empty($_POST['newpassword']) || empty($_POST['newpassword2'])) {
  98. $_SESSION['thisstep'] = "change_password";
  99. $error = $Strings->get("Fill in all three boxes.", false);
  100. break;
  101. }
  102. $user = new User($_SESSION['login_uid']);
  103. try {
  104. $result = $user->changePassword($_POST['oldpassword'], $_POST['newpassword'], $_POST['newpassword2']);
  105. if ($result === TRUE) {
  106. if ($user->has2fa()) {
  107. $_SESSION['thisstep'] = "totp";
  108. } else {
  109. sendUserBack($_GET['code'], $_GET['redirect'], $_SESSION['login_uid']);
  110. }
  111. }
  112. } catch (PasswordMatchException $e) {
  113. $error = $Strings->get(MESSAGES["passwords_same"]["string"], false);
  114. } catch (PasswordMismatchException $e) {
  115. $error = $Strings->get(MESSAGES["new_password_mismatch"]["string"], false);
  116. } catch (IncorrectPasswordException $e) {
  117. $error = $Strings->get(MESSAGES["old_password_mismatch"]["string"], false);
  118. } catch (WeakPasswordException $e) {
  119. $error = $Strings->get(MESSAGES["weak_password"]["string"], false);
  120. }
  121. break;
  122. case "totp":
  123. if (empty($_POST['totp']) || empty($_SESSION['login_uid'])) {
  124. $_SESSION['thisstep'] = "username";
  125. break;
  126. }
  127. $user = new User($_SESSION['login_uid']);
  128. if ($user->check2fa($_POST['totp'])) {
  129. sendUserBack($_GET['code'], $_GET['redirect'], $_SESSION['login_uid']);
  130. } else {
  131. $error = $Strings->get("Code incorrect.", false);
  132. Log::insert(LogType::BAD_2FA, null, "Username: " . $user->getUsername());
  133. }
  134. break;
  135. }
  136. }
  137. include __DIR__ . "/parts/header.php";
  138. switch ($_SESSION['thisstep']) {
  139. case "username":
  140. require __DIR__ . "/parts/username.php";
  141. break;
  142. case "password":
  143. require __DIR__ . "/parts/password.php";
  144. break;
  145. case "change_password":
  146. require __DIR__ . "/parts/change_password.php";
  147. break;
  148. case "totp":
  149. require __DIR__ . "/parts/totp.php";
  150. break;
  151. }
  152. include __DIR__ . "/parts/footer.php";