mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 00:33:44 +00:00
[EC-598] feat: add logging to fido2 client
This commit is contained in:
@@ -507,7 +507,10 @@ export default class MainBackground {
|
|||||||
this.fido2UserInterfaceService,
|
this.fido2UserInterfaceService,
|
||||||
this.logService
|
this.logService
|
||||||
);
|
);
|
||||||
this.fido2ClientService = new Fido2ClientService(this.fido2AuthenticatorService);
|
this.fido2ClientService = new Fido2ClientService(
|
||||||
|
this.fido2AuthenticatorService,
|
||||||
|
this.logService
|
||||||
|
);
|
||||||
|
|
||||||
const systemUtilsServiceReloadCallback = () => {
|
const systemUtilsServiceReloadCallback = () => {
|
||||||
const forceWindowReload =
|
const forceWindowReload =
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { parse } from "tldts";
|
import { parse } from "tldts";
|
||||||
|
|
||||||
|
import { LogService } from "../../abstractions/log.service";
|
||||||
import { Utils } from "../../misc/utils";
|
import { Utils } from "../../misc/utils";
|
||||||
import {
|
import {
|
||||||
Fido2AutenticatorError,
|
Fido2AutenticatorError,
|
||||||
@@ -25,18 +26,24 @@ import { Fido2Utils } from "../abstractions/fido2-utils";
|
|||||||
import { isValidRpId } from "./domain-utils";
|
import { isValidRpId } from "./domain-utils";
|
||||||
|
|
||||||
export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
||||||
constructor(private authenticator: Fido2AuthenticatorService) {}
|
constructor(private authenticator: Fido2AuthenticatorService, private logService?: LogService) {}
|
||||||
|
|
||||||
async createCredential(
|
async createCredential(
|
||||||
params: CreateCredentialParams,
|
params: CreateCredentialParams,
|
||||||
abortController = new AbortController()
|
abortController = new AbortController()
|
||||||
): Promise<CreateCredentialResult> {
|
): Promise<CreateCredentialResult> {
|
||||||
if (!params.sameOriginWithAncestors) {
|
if (!params.sameOriginWithAncestors) {
|
||||||
|
this.logService?.warning(
|
||||||
|
`[Fido2Client] Invalid 'sameOriginWithAncestors' value: ${params.sameOriginWithAncestors}`
|
||||||
|
);
|
||||||
throw new DOMException("Invalid 'sameOriginWithAncestors' value", "NotAllowedError");
|
throw new DOMException("Invalid 'sameOriginWithAncestors' value", "NotAllowedError");
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = Fido2Utils.stringToBuffer(params.user.id);
|
const userId = Fido2Utils.stringToBuffer(params.user.id);
|
||||||
if (userId.length < 1 || userId.length > 64) {
|
if (userId.length < 1 || userId.length > 64) {
|
||||||
|
this.logService?.warning(
|
||||||
|
`[Fido2Client] Invalid 'user.id' length: ${params.user.id} (${userId.length})`
|
||||||
|
);
|
||||||
throw new TypeError("Invalid 'user.id' length");
|
throw new TypeError("Invalid 'user.id' length");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,10 +51,14 @@ export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
|||||||
const rpId = params.rp.id ?? parsedOrigin.hostname;
|
const rpId = params.rp.id ?? parsedOrigin.hostname;
|
||||||
|
|
||||||
if (parsedOrigin.hostname == undefined || !params.origin.startsWith("https://")) {
|
if (parsedOrigin.hostname == undefined || !params.origin.startsWith("https://")) {
|
||||||
|
this.logService?.warning(`[Fido2Client] Invalid https origin: ${params.origin}`);
|
||||||
throw new DOMException("'origin' is not a valid https origin", "SecurityError");
|
throw new DOMException("'origin' is not a valid https origin", "SecurityError");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isValidRpId(rpId, params.origin)) {
|
if (!isValidRpId(rpId, params.origin)) {
|
||||||
|
this.logService?.warning(
|
||||||
|
`[Fido2Client] 'rp.id' cannot be used with the current origin: rp.id = ${rpId}; origin = ${params.origin}`
|
||||||
|
);
|
||||||
throw new DOMException("'rp.id' cannot be used with the current origin", "SecurityError");
|
throw new DOMException("'rp.id' cannot be used with the current origin", "SecurityError");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +75,10 @@ export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (credTypesAndPubKeyAlgs.length === 0) {
|
if (credTypesAndPubKeyAlgs.length === 0) {
|
||||||
|
const requestedAlgorithms = credTypesAndPubKeyAlgs.map((p) => p.alg).join(", ");
|
||||||
|
this.logService?.warning(
|
||||||
|
`[Fido2Client] No compatible algorithms found, RP requested: ${requestedAlgorithms}`
|
||||||
|
);
|
||||||
throw new DOMException("No supported key algorithms were found", "NotSupportedError");
|
throw new DOMException("No supported key algorithms were found", "NotSupportedError");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +93,7 @@ export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
|||||||
const clientDataJSONBytes = Utils.fromByteStringToArray(clientDataJSON);
|
const clientDataJSONBytes = Utils.fromByteStringToArray(clientDataJSON);
|
||||||
const clientDataHash = await crypto.subtle.digest({ name: "SHA-256" }, clientDataJSONBytes);
|
const clientDataHash = await crypto.subtle.digest({ name: "SHA-256" }, clientDataJSONBytes);
|
||||||
if (abortController.signal.aborted) {
|
if (abortController.signal.aborted) {
|
||||||
|
this.logService?.info(`[Fido2Client] Aborted with AbortController`);
|
||||||
throw new DOMException(undefined, "AbortError");
|
throw new DOMException(undefined, "AbortError");
|
||||||
}
|
}
|
||||||
const timeout = setAbortTimeout(
|
const timeout = setAbortTimeout(
|
||||||
@@ -123,6 +139,7 @@ export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
|||||||
abortController.signal.aborted &&
|
abortController.signal.aborted &&
|
||||||
abortController.signal.reason === UserRequestedFallbackAbortReason
|
abortController.signal.reason === UserRequestedFallbackAbortReason
|
||||||
) {
|
) {
|
||||||
|
this.logService?.info(`[Fido2Client] Aborting because user requested fallback`);
|
||||||
throw new FallbackRequestedError();
|
throw new FallbackRequestedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,13 +147,16 @@ export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
|||||||
error instanceof Fido2AutenticatorError &&
|
error instanceof Fido2AutenticatorError &&
|
||||||
error.errorCode === Fido2AutenticatorErrorCode.InvalidState
|
error.errorCode === Fido2AutenticatorErrorCode.InvalidState
|
||||||
) {
|
) {
|
||||||
|
this.logService?.warning(`[Fido2Client] Unknown error: ${error}`);
|
||||||
throw new DOMException(undefined, "InvalidStateError");
|
throw new DOMException(undefined, "InvalidStateError");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.logService?.info(`[Fido2Client] Aborted by user: ${error}`);
|
||||||
throw new DOMException(undefined, "NotAllowedError");
|
throw new DOMException(undefined, "NotAllowedError");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abortController.signal.aborted) {
|
if (abortController.signal.aborted) {
|
||||||
|
this.logService?.info(`[Fido2Client] Aborted with AbortController`);
|
||||||
throw new DOMException(undefined, "AbortError");
|
throw new DOMException(undefined, "AbortError");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,6 +177,7 @@ export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
|||||||
): Promise<AssertCredentialResult> {
|
): Promise<AssertCredentialResult> {
|
||||||
const { domain: effectiveDomain } = parse(params.origin, { allowPrivateDomains: true });
|
const { domain: effectiveDomain } = parse(params.origin, { allowPrivateDomains: true });
|
||||||
if (effectiveDomain == undefined) {
|
if (effectiveDomain == undefined) {
|
||||||
|
this.logService?.warning(`[Fido2Client] Invalid origin: ${params.origin}`);
|
||||||
throw new DOMException("'origin' is not a valid domain", "SecurityError");
|
throw new DOMException("'origin' is not a valid domain", "SecurityError");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,10 +185,14 @@ export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
|||||||
const rpId = params.rpId ?? parsedOrigin.hostname;
|
const rpId = params.rpId ?? parsedOrigin.hostname;
|
||||||
|
|
||||||
if (parsedOrigin.hostname == undefined || !params.origin.startsWith("https://")) {
|
if (parsedOrigin.hostname == undefined || !params.origin.startsWith("https://")) {
|
||||||
|
this.logService?.warning(`[Fido2Client] Invalid https origin: ${params.origin}`);
|
||||||
throw new DOMException("'origin' is not a valid https origin", "SecurityError");
|
throw new DOMException("'origin' is not a valid https origin", "SecurityError");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isValidRpId(rpId, params.origin)) {
|
if (!isValidRpId(rpId, params.origin)) {
|
||||||
|
this.logService?.warning(
|
||||||
|
`[Fido2Client] 'rp.id' cannot be used with the current origin: rp.id = ${rpId}; origin = ${params.origin}`
|
||||||
|
);
|
||||||
throw new DOMException("'rp.id' cannot be used with the current origin", "SecurityError");
|
throw new DOMException("'rp.id' cannot be used with the current origin", "SecurityError");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,6 +208,7 @@ export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
|||||||
const clientDataHash = await crypto.subtle.digest({ name: "SHA-256" }, clientDataJSONBytes);
|
const clientDataHash = await crypto.subtle.digest({ name: "SHA-256" }, clientDataJSONBytes);
|
||||||
|
|
||||||
if (abortController.signal.aborted) {
|
if (abortController.signal.aborted) {
|
||||||
|
this.logService?.info(`[Fido2Client] Aborted with AbortController`);
|
||||||
throw new DOMException(undefined, "AbortError");
|
throw new DOMException(undefined, "AbortError");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,6 +239,7 @@ export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
|||||||
abortController.signal.aborted &&
|
abortController.signal.aborted &&
|
||||||
abortController.signal.reason === UserRequestedFallbackAbortReason
|
abortController.signal.reason === UserRequestedFallbackAbortReason
|
||||||
) {
|
) {
|
||||||
|
this.logService?.info(`[Fido2Client] Aborting because user requested fallback`);
|
||||||
throw new FallbackRequestedError();
|
throw new FallbackRequestedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,12 +247,16 @@ export class Fido2ClientService implements Fido2ClientServiceAbstraction {
|
|||||||
error instanceof Fido2AutenticatorError &&
|
error instanceof Fido2AutenticatorError &&
|
||||||
error.errorCode === Fido2AutenticatorErrorCode.InvalidState
|
error.errorCode === Fido2AutenticatorErrorCode.InvalidState
|
||||||
) {
|
) {
|
||||||
|
this.logService?.warning(`[Fido2Client] Unknown error: ${error}`);
|
||||||
throw new DOMException(undefined, "InvalidStateError");
|
throw new DOMException(undefined, "InvalidStateError");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.logService?.info(`[Fido2Client] Aborted by user: ${error}`);
|
||||||
throw new DOMException(undefined, "NotAllowedError");
|
throw new DOMException(undefined, "NotAllowedError");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abortController.signal.aborted) {
|
if (abortController.signal.aborted) {
|
||||||
|
this.logService?.info(`[Fido2Client] Aborted with AbortController`);
|
||||||
throw new DOMException(undefined, "AbortError");
|
throw new DOMException(undefined, "AbortError");
|
||||||
}
|
}
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
|
|||||||
Reference in New Issue
Block a user