mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Get 2FA plugin somesort of working
This commit is contained in:
parent
868f7a4b0a
commit
2d1f99a8ce
12 changed files with 151 additions and 216 deletions
|
|
@ -1,8 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
/*
|
|
||||||
$this->DefaultResponse(__FUNCTION__,
|
|
||||||
$this->FalseResponse(__FUNCTION__);
|
|
||||||
*/
|
|
||||||
|
|
||||||
use \RainLoop\Exceptions\ClientException;
|
use \RainLoop\Exceptions\ClientException;
|
||||||
|
|
||||||
|
|
@ -14,21 +10,18 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
RELEASE = '2021-07-22',
|
RELEASE = '2021-07-22',
|
||||||
REQUIRED = '2.5.4',
|
REQUIRED = '2.5.4',
|
||||||
CATEGORY = 'Login',
|
CATEGORY = 'Login',
|
||||||
DESCRIPTION = 'This plugin allows you to to have TOTP';
|
DESCRIPTION = 'This plugin allows you to have TOTP 2FA';
|
||||||
|
|
||||||
// \RainLoop\Notifications\
|
|
||||||
const
|
const
|
||||||
AccountTwoFactorAuthRequired = 120,
|
AccountTwoFactorAuthRequired = 120,
|
||||||
AccountTwoFactorAuthError = 121,
|
AccountTwoFactorAuthError = 121;
|
||||||
|
|
||||||
Capa_TWO_FACTOR = 'TWO_FACTOR',
|
|
||||||
Capa_TWO_FACTOR_FORCE = 'TWO_FACTOR_FORCE';
|
|
||||||
|
|
||||||
public function Init() : void
|
public function Init() : void
|
||||||
{
|
{
|
||||||
$this->UseLangs(true);
|
$this->UseLangs(true);
|
||||||
|
|
||||||
// $this->addCss('style.less');
|
// $this->addCss('style.less');
|
||||||
|
$this->addJs('js/TwoFactorAuthLogin.js');
|
||||||
$this->addJs('js/TwoFactorAuthSettings.js');
|
$this->addJs('js/TwoFactorAuthSettings.js');
|
||||||
|
|
||||||
$this->addHook('login.success', 'DoLogin');
|
$this->addHook('login.success', 'DoLogin');
|
||||||
|
|
@ -44,84 +37,50 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
$this->addTemplate('templates/PopupsTwoFactorAuthTest.html');
|
$this->addTemplate('templates/PopupsTwoFactorAuthTest.html');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configMapping() : array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
\RainLoop\Plugins\Property::NewInstance('allow_two_factor_auth')
|
|
||||||
->SetLabel('TAB_SECURITY/LABEL_ALLOW_TWO_STEP')
|
|
||||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL),
|
|
||||||
\RainLoop\Plugins\Property::NewInstance('force_two_factor_auth')
|
|
||||||
->SetLabel('TAB_SECURITY/LABEL_FORCE_TWO_STEP')
|
|
||||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function DoLogin(\RainLoop\Model\Account $oAccount)
|
public function DoLogin(\RainLoop\Model\Account $oAccount)
|
||||||
{
|
{
|
||||||
// Stripped from \RainLoop\Actions::LoginProcess
|
|
||||||
if ($this->TwoFactorAuthProvider($oAccount)) {
|
if ($this->TwoFactorAuthProvider($oAccount)) {
|
||||||
$aData = $this->getTwoFactorInfo($oAccount);
|
$aData = $this->getTwoFactorInfo($oAccount);
|
||||||
if ($aData && isset($aData['IsSet'], $aData['Enable']) && !empty($aData['Secret']) && $aData['IsSet'] && $aData['Enable']) {
|
if ($aData && isset($aData['IsSet'], $aData['Enable']) && !empty($aData['Secret']) && $aData['IsSet'] && $aData['Enable']) {
|
||||||
$sSecretHash = \md5(APP_SALT . $aData['Secret'] . Utils::Fingerprint());
|
$sCode = \trim($this->jsonParam('totp_code', ''));
|
||||||
$sSecretCookieHash = Utils::GetCookie(self::AUTH_TFA_SIGN_ME_TOKEN_KEY, '');
|
if (empty($sCode)) {
|
||||||
|
|
||||||
if (empty($sSecretCookieHash) || $sSecretHash !== $sSecretCookieHash) {
|
|
||||||
$sAdditionalCode = \trim($this->jsonParam('AdditionalCode', ''));
|
|
||||||
if (empty($sAdditionalCode)) {
|
|
||||||
$this->Logger()->Write('TFA: Required Code for ' . $oAccount->ParentEmailHelper() . ' account.');
|
$this->Logger()->Write('TFA: Required Code for ' . $oAccount->ParentEmailHelper() . ' account.');
|
||||||
|
|
||||||
throw new Exceptions\ClientException(Notifications::AccountTwoFactorAuthRequired);
|
throw new ClientException(static::AccountTwoFactorAuthRequired);
|
||||||
} else {
|
} else {
|
||||||
$this->Logger()->Write('TFA: Verify Code for ' . $oAccount->ParentEmailHelper() . ' account.');
|
$this->Logger()->Write('TFA: Verify Code for ' . $oAccount->ParentEmailHelper() . ' account.');
|
||||||
|
|
||||||
$bUseBackupCode = false;
|
$bUseBackupCode = false;
|
||||||
if (6 < \strlen($sAdditionalCode) && !empty($aData['BackupCodes'])) {
|
if (6 < \strlen($sCode) && !empty($aData['BackupCodes'])) {
|
||||||
$aBackupCodes = \explode(' ', \trim(\preg_replace('/[^\d]+/', ' ', $aData['BackupCodes'])));
|
$aBackupCodes = \explode(' ', \trim(\preg_replace('/[^\d]+/', ' ', $aData['BackupCodes'])));
|
||||||
$bUseBackupCode = \in_array($sAdditionalCode, $aBackupCodes);
|
$bUseBackupCode = \in_array($sCode, $aBackupCodes);
|
||||||
|
|
||||||
if ($bUseBackupCode) {
|
if ($bUseBackupCode) {
|
||||||
$this->removeBackupCodeFromTwoFactorInfo($oAccount->ParentEmailHelper(), $sAdditionalCode);
|
$this->removeBackupCodeFromTwoFactorInfo($oAccount->ParentEmailHelper(), $sCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$bUseBackupCode && !$this->TwoFactorAuthProvider($oAccount)->VerifyCode($aData['Secret'], $sAdditionalCode)) {
|
if (!$bUseBackupCode && !$this->TwoFactorAuthProvider($oAccount)->VerifyCode($aData['Secret'], $sCode)) {
|
||||||
$this->Manager()->Actions()->loginErrorDelay();
|
$this->Manager()->Actions()->loginErrorDelay();
|
||||||
|
|
||||||
$this->Manager()->Actions()->LoggerAuthHelper($oAccount);
|
$this->Manager()->Actions()->LoggerAuthHelper($oAccount);
|
||||||
|
|
||||||
throw new Exceptions\ClientException(Notifications::AccountTwoFactorAuthError);
|
throw new ClientException(static::AccountTwoFactorAuthError);
|
||||||
}
|
|
||||||
|
|
||||||
// $bAdditionalCodeSignMe
|
|
||||||
// if ('1' === (string) $this->Manager()->Actions()->GetActionParam('AdditionalCodeSignMe', '0')) {
|
|
||||||
if ('1' === (string) $this->jsonParam('AdditionalCodeSignMe', '0')) {
|
|
||||||
Utils::SetCookie(self::AUTH_TFA_SIGN_ME_TOKEN_KEY, $sSecretHash,
|
|
||||||
\time() + 60 * 60 * 24 * 14);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
// Stripped from \RainLoop\Actions\User::DoLogin
|
|
||||||
if (Notifications::AccountTwoFactorAuthRequired === $oException->getCode())
|
|
||||||
{
|
|
||||||
return $this->DefaultResponse(__FUNCTION__, true, array(
|
|
||||||
'TwoFactorAuth' => true
|
|
||||||
));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
public function DoGetTwoFactorInfo() : array
|
public function DoGetTwoFactorInfo() : array
|
||||||
{
|
{
|
||||||
$oAccount = $this->getAccountFromToken();
|
$oAccount = $this->getAccountFromToken();
|
||||||
|
|
||||||
if (!$this->TwoFactorAuthProvider($oAccount)) {
|
if (!$this->TwoFactorAuthProvider($oAccount)) {
|
||||||
return $this->FalseResponse(__FUNCTION__);
|
return $this->jsonResponse(__FUNCTION__, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->DefaultResponse(__FUNCTION__, $this->getTwoFactorInfo($oAccount, true));
|
return $this->jsonResponse(__FUNCTION__, $this->getTwoFactorInfo($oAccount, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function DoCreateTwoFactorSecret() : array
|
public function DoCreateTwoFactorSecret() : array
|
||||||
|
|
@ -129,7 +88,7 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
$oAccount = $this->getAccountFromToken();
|
$oAccount = $this->getAccountFromToken();
|
||||||
|
|
||||||
if (!$this->TwoFactorAuthProvider($oAccount)) {
|
if (!$this->TwoFactorAuthProvider($oAccount)) {
|
||||||
return $this->FalseResponse(__FUNCTION__);
|
return $this->jsonResponse(__FUNCTION__, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
$sEmail = $oAccount->ParentEmailHelper();
|
$sEmail = $oAccount->ParentEmailHelper();
|
||||||
|
|
@ -153,9 +112,9 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->Manager()->Actions()->requestSleep();
|
// $this->Manager()->Actions()->requestSleep();
|
||||||
|
|
||||||
return $this->DefaultResponse(__FUNCTION__, $this->getTwoFactorInfo($oAccount));
|
return $this->jsonResponse(__FUNCTION__, $this->getTwoFactorInfo($oAccount));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function DoShowTwoFactorSecret() : array
|
public function DoShowTwoFactorSecret() : array
|
||||||
|
|
@ -163,13 +122,13 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
$oAccount = $this->getAccountFromToken();
|
$oAccount = $this->getAccountFromToken();
|
||||||
|
|
||||||
if (!$this->TwoFactorAuthProvider($oAccount)) {
|
if (!$this->TwoFactorAuthProvider($oAccount)) {
|
||||||
return $this->FalseResponse(__FUNCTION__);
|
return $this->jsonResponse(__FUNCTION__, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
$aResult = $this->getTwoFactorInfo($oAccount);
|
$aResult = $this->getTwoFactorInfo($oAccount);
|
||||||
unset($aResult['BackupCodes']);
|
unset($aResult['BackupCodes']);
|
||||||
|
|
||||||
return $this->DefaultResponse(__FUNCTION__, $aResult);
|
return $this->jsonResponse(__FUNCTION__, $aResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function DoEnableTwoFactor() : array
|
public function DoEnableTwoFactor() : array
|
||||||
|
|
@ -177,7 +136,7 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
$oAccount = $this->getAccountFromToken();
|
$oAccount = $this->getAccountFromToken();
|
||||||
|
|
||||||
if (!$this->TwoFactorAuthProvider($oAccount)) {
|
if (!$this->TwoFactorAuthProvider($oAccount)) {
|
||||||
return $this->FalseResponse(__FUNCTION__);
|
return $this->jsonResponse(__FUNCTION__, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// $this->Manager()->Actions()->setSettingsFromParams($oSettings, 'EnableTwoFactor', 'bool');
|
// $this->Manager()->Actions()->setSettingsFromParams($oSettings, 'EnableTwoFactor', 'bool');
|
||||||
|
|
@ -205,7 +164,7 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->DefaultResponse(__FUNCTION__, $bResult);
|
return $this->jsonResponse(__FUNCTION__, $bResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function DoVerifyTwoFactorCode() : array
|
public function DoVerifyTwoFactorCode() : array
|
||||||
|
|
@ -213,7 +172,7 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
$oAccount = $this->getAccountFromToken();
|
$oAccount = $this->getAccountFromToken();
|
||||||
|
|
||||||
if (!$this->TwoFactorAuthProvider($oAccount)) {
|
if (!$this->TwoFactorAuthProvider($oAccount)) {
|
||||||
return $this->FalseResponse(__FUNCTION__);
|
return $this->jsonResponse(__FUNCTION__, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
$sCode = \trim($this->jsonParam('Code', ''));
|
$sCode = \trim($this->jsonParam('Code', ''));
|
||||||
|
|
@ -226,9 +185,9 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
// $this->TwoFactorAuthProvider($oAccount)->VerifyCode($sSecret, $sCode)
|
// $this->TwoFactorAuthProvider($oAccount)->VerifyCode($sSecret, $sCode)
|
||||||
// ));
|
// ));
|
||||||
|
|
||||||
$this->Manager()->Actions()->requestSleep();
|
// $this->Manager()->Actions()->requestSleep();
|
||||||
|
|
||||||
return $this->DefaultResponse(__FUNCTION__,
|
return $this->jsonResponse(__FUNCTION__,
|
||||||
$this->TwoFactorAuthProvider($oAccount)->VerifyCode($sSecret, $sCode));
|
$this->TwoFactorAuthProvider($oAccount)->VerifyCode($sSecret, $sCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -237,7 +196,7 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
$oAccount = $this->getAccountFromToken();
|
$oAccount = $this->getAccountFromToken();
|
||||||
|
|
||||||
if (!$this->TwoFactorAuthProvider($oAccount)) {
|
if (!$this->TwoFactorAuthProvider($oAccount)) {
|
||||||
return $this->FalseResponse(__FUNCTION__);
|
return $this->jsonResponse(__FUNCTION__, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->StorageProvider()->Clear($oAccount,
|
$this->StorageProvider()->Clear($oAccount,
|
||||||
|
|
@ -245,7 +204,7 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
'two_factor'
|
'two_factor'
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->DefaultResponse(__FUNCTION__, $this->getTwoFactorInfo($oAccount, true));
|
return $this->jsonResponse(__FUNCTION__, $this->getTwoFactorInfo($oAccount, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function Logger() : \RainLoop\Providers\TwoFactorAuth
|
protected function Logger() : \RainLoop\Providers\TwoFactorAuth
|
||||||
|
|
@ -264,10 +223,7 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
private $oTwoFactorAuthProvider;
|
private $oTwoFactorAuthProvider;
|
||||||
protected function TwoFactorAuthProvider(\RainLoop\Model\Account $oAccount) : ?TwoFactorAuthInterface
|
protected function TwoFactorAuthProvider(\RainLoop\Model\Account $oAccount) : ?TwoFactorAuthInterface
|
||||||
{
|
{
|
||||||
// if ($this->Config()->Get('plugin', 'allow_two_factor_auth', 0))
|
if (!$this->oTwoFactorAuthProvider) {
|
||||||
// if ($this->Config()->Get('plugin', 'force_two_factor_auth', 0))
|
|
||||||
|
|
||||||
if (!$this->oTwoFactorAuthProvider && $this->Manager()->Actions()->GetCapa(false, static::Capa_TWO_FACTOR, $oAccount)) {
|
|
||||||
require __DIR__ . '/providers/interface.php';
|
require __DIR__ . '/providers/interface.php';
|
||||||
require __DIR__ . '/providers/totp.php';
|
require __DIR__ . '/providers/totp.php';
|
||||||
$this->oTwoFactorAuthProvider = new TwoFactorAuthTotp();
|
$this->oTwoFactorAuthProvider = new TwoFactorAuthTotp();
|
||||||
|
|
|
||||||
23
plugins/two-factor-auth/js/TwoFactorAuthLogin.js
Normal file
23
plugins/two-factor-auth/js/TwoFactorAuthLogin.js
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
(rl => {
|
||||||
|
|
||||||
|
rl && addEventListener('rl-view-model', e => {
|
||||||
|
if (e.detail && 'Login' === e.detail.viewModelTemplateID) {
|
||||||
|
const container = e.detail.viewModelDom.querySelector('#plugin-Login-BottomControlGroup'),
|
||||||
|
placeholder = 'LOGIN/LABEL_VERIFICATION_CODE';
|
||||||
|
if (container) {
|
||||||
|
container.append(Element.fromHTML('<div class="controls">'
|
||||||
|
+ '<div class="input-append">'
|
||||||
|
+ '<input name="totp_code" type="text" class="input-block-level inputIcon"'
|
||||||
|
+ ' pattern="[0-9]*" inputmode="numeric"'
|
||||||
|
+ ' autocomplete="off" autocorrect="off" autocapitalize="none" spellcheck="false"'
|
||||||
|
+ ' data-bind="textInput: totp, disable: submitRequest" data-i18n="[placeholder]'+placeholder
|
||||||
|
+ '" placeholder="'+rl.i18n(placeholder)+'">'
|
||||||
|
+ '<i class="add-on fontastic">🔑</i>'
|
||||||
|
+ '</div>'
|
||||||
|
+ '</div>'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
})(window.rl);
|
||||||
|
|
@ -5,11 +5,6 @@ import { trigger as translatorTrigger } from 'Common/Translator';
|
||||||
(rl => { if (rl) {
|
(rl => { if (rl) {
|
||||||
|
|
||||||
const
|
const
|
||||||
Capa = {
|
|
||||||
TwoFactor: 'TWO_FACTOR',
|
|
||||||
TwoFactorForce: 'TWO_FACTOR_FORCE',
|
|
||||||
},
|
|
||||||
|
|
||||||
pString = value => null != value ? '' + value : '',
|
pString = value => null != value ? '' + value : '',
|
||||||
|
|
||||||
Remote = new class {
|
Remote = new class {
|
||||||
|
|
@ -56,10 +51,8 @@ class TwoFactorAuthSettings
|
||||||
|
|
||||||
this.viewEnable_ = ko.observable(false);
|
this.viewEnable_ = ko.observable(false);
|
||||||
|
|
||||||
this.capaTwoFactor = rl.settings.capa(Capa.TwoFactor);
|
|
||||||
|
|
||||||
const fn = iError => iError && this.viewEnable_(false);
|
const fn = iError => iError && this.viewEnable_(false);
|
||||||
this.addComputables({
|
Object.entries({
|
||||||
viewEnable: {
|
viewEnable: {
|
||||||
read: this.viewEnable_,
|
read: this.viewEnable_,
|
||||||
write: (value) => {
|
write: (value) => {
|
||||||
|
|
@ -92,12 +85,16 @@ class TwoFactorAuthSettings
|
||||||
},
|
},
|
||||||
|
|
||||||
twoFactorAllowedEnable: () => this.viewEnable() || this.twoFactorTested()
|
twoFactorAllowedEnable: () => this.viewEnable() || this.twoFactorTested()
|
||||||
});
|
}).forEach(([key, fn]) => this[key] = ko.computed(fn));
|
||||||
|
|
||||||
this.onResult = this.onResult.bind(this);
|
this.onResult = this.onResult.bind(this);
|
||||||
this.onShowSecretResult = this.onShowSecretResult.bind(this);
|
this.onShowSecretResult = this.onShowSecretResult.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configureTwoFactor() {
|
||||||
|
// showScreenPopup(require('View/Popup/TwoFactorConfiguration'));
|
||||||
|
}
|
||||||
|
|
||||||
showSecret() {
|
showSecret() {
|
||||||
this.secreting(true);
|
this.secreting(true);
|
||||||
rl.pluginRemoteRequest(this.onShowSecretResult, 'ShowTwoFactorSecret');
|
rl.pluginRemoteRequest(this.onShowSecretResult, 'ShowTwoFactorSecret');
|
||||||
|
|
@ -180,7 +177,7 @@ class TwoFactorAuthSettings
|
||||||
this.viewBackupCodes(pString(oData.Result.BackupCodes).replace(/[\s]+/g, ' '));
|
this.viewBackupCodes(pString(oData.Result.BackupCodes).replace(/[\s]+/g, ' '));
|
||||||
|
|
||||||
this.viewUrlTitle(pString(oData.Result.UrlTitle));
|
this.viewUrlTitle(pString(oData.Result.UrlTitle));
|
||||||
this.viewUrl(qr.toDataURL({ level: 'M', size: 8, value: this.getQr() }));
|
this.viewUrl(null/*qr.toDataURL({ level: 'M', size: 8, value: this.getQr() })*/);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,17 +191,15 @@ class TwoFactorAuthSettings
|
||||||
} else {
|
} else {
|
||||||
this.viewSecret(pString(data.Result.Secret));
|
this.viewSecret(pString(data.Result.Secret));
|
||||||
this.viewUrlTitle(pString(data.Result.UrlTitle));
|
this.viewUrlTitle(pString(data.Result.UrlTitle));
|
||||||
this.viewUrl(qr.toDataURL({ level: 'M', size: 6, value: this.getQr() }));
|
this.viewUrl(null/*qr.toDataURL({ level: 'M', size: 6, value: this.getQr() })*/);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuild() {
|
onBuild() {
|
||||||
if (this.capaTwoFactor) {
|
|
||||||
this.processing(true);
|
this.processing(true);
|
||||||
rl.pluginRemoteRequest(this.onResult, 'GetTwoFactorInfo');
|
rl.pluginRemoteRequest(this.onResult, 'GetTwoFactorInfo');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class TwoFactorAuthTestPopupView extends rl.pluginPopupView {
|
class TwoFactorAuthTestPopupView extends rl.pluginPopupView {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
[TAB_SECURITY]
|
|
||||||
LABEL_ALLOW_TWO_STEP = "Zwei-Faktor-Authentifizierung erlauben"
|
|
||||||
LABEL_FORCE_TWO_STEP = "Zwei-Faktor-Authentifizierung erzwingen"
|
|
||||||
[POPUPS_TWO_FACTOR_CFG]
|
[POPUPS_TWO_FACTOR_CFG]
|
||||||
LEGEND_TWO_FACTOR_AUTH = "Zwei-Faktor-Authentifizierung"
|
LEGEND_TWO_FACTOR_AUTH = "Zwei-Faktor-Authentifizierung"
|
||||||
LABEL_ENABLE_TWO_FACTOR = "Zwei-Faktor-Authentifizierung aktivieren"
|
LABEL_ENABLE_TWO_FACTOR = "Zwei-Faktor-Authentifizierung aktivieren"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
[TAB_SECURITY]
|
|
||||||
LABEL_ALLOW_TWO_STEP = "Allow 2-Step Verification"
|
|
||||||
LABEL_FORCE_TWO_STEP = "Enforce 2-Step Verification"
|
|
||||||
[POPUPS_TWO_FACTOR_TEST]
|
[POPUPS_TWO_FACTOR_TEST]
|
||||||
TITLE_TEST_CODE = "2-Step verification test"
|
TITLE_TEST_CODE = "2-Step verification test"
|
||||||
LABEL_CODE = "Code"
|
LABEL_CODE = "Code"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
[TAB_SECURITY]
|
|
||||||
LABEL_ALLOW_TWO_STEP = "Activar la verificación de 2 pasos"
|
|
||||||
LABEL_FORCE_TWO_STEP = "Forzar la Autenticación en 2 pasos"
|
|
||||||
[POPUPS_TWO_FACTOR_TEST]
|
[POPUPS_TWO_FACTOR_TEST]
|
||||||
TITLE_TEST_CODE = "Prueba de verificación de 2 pasos"
|
TITLE_TEST_CODE = "Prueba de verificación de 2 pasos"
|
||||||
LABEL_CODE = "Código"
|
LABEL_CODE = "Código"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
[TAB_SECURITY]
|
|
||||||
LABEL_ALLOW_TWO_STEP = "Autoriser l'authentification en deux étapes"
|
|
||||||
LABEL_FORCE_TWO_STEP = "Forcer l'authentification en deux étapes"
|
|
||||||
[POPUPS_TWO_FACTOR_CFG]
|
[POPUPS_TWO_FACTOR_CFG]
|
||||||
LEGEND_TWO_FACTOR_AUTH = "Authentification en deux étapes"
|
LEGEND_TWO_FACTOR_AUTH = "Authentification en deux étapes"
|
||||||
LABEL_ENABLE_TWO_FACTOR = "Activer l'authentification en deux étapes"
|
LABEL_ENABLE_TWO_FACTOR = "Activer l'authentification en deux étapes"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
[TAB_SECURITY]
|
|
||||||
LABEL_ALLOW_TWO_STEP = "2 lépcsős hitelesítés engedélyezése"
|
|
||||||
LABEL_FORCE_TWO_STEP = "2 lépcsős hitelesítés kényszerítése"
|
|
||||||
[POPUPS_TWO_FACTOR_CFG]
|
[POPUPS_TWO_FACTOR_CFG]
|
||||||
LEGEND_TWO_FACTOR_AUTH = "2 lépcsős hitelesítés"
|
LEGEND_TWO_FACTOR_AUTH = "2 lépcsős hitelesítés"
|
||||||
LABEL_ENABLE_TWO_FACTOR = "2 lépcsős hitelesítés engedélyezése"
|
LABEL_ENABLE_TWO_FACTOR = "2 lépcsős hitelesítés engedélyezése"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
[TAB_SECURITY]
|
|
||||||
LABEL_ALLOW_TWO_STEP = "2-Stap verificatie toestaan"
|
|
||||||
LABEL_FORCE_TWO_STEP = "2-Stap verificatie afdwingen"
|
|
||||||
[POPUPS_TWO_FACTOR_CFG]
|
[POPUPS_TWO_FACTOR_CFG]
|
||||||
LEGEND_TWO_FACTOR_AUTH = "2-Stap verificatie"
|
LEGEND_TWO_FACTOR_AUTH = "2-Stap verificatie"
|
||||||
LABEL_ENABLE_TWO_FACTOR = "Gebruik 2-Stap verificatie"
|
LABEL_ENABLE_TWO_FACTOR = "Gebruik 2-Stap verificatie"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
[TAB_SECURITY]
|
|
||||||
LABEL_ALLOW_TWO_STEP = "Låt 2-tvåstegsverifiering"
|
|
||||||
LABEL_FORCE_TWO_STEP = "Driva 2-tvåstegsverifiering"
|
|
||||||
[POPUPS_TWO_FACTOR_CFG]
|
[POPUPS_TWO_FACTOR_CFG]
|
||||||
LEGEND_TWO_FACTOR_AUTH = "Tvåstegsverifiering (TOTP)"
|
LEGEND_TWO_FACTOR_AUTH = "Tvåstegsverifiering (TOTP)"
|
||||||
LABEL_ENABLE_TWO_FACTOR = "Aktivera tvåstegsverifiering"
|
LABEL_ENABLE_TWO_FACTOR = "Aktivera tvåstegsverifiering"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
[TAB_SECURITY]
|
|
||||||
LABEL_ALLOW_TWO_STEP = "允许两步验证"
|
|
||||||
LABEL_FORCE_TWO_STEP = "强制使用两步验证"
|
|
||||||
[POPUPS_TWO_FACTOR_CFG]
|
[POPUPS_TWO_FACTOR_CFG]
|
||||||
LEGEND_TWO_FACTOR_AUTH = "两步验证 (TOTP)"
|
LEGEND_TWO_FACTOR_AUTH = "两步验证 (TOTP)"
|
||||||
LABEL_ENABLE_TWO_FACTOR = "启用两步验证"
|
LABEL_ENABLE_TWO_FACTOR = "启用两步验证"
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,7 @@
|
||||||
<div class="b-settings-two-factor">
|
<div class="b-settings-two-factor">
|
||||||
<div class="form-horizontal" data-bind="visible: capaAutoLogout">
|
<div class="form-horizontal">
|
||||||
<div class="legend" data-i18n="POPUPS_TWO_FACTOR_CFG/LEGEND_TWO_FACTOR_AUTH"></div>
|
<div class="legend" data-i18n="POPUPS_TWO_FACTOR_CFG/LEGEND_TWO_FACTOR_AUTH"></div>
|
||||||
<div class="control-group" data-bind="visible: capaTwoFactor">
|
<div class="form-horizontal">
|
||||||
<label class="control-label"></label>
|
|
||||||
<div class="controls">
|
|
||||||
<i class="fontastic">🔒</i>
|
|
||||||
|
|
||||||
<span class="g-ui-link" tabindex="0" data-i18n="SETTINGS_SECURITY/LABEL_CONFIGURE_TWO_FACTOR" data-bind="click: configureTwoFactor, onSpace: configureTwoFactor, onEnter: configureTwoFactor"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-bind="visible: viewEnable() || !lock(), command: cancelCommand">×</button>
|
|
||||||
<h3 data-i18n="POPUPS_TWO_FACTOR_CFG/LEGEND_TWO_FACTOR_AUTH"></h3>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="form-horizontal" data-bind="visible: capaTwoFactor" style="margin-top: 10px;">
|
|
||||||
<div class="control-group" data-bind="visible: twoFactorStatus">
|
<div class="control-group" data-bind="visible: twoFactorStatus">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<div style="display: inline-block" data-bind="attr:{title: viewTwoFactorEnableTooltip}">
|
<div style="display: inline-block" data-bind="attr:{title: viewTwoFactorEnableTooltip}">
|
||||||
|
|
@ -86,8 +71,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<a class="btn pull-left" data-bind="visible: lock, click: logout">
|
<a class="btn pull-left" data-bind="visible: lock, click: logout">
|
||||||
<i class="fontastic">⏻</i>
|
<i class="fontastic">⏻</i>
|
||||||
<span data-i18n="GLOBAL/LOGOUT"></span>
|
<span data-i18n="GLOBAL/LOGOUT"></span>
|
||||||
|
|
@ -100,10 +84,11 @@
|
||||||
<i class="fontastic" data-bind="css: {'icon-spinner': processing()}">▶</i>
|
<i class="fontastic" data-bind="css: {'icon-spinner': processing()}">▶</i>
|
||||||
<span data-i18n="POPUPS_TWO_FACTOR_CFG/BUTTON_ACTIVATE"></span>
|
<span data-i18n="POPUPS_TWO_FACTOR_CFG/BUTTON_ACTIVATE"></span>
|
||||||
</a>
|
</a>
|
||||||
|
<!--
|
||||||
<a class="btn" data-bind="command: cancelCommand, visible: viewEnable() || !lock()">
|
<a class="btn" data-bind="command: cancelCommand, visible: viewEnable() || !lock()">
|
||||||
<i class="icon-ok" ></i>
|
<i class="icon-ok" ></i>
|
||||||
<span data-i18n="GLOBAL/DONE"></span>
|
<span data-i18n="GLOBAL/DONE"></span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue