From 505975e56520edad15c23a2628a250a73015c34c Mon Sep 17 00:00:00 2001 From: danpros Date: Fri, 24 May 2024 10:12:33 +0700 Subject: [PATCH] Improve MFA integration Cleanup the code. Add password validation and error messages. --- system/admin/admin.php | 5 +- system/admin/views/edit-mfa.html.php | 89 ++++++------ system/htmly.php | 204 +++++++++++++++------------ system/includes/functions.php | 12 +- 4 files changed, 169 insertions(+), 141 deletions(-) diff --git a/system/admin/admin.php b/system/admin/admin.php index 8e7e255..3056d64 100644 --- a/system/admin/admin.php +++ b/system/admin/admin.php @@ -40,7 +40,7 @@ function create_user($userName, $password, $role) file_put_contents($file, "password = " . password_hash($password, PASSWORD_DEFAULT) . "\n" . "encryption = password_hash\n" . "role = " . $role . "\n" . - "mfa_secret = none\n", LOCK_EX); + "mfa_secret = disabled\n", LOCK_EX); return true; } } @@ -56,6 +56,7 @@ function session($user, $pass) $user_enc = user('encryption', $user); $user_pass = user('password', $user); $user_role = user('role', $user); + $mfa = user('mfa_secret', $user); if(is_null($user_enc) || is_null($user_pass) || is_null($user_role)) { return $str = '
'; @@ -65,7 +66,6 @@ function session($user, $pass) if (password_verify($pass, $user_pass)) { if (session_status() == PHP_SESSION_NONE) session_start(); if (password_needs_rehash($user_pass, PASSWORD_DEFAULT)) { - $mfa = user('mfa_secret', $user); update_user($user, $pass, $user_role, $mfa); } $_SESSION[site_url()]['user'] = $user; @@ -75,7 +75,6 @@ function session($user, $pass) } } else if (old_password_verify($pass, $user_enc, $user_pass)) { if (session_status() == PHP_SESSION_NONE) session_start(); - $mfa = user('mfa_secret', $user); update_user($user, $pass, $user_role, $mfa); $_SESSION[site_url()]['user'] = $user; header('location: admin'); diff --git a/system/admin/views/edit-mfa.html.php b/system/admin/views/edit-mfa.html.php index 343eca4..b9d0d71 100644 --- a/system/admin/views/edit-mfa.html.php +++ b/system/admin/views/edit-mfa.html.php @@ -4,56 +4,61 @@ if (isset($_SESSION[site_url()]['user'])) { $user = $_SESSION[site_url()]['user']; } - use PragmaRX\Google2FA\Google2FA; - use BaconQrCode\Renderer\GDLibRenderer; - use BaconQrCode\Writer; +use PragmaRX\Google2FA\Google2FA; +use BaconQrCode\Renderer\GDLibRenderer; +use BaconQrCode\Writer; -if (user('mfa_secret', $user) == 'disabled') { - $google2fa = new Google2FA(); - $mfasecret = $google2fa->generateSecretKey(); +$mfa_state = user('mfa_secret', $user); - $g2faUrl = $google2fa->getQRCodeUrl( - $user, - site_url(), - $mfasecret - ); +if (is_null($mfa_state) || $mfa_state == 'disabled') { + $google2fa = new Google2FA(); + $mfasecret = $google2fa->generateSecretKey(); - $renderer = new GDLibRenderer(400); - $writer = new Writer($renderer); + $g2faUrl = $google2fa->getQRCodeUrl( + $user, + site_url(), + $mfasecret + ); - $qrcode_image = base64_encode($writer->writeString($g2faUrl)); + $renderer = new GDLibRenderer(400); + $writer = new Writer($renderer); + + $qrcode_image = base64_encode($writer->writeString($g2faUrl)); } ?>


+ +
+
- - '.i18n('manualsetupkey').': '.$mfasecret.' -
- -
- -
-
-
- -
- -
-
- - '; - } else { - echo ' -
- -
- -
-
- '; - } ?> -
\ No newline at end of file + +
+ +
+ +
+ +
+
+
+ +
+ +
+
+ + ' + + +
+ +
+ +
+
+ + + diff --git a/system/htmly.php b/system/htmly.php index 6400388..227d9fd 100644 --- a/system/htmly.php +++ b/system/htmly.php @@ -121,82 +121,82 @@ get('/index', function () { post('/login', function () { $proper = (is_csrf_proper(from($_REQUEST, 'csrf_token'))); - if (config('login.protect.system') === 'google') { - $captcha = isCaptcha(from($_REQUEST, 'g-recaptcha-response')); - } elseif (config('login.protect.system') === 'cloudflare') { - $captcha = isTurnstile(from($_REQUEST, 'cf-turnstile-response')); - } else { + $captcha = config('login.protect.system'); + if (is_null($captcha) || $captcha === 'disabled') { $captcha = true; + } elseif ($captcha === 'cloudflare') { + $captcha = isTurnstile(from($_REQUEST, 'cf-turnstile-response')); + } elseif ($captcha === 'google') { + $captcha = isCaptcha(from($_REQUEST, 'g-recaptcha-response')); } $user = from($_REQUEST, 'user'); $pass = from($_REQUEST, 'password'); - if ($proper && $captcha && !empty($user) && !empty($pass)) { - - if (user('mfa_secret', $user) !== "disabled") { - $mfa_secret = user('mfa_secret', $user); - $mfacode = from($_REQUEST, 'mfacode'); - $google2fa = new Google2FA(); - if ($google2fa->verifyKey($mfa_secret, $mfacode, '1')) { - session($user, $pass); - $log = session($user, $pass); + $mfa_secret = user('mfa_secret', $user); + if ($proper && $captcha && !empty($user) && !empty($pass)) { + if (!is_null($mfa_secret) && $mfa_secret !== "disabled") { + $mfacode = from($_REQUEST, 'mfacode'); + $google2fa = new Google2FA(); + if ($google2fa->verifyKey($mfa_secret, $mfacode, '1')) { + session($user, $pass); + $log = session($user, $pass); - if (!empty($log)) { + if (!empty($log)) { - config('views.root', 'system/admin/views'); + config('views.root', 'system/admin/views'); - render('login', array( - 'title' => generate_title('is_default', i18n('Login')), - 'description' => i18n('Login') . ' ' . blog_title(), - 'canonical' => site_url(), - 'metatags' => generate_meta(null, null), - 'error' => '', - 'type' => 'is_login', - 'is_login' => true, - 'bodyclass' => 'in-login', - 'breadcrumb' => '' . config('breadcrumb.home') . ' » ' . i18n('Login') - )); - } - } else { - $message['error'] .= '
  • ' . i18n('MFA_Error') . '
  • '; + render('login', array( + 'title' => generate_title('is_default', i18n('Login')), + 'description' => i18n('Login') . ' ' . blog_title(), + 'canonical' => site_url(), + 'metatags' => generate_meta(null, null), + 'error' => '', + 'type' => 'is_login', + 'is_login' => true, + 'bodyclass' => 'in-login', + 'breadcrumb' => '' . config('breadcrumb.home') . ' » ' . i18n('Login') + )); + } + } else { + $message['error'] = ''; + $message['error'] .= '
  • ' . i18n('MFA_Error') . '
  • '; + config('views.root', 'system/admin/views'); - config('views.root', 'system/admin/views'); + render('login', array( + 'title' => generate_title('is_default', i18n('Login')), + 'description' => i18n('Login') . ' ' . blog_title(), + 'canonical' => site_url(), + 'metatags' => generate_meta(null, null), + 'error' => '', + 'username' => $user, + 'password' => $pass, + 'type' => 'is_login', + 'is_login' => true, + 'bodyclass' => 'in-login', + 'breadcrumb' => '' . config('breadcrumb.home') . ' » ' . i18n('Login') + )); + } + } else { + session($user, $pass); + $log = session($user, $pass); - render('login', array( - 'title' => generate_title('is_default', i18n('Login')), - 'description' => i18n('Login') . ' ' . blog_title(), - 'canonical' => site_url(), - 'metatags' => generate_meta(null, null), - 'error' => '', - 'username' => $user, - 'password' => $pass, - 'type' => 'is_login', - 'is_login' => true, - 'bodyclass' => 'in-login', - 'breadcrumb' => '' . config('breadcrumb.home') . ' » ' . i18n('Login') - )); - } - } else { - session($user, $pass); - $log = session($user, $pass); + if (!empty($log)) { - if (!empty($log)) { + config('views.root', 'system/admin/views'); - config('views.root', 'system/admin/views'); - - render('login', array( - 'title' => generate_title('is_default', i18n('Login')), - 'description' => i18n('Login') . ' ' . blog_title(), - 'canonical' => site_url(), - 'metatags' => generate_meta(null, null), - 'error' => '', - 'type' => 'is_login', - 'is_login' => true, - 'bodyclass' => 'in-login', - 'breadcrumb' => '' . config('breadcrumb.home') . ' » ' . i18n('Login') - )); - } - } + render('login', array( + 'title' => generate_title('is_default', i18n('Login')), + 'description' => i18n('Login') . ' ' . blog_title(), + 'canonical' => site_url(), + 'metatags' => generate_meta(null, null), + 'error' => '', + 'type' => 'is_login', + 'is_login' => true, + 'bodyclass' => 'in-login', + 'breadcrumb' => '' . config('breadcrumb.home') . ' » ' . i18n('Login') + )); + } + } } else { $message['error'] = ''; if (empty($user)) { @@ -447,7 +447,7 @@ post('/edit/password', function() { } else { $login = site_url() . 'login'; header("location: $login"); - } + } }); get('/edit/mfa', function () { @@ -474,34 +474,57 @@ post('/edit/mfa', function() { if (login() && $proper) { $username = from($_REQUEST, 'username'); $mfa_secret = from($_REQUEST, 'mfa_secret'); + $mfacode = from($_REQUEST, 'mfacode'); $user = $_SESSION[site_url()]['user']; $role = user('role', $user); + $old_password = user('password', $user); $password = from($_REQUEST, 'password'); + $message['error'] = ''; if ($user === $username) { - if ($mfa_secret !== "disabled") { - $mfacode = from($_REQUEST, 'mfacode'); - $google2fa = new Google2FA(); - if ($google2fa->verifyKey($mfa_secret, $mfacode, '1')) { - $file = 'config/users/' . $user . '.ini'; - if (file_exists($file)) { - if (!empty($mfa_secret)) { - update_user($user, $password, $role, $mfa_secret); - } - } - $redir = site_url() . 'admin'; - header("location: $redir"); - } else { - $redir = site_url() . 'admin'; - header("location: $redir"); - } - } else { - $file = 'config/users/' . $user . '.ini'; - if (file_exists($file)) { - update_user($user, $password, $role, 'disabled'); - } - $redir = site_url() . 'admin'; - header("location: $redir"); - } + if (!is_null($mfa_secret) && $mfa_secret !== "disabled") { + $google2fa = new Google2FA(); + if ($google2fa->verifyKey($mfa_secret, $mfacode)) { + if (password_verify($password, $old_password)) { + if (!empty($mfa_secret)) { + update_user($user, $password, $role, $mfa_secret); + } + } else { + $message['error'] .= '
  • ' . i18n('Pass_Error') . '
  • '; + } + } else { + $message['error'] .= '
  • ' . i18n('MFA_Error') . '
  • '; + } + config('views.root', 'system/admin/views'); + render('edit-mfa', array( + 'title' => generate_title('is_default', i18n('config_mfa')), + 'description' => safe_html(strip_tags(blog_description())), + 'canonical' => site_url(), + 'metatags' => generate_meta(null, null), + 'error' => '', + 'type' => 'is_profile', + 'is_admin' => true, + 'bodyclass' => 'edit-mfa', + 'breadcrumb' => '' . config('breadcrumb.home') . ' » '. i18n('config_mfa'), + )); + } else { + if (password_verify($password, $old_password)) { + update_user($user, $password, $role, 'disabled'); + } else { + $message['error'] .= '
  • ' . i18n('Pass_Error') . '
  • '; + } + config('views.root', 'system/admin/views'); + render('edit-mfa', array( + 'title' => generate_title('is_default', i18n('config_mfa')), + 'description' => safe_html(strip_tags(blog_description())), + 'canonical' => site_url(), + 'metatags' => generate_meta(null, null), + 'error' => '', + 'type' => 'is_profile', + 'is_admin' => true, + 'bodyclass' => 'edit-mfa', + 'breadcrumb' => '' . config('breadcrumb.home') . ' » '. i18n('config_mfa'), + )); + } } else { $redir = site_url(); header("location: $redir"); @@ -509,8 +532,9 @@ post('/edit/mfa', function() { } else { $login = site_url() . 'login'; header("location: $login"); - } + } }); + // Edit the frontpage get('/edit/frontpage', function () { diff --git a/system/includes/functions.php b/system/includes/functions.php index 2330990..f2da09f 100644 --- a/system/includes/functions.php +++ b/system/includes/functions.php @@ -1226,7 +1226,7 @@ function get_author($name) $author->about = MarkdownExtra::defaultTransform(remove_html_comments($content)); $author->description = get_content_tag("d", $content, get_description($author->about)); - + $author->avatar = get_content_tag("image", $content, site_url() . 'system/resources/images/logo-small.png'); $toc = explode('', $author->about); @@ -3440,9 +3440,9 @@ function head_contents() $output .= '' . "\n"; $output .= '' . "\n"; $output .= '' . "\n"; - if (config('show.version') == 'true') { - $output .= '' . "\n"; - } + if (config('show.version') == 'true') { + $output .= '' . "\n"; + } $output .= $favicon; $output .= '' . "\n"; $output .= '' . "\n"; @@ -3583,8 +3583,8 @@ function isCaptcha($reCaptchaResponse) // Cloudflare Turnstile function isTurnstile($turnstileResponse) { - $public = config("login.protect.public"); - $private = config("login.protect.private"); + $public = config("login.protect.public"); + $private = config("login.protect.private"); $ip = $_SERVER['REMOTE_ADDR']; $url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';