diff --git a/dev/Remote/Admin/Fetch.js b/dev/Remote/Admin/Fetch.js index dc0ded270..7fd451842 100644 --- a/dev/Remote/Admin/Fetch.js +++ b/dev/Remote/Admin/Fetch.js @@ -6,10 +6,11 @@ class RemoteAdminFetch extends AbstractFetchRemote { * @param {string} sLogin * @param {string} sPassword */ - adminLogin(fCallback, sLogin, sPassword) { + adminLogin(fCallback, sLogin, sPassword, sCode) { this.defaultRequest(fCallback, 'AdminLogin', { Login: sLogin, - Password: sPassword + Password: sPassword, + TOTP: sCode }); } diff --git a/dev/Styles/Login.less b/dev/Styles/Login.less index c0a5ff70d..f1fbe591f 100644 --- a/dev/Styles/Login.less +++ b/dev/Styles/Login.less @@ -79,14 +79,13 @@ } .controls { - .inputLoginForm, .inputLogin, .inputPassword { + .input-block-level { font-size: 18px; height: 40px; line-height: 20px; padding-left: 12px; - padding-right: 12px; } - .inputLogin, .inputPassword { + .inputIcon { padding-right: 35px; } diff --git a/dev/View/Admin/Login.js b/dev/View/Admin/Login.js index 6cdbb11d7..639998a89 100644 --- a/dev/View/Admin/Login.js +++ b/dev/View/Admin/Login.js @@ -17,6 +17,7 @@ class LoginAdminView extends AbstractViewCenter { this.addObservables({ login: '', password: '', + totp: '', loginError: false, passwordError: false, @@ -59,7 +60,8 @@ class LoginAdminView extends AbstractViewCenter { } }, name, - pass + pass, + this.totp() ); } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Admin.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Admin.php index 61dcf16aa..5bf43c4cf 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Admin.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Admin.php @@ -179,10 +179,13 @@ trait Admin $this->Logger()->AddSecret($sPassword); + $totp = $this->Config()->Get('security', 'admin_totp', ''); + if (0 === strlen($sLogin) || 0 === strlen($sPassword) || !$this->Config()->Get('security', 'allow_admin_panel', true) || $sLogin !== $this->Config()->Get('security', 'admin_login', '') || - !$this->Config()->ValidatePassword($sPassword)) + !$this->Config()->ValidatePassword($sPassword) + || ($totp && !\SnappyMail\TOTP::Verify($totp, $this->GetActionParam('TOTP', '')))) { $this->loginErrorDelay(); $this->LoggerAuthHelper(null, $this->getAdditionalLogParamsByUserLogin($sLogin, true)); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php index 8afc3ec3a..65261b35e 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Config/Application.php @@ -168,6 +168,7 @@ class Application extends \RainLoop\Config\AbstractConfig 'admin_login' => array('admin', 'Login and password for web admin panel'), 'admin_password' => array(''), + 'admin_totp' => array(''), 'allow_admin_panel' => array(true, 'Access settings'), 'hide_x_mailer_header' => array(true), 'admin_panel_host' => array(''), diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/totp.php b/snappymail/v/0.0.0/app/libraries/snappymail/totp.php new file mode 100644 index 000000000..133be37f1 --- /dev/null +++ b/snappymail/v/0.0.0/app/libraries/snappymail/totp.php @@ -0,0 +1,98 @@ + 0, // ord 65 + 'B' => 1, + 'C' => 2, + 'D' => 3, + 'E' => 4, + 'F' => 5, + 'G' => 6, + 'H' => 7, + 'I' => 8, + 'J' => 9, + 'K' => 10, + 'L' => 11, + 'M' => 12, + 'N' => 13, + 'O' => 14, + 'P' => 15, + 'Q' => 16, + 'R' => 17, + 'S' => 18, + 'T' => 19, + 'U' => 20, + 'V' => 21, + 'W' => 22, + 'X' => 23, + 'Y' => 24, + 'Z' => 25, // ord 90 + '2' => 26, // ord 50 + '3' => 27, + '4' => 28, + '5' => 29, + '6' => 30, + '7' => 31 // ord 55 + ); + + protected static function Base32Decode(string $data) + { + $data = \strtoupper(\rtrim($data, "=\x20\t\n\r\0\x0B")); + $dataSize = \strlen($data); + $buf = 0; + $bufSize = 0; + $res = ''; + for ($i = 0; $i < $dataSize; ++$i) { + $c = $data[$i]; + if (isset(static::$map[$c])) { + $buf = ($buf << 5) | static::$map[$c]; + $bufSize += 5; + if ($bufSize > 7) { + $bufSize -= 8; + $res .= \chr(($buf & (0xff << $bufSize)) >> $bufSize); + } + } + } + return $res; + } +} diff --git a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminLogin.html b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminLogin.html index 5af3d0b35..c47208831 100644 --- a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminLogin.html +++ b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminLogin.html @@ -6,7 +6,7 @@
- @@ -15,15 +15,20 @@
- - - 🔑 - - + 🔑 +
+
+
+
+ +
diff --git a/snappymail/v/0.0.0/app/templates/Views/User/Login.html b/snappymail/v/0.0.0/app/templates/Views/User/Login.html index a24f0a7ae..c677637f4 100644 --- a/snappymail/v/0.0.0/app/templates/Views/User/Login.html +++ b/snappymail/v/0.0.0/app/templates/Views/User/Login.html @@ -9,7 +9,7 @@ data-bind="submit: submitForm, css: {'errorAnimated': formError, 'submitting': submitRequest()}">
- @@ -18,7 +18,7 @@
-