mirror of
https://github.com/keepassxreboot/keepassxc-browser.git
synced 2026-03-11 08:54:43 +00:00
Passkeys: Wrap response to PublicKeyCredential
This commit is contained in:
parent
1ccfbff792
commit
cc6d9cde69
3 changed files with 61 additions and 60 deletions
|
|
@ -838,10 +838,7 @@ kpxc.enablePasskeys = function() {
|
|||
let errorMessage;
|
||||
if (ret.response && ret.response.errorCode) {
|
||||
errorMessage = await sendMessage('get_error_message', ret.response.errorCode);
|
||||
// Do not create a notification for this error
|
||||
if (ret?.response?.errorCode !== PASSKEYS_WAIT_FOR_LIFETIMER) {
|
||||
kpxcUI.createNotification('error', errorMessage);
|
||||
}
|
||||
kpxcUI.createNotification('error', errorMessage);
|
||||
|
||||
if (kpxc.settings.passkeysFallback) {
|
||||
kpxcPasskeysUtils.sendPasskeysResponse(undefined, ret.response?.errorCode, errorMessage);
|
||||
|
|
@ -850,8 +847,8 @@ kpxc.enablePasskeys = function() {
|
|||
}
|
||||
}
|
||||
|
||||
const responsePublicKey = callback(ret.response);
|
||||
kpxcPasskeysUtils.sendPasskeysResponse(responsePublicKey, ret.response?.errorCode, errorMessage);
|
||||
logDebug('Passkey response', ret.response);
|
||||
kpxcPasskeysUtils.sendPasskeysResponse(ret.response, ret.response?.errorCode, errorMessage);
|
||||
stopTimer(lifetimeTimer);
|
||||
}
|
||||
};
|
||||
|
|
@ -867,15 +864,15 @@ kpxc.enablePasskeys = function() {
|
|||
ev.detail.publicKey,
|
||||
ev.detail.sameOriginWithAncestors,
|
||||
);
|
||||
logDebug('publicKey', publicKey);
|
||||
await sendResponse('passkeys_register', publicKey, kpxcPasskeysUtils.parsePublicKeyCredential);
|
||||
logDebug('Passkey request', publicKey);
|
||||
await sendResponse('passkeys_register', publicKey);
|
||||
} else if (ev.detail.action === 'passkeys_get') {
|
||||
const publicKey = kpxcPasskeysUtils.buildCredentialRequestOptions(
|
||||
ev.detail.publicKey,
|
||||
ev.detail.sameOriginWithAncestors,
|
||||
);
|
||||
logDebug('publicKey', publicKey);
|
||||
await sendResponse('passkeys_get', publicKey, kpxcPasskeysUtils.parseGetPublicKeyCredential);
|
||||
logDebug('Passkey request', publicKey);
|
||||
await sendResponse('passkeys_get', publicKey);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,16 +4,6 @@ const MINIMUM_TIMEOUT = 15000;
|
|||
const DEFAULT_TIMEOUT = 30000;
|
||||
const DISCOURAGED_TIMEOUT = 120000;
|
||||
|
||||
const stringToArrayBuffer = function(str) {
|
||||
const arr = Uint8Array.from(str, c => c.charCodeAt(0));
|
||||
return arr.buffer;
|
||||
};
|
||||
|
||||
// From URL encoded base64 string to ArrayBuffer
|
||||
const base64ToArrayBuffer = function(str) {
|
||||
return stringToArrayBuffer(window.atob(str.replaceAll('-', '+').replaceAll('_', '/')));
|
||||
};
|
||||
|
||||
// From ArrayBuffer to URL encoded base64 string
|
||||
const arrayBufferToBase64 = function(buf) {
|
||||
const str = [ ...new Uint8Array(buf) ].map(c => String.fromCharCode(c)).join('');
|
||||
|
|
@ -158,36 +148,3 @@ kpxcPasskeysUtils.buildCredentialRequestOptions = function(pkOptions, sameOrigin
|
|||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Parse register response back from base64 strings to ByteArrays
|
||||
kpxcPasskeysUtils.parsePublicKeyCredential = function(publicKeyCredential) {
|
||||
if (!publicKeyCredential || !publicKeyCredential.type) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
publicKeyCredential.rawId = base64ToArrayBuffer(publicKeyCredential.id);
|
||||
publicKeyCredential.response.attestationObject =
|
||||
base64ToArrayBuffer(publicKeyCredential.response.attestationObject);
|
||||
publicKeyCredential.response.clientDataJSON = base64ToArrayBuffer(publicKeyCredential.response.clientDataJSON);
|
||||
|
||||
return publicKeyCredential;
|
||||
};
|
||||
|
||||
// Parse authentication response back from base64 strings to ByteArrays
|
||||
kpxcPasskeysUtils.parseGetPublicKeyCredential = function(publicKeyCredential) {
|
||||
if (!publicKeyCredential || !publicKeyCredential.type) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
publicKeyCredential.rawId = base64ToArrayBuffer(publicKeyCredential.id);
|
||||
publicKeyCredential.response.authenticatorData =
|
||||
base64ToArrayBuffer(publicKeyCredential.response.authenticatorData);
|
||||
publicKeyCredential.response.clientDataJSON = base64ToArrayBuffer(publicKeyCredential.response.clientDataJSON);
|
||||
publicKeyCredential.response.signature = base64ToArrayBuffer(publicKeyCredential.response.signature);
|
||||
|
||||
if (publicKeyCredential.response.userHandle) {
|
||||
publicKeyCredential.response.userHandle = base64ToArrayBuffer(publicKeyCredential.response.userHandle);
|
||||
}
|
||||
|
||||
return publicKeyCredential;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,6 +15,58 @@ const PASSKEYS_UNKNOWN_ERROR = 31;
|
|||
const PASSKEYS_INVALID_CHALLENGE = 32;
|
||||
const PASSKEYS_INVALID_USER_ID = 33;
|
||||
|
||||
const stringToArrayBuffer = function(str) {
|
||||
const arr = Uint8Array.from(str, c => c.charCodeAt(0));
|
||||
return arr.buffer;
|
||||
};
|
||||
|
||||
// From URL encoded base64 string to ArrayBuffer
|
||||
const base64ToArrayBuffer = function(str) {
|
||||
return stringToArrayBuffer(window.atob(str?.replaceAll('-', '+').replaceAll('_', '/')));
|
||||
};
|
||||
|
||||
// Wraps response to AuthenticatorAttestationResponse object
|
||||
const createAttestationResponse = function(publicKey) {
|
||||
const response = {
|
||||
attestationObject: base64ToArrayBuffer(publicKey.response.attestationObject),
|
||||
clientDataJSON: base64ToArrayBuffer(publicKey.response.clientDataJSON),
|
||||
getAuthenticatorData: () => base64ToArrayBuffer(publicKey.response?.authenticatorData),
|
||||
getTransports: () => [ 'internal' ]
|
||||
};
|
||||
|
||||
return Object.setPrototypeOf(response, AuthenticatorAttestationResponse.prototype);
|
||||
};
|
||||
|
||||
// Wraps response to AuthenticatorAssertionResponse object
|
||||
const createAssertionResponse = function(publicKey) {
|
||||
const response = {
|
||||
authenticatorData: base64ToArrayBuffer(publicKey.response?.authenticatorData),
|
||||
clientDataJSON: base64ToArrayBuffer(publicKey.response?.clientDataJSON),
|
||||
signature: base64ToArrayBuffer(publicKey.response?.signature),
|
||||
userHandle: publicKey.response?.userHandle ? base64ToArrayBuffer(publicKey.response?.userHandle) : null
|
||||
};
|
||||
|
||||
return Object.setPrototypeOf(response, AuthenticatorAssertionResponse.prototype);
|
||||
};
|
||||
|
||||
// Wraps public key to PublicKeyCredential object
|
||||
const createPublicKeyCredential = function(publicKey) {
|
||||
const authenticatorResponse = publicKey?.response?.attestationObject
|
||||
? createAttestationResponse(publicKey)
|
||||
: createAssertionResponse(publicKey);
|
||||
const publicKeyCredential = {
|
||||
authenticatorAttachment: publicKey.authenticatorAttachment,
|
||||
id: publicKey.id,
|
||||
rawId: base64ToArrayBuffer(publicKey.id),
|
||||
response: authenticatorResponse,
|
||||
type: publicKey.type,
|
||||
clientExtensionResults: () => publicKey?.response?.clientExtensionResults || {},
|
||||
getClientExtensionResults: () => publicKey?.response?.clientExtensionResults || {}
|
||||
};
|
||||
|
||||
return Object.setPrototypeOf(publicKeyCredential, PublicKeyCredential.prototype);
|
||||
};
|
||||
|
||||
// Posts a message to extension's content script and waits for response
|
||||
const postMessageToExtension = function(request) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
@ -109,10 +161,7 @@ const throwError = function(errorCode, errorMessage) {
|
|||
return response.fallback ? originalCredentials.create(options) : null;
|
||||
}
|
||||
|
||||
response.publicKey.getClientExtensionResults = () => {};
|
||||
response.publicKey.clientExtensionResults = () => {};
|
||||
response.publicKey.response.getTransports = () => [];
|
||||
return response.publicKey;
|
||||
return createPublicKeyCredential(response.publicKey);
|
||||
},
|
||||
async get(options) {
|
||||
if (!options.publicKey || options?.mediation === 'silent') {
|
||||
|
|
@ -137,9 +186,7 @@ const throwError = function(errorCode, errorMessage) {
|
|||
return response.fallback ? originalCredentials.get(options) : null;
|
||||
}
|
||||
|
||||
response.publicKey.getClientExtensionResults = () => {};
|
||||
response.publicKey.clientExtensionResults = () => {};
|
||||
return response.publicKey;
|
||||
return createPublicKeyCredential(response.publicKey);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue