From 9b2334c10c42f3952955e347da9e32e3317b5797 Mon Sep 17 00:00:00 2001 From: Vladimir Y Date: Sat, 6 Apr 2019 07:54:11 +0300 Subject: [PATCH] protonmail: use custom 2fa token submitting detection * the need caused by recent built-in protonmail's web client update: url remains the same for all 3 auth forms * related commit https://github.com/vladimiry/ElectronMail/commit/2cf88eaad885291d4b3d946aee530f4936bf1e26 --- .../webview/protonmail/api/index.ts | 18 +++++++++++++++--- src/electron-preload/webview/util.ts | 18 ++++++++++++++++-- 2 files changed, 31 insertions(+), 5 deletions(-) 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); }