mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-16 10:45:20 +01:00
[EC-598] feat: show new cipher being added
This commit is contained in:
parent
6c7548c7ec
commit
f0b8d32ee6
@ -87,7 +87,7 @@ import { PrivateModeWarningComponent } from "./components/private-mode-warning.c
|
||||
import { SendListComponent } from "./components/send-list.component";
|
||||
import { SetPinComponent } from "./components/set-pin.component";
|
||||
import { UserVerificationComponent } from "./components/user-verification.component";
|
||||
import { Fido2Module } from "./fido2/fido2.module";
|
||||
import { Fido2Component } from "./fido2/fido2.component";
|
||||
import { GeneratorComponent } from "./generator/generator.component";
|
||||
import { PasswordGeneratorHistoryComponent } from "./generator/password-generator-history.component";
|
||||
import { EffluxDatesComponent as SendEffluxDatesComponent } from "./send/efflux-dates.component";
|
||||
@ -193,7 +193,6 @@ registerLocaleData(localeZhTw, "zh-TW");
|
||||
ReactiveFormsModule,
|
||||
ScrollingModule,
|
||||
ServicesModule,
|
||||
Fido2Module,
|
||||
],
|
||||
declarations: [
|
||||
ActionButtonsComponent,
|
||||
@ -246,6 +245,7 @@ registerLocaleData(localeZhTw, "zh-TW");
|
||||
RemovePasswordComponent,
|
||||
VaultSelectComponent,
|
||||
AboutComponent,
|
||||
Fido2Component,
|
||||
],
|
||||
providers: [CurrencyPipe, DatePipe],
|
||||
bootstrap: [AppComponent],
|
||||
|
@ -1,16 +1,23 @@
|
||||
<div class="auth-wrapper">
|
||||
<ng-container *ngIf="data.type == 'VerifyUserRequest'">
|
||||
A site is asking for authentication
|
||||
</ng-container>
|
||||
<ng-container *ngIf="data.type == 'ConfirmNewCredentialRequest'">
|
||||
A site wants to create a new passkey in your vault
|
||||
</ng-container>
|
||||
<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>
|
||||
<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>
|
||||
<ng-container *ngIf="data">
|
||||
<div class="auth-wrapper">
|
||||
<ng-container *ngIf="data.type == 'VerifyUserRequest'">
|
||||
A site is asking for authentication
|
||||
</ng-container>
|
||||
<ng-container *ngIf="data.type == 'ConfirmNewCredentialRequest'">
|
||||
<div class="box list">
|
||||
<div class="box-content">
|
||||
<app-cipher-row [cipher]="cipher"></app-cipher-row>
|
||||
</div>
|
||||
</div>
|
||||
A site wants to create a new passkey in your vault
|
||||
</ng-container>
|
||||
<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>
|
||||
<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>
|
||||
</ng-container>
|
||||
|
@ -1,5 +1,10 @@
|
||||
import { Component, HostListener } from "@angular/core";
|
||||
import { Component, HostListener, OnDestroy, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { CipherType } from "@bitwarden/common/enums/cipherType";
|
||||
import { CipherView } from "@bitwarden/common/models/view/cipher.view";
|
||||
import { Fido2KeyView } from "@bitwarden/common/models/view/fido2-key.view";
|
||||
|
||||
import {
|
||||
BrowserFido2Message,
|
||||
@ -11,11 +16,25 @@ import {
|
||||
templateUrl: "fido2.component.html",
|
||||
styleUrls: [],
|
||||
})
|
||||
export class Fido2Component {
|
||||
export class Fido2Component implements OnInit, OnDestroy {
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
protected data?: BrowserFido2Message;
|
||||
protected cipher?: CipherView;
|
||||
|
||||
constructor(private activatedRoute: ActivatedRoute) {}
|
||||
|
||||
get data() {
|
||||
return this.activatedRoute.snapshot.queryParams as BrowserFido2Message;
|
||||
ngOnInit(): void {
|
||||
this.activatedRoute.queryParamMap.pipe(takeUntil(this.destroy$)).subscribe((queryParamMap) => {
|
||||
this.data = JSON.parse(queryParamMap.get("data"));
|
||||
|
||||
if (this.data?.type === "ConfirmNewCredentialRequest") {
|
||||
this.cipher = new CipherView();
|
||||
this.cipher.name = this.data.name;
|
||||
this.cipher.type = CipherType.Fido2Key;
|
||||
this.cipher.fido2Key = new Fido2KeyView();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async accept() {
|
||||
@ -56,4 +75,9 @@ export class Fido2Component {
|
||||
fallbackRequested: fallback,
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { Fido2Component } from "./fido2.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
declarations: [Fido2Component],
|
||||
exports: [Fido2Component],
|
||||
})
|
||||
export class Fido2Module {}
|
@ -1,6 +1,9 @@
|
||||
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,
|
||||
NewCredentialParams,
|
||||
} from "@bitwarden/common/abstractions/fido2/fido2-user-interface.service.abstraction";
|
||||
import { Utils } from "@bitwarden/common/misc/utils";
|
||||
|
||||
import { RequestAbortedError } from "../../../../../libs/common/src/abstractions/fido2/fido2.service.abstraction";
|
||||
@ -18,6 +21,7 @@ export type BrowserFido2Message = { requestId: string } & (
|
||||
}
|
||||
| {
|
||||
type: "ConfirmNewCredentialRequest";
|
||||
name: string;
|
||||
}
|
||||
| {
|
||||
type: "ConfirmNewCredentialResponse";
|
||||
@ -51,7 +55,7 @@ export class BrowserFido2UserInterfaceService implements Fido2UserInterfaceServi
|
||||
async verifyPresence(): Promise<boolean> {
|
||||
const requestId = Utils.newGuid();
|
||||
const data: BrowserFido2Message = { type: "VerifyUserRequest", requestId };
|
||||
const queryParams = new URLSearchParams(data).toString();
|
||||
const queryParams = new URLSearchParams({ data: JSON.stringify(data) }).toString();
|
||||
this.popupUtilsService.popOut(
|
||||
null,
|
||||
`popup/index.html?uilocation=popout#/fido2?${queryParams}`,
|
||||
@ -77,10 +81,10 @@ export class BrowserFido2UserInterfaceService implements Fido2UserInterfaceServi
|
||||
return false;
|
||||
}
|
||||
|
||||
async confirmNewCredential(): Promise<boolean> {
|
||||
async confirmNewCredential({ name }: NewCredentialParams): Promise<boolean> {
|
||||
const requestId = Utils.newGuid();
|
||||
const data: BrowserFido2Message = { type: "ConfirmNewCredentialRequest", requestId };
|
||||
const queryParams = new URLSearchParams(data).toString();
|
||||
const data: BrowserFido2Message = { type: "ConfirmNewCredentialRequest", requestId, name };
|
||||
const queryParams = new URLSearchParams({ data: JSON.stringify(data) }).toString();
|
||||
this.popupUtilsService.popOut(
|
||||
null,
|
||||
`popup/index.html?uilocation=popout#/fido2?${queryParams}`,
|
||||
|
@ -1,5 +1,9 @@
|
||||
export interface NewCredentialParams {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export abstract class Fido2UserInterfaceService {
|
||||
verifyUser: () => Promise<boolean>;
|
||||
verifyPresence: () => Promise<boolean>;
|
||||
confirmNewCredential: () => Promise<boolean>;
|
||||
confirmNewCredential: (params: NewCredentialParams) => Promise<boolean>;
|
||||
}
|
||||
|
@ -42,7 +42,9 @@ export class Fido2Service implements Fido2ServiceAbstraction {
|
||||
async createCredential(
|
||||
params: CredentialRegistrationParams
|
||||
): Promise<CredentialRegistrationResult> {
|
||||
const presence = await this.fido2UserInterfaceService.confirmNewCredential();
|
||||
const presence = await this.fido2UserInterfaceService.confirmNewCredential({
|
||||
name: params.origin,
|
||||
});
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("Fido2Service.createCredential", params);
|
||||
|
||||
@ -123,14 +125,11 @@ export class Fido2Service implements Fido2ServiceAbstraction {
|
||||
credential = await this.getCredentialByRp(params.rpId);
|
||||
}
|
||||
|
||||
console.log("Found credential: ", credential);
|
||||
|
||||
if (credential === undefined) {
|
||||
throw new NoCredentialFoundError();
|
||||
}
|
||||
|
||||
if (credential.origin !== params.origin) {
|
||||
console.error(`${params.origin} tried to use credential created by ${credential.origin}`);
|
||||
throw new OriginMismatchError();
|
||||
}
|
||||
|
||||
@ -203,8 +202,6 @@ export class Fido2Service implements Fido2ServiceAbstraction {
|
||||
view.fido2Key.rpId = credential.rpId;
|
||||
view.fido2Key.userHandle = Fido2Utils.bufferToString(credential.userHandle);
|
||||
|
||||
console.log("saving credential", { view, credential });
|
||||
|
||||
const cipher = await this.cipherService.encrypt(view);
|
||||
await this.cipherService.createWithServer(cipher);
|
||||
|
||||
@ -237,22 +234,16 @@ interface AuthDataParams {
|
||||
|
||||
async function mapCipherViewToBitCredential(cipherView: CipherView): Promise<BitCredential> {
|
||||
const keyBuffer = Fido2Utils.stringToBuffer(cipherView.fido2Key.key);
|
||||
let privateKey;
|
||||
try {
|
||||
privateKey = await crypto.subtle.importKey(
|
||||
"pkcs8",
|
||||
keyBuffer,
|
||||
{
|
||||
name: "ECDSA",
|
||||
namedCurve: "P-256",
|
||||
},
|
||||
true,
|
||||
KeyUsages
|
||||
);
|
||||
} catch (err) {
|
||||
console.log("Error importing key", { err });
|
||||
throw err;
|
||||
}
|
||||
const privateKey = await crypto.subtle.importKey(
|
||||
"pkcs8",
|
||||
keyBuffer,
|
||||
{
|
||||
name: "ECDSA",
|
||||
namedCurve: "P-256",
|
||||
},
|
||||
true,
|
||||
KeyUsages
|
||||
);
|
||||
|
||||
return {
|
||||
credentialId: new CredentialId(cipherView.id),
|
||||
|
Loading…
Reference in New Issue
Block a user