diff --git a/src/electron-preload/webview/protonmail/api/index.ts b/src/electron-preload/webview/protonmail/api/index.ts index 7920674b8..3d2addb27 100644 --- a/src/electron-preload/webview/protonmail/api/index.ts +++ b/src/electron-preload/webview/protonmail/api/index.ts @@ -153,17 +153,29 @@ const endpoints: ProtonmailApi = { login2fa: ({secret, zoneName}) => from((async (logger = curryFunctionMembers(_logger, "login2fa()", zoneName)) => { logger.info(); - const elements = await resolveDomElements({ + const resolveElementsConfig = { input: () => document.getElementById("twoFactorCode") as HTMLInputElement, button: () => document.getElementById("login_btn_2fa") as HTMLElement, - }); - logger.verbose(`elements resolved`); + }; + const elements = await resolveDomElements(resolveElementsConfig); + + logger.verbose("elements resolved"); return await submitTotpToken( elements.input, elements.button, () => authenticator.generate(secret), logger, + { + submittingDetection: async () => { + try { + await resolveDomElements(resolveElementsConfig, {iterationsLimit: 1}); + } catch { + return true; + } + return false; + }, + }, ); })()), diff --git a/src/electron-preload/webview/util.ts b/src/electron-preload/webview/util.ts index a5eb2c39e..ba98e9526 100644 --- a/src/electron-preload/webview/util.ts +++ b/src/electron-preload/webview/util.ts @@ -118,12 +118,15 @@ export async function submitTotpToken( { submitTimeoutMs = ONE_SECOND_MS * 4, newTokenDelayMs = ONE_SECOND_MS * 2, + submittingDetection, }: { submitTimeoutMs?: number; newTokenDelayMs?: number; + submittingDetection?: () => Promise; } = {}, ): Promise { const logger = curryFunctionMembers(_logger, "submitTotpToken()"); + logger.info(); if (input.value) { @@ -148,7 +151,14 @@ export async function submitTotpToken( async function submit() { logger.verbose("submit - start"); - const urlBeforeSubmit = getLocationHref(); + + const submitted: () => Promise = ( + submittingDetection + || + ((urlBeforeSubmit = getLocationHref()) => { + return async () => getLocationHref() !== urlBeforeSubmit; + })() + ); await fillInputValue(input, tokenResolver()); logger.verbose("input filled"); @@ -158,7 +168,11 @@ export async function submitTotpToken( await asyncDelay(submitTimeoutMs); - if (getLocationHref() === urlBeforeSubmit) { + // TODO consider using unified submitting detection + // like for example testing that input/button elements no longer attached to DOM or visible + if ( + !(await submitted()) + ) { throw new Error(errorMessage); }