Files
nixos/.config/chromium-backup/Default/Extensions/nngceckbapebfimnlniiiahkandclblb/2025.12.1_0/content/fido2-page-script.js
Melvin Ragusa d3d7242351 add: .config
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 14:58:13 +01:00

640 lines
28 KiB
JavaScript

/******/ (function() { // webpackBootstrap
/******/ "use strict";
;// ../../libs/common/src/platform/services/fido2/fido2-utils.ts
// @ts-strict-ignore
class Fido2Utils {
static createResultToJson(result) {
return {
id: result.credentialId,
rawId: result.credentialId,
response: {
clientDataJSON: result.clientDataJSON,
authenticatorData: result.authData,
transports: result.transports,
publicKey: result.publicKey,
publicKeyAlgorithm: result.publicKeyAlgorithm,
attestationObject: result.attestationObject,
},
authenticatorAttachment: "platform",
clientExtensionResults: result.extensions,
type: "public-key",
};
}
static getResultToJson(result) {
return {
id: result.credentialId,
rawId: result.credentialId,
response: {
clientDataJSON: result.clientDataJSON,
authenticatorData: result.authenticatorData,
signature: result.signature,
userHandle: result.userHandle,
},
authenticatorAttachment: "platform",
clientExtensionResults: {},
type: "public-key",
};
}
static bufferToString(bufferSource) {
return Fido2Utils.fromBufferToB64(Fido2Utils.bufferSourceToUint8Array(bufferSource))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
}
static stringToBuffer(str) {
return Fido2Utils.fromB64ToArray(Fido2Utils.fromUrlB64ToB64(str)).buffer;
}
static bufferSourceToUint8Array(bufferSource) {
if (Fido2Utils.isArrayBuffer(bufferSource)) {
return new Uint8Array(bufferSource);
}
else {
return new Uint8Array(bufferSource.buffer, bufferSource.byteOffset, bufferSource.byteLength);
}
}
/** Utility function to identify type of bufferSource. Necessary because of differences between runtimes */
static isArrayBuffer(bufferSource) {
return bufferSource instanceof ArrayBuffer || bufferSource.buffer === undefined;
}
static fromB64toUrlB64(b64Str) {
return b64Str.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
}
static fromBufferToB64(buffer) {
if (buffer == null) {
return null;
}
let binary = "";
const bytes = new Uint8Array(buffer);
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i]);
}
return globalThis.btoa(binary);
}
static fromB64ToArray(str) {
if (str == null) {
return null;
}
const binaryString = globalThis.atob(str);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes;
}
static fromUrlB64ToB64(urlB64Str) {
let output = urlB64Str.replace(/-/g, "+").replace(/_/g, "/");
switch (output.length % 4) {
case 0:
break;
case 2:
output += "==";
break;
case 3:
output += "=";
break;
default:
throw new Error("Illegal base64url string!");
}
return output;
}
/**
* This methods returns true if a cipher either has no passkeys, or has a passkey matching with userHandle
* @param userHandle
*/
static cipherHasNoOtherPasskeys(cipher, userHandle) {
if (cipher.login.fido2Credentials == null || cipher.login.fido2Credentials.length === 0) {
return true;
}
return cipher.login.fido2Credentials.some((passkey) => passkey.userHandle === userHandle);
}
}
;// ./src/autofill/fido2/utils/webauthn-utils.ts
class WebauthnUtils {
static mapCredentialCreationOptions(options, fallbackSupported) {
var _a, _b, _c, _d, _e;
const keyOptions = options.publicKey;
if (keyOptions == undefined) {
throw new Error("Public-key options not found");
}
return {
attestation: keyOptions.attestation,
authenticatorSelection: {
requireResidentKey: (_a = keyOptions.authenticatorSelection) === null || _a === void 0 ? void 0 : _a.requireResidentKey,
residentKey: (_b = keyOptions.authenticatorSelection) === null || _b === void 0 ? void 0 : _b.residentKey,
userVerification: (_c = keyOptions.authenticatorSelection) === null || _c === void 0 ? void 0 : _c.userVerification,
},
challenge: Fido2Utils.bufferToString(keyOptions.challenge),
excludeCredentials: (_d = keyOptions.excludeCredentials) === null || _d === void 0 ? void 0 : _d.map((credential) => ({
id: Fido2Utils.bufferToString(credential.id),
transports: credential.transports,
type: credential.type,
})),
extensions: {
credProps: (_e = keyOptions.extensions) === null || _e === void 0 ? void 0 : _e.credProps,
},
pubKeyCredParams: keyOptions.pubKeyCredParams
.map((params) => ({
// Fix for spec-deviation: Sites using KeycloakJS send `kp.alg` as a string
alg: Number(params.alg),
type: params.type,
}))
.filter((params) => !isNaN(params.alg)),
rp: {
id: keyOptions.rp.id,
name: keyOptions.rp.name,
},
user: {
id: Fido2Utils.bufferToString(keyOptions.user.id),
displayName: keyOptions.user.displayName,
name: keyOptions.user.name,
},
timeout: keyOptions.timeout,
fallbackSupported,
};
}
static mapCredentialRegistrationResult(result) {
const credential = {
id: result.credentialId,
rawId: Fido2Utils.stringToBuffer(result.credentialId),
type: "public-key",
authenticatorAttachment: "platform",
response: {
clientDataJSON: Fido2Utils.stringToBuffer(result.clientDataJSON),
attestationObject: Fido2Utils.stringToBuffer(result.attestationObject),
getAuthenticatorData() {
return Fido2Utils.stringToBuffer(result.authData);
},
getPublicKey() {
return Fido2Utils.stringToBuffer(result.publicKey);
},
getPublicKeyAlgorithm() {
return result.publicKeyAlgorithm;
},
getTransports() {
return result.transports;
},
},
getClientExtensionResults: () => ({
credProps: result.extensions.credProps,
}),
toJSON: () => Fido2Utils.createResultToJson(result),
};
// Modify prototype chains to fix `instanceof` calls.
// This makes these objects indistinguishable from the native classes.
// Unfortunately PublicKeyCredential does not have a javascript constructor so `extends` does not work here.
Object.setPrototypeOf(credential.response, AuthenticatorAttestationResponse.prototype);
Object.setPrototypeOf(credential, PublicKeyCredential.prototype);
return credential;
}
static mapCredentialRequestOptions(options, fallbackSupported) {
var _a, _b;
const keyOptions = options.publicKey;
if (keyOptions == undefined) {
throw new Error("Public-key options not found");
}
return {
allowedCredentialIds: (_b = (_a = keyOptions.allowCredentials) === null || _a === void 0 ? void 0 : _a.map((c) => Fido2Utils.bufferToString(c.id))) !== null && _b !== void 0 ? _b : [],
challenge: Fido2Utils.bufferToString(keyOptions.challenge),
rpId: keyOptions.rpId,
userVerification: keyOptions.userVerification,
timeout: keyOptions.timeout,
mediation: options.mediation,
fallbackSupported,
};
}
static mapCredentialAssertResult(result) {
const credential = {
id: result.credentialId,
rawId: Fido2Utils.stringToBuffer(result.credentialId),
type: "public-key",
response: {
authenticatorData: Fido2Utils.stringToBuffer(result.authenticatorData),
clientDataJSON: Fido2Utils.stringToBuffer(result.clientDataJSON),
signature: Fido2Utils.stringToBuffer(result.signature),
userHandle: Fido2Utils.stringToBuffer(result.userHandle),
},
getClientExtensionResults: () => ({}),
authenticatorAttachment: "platform",
toJSON: () => Fido2Utils.getResultToJson(result),
};
// Modify prototype chains to fix `instanceof` calls.
// This makes these objects indistinguishable from the native classes.
// Unfortunately PublicKeyCredential does not have a javascript constructor so `extends` does not work here.
Object.setPrototypeOf(credential.response, AuthenticatorAssertionResponse.prototype);
Object.setPrototypeOf(credential, PublicKeyCredential.prototype);
return credential;
}
}
;// ./src/autofill/fido2/content/messaging/message.ts
const MessageTypes = {
CredentialCreationRequest: 0,
CredentialCreationResponse: 1,
CredentialGetRequest: 2,
CredentialGetResponse: 3,
AbortRequest: 4,
DisconnectRequest: 5,
ReconnectRequest: 6,
AbortResponse: 7,
ErrorResponse: 8,
};
;// ./src/autofill/fido2/content/messaging/messenger.ts
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
const SENDER = "bitwarden-webauthn";
/**
* A class that handles communication between the page and content script. It converts
* the browser's broadcasting API into a request/response API with support for seamlessly
* handling aborts and exceptions across separate execution contexts.
*/
class Messenger {
/**
* Creates a messenger that uses the browser's `window.postMessage` API to initiate
* requests in the content script. Every request will then create it's own
* `MessageChannel` through which all subsequent communication will be sent through.
*
* @param window the window object to use for communication
* @returns a `Messenger` instance
*/
static forDOMCommunication(window) {
const windowOrigin = window.location.origin;
return new Messenger({
postMessage: (message, port) => window.postMessage(message, windowOrigin, [port]),
addEventListener: (listener) => window.addEventListener("message", listener),
removeEventListener: (listener) => window.removeEventListener("message", listener),
});
}
constructor(broadcastChannel) {
this.broadcastChannel = broadcastChannel;
this.messageEventListener = null;
this.onDestroy = new EventTarget();
this.messengerId = this.generateUniqueId();
this.messageEventListener = this.createMessageEventListener();
this.broadcastChannel.addEventListener(this.messageEventListener);
}
/**
* Sends a request to the content script and returns the response.
* AbortController signals will be forwarded to the content script.
*
* @param request data to send to the content script
* @param abortSignal the abort controller that might be used to abort the request
* @returns the response from the content script
*/
request(request, abortSignal) {
return __awaiter(this, void 0, void 0, function* () {
const requestChannel = new MessageChannel();
const { port1: localPort, port2: remotePort } = requestChannel;
try {
const promise = new Promise((resolve) => {
localPort.onmessage = (event) => resolve(event.data);
});
const abortListener = () => localPort.postMessage({
metadata: { SENDER },
type: MessageTypes.AbortRequest,
});
abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.addEventListener("abort", abortListener);
this.broadcastChannel.postMessage(Object.assign(Object.assign({}, request), { SENDER, senderId: this.messengerId }), remotePort);
const response = yield promise;
abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.removeEventListener("abort", abortListener);
if (response.type === MessageTypes.ErrorResponse) {
const error = new Error();
Object.assign(error, JSON.parse(response.error));
throw error;
}
return response;
}
finally {
localPort.close();
}
});
}
createMessageEventListener() {
return (event) => __awaiter(this, void 0, void 0, function* () {
var _a;
const windowOrigin = window.location.origin;
if (event.origin !== windowOrigin || !this.handler) {
return;
}
const message = event.data;
const port = (_a = event.ports) === null || _a === void 0 ? void 0 : _a[0];
if ((message === null || message === void 0 ? void 0 : message.SENDER) !== SENDER || message.senderId == this.messengerId || port == null) {
return;
}
const abortController = new AbortController();
port.onmessage = (event) => {
if (event.data.type === MessageTypes.AbortRequest) {
abortController.abort();
}
};
const onDestroyListener = () => abortController.abort();
this.onDestroy.addEventListener("destroy", onDestroyListener);
try {
const handlerResponse = yield this.handler(message, abortController);
port.postMessage(Object.assign(Object.assign({}, handlerResponse), { SENDER }));
}
catch (error) {
port.postMessage({
SENDER,
type: MessageTypes.ErrorResponse,
error: JSON.stringify(error, Object.getOwnPropertyNames(error)),
});
}
finally {
this.onDestroy.removeEventListener("destroy", onDestroyListener);
port.close();
}
});
}
/**
* Cleans up the messenger by removing the message event listener
*/
destroy() {
return __awaiter(this, void 0, void 0, function* () {
this.onDestroy.dispatchEvent(new Event("destroy"));
if (this.messageEventListener) {
yield this.sendDisconnectCommand();
this.broadcastChannel.removeEventListener(this.messageEventListener);
this.messageEventListener = null;
}
});
}
sendDisconnectCommand() {
return __awaiter(this, void 0, void 0, function* () {
yield this.request({ type: MessageTypes.DisconnectRequest });
});
}
generateUniqueId() {
return Date.now().toString(36) + Math.random().toString(36).substring(2);
}
}
;// ./src/autofill/fido2/content/fido2-page-script.ts
var fido2_page_script_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
(function (globalContext) {
if (globalContext.document.currentScript) {
globalContext.document.currentScript.parentNode.removeChild(globalContext.document.currentScript);
}
const shouldExecuteContentScript = globalContext.document.contentType === "text/html" &&
(globalContext.document.location.protocol === "https:" ||
(globalContext.document.location.protocol === "http:" &&
globalContext.document.location.hostname === "localhost"));
if (!shouldExecuteContentScript) {
return;
}
const BrowserPublicKeyCredential = globalContext.PublicKeyCredential;
const BrowserNavigatorCredentials = navigator.credentials;
const BrowserAuthenticatorAttestationResponse = globalContext.AuthenticatorAttestationResponse;
const browserNativeWebauthnSupport = globalContext.PublicKeyCredential != undefined;
let browserNativeWebauthnPlatformAuthenticatorSupport = false;
if (!browserNativeWebauthnSupport) {
// Polyfill webauthn support
try {
// credentials are read-only if supported, use type-casting to force assignment
navigator.credentials = {
create() {
return fido2_page_script_awaiter(this, void 0, void 0, function* () {
throw new Error("Webauthn not supported in this browser.");
});
},
get() {
return fido2_page_script_awaiter(this, void 0, void 0, function* () {
throw new Error("Webauthn not supported in this browser.");
});
},
};
globalContext.PublicKeyCredential = class PolyfillPublicKeyCredential {
static isUserVerifyingPlatformAuthenticatorAvailable() {
return Promise.resolve(true);
}
};
globalContext.AuthenticatorAttestationResponse =
class PolyfillAuthenticatorAttestationResponse {
};
}
catch (_a) {
/* empty */
}
}
else {
void BrowserPublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable().then((available) => {
browserNativeWebauthnPlatformAuthenticatorSupport = available;
if (!available) {
// Polyfill platform authenticator support
globalContext.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable = () => Promise.resolve(true);
}
});
}
const browserCredentials = {
create: navigator.credentials.create.bind(navigator.credentials),
get: navigator.credentials.get.bind(navigator.credentials),
};
const messenger = Messenger.forDOMCommunication(window);
let waitForFocusTimeout;
let focusListenerHandler;
navigator.credentials.create = createWebAuthnCredential;
navigator.credentials.get = getWebAuthnCredential;
/**
* Creates a new webauthn credential.
*
* @param options Options for creating new credentials.
* @returns Promise that resolves to the new credential object.
*/
function createWebAuthnCredential(options) {
return fido2_page_script_awaiter(this, void 0, void 0, function* () {
var _a, _b;
if (!isWebauthnCall(options)) {
return yield browserCredentials.create(options);
}
const authenticatorAttachmentIsPlatform = ((_b = (_a = options === null || options === void 0 ? void 0 : options.publicKey) === null || _a === void 0 ? void 0 : _a.authenticatorSelection) === null || _b === void 0 ? void 0 : _b.authenticatorAttachment) === "platform";
const fallbackSupported = (authenticatorAttachmentIsPlatform && browserNativeWebauthnPlatformAuthenticatorSupport) ||
(!authenticatorAttachmentIsPlatform && browserNativeWebauthnSupport);
try {
const response = yield messenger.request({
type: MessageTypes.CredentialCreationRequest,
data: WebauthnUtils.mapCredentialCreationOptions(options, fallbackSupported),
}, options === null || options === void 0 ? void 0 : options.signal);
if (response.type !== MessageTypes.CredentialCreationResponse) {
throw new Error("Something went wrong.");
}
return WebauthnUtils.mapCredentialRegistrationResult(response.result);
}
catch (error) {
if (error && error.fallbackRequested && fallbackSupported) {
yield waitForFocus();
return yield browserCredentials.create(options);
}
throw error;
}
});
}
/**
* Retrieves a webauthn credential.
*
* @param options Options for creating new credentials.
* @returns Promise that resolves to the new credential object.
*/
function getWebAuthnCredential(options) {
return fido2_page_script_awaiter(this, void 0, void 0, function* () {
if (!isWebauthnCall(options)) {
return yield browserCredentials.get(options);
}
const abortSignal = (options === null || options === void 0 ? void 0 : options.signal) || new AbortController().signal;
const fallbackSupported = browserNativeWebauthnSupport;
if ((options === null || options === void 0 ? void 0 : options.mediation) && options.mediation === "conditional") {
const internalAbortControllers = [new AbortController(), new AbortController()];
const bitwardenResponse = (internalAbortController) => fido2_page_script_awaiter(this, void 0, void 0, function* () {
try {
const abortListener = () => messenger.request({
type: MessageTypes.AbortRequest,
abortedRequestId: abortSignal.toString(),
});
internalAbortController.signal.addEventListener("abort", abortListener);
const response = yield messenger.request({
type: MessageTypes.CredentialGetRequest,
data: WebauthnUtils.mapCredentialRequestOptions(options, fallbackSupported),
}, internalAbortController.signal);
internalAbortController.signal.removeEventListener("abort", abortListener);
if (response.type !== MessageTypes.CredentialGetResponse) {
throw new Error("Something went wrong.");
}
return WebauthnUtils.mapCredentialAssertResult(response.result);
}
catch (_a) {
// Ignoring error
}
});
const browserResponse = (internalAbortController) => browserCredentials.get(Object.assign(Object.assign({}, options), { signal: internalAbortController.signal }));
const abortListener = () => {
internalAbortControllers.forEach((controller) => controller.abort());
};
abortSignal.addEventListener("abort", abortListener);
const response = yield Promise.race([
bitwardenResponse(internalAbortControllers[0]),
browserResponse(internalAbortControllers[1]),
]);
abortSignal.removeEventListener("abort", abortListener);
internalAbortControllers.forEach((controller) => controller.abort());
return response;
}
try {
const response = yield messenger.request({
type: MessageTypes.CredentialGetRequest,
data: WebauthnUtils.mapCredentialRequestOptions(options, fallbackSupported),
}, options === null || options === void 0 ? void 0 : options.signal);
if (response.type !== MessageTypes.CredentialGetResponse) {
throw new Error("Something went wrong.");
}
return WebauthnUtils.mapCredentialAssertResult(response.result);
}
catch (error) {
if (error && error.fallbackRequested && fallbackSupported) {
yield waitForFocus();
return yield browserCredentials.get(options);
}
throw error;
}
});
}
function isWebauthnCall(options) {
return options && "publicKey" in options;
}
/**
* 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.
*/
function waitForFocus() {
return fido2_page_script_awaiter(this, arguments, void 0, function* (fallbackWait = 500, timeout = 5 * 60 * 1000) {
try {
if (globalContext.top.document.hasFocus()) {
return;
}
}
catch (_a) {
// Cannot access window.top due to cross-origin frame, fallback to waiting
return yield new Promise((resolve) => globalContext.setTimeout(resolve, fallbackWait));
}
const focusPromise = new Promise((resolve) => {
focusListenerHandler = () => resolve();
globalContext.top.addEventListener("focus", focusListenerHandler);
});
const timeoutPromise = new Promise((_, reject) => {
waitForFocusTimeout = globalContext.setTimeout(() => reject(new DOMException("The operation either timed out or was not allowed.", "AbortError")), timeout);
});
try {
yield Promise.race([focusPromise, timeoutPromise]);
}
finally {
clearWaitForFocus();
}
});
}
function clearWaitForFocus() {
globalContext.top.removeEventListener("focus", focusListenerHandler);
if (waitForFocusTimeout) {
globalContext.clearTimeout(waitForFocusTimeout);
}
}
function destroy() {
try {
if (browserNativeWebauthnSupport) {
navigator.credentials.create = browserCredentials.create;
navigator.credentials.get = browserCredentials.get;
}
else {
navigator.credentials = BrowserNavigatorCredentials;
globalContext.PublicKeyCredential = BrowserPublicKeyCredential;
globalContext.AuthenticatorAttestationResponse = BrowserAuthenticatorAttestationResponse;
}
clearWaitForFocus();
void messenger.destroy();
}
catch (_a) {
/** empty */
}
}
/**
* Sets up a listener to handle cleanup or reconnection when the extension's
* context changes due to being reloaded or unloaded.
*/
messenger.handler = (message) => {
const type = message.type;
// Handle cleanup for disconnect request
if (type === MessageTypes.DisconnectRequest) {
destroy();
}
};
})(globalThis);
/******/ })()
;