1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-19 01:33:33 +00:00

[SG-998] and [SG-999] Vault and Autofill team refactor (#4542)

* Move DeprecatedVaultFilterService to vault folder

* [libs] move VaultItemsComponent

* [libs] move AddEditComponent

* [libs] move AddEditCustomFields

* [libs] move attachmentsComponent

* [libs] folderAddEditComponent

* [libs] IconComponent

* [libs] PasswordRepormptComponent

* [libs] PremiumComponent

* [libs] ViewCustomFieldsComponent

* [libs] ViewComponent

* [libs] PasswordRepromptService

* [libs] Move FolderService and FolderApiService abstractions

* [libs] FolderService imports

* [libs] PasswordHistoryComponent

* [libs] move Sync and SyncNotifier abstractions

* [libs] SyncService imports

* [libs] fix file casing for passwordReprompt abstraction

* [libs] SyncNotifier import fix

* [libs] CipherServiceAbstraction

* [libs] PasswordRepromptService abstraction

* [libs] Fix file casing for angular passwordReprompt service

* [libs] fix file casing for SyncNotifierService

* [libs] CipherRepromptType

* [libs] rename CipherRepromptType

* [libs] CipherType

* [libs] Rename CipherType

* [libs] CipherData

* [libs] FolderData

* [libs] PasswordHistoryData

* [libs] AttachmentData

* [libs] CardData

* [libs] FieldData

* [libs] IdentityData

* [libs] LocalData

* [libs] LoginData

* [libs] SecureNoteData

* [libs] LoginUriData

* [libs] Domain classes

* [libs] SecureNote

* [libs] Request models

* [libs] Response models

* [libs] View part 1

* [libs] Views part 2

* [libs] Move folder services

* [libs] Views fixes

* [libs] Move sync services

* [libs] cipher service

* [libs] Types

* [libs] Sync file casing

* [libs] Fix folder service import

* [libs] Move spec files

* [libs] casing fixes on spec files

* [browser] Autofill background, clipboard, commands

* [browser] Fix ContextMenusBackground casing

* [browser] Rename fix

* [browser] Autofill content

* [browser] autofill.js

* [libs] enpass importer spec fix

* [browser] autofill models

* [browser] autofill manifest path updates

* [browser] Autofill notification files

* [browser] autofill services

* [browser] Fix file casing

* [browser] Vault popup loose components

* [browser] Vault components

* [browser] Manifest fixes

* [browser] Vault services

* [cli] vault commands and models

* [browser] File capitilization fixes

* [desktop] Vault components and services

* [web] vault loose components

* [web] Vault components

* [browser] Fix misc-utils import

* [libs] Fix psono spec imports

* [fix] Add comments to address lint rules
This commit is contained in:
Robyn MacCallum
2023-01-31 16:08:37 -05:00
committed by GitHub
parent bf1df6ebf6
commit 7ebedbecfb
472 changed files with 1371 additions and 1328 deletions

View File

@@ -5,17 +5,17 @@ import { KdfType } from "../../enums/kdfType";
import { UriMatchType } from "../../enums/uriMatchType";
import { Utils } from "../../misc/utils";
import { DeepJsonify } from "../../types/deep-jsonify";
import { CipherData } from "../data/cipher.data";
import { CipherData } from "../../vault/models/data/cipher.data";
import { FolderData } from "../../vault/models/data/folder.data";
import { CipherView } from "../../vault/models/view/cipher.view";
import { CollectionData } from "../data/collection.data";
import { EncryptedOrganizationKeyData } from "../data/encrypted-organization-key.data";
import { EventData } from "../data/event.data";
import { FolderData } from "../data/folder.data";
import { OrganizationData } from "../data/organization.data";
import { PolicyData } from "../data/policy.data";
import { ProviderData } from "../data/provider.data";
import { SendData } from "../data/send.data";
import { ServerConfigData } from "../data/server-config.data";
import { CipherView } from "../view/cipher.view";
import { CollectionView } from "../view/collection.view";
import { SendView } from "../view/send.view";

View File

@@ -1,109 +0,0 @@
import { Jsonify } from "type-fest";
import { Utils } from "../../misc/utils";
import { AttachmentData } from "../data/attachment.data";
import { AttachmentView } from "../view/attachment.view";
import Domain from "./domain-base";
import { EncString } from "./enc-string";
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
export class Attachment extends Domain {
id: string;
url: string;
size: string;
sizeName: string; // Readable size, ex: "4.2 KB" or "1.43 GB"
key: EncString;
fileName: EncString;
constructor(obj?: AttachmentData) {
super();
if (obj == null) {
return;
}
this.size = obj.size;
this.buildDomainModel(
this,
obj,
{
id: null,
url: null,
sizeName: null,
fileName: null,
key: null,
},
["id", "url", "sizeName"]
);
}
async decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<AttachmentView> {
const view = await this.decryptObj(
new AttachmentView(this),
{
fileName: null,
},
orgId,
encKey
);
if (this.key != null) {
view.key = await this.decryptAttachmentKey(orgId, encKey);
}
return view;
}
private async decryptAttachmentKey(orgId: string, encKey?: SymmetricCryptoKey) {
try {
if (encKey == null) {
encKey = await this.getKeyForDecryption(orgId);
}
const encryptService = Utils.getContainerService().getEncryptService();
const decValue = await encryptService.decryptToBytes(this.key, encKey);
return new SymmetricCryptoKey(decValue);
} catch (e) {
// TODO: error?
}
}
private async getKeyForDecryption(orgId: string) {
const cryptoService = Utils.getContainerService().getCryptoService();
return orgId != null
? await cryptoService.getOrgKey(orgId)
: await cryptoService.getKeyForUserEncryption();
}
toAttachmentData(): AttachmentData {
const a = new AttachmentData();
a.size = this.size;
this.buildDataModel(
this,
a,
{
id: null,
url: null,
sizeName: null,
fileName: null,
key: null,
},
["id", "url", "sizeName"]
);
return a;
}
static fromJSON(obj: Partial<Jsonify<Attachment>>): Attachment {
if (obj == null) {
return null;
}
const key = EncString.fromJSON(obj.key);
const fileName = EncString.fromJSON(obj.fileName);
return Object.assign(new Attachment(), obj, {
key,
fileName,
});
}
}

View File

@@ -1,88 +0,0 @@
import { Jsonify } from "type-fest";
import { CardData } from "../data/card.data";
import { CardView } from "../view/card.view";
import Domain from "./domain-base";
import { EncString } from "./enc-string";
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
export class Card extends Domain {
cardholderName: EncString;
brand: EncString;
number: EncString;
expMonth: EncString;
expYear: EncString;
code: EncString;
constructor(obj?: CardData) {
super();
if (obj == null) {
return;
}
this.buildDomainModel(
this,
obj,
{
cardholderName: null,
brand: null,
number: null,
expMonth: null,
expYear: null,
code: null,
},
[]
);
}
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<CardView> {
return this.decryptObj(
new CardView(),
{
cardholderName: null,
brand: null,
number: null,
expMonth: null,
expYear: null,
code: null,
},
orgId,
encKey
);
}
toCardData(): CardData {
const c = new CardData();
this.buildDataModel(this, c, {
cardholderName: null,
brand: null,
number: null,
expMonth: null,
expYear: null,
code: null,
});
return c;
}
static fromJSON(obj: Partial<Jsonify<Card>>): Card {
if (obj == null) {
return null;
}
const cardholderName = EncString.fromJSON(obj.cardholderName);
const brand = EncString.fromJSON(obj.brand);
const number = EncString.fromJSON(obj.number);
const expMonth = EncString.fromJSON(obj.expMonth);
const expYear = EncString.fromJSON(obj.expYear);
const code = EncString.fromJSON(obj.code);
return Object.assign(new Card(), obj, {
cardholderName,
brand,
number,
expMonth,
expYear,
code,
});
}
}

View File

@@ -1,290 +0,0 @@
import { Jsonify } from "type-fest";
import { CipherRepromptType } from "../../enums/cipherRepromptType";
import { CipherType } from "../../enums/cipherType";
import { Decryptable } from "../../interfaces/decryptable.interface";
import { InitializerKey } from "../../services/cryptography/initializer-key";
import { CipherData } from "../data/cipher.data";
import { LocalData } from "../data/local.data";
import { CipherView } from "../view/cipher.view";
import { Attachment } from "./attachment";
import { Card } from "./card";
import Domain from "./domain-base";
import { EncString } from "./enc-string";
import { Field } from "./field";
import { Identity } from "./identity";
import { Login } from "./login";
import { Password } from "./password";
import { SecureNote } from "./secure-note";
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
export class Cipher extends Domain implements Decryptable<CipherView> {
readonly initializerKey = InitializerKey.Cipher;
id: string;
organizationId: string;
folderId: string;
name: EncString;
notes: EncString;
type: CipherType;
favorite: boolean;
organizationUseTotp: boolean;
edit: boolean;
viewPassword: boolean;
revisionDate: Date;
localData: LocalData;
login: Login;
identity: Identity;
card: Card;
secureNote: SecureNote;
attachments: Attachment[];
fields: Field[];
passwordHistory: Password[];
collectionIds: string[];
creationDate: Date;
deletedDate: Date;
reprompt: CipherRepromptType;
constructor(obj?: CipherData, localData: LocalData = null) {
super();
if (obj == null) {
return;
}
this.buildDomainModel(
this,
obj,
{
id: null,
organizationId: null,
folderId: null,
name: null,
notes: null,
},
["id", "organizationId", "folderId"]
);
this.type = obj.type;
this.favorite = obj.favorite;
this.organizationUseTotp = obj.organizationUseTotp;
this.edit = obj.edit;
if (obj.viewPassword != null) {
this.viewPassword = obj.viewPassword;
} else {
this.viewPassword = true; // Default for already synced Ciphers without viewPassword
}
this.revisionDate = obj.revisionDate != null ? new Date(obj.revisionDate) : null;
this.collectionIds = obj.collectionIds;
this.localData = localData;
this.creationDate = obj.creationDate != null ? new Date(obj.creationDate) : null;
this.deletedDate = obj.deletedDate != null ? new Date(obj.deletedDate) : null;
this.reprompt = obj.reprompt;
switch (this.type) {
case CipherType.Login:
this.login = new Login(obj.login);
break;
case CipherType.SecureNote:
this.secureNote = new SecureNote(obj.secureNote);
break;
case CipherType.Card:
this.card = new Card(obj.card);
break;
case CipherType.Identity:
this.identity = new Identity(obj.identity);
break;
default:
break;
}
if (obj.attachments != null) {
this.attachments = obj.attachments.map((a) => new Attachment(a));
} else {
this.attachments = null;
}
if (obj.fields != null) {
this.fields = obj.fields.map((f) => new Field(f));
} else {
this.fields = null;
}
if (obj.passwordHistory != null) {
this.passwordHistory = obj.passwordHistory.map((ph) => new Password(ph));
} else {
this.passwordHistory = null;
}
}
async decrypt(encKey?: SymmetricCryptoKey): Promise<CipherView> {
const model = new CipherView(this);
await this.decryptObj(
model,
{
name: null,
notes: null,
},
this.organizationId,
encKey
);
switch (this.type) {
case CipherType.Login:
model.login = await this.login.decrypt(this.organizationId, encKey);
break;
case CipherType.SecureNote:
model.secureNote = await this.secureNote.decrypt(this.organizationId, encKey);
break;
case CipherType.Card:
model.card = await this.card.decrypt(this.organizationId, encKey);
break;
case CipherType.Identity:
model.identity = await this.identity.decrypt(this.organizationId, encKey);
break;
default:
break;
}
const orgId = this.organizationId;
if (this.attachments != null && this.attachments.length > 0) {
const attachments: any[] = [];
await this.attachments.reduce((promise, attachment) => {
return promise
.then(() => {
return attachment.decrypt(orgId, encKey);
})
.then((decAttachment) => {
attachments.push(decAttachment);
});
}, Promise.resolve());
model.attachments = attachments;
}
if (this.fields != null && this.fields.length > 0) {
const fields: any[] = [];
await this.fields.reduce((promise, field) => {
return promise
.then(() => {
return field.decrypt(orgId, encKey);
})
.then((decField) => {
fields.push(decField);
});
}, Promise.resolve());
model.fields = fields;
}
if (this.passwordHistory != null && this.passwordHistory.length > 0) {
const passwordHistory: any[] = [];
await this.passwordHistory.reduce((promise, ph) => {
return promise
.then(() => {
return ph.decrypt(orgId, encKey);
})
.then((decPh) => {
passwordHistory.push(decPh);
});
}, Promise.resolve());
model.passwordHistory = passwordHistory;
}
return model;
}
toCipherData(): CipherData {
const c = new CipherData();
c.id = this.id;
c.organizationId = this.organizationId;
c.folderId = this.folderId;
c.edit = this.edit;
c.viewPassword = this.viewPassword;
c.organizationUseTotp = this.organizationUseTotp;
c.favorite = this.favorite;
c.revisionDate = this.revisionDate != null ? this.revisionDate.toISOString() : null;
c.type = this.type;
c.collectionIds = this.collectionIds;
c.creationDate = this.creationDate != null ? this.creationDate.toISOString() : null;
c.deletedDate = this.deletedDate != null ? this.deletedDate.toISOString() : null;
c.reprompt = this.reprompt;
this.buildDataModel(this, c, {
name: null,
notes: null,
});
switch (c.type) {
case CipherType.Login:
c.login = this.login.toLoginData();
break;
case CipherType.SecureNote:
c.secureNote = this.secureNote.toSecureNoteData();
break;
case CipherType.Card:
c.card = this.card.toCardData();
break;
case CipherType.Identity:
c.identity = this.identity.toIdentityData();
break;
default:
break;
}
if (this.fields != null) {
c.fields = this.fields.map((f) => f.toFieldData());
}
if (this.attachments != null) {
c.attachments = this.attachments.map((a) => a.toAttachmentData());
}
if (this.passwordHistory != null) {
c.passwordHistory = this.passwordHistory.map((ph) => ph.toPasswordHistoryData());
}
return c;
}
static fromJSON(obj: Jsonify<Cipher>) {
if (obj == null) {
return null;
}
const domain = new Cipher();
const name = EncString.fromJSON(obj.name);
const notes = EncString.fromJSON(obj.notes);
const revisionDate = obj.revisionDate == null ? null : new Date(obj.revisionDate);
const deletedDate = obj.deletedDate == null ? null : 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));
Object.assign(domain, obj, {
name,
notes,
revisionDate,
deletedDate,
attachments,
fields,
passwordHistory,
});
switch (obj.type) {
case CipherType.Card:
domain.card = Card.fromJSON(obj.card);
break;
case CipherType.Identity:
domain.identity = Identity.fromJSON(obj.identity);
break;
case CipherType.Login:
domain.login = Login.fromJSON(obj.login);
break;
case CipherType.SecureNote:
domain.secureNote = SecureNote.fromJSON(obj.secureNote);
break;
default:
break;
}
return domain;
}
}

