mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 13:23:34 +00:00
[PM-25683] Migrate Cipher model and sub-models (#16974)
* Made domain classes ts-strict compliant and fixed spec files * Fixed domain base class and other test files * Added conditional utils and fixed small nits * removed comments * removd ts expect errors * Added removed counter * renamed test name * fixed tests
This commit is contained in:
@@ -14,15 +14,15 @@ export type DecryptedObject<
|
|||||||
|
|
||||||
// extracts shared keys from the domain and view types
|
// extracts shared keys from the domain and view types
|
||||||
type EncryptableKeys<D extends Domain, V extends View> = (keyof D &
|
type EncryptableKeys<D extends Domain, V extends View> = (keyof D &
|
||||||
ConditionalKeys<D, EncString | null>) &
|
ConditionalKeys<D, EncString | null | undefined>) &
|
||||||
(keyof V & ConditionalKeys<V, string | null>);
|
(keyof V & ConditionalKeys<V, string | null | undefined>);
|
||||||
|
|
||||||
type DomainEncryptableKeys<D extends Domain> = {
|
type DomainEncryptableKeys<D extends Domain> = {
|
||||||
[key in ConditionalKeys<D, EncString | null>]: EncString | null;
|
[key in ConditionalKeys<D, EncString | null | undefined>]?: EncString | null | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ViewEncryptableKeys<V extends View> = {
|
type ViewEncryptableKeys<V extends View> = {
|
||||||
[key in ConditionalKeys<V, string | null>]: string | null;
|
[key in ConditionalKeys<V, string | null | undefined>]?: string | null | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://contributing.bitwarden.com/architecture/clients/data-model#domain
|
// https://contributing.bitwarden.com/architecture/clients/data-model#domain
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ export class CipherPermissionsApi extends BaseResponse implements SdkCipherPermi
|
|||||||
/**
|
/**
|
||||||
* Converts the SDK CipherPermissionsApi to a CipherPermissionsApi.
|
* Converts the SDK CipherPermissionsApi to a CipherPermissionsApi.
|
||||||
*/
|
*/
|
||||||
static fromSdkCipherPermissions(obj: SdkCipherPermissions): CipherPermissionsApi | undefined {
|
static fromSdkCipherPermissions(
|
||||||
|
obj: SdkCipherPermissions | undefined,
|
||||||
|
): CipherPermissionsApi | undefined {
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,12 +32,12 @@ describe("Attachment", () => {
|
|||||||
const attachment = new Attachment(data);
|
const attachment = new Attachment(data);
|
||||||
|
|
||||||
expect(attachment).toEqual({
|
expect(attachment).toEqual({
|
||||||
id: null,
|
id: undefined,
|
||||||
url: null,
|
url: undefined,
|
||||||
size: undefined,
|
size: undefined,
|
||||||
sizeName: null,
|
sizeName: undefined,
|
||||||
key: null,
|
key: undefined,
|
||||||
fileName: null,
|
fileName: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -79,6 +79,8 @@ describe("Attachment", () => {
|
|||||||
attachment.key = mockEnc("key");
|
attachment.key = mockEnc("key");
|
||||||
attachment.fileName = mockEnc("fileName");
|
attachment.fileName = mockEnc("fileName");
|
||||||
|
|
||||||
|
const userKey = new SymmetricCryptoKey(makeStaticByteArray(64));
|
||||||
|
keyService.getUserKey.mockResolvedValue(userKey as UserKey);
|
||||||
encryptService.decryptFileData.mockResolvedValue(makeStaticByteArray(32));
|
encryptService.decryptFileData.mockResolvedValue(makeStaticByteArray(32));
|
||||||
encryptService.unwrapSymmetricKey.mockResolvedValue(
|
encryptService.unwrapSymmetricKey.mockResolvedValue(
|
||||||
new SymmetricCryptoKey(makeStaticByteArray(64)),
|
new SymmetricCryptoKey(makeStaticByteArray(64)),
|
||||||
@@ -152,8 +154,8 @@ describe("Attachment", () => {
|
|||||||
expect(actual).toBeInstanceOf(Attachment);
|
expect(actual).toBeInstanceOf(Attachment);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns null if object is null", () => {
|
it("returns undefined if object is null", () => {
|
||||||
expect(Attachment.fromJSON(null)).toBeNull();
|
expect(Attachment.fromJSON(null)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
|
import { OrgKey, UserKey } from "@bitwarden/common/types/key";
|
||||||
import { Attachment as SdkAttachment } from "@bitwarden/sdk-internal";
|
import { Attachment as SdkAttachment } from "@bitwarden/sdk-internal";
|
||||||
|
|
||||||
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
||||||
import { Utils } from "../../../platform/misc/utils";
|
import { Utils } from "../../../platform/misc/utils";
|
||||||
import Domain from "../../../platform/models/domain/domain-base";
|
import Domain from "../../../platform/models/domain/domain-base";
|
||||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||||
|
import { conditionalEncString, encStringFrom } from "../../utils/domain-utils";
|
||||||
import { AttachmentData } from "../data/attachment.data";
|
import { AttachmentData } from "../data/attachment.data";
|
||||||
import { AttachmentView } from "../view/attachment.view";
|
import { AttachmentView } from "../view/attachment.view";
|
||||||
|
|
||||||
export class Attachment extends Domain {
|
export class Attachment extends Domain {
|
||||||
id: string;
|
id?: string;
|
||||||
url: string;
|
url?: string;
|
||||||
size: string;
|
size?: string;
|
||||||
sizeName: string; // Readable size, ex: "4.2 KB" or "1.43 GB"
|
sizeName?: string; // Readable size, ex: "4.2 KB" or "1.43 GB"
|
||||||
key: EncString;
|
key?: EncString;
|
||||||
fileName: EncString;
|
fileName?: EncString;
|
||||||
|
|
||||||
constructor(obj?: AttachmentData) {
|
constructor(obj?: AttachmentData) {
|
||||||
super();
|
super();
|
||||||
@@ -25,32 +25,24 @@ export class Attachment extends Domain {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.id = obj.id;
|
||||||
|
this.url = obj.url;
|
||||||
this.size = obj.size;
|
this.size = obj.size;
|
||||||
this.buildDomainModel(
|
this.sizeName = obj.sizeName;
|
||||||
this,
|
this.fileName = conditionalEncString(obj.fileName);
|
||||||
obj,
|
this.key = conditionalEncString(obj.key);
|
||||||
{
|
|
||||||
id: null,
|
|
||||||
url: null,
|
|
||||||
sizeName: null,
|
|
||||||
fileName: null,
|
|
||||||
key: null,
|
|
||||||
},
|
|
||||||
["id", "url", "sizeName"],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async decrypt(
|
async decrypt(
|
||||||
orgId: string,
|
orgId: string | undefined,
|
||||||
context = "No Cipher Context",
|
context = "No Cipher Context",
|
||||||
encKey?: SymmetricCryptoKey,
|
encKey?: SymmetricCryptoKey,
|
||||||
): Promise<AttachmentView> {
|
): Promise<AttachmentView> {
|
||||||
const view = await this.decryptObj<Attachment, AttachmentView>(
|
const view = await this.decryptObj<Attachment, AttachmentView>(
|
||||||
this,
|
this,
|
||||||
// @ts-expect-error ViewEncryptableKeys type should be fixed to allow for optional values, but is out of scope for now.
|
|
||||||
new AttachmentView(this),
|
new AttachmentView(this),
|
||||||
["fileName"],
|
["fileName"],
|
||||||
orgId,
|
orgId ?? null,
|
||||||
encKey,
|
encKey,
|
||||||
"DomainType: Attachment; " + context,
|
"DomainType: Attachment; " + context,
|
||||||
);
|
);
|
||||||
@@ -63,30 +55,46 @@ export class Attachment extends Domain {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async decryptAttachmentKey(orgId: string, encKey?: SymmetricCryptoKey) {
|
private async decryptAttachmentKey(
|
||||||
|
orgId: string | undefined,
|
||||||
|
encKey?: SymmetricCryptoKey,
|
||||||
|
): Promise<SymmetricCryptoKey | undefined> {
|
||||||
try {
|
try {
|
||||||
|
if (this.key == null) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
if (encKey == null) {
|
if (encKey == null) {
|
||||||
encKey = await this.getKeyForDecryption(orgId);
|
const key = await this.getKeyForDecryption(orgId);
|
||||||
|
|
||||||
|
// If we don't have a key, we can't decrypt
|
||||||
|
if (key == null) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
encKey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptService = Utils.getContainerService().getEncryptService();
|
const encryptService = Utils.getContainerService().getEncryptService();
|
||||||
const decValue = await encryptService.unwrapSymmetricKey(this.key, encKey);
|
const decValue = await encryptService.unwrapSymmetricKey(this.key, encKey);
|
||||||
return decValue;
|
return decValue;
|
||||||
// FIXME: Remove when updating file. Eslint update
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// TODO: error?
|
// eslint-disable-next-line no-console
|
||||||
|
console.error("[Attachment] Error decrypting attachment", e);
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getKeyForDecryption(orgId: string) {
|
private async getKeyForDecryption(orgId: string | undefined): Promise<OrgKey | UserKey | null> {
|
||||||
const keyService = Utils.getContainerService().getKeyService();
|
const keyService = Utils.getContainerService().getKeyService();
|
||||||
return orgId != null ? await keyService.getOrgKey(orgId) : await keyService.getUserKey();
|
return orgId != null ? await keyService.getOrgKey(orgId) : await keyService.getUserKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
toAttachmentData(): AttachmentData {
|
toAttachmentData(): AttachmentData {
|
||||||
const a = new AttachmentData();
|
const a = new AttachmentData();
|
||||||
a.size = this.size;
|
if (this.size != null) {
|
||||||
|
a.size = this.size;
|
||||||
|
}
|
||||||
this.buildDataModel(
|
this.buildDataModel(
|
||||||
this,
|
this,
|
||||||
a,
|
a,
|
||||||
@@ -102,18 +110,20 @@ export class Attachment extends Domain {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON(obj: Partial<Jsonify<Attachment>>): Attachment {
|
static fromJSON(obj: Partial<Jsonify<Attachment>> | undefined): Attachment | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = EncString.fromJSON(obj.key);
|
const attachment = new Attachment();
|
||||||
const fileName = EncString.fromJSON(obj.fileName);
|
attachment.id = obj.id;
|
||||||
|
attachment.url = obj.url;
|
||||||
|
attachment.size = obj.size;
|
||||||
|
attachment.sizeName = obj.sizeName;
|
||||||
|
attachment.key = encStringFrom(obj.key);
|
||||||
|
attachment.fileName = encStringFrom(obj.fileName);
|
||||||
|
|
||||||
return Object.assign(new Attachment(), obj, {
|
return attachment;
|
||||||
key,
|
|
||||||
fileName,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,7 +146,7 @@ export class Attachment extends Domain {
|
|||||||
* Maps an SDK Attachment object to an Attachment
|
* Maps an SDK Attachment object to an Attachment
|
||||||
* @param obj - The SDK attachment object
|
* @param obj - The SDK attachment object
|
||||||
*/
|
*/
|
||||||
static fromSdkAttachment(obj: SdkAttachment): Attachment | undefined {
|
static fromSdkAttachment(obj?: SdkAttachment): Attachment | undefined {
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -146,8 +156,8 @@ export class Attachment extends Domain {
|
|||||||
attachment.url = obj.url;
|
attachment.url = obj.url;
|
||||||
attachment.size = obj.size;
|
attachment.size = obj.size;
|
||||||
attachment.sizeName = obj.sizeName;
|
attachment.sizeName = obj.sizeName;
|
||||||
attachment.fileName = EncString.fromJSON(obj.fileName);
|
attachment.fileName = encStringFrom(obj.fileName);
|
||||||
attachment.key = EncString.fromJSON(obj.key);
|
attachment.key = encStringFrom(obj.key);
|
||||||
|
|
||||||
return attachment;
|
return attachment;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,12 +22,12 @@ describe("Card", () => {
|
|||||||
const card = new Card(data);
|
const card = new Card(data);
|
||||||
|
|
||||||
expect(card).toEqual({
|
expect(card).toEqual({
|
||||||
cardholderName: null,
|
cardholderName: undefined,
|
||||||
brand: null,
|
brand: undefined,
|
||||||
number: null,
|
number: undefined,
|
||||||
expMonth: null,
|
expMonth: undefined,
|
||||||
expYear: null,
|
expYear: undefined,
|
||||||
code: null,
|
code: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -94,8 +94,8 @@ describe("Card", () => {
|
|||||||
expect(actual).toBeInstanceOf(Card);
|
expect(actual).toBeInstanceOf(Card);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns null if object is null", () => {
|
it("returns undefined if object is null", () => {
|
||||||
expect(Card.fromJSON(null)).toBeNull();
|
expect(Card.fromJSON(null)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { Card as SdkCard } from "@bitwarden/sdk-internal";
|
import { Card as SdkCard } from "@bitwarden/sdk-internal";
|
||||||
@@ -7,16 +5,17 @@ import { Card as SdkCard } from "@bitwarden/sdk-internal";
|
|||||||
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
||||||
import Domain from "../../../platform/models/domain/domain-base";
|
import Domain from "../../../platform/models/domain/domain-base";
|
||||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||||
|
import { conditionalEncString, encStringFrom } from "../../utils/domain-utils";
|
||||||
import { CardData } from "../data/card.data";
|
import { CardData } from "../data/card.data";
|
||||||
import { CardView } from "../view/card.view";
|
import { CardView } from "../view/card.view";
|
||||||
|
|
||||||
export class Card extends Domain {
|
export class Card extends Domain {
|
||||||
cardholderName: EncString;
|
cardholderName?: EncString;
|
||||||
brand: EncString;
|
brand?: EncString;
|
||||||
number: EncString;
|
number?: EncString;
|
||||||
expMonth: EncString;
|
expMonth?: EncString;
|
||||||
expYear: EncString;
|
expYear?: EncString;
|
||||||
code: EncString;
|
code?: EncString;
|
||||||
|
|
||||||
constructor(obj?: CardData) {
|
constructor(obj?: CardData) {
|
||||||
super();
|
super();
|
||||||
@@ -24,23 +23,16 @@ export class Card extends Domain {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.buildDomainModel(
|
this.cardholderName = conditionalEncString(obj.cardholderName);
|
||||||
this,
|
this.brand = conditionalEncString(obj.brand);
|
||||||
obj,
|
this.number = conditionalEncString(obj.number);
|
||||||
{
|
this.expMonth = conditionalEncString(obj.expMonth);
|
||||||
cardholderName: null,
|
this.expYear = conditionalEncString(obj.expYear);
|
||||||
brand: null,
|
this.code = conditionalEncString(obj.code);
|
||||||
number: null,
|
|
||||||
expMonth: null,
|
|
||||||
expYear: null,
|
|
||||||
code: null,
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async decrypt(
|
async decrypt(
|
||||||
orgId: string,
|
orgId: string | undefined,
|
||||||
context = "No Cipher Context",
|
context = "No Cipher Context",
|
||||||
encKey?: SymmetricCryptoKey,
|
encKey?: SymmetricCryptoKey,
|
||||||
): Promise<CardView> {
|
): Promise<CardView> {
|
||||||
@@ -48,7 +40,7 @@ export class Card extends Domain {
|
|||||||
this,
|
this,
|
||||||
new CardView(),
|
new CardView(),
|
||||||
["cardholderName", "brand", "number", "expMonth", "expYear", "code"],
|
["cardholderName", "brand", "number", "expMonth", "expYear", "code"],
|
||||||
orgId,
|
orgId ?? null,
|
||||||
encKey,
|
encKey,
|
||||||
"DomainType: Card; " + context,
|
"DomainType: Card; " + context,
|
||||||
);
|
);
|
||||||
@@ -67,25 +59,20 @@ export class Card extends Domain {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON(obj: Partial<Jsonify<Card>>): Card {
|
static fromJSON(obj: Partial<Jsonify<Card>> | undefined): Card | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cardholderName = EncString.fromJSON(obj.cardholderName);
|
const card = new Card();
|
||||||
const brand = EncString.fromJSON(obj.brand);
|
card.cardholderName = encStringFrom(obj.cardholderName);
|
||||||
const number = EncString.fromJSON(obj.number);
|
card.brand = encStringFrom(obj.brand);
|
||||||
const expMonth = EncString.fromJSON(obj.expMonth);
|
card.number = encStringFrom(obj.number);
|
||||||
const expYear = EncString.fromJSON(obj.expYear);
|
card.expMonth = encStringFrom(obj.expMonth);
|
||||||
const code = EncString.fromJSON(obj.code);
|
card.expYear = encStringFrom(obj.expYear);
|
||||||
return Object.assign(new Card(), obj, {
|
card.code = encStringFrom(obj.code);
|
||||||
cardholderName,
|
|
||||||
brand,
|
return card;
|
||||||
number,
|
|
||||||
expMonth,
|
|
||||||
expYear,
|
|
||||||
code,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -108,18 +95,18 @@ export class Card extends Domain {
|
|||||||
* Maps an SDK Card object to a Card
|
* Maps an SDK Card object to a Card
|
||||||
* @param obj - The SDK Card object
|
* @param obj - The SDK Card object
|
||||||
*/
|
*/
|
||||||
static fromSdkCard(obj: SdkCard): Card | undefined {
|
static fromSdkCard(obj?: SdkCard): Card | undefined {
|
||||||
if (obj == null) {
|
if (!obj) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const card = new Card();
|
const card = new Card();
|
||||||
card.cardholderName = EncString.fromJSON(obj.cardholderName);
|
card.cardholderName = encStringFrom(obj.cardholderName);
|
||||||
card.brand = EncString.fromJSON(obj.brand);
|
card.brand = encStringFrom(obj.brand);
|
||||||
card.number = EncString.fromJSON(obj.number);
|
card.number = encStringFrom(obj.number);
|
||||||
card.expMonth = EncString.fromJSON(obj.expMonth);
|
card.expMonth = encStringFrom(obj.expMonth);
|
||||||
card.expYear = EncString.fromJSON(obj.expYear);
|
card.expYear = encStringFrom(obj.expYear);
|
||||||
card.code = EncString.fromJSON(obj.code);
|
card.code = encStringFrom(obj.code);
|
||||||
|
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,31 +44,28 @@ describe("Cipher DTO", () => {
|
|||||||
const data = new CipherData();
|
const data = new CipherData();
|
||||||
const cipher = new Cipher(data);
|
const cipher = new Cipher(data);
|
||||||
|
|
||||||
expect(cipher).toEqual({
|
expect(cipher.id).toBeUndefined();
|
||||||
initializerKey: InitializerKey.Cipher,
|
expect(cipher.organizationId).toBeUndefined();
|
||||||
id: null,
|
expect(cipher.folderId).toBeUndefined();
|
||||||
organizationId: null,
|
expect(cipher.name).toBeInstanceOf(EncString);
|
||||||
folderId: null,
|
expect(cipher.notes).toBeUndefined();
|
||||||
name: null,
|
expect(cipher.type).toBeUndefined();
|
||||||
notes: null,
|
expect(cipher.favorite).toBeUndefined();
|
||||||
type: undefined,
|
expect(cipher.organizationUseTotp).toBeUndefined();
|
||||||
favorite: undefined,
|
expect(cipher.edit).toBeUndefined();
|
||||||
organizationUseTotp: undefined,
|
expect(cipher.viewPassword).toBeUndefined();
|
||||||
edit: undefined,
|
expect(cipher.revisionDate).toBeInstanceOf(Date);
|
||||||
viewPassword: true,
|
expect(cipher.collectionIds).toEqual([]);
|
||||||
revisionDate: null,
|
expect(cipher.localData).toBeUndefined();
|
||||||
collectionIds: undefined,
|
expect(cipher.creationDate).toBeInstanceOf(Date);
|
||||||
localData: null,
|
expect(cipher.deletedDate).toBeUndefined();
|
||||||
creationDate: null,
|
expect(cipher.reprompt).toBeUndefined();
|
||||||
deletedDate: undefined,
|
expect(cipher.attachments).toBeUndefined();
|
||||||
reprompt: undefined,
|
expect(cipher.fields).toBeUndefined();
|
||||||
attachments: null,
|
expect(cipher.passwordHistory).toBeUndefined();
|
||||||
fields: null,
|
expect(cipher.key).toBeUndefined();
|
||||||
passwordHistory: null,
|
expect(cipher.permissions).toBeUndefined();
|
||||||
key: null,
|
expect(cipher.archivedDate).toBeUndefined();
|
||||||
permissions: undefined,
|
|
||||||
archivedDate: undefined,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Decrypt should handle cipher key error", async () => {
|
it("Decrypt should handle cipher key error", async () => {
|
||||||
@@ -121,7 +118,7 @@ describe("Cipher DTO", () => {
|
|||||||
edit: true,
|
edit: true,
|
||||||
viewPassword: true,
|
viewPassword: true,
|
||||||
decryptionFailure: true,
|
decryptionFailure: true,
|
||||||
collectionIds: undefined,
|
collectionIds: [],
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||||
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
||||||
deletedDate: undefined,
|
deletedDate: undefined,
|
||||||
@@ -155,6 +152,7 @@ describe("Cipher DTO", () => {
|
|||||||
reprompt: CipherRepromptType.None,
|
reprompt: CipherRepromptType.None,
|
||||||
key: "EncryptedString",
|
key: "EncryptedString",
|
||||||
archivedDate: undefined,
|
archivedDate: undefined,
|
||||||
|
collectionIds: [],
|
||||||
login: {
|
login: {
|
||||||
uris: [
|
uris: [
|
||||||
{
|
{
|
||||||
@@ -223,8 +221,8 @@ describe("Cipher DTO", () => {
|
|||||||
edit: true,
|
edit: true,
|
||||||
viewPassword: true,
|
viewPassword: true,
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||||
collectionIds: undefined,
|
collectionIds: [],
|
||||||
localData: null,
|
localData: undefined,
|
||||||
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
||||||
deletedDate: undefined,
|
deletedDate: undefined,
|
||||||
permissions: new CipherPermissionsApi(),
|
permissions: new CipherPermissionsApi(),
|
||||||
@@ -265,13 +263,13 @@ describe("Cipher DTO", () => {
|
|||||||
],
|
],
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
linkedId: null,
|
linkedId: undefined,
|
||||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||||
type: 0,
|
type: 0,
|
||||||
value: { encryptedString: "EncryptedString", encryptionType: 0 },
|
value: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
linkedId: null,
|
linkedId: undefined,
|
||||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||||
type: 1,
|
type: 1,
|
||||||
value: { encryptedString: "EncryptedString", encryptionType: 0 },
|
value: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||||
@@ -348,7 +346,7 @@ describe("Cipher DTO", () => {
|
|||||||
attachments: [],
|
attachments: [],
|
||||||
fields: [],
|
fields: [],
|
||||||
passwordHistory: [],
|
passwordHistory: [],
|
||||||
collectionIds: undefined,
|
collectionIds: [],
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||||
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
||||||
deletedDate: undefined,
|
deletedDate: undefined,
|
||||||
@@ -380,6 +378,7 @@ describe("Cipher DTO", () => {
|
|||||||
deletedDate: undefined,
|
deletedDate: undefined,
|
||||||
reprompt: CipherRepromptType.None,
|
reprompt: CipherRepromptType.None,
|
||||||
key: "EncKey",
|
key: "EncKey",
|
||||||
|
collectionIds: [],
|
||||||
secureNote: {
|
secureNote: {
|
||||||
type: SecureNoteType.Generic,
|
type: SecureNoteType.Generic,
|
||||||
},
|
},
|
||||||
@@ -404,15 +403,15 @@ describe("Cipher DTO", () => {
|
|||||||
edit: true,
|
edit: true,
|
||||||
viewPassword: true,
|
viewPassword: true,
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||||
collectionIds: undefined,
|
collectionIds: [],
|
||||||
localData: null,
|
localData: undefined,
|
||||||
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
||||||
deletedDate: undefined,
|
deletedDate: undefined,
|
||||||
reprompt: 0,
|
reprompt: 0,
|
||||||
secureNote: { type: SecureNoteType.Generic },
|
secureNote: { type: SecureNoteType.Generic },
|
||||||
attachments: null,
|
attachments: undefined,
|
||||||
fields: null,
|
fields: undefined,
|
||||||
passwordHistory: null,
|
passwordHistory: undefined,
|
||||||
key: { encryptedString: "EncKey", encryptionType: 0 },
|
key: { encryptedString: "EncKey", encryptionType: 0 },
|
||||||
permissions: new CipherPermissionsApi(),
|
permissions: new CipherPermissionsApi(),
|
||||||
archivedDate: undefined,
|
archivedDate: undefined,
|
||||||
@@ -475,7 +474,7 @@ describe("Cipher DTO", () => {
|
|||||||
attachments: [],
|
attachments: [],
|
||||||
fields: [],
|
fields: [],
|
||||||
passwordHistory: [],
|
passwordHistory: [],
|
||||||
collectionIds: undefined,
|
collectionIds: [],
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||||
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
||||||
deletedDate: undefined,
|
deletedDate: undefined,
|
||||||
@@ -507,6 +506,7 @@ describe("Cipher DTO", () => {
|
|||||||
deletedDate: undefined,
|
deletedDate: undefined,
|
||||||
permissions: new CipherPermissionsApi(),
|
permissions: new CipherPermissionsApi(),
|
||||||
reprompt: CipherRepromptType.None,
|
reprompt: CipherRepromptType.None,
|
||||||
|
collectionIds: [],
|
||||||
card: {
|
card: {
|
||||||
cardholderName: "EncryptedString",
|
cardholderName: "EncryptedString",
|
||||||
brand: "EncryptedString",
|
brand: "EncryptedString",
|
||||||
@@ -536,8 +536,8 @@ describe("Cipher DTO", () => {
|
|||||||
edit: true,
|
edit: true,
|
||||||
viewPassword: true,
|
viewPassword: true,
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||||
collectionIds: undefined,
|
collectionIds: [],
|
||||||
localData: null,
|
localData: undefined,
|
||||||
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
||||||
deletedDate: undefined,
|
deletedDate: undefined,
|
||||||
reprompt: 0,
|
reprompt: 0,
|
||||||
@@ -549,9 +549,9 @@ describe("Cipher DTO", () => {
|
|||||||
expYear: { encryptedString: "EncryptedString", encryptionType: 0 },
|
expYear: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||||
code: { encryptedString: "EncryptedString", encryptionType: 0 },
|
code: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||||
},
|
},
|
||||||
attachments: null,
|
attachments: undefined,
|
||||||
fields: null,
|
fields: undefined,
|
||||||
passwordHistory: null,
|
passwordHistory: undefined,
|
||||||
key: { encryptedString: "EncKey", encryptionType: 0 },
|
key: { encryptedString: "EncKey", encryptionType: 0 },
|
||||||
permissions: new CipherPermissionsApi(),
|
permissions: new CipherPermissionsApi(),
|
||||||
archivedDate: undefined,
|
archivedDate: undefined,
|
||||||
@@ -620,7 +620,7 @@ describe("Cipher DTO", () => {
|
|||||||
attachments: [],
|
attachments: [],
|
||||||
fields: [],
|
fields: [],
|
||||||
passwordHistory: [],
|
passwordHistory: [],
|
||||||
collectionIds: undefined,
|
collectionIds: [],
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||||
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
||||||
deletedDate: undefined,
|
deletedDate: undefined,
|
||||||
@@ -654,6 +654,7 @@ describe("Cipher DTO", () => {
|
|||||||
reprompt: CipherRepromptType.None,
|
reprompt: CipherRepromptType.None,
|
||||||
key: "EncKey",
|
key: "EncKey",
|
||||||
archivedDate: undefined,
|
archivedDate: undefined,
|
||||||
|
collectionIds: [],
|
||||||
identity: {
|
identity: {
|
||||||
title: "EncryptedString",
|
title: "EncryptedString",
|
||||||
firstName: "EncryptedString",
|
firstName: "EncryptedString",
|
||||||
@@ -693,8 +694,8 @@ describe("Cipher DTO", () => {
|
|||||||
edit: true,
|
edit: true,
|
||||||
viewPassword: true,
|
viewPassword: true,
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||||
collectionIds: undefined,
|
collectionIds: [],
|
||||||
localData: null,
|
localData: undefined,
|
||||||
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
||||||
deletedDate: undefined,
|
deletedDate: undefined,
|
||||||
reprompt: 0,
|
reprompt: 0,
|
||||||
@@ -719,9 +720,9 @@ describe("Cipher DTO", () => {
|
|||||||
passportNumber: { encryptedString: "EncryptedString", encryptionType: 0 },
|
passportNumber: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||||
licenseNumber: { encryptedString: "EncryptedString", encryptionType: 0 },
|
licenseNumber: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||||
},
|
},
|
||||||
attachments: null,
|
attachments: undefined,
|
||||||
fields: null,
|
fields: undefined,
|
||||||
passwordHistory: null,
|
passwordHistory: undefined,
|
||||||
key: { encryptedString: "EncKey", encryptionType: 0 },
|
key: { encryptedString: "EncKey", encryptionType: 0 },
|
||||||
permissions: new CipherPermissionsApi(),
|
permissions: new CipherPermissionsApi(),
|
||||||
});
|
});
|
||||||
@@ -789,7 +790,7 @@ describe("Cipher DTO", () => {
|
|||||||
attachments: [],
|
attachments: [],
|
||||||
fields: [],
|
fields: [],
|
||||||
passwordHistory: [],
|
passwordHistory: [],
|
||||||
collectionIds: undefined,
|
collectionIds: [],
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||||
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
creationDate: new Date("2022-01-01T12:00:00.000Z"),
|
||||||
deletedDate: undefined,
|
deletedDate: undefined,
|
||||||
@@ -858,8 +859,8 @@ describe("Cipher DTO", () => {
|
|||||||
expect(actual).toMatchObject(expected);
|
expect(actual).toMatchObject(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns null if object is null", () => {
|
it("returns undefined if object is undefined", () => {
|
||||||
expect(Cipher.fromJSON(null)).toBeNull();
|
expect(Cipher.fromJSON(undefined)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { Cipher as SdkCipher } from "@bitwarden/sdk-internal";
|
import { Cipher as SdkCipher } from "@bitwarden/sdk-internal";
|
||||||
@@ -13,6 +11,7 @@ import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-cr
|
|||||||
import { InitializerKey } from "../../../platform/services/cryptography/initializer-key";
|
import { InitializerKey } from "../../../platform/services/cryptography/initializer-key";
|
||||||
import { CipherRepromptType } from "../../enums/cipher-reprompt-type";
|
import { CipherRepromptType } from "../../enums/cipher-reprompt-type";
|
||||||
import { CipherType } from "../../enums/cipher-type";
|
import { CipherType } from "../../enums/cipher-type";
|
||||||
|
import { conditionalEncString, encStringFrom } from "../../utils/domain-utils";
|
||||||
import { CipherPermissionsApi } from "../api/cipher-permissions.api";
|
import { CipherPermissionsApi } from "../api/cipher-permissions.api";
|
||||||
import { CipherData } from "../data/cipher.data";
|
import { CipherData } from "../data/cipher.data";
|
||||||
import { LocalData, fromSdkLocalData, toSdkLocalData } from "../data/local.data";
|
import { LocalData, fromSdkLocalData, toSdkLocalData } from "../data/local.data";
|
||||||
@@ -33,71 +32,60 @@ import { SshKey } from "./ssh-key";
|
|||||||
export class Cipher extends Domain implements Decryptable<CipherView> {
|
export class Cipher extends Domain implements Decryptable<CipherView> {
|
||||||
readonly initializerKey = InitializerKey.Cipher;
|
readonly initializerKey = InitializerKey.Cipher;
|
||||||
|
|
||||||
id: string;
|
id: string = "";
|
||||||
organizationId: string;
|
organizationId?: string;
|
||||||
folderId: string;
|
folderId?: string;
|
||||||
name: EncString;
|
name: EncString = new EncString("");
|
||||||
notes: EncString;
|
notes?: EncString;
|
||||||
type: CipherType;
|
type: CipherType = CipherType.Login;
|
||||||
favorite: boolean;
|
favorite: boolean = false;
|
||||||
organizationUseTotp: boolean;
|
organizationUseTotp: boolean = false;
|
||||||
edit: boolean;
|
edit: boolean = false;
|
||||||
viewPassword: boolean;
|
viewPassword: boolean = true;
|
||||||
permissions: CipherPermissionsApi;
|
permissions?: CipherPermissionsApi;
|
||||||
revisionDate: Date;
|
revisionDate: Date;
|
||||||
localData: LocalData;
|
localData?: LocalData;
|
||||||
login: Login;
|
login?: Login;
|
||||||
identity: Identity;
|
identity?: Identity;
|
||||||
card: Card;
|
card?: Card;
|
||||||
secureNote: SecureNote;
|
secureNote?: SecureNote;
|
||||||
sshKey: SshKey;
|
sshKey?: SshKey;
|
||||||
attachments: Attachment[];
|
attachments?: Attachment[];
|
||||||
fields: Field[];
|
fields?: Field[];
|
||||||
passwordHistory: Password[];
|
passwordHistory?: Password[];
|
||||||
collectionIds: string[];
|
collectionIds: string[] = [];
|
||||||
creationDate: Date;
|
creationDate: Date;
|
||||||
deletedDate: Date | undefined;
|
deletedDate?: Date;
|
||||||
archivedDate: Date | undefined;
|
archivedDate?: Date;
|
||||||
reprompt: CipherRepromptType;
|
reprompt: CipherRepromptType = CipherRepromptType.None;
|
||||||
key: EncString;
|
key?: EncString;
|
||||||
|
|
||||||
constructor(obj?: CipherData, localData: LocalData = null) {
|
constructor(obj?: CipherData, localData?: LocalData) {
|
||||||
super();
|
super();
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
|
this.creationDate = this.revisionDate = new Date();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.buildDomainModel(
|
this.id = obj.id;
|
||||||
this,
|
this.organizationId = obj.organizationId;
|
||||||
obj,
|
this.folderId = obj.folderId;
|
||||||
{
|
this.name = new EncString(obj.name);
|
||||||
id: null,
|
this.notes = conditionalEncString(obj.notes);
|
||||||
organizationId: null,
|
|
||||||
folderId: null,
|
|
||||||
name: null,
|
|
||||||
notes: null,
|
|
||||||
key: null,
|
|
||||||
},
|
|
||||||
["id", "organizationId", "folderId"],
|
|
||||||
);
|
|
||||||
|
|
||||||
this.type = obj.type;
|
this.type = obj.type;
|
||||||
this.favorite = obj.favorite;
|
this.favorite = obj.favorite;
|
||||||
this.organizationUseTotp = obj.organizationUseTotp;
|
this.organizationUseTotp = obj.organizationUseTotp;
|
||||||
this.edit = obj.edit;
|
this.edit = obj.edit;
|
||||||
if (obj.viewPassword != null) {
|
this.viewPassword = obj.viewPassword;
|
||||||
this.viewPassword = obj.viewPassword;
|
|
||||||
} else {
|
|
||||||
this.viewPassword = true; // Default for already synced Ciphers without viewPassword
|
|
||||||
}
|
|
||||||
this.permissions = obj.permissions;
|
this.permissions = obj.permissions;
|
||||||
this.revisionDate = obj.revisionDate != null ? new Date(obj.revisionDate) : null;
|
this.revisionDate = new Date(obj.revisionDate);
|
||||||
this.collectionIds = obj.collectionIds;
|
|
||||||
this.localData = localData;
|
this.localData = localData;
|
||||||
this.creationDate = obj.creationDate != null ? new Date(obj.creationDate) : null;
|
this.collectionIds = obj.collectionIds ?? [];
|
||||||
|
this.creationDate = new Date(obj.creationDate);
|
||||||
this.deletedDate = obj.deletedDate != null ? new Date(obj.deletedDate) : undefined;
|
this.deletedDate = obj.deletedDate != null ? new Date(obj.deletedDate) : undefined;
|
||||||
this.archivedDate = obj.archivedDate != null ? new Date(obj.archivedDate) : undefined;
|
this.archivedDate = obj.archivedDate != null ? new Date(obj.archivedDate) : undefined;
|
||||||
this.reprompt = obj.reprompt;
|
this.reprompt = obj.reprompt;
|
||||||
|
this.key = conditionalEncString(obj.key);
|
||||||
|
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case CipherType.Login:
|
case CipherType.Login:
|
||||||
@@ -121,20 +109,14 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
|
|
||||||
if (obj.attachments != null) {
|
if (obj.attachments != null) {
|
||||||
this.attachments = obj.attachments.map((a) => new Attachment(a));
|
this.attachments = obj.attachments.map((a) => new Attachment(a));
|
||||||
} else {
|
|
||||||
this.attachments = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.fields != null) {
|
if (obj.fields != null) {
|
||||||
this.fields = obj.fields.map((f) => new Field(f));
|
this.fields = obj.fields.map((f) => new Field(f));
|
||||||
} else {
|
|
||||||
this.fields = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.passwordHistory != null) {
|
if (obj.passwordHistory != null) {
|
||||||
this.passwordHistory = obj.passwordHistory.map((ph) => new Password(ph));
|
this.passwordHistory = obj.passwordHistory.map((ph) => new Password(ph));
|
||||||
} else {
|
|
||||||
this.passwordHistory = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,46 +143,54 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
|
|
||||||
await this.decryptObj<Cipher, CipherView>(
|
await this.decryptObj<Cipher, CipherView>(
|
||||||
this,
|
this,
|
||||||
// @ts-expect-error Ciphers have optional Ids which are getting swallowed by the ViewEncryptableKeys type
|
|
||||||
// The ViewEncryptableKeys type should be fixed to allow for optional Ids, but is out of scope for now.
|
|
||||||
model,
|
model,
|
||||||
["name", "notes"],
|
["name", "notes"],
|
||||||
this.organizationId,
|
this.organizationId ?? null,
|
||||||
encKey,
|
encKey,
|
||||||
);
|
);
|
||||||
|
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case CipherType.Login:
|
case CipherType.Login:
|
||||||
model.login = await this.login.decrypt(
|
if (this.login != null) {
|
||||||
this.organizationId,
|
model.login = await this.login.decrypt(
|
||||||
bypassValidation,
|
this.organizationId,
|
||||||
`Cipher Id: ${this.id}`,
|
bypassValidation,
|
||||||
encKey,
|
`Cipher Id: ${this.id}`,
|
||||||
);
|
encKey,
|
||||||
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.SecureNote:
|
case CipherType.SecureNote:
|
||||||
model.secureNote = await this.secureNote.decrypt(
|
if (this.secureNote != null) {
|
||||||
this.organizationId,
|
model.secureNote = await this.secureNote.decrypt();
|
||||||
`Cipher Id: ${this.id}`,
|
}
|
||||||
encKey,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case CipherType.Card:
|
case CipherType.Card:
|
||||||
model.card = await this.card.decrypt(this.organizationId, `Cipher Id: ${this.id}`, encKey);
|
if (this.card != null) {
|
||||||
|
model.card = await this.card.decrypt(
|
||||||
|
this.organizationId,
|
||||||
|
`Cipher Id: ${this.id}`,
|
||||||
|
encKey,
|
||||||
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.Identity:
|
case CipherType.Identity:
|
||||||
model.identity = await this.identity.decrypt(
|
if (this.identity != null) {
|
||||||
this.organizationId,
|
model.identity = await this.identity.decrypt(
|
||||||
`Cipher Id: ${this.id}`,
|
this.organizationId,
|
||||||
encKey,
|
`Cipher Id: ${this.id}`,
|
||||||
);
|
encKey,
|
||||||
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.SshKey:
|
case CipherType.SshKey:
|
||||||
model.sshKey = await this.sshKey.decrypt(
|
if (this.sshKey != null) {
|
||||||
this.organizationId,
|
model.sshKey = await this.sshKey.decrypt(
|
||||||
`Cipher Id: ${this.id}`,
|
this.organizationId,
|
||||||
encKey,
|
`Cipher Id: ${this.id}`,
|
||||||
);
|
encKey,
|
||||||
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -209,9 +199,12 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
if (this.attachments != null && this.attachments.length > 0) {
|
if (this.attachments != null && this.attachments.length > 0) {
|
||||||
const attachments: AttachmentView[] = [];
|
const attachments: AttachmentView[] = [];
|
||||||
for (const attachment of this.attachments) {
|
for (const attachment of this.attachments) {
|
||||||
attachments.push(
|
const decryptedAttachment = await attachment.decrypt(
|
||||||
await attachment.decrypt(this.organizationId, `Cipher Id: ${this.id}`, encKey),
|
this.organizationId,
|
||||||
|
`Cipher Id: ${this.id}`,
|
||||||
|
encKey,
|
||||||
);
|
);
|
||||||
|
attachments.push(decryptedAttachment);
|
||||||
}
|
}
|
||||||
model.attachments = attachments;
|
model.attachments = attachments;
|
||||||
}
|
}
|
||||||
@@ -219,7 +212,8 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
if (this.fields != null && this.fields.length > 0) {
|
if (this.fields != null && this.fields.length > 0) {
|
||||||
const fields: FieldView[] = [];
|
const fields: FieldView[] = [];
|
||||||
for (const field of this.fields) {
|
for (const field of this.fields) {
|
||||||
fields.push(await field.decrypt(this.organizationId, encKey));
|
const decryptedField = await field.decrypt(this.organizationId, encKey);
|
||||||
|
fields.push(decryptedField);
|
||||||
}
|
}
|
||||||
model.fields = fields;
|
model.fields = fields;
|
||||||
}
|
}
|
||||||
@@ -227,7 +221,8 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
if (this.passwordHistory != null && this.passwordHistory.length > 0) {
|
if (this.passwordHistory != null && this.passwordHistory.length > 0) {
|
||||||
const passwordHistory: PasswordHistoryView[] = [];
|
const passwordHistory: PasswordHistoryView[] = [];
|
||||||
for (const ph of this.passwordHistory) {
|
for (const ph of this.passwordHistory) {
|
||||||
passwordHistory.push(await ph.decrypt(this.organizationId, encKey));
|
const decryptedPh = await ph.decrypt(this.organizationId, encKey);
|
||||||
|
passwordHistory.push(decryptedPh);
|
||||||
}
|
}
|
||||||
model.passwordHistory = passwordHistory;
|
model.passwordHistory = passwordHistory;
|
||||||
}
|
}
|
||||||
@@ -238,20 +233,32 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
toCipherData(): CipherData {
|
toCipherData(): CipherData {
|
||||||
const c = new CipherData();
|
const c = new CipherData();
|
||||||
c.id = this.id;
|
c.id = this.id;
|
||||||
c.organizationId = this.organizationId;
|
if (this.organizationId != null) {
|
||||||
c.folderId = this.folderId;
|
c.organizationId = this.organizationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.folderId != null) {
|
||||||
|
c.folderId = this.folderId;
|
||||||
|
}
|
||||||
c.edit = this.edit;
|
c.edit = this.edit;
|
||||||
c.viewPassword = this.viewPassword;
|
c.viewPassword = this.viewPassword;
|
||||||
c.organizationUseTotp = this.organizationUseTotp;
|
c.organizationUseTotp = this.organizationUseTotp;
|
||||||
c.favorite = this.favorite;
|
c.favorite = this.favorite;
|
||||||
c.revisionDate = this.revisionDate != null ? this.revisionDate.toISOString() : null;
|
c.revisionDate = this.revisionDate.toISOString();
|
||||||
c.type = this.type;
|
c.type = this.type;
|
||||||
c.collectionIds = this.collectionIds;
|
c.collectionIds = this.collectionIds;
|
||||||
c.creationDate = this.creationDate != null ? this.creationDate.toISOString() : null;
|
c.creationDate = this.creationDate.toISOString();
|
||||||
c.deletedDate = this.deletedDate != null ? this.deletedDate.toISOString() : undefined;
|
c.deletedDate = this.deletedDate != null ? this.deletedDate.toISOString() : undefined;
|
||||||
c.reprompt = this.reprompt;
|
c.reprompt = this.reprompt;
|
||||||
c.key = this.key?.encryptedString;
|
|
||||||
c.permissions = this.permissions;
|
if (this.key != null && this.key.encryptedString != null) {
|
||||||
|
c.key = this.key.encryptedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.permissions != null) {
|
||||||
|
c.permissions = this.permissions;
|
||||||
|
}
|
||||||
|
|
||||||
c.archivedDate = this.archivedDate != null ? this.archivedDate.toISOString() : undefined;
|
c.archivedDate = this.archivedDate != null ? this.archivedDate.toISOString() : undefined;
|
||||||
|
|
||||||
this.buildDataModel(this, c, {
|
this.buildDataModel(this, c, {
|
||||||
@@ -261,19 +268,29 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
|
|
||||||
switch (c.type) {
|
switch (c.type) {
|
||||||
case CipherType.Login:
|
case CipherType.Login:
|
||||||
c.login = this.login.toLoginData();
|
if (this.login != null) {
|
||||||
|
c.login = this.login.toLoginData();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.SecureNote:
|
case CipherType.SecureNote:
|
||||||
c.secureNote = this.secureNote.toSecureNoteData();
|
if (this.secureNote != null) {
|
||||||
|
c.secureNote = this.secureNote.toSecureNoteData();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.Card:
|
case CipherType.Card:
|
||||||
c.card = this.card.toCardData();
|
if (this.card != null) {
|
||||||
|
c.card = this.card.toCardData();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.Identity:
|
case CipherType.Identity:
|
||||||
c.identity = this.identity.toIdentityData();
|
if (this.identity != null) {
|
||||||
|
c.identity = this.identity.toIdentityData();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.SshKey:
|
case CipherType.SshKey:
|
||||||
c.sshKey = this.sshKey.toSshKeyData();
|
if (this.sshKey != null) {
|
||||||
|
c.sshKey = this.sshKey.toSshKeyData();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -291,51 +308,71 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON(obj: Jsonify<Cipher>) {
|
static fromJSON(obj: Jsonify<Cipher> | undefined): Cipher | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const domain = new Cipher();
|
const domain = new Cipher();
|
||||||
const name = EncString.fromJSON(obj.name);
|
|
||||||
const notes = EncString.fromJSON(obj.notes);
|
|
||||||
const creationDate = obj.creationDate == null ? null : new Date(obj.creationDate);
|
|
||||||
const revisionDate = obj.revisionDate == null ? null : new Date(obj.revisionDate);
|
|
||||||
const deletedDate = obj.deletedDate == null ? undefined : new Date(obj.deletedDate);
|
|
||||||
const attachments = obj.attachments?.map((a: any) => Attachment.fromJSON(a));
|
|
||||||
const fields = obj.fields?.map((f: any) => Field.fromJSON(f));
|
|
||||||
const passwordHistory = obj.passwordHistory?.map((ph: any) => Password.fromJSON(ph));
|
|
||||||
const key = EncString.fromJSON(obj.key);
|
|
||||||
const archivedDate = obj.archivedDate == null ? undefined : new Date(obj.archivedDate);
|
|
||||||
|
|
||||||
Object.assign(domain, obj, {
|
domain.id = obj.id;
|
||||||
name,
|
domain.organizationId = obj.organizationId;
|
||||||
notes,
|
domain.folderId = obj.folderId;
|
||||||
creationDate,
|
domain.type = obj.type;
|
||||||
revisionDate,
|
domain.favorite = obj.favorite;
|
||||||
deletedDate,
|
domain.organizationUseTotp = obj.organizationUseTotp;
|
||||||
attachments,
|
domain.edit = obj.edit;
|
||||||
fields,
|
domain.viewPassword = obj.viewPassword;
|
||||||
passwordHistory,
|
|
||||||
key,
|
if (obj.permissions != null) {
|
||||||
archivedDate,
|
domain.permissions = new CipherPermissionsApi(obj.permissions);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
domain.collectionIds = obj.collectionIds;
|
||||||
|
domain.localData = obj.localData;
|
||||||
|
domain.reprompt = obj.reprompt;
|
||||||
|
domain.creationDate = new Date(obj.creationDate);
|
||||||
|
domain.revisionDate = new Date(obj.revisionDate);
|
||||||
|
domain.deletedDate = obj.deletedDate != null ? new Date(obj.deletedDate) : undefined;
|
||||||
|
domain.archivedDate = obj.archivedDate != null ? new Date(obj.archivedDate) : undefined;
|
||||||
|
domain.name = EncString.fromJSON(obj.name);
|
||||||
|
domain.notes = encStringFrom(obj.notes);
|
||||||
|
domain.key = encStringFrom(obj.key);
|
||||||
|
domain.attachments = obj.attachments
|
||||||
|
?.map((a: any) => Attachment.fromJSON(a))
|
||||||
|
.filter((a): a is Attachment => a != null);
|
||||||
|
domain.fields = obj.fields
|
||||||
|
?.map((f: any) => Field.fromJSON(f))
|
||||||
|
.filter((f): f is Field => f != null);
|
||||||
|
domain.passwordHistory = obj.passwordHistory
|
||||||
|
?.map((ph: any) => Password.fromJSON(ph))
|
||||||
|
.filter((ph): ph is Password => ph != null);
|
||||||
|
|
||||||
switch (obj.type) {
|
switch (obj.type) {
|
||||||
case CipherType.Card:
|
case CipherType.Card:
|
||||||
domain.card = Card.fromJSON(obj.card);
|
if (obj.card != null) {
|
||||||
|
domain.card = Card.fromJSON(obj.card);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.Identity:
|
case CipherType.Identity:
|
||||||
domain.identity = Identity.fromJSON(obj.identity);
|
if (obj.identity != null) {
|
||||||
|
domain.identity = Identity.fromJSON(obj.identity);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.Login:
|
case CipherType.Login:
|
||||||
domain.login = Login.fromJSON(obj.login);
|
if (obj.login != null) {
|
||||||
|
domain.login = Login.fromJSON(obj.login);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.SecureNote:
|
case CipherType.SecureNote:
|
||||||
domain.secureNote = SecureNote.fromJSON(obj.secureNote);
|
if (obj.secureNote != null) {
|
||||||
|
domain.secureNote = SecureNote.fromJSON(obj.secureNote);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.SshKey:
|
case CipherType.SshKey:
|
||||||
domain.sshKey = SshKey.fromJSON(obj.sshKey);
|
if (obj.sshKey != null) {
|
||||||
|
domain.sshKey = SshKey.fromJSON(obj.sshKey);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -359,22 +396,22 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
name: this.name.toSdk(),
|
name: this.name.toSdk(),
|
||||||
notes: this.notes?.toSdk(),
|
notes: this.notes?.toSdk(),
|
||||||
type: this.type,
|
type: this.type,
|
||||||
favorite: this.favorite ?? false,
|
favorite: this.favorite,
|
||||||
organizationUseTotp: this.organizationUseTotp ?? false,
|
organizationUseTotp: this.organizationUseTotp,
|
||||||
edit: this.edit ?? true,
|
edit: this.edit,
|
||||||
permissions: this.permissions
|
permissions: this.permissions
|
||||||
? {
|
? {
|
||||||
delete: this.permissions.delete,
|
delete: this.permissions.delete,
|
||||||
restore: this.permissions.restore,
|
restore: this.permissions.restore,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
viewPassword: this.viewPassword ?? true,
|
viewPassword: this.viewPassword,
|
||||||
localData: toSdkLocalData(this.localData),
|
localData: toSdkLocalData(this.localData),
|
||||||
attachments: this.attachments?.map((a) => a.toSdkAttachment()),
|
attachments: this.attachments?.map((a) => a.toSdkAttachment()),
|
||||||
fields: this.fields?.map((f) => f.toSdkField()),
|
fields: this.fields?.map((f) => f.toSdkField()),
|
||||||
passwordHistory: this.passwordHistory?.map((ph) => ph.toSdkPasswordHistory()),
|
passwordHistory: this.passwordHistory?.map((ph) => ph.toSdkPasswordHistory()),
|
||||||
revisionDate: this.revisionDate?.toISOString(),
|
revisionDate: this.revisionDate.toISOString(),
|
||||||
creationDate: this.creationDate?.toISOString(),
|
creationDate: this.creationDate.toISOString(),
|
||||||
deletedDate: this.deletedDate?.toISOString(),
|
deletedDate: this.deletedDate?.toISOString(),
|
||||||
archivedDate: this.archivedDate?.toISOString(),
|
archivedDate: this.archivedDate?.toISOString(),
|
||||||
reprompt: this.reprompt,
|
reprompt: this.reprompt,
|
||||||
@@ -388,19 +425,29 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
|
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case CipherType.Login:
|
case CipherType.Login:
|
||||||
sdkCipher.login = this.login.toSdkLogin();
|
if (this.login != null) {
|
||||||
|
sdkCipher.login = this.login.toSdkLogin();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.SecureNote:
|
case CipherType.SecureNote:
|
||||||
sdkCipher.secureNote = this.secureNote.toSdkSecureNote();
|
if (this.secureNote != null) {
|
||||||
|
sdkCipher.secureNote = this.secureNote.toSdkSecureNote();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.Card:
|
case CipherType.Card:
|
||||||
sdkCipher.card = this.card.toSdkCard();
|
if (this.card != null) {
|
||||||
|
sdkCipher.card = this.card.toSdkCard();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.Identity:
|
case CipherType.Identity:
|
||||||
sdkCipher.identity = this.identity.toSdkIdentity();
|
if (this.identity != null) {
|
||||||
|
sdkCipher.identity = this.identity.toSdkIdentity();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CipherType.SshKey:
|
case CipherType.SshKey:
|
||||||
sdkCipher.sshKey = this.sshKey.toSdkSshKey();
|
if (this.sshKey != null) {
|
||||||
|
sdkCipher.sshKey = this.sshKey.toSdkSshKey();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -413,22 +460,22 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
* Maps an SDK Cipher object to a Cipher
|
* Maps an SDK Cipher object to a Cipher
|
||||||
* @param sdkCipher - The SDK Cipher object
|
* @param sdkCipher - The SDK Cipher object
|
||||||
*/
|
*/
|
||||||
static fromSdkCipher(sdkCipher: SdkCipher | null): Cipher | undefined {
|
static fromSdkCipher(sdkCipher?: SdkCipher): Cipher | undefined {
|
||||||
if (sdkCipher == null) {
|
if (sdkCipher == null) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cipher = new Cipher();
|
const cipher = new Cipher();
|
||||||
|
|
||||||
cipher.id = sdkCipher.id ? uuidAsString(sdkCipher.id) : undefined;
|
cipher.id = sdkCipher.id ? uuidAsString(sdkCipher.id) : "";
|
||||||
cipher.organizationId = sdkCipher.organizationId
|
cipher.organizationId = sdkCipher.organizationId
|
||||||
? uuidAsString(sdkCipher.organizationId)
|
? uuidAsString(sdkCipher.organizationId)
|
||||||
: undefined;
|
: undefined;
|
||||||
cipher.folderId = sdkCipher.folderId ? uuidAsString(sdkCipher.folderId) : undefined;
|
cipher.folderId = sdkCipher.folderId ? uuidAsString(sdkCipher.folderId) : undefined;
|
||||||
cipher.collectionIds = sdkCipher.collectionIds ? sdkCipher.collectionIds.map(uuidAsString) : [];
|
cipher.collectionIds = sdkCipher.collectionIds ? sdkCipher.collectionIds.map(uuidAsString) : [];
|
||||||
cipher.key = EncString.fromJSON(sdkCipher.key);
|
cipher.key = encStringFrom(sdkCipher.key);
|
||||||
cipher.name = EncString.fromJSON(sdkCipher.name);
|
cipher.name = EncString.fromJSON(sdkCipher.name);
|
||||||
cipher.notes = EncString.fromJSON(sdkCipher.notes);
|
cipher.notes = encStringFrom(sdkCipher.notes);
|
||||||
cipher.type = sdkCipher.type;
|
cipher.type = sdkCipher.type;
|
||||||
cipher.favorite = sdkCipher.favorite;
|
cipher.favorite = sdkCipher.favorite;
|
||||||
cipher.organizationUseTotp = sdkCipher.organizationUseTotp;
|
cipher.organizationUseTotp = sdkCipher.organizationUseTotp;
|
||||||
@@ -436,10 +483,15 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
cipher.permissions = CipherPermissionsApi.fromSdkCipherPermissions(sdkCipher.permissions);
|
cipher.permissions = CipherPermissionsApi.fromSdkCipherPermissions(sdkCipher.permissions);
|
||||||
cipher.viewPassword = sdkCipher.viewPassword;
|
cipher.viewPassword = sdkCipher.viewPassword;
|
||||||
cipher.localData = fromSdkLocalData(sdkCipher.localData);
|
cipher.localData = fromSdkLocalData(sdkCipher.localData);
|
||||||
cipher.attachments = sdkCipher.attachments?.map((a) => Attachment.fromSdkAttachment(a)) ?? [];
|
cipher.attachments = sdkCipher.attachments
|
||||||
cipher.fields = sdkCipher.fields?.map((f) => Field.fromSdkField(f)) ?? [];
|
?.map((a) => Attachment.fromSdkAttachment(a))
|
||||||
cipher.passwordHistory =
|
.filter((a): a is Attachment => a != null);
|
||||||
sdkCipher.passwordHistory?.map((ph) => Password.fromSdkPasswordHistory(ph)) ?? [];
|
cipher.fields = sdkCipher.fields
|
||||||
|
?.map((f) => Field.fromSdkField(f))
|
||||||
|
.filter((f): f is Field => f != null);
|
||||||
|
cipher.passwordHistory = sdkCipher.passwordHistory
|
||||||
|
?.map((ph) => Password.fromSdkPasswordHistory(ph))
|
||||||
|
.filter((ph): ph is Password => ph != null);
|
||||||
cipher.creationDate = new Date(sdkCipher.creationDate);
|
cipher.creationDate = new Date(sdkCipher.creationDate);
|
||||||
cipher.revisionDate = new Date(sdkCipher.revisionDate);
|
cipher.revisionDate = new Date(sdkCipher.revisionDate);
|
||||||
cipher.deletedDate = sdkCipher.deletedDate ? new Date(sdkCipher.deletedDate) : undefined;
|
cipher.deletedDate = sdkCipher.deletedDate ? new Date(sdkCipher.deletedDate) : undefined;
|
||||||
|
|||||||
@@ -13,25 +13,23 @@ describe("Fido2Credential", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("constructor", () => {
|
describe("constructor", () => {
|
||||||
it("returns all fields null when given empty data parameter", () => {
|
it("returns all fields undefined when given empty data parameter", () => {
|
||||||
const data = new Fido2CredentialData();
|
const data = new Fido2CredentialData();
|
||||||
const credential = new Fido2Credential(data);
|
const credential = new Fido2Credential(data);
|
||||||
|
|
||||||
expect(credential).toEqual({
|
expect(credential.credentialId).toBeDefined();
|
||||||
credentialId: null,
|
expect(credential.keyType).toBeDefined();
|
||||||
keyType: null,
|
expect(credential.keyAlgorithm).toBeDefined();
|
||||||
keyAlgorithm: null,
|
expect(credential.keyCurve).toBeDefined();
|
||||||
keyCurve: null,
|
expect(credential.keyValue).toBeDefined();
|
||||||
keyValue: null,
|
expect(credential.rpId).toBeDefined();
|
||||||
rpId: null,
|
expect(credential.counter).toBeDefined();
|
||||||
userHandle: null,
|
expect(credential.discoverable).toBeDefined();
|
||||||
userName: null,
|
expect(credential.userHandle).toBeUndefined();
|
||||||
rpName: null,
|
expect(credential.userName).toBeUndefined();
|
||||||
userDisplayName: null,
|
expect(credential.rpName).toBeUndefined();
|
||||||
counter: null,
|
expect(credential.userDisplayName).toBeUndefined();
|
||||||
discoverable: null,
|
expect(credential.creationDate).toBeInstanceOf(Date);
|
||||||
creationDate: null,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns all fields as EncStrings except creationDate when given full Fido2CredentialData", () => {
|
it("returns all fields as EncStrings except creationDate when given full Fido2CredentialData", () => {
|
||||||
@@ -69,12 +67,22 @@ describe("Fido2Credential", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not populate fields when data parameter is not given", () => {
|
it("should not populate fields when data parameter is not given except creationDate", () => {
|
||||||
const credential = new Fido2Credential();
|
const credential = new Fido2Credential();
|
||||||
|
|
||||||
expect(credential).toEqual({
|
expect(credential.credentialId).toBeUndefined();
|
||||||
credentialId: null,
|
expect(credential.keyType).toBeUndefined();
|
||||||
});
|
expect(credential.keyAlgorithm).toBeUndefined();
|
||||||
|
expect(credential.keyCurve).toBeUndefined();
|
||||||
|
expect(credential.keyValue).toBeUndefined();
|
||||||
|
expect(credential.rpId).toBeUndefined();
|
||||||
|
expect(credential.userHandle).toBeUndefined();
|
||||||
|
expect(credential.userName).toBeUndefined();
|
||||||
|
expect(credential.counter).toBeUndefined();
|
||||||
|
expect(credential.rpName).toBeUndefined();
|
||||||
|
expect(credential.userDisplayName).toBeUndefined();
|
||||||
|
expect(credential.discoverable).toBeUndefined();
|
||||||
|
expect(credential.creationDate).toBeInstanceOf(Date);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -163,8 +171,8 @@ describe("Fido2Credential", () => {
|
|||||||
expect(result).toEqual(credential);
|
expect(result).toEqual(credential);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns null if input is null", () => {
|
it("returns undefined if input is null", () => {
|
||||||
expect(Fido2Credential.fromJSON(null)).toBeNull();
|
expect(Fido2Credential.fromJSON(null)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { Fido2Credential as SdkFido2Credential } from "@bitwarden/sdk-internal";
|
import { Fido2Credential as SdkFido2Credential } from "@bitwarden/sdk-internal";
|
||||||
@@ -7,56 +5,53 @@ import { Fido2Credential as SdkFido2Credential } from "@bitwarden/sdk-internal";
|
|||||||
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
||||||
import Domain from "../../../platform/models/domain/domain-base";
|
import Domain from "../../../platform/models/domain/domain-base";
|
||||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||||
|
import { conditionalEncString, encStringFrom } from "../../utils/domain-utils";
|
||||||
import { Fido2CredentialData } from "../data/fido2-credential.data";
|
import { Fido2CredentialData } from "../data/fido2-credential.data";
|
||||||
import { Fido2CredentialView } from "../view/fido2-credential.view";
|
import { Fido2CredentialView } from "../view/fido2-credential.view";
|
||||||
|
|
||||||
export class Fido2Credential extends Domain {
|
export class Fido2Credential extends Domain {
|
||||||
credentialId: EncString | null = null;
|
credentialId!: EncString;
|
||||||
keyType: EncString;
|
keyType!: EncString;
|
||||||
keyAlgorithm: EncString;
|
keyAlgorithm!: EncString;
|
||||||
keyCurve: EncString;
|
keyCurve!: EncString;
|
||||||
keyValue: EncString;
|
keyValue!: EncString;
|
||||||
rpId: EncString;
|
rpId!: EncString;
|
||||||
userHandle: EncString;
|
userHandle?: EncString;
|
||||||
userName: EncString;
|
userName?: EncString;
|
||||||
counter: EncString;
|
counter!: EncString;
|
||||||
rpName: EncString;
|
rpName?: EncString;
|
||||||
userDisplayName: EncString;
|
userDisplayName?: EncString;
|
||||||
discoverable: EncString;
|
discoverable!: EncString;
|
||||||
creationDate: Date;
|
creationDate!: Date;
|
||||||
|
|
||||||
constructor(obj?: Fido2CredentialData) {
|
constructor(obj?: Fido2CredentialData) {
|
||||||
super();
|
super();
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
|
this.creationDate = new Date();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.buildDomainModel(
|
this.credentialId = new EncString(obj.credentialId);
|
||||||
this,
|
this.keyType = new EncString(obj.keyType);
|
||||||
obj,
|
this.keyAlgorithm = new EncString(obj.keyAlgorithm);
|
||||||
{
|
this.keyCurve = new EncString(obj.keyCurve);
|
||||||
credentialId: null,
|
this.keyValue = new EncString(obj.keyValue);
|
||||||
keyType: null,
|
this.rpId = new EncString(obj.rpId);
|
||||||
keyAlgorithm: null,
|
this.counter = new EncString(obj.counter);
|
||||||
keyCurve: null,
|
this.discoverable = new EncString(obj.discoverable);
|
||||||
keyValue: null,
|
this.userHandle = conditionalEncString(obj.userHandle);
|
||||||
rpId: null,
|
this.userName = conditionalEncString(obj.userName);
|
||||||
userHandle: null,
|
this.rpName = conditionalEncString(obj.rpName);
|
||||||
userName: null,
|
this.userDisplayName = conditionalEncString(obj.userDisplayName);
|
||||||
counter: null,
|
this.creationDate = new Date(obj.creationDate);
|
||||||
rpName: null,
|
|
||||||
userDisplayName: null,
|
|
||||||
discoverable: null,
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
this.creationDate = obj.creationDate != null ? new Date(obj.creationDate) : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<Fido2CredentialView> {
|
async decrypt(
|
||||||
|
orgId: string | undefined,
|
||||||
|
encKey?: SymmetricCryptoKey,
|
||||||
|
): Promise<Fido2CredentialView> {
|
||||||
const view = await this.decryptObj<Fido2Credential, Fido2CredentialView>(
|
const view = await this.decryptObj<Fido2Credential, Fido2CredentialView>(
|
||||||
this,
|
this,
|
||||||
// @ts-expect-error ViewEncryptableKeys type should be fixed to allow for optional values, but is out of scope for now.
|
|
||||||
new Fido2CredentialView(),
|
new Fido2CredentialView(),
|
||||||
[
|
[
|
||||||
"credentialId",
|
"credentialId",
|
||||||
@@ -70,7 +65,7 @@ export class Fido2Credential extends Domain {
|
|||||||
"rpName",
|
"rpName",
|
||||||
"userDisplayName",
|
"userDisplayName",
|
||||||
],
|
],
|
||||||
orgId,
|
orgId ?? null,
|
||||||
encKey,
|
encKey,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -79,7 +74,7 @@ export class Fido2Credential extends Domain {
|
|||||||
{
|
{
|
||||||
counter: string;
|
counter: string;
|
||||||
}
|
}
|
||||||
>(this, { counter: "" }, ["counter"], orgId, encKey);
|
>(this, { counter: "" }, ["counter"], orgId ?? null, encKey);
|
||||||
// Counter will end up as NaN if this fails
|
// Counter will end up as NaN if this fails
|
||||||
view.counter = parseInt(counter);
|
view.counter = parseInt(counter);
|
||||||
|
|
||||||
@@ -87,7 +82,7 @@ export class Fido2Credential extends Domain {
|
|||||||
this,
|
this,
|
||||||
{ discoverable: "" },
|
{ discoverable: "" },
|
||||||
["discoverable"],
|
["discoverable"],
|
||||||
orgId,
|
orgId ?? null,
|
||||||
encKey,
|
encKey,
|
||||||
);
|
);
|
||||||
view.discoverable = discoverable === "true";
|
view.discoverable = discoverable === "true";
|
||||||
@@ -116,40 +111,28 @@ export class Fido2Credential extends Domain {
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON(obj: Jsonify<Fido2Credential>): Fido2Credential {
|
static fromJSON(obj: Jsonify<Fido2Credential> | undefined): Fido2Credential | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const credentialId = EncString.fromJSON(obj.credentialId);
|
const credential = new Fido2Credential();
|
||||||
const keyType = EncString.fromJSON(obj.keyType);
|
|
||||||
const keyAlgorithm = EncString.fromJSON(obj.keyAlgorithm);
|
|
||||||
const keyCurve = EncString.fromJSON(obj.keyCurve);
|
|
||||||
const keyValue = EncString.fromJSON(obj.keyValue);
|
|
||||||
const rpId = EncString.fromJSON(obj.rpId);
|
|
||||||
const userHandle = EncString.fromJSON(obj.userHandle);
|
|
||||||
const userName = EncString.fromJSON(obj.userName);
|
|
||||||
const counter = EncString.fromJSON(obj.counter);
|
|
||||||
const rpName = EncString.fromJSON(obj.rpName);
|
|
||||||
const userDisplayName = EncString.fromJSON(obj.userDisplayName);
|
|
||||||
const discoverable = EncString.fromJSON(obj.discoverable);
|
|
||||||
const creationDate = obj.creationDate != null ? new Date(obj.creationDate) : null;
|
|
||||||
|
|
||||||
return Object.assign(new Fido2Credential(), obj, {
|
credential.credentialId = EncString.fromJSON(obj.credentialId);
|
||||||
credentialId,
|
credential.keyType = EncString.fromJSON(obj.keyType);
|
||||||
keyType,
|
credential.keyAlgorithm = EncString.fromJSON(obj.keyAlgorithm);
|
||||||
keyAlgorithm,
|
credential.keyCurve = EncString.fromJSON(obj.keyCurve);
|
||||||
keyCurve,
|
credential.keyValue = EncString.fromJSON(obj.keyValue);
|
||||||
keyValue,
|
credential.rpId = EncString.fromJSON(obj.rpId);
|
||||||
rpId,
|
credential.userHandle = encStringFrom(obj.userHandle);
|
||||||
userHandle,
|
credential.userName = encStringFrom(obj.userName);
|
||||||
userName,
|
credential.counter = EncString.fromJSON(obj.counter);
|
||||||
counter,
|
credential.rpName = encStringFrom(obj.rpName);
|
||||||
rpName,
|
credential.userDisplayName = encStringFrom(obj.userDisplayName);
|
||||||
userDisplayName,
|
credential.discoverable = EncString.fromJSON(obj.discoverable);
|
||||||
discoverable,
|
credential.creationDate = new Date(obj.creationDate);
|
||||||
creationDate,
|
|
||||||
});
|
return credential;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -179,8 +162,8 @@ export class Fido2Credential extends Domain {
|
|||||||
* Maps an SDK Fido2Credential object to a Fido2Credential
|
* Maps an SDK Fido2Credential object to a Fido2Credential
|
||||||
* @param obj - The SDK Fido2Credential object
|
* @param obj - The SDK Fido2Credential object
|
||||||
*/
|
*/
|
||||||
static fromSdkFido2Credential(obj: SdkFido2Credential): Fido2Credential | undefined {
|
static fromSdkFido2Credential(obj?: SdkFido2Credential): Fido2Credential | undefined {
|
||||||
if (!obj) {
|
if (obj == null) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,11 +175,11 @@ export class Fido2Credential extends Domain {
|
|||||||
credential.keyCurve = EncString.fromJSON(obj.keyCurve);
|
credential.keyCurve = EncString.fromJSON(obj.keyCurve);
|
||||||
credential.keyValue = EncString.fromJSON(obj.keyValue);
|
credential.keyValue = EncString.fromJSON(obj.keyValue);
|
||||||
credential.rpId = EncString.fromJSON(obj.rpId);
|
credential.rpId = EncString.fromJSON(obj.rpId);
|
||||||
credential.userHandle = EncString.fromJSON(obj.userHandle);
|
|
||||||
credential.userName = EncString.fromJSON(obj.userName);
|
|
||||||
credential.counter = EncString.fromJSON(obj.counter);
|
credential.counter = EncString.fromJSON(obj.counter);
|
||||||
credential.rpName = EncString.fromJSON(obj.rpName);
|
credential.userHandle = encStringFrom(obj.userHandle);
|
||||||
credential.userDisplayName = EncString.fromJSON(obj.userDisplayName);
|
credential.userName = encStringFrom(obj.userName);
|
||||||
|
credential.rpName = encStringFrom(obj.rpName);
|
||||||
|
credential.userDisplayName = encStringFrom(obj.userDisplayName);
|
||||||
credential.discoverable = EncString.fromJSON(obj.discoverable);
|
credential.discoverable = EncString.fromJSON(obj.discoverable);
|
||||||
credential.creationDate = new Date(obj.creationDate);
|
credential.creationDate = new Date(obj.creationDate);
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ describe("Field", () => {
|
|||||||
|
|
||||||
expect(field).toEqual({
|
expect(field).toEqual({
|
||||||
type: undefined,
|
type: undefined,
|
||||||
name: null,
|
name: undefined,
|
||||||
value: null,
|
value: undefined,
|
||||||
linkedId: undefined,
|
linkedId: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -41,9 +41,9 @@ describe("Field", () => {
|
|||||||
|
|
||||||
expect(field).toEqual({
|
expect(field).toEqual({
|
||||||
type: FieldType.Text,
|
type: FieldType.Text,
|
||||||
name: { encryptedString: "encName", encryptionType: 0 },
|
name: new EncString("encName"),
|
||||||
value: { encryptedString: "encValue", encryptionType: 0 },
|
value: new EncString("encValue"),
|
||||||
linkedId: null,
|
linkedId: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -82,12 +82,14 @@ describe("Field", () => {
|
|||||||
expect(actual).toEqual({
|
expect(actual).toEqual({
|
||||||
name: "myName_fromJSON",
|
name: "myName_fromJSON",
|
||||||
value: "myValue_fromJSON",
|
value: "myValue_fromJSON",
|
||||||
|
type: FieldType.Text,
|
||||||
|
linkedId: undefined,
|
||||||
});
|
});
|
||||||
expect(actual).toBeInstanceOf(Field);
|
expect(actual).toBeInstanceOf(Field);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns null if object is null", () => {
|
it("returns undefined if object is null", () => {
|
||||||
expect(Field.fromJSON(null)).toBeNull();
|
expect(Field.fromJSON(null)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { Field as SdkField, LinkedIdType as SdkLinkedIdType } from "@bitwarden/sdk-internal";
|
import { Field as SdkField, LinkedIdType as SdkLinkedIdType } from "@bitwarden/sdk-internal";
|
||||||
@@ -8,14 +6,15 @@ import { EncString } from "../../../key-management/crypto/models/enc-string";
|
|||||||
import Domain from "../../../platform/models/domain/domain-base";
|
import Domain from "../../../platform/models/domain/domain-base";
|
||||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||||
import { FieldType, LinkedIdType } from "../../enums";
|
import { FieldType, LinkedIdType } from "../../enums";
|
||||||
|
import { conditionalEncString, encStringFrom } from "../../utils/domain-utils";
|
||||||
import { FieldData } from "../data/field.data";
|
import { FieldData } from "../data/field.data";
|
||||||
import { FieldView } from "../view/field.view";
|
import { FieldView } from "../view/field.view";
|
||||||
|
|
||||||
export class Field extends Domain {
|
export class Field extends Domain {
|
||||||
name: EncString;
|
name?: EncString;
|
||||||
value: EncString;
|
value?: EncString;
|
||||||
type: FieldType;
|
type: FieldType = FieldType.Text;
|
||||||
linkedId: LinkedIdType;
|
linkedId?: LinkedIdType;
|
||||||
|
|
||||||
constructor(obj?: FieldData) {
|
constructor(obj?: FieldData) {
|
||||||
super();
|
super();
|
||||||
@@ -24,25 +23,17 @@ export class Field extends Domain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.type = obj.type;
|
this.type = obj.type;
|
||||||
this.linkedId = obj.linkedId;
|
this.linkedId = obj.linkedId ?? undefined;
|
||||||
this.buildDomainModel(
|
this.name = conditionalEncString(obj.name);
|
||||||
this,
|
this.value = conditionalEncString(obj.value);
|
||||||
obj,
|
|
||||||
{
|
|
||||||
name: null,
|
|
||||||
value: null,
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<FieldView> {
|
decrypt(orgId: string | undefined, encKey?: SymmetricCryptoKey): Promise<FieldView> {
|
||||||
return this.decryptObj<Field, FieldView>(
|
return this.decryptObj<Field, FieldView>(
|
||||||
this,
|
this,
|
||||||
// @ts-expect-error ViewEncryptableKeys type should be fixed to allow for optional values, but is out of scope for now.
|
|
||||||
new FieldView(this),
|
new FieldView(this),
|
||||||
["name", "value"],
|
["name", "value"],
|
||||||
orgId,
|
orgId ?? null,
|
||||||
encKey,
|
encKey,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -63,18 +54,18 @@ export class Field extends Domain {
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON(obj: Partial<Jsonify<Field>>): Field {
|
static fromJSON(obj: Partial<Jsonify<Field>> | undefined): Field | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = EncString.fromJSON(obj.name);
|
const field = new Field();
|
||||||
const value = EncString.fromJSON(obj.value);
|
field.type = obj.type ?? FieldType.Text;
|
||||||
|
field.linkedId = obj.linkedId ?? undefined;
|
||||||
|
field.name = encStringFrom(obj.name);
|
||||||
|
field.value = encStringFrom(obj.value);
|
||||||
|
|
||||||
return Object.assign(new Field(), obj, {
|
return field;
|
||||||
name,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,14 +87,14 @@ export class Field extends Domain {
|
|||||||
* Maps SDK Field to Field
|
* Maps SDK Field to Field
|
||||||
* @param obj The SDK Field object to map
|
* @param obj The SDK Field object to map
|
||||||
*/
|
*/
|
||||||
static fromSdkField(obj: SdkField): Field | undefined {
|
static fromSdkField(obj?: SdkField): Field | undefined {
|
||||||
if (!obj) {
|
if (obj == null) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const field = new Field();
|
const field = new Field();
|
||||||
field.name = EncString.fromJSON(obj.name);
|
field.name = encStringFrom(obj.name);
|
||||||
field.value = EncString.fromJSON(obj.value);
|
field.value = encStringFrom(obj.value);
|
||||||
field.type = obj.type;
|
field.type = obj.type;
|
||||||
field.linkedId = obj.linkedId;
|
field.linkedId = obj.linkedId;
|
||||||
|
|
||||||
|
|||||||
@@ -34,24 +34,24 @@ describe("Identity", () => {
|
|||||||
const identity = new Identity(data);
|
const identity = new Identity(data);
|
||||||
|
|
||||||
expect(identity).toEqual({
|
expect(identity).toEqual({
|
||||||
address1: null,
|
address1: undefined,
|
||||||
address2: null,
|
address2: undefined,
|
||||||
address3: null,
|
address3: undefined,
|
||||||
city: null,
|
city: undefined,
|
||||||
company: null,
|
company: undefined,
|
||||||
country: null,
|
country: undefined,
|
||||||
email: null,
|
email: undefined,
|
||||||
firstName: null,
|
firstName: undefined,
|
||||||
lastName: null,
|
lastName: undefined,
|
||||||
licenseNumber: null,
|
licenseNumber: undefined,
|
||||||
middleName: null,
|
middleName: undefined,
|
||||||
passportNumber: null,
|
passportNumber: undefined,
|
||||||
phone: null,
|
phone: undefined,
|
||||||
postalCode: null,
|
postalCode: undefined,
|
||||||
ssn: null,
|
ssn: undefined,
|
||||||
state: null,
|
state: undefined,
|
||||||
title: null,
|
title: undefined,
|
||||||
username: null,
|
username: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -179,8 +179,8 @@ describe("Identity", () => {
|
|||||||
expect(actual).toBeInstanceOf(Identity);
|
expect(actual).toBeInstanceOf(Identity);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns null if object is null", () => {
|
it("returns undefined if object is null", () => {
|
||||||
expect(Identity.fromJSON(null)).toBeNull();
|
expect(Identity.fromJSON(null)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { Identity as SdkIdentity } from "@bitwarden/sdk-internal";
|
import { Identity as SdkIdentity } from "@bitwarden/sdk-internal";
|
||||||
@@ -7,28 +5,29 @@ import { Identity as SdkIdentity } from "@bitwarden/sdk-internal";
|
|||||||
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
||||||
import Domain from "../../../platform/models/domain/domain-base";
|
import Domain from "../../../platform/models/domain/domain-base";
|
||||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||||
|
import { conditionalEncString, encStringFrom } from "../../utils/domain-utils";
|
||||||
import { IdentityData } from "../data/identity.data";
|
import { IdentityData } from "../data/identity.data";
|
||||||
import { IdentityView } from "../view/identity.view";
|
import { IdentityView } from "../view/identity.view";
|
||||||
|
|
||||||
export class Identity extends Domain {
|
export class Identity extends Domain {
|
||||||
title: EncString;
|
title?: EncString;
|
||||||
firstName: EncString;
|
firstName?: EncString;
|
||||||
middleName: EncString;
|
middleName?: EncString;
|
||||||
lastName: EncString;
|
lastName?: EncString;
|
||||||
address1: EncString;
|
address1?: EncString;
|
||||||
address2: EncString;
|
address2?: EncString;
|
||||||
address3: EncString;
|
address3?: EncString;
|
||||||
city: EncString;
|
city?: EncString;
|
||||||
state: EncString;
|
state?: EncString;
|
||||||
postalCode: EncString;
|
postalCode?: EncString;
|
||||||
country: EncString;
|
country?: EncString;
|
||||||
company: EncString;
|
company?: EncString;
|
||||||
email: EncString;
|
email?: EncString;
|
||||||
phone: EncString;
|
phone?: EncString;
|
||||||
ssn: EncString;
|
ssn?: EncString;
|
||||||
username: EncString;
|
username?: EncString;
|
||||||
passportNumber: EncString;
|
passportNumber?: EncString;
|
||||||
licenseNumber: EncString;
|
licenseNumber?: EncString;
|
||||||
|
|
||||||
constructor(obj?: IdentityData) {
|
constructor(obj?: IdentityData) {
|
||||||
super();
|
super();
|
||||||
@@ -36,35 +35,28 @@ export class Identity extends Domain {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.buildDomainModel(
|
this.title = conditionalEncString(obj.title);
|
||||||
this,
|
this.firstName = conditionalEncString(obj.firstName);
|
||||||
obj,
|
this.middleName = conditionalEncString(obj.middleName);
|
||||||
{
|
this.lastName = conditionalEncString(obj.lastName);
|
||||||
title: null,
|
this.address1 = conditionalEncString(obj.address1);
|
||||||
firstName: null,
|
this.address2 = conditionalEncString(obj.address2);
|
||||||
middleName: null,
|
this.address3 = conditionalEncString(obj.address3);
|
||||||
lastName: null,
|
this.city = conditionalEncString(obj.city);
|
||||||
address1: null,
|
this.state = conditionalEncString(obj.state);
|
||||||
address2: null,
|
this.postalCode = conditionalEncString(obj.postalCode);
|
||||||
address3: null,
|
this.country = conditionalEncString(obj.country);
|
||||||
city: null,
|
this.company = conditionalEncString(obj.company);
|
||||||
state: null,
|
this.email = conditionalEncString(obj.email);
|
||||||
postalCode: null,
|
this.phone = conditionalEncString(obj.phone);
|
||||||
country: null,
|
this.ssn = conditionalEncString(obj.ssn);
|
||||||
company: null,
|
this.username = conditionalEncString(obj.username);
|
||||||
email: null,
|
this.passportNumber = conditionalEncString(obj.passportNumber);
|
||||||
phone: null,
|
this.licenseNumber = conditionalEncString(obj.licenseNumber);
|
||||||
ssn: null,
|
|
||||||
username: null,
|
|
||||||
passportNumber: null,
|
|
||||||
licenseNumber: null,
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypt(
|
decrypt(
|
||||||
orgId: string,
|
orgId: string | undefined,
|
||||||
context: string = "No Cipher Context",
|
context: string = "No Cipher Context",
|
||||||
encKey?: SymmetricCryptoKey,
|
encKey?: SymmetricCryptoKey,
|
||||||
): Promise<IdentityView> {
|
): Promise<IdentityView> {
|
||||||
@@ -91,7 +83,7 @@ export class Identity extends Domain {
|
|||||||
"passportNumber",
|
"passportNumber",
|
||||||
"licenseNumber",
|
"licenseNumber",
|
||||||
],
|
],
|
||||||
orgId,
|
orgId ?? null,
|
||||||
encKey,
|
encKey,
|
||||||
"DomainType: Identity; " + context,
|
"DomainType: Identity; " + context,
|
||||||
);
|
);
|
||||||
@@ -122,50 +114,32 @@ export class Identity extends Domain {
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON(obj: Jsonify<Identity>): Identity {
|
static fromJSON(obj: Jsonify<Identity> | undefined): Identity | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = EncString.fromJSON(obj.title);
|
const identity = new Identity();
|
||||||
const firstName = EncString.fromJSON(obj.firstName);
|
identity.title = encStringFrom(obj.title);
|
||||||
const middleName = EncString.fromJSON(obj.middleName);
|
identity.firstName = encStringFrom(obj.firstName);
|
||||||
const lastName = EncString.fromJSON(obj.lastName);
|
identity.middleName = encStringFrom(obj.middleName);
|
||||||
const address1 = EncString.fromJSON(obj.address1);
|
identity.lastName = encStringFrom(obj.lastName);
|
||||||
const address2 = EncString.fromJSON(obj.address2);
|
identity.address1 = encStringFrom(obj.address1);
|
||||||
const address3 = EncString.fromJSON(obj.address3);
|
identity.address2 = encStringFrom(obj.address2);
|
||||||
const city = EncString.fromJSON(obj.city);
|
identity.address3 = encStringFrom(obj.address3);
|
||||||
const state = EncString.fromJSON(obj.state);
|
identity.city = encStringFrom(obj.city);
|
||||||
const postalCode = EncString.fromJSON(obj.postalCode);
|
identity.state = encStringFrom(obj.state);
|
||||||
const country = EncString.fromJSON(obj.country);
|
identity.postalCode = encStringFrom(obj.postalCode);
|
||||||
const company = EncString.fromJSON(obj.company);
|
identity.country = encStringFrom(obj.country);
|
||||||
const email = EncString.fromJSON(obj.email);
|
identity.company = encStringFrom(obj.company);
|
||||||
const phone = EncString.fromJSON(obj.phone);
|
identity.email = encStringFrom(obj.email);
|
||||||
const ssn = EncString.fromJSON(obj.ssn);
|
identity.phone = encStringFrom(obj.phone);
|
||||||
const username = EncString.fromJSON(obj.username);
|
identity.ssn = encStringFrom(obj.ssn);
|
||||||
const passportNumber = EncString.fromJSON(obj.passportNumber);
|
identity.username = encStringFrom(obj.username);
|
||||||
const licenseNumber = EncString.fromJSON(obj.licenseNumber);
|
identity.passportNumber = encStringFrom(obj.passportNumber);
|
||||||
|
identity.licenseNumber = encStringFrom(obj.licenseNumber);
|
||||||
|
|
||||||
return Object.assign(new Identity(), obj, {
|
return identity;
|
||||||
title,
|
|
||||||
firstName,
|
|
||||||
middleName,
|
|
||||||
lastName,
|
|
||||||
address1,
|
|
||||||
address2,
|
|
||||||
address3,
|
|
||||||
city,
|
|
||||||
state,
|
|
||||||
postalCode,
|
|
||||||
country,
|
|
||||||
company,
|
|
||||||
email,
|
|
||||||
phone,
|
|
||||||
ssn,
|
|
||||||
username,
|
|
||||||
passportNumber,
|
|
||||||
licenseNumber,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -200,30 +174,30 @@ export class Identity extends Domain {
|
|||||||
* Maps an SDK Identity object to an Identity
|
* Maps an SDK Identity object to an Identity
|
||||||
* @param obj - The SDK Identity object
|
* @param obj - The SDK Identity object
|
||||||
*/
|
*/
|
||||||
static fromSdkIdentity(obj: SdkIdentity): Identity | undefined {
|
static fromSdkIdentity(obj?: SdkIdentity): Identity | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const identity = new Identity();
|
const identity = new Identity();
|
||||||
identity.title = EncString.fromJSON(obj.title);
|
identity.title = encStringFrom(obj.title);
|
||||||
identity.firstName = EncString.fromJSON(obj.firstName);
|
identity.firstName = encStringFrom(obj.firstName);
|
||||||
identity.middleName = EncString.fromJSON(obj.middleName);
|
identity.middleName = encStringFrom(obj.middleName);
|
||||||
identity.lastName = EncString.fromJSON(obj.lastName);
|
identity.lastName = encStringFrom(obj.lastName);
|
||||||
identity.address1 = EncString.fromJSON(obj.address1);
|
identity.address1 = encStringFrom(obj.address1);
|
||||||
identity.address2 = EncString.fromJSON(obj.address2);
|
identity.address2 = encStringFrom(obj.address2);
|
||||||
identity.address3 = EncString.fromJSON(obj.address3);
|
identity.address3 = encStringFrom(obj.address3);
|
||||||
identity.city = EncString.fromJSON(obj.city);
|
identity.city = encStringFrom(obj.city);
|
||||||
identity.state = EncString.fromJSON(obj.state);
|
identity.state = encStringFrom(obj.state);
|
||||||
identity.postalCode = EncString.fromJSON(obj.postalCode);
|
identity.postalCode = encStringFrom(obj.postalCode);
|
||||||
identity.country = EncString.fromJSON(obj.country);
|
identity.country = encStringFrom(obj.country);
|
||||||
identity.company = EncString.fromJSON(obj.company);
|
identity.company = encStringFrom(obj.company);
|
||||||
identity.email = EncString.fromJSON(obj.email);
|
identity.email = encStringFrom(obj.email);
|
||||||
identity.phone = EncString.fromJSON(obj.phone);
|
identity.phone = encStringFrom(obj.phone);
|
||||||
identity.ssn = EncString.fromJSON(obj.ssn);
|
identity.ssn = encStringFrom(obj.ssn);
|
||||||
identity.username = EncString.fromJSON(obj.username);
|
identity.username = encStringFrom(obj.username);
|
||||||
identity.passportNumber = EncString.fromJSON(obj.passportNumber);
|
identity.passportNumber = encStringFrom(obj.passportNumber);
|
||||||
identity.licenseNumber = EncString.fromJSON(obj.licenseNumber);
|
identity.licenseNumber = encStringFrom(obj.licenseNumber);
|
||||||
|
|
||||||
return identity;
|
return identity;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ describe("LoginUri", () => {
|
|||||||
const loginUri = new LoginUri(data);
|
const loginUri = new LoginUri(data);
|
||||||
|
|
||||||
expect(loginUri).toEqual({
|
expect(loginUri).toEqual({
|
||||||
match: null,
|
match: undefined,
|
||||||
uri: null,
|
uri: undefined,
|
||||||
uriChecksum: null,
|
uriChecksum: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ describe("LoginUri", () => {
|
|||||||
loginUri.uriChecksum = mockEnc("checksum");
|
loginUri.uriChecksum = mockEnc("checksum");
|
||||||
encryptService.hash.mockResolvedValue("checksum");
|
encryptService.hash.mockResolvedValue("checksum");
|
||||||
|
|
||||||
const actual = await loginUri.validateChecksum("uri", null, null);
|
const actual = await loginUri.validateChecksum("uri", undefined, undefined);
|
||||||
|
|
||||||
expect(actual).toBe(true);
|
expect(actual).toBe(true);
|
||||||
expect(encryptService.hash).toHaveBeenCalledWith("uri", "sha256");
|
expect(encryptService.hash).toHaveBeenCalledWith("uri", "sha256");
|
||||||
@@ -88,7 +88,7 @@ describe("LoginUri", () => {
|
|||||||
loginUri.uriChecksum = mockEnc("checksum");
|
loginUri.uriChecksum = mockEnc("checksum");
|
||||||
encryptService.hash.mockResolvedValue("incorrect checksum");
|
encryptService.hash.mockResolvedValue("incorrect checksum");
|
||||||
|
|
||||||
const actual = await loginUri.validateChecksum("uri", null, null);
|
const actual = await loginUri.validateChecksum("uri", undefined, undefined);
|
||||||
|
|
||||||
expect(actual).toBe(false);
|
expect(actual).toBe(false);
|
||||||
});
|
});
|
||||||
@@ -112,8 +112,8 @@ describe("LoginUri", () => {
|
|||||||
expect(actual).toBeInstanceOf(LoginUri);
|
expect(actual).toBeInstanceOf(LoginUri);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns null if object is null", () => {
|
it("returns undefined if object is null", () => {
|
||||||
expect(LoginUri.fromJSON(null)).toBeNull();
|
expect(LoginUri.fromJSON(null)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { LoginUri as SdkLoginUri } from "@bitwarden/sdk-internal";
|
import { LoginUri as SdkLoginUri } from "@bitwarden/sdk-internal";
|
||||||
@@ -9,13 +7,14 @@ import { UriMatchStrategySetting } from "../../../models/domain/domain-service";
|
|||||||
import { Utils } from "../../../platform/misc/utils";
|
import { Utils } from "../../../platform/misc/utils";
|
||||||
import Domain from "../../../platform/models/domain/domain-base";
|
import Domain from "../../../platform/models/domain/domain-base";
|
||||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||||
|
import { conditionalEncString, encStringFrom } from "../../utils/domain-utils";
|
||||||
import { LoginUriData } from "../data/login-uri.data";
|
import { LoginUriData } from "../data/login-uri.data";
|
||||||
import { LoginUriView } from "../view/login-uri.view";
|
import { LoginUriView } from "../view/login-uri.view";
|
||||||
|
|
||||||
export class LoginUri extends Domain {
|
export class LoginUri extends Domain {
|
||||||
uri: EncString;
|
uri?: EncString;
|
||||||
uriChecksum: EncString | undefined;
|
uriChecksum?: EncString;
|
||||||
match: UriMatchStrategySetting;
|
match?: UriMatchStrategySetting;
|
||||||
|
|
||||||
constructor(obj?: LoginUriData) {
|
constructor(obj?: LoginUriData) {
|
||||||
super();
|
super();
|
||||||
@@ -23,20 +22,13 @@ export class LoginUri extends Domain {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.match = obj.match;
|
this.uri = conditionalEncString(obj.uri);
|
||||||
this.buildDomainModel(
|
this.uriChecksum = conditionalEncString(obj.uriChecksum);
|
||||||
this,
|
this.match = obj.match ?? undefined;
|
||||||
obj,
|
|
||||||
{
|
|
||||||
uri: null,
|
|
||||||
uriChecksum: null,
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypt(
|
decrypt(
|
||||||
orgId: string,
|
orgId: string | undefined,
|
||||||
context: string = "No Cipher Context",
|
context: string = "No Cipher Context",
|
||||||
encKey?: SymmetricCryptoKey,
|
encKey?: SymmetricCryptoKey,
|
||||||
): Promise<LoginUriView> {
|
): Promise<LoginUriView> {
|
||||||
@@ -44,13 +36,13 @@ export class LoginUri extends Domain {
|
|||||||
this,
|
this,
|
||||||
new LoginUriView(this),
|
new LoginUriView(this),
|
||||||
["uri"],
|
["uri"],
|
||||||
orgId,
|
orgId ?? null,
|
||||||
encKey,
|
encKey,
|
||||||
context,
|
context,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async validateChecksum(clearTextUri: string, orgId: string, encKey: SymmetricCryptoKey) {
|
async validateChecksum(clearTextUri: string, orgId?: string, encKey?: SymmetricCryptoKey) {
|
||||||
if (this.uriChecksum == null) {
|
if (this.uriChecksum == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -58,7 +50,7 @@ export class LoginUri extends Domain {
|
|||||||
const keyService = Utils.getContainerService().getEncryptService();
|
const keyService = Utils.getContainerService().getEncryptService();
|
||||||
const localChecksum = await keyService.hash(clearTextUri, "sha256");
|
const localChecksum = await keyService.hash(clearTextUri, "sha256");
|
||||||
|
|
||||||
const remoteChecksum = await this.uriChecksum.decrypt(orgId, encKey);
|
const remoteChecksum = await this.uriChecksum.decrypt(orgId ?? null, encKey);
|
||||||
return remoteChecksum === localChecksum;
|
return remoteChecksum === localChecksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,17 +69,17 @@ export class LoginUri extends Domain {
|
|||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON(obj: Jsonify<LoginUri>): LoginUri {
|
static fromJSON(obj: Jsonify<LoginUri> | undefined): LoginUri | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uri = EncString.fromJSON(obj.uri);
|
const loginUri = new LoginUri();
|
||||||
const uriChecksum = EncString.fromJSON(obj.uriChecksum);
|
loginUri.uri = encStringFrom(obj.uri);
|
||||||
return Object.assign(new LoginUri(), obj, {
|
loginUri.match = obj.match ?? undefined;
|
||||||
uri,
|
loginUri.uriChecksum = encStringFrom(obj.uriChecksum);
|
||||||
uriChecksum,
|
|
||||||
});
|
return loginUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,16 +95,16 @@ export class LoginUri extends Domain {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromSdkLoginUri(obj: SdkLoginUri): LoginUri | undefined {
|
static fromSdkLoginUri(obj?: SdkLoginUri): LoginUri | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const view = new LoginUri();
|
const loginUri = new LoginUri();
|
||||||
view.uri = EncString.fromJSON(obj.uri);
|
loginUri.uri = encStringFrom(obj.uri);
|
||||||
view.uriChecksum = obj.uriChecksum ? EncString.fromJSON(obj.uriChecksum) : undefined;
|
loginUri.uriChecksum = encStringFrom(obj.uriChecksum);
|
||||||
view.match = obj.match;
|
loginUri.match = obj.match;
|
||||||
|
|
||||||
return view;
|
return loginUri;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ describe("Login DTO", () => {
|
|||||||
const login = new Login(data);
|
const login = new Login(data);
|
||||||
|
|
||||||
expect(login).toEqual({
|
expect(login).toEqual({
|
||||||
passwordRevisionDate: null,
|
passwordRevisionDate: undefined,
|
||||||
autofillOnPageLoad: undefined,
|
autofillOnPageLoad: undefined,
|
||||||
username: null,
|
username: undefined,
|
||||||
password: null,
|
password: undefined,
|
||||||
totp: null,
|
totp: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -193,8 +193,8 @@ describe("Login DTO", () => {
|
|||||||
expect(actual).toBeInstanceOf(Login);
|
expect(actual).toBeInstanceOf(Login);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns null if object is null", () => {
|
it("returns undefined if object is null", () => {
|
||||||
expect(Login.fromJSON(null)).toBeNull();
|
expect(Login.fromJSON(null)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { Login as SdkLogin } from "@bitwarden/sdk-internal";
|
import { Login as SdkLogin } from "@bitwarden/sdk-internal";
|
||||||
@@ -7,6 +5,7 @@ import { Login as SdkLogin } from "@bitwarden/sdk-internal";
|
|||||||
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
||||||
import Domain from "../../../platform/models/domain/domain-base";
|
import Domain from "../../../platform/models/domain/domain-base";
|
||||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||||
|
import { conditionalEncString, encStringFrom } from "../../utils/domain-utils";
|
||||||
import { LoginData } from "../data/login.data";
|
import { LoginData } from "../data/login.data";
|
||||||
import { LoginView } from "../view/login.view";
|
import { LoginView } from "../view/login.view";
|
||||||
|
|
||||||
@@ -14,13 +13,13 @@ import { Fido2Credential } from "./fido2-credential";
|
|||||||
import { LoginUri } from "./login-uri";
|
import { LoginUri } from "./login-uri";
|
||||||
|
|
||||||
export class Login extends Domain {
|
export class Login extends Domain {
|
||||||
uris: LoginUri[];
|
uris?: LoginUri[];
|
||||||
username: EncString;
|
username?: EncString;
|
||||||
password: EncString;
|
password?: EncString;
|
||||||
passwordRevisionDate?: Date;
|
passwordRevisionDate?: Date;
|
||||||
totp: EncString;
|
totp?: EncString;
|
||||||
autofillOnPageLoad: boolean;
|
autofillOnPageLoad?: boolean;
|
||||||
fido2Credentials: Fido2Credential[];
|
fido2Credentials?: Fido2Credential[];
|
||||||
|
|
||||||
constructor(obj?: LoginData) {
|
constructor(obj?: LoginData) {
|
||||||
super();
|
super();
|
||||||
@@ -29,24 +28,14 @@ export class Login extends Domain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.passwordRevisionDate =
|
this.passwordRevisionDate =
|
||||||
obj.passwordRevisionDate != null ? new Date(obj.passwordRevisionDate) : null;
|
obj.passwordRevisionDate != null ? new Date(obj.passwordRevisionDate) : undefined;
|
||||||
this.autofillOnPageLoad = obj.autofillOnPageLoad;
|
this.autofillOnPageLoad = obj.autofillOnPageLoad;
|
||||||
this.buildDomainModel(
|
this.username = conditionalEncString(obj.username);
|
||||||
this,
|
this.password = conditionalEncString(obj.password);
|
||||||
obj,
|
this.totp = conditionalEncString(obj.totp);
|
||||||
{
|
|
||||||
username: null,
|
|
||||||
password: null,
|
|
||||||
totp: null,
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (obj.uris) {
|
if (obj.uris) {
|
||||||
this.uris = [];
|
this.uris = obj.uris.map((u) => new LoginUri(u));
|
||||||
obj.uris.forEach((u) => {
|
|
||||||
this.uris.push(new LoginUri(u));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.fido2Credentials) {
|
if (obj.fido2Credentials) {
|
||||||
@@ -55,7 +44,7 @@ export class Login extends Domain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async decrypt(
|
async decrypt(
|
||||||
orgId: string,
|
orgId: string | undefined,
|
||||||
bypassValidation: boolean,
|
bypassValidation: boolean,
|
||||||
context: string = "No Cipher Context",
|
context: string = "No Cipher Context",
|
||||||
encKey?: SymmetricCryptoKey,
|
encKey?: SymmetricCryptoKey,
|
||||||
@@ -64,7 +53,7 @@ export class Login extends Domain {
|
|||||||
this,
|
this,
|
||||||
new LoginView(this),
|
new LoginView(this),
|
||||||
["username", "password", "totp"],
|
["username", "password", "totp"],
|
||||||
orgId,
|
orgId ?? null,
|
||||||
encKey,
|
encKey,
|
||||||
`DomainType: Login; ${context}`,
|
`DomainType: Login; ${context}`,
|
||||||
);
|
);
|
||||||
@@ -78,12 +67,21 @@ export class Login extends Domain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const uri = await this.uris[i].decrypt(orgId, context, encKey);
|
const uri = await this.uris[i].decrypt(orgId, context, encKey);
|
||||||
|
const uriString = uri.uri;
|
||||||
|
|
||||||
|
if (uriString == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// URIs are shared remotely after decryption
|
// URIs are shared remotely after decryption
|
||||||
// we need to validate that the string hasn't been changed by a compromised server
|
// we need to validate that the string hasn't been changed by a compromised server
|
||||||
// This validation is tied to the existence of cypher.key for backwards compatibility
|
// This validation is tied to the existence of cypher.key for backwards compatibility
|
||||||
// So we bypass the validation if there's no cipher.key or procceed with the validation and
|
// So we bypass the validation if there's no cipher.key or proceed with the validation and
|
||||||
// Skip the value if it's been tampered with.
|
// Skip the value if it's been tampered with.
|
||||||
if (bypassValidation || (await this.uris[i].validateChecksum(uri.uri, orgId, encKey))) {
|
const isValidUri =
|
||||||
|
bypassValidation || (await this.uris[i].validateChecksum(uriString, orgId, encKey));
|
||||||
|
|
||||||
|
if (isValidUri) {
|
||||||
view.uris.push(uri);
|
view.uris.push(uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,9 +98,12 @@ export class Login extends Domain {
|
|||||||
|
|
||||||
toLoginData(): LoginData {
|
toLoginData(): LoginData {
|
||||||
const l = new LoginData();
|
const l = new LoginData();
|
||||||
l.passwordRevisionDate =
|
if (this.passwordRevisionDate != null) {
|
||||||
this.passwordRevisionDate != null ? this.passwordRevisionDate.toISOString() : null;
|
l.passwordRevisionDate = this.passwordRevisionDate.toISOString();
|
||||||
l.autofillOnPageLoad = this.autofillOnPageLoad;
|
}
|
||||||
|
if (this.autofillOnPageLoad != null) {
|
||||||
|
l.autofillOnPageLoad = this.autofillOnPageLoad;
|
||||||
|
}
|
||||||
this.buildDataModel(this, l, {
|
this.buildDataModel(this, l, {
|
||||||
username: null,
|
username: null,
|
||||||
password: null,
|
password: null,
|
||||||
@@ -123,28 +124,27 @@ export class Login extends Domain {
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON(obj: Partial<Jsonify<Login>>): Login {
|
static fromJSON(obj: Partial<Jsonify<Login>> | undefined): Login | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const username = EncString.fromJSON(obj.username);
|
const login = new Login();
|
||||||
const password = EncString.fromJSON(obj.password);
|
login.passwordRevisionDate =
|
||||||
const totp = EncString.fromJSON(obj.totp);
|
obj.passwordRevisionDate != null ? new Date(obj.passwordRevisionDate) : undefined;
|
||||||
const passwordRevisionDate =
|
login.autofillOnPageLoad = obj.autofillOnPageLoad;
|
||||||
obj.passwordRevisionDate == null ? null : new Date(obj.passwordRevisionDate);
|
login.username = encStringFrom(obj.username);
|
||||||
const uris = obj.uris?.map((uri: any) => LoginUri.fromJSON(uri));
|
login.password = encStringFrom(obj.password);
|
||||||
const fido2Credentials =
|
login.totp = encStringFrom(obj.totp);
|
||||||
obj.fido2Credentials?.map((key) => Fido2Credential.fromJSON(key)) ?? [];
|
login.uris = obj.uris
|
||||||
|
?.map((uri: any) => LoginUri.fromJSON(uri))
|
||||||
|
.filter((u): u is LoginUri => u != null);
|
||||||
|
login.fido2Credentials =
|
||||||
|
obj.fido2Credentials
|
||||||
|
?.map((key) => Fido2Credential.fromJSON(key))
|
||||||
|
.filter((c): c is Fido2Credential => c != null) ?? undefined;
|
||||||
|
|
||||||
return Object.assign(new Login(), obj, {
|
return login;
|
||||||
username,
|
|
||||||
password,
|
|
||||||
totp,
|
|
||||||
passwordRevisionDate,
|
|
||||||
uris,
|
|
||||||
fido2Credentials,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,25 +168,27 @@ export class Login extends Domain {
|
|||||||
* Maps an SDK Login object to a Login
|
* Maps an SDK Login object to a Login
|
||||||
* @param obj - The SDK Login object
|
* @param obj - The SDK Login object
|
||||||
*/
|
*/
|
||||||
static fromSdkLogin(obj: SdkLogin): Login | undefined {
|
static fromSdkLogin(obj?: SdkLogin): Login | undefined {
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const login = new Login();
|
const login = new Login();
|
||||||
|
login.passwordRevisionDate =
|
||||||
login.uris =
|
obj.passwordRevisionDate != null ? new Date(obj.passwordRevisionDate) : undefined;
|
||||||
obj.uris?.filter((u) => u.uri != null).map((uri) => LoginUri.fromSdkLoginUri(uri)) ?? [];
|
|
||||||
login.username = EncString.fromJSON(obj.username);
|
|
||||||
login.password = EncString.fromJSON(obj.password);
|
|
||||||
login.passwordRevisionDate = obj.passwordRevisionDate
|
|
||||||
? new Date(obj.passwordRevisionDate)
|
|
||||||
: undefined;
|
|
||||||
login.totp = EncString.fromJSON(obj.totp);
|
|
||||||
login.autofillOnPageLoad = obj.autofillOnPageLoad;
|
login.autofillOnPageLoad = obj.autofillOnPageLoad;
|
||||||
login.fido2Credentials = obj.fido2Credentials?.map((f) =>
|
login.username = encStringFrom(obj.username);
|
||||||
Fido2Credential.fromSdkFido2Credential(f),
|
login.password = encStringFrom(obj.password);
|
||||||
);
|
login.totp = encStringFrom(obj.totp);
|
||||||
|
login.uris =
|
||||||
|
obj.uris
|
||||||
|
?.filter((u) => u.uri != null)
|
||||||
|
.map((uri) => LoginUri.fromSdkLoginUri(uri))
|
||||||
|
.filter((u): u is LoginUri => u != null) ?? undefined;
|
||||||
|
login.fido2Credentials =
|
||||||
|
obj.fido2Credentials
|
||||||
|
?.map((f) => Fido2Credential.fromSdkFido2Credential(f))
|
||||||
|
.filter((c): c is Fido2Credential => c != null) ?? undefined;
|
||||||
|
|
||||||
return login;
|
return login;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ describe("Password", () => {
|
|||||||
const data = new PasswordHistoryData();
|
const data = new PasswordHistoryData();
|
||||||
const password = new Password(data);
|
const password = new Password(data);
|
||||||
|
|
||||||
expect(password).toMatchObject({
|
expect(password).toBeInstanceOf(Password);
|
||||||
password: null,
|
expect(password.password).toBeInstanceOf(EncString);
|
||||||
});
|
expect(password.lastUsedDate).toBeInstanceOf(Date);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Convert", () => {
|
it("Convert", () => {
|
||||||
@@ -66,8 +66,8 @@ describe("Password", () => {
|
|||||||
expect(actual).toBeInstanceOf(Password);
|
expect(actual).toBeInstanceOf(Password);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns null if object is null", () => {
|
it("returns undefined if object is null", () => {
|
||||||
expect(Password.fromJSON(null)).toBeNull();
|
expect(Password.fromJSON(null)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { PasswordHistory } from "@bitwarden/sdk-internal";
|
import { PasswordHistory } from "@bitwarden/sdk-internal";
|
||||||
@@ -11,8 +9,8 @@ import { PasswordHistoryData } from "../data/password-history.data";
|
|||||||
import { PasswordHistoryView } from "../view/password-history.view";
|
import { PasswordHistoryView } from "../view/password-history.view";
|
||||||
|
|
||||||
export class Password extends Domain {
|
export class Password extends Domain {
|
||||||
password: EncString;
|
password!: EncString;
|
||||||
lastUsedDate: Date;
|
lastUsedDate!: Date;
|
||||||
|
|
||||||
constructor(obj?: PasswordHistoryData) {
|
constructor(obj?: PasswordHistoryData) {
|
||||||
super();
|
super();
|
||||||
@@ -20,18 +18,16 @@ export class Password extends Domain {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.buildDomainModel(this, obj, {
|
this.password = new EncString(obj.password);
|
||||||
password: null,
|
|
||||||
});
|
|
||||||
this.lastUsedDate = new Date(obj.lastUsedDate);
|
this.lastUsedDate = new Date(obj.lastUsedDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<PasswordHistoryView> {
|
decrypt(orgId: string | undefined, encKey?: SymmetricCryptoKey): Promise<PasswordHistoryView> {
|
||||||
return this.decryptObj<Password, PasswordHistoryView>(
|
return this.decryptObj<Password, PasswordHistoryView>(
|
||||||
this,
|
this,
|
||||||
new PasswordHistoryView(this),
|
new PasswordHistoryView(this),
|
||||||
["password"],
|
["password"],
|
||||||
orgId,
|
orgId ?? null,
|
||||||
encKey,
|
encKey,
|
||||||
"DomainType: PasswordHistory",
|
"DomainType: PasswordHistory",
|
||||||
);
|
);
|
||||||
@@ -46,18 +42,16 @@ export class Password extends Domain {
|
|||||||
return ph;
|
return ph;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON(obj: Partial<Jsonify<Password>>): Password {
|
static fromJSON(obj: Jsonify<Password> | undefined): Password | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const password = EncString.fromJSON(obj.password);
|
const passwordHistory = new Password();
|
||||||
const lastUsedDate = obj.lastUsedDate == null ? null : new Date(obj.lastUsedDate);
|
passwordHistory.password = EncString.fromJSON(obj.password);
|
||||||
|
passwordHistory.lastUsedDate = new Date(obj.lastUsedDate);
|
||||||
|
|
||||||
return Object.assign(new Password(), obj, {
|
return passwordHistory;
|
||||||
password,
|
|
||||||
lastUsedDate,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,7 +70,7 @@ export class Password extends Domain {
|
|||||||
* Maps an SDK PasswordHistory object to a Password
|
* Maps an SDK PasswordHistory object to a Password
|
||||||
* @param obj - The SDK PasswordHistory object
|
* @param obj - The SDK PasswordHistory object
|
||||||
*/
|
*/
|
||||||
static fromSdkPasswordHistory(obj: PasswordHistory): Password | undefined {
|
static fromSdkPasswordHistory(obj?: PasswordHistory): Password | undefined {
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ describe("SecureNote", () => {
|
|||||||
const secureNote = new SecureNote();
|
const secureNote = new SecureNote();
|
||||||
secureNote.type = SecureNoteType.Generic;
|
secureNote.type = SecureNoteType.Generic;
|
||||||
|
|
||||||
const view = await secureNote.decrypt(null);
|
const view = await secureNote.decrypt();
|
||||||
|
|
||||||
expect(view).toEqual({
|
expect(view).toEqual({
|
||||||
type: 0,
|
type: 0,
|
||||||
@@ -46,8 +46,8 @@ describe("SecureNote", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("fromJSON", () => {
|
describe("fromJSON", () => {
|
||||||
it("returns null if object is null", () => {
|
it("returns undefined if object is null", () => {
|
||||||
expect(SecureNote.fromJSON(null)).toBeNull();
|
expect(SecureNote.fromJSON(null)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { SecureNote as SdkSecureNote } from "@bitwarden/sdk-internal";
|
import { SecureNote as SdkSecureNote } from "@bitwarden/sdk-internal";
|
||||||
|
|
||||||
import Domain from "../../../platform/models/domain/domain-base";
|
import Domain from "../../../platform/models/domain/domain-base";
|
||||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
|
||||||
import { SecureNoteType } from "../../enums";
|
import { SecureNoteType } from "../../enums";
|
||||||
import { SecureNoteData } from "../data/secure-note.data";
|
import { SecureNoteData } from "../data/secure-note.data";
|
||||||
import { SecureNoteView } from "../view/secure-note.view";
|
import { SecureNoteView } from "../view/secure-note.view";
|
||||||
|
|
||||||
export class SecureNote extends Domain {
|
export class SecureNote extends Domain {
|
||||||
type: SecureNoteType;
|
type: SecureNoteType = SecureNoteType.Generic;
|
||||||
|
|
||||||
constructor(obj?: SecureNoteData) {
|
constructor(obj?: SecureNoteData) {
|
||||||
super();
|
super();
|
||||||
@@ -22,11 +19,7 @@ export class SecureNote extends Domain {
|
|||||||
this.type = obj.type;
|
this.type = obj.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
async decrypt(
|
async decrypt(): Promise<SecureNoteView> {
|
||||||
orgId: string,
|
|
||||||
context = "No Cipher Context",
|
|
||||||
encKey?: SymmetricCryptoKey,
|
|
||||||
): Promise<SecureNoteView> {
|
|
||||||
return new SecureNoteView(this);
|
return new SecureNoteView(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,12 +29,14 @@ export class SecureNote extends Domain {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON(obj: Jsonify<SecureNote>): SecureNote {
|
static fromJSON(obj: Jsonify<SecureNote> | undefined): SecureNote | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.assign(new SecureNote(), obj);
|
const secureNote = new SecureNote();
|
||||||
|
secureNote.type = obj.type;
|
||||||
|
return secureNote;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,7 +54,7 @@ export class SecureNote extends Domain {
|
|||||||
* Maps an SDK SecureNote object to a SecureNote
|
* Maps an SDK SecureNote object to a SecureNote
|
||||||
* @param obj - The SDK SecureNote object
|
* @param obj - The SDK SecureNote object
|
||||||
*/
|
*/
|
||||||
static fromSdkSecureNote(obj: SdkSecureNote): SecureNote | undefined {
|
static fromSdkSecureNote(obj?: SdkSecureNote): SecureNote | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
|
||||||
|
|
||||||
import { mockEnc } from "../../../../spec";
|
import { mockEnc } from "../../../../spec";
|
||||||
import { SshKeyApi } from "../api/ssh-key.api";
|
import { SshKeyApi } from "../api/ssh-key.api";
|
||||||
import { SshKeyData } from "../data/ssh-key.data";
|
import { SshKeyData } from "../data/ssh-key.data";
|
||||||
@@ -31,11 +33,10 @@ describe("Sshkey", () => {
|
|||||||
const data = new SshKeyData();
|
const data = new SshKeyData();
|
||||||
const sshKey = new SshKey(data);
|
const sshKey = new SshKey(data);
|
||||||
|
|
||||||
expect(sshKey).toEqual({
|
expect(sshKey).toBeInstanceOf(SshKey);
|
||||||
privateKey: null,
|
expect(sshKey.privateKey).toBeInstanceOf(EncString);
|
||||||
publicKey: null,
|
expect(sshKey.publicKey).toBeInstanceOf(EncString);
|
||||||
keyFingerprint: null,
|
expect(sshKey.keyFingerprint).toBeInstanceOf(EncString);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("toSshKeyData", () => {
|
it("toSshKeyData", () => {
|
||||||
@@ -60,8 +61,8 @@ describe("Sshkey", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("fromJSON", () => {
|
describe("fromJSON", () => {
|
||||||
it("returns null if object is null", () => {
|
it("returns undefined if object is null", () => {
|
||||||
expect(SshKey.fromJSON(null)).toBeNull();
|
expect(SshKey.fromJSON(null)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { SshKey as SdkSshKey } from "@bitwarden/sdk-internal";
|
import { SshKey as SdkSshKey } from "@bitwarden/sdk-internal";
|
||||||
@@ -11,9 +9,9 @@ import { SshKeyData } from "../data/ssh-key.data";
|
|||||||
import { SshKeyView } from "../view/ssh-key.view";
|
import { SshKeyView } from "../view/ssh-key.view";
|
||||||
|
|
||||||
export class SshKey extends Domain {
|
export class SshKey extends Domain {
|
||||||
privateKey: EncString;
|
privateKey!: EncString;
|
||||||
publicKey: EncString;
|
publicKey!: EncString;
|
||||||
keyFingerprint: EncString;
|
keyFingerprint!: EncString;
|
||||||
|
|
||||||
constructor(obj?: SshKeyData) {
|
constructor(obj?: SshKeyData) {
|
||||||
super();
|
super();
|
||||||
@@ -21,20 +19,13 @@ export class SshKey extends Domain {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.buildDomainModel(
|
this.privateKey = new EncString(obj.privateKey);
|
||||||
this,
|
this.publicKey = new EncString(obj.publicKey);
|
||||||
obj,
|
this.keyFingerprint = new EncString(obj.keyFingerprint);
|
||||||
{
|
|
||||||
privateKey: null,
|
|
||||||
publicKey: null,
|
|
||||||
keyFingerprint: null,
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypt(
|
decrypt(
|
||||||
orgId: string,
|
orgId: string | undefined,
|
||||||
context = "No Cipher Context",
|
context = "No Cipher Context",
|
||||||
encKey?: SymmetricCryptoKey,
|
encKey?: SymmetricCryptoKey,
|
||||||
): Promise<SshKeyView> {
|
): Promise<SshKeyView> {
|
||||||
@@ -42,7 +33,7 @@ export class SshKey extends Domain {
|
|||||||
this,
|
this,
|
||||||
new SshKeyView(),
|
new SshKeyView(),
|
||||||
["privateKey", "publicKey", "keyFingerprint"],
|
["privateKey", "publicKey", "keyFingerprint"],
|
||||||
orgId,
|
orgId ?? null,
|
||||||
encKey,
|
encKey,
|
||||||
"DomainType: SshKey; " + context,
|
"DomainType: SshKey; " + context,
|
||||||
);
|
);
|
||||||
@@ -58,19 +49,17 @@ export class SshKey extends Domain {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON(obj: Partial<Jsonify<SshKey>>): SshKey {
|
static fromJSON(obj: Jsonify<SshKey> | undefined): SshKey | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const privateKey = EncString.fromJSON(obj.privateKey);
|
const sshKey = new SshKey();
|
||||||
const publicKey = EncString.fromJSON(obj.publicKey);
|
sshKey.privateKey = EncString.fromJSON(obj.privateKey);
|
||||||
const keyFingerprint = EncString.fromJSON(obj.keyFingerprint);
|
sshKey.publicKey = EncString.fromJSON(obj.publicKey);
|
||||||
return Object.assign(new SshKey(), obj, {
|
sshKey.keyFingerprint = EncString.fromJSON(obj.keyFingerprint);
|
||||||
privateKey,
|
|
||||||
publicKey,
|
return sshKey;
|
||||||
keyFingerprint,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,7 +79,7 @@ export class SshKey extends Domain {
|
|||||||
* Maps an SDK SshKey object to a SshKey
|
* Maps an SDK SshKey object to a SshKey
|
||||||
* @param obj - The SDK SshKey object
|
* @param obj - The SDK SshKey object
|
||||||
*/
|
*/
|
||||||
static fromSdkSshKey(obj: SdkSshKey): SshKey | undefined {
|
static fromSdkSshKey(obj?: SdkSshKey): SshKey | undefined {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Cipher } from "../domain/cipher";
|
import { Cipher } from "../domain/cipher";
|
||||||
|
|
||||||
export class CipherPartialRequest {
|
export class CipherPartialRequest {
|
||||||
folderId: string;
|
folderId?: string;
|
||||||
favorite: boolean;
|
favorite: boolean;
|
||||||
|
|
||||||
constructor(cipher: Cipher) {
|
constructor(cipher: Cipher) {
|
||||||
|
|||||||
@@ -869,13 +869,14 @@ export class CipherService implements CipherServiceAbstraction {
|
|||||||
response = await this.apiService.postCipherAdmin(request);
|
response = await this.apiService.postCipherAdmin(request);
|
||||||
const data = new CipherData(response, cipher.collectionIds);
|
const data = new CipherData(response, cipher.collectionIds);
|
||||||
return new Cipher(data);
|
return new Cipher(data);
|
||||||
} else if (cipher.collectionIds != null) {
|
} else if (cipher.collectionIds != null && cipher.collectionIds.length > 0) {
|
||||||
const request = new CipherCreateRequest({ cipher, encryptedFor });
|
const request = new CipherCreateRequest({ cipher, encryptedFor });
|
||||||
response = await this.apiService.postCipherCreate(request);
|
response = await this.apiService.postCipherCreate(request);
|
||||||
} else {
|
} else {
|
||||||
const request = new CipherRequest({ cipher, encryptedFor });
|
const request = new CipherRequest({ cipher, encryptedFor });
|
||||||
response = await this.apiService.postCipher(request);
|
response = await this.apiService.postCipher(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
cipher.id = response.id;
|
cipher.id = response.id;
|
||||||
|
|
||||||
const data = new CipherData(response, cipher.collectionIds);
|
const data = new CipherData(response, cipher.collectionIds);
|
||||||
|
|||||||
27
libs/common/src/vault/utils/domain-utils.ts
Normal file
27
libs/common/src/vault/utils/domain-utils.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
|
||||||
|
import { EncString as SdkEncString } from "@bitwarden/sdk-internal";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string value to an EncString, handling null/undefined gracefully.
|
||||||
|
*
|
||||||
|
* @param value - The string value to convert, or undefined
|
||||||
|
* @returns An EncString instance if value is defined, otherwise undefined
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const conditionalEncString = (value?: string): EncString | undefined => {
|
||||||
|
return value != null ? new EncString(value) : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an EncString representation (from JSON or SDK) to a domain EncString instance.
|
||||||
|
* Handles both serialized JSON representations and SDK EncString objects.
|
||||||
|
*
|
||||||
|
* @param value - The EncString representation (string, object, or SdkEncString), or undefined
|
||||||
|
* @returns A domain EncString instance if value is defined, otherwise undefined
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const encStringFrom = <T extends string | SdkEncString>(
|
||||||
|
value?: T,
|
||||||
|
): EncString | undefined => {
|
||||||
|
return value != null ? EncString.fromJSON(value) : undefined;
|
||||||
|
};
|
||||||
@@ -343,7 +343,7 @@ describe("VaultExportService", () => {
|
|||||||
const exportData: BitwardenJsonExport = JSON.parse(data);
|
const exportData: BitwardenJsonExport = JSON.parse(data);
|
||||||
expect(exportData.items.length).toBe(1);
|
expect(exportData.items.length).toBe(1);
|
||||||
expect(exportData.items[0].id).toBe("mock-id");
|
expect(exportData.items[0].id).toBe("mock-id");
|
||||||
expect(exportData.items[0].organizationId).toBe(null);
|
expect(exportData.items[0].organizationId).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([[400], [401], [404], [500]])(
|
it.each([[400], [401], [404], [500]])(
|
||||||
|
|||||||
Reference in New Issue
Block a user