[WIP] 2fa

* Don't allow per get request to disable 2fa
* Fix google recaptcha issue
* Fix rec key check
* Make input auth code required + autofocus
This commit is contained in:
slawkens
2026-01-31 20:44:26 +01:00
parent 381d5bb884
commit 7471c49793
13 changed files with 86 additions and 75 deletions

View File

@@ -3,14 +3,24 @@ defined('MYAAC') or die('Direct access not allowed!');
require __DIR__ . '/../base.php'; require __DIR__ . '/../base.php';
if (!isRequestMethod('post')) {
error('This page cannot be accessed directly.');
return;
}
if (!$account_logged->isLoaded()) { if (!$account_logged->isLoaded()) {
error('Account not found!'); error('Account not found!');
return; return;
} }
if (!$twoFactorAuth->isActive($twoFactorAuth::TYPE_APP)) {
error("Your account does not have Two Factor App Authentication enabled.");
return;
}
$twoFactorAuth->disable(); $twoFactorAuth->disable();
$twig->display('success.html.twig', [ $twig->display('success.html.twig', [
'title' => 'Disabled', 'title' => 'Disabled',
'description' => 'Two Factor Authentication has been disabled.' 'description' => 'Two Factor App Authentication has been disabled.'
]); ]);

View File

@@ -5,9 +5,9 @@ use MyAAC\TwoFactorAuth\TwoFactorAuth;
require __DIR__ . '/../base.php'; require __DIR__ . '/../base.php';
if (!empty($account_logged->getCustomField('2fa_secret'))) { if ($twoFactorAuth->isActive()) {
$errors[] = 'Two-factor authentication is already enabled on your account.';
$twig->display('account/2fa/app/enable.already_connected.html.twig'); $twig->display('error_box.html.twig', ['errors' => $errors]);
return; return;
} }

View File

@@ -12,11 +12,6 @@ $title = 'Two Factor Authentication';
*/ */
$code = $_REQUEST['auth-code'] ?? ''; $code = $_REQUEST['auth-code'] ?? '';
if ((!setting('core.mail_enabled')) && ACTION == 'email-code') {
$twig->display('error_box.html.twig', ['errors' => ['Account two-factor e-mail authentication disabled.']]);
return;
}
if (!$account_logged->isLoaded()) { if (!$account_logged->isLoaded()) {
$current_session = getSession('account'); $current_session = getSession('account');
if($current_session) { if($current_session) {

View File

@@ -3,14 +3,26 @@ defined('MYAAC') or die('Direct access not allowed!');
require __DIR__ . '/../base.php'; require __DIR__ . '/../base.php';
//if (!$twoFactorAuth->hasRecentEmailCode(15 * 60)) { if ((!setting('core.mail_enabled'))) {
// $twoFactorAuth->resendEmailCode(); $twig->display('error_box.html.twig', ['errors' => ['Account Two-Factor E-Mail Authentication disabled.']]);
//} return;
}
if (!isRequestMethod('post')) {
error('This page cannot be accessed directly.');
return;
}
if (!$account_logged->isLoaded()) {
error('Account not found!');
return;
}
if (!$twoFactorAuth->isActive($twoFactorAuth::TYPE_EMAIL)) {
error("Your account does not have Two Factor E-Mail Authentication enabled.");
return;
}
/*if (isset($_POST['save'])) {
if (!empty($code)) {
if ($twoFactorAuth->getAuthGateway()->verifyCode($code)) {
*/
$twoFactorAuth->disable(); $twoFactorAuth->disable();
$twoFactorAuth->deleteOldCodes(); $twoFactorAuth->deleteOldCodes();
@@ -20,18 +32,3 @@ $twig->display('success.html.twig',
'description' => 'You have successfully <strong>disabled</strong> the <b>Email Code Authentication</b> for your account.' 'description' => 'You have successfully <strong>disabled</strong> the <b>Email Code Authentication</b> for your account.'
] ]
); );
/*
}
else {
$errors[] = 'Invalid email code!';
}
}
}*/
/*
if (!empty($errors)) {
$twig->display('error_box.html.twig', ['errors' => $errors]);
}
$twig->display('account/2fa/email/deactivate.html.twig', ['wrongCode' => count($errors) > 0]);
*/

View File

@@ -6,6 +6,18 @@ defined('MYAAC') or die('Direct access not allowed!');
require __DIR__ . '/../base.php'; require __DIR__ . '/../base.php';
if ((!setting('core.mail_enabled'))) {
$twig->display('error_box.html.twig', ['errors' => ['Account Two-Factor E-Mail Authentication disabled.']]);
return;
}
if ($twoFactorAuth->isActive()) {
$errors[] = 'Two-factor authentication is already enabled on your account.';
$twig->display('error_box.html.twig', ['errors' => $errors]);
return;
}
if (!$twoFactorAuth->hasRecentEmailCode(15 * 60)) { if (!$twoFactorAuth->hasRecentEmailCode(15 * 60)) {
$twoFactorAuth->resendEmailCode(); $twoFactorAuth->resendEmailCode();
} }

