WebOrbiton
v1.0.0.0

StocketBase

92 lines · 2.8 KB
  1. <?php
  2. ​
  3. declare(strict_types=1);
  4. ​
  5. if (count(get_included_files()) === 1) {
  6. http_response_code(403);
  7. exit;
  8. }
  9. ​
  10. $accountId = (int) $currentUser['id'];
  11. $twoFactorEnabled = TwoFactor::isEnabled($currentUser);
  12. ​
  13. $confirmIdentity = static function () use ($currentUser, $accountId): ?string {
  14. $wait = LoginThrottle::secondsUntilAllowed('totp_manage', (string) $accountId);
  15. if ($wait > 0) {
  16. return LoginThrottle::message($wait);
  17. }
  18. ​
  19. $passwordValid = password_verify((string) ($_POST['password'] ?? ''), (string) $currentUser['password_hash']);
  20. if (!$passwordValid || !TwoFactor::verify($currentUser, (string) ($_POST['code'] ?? ''))) {
  21. LoginThrottle::recordFailure('totp_manage', (string) $accountId);
  22. return 'The password or the code is not correct.';
  23. }
  24. ​
  25. LoginThrottle::clear('totp_manage', (string) $accountId);
  26. ​
  27. return null;
  28. };
  29. ​
  30. if ($action === 'totp_begin') {
  31. if (!$twoFactorEnabled) {
  32. $_SESSION['totp_setup_secret'] = Totp::generateSecret();
  33. }
  34. ​
  35. return [null, 'success', true];
  36. }
  37. ​
  38. if ($action === 'totp_cancel') {
  39. unset($_SESSION['totp_setup_secret']);
  40. ​
  41. return [null, 'success', true];
  42. }
  43. ​
  44. if ($action === 'totp_confirm') {
  45. $secret = (string) ($_SESSION['totp_setup_secret'] ?? '');
  46. if ($twoFactorEnabled || $secret === '') {
  47. return ['Start the setup again.', 'error', false];
  48. }
  49. ​
  50. $wait = LoginThrottle::secondsUntilAllowed('totp_setup', (string) $accountId);
  51. if ($wait > 0) {
  52. return [LoginThrottle::message($wait), 'error', false];
  53. }
  54. ​
  55. $step = Totp::verify($secret, (string) ($_POST['code'] ?? ''), null);
  56. if ($step === null) {
  57. LoginThrottle::recordFailure('totp_setup', (string) $accountId);
  58. ​
  59. return ['That code is not valid. Check the time on your phone and try again.', 'error', false];
  60. }
  61. ​
  62. LoginThrottle::clear('totp_setup', (string) $accountId);
  63. $_SESSION['totp_new_codes'] = TwoFactor::enable($accountId, $secret, $step);
  64. unset($_SESSION['totp_setup_secret']);
  65. ActivityLog::record('security.2fa_enabled', 'account', $accountId);
  66. ​
  67. return [null, 'success', true];
  68. }
  69. ​
  70. if ($action === 'totp_disable' || $action === 'totp_regenerate') {
  71. if (!$twoFactorEnabled) {
  72. return ['Two-factor authentication is not enabled.', 'error', false];
  73. }
  74. ​
  75. $problem = $confirmIdentity();
  76. if ($problem !== null) {
  77. return [$problem, 'error', false];
  78. }
  79. ​
  80. if ($action === 'totp_disable') {
  81. TwoFactor::disable($accountId);
  82. ActivityLog::record('security.2fa_disabled', 'account', $accountId);
  83. } else {
  84. $_SESSION['totp_new_codes'] = TwoFactor::regenerateRecoveryCodes($accountId);
  85. ActivityLog::record('security.2fa_recovery_codes', 'account', $accountId);
  86. }
  87. ​
  88. return [null, 'success', true];
  89. }
  90. ​
  91. return ['Unknown action.', 'error', false];
  92. ​