From 3ce64d271b2b470bd6c9f7294946347dcdfed9b9 Mon Sep 17 00:00:00 2001 From: Inverle Date: Thu, 31 Jul 2025 13:53:14 +0200 Subject: 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 --- app/Controllers/authController.php | 33 ++++++++++++++++++ app/Controllers/updateController.php | 4 +++ app/Controllers/userController.php | 57 ++++++++++++++++++++++++++++---- app/Models/Auth.php | 51 ++++++++++++++++++++++++++++ app/Models/SystemConfiguration.php | 2 ++ app/i18n/cs/gen.php | 5 +++ app/i18n/de/gen.php | 5 +++ app/i18n/el/gen.php | 5 +++ app/i18n/en-us/gen.php | 5 +++ app/i18n/en/gen.php | 5 +++ app/i18n/es/gen.php | 5 +++ app/i18n/fa/gen.php | 5 +++ app/i18n/fi/gen.php | 5 +++ app/i18n/fr/gen.php | 5 +++ app/i18n/he/gen.php | 5 +++ app/i18n/hu/gen.php | 5 +++ app/i18n/id/gen.php | 5 +++ app/i18n/it/gen.php | 5 +++ app/i18n/ja/gen.php | 5 +++ app/i18n/ko/gen.php | 5 +++ app/i18n/lv/gen.php | 5 +++ app/i18n/nl/gen.php | 5 +++ app/i18n/oc/gen.php | 5 +++ app/i18n/pl/gen.php | 5 +++ app/i18n/pt-br/gen.php | 5 +++ app/i18n/pt-pt/gen.php | 5 +++ app/i18n/ru/gen.php | 5 +++ app/i18n/sk/gen.php | 5 +++ app/i18n/tr/gen.php | 5 +++ app/i18n/zh-cn/gen.php | 5 +++ app/i18n/zh-tw/gen.php | 5 +++ app/views/auth/reauth.phtml | 32 ++++++++++++++++++ config.default.php | 7 ++++ docs/i18n/flags/gen/de.svg | 2 +- docs/i18n/flags/gen/id.svg | 2 +- lib/core-extensions/UserJS/extension.php | 4 +++ lib/core-extensions/UserJS/metadata.json | 2 +- p/scripts/extra.js | 5 +++ 38 files changed, 321 insertions(+), 10 deletions(-) create mode 100644 app/views/auth/reauth.phtml 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} $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}|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 $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' => 'Alespoň 7 znaků', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'mindestens 7 Zeichen', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'At least 7 characters', // TODO ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'At least 7 characters', // IGNORE ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // IGNORE + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'At least 7 characters', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', + 'tip' => 'You won’t be asked to sign in again for %d minutes', + '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' => 'Mínimo de 7 caracteres', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'حداقل 7 نویسه', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'Vähintään 7 merkkiä', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => '7 caractères minimum', ), + 'reauth' => array( + 'header' => 'Une réauthentification est requise', + 'tip' => 'La réauthentification sera valide pendant %d minutes', + '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' => 'At least 7 characters', // TODO ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'Legalább 7 karakter hosszú', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'Paling tidak 7 karakter', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'almeno 7 caratteri', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => '最低7文字必要です', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => '7 글자 이상이어야 합니다', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'Vismaz 7 rakstzīmes', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'Ten minste 7 tekens', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'Almens 7 caractèrs', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'przynajmniej 7 znaków', ), + 'reauth' => array( + 'header' => 'Wymagane ponowne logowanie', + 'tip' => 'Nie będziesz proszony o ponowne logowanie przez %d minut', + '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' => 'Ao menos 7 caracteres', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'Pelo menos 7 caracteres', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'Не менее 7 символов', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'Najmenej 7 znakov', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => 'En az 7 karakter', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => '至少 7 个字符', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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' => '至少 7 個字元', ), + 'reauth' => array( + 'header' => 'Reauthentication is required', // TODO + 'tip' => 'You won’t be asked to sign in again for %d minutes', // 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 @@ + + +
+

+ +
+ + +
+ +
+ + +
+ + +
+ reauth_time; + ?> +

+
+ +
+
+
+ diff --git a/config.default.php b/config.default.php index f42fdc215..c839c9a3c 100644 --- a/config.default.php +++ b/config.default.php @@ -59,6 +59,13 @@ return [ # and in particular not protect `/FreshRSS/p/api/` if you would like to use the API (different login system). 'auth_type' => 'form', + # Whether reauthentication is required for performing sensitive actions e.g. promoting a user or applying an update + 'reauth_required' => true, + + # Time before asking for reauth + # Default: 1200s (20 min) + 'reauth_time' => 1200, + # When using http_auth, automatically register any unknown user 'http_auth_auto_register' => true, diff --git a/docs/i18n/flags/gen/de.svg b/docs/i18n/flags/gen/de.svg index e159e6658..b2806e1ac 100644 --- a/docs/i18n/flags/gen/de.svg +++ b/docs/i18n/flags/gen/de.svg @@ -2,6 +2,6 @@ - 🇩🇪 96% + 🇩🇪 95% \ No newline at end of file diff --git a/docs/i18n/flags/gen/id.svg b/docs/i18n/flags/gen/id.svg index 45745ee5e..6e2a1e6d0 100644 --- a/docs/i18n/flags/gen/id.svg +++ b/docs/i18n/flags/gen/id.svg @@ -2,6 +2,6 @@ - 🇮🇩 99% + 🇮🇩 98% \ No newline at end of file diff --git a/lib/core-extensions/UserJS/extension.php b/lib/core-extensions/UserJS/extension.php index db27b9ebd..e14827450 100644 --- a/lib/core-extensions/UserJS/extension.php +++ b/lib/core-extensions/UserJS/extension.php @@ -21,6 +21,10 @@ final class UserJSExtension extends Minz_Extension { $this->registerTranslates(); + if (FreshRSS_Auth::requestReauth()) { + return; + } + if (Minz_Request::isPost()) { $js_rules = Minz_Request::paramString('js-rules', plaintext: true); $this->saveFile(self::FILENAME, $js_rules); diff --git a/lib/core-extensions/UserJS/metadata.json b/lib/core-extensions/UserJS/metadata.json index 9096d753d..5a82753f0 100644 --- a/lib/core-extensions/UserJS/metadata.json +++ b/lib/core-extensions/UserJS/metadata.json @@ -2,7 +2,7 @@ "name": "User JS", "author": "hkcomori, Frans de Jonge", "description": "Apply user JS.", - "version": "1.1.0", + "version": "1.1.1", "entrypoint": "UserJS", "type": "user" } diff --git a/p/scripts/extra.js b/p/scripts/extra.js index c94d004ce..5a77aee4b 100644 --- a/p/scripts/extra.js +++ b/p/scripts/extra.js @@ -327,6 +327,11 @@ function open_slider_listener(ev) { req.open('GET', ahref, true); req.responseType = 'document'; req.onload = function (e) { + if (this.status === 403) { + // Redirect to reauth page (or fail if session expired) + location.href = a.href; + return; + } location.href = '#slider'; // close menu/dropdown document.documentElement.classList.add('slider-active'); slider.classList.add('active'); -- cgit v1.2.3