mirror of
https://github.com/bitwarden/browser
synced 2025-12-18 09:13:33 +00:00
[EC-598] feat: rudimentar error handling
This commit is contained in:
@@ -209,9 +209,17 @@ export default class RuntimeBackground {
|
|||||||
this.platformUtilsService.copyToClipboard(msg.identifier, { window: window });
|
this.platformUtilsService.copyToClipboard(msg.identifier, { window: window });
|
||||||
break;
|
break;
|
||||||
case "fido2RegisterCredentialRequest":
|
case "fido2RegisterCredentialRequest":
|
||||||
return await this.main.fido2Service.createCredential(msg.data);
|
try {
|
||||||
|
return { result: await this.main.fido2Service.createCredential(msg.data) };
|
||||||
|
} catch (error) {
|
||||||
|
return { error: { ...error, message: error.message } };
|
||||||
|
}
|
||||||
case "fido2GetCredentialRequest":
|
case "fido2GetCredentialRequest":
|
||||||
return await this.main.fido2Service.assertCredential(msg.data);
|
try {
|
||||||
|
return { result: await this.main.fido2Service.assertCredential(msg.data) };
|
||||||
|
} catch (error) {
|
||||||
|
return { error: { ...error, message: error.message } };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ messenger.addHandler(async (message) => {
|
|||||||
(response) => {
|
(response) => {
|
||||||
resolve({
|
resolve({
|
||||||
type: MessageType.CredentialCreationResponse,
|
type: MessageType.CredentialCreationResponse,
|
||||||
approved: true,
|
result: response.result,
|
||||||
result: response,
|
error: response.error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -39,7 +39,8 @@ messenger.addHandler(async (message) => {
|
|||||||
(response) => {
|
(response) => {
|
||||||
resolve({
|
resolve({
|
||||||
type: MessageType.CredentialGetResponse,
|
type: MessageType.CredentialGetResponse,
|
||||||
result: response,
|
result: response.result,
|
||||||
|
error: response.error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
10
apps/browser/src/content/webauthn/messaging/error.ts
Normal file
10
apps/browser/src/content/webauthn/messaging/error.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export enum MessageErrorType {
|
||||||
|
RequestAborted,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RequestAbortedMessageError = {
|
||||||
|
fallbackRequested: boolean;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MessageError = RequestAbortedMessageError;
|
||||||
@@ -5,6 +5,8 @@ import {
|
|||||||
CredentialRegistrationResult,
|
CredentialRegistrationResult,
|
||||||
} from "@bitwarden/common/abstractions/fido2/fido2.service.abstraction";
|
} from "@bitwarden/common/abstractions/fido2/fido2.service.abstraction";
|
||||||
|
|
||||||
|
import { MessageError } from "./error";
|
||||||
|
|
||||||
export enum MessageType {
|
export enum MessageType {
|
||||||
CredentialCreationRequest,
|
CredentialCreationRequest,
|
||||||
CredentialCreationResponse,
|
CredentialCreationResponse,
|
||||||
@@ -21,8 +23,8 @@ export type CredentialCreationRequest = {
|
|||||||
|
|
||||||
export type CredentialCreationResponse = {
|
export type CredentialCreationResponse = {
|
||||||
type: MessageType.CredentialCreationResponse;
|
type: MessageType.CredentialCreationResponse;
|
||||||
approved: boolean;
|
|
||||||
result?: CredentialRegistrationResult;
|
result?: CredentialRegistrationResult;
|
||||||
|
error?: MessageError;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CredentialGetRequest = {
|
export type CredentialGetRequest = {
|
||||||
@@ -33,6 +35,7 @@ export type CredentialGetRequest = {
|
|||||||
export type CredentialGetResponse = {
|
export type CredentialGetResponse = {
|
||||||
type: MessageType.CredentialGetResponse;
|
type: MessageType.CredentialGetResponse;
|
||||||
result?: CredentialAssertResult;
|
result?: CredentialAssertResult;
|
||||||
|
error?: MessageError;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AbortRequest = {
|
export type AbortRequest = {
|
||||||
|
|||||||
@@ -19,10 +19,18 @@ navigator.credentials.create = async (options?: CredentialCreationOptions): Prom
|
|||||||
data: WebauthnUtils.mapCredentialCreationOptions(options, window.location.origin),
|
data: WebauthnUtils.mapCredentialCreationOptions(options, window.location.origin),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.type !== MessageType.CredentialCreationResponse || !response.approved) {
|
if (response.type !== MessageType.CredentialCreationResponse) {
|
||||||
return await browserCredentials.create(options);
|
return await browserCredentials.create(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (response.error && response.error.fallbackRequested) {
|
||||||
|
return await browserCredentials.create(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
throw new Error(response.error.message ?? "The request was aborted.");
|
||||||
|
}
|
||||||
|
|
||||||
return WebauthnUtils.mapCredentialRegistrationResult(response.result);
|
return WebauthnUtils.mapCredentialRegistrationResult(response.result);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -36,5 +44,13 @@ navigator.credentials.get = async (options?: CredentialRequestOptions): Promise<
|
|||||||
return await browserCredentials.get(options);
|
return await browserCredentials.get(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (response.error && response.error.fallbackRequested) {
|
||||||
|
return await browserCredentials.create(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
throw new Error(response.error.message ?? "The request was aborted.");
|
||||||
|
}
|
||||||
|
|
||||||
return WebauthnUtils.mapCredentialAssertResult(response.result);
|
return WebauthnUtils.mapCredentialAssertResult(response.result);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,5 +9,8 @@
|
|||||||
<ng-container *ngIf="data.type == 'VerifyUserRequest'">Authenticate</ng-container>
|
<ng-container *ngIf="data.type == 'VerifyUserRequest'">Authenticate</ng-container>
|
||||||
<ng-container *ngIf="data.type == 'ConfirmNewCredentialRequest'">Create</ng-container>
|
<ng-container *ngIf="data.type == 'ConfirmNewCredentialRequest'">Create</ng-container>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-outline-secondary" (click)="cancel()">Cancel</button>
|
<button type="button" class="btn btn-outline-secondary" (click)="cancel(true)">
|
||||||
|
Use browser built-in
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-secondary" (click)="cancel(false)">Abort</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -35,23 +35,25 @@ export class Fido2Component {
|
|||||||
BrowserFido2UserInterfaceService.sendMessage({
|
BrowserFido2UserInterfaceService.sendMessage({
|
||||||
requestId: data.requestId,
|
requestId: data.requestId,
|
||||||
type: "RequestCancelled",
|
type: "RequestCancelled",
|
||||||
|
fallbackRequested: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
window.close();
|
window.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
cancel(fallback: boolean) {
|
||||||
this.unload();
|
this.unload(fallback);
|
||||||
window.close();
|
window.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener("window:unload")
|
@HostListener("window:unload")
|
||||||
unload() {
|
unload(fallback = true) {
|
||||||
const data = this.data;
|
const data = this.data;
|
||||||
BrowserFido2UserInterfaceService.sendMessage({
|
BrowserFido2UserInterfaceService.sendMessage({
|
||||||
requestId: data.requestId,
|
requestId: data.requestId,
|
||||||
type: "RequestCancelled",
|
type: "RequestCancelled",
|
||||||
|
fallbackRequested: fallback,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { filter, first, lastValueFrom, Subject, takeUntil } from "rxjs";
|
|||||||
import { Fido2UserInterfaceService as Fido2UserInterfaceServiceAbstraction } from "@bitwarden/common/abstractions/fido2/fido2-user-interface.service.abstraction";
|
import { Fido2UserInterfaceService as Fido2UserInterfaceServiceAbstraction } from "@bitwarden/common/abstractions/fido2/fido2-user-interface.service.abstraction";
|
||||||
import { Utils } from "@bitwarden/common/misc/utils";
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
|
|
||||||
|
import { RequestAbortedError } from "../../../../../libs/common/src/abstractions/fido2/fido2.service.abstraction";
|
||||||
import { BrowserApi } from "../../browser/browserApi";
|
import { BrowserApi } from "../../browser/browserApi";
|
||||||
import { PopupUtilsService } from "../../popup/services/popup-utils.service";
|
import { PopupUtilsService } from "../../popup/services/popup-utils.service";
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ export type BrowserFido2Message = { requestId: string } & (
|
|||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: "RequestCancelled";
|
type: "RequestCancelled";
|
||||||
|
fallbackRequested: boolean;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -68,6 +70,10 @@ export class BrowserFido2UserInterfaceService implements Fido2UserInterfaceServi
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (response.type === "RequestCancelled") {
|
||||||
|
throw new RequestAbortedError(response.fallbackRequested);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +99,10 @@ export class BrowserFido2UserInterfaceService implements Fido2UserInterfaceServi
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (response.type === "RequestCancelled") {
|
||||||
|
throw new RequestAbortedError(response.fallbackRequested);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,12 @@ export interface CredentialAssertResult {
|
|||||||
userHandle: string;
|
userHandle: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class RequestAbortedError extends Error {
|
||||||
|
constructor(readonly fallbackRequested = false) {
|
||||||
|
super("Fido2 request was aborted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class Fido2Service {
|
export abstract class Fido2Service {
|
||||||
createCredential: (params: CredentialRegistrationParams) => Promise<CredentialRegistrationResult>;
|
createCredential: (params: CredentialRegistrationParams) => Promise<CredentialRegistrationResult>;
|
||||||
assertCredential: (params: CredentialAssertParams) => Promise<CredentialAssertResult>;
|
assertCredential: (params: CredentialAssertParams) => Promise<CredentialAssertResult>;
|
||||||
|
|||||||
Reference in New Issue
Block a user