Improve webauthn popup close robustness

This commit is contained in:
Leendert de Borst
2025-11-01 13:42:22 +01:00
parent 9de879a387
commit 0d62b4af55
3 changed files with 25 additions and 16 deletions

View File

@@ -27,6 +27,10 @@ import { browser, storage } from '#imports';
const pendingRequests = new Map<string, {
resolve: (value: any) => void;
reject: (error: any) => void;
/**
* Store window ID in order to close the popup window from background script later.
*/
windowId?: number;
}>();
// Store request data temporarily (to avoid URL length limits)
@@ -90,7 +94,7 @@ export async function handleWebAuthnCreate(data: any): Promise<any> {
// Wait for response from popup
return new Promise((resolve, reject) => {
pendingRequests.set(requestId, { resolve, reject });
pendingRequests.set(requestId, { resolve, reject, windowId: popup.id });
// Clean up if popup is closed without response
const checkClosed = setInterval(async () => {
@@ -149,7 +153,7 @@ export async function handleWebAuthnGet(data: any): Promise<any> {
// Wait for response from popup
return new Promise((resolve, reject) => {
pendingRequests.set(requestId, { resolve, reject });
pendingRequests.set(requestId, { resolve, reject, windowId: popup.id });
// Clean up if popup is closed without response
const checkClosed = setInterval(async () => {
@@ -185,6 +189,19 @@ export async function handlePasskeyPopupResponse(data: any): Promise<{ success:
return { success: false };
}
/**
* Close the popup window from background script to ensure it always works.
* Calling window.close() from the popup does not work in all browsers.
*/
if (request.windowId) {
try {
await browser.windows.remove(request.windowId);
} catch (error) {
// Window might already be closed, ignore error
console.debug('Failed to close popup window:', error);
}
}
// Clean up both maps
pendingRequests.delete(requestId);
pendingRequestData.delete(requestId);

View File

@@ -285,13 +285,11 @@ const PasskeyAuthenticate: React.FC = () => {
};
// Send response back
// The background script will close the window (Safari-compatible)
await sendMessage('PASSKEY_POPUP_RESPONSE', {
requestId: request.requestId,
credential
}, 'background');
// Auto-close window on success
window.close();
} catch (error) {
console.error('PasskeyAuthenticate: Error during authentication', error);
setLoading(false);
@@ -328,12 +326,11 @@ const PasskeyAuthenticate: React.FC = () => {
// For 'once', we don't store anything - just bypass this one time
// Tell background to use native implementation
// The background script will close the window (Safari-compatible)
await sendMessage('PASSKEY_POPUP_RESPONSE', {
requestId: request.requestId,
fallback: true
}, 'background');
window.close();
};
/**
@@ -345,12 +342,11 @@ const PasskeyAuthenticate: React.FC = () => {
}
// Tell background user cancelled
// The background script will close the window (Safari-compatible)
await sendMessage('PASSKEY_POPUP_RESPONSE', {
requestId: request.requestId,
cancelled: true
}, 'background');
window.close();
};
if (!request) {

View File

@@ -398,13 +398,11 @@ const PasskeyCreate: React.FC = () => {
};
// Send response back to background
// The background script will close the window (Safari-compatible)
await sendMessage('PASSKEY_POPUP_RESPONSE', {
requestId: request.requestId,
credential: flattenedCredential
}, 'background');
// Auto-close window on success
window.close();
},
/**
* onError
@@ -450,12 +448,11 @@ const PasskeyCreate: React.FC = () => {
// For 'once', we don't store anything - just bypass this one time
// Tell background to use native implementation
// The background script will close the window (Safari-compatible)
await sendMessage('PASSKEY_POPUP_RESPONSE', {
requestId: request.requestId,
fallback: true
}, 'background');
window.close();
};
/**
@@ -467,12 +464,11 @@ const PasskeyCreate: React.FC = () => {
}
// Tell background user cancelled
// The background script will close the window (Safari-compatible)
await sendMessage('PASSKEY_POPUP_RESPONSE', {
requestId: request.requestId,
cancelled: true
}, 'background');
window.close();
};
if (!request) {