From ddb51c0e95074c6fbddade547ca267801177bb01 Mon Sep 17 00:00:00 2001 From: Inverle Date: Mon, 15 Sep 2025 22:17:14 +0200 Subject: Fix another user self-delete regression (#7877) Regression from #7763 Earlier regression which was fixed before #7626 In addition: * get rid of `data-toggle` (refactor) * show invalid login message if deleting account and entered incorrect password instead of redirect to 403 * remove unused reference to `r` parameter * `forgetOpenCategories()` on login not on any crypto form --- app/Controllers/userController.php | 9 ++- app/views/auth/formLogin.phtml | 6 +- app/views/auth/reauth.phtml | 8 +- app/views/auth/register.phtml | 2 +- app/views/feed/add.phtml | 2 +- app/views/helpers/feed/update.phtml | 2 +- app/views/subscription/add.phtml | 2 +- app/views/user/details.phtml | 2 +- app/views/user/manage.phtml | 2 +- app/views/user/profile.phtml | 29 +++---- p/scripts/extra.js | 153 ++++++++++++++++++------------------ 11 files changed, 105 insertions(+), 112 deletions(-) diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 1f4452523..e71c8aaa0 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -635,13 +635,16 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController { $username, FreshRSS_Context::userConf()->passwordHash, $nonce, $challenge ); + if (!$ok) { + Minz_Request::bad(_t('feedback.auth.login.invalid'), ['c' => 'user', 'a' => 'profile']); + return; + } } elseif (self::reauthRedirect()) { return; } - if ($ok) { - $ok &= self::deleteUser($username); - } + $ok &= self::deleteUser($username); + if ($ok && $self_deletion) { FreshRSS_Auth::removeAccess(); $redirect_url = ['c' => 'index', 'a' => 'index']; diff --git a/app/views/auth/formLogin.phtml b/app/views/auth/formLogin.phtml index d72d0b1b3..23fceeb88 100644 --- a/app/views/auth/formLogin.phtml +++ b/app/views/auth/formLogin.phtml @@ -11,7 +11,7 @@ -
+ @@ -24,8 +24,8 @@
- - + +
diff --git a/app/views/auth/reauth.phtml b/app/views/auth/reauth.phtml index d5b75decd..b48f89e5f 100644 --- a/app/views/auth/reauth.phtml +++ b/app/views/auth/reauth.phtml @@ -6,14 +6,14 @@

- +
- - + +
@@ -23,7 +23,7 @@ ?>

-
diff --git a/app/views/auth/register.phtml b/app/views/auth/register.phtml index daaf08b8c..5787b36fc 100644 --- a/app/views/auth/register.phtml +++ b/app/views/auth/register.phtml @@ -50,7 +50,7 @@
- +

diff --git a/app/views/feed/add.phtml b/app/views/feed/add.phtml index ceec0d7b6..a30ce19a1 100644 --- a/app/views/feed/add.phtml +++ b/app/views/feed/add.phtml @@ -83,7 +83,7 @@
- +
diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index c363532f5..e95400953 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -231,7 +231,7 @@
- +
diff --git a/app/views/subscription/add.phtml b/app/views/subscription/add.phtml index 3e5d6d08b..a822b4440 100644 --- a/app/views/subscription/add.phtml +++ b/app/views/subscription/add.phtml @@ -277,7 +277,7 @@
- +
diff --git a/app/views/user/details.phtml b/app/views/user/details.phtml index 20ab4d804..648bbfd27 100644 --- a/app/views/user/details.phtml +++ b/app/views/user/details.phtml @@ -61,7 +61,7 @@
username ? '' : 'disabled="disabled" ' ?>/> - +

diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index d416d0c0c..2c2354b3a 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -71,7 +71,7 @@
- +

diff --git a/app/views/user/profile.phtml b/app/views/user/profile.phtml index d49147c59..f55eead4d 100644 --- a/app/views/user/profile.phtml +++ b/app/views/user/profile.phtml @@ -7,7 +7,7 @@ ?>
- +

@@ -58,12 +58,12 @@
>
- +
- - + +
@@ -89,7 +89,7 @@
- +
@@ -120,7 +120,7 @@ placeholder="" pattern=".{7,}" /> - +

@@ -146,7 +146,7 @@

- +

@@ -155,8 +155,8 @@
- - + +

@@ -165,13 +165,6 @@
- 'user', 'a' => 'profile'], - 'php', true - )); - ?> -
diff --git a/p/scripts/extra.js b/p/scripts/extra.js index 8d5b960c8..48f50325b 100644 --- a/p/scripts/extra.js +++ b/p/scripts/extra.js @@ -16,114 +16,107 @@ function forgetOpenCategories() { localStorage.removeItem('FreshRSS_open_categories'); } -function init_crypto_form() { - /* globals bcrypt */ - const crypto_form = document.getElementById('crypto-form'); - if (!crypto_form) { - return; - } - +function init_crypto_forms() { if (!(window.bcrypt)) { if (window.console) { console.log('FreshRSS waiting for bcrypt.js
'); } - setTimeout(init_crypto_form, 100); + setTimeout(init_crypto_forms, 100); return; } - forgetOpenCategories(); - - const submit_button = crypto_form.querySelector('[type="submit"]'); - if (submit_button) { - submit_button.disabled = false; - } + /* globals bcrypt */ + const crypto_forms = document.querySelectorAll('.crypto-form'); + crypto_forms.forEach(crypto_form => { + const submit_button = crypto_form.querySelector('[type="submit"]'); + if (submit_button) { + submit_button.disabled = false; + } - crypto_form.onsubmit = function (e) { - let challenge = crypto_form.querySelector('#challenge'); - if (!challenge) { - crypto_form.querySelectorAll('[data-challenge-if-not-empty] input[type="password"]').forEach(el => { - if (el.value !== '' && !challenge) { - crypto_form.insertAdjacentHTML('beforeend', ''); - challenge = crypto_form.querySelector('#challenge'); - } - }); + crypto_form.onsubmit = function (e) { + let challenge = crypto_form.querySelector('#challenge'); if (!challenge) { - return true; + crypto_form.querySelectorAll('[data-challenge-if-not-empty] input[type="password"]').forEach(el => { + if (el.value !== '' && !challenge) { + crypto_form.insertAdjacentHTML('beforeend', ''); + challenge = crypto_form.querySelector('#challenge'); + } + }); + if (!challenge) { + return true; + } } - } - e.preventDefault(); + e.preventDefault(); - if (!submit_button) { - return false; - } - submit_button.disabled = true; + if (!submit_button) { + return false; + } + submit_button.disabled = true; - const req = new XMLHttpRequest(); - req.open('GET', './?c=javascript&a=nonce&user=' + document.getElementById('username').value, true); + const req = new XMLHttpRequest(); + req.open('GET', './?c=javascript&a=nonce&user=' + crypto_form.querySelector('#username').value, true); - req.onerror = function () { - openNotification('Communication error!', 'bad'); - submit_button.disabled = false; - }; + req.onerror = function () { + openNotification('Communication error!', 'bad'); + submit_button.disabled = false; + }; - req.onload = function () { - if (req.status == 200) { - const json = xmlHttpRequestJson(req); - if (!json.salt1 || !json.nonce) { - openNotification('Invalid user!', 'bad'); - } else { - try { - const strong = window.Uint32Array && window.crypto && (typeof window.crypto.getRandomValues === 'function'); - const s = bcrypt.hashSync(document.getElementById('passwordPlain').value, json.salt1); - const c = bcrypt.hashSync(json.nonce + s, strong ? bcrypt.genSaltSync(4) : poormanSalt()); - challenge.value = c; - if (!s || !c) { - openNotification('Crypto error!', 'bad'); - } else { - crypto_form.removeEventListener('submit', crypto_form.onsubmit); - crypto_form.submit(); + req.onload = function () { + if (req.status == 200) { + const json = xmlHttpRequestJson(req); + if (!json.salt1 || !json.nonce) { + openNotification('Invalid user!', 'bad'); + } else { + try { + const strong = window.Uint32Array && window.crypto && (typeof window.crypto.getRandomValues === 'function'); + const s = bcrypt.hashSync(crypto_form.querySelector('.passwordPlain').value, json.salt1); + const c = bcrypt.hashSync(json.nonce + s, strong ? bcrypt.genSaltSync(4) : poormanSalt()); + challenge.value = c; + if (!s || !c) { + openNotification('Crypto error!', 'bad'); + } else { + crypto_form.removeEventListener('submit', crypto_form.onsubmit); + crypto_form.submit(); + } + } catch (ex) { + openNotification('Crypto exception! ' + ex, 'bad'); } - } catch (ex) { - openNotification('Crypto exception! ' + ex, 'bad'); } + } else { + req.onerror(); } - } else { - req.onerror(); - } - submit_button.disabled = false; - }; + submit_button.disabled = false; + }; - req.send(); - }; + req.send(); + }; + }); } // // -let timeoutHide; - -function showPW_this() { - const id_passwordField = this.getAttribute('data-toggle'); - if (this.classList.contains('active')) { - hidePW(id_passwordField); +function togglePW(btn) { + if (btn.classList.contains('active')) { + hidePW(btn); } else { - showPW(id_passwordField); + showPW(btn); } return false; } -function showPW(id_passwordField) { - const passwordField = document.getElementById(id_passwordField); +function showPW(btn) { + const passwordField = btn.previousElementSibling; passwordField.setAttribute('type', 'text'); - passwordField.nextElementSibling.classList.add('active'); - clearTimeout(timeoutHide); - timeoutHide = setTimeout(function () { hidePW(id_passwordField); }, 5000); + btn.classList.add('active'); + clearTimeout(btn.timeoutHide); + btn.timeoutHide = setTimeout(function () { hidePW(btn); }, 5000); return false; } -function hidePW(id_passwordField) { - clearTimeout(timeoutHide); - const passwordField = document.getElementById(id_passwordField); +function hidePW(btn) { + clearTimeout(btn.timeoutHide); + const passwordField = btn.previousElementSibling; passwordField.setAttribute('type', 'password'); passwordField.nextElementSibling.classList.remove('active'); return false; @@ -131,7 +124,7 @@ function hidePW(id_passwordField) { function init_password_observers(parent) { parent.querySelectorAll('.toggle-password').forEach(function (btn) { - btn.addEventListener('click', showPW_this); + btn.onclick = () => togglePW(btn); }); } // @@ -500,8 +493,12 @@ function init_extra_afterDOM() { setTimeout(init_extra_afterDOM, 50); return; } + const loginButton = document.querySelector('#loginButton'); + if (loginButton) { + loginButton.addEventListener('click', forgetOpenCategories); + } if (!['normal', 'global', 'reader'].includes(context.current_view)) { - init_crypto_form(); + init_crypto_forms(); init_password_observers(document.body); init_select_observers(); init_configuration_alert(); -- cgit v1.2.3