View File

@@ -3,8 +3,23 @@ defined('MYAAC') or die('Direct access not allowed!');
require __DIR__ . '/../base.php'; require __DIR__ . '/../base.php';
if ($twoFactorAuth->hasRecentEmailCode(1 * 60)) { if ((!setting('core.mail_enabled'))) {
$errors = ['Sorry, one email per 15 minutes']; $twig->display('error_box.html.twig', ['errors' => ['Account Two-Factor E-Mail Authentication disabled.']]);
return;
}
if (!$account_logged->isLoaded()) {
error('Account not found!');
return;
}
if ($twoFactorAuth->isActive($twoFactorAuth::TYPE_APP)) {
error('You have to disable the app auth first!');
return;
}
if ($twoFactorAuth->hasRecentEmailCode(30 * 60)) {
$errors = ['Sorry, one email per 30 minutes'];
} }
else { else {
$twoFactorAuth->resendEmailCode(); $twoFactorAuth->resendEmailCode();
@@ -14,4 +29,4 @@ if (!empty($errors)) {
$twig->display('error_box.html.twig', ['errors' => $errors]); $twig->display('error_box.html.twig', ['errors' => $errors]);
} }
$twig->display('account/2fa/email/login.html.twig'); $twig->display('account/2fa/email/enable.html.twig');

View File

@@ -55,6 +55,10 @@ if(!empty($login_account) && !empty($login_password))
} else { } else {
setSession('account', $account_logged->getId()); setSession('account', $account_logged->getId());
if (!$hooks->trigger(HOOK_ACCOUNT_LOGIN_PRE)) {
return;
}
$twoFactorAuth = TwoFactorAuth::getInstance($account_logged); $twoFactorAuth = TwoFactorAuth::getInstance($account_logged);
if (!$twoFactorAuth->process($login_account, $login_password, $remember_me, $_POST['auth-code'] ?? '')) { if (!$twoFactorAuth->process($login_account, $login_password, $remember_me, $_POST['auth-code'] ?? '')) {
return; return;

View File

@@ -54,7 +54,6 @@ class TwoFactorAuth
} }
$view = 'app'; $view = 'app';
if ($this->authType == self::TYPE_EMAIL) { if ($this->authType == self::TYPE_EMAIL) {
$view = 'email';# $view = 'email';#
} }
@@ -63,7 +62,6 @@ class TwoFactorAuth
if ($this->authType == self::TYPE_EMAIL) { if ($this->authType == self::TYPE_EMAIL) {
if (!$this->hasRecentEmailCode(15 * 60)) { if (!$this->hasRecentEmailCode(15 * 60)) {
$this->resendEmailCode(); $this->resendEmailCode();
//success('Resent email.');
} }
} }
@@ -99,7 +97,7 @@ class TwoFactorAuth
$errors[] = 'The token is invalid!'; $errors[] = 'The token is invalid!';
} }
else { else {
$errors[] = 'Invalid email code!'; $errors[] = 'Invalid E-Mail code!';
} }
$twig->display('error_box.html.twig', ['errors' => $errors]); $twig->display('error_box.html.twig', ['errors' => $errors]);
@@ -161,7 +159,11 @@ class TwoFactorAuth
$this->account->setCustomField('2fa_secret', ''); $this->account->setCustomField('2fa_secret', '');
} }
public function isActive(): bool { public function isActive(?int $authType = null): bool {
if ($authType !== null) {
return $this->authType === $authType;
}
return $this->authType != self::TYPE_NONE; return $this->authType != self::TYPE_NONE;
} }

View File

@@ -69,6 +69,7 @@ define('HOOK_ACCOUNT_LOGIN_AFTER_PASSWORD', ++$i);
define('HOOK_ACCOUNT_LOGIN_AFTER_REMEMBER_ME', ++$i); define('HOOK_ACCOUNT_LOGIN_AFTER_REMEMBER_ME', ++$i);
define('HOOK_ACCOUNT_LOGIN_AFTER_PAGE', ++$i); define('HOOK_ACCOUNT_LOGIN_AFTER_PAGE', ++$i);
define('HOOK_ACCOUNT_LOGIN_POST', ++$i); define('HOOK_ACCOUNT_LOGIN_POST', ++$i);
define('HOOK_ACCOUNT_LOGIN_PRE', ++$i);
define('HOOK_ACCOUNT_LOST_CHECK_CODE_FINISH_AFTER_PASSWORD', ++$i); define('HOOK_ACCOUNT_LOST_CHECK_CODE_FINISH_AFTER_PASSWORD', ++$i);
define('HOOK_ACCOUNT_LOST_CHECK_CODE_FINISH_AFTER_PASSWORD_REPEAT', ++$i); define('HOOK_ACCOUNT_LOST_CHECK_CODE_FINISH_AFTER_PASSWORD_REPEAT', ++$i);
define('HOOK_ACCOUNT_LOST_EMAIL_SET_NEW_PASSWORD_POST', ++$i); define('HOOK_ACCOUNT_LOST_EMAIL_SET_NEW_PASSWORD_POST', ++$i);

