diff options
| author | 2025-07-31 13:53:14 +0200 | |
|---|---|---|
| committer | 2025-07-31 13:53:14 +0200 | |
| commit | 3ce64d271b2b470bd6c9f7294946347dcdfed9b9 (patch) | |
| tree | 56b5a0928f1ce2b0486e866abd5456bc43ea8ed9 /app | |
| parent | d0425f8c3ab14e72142b1a4f946d57b408f26c88 (diff) | |
Implement sudo mode / reauthentication (#7753)
* Implement sudo mode / reauthentication
* i18n: fr
* generate flags
* Improvements
* Remove HMAC check
* Don't require reauth to access logs when signed in as admin
* Notify user of bad login via notification instead
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Diffstat (limited to 'app')
32 files changed, 302 insertions, 7 deletions
diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index b090eb486..6b8d924d6 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -21,6 +21,10 @@ class FreshRSS_auth_Controller extends FreshRSS_ActionController { Minz_Error::error(403); } + if (FreshRSS_Auth::requestReauth()) { + return; + } + FreshRSS_View::prependTitle(_t('admin.auth.title') . ' · '); if (Minz_Request::isPost()) { @@ -219,6 +223,35 @@ class FreshRSS_auth_Controller extends FreshRSS_ActionController { } } + public function reauthAction(): void { + if (!FreshRSS_Auth::hasAccess()) { + Minz_Error::error(403); + return; + } + /** @var array{c?: string, a?: string, params?: array<string, mixed>} $redirect */ + $redirect = Minz_Url::unserialize(Minz_Request::paramString('r')); + if (!FreshRSS_Auth::needsReauth()) { + Minz_Request::forward($redirect, true); + return; + } + if (Minz_Request::isPost()) { + $username = Minz_User::name() ?? ''; + $nonce = Minz_Session::paramString('nonce'); + $challenge = Minz_Request::paramString('challenge'); + if (!FreshRSS_FormAuth::checkCredentials( + $username, FreshRSS_Context::userConf()->passwordHash, $nonce, $challenge + )) { + Minz_Request::setBadNotification(_t('feedback.auth.login.invalid')); + } else { + Minz_Session::_param('lastReauth', time()); + Minz_Request::forward($redirect, true); + return; + } + } + FreshRSS_View::prependTitle(_t('gen.auth.reauth.title') . ' · '); + FreshRSS_View::appendScript(Minz_Url::display('/scripts/vendor/bcrypt.js?' . @filemtime(PUBLIC_PATH . '/scripts/vendor/bcrypt.js'))); + } + /** * This action removes all accesses of the current user. */ diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index f6ed00986..b76b528d8 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -270,6 +270,10 @@ class FreshRSS_update_Controller extends FreshRSS_ActionController { Minz_Request::forward(['c' => 'update'], true); } + if (FreshRSS_Auth::requestReauth()) { + return; + } + if (Minz_Request::paramBoolean('post_conf')) { if (self::isGit()) { $res = !self::hasGitUpdate(); diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 05d73f971..c4c3c00a8 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -72,6 +72,10 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController { } if (Minz_Request::isPost()) { + if (self::reauthRedirect()) { + return; + } + $username = Minz_Request::paramString('username'); $newPasswordPlain = Minz_User::name() !== $username ? Minz_Request::paramString('newPasswordPlain', true) : ''; @@ -190,21 +194,41 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController { } } + public static function reauthRedirect(): bool { + $url_redirect = [ + 'c' => 'user', + 'a' => 'manage', + 'params' => [], + ]; + $username = Minz_Request::paramStringNull('username'); + if ($username !== null) { + $url_redirect['a'] = 'details'; + $url_redirect['params']['username'] = $username; + } + return FreshRSS_Auth::requestReauth($url_redirect); + } + public function purgeAction(): void { if (!FreshRSS_Auth::hasAccess('admin')) { Minz_Error::error(403); } - if (Minz_Request::isPost()) { - $username = Minz_Request::paramString('username'); + if (!Minz_Request::isPost()) { + Minz_Error::error(403); + } - if (!FreshRSS_UserDAO::exists($username)) { - Minz_Error::error(404); - } + if (self::reauthRedirect()) { + return; + } + + $username = Minz_Request::paramString('username'); - $feedDAO = FreshRSS_Factory::createFeedDao($username); - $feedDAO->purge(); + if (!FreshRSS_UserDAO::exists($username)) { + Minz_Error::error(404); } + + $feedDAO = FreshRSS_Factory::createFeedDao($username); + $feedDAO->purge(); } /** @@ -215,6 +239,10 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController { Minz_Error::error(403); } + if (self::reauthRedirect()) { + return; + } + FreshRSS_View::prependTitle(_t('admin.user.title') . ' · '); if (Minz_Request::isPost()) { @@ -337,6 +365,10 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController { Minz_Error::error(403); } + if (self::reauthRedirect()) { + return; + } + if (Minz_Request::isPost()) { $new_user_name = Minz_Request::paramString('new_user_name'); $email = Minz_Request::paramString('new_user_email'); @@ -602,7 +634,10 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController { $username, FreshRSS_Context::userConf()->passwordHash, $nonce, $challenge ); + } elseif (self::reauthRedirect()) { + return; } + if ($ok) { $ok &= self::deleteUser($username); } @@ -647,6 +682,10 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController { Minz_Error::error(403); } + if (self::reauthRedirect()) { + return; + } + $username = Minz_Request::paramString('username'); if (!FreshRSS_UserDAO::exists($username)) { Minz_Error::error(404); @@ -682,6 +721,10 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController { Minz_Error::error(403); } + if (self::reauthRedirect()) { + return; + } + $username = Minz_Request::paramString('username'); if (!FreshRSS_UserDAO::exists($username)) { Minz_Error::error(404); diff --git a/app/Models/Auth.php b/app/Models/Auth.php index 5c861f1db..19cd26aa5 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -165,6 +165,7 @@ class FreshRSS_Auth { self::$login_ok = false; Minz_Session::_params([ 'loginOk' => false, + 'lastReauth' => false, 'csrf' => false, 'REMOTE_USER' => false, ]); @@ -230,4 +231,54 @@ class FreshRSS_Auth { } return $token != '' && $token === $csrf; } + + public static function needsReauth(): bool { + $auth_type = FreshRSS_Context::systemConf()->auth_type; + $reauth_required = FreshRSS_Context::systemConf()->reauth_required; + $reauth_time = FreshRSS_Context::systemConf()->reauth_time; + + if (!$reauth_required) { + return false; + } + + $last_reauth = Minz_Session::paramInt('lastReauth'); + + if ($auth_type !== 'none' && time() - $last_reauth > $reauth_time) { + if ($auth_type === 'http_auth') { + // TODO: not implemented - just let the user through + return false; + } + return true; + } + return false; + } + + /** + * Return if user needs reauth and got redirected to login page. + * + * @param array{c?: string, a?: string, params?: array<string, mixed>}|null $redirect + */ + public static function requestReauth(?array $redirect = null): bool { + if (self::needsReauth()) { + if (Minz_Request::paramBoolean('ajax')) { + // Send 403 and exit instead of redirect with Minz_Error::error() + header('HTTP/1.1 403 Forbidden'); + exit(); + } + + $redirect = Minz_Url::serialize($redirect ?? Minz_Request::currentRequest()); + + Minz_Request::forward([ + 'c' => 'auth', + 'a' => 'reauth', + 'params' => [ + 'r' => $redirect, + ], + ], true); + + return true; + } + + return false; + } } diff --git a/app/Models/SystemConfiguration.php b/app/Models/SystemConfiguration.php index 403950728..7c7862b8a 100644 --- a/app/Models/SystemConfiguration.php +++ b/app/Models/SystemConfiguration.php @@ -9,6 +9,8 @@ declare(strict_types=1); * @property bool $api_enabled * @property string $archiving * @property 'form'|'http_auth'|'none' $auth_type + * @property-read bool $reauth_required + * @property-read int $reauth_time * @property-read string $auto_update_url * @property-read array<int,mixed> $curl_options * @property string $default_user diff --git a/app/i18n/cs/gen.php b/app/i18n/cs/gen.php index 173b2c2d7..232251ab2 100644 --- a/app/i18n/cs/gen.php +++ b/app/i18n/cs/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Heslo', 'format' => '<small>Alespoň 7 znaků</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Nový účet', 'ask' => 'Vytvořit účet?', diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index d21b1a25a..b373b38f2 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Passwort', 'format' => '<small>mindestens 7 Zeichen</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Neuer Account', 'ask' => 'Erstelle einen Account?', diff --git a/app/i18n/el/gen.php b/app/i18n/el/gen.php index 5c9daf67b..a8a22e699 100644 --- a/app/i18n/el/gen.php +++ b/app/i18n/el/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Password', // TODO 'format' => '<small>At least 7 characters</small>', // TODO ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'New account', // TODO 'ask' => 'Create an account?', // TODO diff --git a/app/i18n/en-us/gen.php b/app/i18n/en-us/gen.php index b233595fe..f272f9d12 100644 --- a/app/i18n/en-us/gen.php +++ b/app/i18n/en-us/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Password', // IGNORE 'format' => '<small>At least 7 characters</small>', // IGNORE ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // IGNORE + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // IGNORE + 'title' => 'Reauthentication', // IGNORE + ), 'registration' => array( '_' => 'New account', // IGNORE 'ask' => 'Create an account?', // IGNORE diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 0f3e5aff7..398e7e60b 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Password', 'format' => '<small>At least 7 characters</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', + 'title' => 'Reauthentication', + ), 'registration' => array( '_' => 'New account', 'ask' => 'Create an account?', diff --git a/app/i18n/es/gen.php b/app/i18n/es/gen.php index c7dae3b64..bca993c13 100644 --- a/app/i18n/es/gen.php +++ b/app/i18n/es/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Contraseña', 'format' => '<small>Mínimo de 7 caracteres</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Nueva cuenta', 'ask' => '¿Crear una cuenta?', diff --git a/app/i18n/fa/gen.php b/app/i18n/fa/gen.php index bce9f38bc..33f3056cc 100644 --- a/app/i18n/fa/gen.php +++ b/app/i18n/fa/gen.php @@ -61,6 +61,11 @@ return array( '_' => ' رمز عبور', 'format' => '<small>حداقل 7 نویسه</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => ' حساب جدید', 'ask' => ' یک حساب کاربری ایجاد کنید؟', diff --git a/app/i18n/fi/gen.php b/app/i18n/fi/gen.php index 3860055ac..b8a8ad905 100644 --- a/app/i18n/fi/gen.php +++ b/app/i18n/fi/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Salasana', 'format' => '<small>Vähintään 7 merkkiä</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Uusi tili', 'ask' => 'Haluatko luoda tilin?', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 9706e57fc..282fc82c9 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Mot de passe', 'format' => '<small>7 caractères minimum</small>', ), + 'reauth' => array( + 'header' => 'Une réauthentification est requise', + 'tip' => 'La réauthentification sera valide pendant <u>%d minutes</u>', + 'title' => 'Réauthentification', + ), 'registration' => array( '_' => 'Nouveau compte', 'ask' => 'Créer un compte ?', diff --git a/app/i18n/he/gen.php b/app/i18n/he/gen.php index 7af4b4ce0..1ce9b7bdb 100644 --- a/app/i18n/he/gen.php +++ b/app/i18n/he/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'סיסמה', 'format' => '<small>At least 7 characters</small>', // TODO ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'New account', // TODO 'ask' => 'Create an account?', // TODO diff --git a/app/i18n/hu/gen.php b/app/i18n/hu/gen.php index 891ae3695..54a2eaf56 100755 --- a/app/i18n/hu/gen.php +++ b/app/i18n/hu/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Jelszó', 'format' => '<small>Legalább 7 karakter hosszú</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Új fiók', 'ask' => 'Létrehoz egy új fiókot?', diff --git a/app/i18n/id/gen.php b/app/i18n/id/gen.php index eaee65687..d62166902 100644 --- a/app/i18n/id/gen.php +++ b/app/i18n/id/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Kata sandi', 'format' => '<small>Paling tidak 7 karakter</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Akun baru', 'ask' => 'Buat akun?', diff --git a/app/i18n/it/gen.php b/app/i18n/it/gen.php index d2ed49ee4..485f51371 100644 --- a/app/i18n/it/gen.php +++ b/app/i18n/it/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Password', // IGNORE 'format' => '<small>almeno 7 caratteri</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Nuovo profilo', 'ask' => 'Vuoi creare un nuovo profilo?', diff --git a/app/i18n/ja/gen.php b/app/i18n/ja/gen.php index bc494802c..5debea06f 100644 --- a/app/i18n/ja/gen.php +++ b/app/i18n/ja/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'パスワード', 'format' => '<small>最低7文字必要です</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => '新規アカウント', 'ask' => 'アカウントを作りますか?', diff --git a/app/i18n/ko/gen.php b/app/i18n/ko/gen.php index b8f8318ba..803f02ff9 100644 --- a/app/i18n/ko/gen.php +++ b/app/i18n/ko/gen.php @@ -61,6 +61,11 @@ return array( '_' => '암호', 'format' => '<small>7 글자 이상이어야 합니다</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => '새 계정', 'ask' => '새 계정을 만들까요?', diff --git a/app/i18n/lv/gen.php b/app/i18n/lv/gen.php index 61f06f610..dd3ed807f 100644 --- a/app/i18n/lv/gen.php +++ b/app/i18n/lv/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Parole', 'format' => '<small>Vismaz 7 rakstzīmes</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Jauns konts', 'ask' => 'Uztaisīt kontu?', diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php index 351024019..d259edb30 100644 --- a/app/i18n/nl/gen.php +++ b/app/i18n/nl/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Wachtwoord', 'format' => '<small>Ten minste 7 tekens</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Nieuw account', 'ask' => 'Maak een account?', diff --git a/app/i18n/oc/gen.php b/app/i18n/oc/gen.php index 3f5cdeb88..22d9918e7 100644 --- a/app/i18n/oc/gen.php +++ b/app/i18n/oc/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Senhal', 'format' => '<small>Almens 7 caractèrs</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Compte nòu', 'ask' => 'Crear un compte?', diff --git a/app/i18n/pl/gen.php b/app/i18n/pl/gen.php index f59926574..4630abdf3 100644 --- a/app/i18n/pl/gen.php +++ b/app/i18n/pl/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Hasło', 'format' => '<small>przynajmniej 7 znaków</small>', ), + 'reauth' => array( + 'header' => 'Wymagane ponowne logowanie', + 'tip' => 'Nie będziesz proszony o ponowne logowanie przez <u>%d minut</u>', + 'title' => 'Ponowne logowanie', + ), 'registration' => array( '_' => 'Tworzenie konta', 'ask' => 'Nie masz konta?', diff --git a/app/i18n/pt-br/gen.php b/app/i18n/pt-br/gen.php index 4711146b2..77e3acb5f 100644 --- a/app/i18n/pt-br/gen.php +++ b/app/i18n/pt-br/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Senha', 'format' => '<small>Ao menos 7 caracteres</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Nova conta', 'ask' => 'Criar novoa conta?', diff --git a/app/i18n/pt-pt/gen.php b/app/i18n/pt-pt/gen.php index 104b61636..893a174aa 100644 --- a/app/i18n/pt-pt/gen.php +++ b/app/i18n/pt-pt/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Senha', 'format' => '<small>Pelo menos 7 caracteres</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Nova conta', 'ask' => 'Criar novoa conta?', diff --git a/app/i18n/ru/gen.php b/app/i18n/ru/gen.php index e11b1cdc4..68bfa7cba 100644 --- a/app/i18n/ru/gen.php +++ b/app/i18n/ru/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Пароль', 'format' => '<small>Не менее 7 символов</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Новый аккаунт', 'ask' => 'Создать аккаунт?', diff --git a/app/i18n/sk/gen.php b/app/i18n/sk/gen.php index b8df72a16..54e8c8cb2 100644 --- a/app/i18n/sk/gen.php +++ b/app/i18n/sk/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Heslo', 'format' => '<small>Najmenej 7 znakov</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Nový účet', 'ask' => 'Vytvoriť účet?', diff --git a/app/i18n/tr/gen.php b/app/i18n/tr/gen.php index 99ab450fb..3525cd6b0 100644 --- a/app/i18n/tr/gen.php +++ b/app/i18n/tr/gen.php @@ -61,6 +61,11 @@ return array( '_' => 'Parola', 'format' => '<small>En az 7 karakter</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => 'Yeni hesap', 'ask' => 'Hesap oluştur?', diff --git a/app/i18n/zh-cn/gen.php b/app/i18n/zh-cn/gen.php index a0ba4bab8..ec910a012 100644 --- a/app/i18n/zh-cn/gen.php +++ b/app/i18n/zh-cn/gen.php @@ -61,6 +61,11 @@ return array( '_' => '密码', 'format' => '<small>至少 7 个字符</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => '新用户', 'ask' => '创建新用户?', diff --git a/app/i18n/zh-tw/gen.php b/app/i18n/zh-tw/gen.php index 4b0e0feab..82e70b730 100644 --- a/app/i18n/zh-tw/gen.php +++ b/app/i18n/zh-tw/gen.php @@ -61,6 +61,11 @@ return array( '_' => '密碼', 'format' => '<small>至少 7 個字元</small>', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for <u>%d minutes</u>', // TODO + 'title' => 'Reauthentication', // TODO + ), 'registration' => array( '_' => '新使用者', 'ask' => '創建新使用者?', diff --git a/app/views/auth/reauth.phtml b/app/views/auth/reauth.phtml new file mode 100644 index 000000000..d5b75decd --- /dev/null +++ b/app/views/auth/reauth.phtml @@ -0,0 +1,32 @@ +<?php + declare(strict_types=1); + /** @var FreshRSS_View $this */ +?> + +<main class="prompt"> + <h1><?= _t('gen.auth.reauth.header') ?></h1> + + <form id="crypto-form" method="post"> + <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" /> + <input type="hidden" id="username" value="<?= Minz_User::name() ?>" /> + <div class="form-group"> + <label for="passwordPlain"><?= _t('gen.auth.password') ?></label> + <div class="stick"> + <input type="password" id="passwordPlain" required="required" /> + <button type="button" class="btn toggle-password" data-toggle="passwordPlain"><?= _i('key') ?></button> + </div> + <input type="hidden" id="challenge" name="challenge" /> + <noscript><strong><?= _t('gen.js.should_be_activated') ?></strong></noscript> + </div> + <?php + $reauth_time = FreshRSS_Context::systemConf()->reauth_time; + ?> + <p class="help"><?= _i('help') ?> <?= _t('gen.auth.reauth.tip', intval($reauth_time / 60)) ?></p> + <div class="form-group form-group-actions"> + <button id="loginButton" type="submit" class="btn btn-important" disabled="disabled"> + <?= _t('gen.auth.login') ?> + </button> + </div> + </form> +</main> + |
