mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 08:43:33 +00:00
[EC-598] feat: add fido2Key to cipher
This commit is contained in:
@@ -3,4 +3,5 @@ export enum CipherType {
|
|||||||
SecureNote = 2,
|
SecureNote = 2,
|
||||||
Card = 3,
|
Card = 3,
|
||||||
Identity = 4,
|
Identity = 4,
|
||||||
|
Fido2Key = 5,
|
||||||
}
|
}
|
||||||
|
|||||||
20
libs/common/src/models/api/fido2-key.api.ts
Normal file
20
libs/common/src/models/api/fido2-key.api.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { BaseResponse } from "../response/base.response";
|
||||||
|
|
||||||
|
export class Fido2KeyApi extends BaseResponse {
|
||||||
|
key: string;
|
||||||
|
rpId: string;
|
||||||
|
origin: string;
|
||||||
|
userHandle: string;
|
||||||
|
|
||||||
|
constructor(data: any = null) {
|
||||||
|
super(data);
|
||||||
|
if (data == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.key = this.getResponseProperty("Key");
|
||||||
|
this.rpId = this.getResponseProperty("RpId");
|
||||||
|
this.origin = this.getResponseProperty("Origin");
|
||||||
|
this.userHandle = this.getResponseProperty("UserHandle");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import { CipherResponse } from "../response/cipher.response";
|
|||||||
|
|
||||||
import { AttachmentData } from "./attachment.data";
|
import { AttachmentData } from "./attachment.data";
|
||||||
import { CardData } from "./card.data";
|
import { CardData } from "./card.data";
|
||||||
|
import { Fido2KeyData } from "./fido2-key.data";
|
||||||
import { FieldData } from "./field.data";
|
import { FieldData } from "./field.data";
|
||||||
import { IdentityData } from "./identity.data";
|
import { IdentityData } from "./identity.data";
|
||||||
import { LoginData } from "./login.data";
|
import { LoginData } from "./login.data";
|
||||||
@@ -26,6 +27,7 @@ export class CipherData {
|
|||||||
secureNote?: SecureNoteData;
|
secureNote?: SecureNoteData;
|
||||||
card?: CardData;
|
card?: CardData;
|
||||||
identity?: IdentityData;
|
identity?: IdentityData;
|
||||||
|
fido2Key?: Fido2KeyData;
|
||||||
fields?: FieldData[];
|
fields?: FieldData[];
|
||||||
attachments?: AttachmentData[];
|
attachments?: AttachmentData[];
|
||||||
passwordHistory?: PasswordHistoryData[];
|
passwordHistory?: PasswordHistoryData[];
|
||||||
@@ -68,6 +70,9 @@ export class CipherData {
|
|||||||
case CipherType.Identity:
|
case CipherType.Identity:
|
||||||
this.identity = new IdentityData(response.identity);
|
this.identity = new IdentityData(response.identity);
|
||||||
break;
|
break;
|
||||||
|
case CipherType.Fido2Key:
|
||||||
|
this.fido2Key = new Fido2KeyData(response.fido2Key);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
19
libs/common/src/models/data/fido2-key.data.ts
Normal file
19
libs/common/src/models/data/fido2-key.data.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { Fido2KeyApi } from "../api/fido2-key.api";
|
||||||
|
|
||||||
|
export class Fido2KeyData {
|
||||||
|
key: string;
|
||||||
|
rpId: string;
|
||||||
|
origin: string;
|
||||||
|
userHandle: string;
|
||||||
|
|
||||||
|
constructor(data?: Fido2KeyApi) {
|
||||||
|
if (data == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.key = data.key;
|
||||||
|
this.rpId = data.rpId;
|
||||||
|
this.origin = data.origin;
|
||||||
|
this.userHandle = data.userHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ import { Attachment } from "./attachment";
|
|||||||
import { Card } from "./card";
|
import { Card } from "./card";
|
||||||
import Domain from "./domain-base";
|
import Domain from "./domain-base";
|
||||||
import { EncString } from "./enc-string";
|
import { EncString } from "./enc-string";
|
||||||
|
import { Fido2Key } from "./fido2-key";
|
||||||
import { Field } from "./field";
|
import { Field } from "./field";
|
||||||
import { Identity } from "./identity";
|
import { Identity } from "./identity";
|
||||||
import { Login } from "./login";
|
import { Login } from "./login";
|
||||||
@@ -38,6 +39,7 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
identity: Identity;
|
identity: Identity;
|
||||||
card: Card;
|
card: Card;
|
||||||
secureNote: SecureNote;
|
secureNote: SecureNote;
|
||||||
|
fido2Key: Fido2Key;
|
||||||
attachments: Attachment[];
|
attachments: Attachment[];
|
||||||
fields: Field[];
|
fields: Field[];
|
||||||
passwordHistory: Password[];
|
passwordHistory: Password[];
|
||||||
@@ -94,6 +96,9 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
case CipherType.Identity:
|
case CipherType.Identity:
|
||||||
this.identity = new Identity(obj.identity);
|
this.identity = new Identity(obj.identity);
|
||||||
break;
|
break;
|
||||||
|
case CipherType.Fido2Key:
|
||||||
|
this.fido2Key = new Fido2Key(obj.fido2Key);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -143,6 +148,9 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
case CipherType.Identity:
|
case CipherType.Identity:
|
||||||
model.identity = await this.identity.decrypt(this.organizationId, encKey);
|
model.identity = await this.identity.decrypt(this.organizationId, encKey);
|
||||||
break;
|
break;
|
||||||
|
case CipherType.Fido2Key:
|
||||||
|
model.fido2Key = await this.fido2Key.decrypt(this.organizationId, encKey);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -228,6 +236,9 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
case CipherType.Identity:
|
case CipherType.Identity:
|
||||||
c.identity = this.identity.toIdentityData();
|
c.identity = this.identity.toIdentityData();
|
||||||
break;
|
break;
|
||||||
|
case CipherType.Fido2Key:
|
||||||
|
c.fido2Key = this.fido2Key.toFido2KeyData();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -281,6 +292,9 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
case CipherType.SecureNote:
|
case CipherType.SecureNote:
|
||||||
domain.secureNote = SecureNote.fromJSON(obj.secureNote);
|
domain.secureNote = SecureNote.fromJSON(obj.secureNote);
|
||||||
break;
|
break;
|
||||||
|
case CipherType.Fido2Key:
|
||||||
|
domain.fido2Key = Fido2Key.fromJSON(obj.fido2Key);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
78
libs/common/src/models/domain/fido2-key.ts
Normal file
78
libs/common/src/models/domain/fido2-key.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
|
import { Fido2KeyData } from "../data/fido2-key.data";
|
||||||
|
import { Fido2KeyView } from "../view/fido2-key.view";
|
||||||
|
|
||||||
|
import Domain from "./domain-base";
|
||||||
|
import { EncString } from "./enc-string";
|
||||||
|
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
|
||||||
|
|
||||||
|
export class Fido2Key extends Domain {
|
||||||
|
key: EncString; // PCKS#8
|
||||||
|
rpId: EncString;
|
||||||
|
origin: EncString;
|
||||||
|
userHandle: EncString;
|
||||||
|
// extensions: Record<string, unknown>;
|
||||||
|
|
||||||
|
constructor(obj?: Fido2KeyData) {
|
||||||
|
super();
|
||||||
|
if (obj == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.buildDomainModel(
|
||||||
|
this,
|
||||||
|
obj,
|
||||||
|
{
|
||||||
|
key: null,
|
||||||
|
rpId: null,
|
||||||
|
origin: null,
|
||||||
|
userHandle: null,
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<Fido2KeyView> {
|
||||||
|
return this.decryptObj(
|
||||||
|
new Fido2KeyView(),
|
||||||
|
{
|
||||||
|
key: null,
|
||||||
|
rpId: null,
|
||||||
|
origin: null,
|
||||||
|
userHandle: null,
|
||||||
|
},
|
||||||
|
orgId,
|
||||||
|
encKey
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
toFido2KeyData(): Fido2KeyData {
|
||||||
|
const i = new Fido2KeyData();
|
||||||
|
this.buildDataModel(this, i, {
|
||||||
|
key: null,
|
||||||
|
rpId: null,
|
||||||
|
origin: null,
|
||||||
|
userHandle: null,
|
||||||
|
});
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJSON(obj: Jsonify<Fido2Key>): Fido2Key {
|
||||||
|
if (obj == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = EncString.fromJSON(obj.key);
|
||||||
|
const rpId = EncString.fromJSON(obj.rpId);
|
||||||
|
const origin = EncString.fromJSON(obj.origin);
|
||||||
|
const userHandle = EncString.fromJSON(obj.userHandle);
|
||||||
|
|
||||||
|
return Object.assign(new Fido2Key(), obj, {
|
||||||
|
key,
|
||||||
|
rpId,
|
||||||
|
origin,
|
||||||
|
userHandle,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { CipherRepromptType } from "../../enums/cipherRepromptType";
|
import { CipherRepromptType } from "../../enums/cipherRepromptType";
|
||||||
import { CardApi } from "../api/card.api";
|
import { CardApi } from "../api/card.api";
|
||||||
|
import { Fido2KeyApi } from "../api/fido2-key.api";
|
||||||
import { FieldApi } from "../api/field.api";
|
import { FieldApi } from "../api/field.api";
|
||||||
import { IdentityApi } from "../api/identity.api";
|
import { IdentityApi } from "../api/identity.api";
|
||||||
import { LoginApi } from "../api/login.api";
|
import { LoginApi } from "../api/login.api";
|
||||||
@@ -21,6 +22,7 @@ export class CipherResponse extends BaseResponse {
|
|||||||
card: CardApi;
|
card: CardApi;
|
||||||
identity: IdentityApi;
|
identity: IdentityApi;
|
||||||
secureNote: SecureNoteApi;
|
secureNote: SecureNoteApi;
|
||||||
|
fido2Key: Fido2KeyApi;
|
||||||
favorite: boolean;
|
favorite: boolean;
|
||||||
edit: boolean;
|
edit: boolean;
|
||||||
viewPassword: boolean;
|
viewPassword: boolean;
|
||||||
@@ -74,6 +76,11 @@ export class CipherResponse extends BaseResponse {
|
|||||||
this.secureNote = new SecureNoteApi(secureNote);
|
this.secureNote = new SecureNoteApi(secureNote);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fido2Key = this.getResponseProperty("Fido2Key");
|
||||||
|
if (fido2Key != null) {
|
||||||
|
this.fido2Key = new Fido2KeyApi(fido2Key);
|
||||||
|
}
|
||||||
|
|
||||||
const fields = this.getResponseProperty("Fields");
|
const fields = this.getResponseProperty("Fields");
|
||||||
if (fields != null) {
|
if (fields != null) {
|
||||||
this.fields = fields.map((f: any) => new FieldApi(f));
|
this.fields = fields.map((f: any) => new FieldApi(f));
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { Cipher } from "../domain/cipher";
|
|||||||
|
|
||||||
import { AttachmentView } from "./attachment.view";
|
import { AttachmentView } from "./attachment.view";
|
||||||
import { CardView } from "./card.view";
|
import { CardView } from "./card.view";
|
||||||
|
import { Fido2KeyView } from "./fido2-key.view";
|
||||||
import { FieldView } from "./field.view";
|
import { FieldView } from "./field.view";
|
||||||
import { IdentityView } from "./identity.view";
|
import { IdentityView } from "./identity.view";
|
||||||
import { LoginView } from "./login.view";
|
import { LoginView } from "./login.view";
|
||||||
@@ -35,6 +36,7 @@ export class CipherView implements View, InitializerMetadata {
|
|||||||
identity = new IdentityView();
|
identity = new IdentityView();
|
||||||
card = new CardView();
|
card = new CardView();
|
||||||
secureNote = new SecureNoteView();
|
secureNote = new SecureNoteView();
|
||||||
|
fido2Key = new Fido2KeyView();
|
||||||
attachments: AttachmentView[] = null;
|
attachments: AttachmentView[] = null;
|
||||||
fields: FieldView[] = null;
|
fields: FieldView[] = null;
|
||||||
passwordHistory: PasswordHistoryView[] = null;
|
passwordHistory: PasswordHistoryView[] = null;
|
||||||
|
|||||||
7
libs/common/src/models/view/fido2-key.view.ts
Normal file
7
libs/common/src/models/view/fido2-key.view.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export class Fido2KeyView {
|
||||||
|
id: string;
|
||||||
|
key: string;
|
||||||
|
rpId: string;
|
||||||
|
origin: string;
|
||||||
|
userHandle: string;
|
||||||
|
}
|
||||||
@@ -84,7 +84,7 @@ export class Fido2Service implements Fido2ServiceAbstraction {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
this.credentials.set(credentialId.encoded, {
|
await this.saveCredential({
|
||||||
credentialId,
|
credentialId,
|
||||||
keyPair,
|
keyPair,
|
||||||
origin: params.origin,
|
origin: params.origin,
|
||||||
@@ -170,6 +170,10 @@ export class Fido2Service implements Fido2ServiceAbstraction {
|
|||||||
return credential;
|
return credential;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async saveCredential(credential: BitCredential): Promise<void> {
|
||||||
|
this.credentials.set(credential.credentialId.encoded, credential);
|
||||||
|
}
|
||||||
|
|
||||||
private getCredentialByRp(rpId: string): BitCredential | undefined {
|
private getCredentialByRp(rpId: string): BitCredential | undefined {
|
||||||
for (const credential of this.credentials.values()) {
|
for (const credential of this.credentials.values()) {
|
||||||
if (credential.rpId === rpId) {
|
if (credential.rpId === rpId) {
|
||||||
|
|||||||
Reference in New Issue
Block a user