mirror of
https://github.com/FreshRSS/FreshRSS.git
synced 2026-05-19 22:04:50 -04:00
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>
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 (!FreshRSS_UserDAO::exists($username)) {
|
||||
Minz_Error::error(404);
|
||||
}
|
||||
|
||||
$feedDAO = FreshRSS_Factory::createFeedDao($username);
|
||||
$feedDAO->purge();
|
||||
if (!Minz_Request::isPost()) {
|
||||
Minz_Error::error(403);
|
||||
}
|
||||
|
||||
if (self::reauthRedirect()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$username = Minz_Request::paramString('username');
|
||||
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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' => ' یک حساب کاربری ایجاد کنید؟',
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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 ?',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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' => 'アカウントを作りますか?',
|
||||
|
||||
@@ -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' => '새 계정을 만들까요?',
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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' => 'Создать аккаунт?',
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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?',
|
||||
|
||||
@@ -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' => '创建新用户?',
|
||||
|
||||
@@ -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' => '創建新使用者?',
|
||||
|
||||
32
app/views/auth/reauth.phtml
Normal file
32
app/views/auth/reauth.phtml
Normal file
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="70" height="20">
|
||||
<g fill="white" font-size="12" font-family="Verdana" text-anchor="middle">
|
||||
<rect rx="3" width="70" height="20" fill="green" />
|
||||
<text x="34" y="14">🇩🇪 96%</text>
|
||||
<text x="34" y="14">🇩🇪 95%</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 328 B After Width: | Height: | Size: 328 B |
@@ -2,6 +2,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="70" height="20">
|
||||
<g fill="white" font-size="12" font-family="Verdana" text-anchor="middle">
|
||||
<rect rx="3" width="70" height="20" fill="green" />
|
||||
<text x="34" y="14">🇮🇩 99%</text>
|
||||
<text x="34" y="14">🇮🇩 98%</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 328 B After Width: | Height: | Size: 328 B |
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
|
||||
Reference in New Issue
Block a user