View File

@@ -1,78 +0,0 @@
import { Jsonify } from "type-fest";
import { FieldType } from "../../enums/fieldType";
import { LinkedIdType } from "../../enums/linkedIdType";
import { FieldData } from "../data/field.data";
import { FieldView } from "../view/field.view";
import Domain from "./domain-base";
import { EncString } from "./enc-string";
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
export class Field extends Domain {
name: EncString;
value: EncString;
type: FieldType;
linkedId: LinkedIdType;
constructor(obj?: FieldData) {
super();
if (obj == null) {
return;
}
this.type = obj.type;
this.linkedId = obj.linkedId;
this.buildDomainModel(
this,
obj,
{
name: null,
value: null,
},
[]
);
}
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<FieldView> {
return this.decryptObj(
new FieldView(this),
{
name: null,
value: null,
},
orgId,
encKey
);
}
toFieldData(): FieldData {
const f = new FieldData();
this.buildDataModel(
this,
f,
{
name: null,
value: null,
type: null,
linkedId: null,
},
["type", "linkedId"]
);
return f;
}
static fromJSON(obj: Partial<Jsonify<Field>>): Field {
if (obj == null) {
return null;
}
const name = EncString.fromJSON(obj.name);
const value = EncString.fromJSON(obj.value);
return Object.assign(new Field(), obj, {
name,
value,
});
}
}

