import { Jsonify } from "type-fest"; import { UriMatchStrategySetting } from "../../../models/domain/domain-service"; import { GeneratorOptions } from "../../../tools/generator/generator-options"; import { GeneratedPasswordHistory, PasswordGeneratorOptions, } from "../../../tools/generator/password"; import { UsernameGeneratorOptions } from "../../../tools/generator/username/username-generation-options"; import { DeepJsonify } from "../../../types/deep-jsonify"; import { KdfType } from "../../enums"; import { Utils } from "../../misc/utils"; import { EncryptedString, EncString } from "./enc-string"; import { SymmetricCryptoKey } from "./symmetric-crypto-key"; export class EncryptionPair { encrypted?: TEncrypted; decrypted?: TDecrypted; toJSON() { return { encrypted: this.encrypted, decrypted: this.decrypted instanceof ArrayBuffer ? Utils.fromBufferToByteString(this.decrypted) : this.decrypted, }; } static fromJSON( obj: { encrypted?: Jsonify; decrypted?: string | Jsonify }, decryptedFromJson?: (decObj: Jsonify | string) => TDecrypted, encryptedFromJson?: (encObj: Jsonify) => TEncrypted, ) { if (obj == null) { return null; } const pair = new EncryptionPair(); if (obj?.encrypted != null) { pair.encrypted = encryptedFromJson ? encryptedFromJson(obj.encrypted) : (obj.encrypted as TEncrypted); } if (obj?.decrypted != null) { pair.decrypted = decryptedFromJson ? decryptedFromJson(obj.decrypted) : (obj.decrypted as TDecrypted); } return pair; } } export class DataEncryptionPair { encrypted?: Record; decrypted?: TDecrypted[]; } export class AccountData { passwordGenerationHistory?: EncryptionPair< GeneratedPasswordHistory[], GeneratedPasswordHistory[] > = new EncryptionPair(); static fromJSON(obj: DeepJsonify): AccountData { if (obj == null) { return null; } return Object.assign(new AccountData(), obj); } } export class AccountKeys { publicKey?: Uint8Array; /** @deprecated July 2023, left for migration purposes*/ cryptoMasterKeyAuto?: string; /** @deprecated July 2023, left for migration purposes*/ cryptoMasterKeyBiometric?: string; /** @deprecated July 2023, left for migration purposes*/ cryptoSymmetricKey?: EncryptionPair = new EncryptionPair< string, SymmetricCryptoKey >(); toJSON() { // If you pass undefined into fromBufferToByteString, you will get an empty string back // which will cause all sorts of headaches down the line when you try to getPublicKey // and expect a Uint8Array and get an empty string instead. return Utils.merge(this, { publicKey: this.publicKey ? Utils.fromBufferToByteString(this.publicKey) : undefined, }); } static fromJSON(obj: DeepJsonify): AccountKeys { if (obj == null) { return null; } return Object.assign(new AccountKeys(), obj, { cryptoSymmetricKey: EncryptionPair.fromJSON( obj?.cryptoSymmetricKey, SymmetricCryptoKey.fromJSON, ), publicKey: Utils.fromByteStringToArray(obj?.publicKey), }); } static initRecordEncryptionPairsFromJSON(obj: any) { return EncryptionPair.fromJSON(obj, (decObj: any) => { if (obj == null) { return null; } const record: Record = {}; for (const id in decObj) { record[id] = SymmetricCryptoKey.fromJSON(decObj[id]); } return record; }); } } export class AccountProfile { name?: string; email?: string; emailVerified?: boolean; lastSync?: string; userId?: string; kdfIterations?: number; kdfMemory?: number; kdfParallelism?: number; kdfType?: KdfType; static fromJSON(obj: Jsonify): AccountProfile { if (obj == null) { return null; } return Object.assign(new AccountProfile(), obj); } } export class AccountSettings { defaultUriMatch?: UriMatchStrategySetting; minimizeOnCopyToClipboard?: boolean; passwordGenerationOptions?: PasswordGeneratorOptions; usernameGenerationOptions?: UsernameGeneratorOptions; generatorOptions?: GeneratorOptions; pinKeyEncryptedUserKey?: EncryptedString; pinKeyEncryptedUserKeyEphemeral?: EncryptedString; protectedPin?: string; vaultTimeout?: number; vaultTimeoutAction?: string = "lock"; /** @deprecated July 2023, left for migration purposes*/ pinProtected?: EncryptionPair = new EncryptionPair(); static fromJSON(obj: Jsonify): AccountSettings { if (obj == null) { return null; } return Object.assign(new AccountSettings(), obj, { pinProtected: EncryptionPair.fromJSON( obj?.pinProtected, EncString.fromJSON, ), }); } } export class Account { data?: AccountData = new AccountData(); keys?: AccountKeys = new AccountKeys(); profile?: AccountProfile = new AccountProfile(); settings?: AccountSettings = new AccountSettings(); constructor(init: Partial) { Object.assign(this, { data: { ...new AccountData(), ...init?.data, }, keys: { ...new AccountKeys(), ...init?.keys, }, profile: { ...new AccountProfile(), ...init?.profile, }, settings: { ...new AccountSettings(), ...init?.settings, }, }); } static fromJSON(json: Jsonify): Account { if (json == null) { return null; } return Object.assign(new Account({}), json, { keys: AccountKeys.fromJSON(json?.keys), data: AccountData.fromJSON(json?.data), profile: AccountProfile.fromJSON(json?.profile), settings: AccountSettings.fromJSON(json?.settings), }); } }