1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 00:33:44 +00:00

[EC-598] feat: implement full support for timeouts

This commit is contained in:
Andreas Coroiu
2023-02-10 16:02:40 +01:00
parent 158d1fbe01
commit 1a034ea26e
2 changed files with 44 additions and 10 deletions

View File

@@ -1,3 +1,5 @@
export type UserVerification = "discouraged" | "preferred" | "required";
export interface CredentialRegistrationParams { export interface CredentialRegistrationParams {
origin: string; origin: string;
attestation?: "direct" | "enterprise" | "indirect" | "none"; attestation?: "direct" | "enterprise" | "indirect" | "none";
@@ -5,7 +7,7 @@ export interface CredentialRegistrationParams {
// authenticatorAttachment?: AuthenticatorAttachment; // not used // authenticatorAttachment?: AuthenticatorAttachment; // not used
requireResidentKey?: boolean; requireResidentKey?: boolean;
residentKey?: "discouraged" | "preferred" | "required"; residentKey?: "discouraged" | "preferred" | "required";
userVerification?: "discouraged" | "preferred" | "required"; userVerification?: UserVerification;
}; };
challenge: string; // b64 encoded challenge: string; // b64 encoded
excludeCredentials?: { excludeCredentials?: {
@@ -48,7 +50,7 @@ export interface CredentialAssertParams {
rpId: string; rpId: string;
origin: string; origin: string;
challenge: string; challenge: string;
userVerification?: "discouraged" | "preferred" | "required"; userVerification?: UserVerification;
timeout: number; timeout: number;
} }

View File

@@ -14,6 +14,7 @@ import {
CredentialRegistrationResult, CredentialRegistrationResult,
Fido2Service as Fido2ServiceAbstraction, Fido2Service as Fido2ServiceAbstraction,
NoCredentialFoundError, NoCredentialFoundError,
UserVerification,
} from "../abstractions/fido2.service.abstraction"; } from "../abstractions/fido2.service.abstraction";
import { Fido2KeyView } from "../models/view/fido2-key.view"; import { Fido2KeyView } from "../models/view/fido2-key.view";
@@ -23,9 +24,18 @@ import { joseToDer } from "./ecdsa-utils";
// We support self-signing, but Google won't accept it. // We support self-signing, but Google won't accept it.
// TODO: Look into supporting self-signed packed format. // TODO: Look into supporting self-signed packed format.
const STANDARD_ATTESTATION_FORMAT: "none" | "packed" = "none"; const STANDARD_ATTESTATION_FORMAT: "none" | "packed" = "none";
const DEFAULT_TIMEOUT = 120000; const TIMEOUTS = {
const MIN_TIMEOUT = 30000; NO_VERIFICATION: {
const MAX_TIMEOUT = 600000; DEFAULT: 120000,
MIN: 30000,
MAX: 180000,
},
WITH_VERIFICATION: {
DEFAULT: 300000,
MIN: 30000,
MAX: 600000,
},
};
interface BitCredential { interface BitCredential {
credentialId: CredentialId; credentialId: CredentialId;
@@ -54,7 +64,11 @@ export class Fido2Service implements Fido2ServiceAbstraction {
// Comment: Timeouts could potentially be implemented using decorators. // Comment: Timeouts could potentially be implemented using decorators.
// But since I try to use decorators a little as possible and only // But since I try to use decorators a little as possible and only
// for the most generic solutions, I'm gonne leave this as is untill peer review. // for the most generic solutions, I'm gonne leave this as is untill peer review.
const timeout = setAbortTimeout(abortController); const timeout = setAbortTimeout(
abortController,
params.authenticatorSelection.userVerification,
params.timeout
);
const presence = await this.fido2UserInterfaceService.confirmNewCredential( const presence = await this.fido2UserInterfaceService.confirmNewCredential(
{ {
@@ -139,7 +153,7 @@ export class Fido2Service implements Fido2ServiceAbstraction {
params: CredentialAssertParams, params: CredentialAssertParams,
abortController = new AbortController() abortController = new AbortController()
): Promise<CredentialAssertResult> { ): Promise<CredentialAssertResult> {
const timeout = setAbortTimeout(abortController); const timeout = setAbortTimeout(abortController, params.userVerification, params.timeout);
let credential: BitCredential | undefined; let credential: BitCredential | undefined;
if (params.allowedCredentialIds && params.allowedCredentialIds.length > 0) { if (params.allowedCredentialIds && params.allowedCredentialIds.length > 0) {
@@ -426,8 +440,26 @@ function authDataFlags(options: Flags): number {
return flags; return flags;
} }
function setAbortTimeout(abortController: AbortController, timeout = DEFAULT_TIMEOUT): number { function setAbortTimeout(
// TODO: Set different timeouts depending on `userVerification` value abortController: AbortController,
const clampedTimeout = Math.max(MIN_TIMEOUT, Math.min(timeout, MAX_TIMEOUT)); userVerification: UserVerification,
timeout?: number
): number {
let clampedTimeout: number;
if (userVerification === "discouraged") {
timeout = timeout ?? TIMEOUTS.NO_VERIFICATION.DEFAULT;
clampedTimeout = Math.max(
TIMEOUTS.NO_VERIFICATION.MIN,
Math.min(timeout, TIMEOUTS.NO_VERIFICATION.MAX)
);
} else {
timeout = timeout ?? TIMEOUTS.WITH_VERIFICATION.DEFAULT;
clampedTimeout = Math.max(
TIMEOUTS.WITH_VERIFICATION.MIN,
Math.min(timeout, TIMEOUTS.WITH_VERIFICATION.MAX)
);
}
return window.setTimeout(() => abortController.abort(), clampedTimeout); return window.setTimeout(() => abortController.abort(), clampedTimeout);
} }