mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +00:00
[EC-598] feat: differntiate between resident auth and 2fa
This commit is contained in:
@@ -1,7 +1,18 @@
|
|||||||
<ng-container *ngIf="data">
|
<ng-container *ngIf="data">
|
||||||
<div class="auth-wrapper">
|
<div class="auth-wrapper">
|
||||||
|
<ng-container *ngIf="data.type == 'ConfirmCredentialRequest'">
|
||||||
|
A site is asking for authentication using the following credential:
|
||||||
|
<div class="box list">
|
||||||
|
<div class="box-content">
|
||||||
|
<app-cipher-row [cipher]="ciphers[0]"></app-cipher-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-outline-secondary" (click)="confirm()">
|
||||||
|
Authenticate
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
||||||
<ng-container *ngIf="data.type == 'PickCredentialRequest'">
|
<ng-container *ngIf="data.type == 'PickCredentialRequest'">
|
||||||
A site is asking for authentication, please choose one of the following credentials to use
|
A site is asking for authentication, please choose one of the following credentials to use:
|
||||||
<div class="box list">
|
<div class="box list">
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<app-cipher-row
|
<app-cipher-row
|
||||||
@@ -11,10 +22,6 @@
|
|||||||
></app-cipher-row>
|
></app-cipher-row>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <button type="button" class="btn btn-outline-secondary" (click)="accept()">
|
|
||||||
<ng-container *ngIf="data.type == 'VerifyUserRequest'">Authenticate</ng-container>
|
|
||||||
<ng-container *ngIf="data.type == 'ConfirmNewCredentialRequest'">Create</ng-container>
|
|
||||||
</button> -->
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="data.type == 'ConfirmNewCredentialRequest'">
|
<ng-container *ngIf="data.type == 'ConfirmNewCredentialRequest'">
|
||||||
A site wants to create the following passkey in your vault
|
A site wants to create the following passkey in your vault
|
||||||
@@ -23,9 +30,7 @@
|
|||||||
<app-cipher-row [cipher]="ciphers[0]"></app-cipher-row>
|
<app-cipher-row [cipher]="ciphers[0]"></app-cipher-row>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-outline-secondary" (click)="confirm()">
|
<button type="button" class="btn btn-outline-secondary" (click)="confirmNew()">Create</button>
|
||||||
<ng-container *ngIf="data.type == 'ConfirmNewCredentialRequest'">Create</ng-container>
|
|
||||||
</button>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<button type="button" class="btn btn-outline-secondary" (click)="cancel(true)">
|
<button type="button" class="btn btn-outline-secondary" (click)="cancel(true)">
|
||||||
Use browser built-in
|
Use browser built-in
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ export class Fido2Component implements OnInit, OnDestroy {
|
|||||||
cipher.type = CipherType.Fido2Key;
|
cipher.type = CipherType.Fido2Key;
|
||||||
cipher.fido2Key = new Fido2KeyView();
|
cipher.fido2Key = new Fido2KeyView();
|
||||||
this.ciphers = [cipher];
|
this.ciphers = [cipher];
|
||||||
|
} else if (this.data?.type === "ConfirmCredentialRequest") {
|
||||||
|
const cipher = await this.cipherService.get(this.data.cipherId);
|
||||||
|
this.ciphers = [await cipher.decrypt()];
|
||||||
} else if (this.data?.type === "PickCredentialRequest") {
|
} else if (this.data?.type === "PickCredentialRequest") {
|
||||||
this.ciphers = await Promise.all(
|
this.ciphers = await Promise.all(
|
||||||
this.data.cipherIds.map(async (cipherId) => {
|
this.data.cipherIds.map(async (cipherId) => {
|
||||||
@@ -62,6 +65,14 @@ export class Fido2Component implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
confirm() {
|
confirm() {
|
||||||
|
BrowserFido2UserInterfaceService.sendMessage({
|
||||||
|
requestId: this.data.requestId,
|
||||||
|
type: "ConfirmCredentialResponse",
|
||||||
|
});
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmNew() {
|
||||||
BrowserFido2UserInterfaceService.sendMessage({
|
BrowserFido2UserInterfaceService.sendMessage({
|
||||||
requestId: this.data.requestId,
|
requestId: this.data.requestId,
|
||||||
type: "ConfirmNewCredentialResponse",
|
type: "ConfirmNewCredentialResponse",
|
||||||
|
|||||||
@@ -21,6 +21,13 @@ export type BrowserFido2Message = { requestId: string } & (
|
|||||||
type: "PickCredentialResponse";
|
type: "PickCredentialResponse";
|
||||||
cipherId?: string;
|
cipherId?: string;
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: "ConfirmCredentialRequest";
|
||||||
|
cipherId: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "ConfirmCredentialResponse";
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
type: "ConfirmNewCredentialRequest";
|
type: "ConfirmNewCredentialRequest";
|
||||||
name: string;
|
name: string;
|
||||||
@@ -50,6 +57,35 @@ export class BrowserFido2UserInterfaceService implements Fido2UserInterfaceServi
|
|||||||
BrowserApi.messageListener(BrowserFido2MessageName, this.processMessage.bind(this));
|
BrowserApi.messageListener(BrowserFido2MessageName, this.processMessage.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async confirmCredential(cipherId: string): Promise<boolean> {
|
||||||
|
const requestId = Utils.newGuid();
|
||||||
|
const data: BrowserFido2Message = { type: "ConfirmCredentialRequest", cipherId, requestId };
|
||||||
|
const queryParams = new URLSearchParams({ data: JSON.stringify(data) }).toString();
|
||||||
|
this.popupUtilsService.popOut(
|
||||||
|
null,
|
||||||
|
`popup/index.html?uilocation=popout#/fido2?${queryParams}`,
|
||||||
|
{ center: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const response = await lastValueFrom(
|
||||||
|
this.messages$.pipe(
|
||||||
|
filter((msg) => msg.requestId === requestId),
|
||||||
|
first(),
|
||||||
|
takeUntil(this.destroy$)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.type === "ConfirmCredentialResponse") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.type === "RequestCancelled") {
|
||||||
|
throw new RequestAbortedError(response.fallbackRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
async pickCredential(cipherIds: string[]): Promise<string> {
|
async pickCredential(cipherIds: string[]): Promise<string> {
|
||||||
const requestId = Utils.newGuid();
|
const requestId = Utils.newGuid();
|
||||||
const data: BrowserFido2Message = { type: "PickCredentialRequest", cipherIds, requestId };
|
const data: BrowserFido2Message = { type: "PickCredentialRequest", cipherIds, requestId };
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ export interface NewCredentialParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export abstract class Fido2UserInterfaceService {
|
export abstract class Fido2UserInterfaceService {
|
||||||
|
confirmCredential: (cipherId: string) => Promise<boolean>;
|
||||||
pickCredential: (cipherIds: string[]) => Promise<string>;
|
pickCredential: (cipherIds: string[]) => Promise<string>;
|
||||||
confirmNewCredential: (params: NewCredentialParams) => Promise<boolean>;
|
confirmNewCredential: (params: NewCredentialParams) => Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ export class Fido2Service implements Fido2ServiceAbstraction {
|
|||||||
throw new OriginMismatchError();
|
throw new OriginMismatchError();
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.fido2UserInterfaceService.pickCredential([credential.credentialId.encoded]);
|
await this.fido2UserInterfaceService.confirmCredential(credential.credentialId.encoded);
|
||||||
} else {
|
} else {
|
||||||
// We're looking for a resident key
|
// We're looking for a resident key
|
||||||
const credentials = await this.getCredentialsByRp(params.rpId);
|
const credentials = await this.getCredentialsByRp(params.rpId);
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ import { Fido2UserInterfaceService as Fido2UserInterfaceServiceAbstraction } fro
|
|||||||
import { RequestAbortedError } from "../../abstractions/fido2/fido2.service.abstraction";
|
import { RequestAbortedError } from "../../abstractions/fido2/fido2.service.abstraction";
|
||||||
|
|
||||||
export class Fido2UserInterfaceService implements Fido2UserInterfaceServiceAbstraction {
|
export class Fido2UserInterfaceService implements Fido2UserInterfaceServiceAbstraction {
|
||||||
|
async confirmCredential(cipherId: string): Promise<boolean> {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pickCredential(cipherIds: string[]): Promise<string> {
|
pickCredential(cipherIds: string[]): Promise<string> {
|
||||||
throw new RequestAbortedError();
|
throw new RequestAbortedError();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user