View File

@@ -1,22 +0,0 @@
{% set title = 'Disable Two Factor App' %}
{% set background = config('darkborder') %}
{% set content %}
<table style="width:100%;">
<tbody>
<tr>
<td>
Two-factor authentication is already enabled on your account.<br/>
Click the button to disable the two-factor app.<br/><br/>
<form action="{{ getLink('account/2fa/app/disable') }}" method="post" style="padding:0;margin:0;">
{{ csrf() }}
{% set button_name = 'Disable' %}
{{ include('buttons.base.html.twig') }}
</form>
</td>
</tr>
</tbody>
</table>
{% endset %}
{% include 'tables.headline.html.twig' %}

View File

@@ -38,7 +38,7 @@
{% if newRecoveryKeyFormat %} {% if newRecoveryKeyFormat %}
<input form="form" class="UpperCaseInput" name="key1" value="" size="5" maxlength="5" autocomplete="off"> - <input form="form" class="UpperCaseInput" name="key1" value="" size="5" maxlength="5" autocomplete="off"> -
<input form="form" class="UpperCaseInput" name="key2" value="" size="5" maxlength="5" autocomplete="off"> - <input class="UpperCaseInput" name="key3" value="" size="5" maxlength="5" autocomplete="off"> - <input form="form" class="UpperCaseInput" name="key2" value="" size="5" maxlength="5" autocomplete="off"> - <input form="form" class="UpperCaseInput" name="key3" value="" size="5" maxlength="5" autocomplete="off"> -
<input form="form" class="UpperCaseInput" name="key4" value="" size="5" maxlength="5" autocomplete="off"> <input form="form" class="UpperCaseInput" name="key4" value="" size="5" maxlength="5" autocomplete="off">
{% else %} {% else %}

View File

@@ -12,10 +12,8 @@
<tr> <tr>
<td>Enter the verification code generated by the app:<br> <td>Enter the verification code generated by the app:<br>
<div style="margin-top: 15px; margin-bottom: 15px;"> <div style="margin-top: 15px; margin-bottom: 15px;">
<div class="LabelV200" style="float:left;">Authenticator App <div class="LabelV200" style="float:left;">Authenticator App Token:</div>
Token: <input form="form" id="auth-code" name="auth-code" maxlength="6" autocomplete="off" required autofocus></div>
</div>
<input form="form" id="auth-code" name="auth-code" maxlength="6" autocomplete="off"></div>
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@@ -17,14 +17,13 @@
> >
{{ csrf() }} {{ csrf() }}
{% set button_name = 'Resend Email Code' %} {% set button_name = 'Resend E-Mail Code' %}
{{ include('buttons.base.html.twig') }} {{ include('buttons.base.html.twig') }}
</form> </form>
</div> </div>
An <b>email code</b> has already been sent to the email address assigned to your account. An <b>E-Mail code</b> has already been sent to the E-Mail address assigned to your account.
Please check your email account's spam/junk filter and make sure that your mailbox is not Please check your E-Mail account's spam/junk filter and make sure that your mailbox is not
full.<br>In case you need a new email code, you can request one by clicking on "Resend Email full.<br>In case you need a new E-Mail code, you can request one by clicking on "Resend E-Mail Code".
Code".
</td> </td>
</tr> </tr>
</tbody> </tbody>
@@ -38,15 +37,15 @@
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;"> <table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody> <tbody>
<tr> <tr>
<td><b>Email code authentication is enabled for your account.</b><br><br>Please enter the <b>most <td><b>E-Mail code authentication is enabled for your account.</b><br><br>Please enter the <b>most
recent email code</b> you have received in order to log in.<br> recent E-Mail code</b> you have received in order to log in.<br>
<div style="margin-top: 15px; margin-bottom: 15px;"> <div style="margin-top: 15px; margin-bottom: 15px;">
<div class="LabelV150 {{ wrongCode ? 'red' : '' }}" style="float:left;"><label for="email-code">Email Code:</label></div> <div class="LabelV150 {{ wrongCode ? 'red' : '' }}" style="float:left;"><label for="email-code">E-Mail Code:</label></div>
<input form="form" id="auth-code" name="auth-code" maxlength="15" autocomplete="off"> <input form="form" id="auth-code" name="auth-code" maxlength="15" autocomplete="off" required autofocus>
{% if wrongCode %} {% if wrongCode %}
<br/> <br/>
<div class="LabelV150" style="float:left;">&nbsp; </div> <div class="LabelV150" style="float:left;">&nbsp; </div>
<div class="FormFieldError">Invalid email code!</div> <div class="FormFieldError">Invalid E-Mail code!</div>
{% endif %} {% endif %}
</div> </div>
</td> </td>