From cdf44dd69c501d7be6489991fa3ec6e6677890da Mon Sep 17 00:00:00 2001 From: jelveh Date: Thu, 16 Jul 2026 19:45:03 -0700 Subject: [PATCH] fix: resolve 2FA setup promise on every close so Dashboard toggle can't freeze UIWindow2FASetup only resolved its promise from the Done button and, in on_before_exit, when setup had NOT succeeded. Clicking "Enable" sets setup_succeeded=true and advances to the recovery-codes screen without resolving; if the user then closes that screen via the backdrop or Escape instead of Done, the promise never settles. The Dashboard Security tab is the only caller: it disables the 2FA toggle and `await`s this promise, so the hang leaves the toggle permanently disabled and stuck in the pending state for the rest of the session. Resolve with setup_succeeded on any exit; resolve_promise is idempotent so a prior Done-resolve is unaffected. --- src/gui/src/UI/UIWindow2FASetup.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gui/src/UI/UIWindow2FASetup.js b/src/gui/src/UI/UIWindow2FASetup.js index 36a3f5a2d..afeb4c4a3 100644 --- a/src/gui/src/UI/UIWindow2FASetup.js +++ b/src/gui/src/UI/UIWindow2FASetup.js @@ -751,7 +751,13 @@ const UIWindow2FASetup = async function UIWindow2FASetup () { is_draggable: false, backdrop: true, on_before_exit: async () => { - if ( ! setup_succeeded ) resolve_promise(false); + // Settle the promise on every close path. Clicking "Enable" sets + // setup_succeeded but does not resolve (only the Done button does), + // so closing the success screen via backdrop/Escape must resolve + // here too — otherwise the caller (Dashboard 2FA toggle) awaits a + // promise that never settles and leaves its control stuck disabled. + // resolve_promise is idempotent, so a prior Done-resolve is a no-op. + resolve_promise(setup_succeeded); return true; }, window_class: 'window-tfa-setup',