From 862bf28348e250750ad433559ae595f6f48659a6 Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Wed, 16 Nov 2022 19:13:13 -0500 Subject: [PATCH] Serialize Browser Accounts --- apps/browser/src/models/account.ts | 24 +++++++++++++++++ .../src/models/browserComponentState.ts | 10 +++++++ .../models/browserGroupingsComponentState.ts | 26 +++++++++++++++++++ .../src/models/browserSendComponentState.ts | 19 ++++++++++++++ .../popup/send/send-groupings.component.ts | 4 +-- .../src/popup/vault/vault-filter.component.ts | 4 +-- libs/common/src/models/view/send-file.view.ts | 9 +++++++ libs/common/src/models/view/send-text.view.ts | 9 +++++++ libs/common/src/models/view/send.view.ts | 23 ++++++++++++++++ 9 files changed, 124 insertions(+), 4 deletions(-) diff --git a/apps/browser/src/models/account.ts b/apps/browser/src/models/account.ts index f49c55d2909..cfbcbecf979 100644 --- a/apps/browser/src/models/account.ts +++ b/apps/browser/src/models/account.ts @@ -1,3 +1,5 @@ +import { Jsonify } from "type-fest"; + import { Account as BaseAccount, AccountSettings as BaseAccountSettings, @@ -9,6 +11,14 @@ import { BrowserSendComponentState } from "./browserSendComponentState"; export class AccountSettings extends BaseAccountSettings { vaultTimeout = -1; // On Restart + + static fromJSON(json: Jsonify): AccountSettings { + if (json == null) { + return null; + } + + return Object.assign(new AccountSettings(), json, super.fromJSON(json)); + } } export class Account extends BaseAccount { @@ -29,4 +39,18 @@ export class Account extends BaseAccount { this.ciphers = init?.ciphers ?? new BrowserComponentState(); this.sendType = init?.sendType ?? new BrowserComponentState(); } + + static fromJSON(json: Jsonify): Account { + if (json == null) { + return null; + } + + return Object.assign(new Account({}), json, super.fromJSON(json), { + settings: AccountSettings.fromJSON(json.settings), + groupings: BrowserGroupingsComponentState.fromJSON(json.groupings), + send: BrowserSendComponentState.fromJSON(json.send), + ciphers: BrowserComponentState.fromJSON(json.ciphers), + sendType: BrowserComponentState.fromJSON(json.sendType), + }); + } } diff --git a/apps/browser/src/models/browserComponentState.ts b/apps/browser/src/models/browserComponentState.ts index d968726c413..c5540d088ff 100644 --- a/apps/browser/src/models/browserComponentState.ts +++ b/apps/browser/src/models/browserComponentState.ts @@ -1,4 +1,14 @@ +import { Jsonify } from "type-fest"; + export class BrowserComponentState { scrollY: number; searchText: string; + + static fromJSON(json: Jsonify) { + if (json == null) { + return null; + } + + return Object.assign(new BrowserComponentState(), json); + } } diff --git a/apps/browser/src/models/browserGroupingsComponentState.ts b/apps/browser/src/models/browserGroupingsComponentState.ts index 63eb4aaa88f..f406e3d8271 100644 --- a/apps/browser/src/models/browserGroupingsComponentState.ts +++ b/apps/browser/src/models/browserGroupingsComponentState.ts @@ -1,7 +1,9 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; +import { Utils } from "@bitwarden/common/misc/utils"; import { CipherView } from "@bitwarden/common/models/view/cipher.view"; import { CollectionView } from "@bitwarden/common/models/view/collection.view"; import { FolderView } from "@bitwarden/common/models/view/folder.view"; +import { DeepJsonify } from "@bitwarden/common/types/deep-jsonify"; import { BrowserComponentState } from "./browserComponentState"; @@ -15,4 +17,28 @@ export class BrowserGroupingsComponentState extends BrowserComponentState { folders: FolderView[]; collections: CollectionView[]; deletedCount: number; + + toJSON() { + return Utils.merge(this, { + collectionCounts: Utils.mapToRecord(this.collectionCounts), + folderCounts: Utils.mapToRecord(this.folderCounts), + typeCounts: Utils.mapToRecord(this.typeCounts), + }); + } + + static fromJSON(json: DeepJsonify) { + if (json == null) { + return null; + } + + return Object.assign(new BrowserGroupingsComponentState(), json, { + favoriteCiphers: json.favoriteCiphers?.map((c) => CipherView.fromJSON(c)), + noFolderCiphers: json.noFolderCiphers?.map((c) => CipherView.fromJSON(c)), + ciphers: json.ciphers?.map((c) => CipherView.fromJSON(c)), + collectionCounts: Utils.recordToMap(json.collectionCounts), + folderCounts: Utils.recordToMap(json.folderCounts), + typeCounts: Utils.recordToMap(json.typeCounts), + folders: json.folders?.map((f) => FolderView.fromJSON(f)), + }); + } } diff --git a/apps/browser/src/models/browserSendComponentState.ts b/apps/browser/src/models/browserSendComponentState.ts index e2bf4eaa5d6..99508737ab1 100644 --- a/apps/browser/src/models/browserSendComponentState.ts +++ b/apps/browser/src/models/browserSendComponentState.ts @@ -1,9 +1,28 @@ import { SendType } from "@bitwarden/common/enums/sendType"; +import { Utils } from "@bitwarden/common/misc/utils"; import { SendView } from "@bitwarden/common/models/view/send.view"; +import { DeepJsonify } from "@bitwarden/common/types/deep-jsonify"; import { BrowserComponentState } from "./browserComponentState"; export class BrowserSendComponentState extends BrowserComponentState { sends: SendView[]; typeCounts: Map; + + toJSON() { + return Utils.merge(this, { + typeCounts: Utils.mapToRecord(this.typeCounts), + }); + } + + static fromJSON(json: DeepJsonify) { + if (json == null) { + return null; + } + + return Object.assign(new BrowserSendComponentState(), json, { + sends: json.sends?.map((s) => SendView.fromJSON(s)), + typeCounts: Utils.recordToMap(json.typeCounts), + }); + } } diff --git a/apps/browser/src/popup/send/send-groupings.component.ts b/apps/browser/src/popup/send/send-groupings.component.ts index 1af715ada0f..00bcb99df7a 100644 --- a/apps/browser/src/popup/send/send-groupings.component.ts +++ b/apps/browser/src/popup/send/send-groupings.component.ts @@ -165,12 +165,12 @@ export class SendGroupingsComponent extends BaseSendComponent { } private async saveState() { - this.state = { + this.state = Object.assign(new BrowserSendComponentState(), { scrollY: this.popupUtils.getContentScrollY(window), searchText: this.searchText, sends: this.sends, typeCounts: this.typeCounts, - }; + }); await this.stateService.setBrowserSendComponentState(this.state); } diff --git a/apps/browser/src/popup/vault/vault-filter.component.ts b/apps/browser/src/popup/vault/vault-filter.component.ts index 6ae6f9b88d9..9e7e7f3709a 100644 --- a/apps/browser/src/popup/vault/vault-filter.component.ts +++ b/apps/browser/src/popup/vault/vault-filter.component.ts @@ -373,7 +373,7 @@ export class VaultFilterComponent implements OnInit, OnDestroy { } private async saveState() { - this.state = { + this.state = Object.assign(new BrowserGroupingsComponentState(), { scrollY: this.popupUtils.getContentScrollY(window), searchText: this.searchText, favoriteCiphers: this.favoriteCiphers, @@ -385,7 +385,7 @@ export class VaultFilterComponent implements OnInit, OnDestroy { folders: this.folders, collections: this.collections, deletedCount: this.deletedCount, - }; + }); await this.browserStateService.setBrowserGroupingComponentState(this.state); } diff --git a/libs/common/src/models/view/send-file.view.ts b/libs/common/src/models/view/send-file.view.ts index 7ed291a2b73..3ac12b8203d 100644 --- a/libs/common/src/models/view/send-file.view.ts +++ b/libs/common/src/models/view/send-file.view.ts @@ -1,3 +1,4 @@ +import { DeepJsonify } from "../../types/deep-jsonify"; import { SendFile } from "../domain/send-file"; import { View } from "./view"; @@ -28,4 +29,12 @@ export class SendFileView implements View { } return 0; } + + static fromJSON(json: DeepJsonify) { + if (json == null) { + return null; + } + + return Object.assign(new SendFileView(), json); + } } diff --git a/libs/common/src/models/view/send-text.view.ts b/libs/common/src/models/view/send-text.view.ts index cd10c799b64..638f66ad661 100644 --- a/libs/common/src/models/view/send-text.view.ts +++ b/libs/common/src/models/view/send-text.view.ts @@ -1,3 +1,4 @@ +import { DeepJsonify } from "../../types/deep-jsonify"; import { SendText } from "../domain/send-text"; import { View } from "./view"; @@ -17,4 +18,12 @@ export class SendTextView implements View { get maskedText(): string { return this.text != null ? "••••••••" : null; } + + static fromJSON(json: DeepJsonify) { + if (json == null) { + return null; + } + + return Object.assign(new SendTextView(), json); + } } diff --git a/libs/common/src/models/view/send.view.ts b/libs/common/src/models/view/send.view.ts index 3ef6bf9f0e3..c5da1d2f683 100644 --- a/libs/common/src/models/view/send.view.ts +++ b/libs/common/src/models/view/send.view.ts @@ -1,5 +1,6 @@ import { SendType } from "../../enums/sendType"; import { Utils } from "../../misc/utils"; +import { DeepJsonify } from "../../types/deep-jsonify"; import { Send } from "../domain/send"; import { SymmetricCryptoKey } from "../domain/symmetric-crypto-key"; @@ -65,4 +66,26 @@ export class SendView implements View { get pendingDelete(): boolean { return this.deletionDate <= new Date(); } + + toJSON() { + return Utils.merge(this, { + key: Utils.fromBufferToB64(this.key), + }); + } + + static fromJSON(json: DeepJsonify) { + if (json == null) { + return null; + } + + return Object.assign(new SendView(), json, { + key: Utils.fromB64ToArray(json.key)?.buffer, + cryptoKey: SymmetricCryptoKey.fromJSON(json.cryptoKey), + text: SendTextView.fromJSON(json.text), + file: SendFileView.fromJSON(json.file), + revisionDate: json.revisionDate == null ? null : new Date(json.revisionDate), + deletionDate: json.deletionDate == null ? null : new Date(json.deletionDate), + expirationDate: json.expirationDate == null ? null : new Date(json.expirationDate), + }); + } }