[PM-4678] [Defect] Passkey browser fallback broken on iCloud (#6783)

* [PM-4678] fix: add cross-origin frame handling

* [PM-4678] feat: force window and tab focus
This commit is contained in:
Andreas Coroiu 2023-11-06 17:14:48 +01:00 committed by GitHub
parent 200189c895
commit ffd08a6d6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 8 deletions

View File

@ -312,12 +312,36 @@ export default class RuntimeBackground {
case "checkFido2FeatureEnabled":
return await this.main.fido2ClientService.isFido2FeatureEnabled();
case "fido2RegisterCredentialRequest":
return await this.abortManager.runWithAbortController(msg.requestId, (abortController) =>
this.main.fido2ClientService.createCredential(msg.data, sender.tab, abortController)
return await this.abortManager.runWithAbortController(
msg.requestId,
async (abortController) => {
try {
return await this.main.fido2ClientService.createCredential(
msg.data,
sender.tab,
abortController
);
} finally {
await BrowserApi.focusTab(sender.tab.id);
await BrowserApi.focusWindow(sender.tab.windowId);
}
}
);
case "fido2GetCredentialRequest":
return await this.abortManager.runWithAbortController(msg.requestId, (abortController) =>
this.main.fido2ClientService.assertCredential(msg.data, sender.tab, abortController)
return await this.abortManager.runWithAbortController(
msg.requestId,
async (abortController) => {
try {
return await this.main.fido2ClientService.assertCredential(
msg.data,
sender.tab,
abortController
);
} finally {
await BrowserApi.focusTab(sender.tab.id);
await BrowserApi.focusWindow(sender.tab.windowId);
}
}
);
}
}

View File

@ -157,18 +157,24 @@ function isWebauthnCall(options?: CredentialCreationOptions | CredentialRequestO
* Wait for window to be focused.
* Safari doesn't allow scripts to trigger webauthn when window is not focused.
*
* @param fallbackWait How long to wait when the script is not able to add event listeners to `window.top`. Defaults to 500ms.
* @param timeout Maximum time to wait for focus in milliseconds. Defaults to 5 minutes.
* @returns Promise that resolves when window is focused, or rejects if timeout is reached.
*/
async function waitForFocus(timeout: number = 5 * 60 * 1000) {
if (window.top.document.hasFocus()) {
return;
async function waitForFocus(fallbackWait = 500, timeout = 5 * 60 * 1000) {
try {
if (window.top.document.hasFocus()) {
return;
}
} catch {
// Cannot access window.top due to cross-origin frame, fallback to waiting
return await new Promise((resolve) => window.setTimeout(resolve, fallbackWait));
}
let focusListener;
const focusPromise = new Promise<void>((resolve) => {
focusListener = () => resolve();
window.top.addEventListener("focus", focusListener, { once: true });
window.top.addEventListener("focus", focusListener);
});
let timeoutId;