diff --git a/keepassxc-browser/content/passkeys-inject.js b/keepassxc-browser/content/passkeys-inject.js index 3ffb1fb3..a43a66fe 100644 --- a/keepassxc-browser/content/passkeys-inject.js +++ b/keepassxc-browser/content/passkeys-inject.js @@ -7,7 +7,8 @@ const PASSKEYS_WAIT_FOR_LIFETIMER = 30; // Apply a script to the page for intercepting Passkeys (WebAuthn) requests const enablePasskeys = async function() { const passkeysLogDebug = function(message, extra) { - if (kpxcPasskeysUtils.debugLogging) { + // `global.js` runs at `document_idle` + if (kpxcPasskeysUtils.debugLogging && typeof debugLogMessage === 'function') { debugLogMessage(message, extra); } }; @@ -63,8 +64,21 @@ const enablePasskeys = async function() { } }; - const isSameOriginWithAncestors = function () { + /** + * @param {'create' | 'get'} action + * @returns {boolean} + */ + const isAllowedByPolicy = function (action) { + // https://www.w3.org/TR/webauthn-2/#sctn-permissions-policy + const policy = document.featurePolicy || document.permissionsPolicy; + if (policy) { + passkeysLogDebug('Checking Permissions Policy'); + return policy.allowsFeature(`publickey-credentials-${action}`); + } + + // fallback to sameOriginWithAncestors try { + passkeysLogDebug('Checking sameOriginWithAncestors'); return window.origin === window.top.origin; } catch (_err) { return false; @@ -80,14 +94,14 @@ const enablePasskeys = async function() { if (ev.detail.action === 'passkeys_create') { const publicKey = kpxcPasskeysUtils.buildCredentialCreationOptions( ev.detail.publicKey, - isSameOriginWithAncestors(), + isAllowedByPolicy('create'), ); passkeysLogDebug('Passkey request', publicKey); await sendResponse('passkeys_register', publicKey); } else if (ev.detail.action === 'passkeys_get') { const publicKey = kpxcPasskeysUtils.buildCredentialRequestOptions( ev.detail.publicKey, - isSameOriginWithAncestors(), + isAllowedByPolicy('get'), ); passkeysLogDebug('Passkey request', publicKey); await sendResponse('passkeys_get', publicKey);