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

[EC-598] feat: add automatic default timeouts

This commit is contained in:
Andreas Coroiu
2023-01-31 13:42:09 +01:00
parent c7e7ce832b
commit e981a1b0f2
2 changed files with 26 additions and 6 deletions

View File

@@ -188,4 +188,8 @@ export class BrowserFido2UserInterfaceService implements Fido2UserInterfaceServi
return false; return false;
} }
private setAbortTimeout(abortController: AbortController) {
return setTimeout(() => abortController.abort());
}
} }

View File

@@ -23,6 +23,9 @@ 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 MIN_TIMEOUT = 30000;
const MAX_TIMEOUT = 600000;
interface BitCredential { interface BitCredential {
credentialId: CredentialId; credentialId: CredentialId;
@@ -46,8 +49,13 @@ export class Fido2Service implements Fido2ServiceAbstraction {
async createCredential( async createCredential(
params: CredentialRegistrationParams, params: CredentialRegistrationParams,
abortController?: AbortController abortController = new AbortController()
): Promise<CredentialRegistrationResult> { ): Promise<CredentialRegistrationResult> {
// Comment: Timeouts could potentially be implemented using decorators.
// 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.
const timeout = setAbortTimeout(abortController);
const presence = await this.fido2UserInterfaceService.confirmNewCredential( const presence = await this.fido2UserInterfaceService.confirmNewCredential(
{ {
credentialName: params.rp.name, credentialName: params.rp.name,
@@ -115,6 +123,8 @@ export class Fido2Service implements Fido2ServiceAbstraction {
}) })
); );
clearTimeout(timeout);
return { return {
credentialId: Fido2Utils.bufferToString(credentialId.raw), credentialId: Fido2Utils.bufferToString(credentialId.raw),
clientDataJSON: Fido2Utils.bufferToString(clientData), clientDataJSON: Fido2Utils.bufferToString(clientData),
@@ -127,8 +137,9 @@ export class Fido2Service implements Fido2ServiceAbstraction {
async assertCredential( async assertCredential(
params: CredentialAssertParams, params: CredentialAssertParams,
abortController?: AbortController abortController = new AbortController()
): Promise<CredentialAssertResult> { ): Promise<CredentialAssertResult> {
const timeout = setAbortTimeout(abortController);
let credential: BitCredential | undefined; let credential: BitCredential | undefined;
if (params.allowedCredentialIds && params.allowedCredentialIds.length > 0) { if (params.allowedCredentialIds && params.allowedCredentialIds.length > 0) {
@@ -185,6 +196,8 @@ export class Fido2Service implements Fido2ServiceAbstraction {
privateKey: credential.keyValue, privateKey: credential.keyValue,
}); });
clearTimeout(timeout);
return { return {
credentialId: credential.credentialId.encoded, credentialId: credential.credentialId.encoded,
clientDataJSON: Fido2Utils.bufferToString(clientData), clientDataJSON: Fido2Utils.bufferToString(clientData),
@@ -194,10 +207,7 @@ export class Fido2Service implements Fido2ServiceAbstraction {
}; };
} }
private async getCredential( private async getCredential(allowedCredentialIds: string[]): Promise<BitCredential | undefined> {
allowedCredentialIds: string[],
abortController?: AbortController
): Promise<BitCredential | undefined> {
let cipher: Cipher | undefined; let cipher: Cipher | undefined;
for (const allowedCredential of allowedCredentialIds) { for (const allowedCredential of allowedCredentialIds) {
cipher = await this.cipherService.get(allowedCredential); cipher = await this.cipherService.get(allowedCredential);
@@ -414,3 +424,9 @@ function authDataFlags(options: Flags): number {
return flags; return flags;
} }
function setAbortTimeout(abortController: AbortController, timeout = DEFAULT_TIMEOUT): number {
// TODO: Set different timeouts depending on `userVerification` value
const clampedTimeout = Math.max(MIN_TIMEOUT, Math.min(timeout, MAX_TIMEOUT));
return window.setTimeout(() => abortController.abort(), clampedTimeout);
}