View File

@@ -1,47 +0,0 @@
import { Jsonify } from "type-fest";
import { FolderData } from "../data/folder.data";
import { FolderView } from "../view/folder.view";
import Domain from "./domain-base";
import { EncString } from "./enc-string";
export class Folder extends Domain {
id: string;
name: EncString;
revisionDate: Date;
constructor(obj?: FolderData) {
super();
if (obj == null) {
return;
}
this.buildDomainModel(
this,
obj,
{
id: null,
name: null,
},
["id"]
);
this.revisionDate = obj.revisionDate != null ? new Date(obj.revisionDate) : null;
}
decrypt(): Promise<FolderView> {
return this.decryptObj(
new FolderView(this),
{
name: null,
},
null
);
}
static fromJSON(obj: Jsonify<Folder>) {
const revisionDate = obj.revisionDate == null ? null : new Date(obj.revisionDate);
return Object.assign(new Folder(), obj, { name: EncString.fromJSON(obj.name), revisionDate });
}
}

View File

@@ -1,161 +0,0 @@
import { Jsonify } from "type-fest";
import { IdentityData } from "../data/identity.data";
import { IdentityView } from "../view/identity.view";
import Domain from "./domain-base";
import { EncString } from "./enc-string";
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
export class Identity extends Domain {
title: EncString;
firstName: EncString;
middleName: EncString;
lastName: EncString;
address1: EncString;
address2: EncString;
address3: EncString;
city: EncString;
state: EncString;
postalCode: EncString;
country: EncString;
company: EncString;
email: EncString;
phone: EncString;
ssn: EncString;
username: EncString;
passportNumber: EncString;
licenseNumber: EncString;
constructor(obj?: IdentityData) {
super();
if (obj == null) {
return;
}
this.buildDomainModel(
this,
obj,
{
title: null,
firstName: null,
middleName: null,
lastName: null,
address1: null,
address2: null,
address3: null,
city: null,
state: null,
postalCode: null,
country: null,
company: null,
email: null,
phone: null,
ssn: null,
username: null,
passportNumber: null,
licenseNumber: null,
},
[]
);
}
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<IdentityView> {
return this.decryptObj(
new IdentityView(),
{
title: null,
firstName: null,
middleName: null,
lastName: null,
address1: null,
address2: null,
address3: null,
city: null,
state: null,
postalCode: null,
country: null,
company: null,
email: null,
phone: null,
ssn: null,
username: null,
passportNumber: null,
licenseNumber: null,
},
orgId,
encKey
);
}
toIdentityData(): IdentityData {
const i = new IdentityData();
this.buildDataModel(this, i, {
title: null,
firstName: null,
middleName: null,
lastName: null,
address1: null,
address2: null,
address3: null,
city: null,
state: null,
postalCode: null,
country: null,
company: null,
email: null,
phone: null,
ssn: null,
username: null,
passportNumber: null,
licenseNumber: null,
});
return i;
}
static fromJSON(obj: Jsonify<Identity>): Identity {
if (obj == null) {
return null;
}
const title = EncString.fromJSON(obj.title);
const firstName = EncString.fromJSON(obj.firstName);
const middleName = EncString.fromJSON(obj.middleName);
const lastName = EncString.fromJSON(obj.lastName);
const address1 = EncString.fromJSON(obj.address1);
const address2 = EncString.fromJSON(obj.address2);
const address3 = EncString.fromJSON(obj.address3);
const city = EncString.fromJSON(obj.city);
const state = EncString.fromJSON(obj.state);
const postalCode = EncString.fromJSON(obj.postalCode);
const country = EncString.fromJSON(obj.country);
const company = EncString.fromJSON(obj.company);
const email = EncString.fromJSON(obj.email);
const phone = EncString.fromJSON(obj.phone);
const ssn = EncString.fromJSON(obj.ssn);
const username = EncString.fromJSON(obj.username);
const passportNumber = EncString.fromJSON(obj.passportNumber);
const licenseNumber = EncString.fromJSON(obj.licenseNumber);
return Object.assign(new Identity(), obj, {
title,
firstName,
middleName,
lastName,
address1,
address2,
address3,
city,
state,
postalCode,
country,
company,
email,
phone,
ssn,
username,
passportNumber,
licenseNumber,
});
}
}

View File

@@ -1,6 +1,6 @@
import { CipherView } from "../view/cipher.view";
import { CipherView } from "../../vault/models/view/cipher.view";
import { FolderView } from "../../vault/models/view/folder.view";
import { CollectionView } from "../view/collection.view";
import { FolderView } from "../view/folder.view";
export class ImportResult {
success = false;

View File

@@ -1,67 +0,0 @@
import { Jsonify } from "type-fest";
import { UriMatchType } from "../../enums/uriMatchType";
import { LoginUriData } from "../data/login-uri.data";
import { LoginUriView } from "../view/login-uri.view";
import Domain from "./domain-base";
import { EncString } from "./enc-string";
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
export class LoginUri extends Domain {
uri: EncString;
match: UriMatchType;
constructor(obj?: LoginUriData) {
super();
if (obj == null) {
return;
}
this.match = obj.match;
this.buildDomainModel(
this,
obj,
{
uri: null,
},
[]
);
}
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<LoginUriView> {
return this.decryptObj(
new LoginUriView(this),
{
uri: null,
},
orgId,
encKey
);
}
toLoginUriData(): LoginUriData {
const u = new LoginUriData();
this.buildDataModel(
this,
u,
{
uri: null,
match: null,
},
["match"]
);
return u;
}
static fromJSON(obj: Jsonify<LoginUri>): LoginUri {
if (obj == null) {
return null;
}
const uri = EncString.fromJSON(obj.uri);
return Object.assign(new LoginUri(), obj, {
uri,
});
}
}

View File

@@ -1,111 +0,0 @@
import { Jsonify } from "type-fest";
import { LoginData } from "../data/login.data";
import { LoginView } from "../view/login.view";
import Domain from "./domain-base";
import { EncString } from "./enc-string";
import { LoginUri } from "./login-uri";
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
export class Login extends Domain {
uris: LoginUri[];
username: EncString;
password: EncString;
passwordRevisionDate?: Date;
totp: EncString;
autofillOnPageLoad: boolean;
constructor(obj?: LoginData) {
super();
if (obj == null) {
return;
}
this.passwordRevisionDate =
obj.passwordRevisionDate != null ? new Date(obj.passwordRevisionDate) : null;
this.autofillOnPageLoad = obj.autofillOnPageLoad;
this.buildDomainModel(
this,
obj,
{
username: null,
password: null,
totp: null,
},
[]
);
if (obj.uris) {
this.uris = [];
obj.uris.forEach((u) => {
this.uris.push(new LoginUri(u));
});
}
}
async decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<LoginView> {
const view = await this.decryptObj(
new LoginView(this),
{
username: null,
password: null,
totp: null,
},
orgId,
encKey
);
if (this.uris != null) {
view.uris = [];
for (let i = 0; i < this.uris.length; i++) {
const uri = await this.uris[i].decrypt(orgId, encKey);
view.uris.push(uri);
}
}
return view;
}
toLoginData(): LoginData {
const l = new LoginData();
l.passwordRevisionDate =
this.passwordRevisionDate != null ? this.passwordRevisionDate.toISOString() : null;
l.autofillOnPageLoad = this.autofillOnPageLoad;
this.buildDataModel(this, l, {
username: null,
password: null,
totp: null,
});
if (this.uris != null && this.uris.length > 0) {
l.uris = [];
this.uris.forEach((u) => {
l.uris.push(u.toLoginUriData());
});
}
return l;
}
static fromJSON(obj: Partial<Jsonify<Login>>): Login {
if (obj == null) {
return null;
}
const username = EncString.fromJSON(obj.username);
const password = EncString.fromJSON(obj.password);
const totp = EncString.fromJSON(obj.totp);
const passwordRevisionDate =
obj.passwordRevisionDate == null ? null : new Date(obj.passwordRevisionDate);
const uris = obj.uris?.map((uri: any) => LoginUri.fromJSON(uri));
return Object.assign(new Login(), obj, {
username,
password,
totp,
passwordRevisionDate: passwordRevisionDate,
uris: uris,
});
}
}

View File

@@ -1,59 +0,0 @@
import { Jsonify } from "type-fest";
import { PasswordHistoryData } from "../data/password-history.data";
import { PasswordHistoryView } from "../view/password-history.view";
import Domain from "./domain-base";
import { EncString } from "./enc-string";
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
export class Password extends Domain {
password: EncString;
lastUsedDate: Date;
constructor(obj?: PasswordHistoryData) {
super();
if (obj == null) {
return;
}
this.buildDomainModel(this, obj, {
password: null,
});
this.lastUsedDate = new Date(obj.lastUsedDate);
}
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<PasswordHistoryView> {
return this.decryptObj(
new PasswordHistoryView(this),
{
password: null,
},
orgId,
encKey
);
}
toPasswordHistoryData(): PasswordHistoryData {
const ph = new PasswordHistoryData();
ph.lastUsedDate = this.lastUsedDate.toISOString();
this.buildDataModel(this, ph, {
password: null,
});
return ph;
}
static fromJSON(obj: Partial<Jsonify<Password>>): Password {
if (obj == null) {
return null;
}
const password = EncString.fromJSON(obj.password);
const lastUsedDate = obj.lastUsedDate == null ? null : new Date(obj.lastUsedDate);
return Object.assign(new Password(), obj, {
password,
lastUsedDate,
});
}
}

View File

@@ -1,39 +0,0 @@
import { Jsonify } from "type-fest";
import { SecureNoteType } from "../../enums/secureNoteType";
import { SecureNoteData } from "../data/secure-note.data";
import { SecureNoteView } from "../view/secure-note.view";
import Domain from "./domain-base";
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
export class SecureNote extends Domain {
type: SecureNoteType;
constructor(obj?: SecureNoteData) {
super();
if (obj == null) {
return;
}
this.type = obj.type;
}
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<SecureNoteView> {
return Promise.resolve(new SecureNoteView(this));
}
toSecureNoteData(): SecureNoteData {
const n = new SecureNoteData();
n.type = this.type;
return n;
}
static fromJSON(obj: Jsonify<SecureNote>): SecureNote {
if (obj == null) {
return null;
}
return Object.assign(new SecureNote(), obj);
}
}

View File

@@ -1,87 +0,0 @@
import { CipherView } from "../view/cipher.view";
const CacheTTL = 3000;
export class SortedCiphersCache {
private readonly sortedCiphersByUrl: Map<string, Ciphers> = new Map<string, Ciphers>();
private readonly timeouts: Map<string, any> = new Map<string, any>();
constructor(private readonly comparator: (a: CipherView, b: CipherView) => number) {}
isCached(url: string) {
return this.sortedCiphersByUrl.has(url);
}
addCiphers(url: string, ciphers: CipherView[]) {
ciphers.sort(this.comparator);
this.sortedCiphersByUrl.set(url, new Ciphers(ciphers));
this.resetTimer(url);
}
getLastUsed(url: string) {
this.resetTimer(url);
return this.isCached(url) ? this.sortedCiphersByUrl.get(url).getLastUsed() : null;
}
getLastLaunched(url: string) {
return this.isCached(url) ? this.sortedCiphersByUrl.get(url).getLastLaunched() : null;
}
getNext(url: string) {
this.resetTimer(url);
return this.isCached(url) ? this.sortedCiphersByUrl.get(url).getNext() : null;
}
updateLastUsedIndex(url: string) {
if (this.isCached(url)) {
this.sortedCiphersByUrl.get(url).updateLastUsedIndex();
}
}
clear() {
this.sortedCiphersByUrl.clear();
this.timeouts.clear();
}
private resetTimer(url: string) {
clearTimeout(this.timeouts.get(url));
this.timeouts.set(
url,
setTimeout(() => {
this.sortedCiphersByUrl.delete(url);
this.timeouts.delete(url);
}, CacheTTL)
);
}
}
class Ciphers {
lastUsedIndex = -1;
constructor(private readonly ciphers: CipherView[]) {}
getLastUsed() {
this.lastUsedIndex = Math.max(this.lastUsedIndex, 0);
return this.ciphers[this.lastUsedIndex];
}
getLastLaunched() {
const usedCiphers = this.ciphers.filter((cipher) => cipher.localData?.lastLaunched);
const sortedCiphers = usedCiphers.sort(
(x, y) => y.localData.lastLaunched.valueOf() - x.localData.lastLaunched.valueOf()
);
return sortedCiphers[0];
}
getNextIndex() {
return (this.lastUsedIndex + 1) % this.ciphers.length;
}
getNext() {
return this.ciphers[this.getNextIndex()];
}
updateLastUsedIndex() {
this.lastUsedIndex = this.getNextIndex();
}
}