1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 07:43:35 +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

@@ -1,22 +0,0 @@
import { AttachmentResponse } from "../response/attachment.response";
export class AttachmentData {
id: string;
url: string;
fileName: string;
key: string;
size: string;
sizeName: string;
constructor(response?: AttachmentResponse) {
if (response == null) {
return;
}
this.id = response.id;
this.url = response.url;
this.fileName = response.fileName;
this.key = response.key;
this.size = response.size;
this.sizeName = response.sizeName;
}
}

View File

@@ -1,23 +0,0 @@
import { CardApi } from "../api/card.api";
export class CardData {
cardholderName: string;
brand: string;
number: string;
expMonth: string;
expYear: string;
code: string;
constructor(data?: CardApi) {
if (data == null) {
return;
}
this.cardholderName = data.cardholderName;
this.brand = data.brand;
this.number = data.number;
this.expMonth = data.expMonth;
this.expYear = data.expYear;
this.code = data.code;
}
}

View File

@@ -1,85 +0,0 @@
import { CipherRepromptType } from "../../enums/cipherRepromptType";
import { CipherType } from "../../enums/cipherType";
import { CipherResponse } from "../response/cipher.response";
import { AttachmentData } from "./attachment.data";
import { CardData } from "./card.data";
import { FieldData } from "./field.data";
import { IdentityData } from "./identity.data";
import { LoginData } from "./login.data";
import { PasswordHistoryData } from "./password-history.data";
import { SecureNoteData } from "./secure-note.data";
export class CipherData {
id: string;
organizationId: string;
folderId: string;
edit: boolean;
viewPassword: boolean;
organizationUseTotp: boolean;
favorite: boolean;
revisionDate: string;
type: CipherType;
name: string;
notes: string;
login?: LoginData;
secureNote?: SecureNoteData;
card?: CardData;
identity?: IdentityData;
fields?: FieldData[];
attachments?: AttachmentData[];
passwordHistory?: PasswordHistoryData[];
collectionIds?: string[];
creationDate: string;
deletedDate: string;
reprompt: CipherRepromptType;
constructor(response?: CipherResponse, collectionIds?: string[]) {
if (response == null) {
return;
}
this.id = response.id;
this.organizationId = response.organizationId;
this.folderId = response.folderId;
this.edit = response.edit;
this.viewPassword = response.viewPassword;
this.organizationUseTotp = response.organizationUseTotp;
this.favorite = response.favorite;
this.revisionDate = response.revisionDate;
this.type = response.type;
this.name = response.name;
this.notes = response.notes;
this.collectionIds = collectionIds != null ? collectionIds : response.collectionIds;
this.creationDate = response.creationDate;
this.deletedDate = response.deletedDate;
this.reprompt = response.reprompt;
switch (this.type) {
case CipherType.Login:
this.login = new LoginData(response.login);
break;
case CipherType.SecureNote:
this.secureNote = new SecureNoteData(response.secureNote);
break;
case CipherType.Card:
this.card = new CardData(response.card);
break;
case CipherType.Identity:
this.identity = new IdentityData(response.identity);
break;
default:
break;
}
if (response.fields != null) {
this.fields = response.fields.map((f) => new FieldData(f));
}
if (response.attachments != null) {
this.attachments = response.attachments.map((a) => new AttachmentData(a));
}
if (response.passwordHistory != null) {
this.passwordHistory = response.passwordHistory.map((ph) => new PasswordHistoryData(ph));
}
}
}

View File

@@ -1,20 +0,0 @@
import { FieldType } from "../../enums/fieldType";
import { LinkedIdType } from "../../enums/linkedIdType";
import { FieldApi } from "../api/field.api";
export class FieldData {
type: FieldType;
name: string;
value: string;
linkedId: LinkedIdType;
constructor(response?: FieldApi) {
if (response == null) {
return;
}
this.type = response.type;
this.name = response.name;
this.value = response.value;
this.linkedId = response.linkedId;
}
}

View File

@@ -1,13 +0,0 @@
import { FolderResponse } from "../response/folder.response";
export class FolderData {
id: string;
name: string;
revisionDate: string;
constructor(response: FolderResponse) {
this.name = response.name;
this.id = response.id;
this.revisionDate = response.revisionDate;
}
}

View File

@@ -1,47 +0,0 @@
import { IdentityApi } from "../api/identity.api";
export class IdentityData {
title: string;
firstName: string;
middleName: string;
lastName: string;
address1: string;
address2: string;
address3: string;
city: string;
state: string;
postalCode: string;
country: string;
company: string;
email: string;
phone: string;
ssn: string;
username: string;
passportNumber: string;
licenseNumber: string;
constructor(data?: IdentityApi) {
if (data == null) {
return;
}
this.title = data.title;
this.firstName = data.firstName;
this.middleName = data.middleName;
this.lastName = data.lastName;
this.address1 = data.address1;
this.address2 = data.address2;
this.address3 = data.address3;
this.city = data.city;
this.state = data.state;
this.postalCode = data.postalCode;
this.country = data.country;
this.company = data.company;
this.email = data.email;
this.phone = data.phone;
this.ssn = data.ssn;
this.username = data.username;
this.passportNumber = data.passportNumber;
this.licenseNumber = data.licenseNumber;
}
}

View File

@@ -1,4 +0,0 @@
export type LocalData = {
lastUsedDate?: number;
lastLaunched?: number;
};

View File

@@ -1,15 +0,0 @@
import { UriMatchType } from "../../enums/uriMatchType";
import { LoginUriApi } from "../api/login-uri.api";
export class LoginUriData {
uri: string;
match: UriMatchType = null;
constructor(data?: LoginUriApi) {
if (data == null) {
return;
}
this.uri = data.uri;
this.match = data.match;
}
}

View File

@@ -1,28 +0,0 @@
import { LoginApi } from "../api/login.api";
import { LoginUriData } from "./login-uri.data";
export class LoginData {
uris: LoginUriData[];
username: string;
password: string;
passwordRevisionDate: string;
totp: string;
autofillOnPageLoad: boolean;
constructor(data?: LoginApi) {
if (data == null) {
return;
}
this.username = data.username;
this.password = data.password;
this.passwordRevisionDate = data.passwordRevisionDate;
this.totp = data.totp;
this.autofillOnPageLoad = data.autofillOnPageLoad;
if (data.uris) {
this.uris = data.uris.map((u) => new LoginUriData(u));
}
}
}

View File

@@ -1,15 +0,0 @@
import { PasswordHistoryResponse } from "../response/password-history.response";
export class PasswordHistoryData {
password: string;
lastUsedDate: string;
constructor(response?: PasswordHistoryResponse) {
if (response == null) {
return;
}
this.password = response.password;
this.lastUsedDate = response.lastUsedDate;
}
}

View File

@@ -1,14 +0,0 @@
import { SecureNoteType } from "../../enums/secureNoteType";
import { SecureNoteApi } from "../api/secure-note.api";
export class SecureNoteData {
type: SecureNoteType;
constructor(data?: SecureNoteApi) {
if (data == null) {
return;
}
this.type = data.type;
}
}

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();
}
}

View File

@@ -1,6 +1,6 @@
import { Card as CardDomain } from "../domain/card";
import { Card as CardDomain } from "../../vault/models/domain/card";
import { CardView } from "../../vault/models/view/card.view";
import { EncString } from "../domain/enc-string";
import { CardView } from "../view/card.view";
export class CardExport {
static template(): CardExport {

View File

@@ -1,5 +1,5 @@
import { Cipher as CipherDomain } from "../domain/cipher";
import { CipherView } from "../view/cipher.view";
import { Cipher as CipherDomain } from "../../vault/models/domain/cipher";
import { CipherView } from "../../vault/models/view/cipher.view";
import { CipherExport } from "./cipher.export";

View File

@@ -1,8 +1,8 @@
import { CipherRepromptType } from "../../enums/cipherRepromptType";
import { CipherType } from "../../enums/cipherType";
import { Cipher as CipherDomain } from "../domain/cipher";
import { CipherRepromptType } from "../../vault/enums/cipher-reprompt-type";
import { CipherType } from "../../vault/enums/cipher-type";
import { Cipher as CipherDomain } from "../../vault/models/domain/cipher";
import { CipherView } from "../../vault/models/view/cipher.view";
import { EncString } from "../domain/enc-string";
import { CipherView } from "../view/cipher.view";
import { CardExport } from "./card.export";
import { FieldExport } from "./field.export";

View File

@@ -1,8 +1,8 @@
import { FieldType } from "../../enums/fieldType";
import { LinkedIdType } from "../../enums/linkedIdType";
import { Field as FieldDomain } from "../../vault/models/domain/field";
import { FieldView } from "../../vault/models/view/field.view";
import { EncString } from "../domain/enc-string";
import { Field as FieldDomain } from "../domain/field";
import { FieldView } from "../view/field.view";
export class FieldExport {
static template(): FieldExport {

View File

@@ -1,5 +1,5 @@
import { Folder as FolderDomain } from "../domain/folder";
import { FolderView } from "../view/folder.view";
import { Folder as FolderDomain } from "../../vault/models/domain/folder";
import { FolderView } from "../../vault/models/view/folder.view";
import { FolderExport } from "./folder.export";

View File

@@ -1,6 +1,6 @@
import { Folder as FolderDomain } from "../../vault/models/domain/folder";
import { FolderView } from "../../vault/models/view/folder.view";
import { EncString } from "../domain/enc-string";
import { Folder as FolderDomain } from "../domain/folder";
import { FolderView } from "../view/folder.view";
export class FolderExport {
static template(): FolderExport {

View File

@@ -1,6 +1,6 @@
import { Identity as IdentityDomain } from "../../vault/models/domain/identity";
import { IdentityView } from "../../vault/models/view/identity.view";
import { EncString } from "../domain/enc-string";
import { Identity as IdentityDomain } from "../domain/identity";
import { IdentityView } from "../view/identity.view";
export class IdentityExport {
static template(): IdentityExport {

View File

@@ -1,7 +1,7 @@
import { UriMatchType } from "../../enums/uriMatchType";
import { LoginUri as LoginUriDomain } from "../../vault/models/domain/login-uri";
import { LoginUriView } from "../../vault/models/view/login-uri.view";
import { EncString } from "../domain/enc-string";
import { LoginUri as LoginUriDomain } from "../domain/login-uri";
import { LoginUriView } from "../view/login-uri.view";
export class LoginUriExport {
static template(): LoginUriExport {

View File

@@ -1,6 +1,6 @@
import { Login as LoginDomain } from "../../vault/models/domain/login";
import { LoginView } from "../../vault/models/view/login.view";
import { EncString } from "../domain/enc-string";
import { Login as LoginDomain } from "../domain/login";
import { LoginView } from "../view/login.view";
import { LoginUriExport } from "./login-uri.export";

View File

@@ -1,6 +1,6 @@
import { SecureNoteType } from "../../enums/secureNoteType";
import { SecureNote as SecureNoteDomain } from "../domain/secure-note";
import { SecureNoteView } from "../view/secure-note.view";
import { SecureNote as SecureNoteDomain } from "../../vault/models/domain/secure-note";
import { SecureNoteView } from "../../vault/models/view/secure-note.view";
export class SecureNoteExport {
static template(): SecureNoteExport {

View File

@@ -1,6 +0,0 @@
export class AttachmentRequest {
fileName: string;
key: string;
fileSize: number;
adminRequest: boolean;
}

View File

@@ -1,9 +0,0 @@
export class CipherBulkDeleteRequest {
ids: string[];
organizationId: string;
constructor(ids: string[], organizationId?: string) {
this.ids = ids == null ? [] : ids;
this.organizationId = organizationId;
}
}

View File

@@ -1,9 +0,0 @@
export class CipherBulkMoveRequest {
ids: string[];
folderId: string;
constructor(ids: string[], folderId: string) {
this.ids = ids == null ? [] : ids;
this.folderId = folderId;
}
}

View File

@@ -1,7 +0,0 @@
export class CipherBulkRestoreRequest {
ids: string[];
constructor(ids: string[]) {
this.ids = ids == null ? [] : ids;
}
}

View File

@@ -1,18 +0,0 @@
import { Cipher } from "../domain/cipher";
import { CipherWithIdRequest } from "./cipher-with-id.request";
export class CipherBulkShareRequest {
ciphers: CipherWithIdRequest[];
collectionIds: string[];
constructor(ciphers: Cipher[], collectionIds: string[]) {
if (ciphers != null) {
this.ciphers = [];
ciphers.forEach((c) => {
this.ciphers.push(new CipherWithIdRequest(c));
});
}
this.collectionIds = collectionIds;
}
}

View File

@@ -1,7 +0,0 @@
export class CipherCollectionsRequest {
collectionIds: string[];
constructor(collectionIds: string[]) {
this.collectionIds = collectionIds == null ? [] : collectionIds;
}
}

View File

@@ -1,13 +0,0 @@
import { Cipher } from "../domain/cipher";
import { CipherRequest } from "./cipher.request";
export class CipherCreateRequest {
cipher: CipherRequest;
collectionIds: string[];
constructor(cipher: Cipher) {
this.cipher = new CipherRequest(cipher);
this.collectionIds = cipher.collectionIds;
}
}

View File

@@ -1,11 +0,0 @@
import { Cipher } from "../domain/cipher";
export class CipherPartialRequest {
folderId: string;
favorite: boolean;
constructor(cipher: Cipher) {
this.folderId = cipher.folderId;
this.favorite = cipher.favorite;
}
}

View File

@@ -1,13 +0,0 @@
import { Cipher } from "../domain/cipher";
import { CipherRequest } from "./cipher.request";
export class CipherShareRequest {
cipher: CipherRequest;
collectionIds: string[];
constructor(cipher: Cipher) {
this.cipher = new CipherRequest(cipher);
this.collectionIds = cipher.collectionIds;
}
}

View File

@@ -1,12 +0,0 @@
import { Cipher } from "../domain/cipher";
import { CipherRequest } from "./cipher.request";
export class CipherWithIdRequest extends CipherRequest {
id: string;
constructor(cipher: Cipher) {
super(cipher);
this.id = cipher.id;
}
}

View File

@@ -1,164 +0,0 @@
import { CipherRepromptType } from "../../enums/cipherRepromptType";
import { CipherType } from "../../enums/cipherType";
import { CardApi } from "../api/card.api";
import { FieldApi } from "../api/field.api";
import { IdentityApi } from "../api/identity.api";
import { LoginUriApi } from "../api/login-uri.api";
import { LoginApi } from "../api/login.api";
import { SecureNoteApi } from "../api/secure-note.api";
import { Cipher } from "../domain/cipher";
import { AttachmentRequest } from "./attachment.request";
import { PasswordHistoryRequest } from "./password-history.request";
export class CipherRequest {
type: CipherType;
folderId: string;
organizationId: string;
name: string;
notes: string;
favorite: boolean;
login: LoginApi;
secureNote: SecureNoteApi;
card: CardApi;
identity: IdentityApi;
fields: FieldApi[];
passwordHistory: PasswordHistoryRequest[];
// Deprecated, remove at some point and rename attachments2 to attachments
attachments: { [id: string]: string };
attachments2: { [id: string]: AttachmentRequest };
lastKnownRevisionDate: Date;
reprompt: CipherRepromptType;
constructor(cipher: Cipher) {
this.type = cipher.type;
this.folderId = cipher.folderId;
this.organizationId = cipher.organizationId;
this.name = cipher.name ? cipher.name.encryptedString : null;
this.notes = cipher.notes ? cipher.notes.encryptedString : null;
this.favorite = cipher.favorite;
this.lastKnownRevisionDate = cipher.revisionDate;
this.reprompt = cipher.reprompt;
switch (this.type) {
case CipherType.Login:
this.login = new LoginApi();
this.login.uris = null;
this.login.username = cipher.login.username ? cipher.login.username.encryptedString : null;
this.login.password = cipher.login.password ? cipher.login.password.encryptedString : null;
this.login.passwordRevisionDate =
cipher.login.passwordRevisionDate != null
? cipher.login.passwordRevisionDate.toISOString()
: null;
this.login.totp = cipher.login.totp ? cipher.login.totp.encryptedString : null;
this.login.autofillOnPageLoad = cipher.login.autofillOnPageLoad;
if (cipher.login.uris != null) {
this.login.uris = cipher.login.uris.map((u) => {
const uri = new LoginUriApi();
uri.uri = u.uri != null ? u.uri.encryptedString : null;
uri.match = u.match != null ? u.match : null;
return uri;
});
}
break;
case CipherType.SecureNote:
this.secureNote = new SecureNoteApi();
this.secureNote.type = cipher.secureNote.type;
break;
case CipherType.Card:
this.card = new CardApi();
this.card.cardholderName =
cipher.card.cardholderName != null ? cipher.card.cardholderName.encryptedString : null;
this.card.brand = cipher.card.brand != null ? cipher.card.brand.encryptedString : null;
this.card.number = cipher.card.number != null ? cipher.card.number.encryptedString : null;
this.card.expMonth =
cipher.card.expMonth != null ? cipher.card.expMonth.encryptedString : null;
this.card.expYear =
cipher.card.expYear != null ? cipher.card.expYear.encryptedString : null;
this.card.code = cipher.card.code != null ? cipher.card.code.encryptedString : null;
break;
case CipherType.Identity:
this.identity = new IdentityApi();
this.identity.title =
cipher.identity.title != null ? cipher.identity.title.encryptedString : null;
this.identity.firstName =
cipher.identity.firstName != null ? cipher.identity.firstName.encryptedString : null;
this.identity.middleName =
cipher.identity.middleName != null ? cipher.identity.middleName.encryptedString : null;
this.identity.lastName =
cipher.identity.lastName != null ? cipher.identity.lastName.encryptedString : null;
this.identity.address1 =
cipher.identity.address1 != null ? cipher.identity.address1.encryptedString : null;
this.identity.address2 =
cipher.identity.address2 != null ? cipher.identity.address2.encryptedString : null;
this.identity.address3 =
cipher.identity.address3 != null ? cipher.identity.address3.encryptedString : null;
this.identity.city =
cipher.identity.city != null ? cipher.identity.city.encryptedString : null;
this.identity.state =
cipher.identity.state != null ? cipher.identity.state.encryptedString : null;
this.identity.postalCode =
cipher.identity.postalCode != null ? cipher.identity.postalCode.encryptedString : null;
this.identity.country =
cipher.identity.country != null ? cipher.identity.country.encryptedString : null;
this.identity.company =
cipher.identity.company != null ? cipher.identity.company.encryptedString : null;
this.identity.email =
cipher.identity.email != null ? cipher.identity.email.encryptedString : null;
this.identity.phone =
cipher.identity.phone != null ? cipher.identity.phone.encryptedString : null;
this.identity.ssn =
cipher.identity.ssn != null ? cipher.identity.ssn.encryptedString : null;
this.identity.username =
cipher.identity.username != null ? cipher.identity.username.encryptedString : null;
this.identity.passportNumber =
cipher.identity.passportNumber != null
? cipher.identity.passportNumber.encryptedString
: null;
this.identity.licenseNumber =
cipher.identity.licenseNumber != null
? cipher.identity.licenseNumber.encryptedString
: null;
break;
default:
break;
}
if (cipher.fields != null) {
this.fields = cipher.fields.map((f) => {
const field = new FieldApi();
field.type = f.type;
field.name = f.name ? f.name.encryptedString : null;
field.value = f.value ? f.value.encryptedString : null;
field.linkedId = f.linkedId;
return field;
});
}
if (cipher.passwordHistory != null) {
this.passwordHistory = [];
cipher.passwordHistory.forEach((ph) => {
this.passwordHistory.push({
lastUsedDate: ph.lastUsedDate,
password: ph.password ? ph.password.encryptedString : null,
});
});
}
if (cipher.attachments != null) {
this.attachments = {};
this.attachments2 = {};
cipher.attachments.forEach((attachment) => {
const fileName = attachment.fileName ? attachment.fileName.encryptedString : null;
this.attachments[attachment.id] = fileName;
const attachmentRequest = new AttachmentRequest();
attachmentRequest.fileName = fileName;
if (attachment.key != null) {
attachmentRequest.key = attachment.key.encryptedString;
}
this.attachments2[attachment.id] = attachmentRequest;
});
}
}
}

View File

@@ -1,12 +0,0 @@
import { Folder } from "../domain/folder";
import { FolderRequest } from "./folder.request";
export class FolderWithIdRequest extends FolderRequest {
id: string;
constructor(folder: Folder) {
super(folder);
this.id = folder.id;
}
}

View File

@@ -1,9 +0,0 @@
import { Folder } from "../domain/folder";
export class FolderRequest {
name: string;
constructor(folder: Folder) {
this.name = folder.name ? folder.name.encryptedString : null;
}
}

View File

@@ -1,5 +1,6 @@
import { CipherRequest } from "./cipher.request";
import { FolderRequest } from "./folder.request";
import { CipherRequest } from "../../vault/models/request/cipher.request";
import { FolderRequest } from "../../vault/models/request/folder.request";
import { KvpRequest } from "./kvp.request";
export class ImportCiphersRequest {

View File

@@ -1,4 +1,5 @@
import { CipherRequest } from "./cipher.request";
import { CipherRequest } from "../../vault/models/request/cipher.request";
import { CollectionRequest } from "./collection.request";
import { KvpRequest } from "./kvp.request";

View File

@@ -1,4 +0,0 @@
export class PasswordHistoryRequest {
password: string;
lastUsedDate: Date;
}

View File

@@ -1,5 +1,6 @@
import { CipherWithIdRequest } from "./cipher-with-id.request";
import { FolderWithIdRequest } from "./folder-with-id.request";
import { CipherWithIdRequest } from "../../vault/models/request/cipher-with-id.request";
import { FolderWithIdRequest } from "../../vault/models/request/folder-with-id.request";
import { SendWithIdRequest } from "./send-with-id.request";
export class UpdateKeyRequest {

View File

@@ -1,23 +0,0 @@
import { FileUploadType } from "../../enums/fileUploadType";
import { BaseResponse } from "./base.response";
import { CipherResponse } from "./cipher.response";
export class AttachmentUploadDataResponse extends BaseResponse {
attachmentId: string;
fileUploadType: FileUploadType;
cipherResponse: CipherResponse;
cipherMiniResponse: CipherResponse;
url: string = null;
constructor(response: any) {
super(response);
this.attachmentId = this.getResponseProperty("AttachmentId");
this.fileUploadType = this.getResponseProperty("FileUploadType");
const cipherResponse = this.getResponseProperty("CipherResponse");
const cipherMiniResponse = this.getResponseProperty("CipherMiniResponse");
this.cipherResponse = cipherResponse == null ? null : new CipherResponse(cipherResponse);
this.cipherMiniResponse =
cipherMiniResponse == null ? null : new CipherResponse(cipherMiniResponse);
this.url = this.getResponseProperty("Url");
}
}

View File

@@ -1,20 +0,0 @@
import { BaseResponse } from "./base.response";
export class AttachmentResponse extends BaseResponse {
id: string;
url: string;
fileName: string;
key: string;
size: string;
sizeName: string;
constructor(response: any) {
super(response);
this.id = this.getResponseProperty("Id");
this.url = this.getResponseProperty("Url");
this.fileName = this.getResponseProperty("FileName");
this.key = this.getResponseProperty("Key");
this.size = this.getResponseProperty("Size");
this.sizeName = this.getResponseProperty("SizeName");
}
}

View File

@@ -1,94 +0,0 @@
import { CipherRepromptType } from "../../enums/cipherRepromptType";
import { CardApi } from "../api/card.api";
import { FieldApi } from "../api/field.api";
import { IdentityApi } from "../api/identity.api";
import { LoginApi } from "../api/login.api";
import { SecureNoteApi } from "../api/secure-note.api";
import { AttachmentResponse } from "./attachment.response";
import { BaseResponse } from "./base.response";
import { PasswordHistoryResponse } from "./password-history.response";
export class CipherResponse extends BaseResponse {
id: string;
organizationId: string;
folderId: string;
type: number;
name: string;
notes: string;
fields: FieldApi[];
login: LoginApi;
card: CardApi;
identity: IdentityApi;
secureNote: SecureNoteApi;
favorite: boolean;
edit: boolean;
viewPassword: boolean;
organizationUseTotp: boolean;
revisionDate: string;
attachments: AttachmentResponse[];
passwordHistory: PasswordHistoryResponse[];
collectionIds: string[];
creationDate: string;
deletedDate: string;
reprompt: CipherRepromptType;
constructor(response: any) {
super(response);
this.id = this.getResponseProperty("Id");
this.organizationId = this.getResponseProperty("OrganizationId");
this.folderId = this.getResponseProperty("FolderId") || null;
this.type = this.getResponseProperty("Type");
this.name = this.getResponseProperty("Name");
this.notes = this.getResponseProperty("Notes");
this.favorite = this.getResponseProperty("Favorite") || false;
this.edit = !!this.getResponseProperty("Edit");
if (this.getResponseProperty("ViewPassword") == null) {
this.viewPassword = true;
} else {
this.viewPassword = this.getResponseProperty("ViewPassword");
}
this.organizationUseTotp = this.getResponseProperty("OrganizationUseTotp");
this.revisionDate = this.getResponseProperty("RevisionDate");
this.collectionIds = this.getResponseProperty("CollectionIds");
this.creationDate = this.getResponseProperty("CreationDate");
this.deletedDate = this.getResponseProperty("DeletedDate");
const login = this.getResponseProperty("Login");
if (login != null) {
this.login = new LoginApi(login);
}
const card = this.getResponseProperty("Card");
if (card != null) {
this.card = new CardApi(card);
}
const identity = this.getResponseProperty("Identity");
if (identity != null) {
this.identity = new IdentityApi(identity);
}
const secureNote = this.getResponseProperty("SecureNote");
if (secureNote != null) {
this.secureNote = new SecureNoteApi(secureNote);
}
const fields = this.getResponseProperty("Fields");
if (fields != null) {
this.fields = fields.map((f: any) => new FieldApi(f));
}
const attachments = this.getResponseProperty("Attachments");
if (attachments != null) {
this.attachments = attachments.map((a: any) => new AttachmentResponse(a));
}
const passwordHistory = this.getResponseProperty("PasswordHistory");
if (passwordHistory != null) {
this.passwordHistory = passwordHistory.map((h: any) => new PasswordHistoryResponse(h));
}
this.reprompt = this.getResponseProperty("Reprompt") || CipherRepromptType.None;
}
}

View File

@@ -1,9 +1,9 @@
import { EmergencyAccessStatusType } from "../../enums/emergencyAccessStatusType";
import { EmergencyAccessType } from "../../enums/emergencyAccessType";
import { KdfType } from "../../enums/kdfType";
import { CipherResponse } from "../../vault/models/response/cipher.response";
import { BaseResponse } from "./base.response";
import { CipherResponse } from "./cipher.response";
export class EmergencyAccessGranteeDetailsResponse extends BaseResponse {
id: string;

View File

@@ -1,14 +0,0 @@
import { BaseResponse } from "./base.response";
export class FolderResponse extends BaseResponse {
id: string;
name: string;
revisionDate: string;
constructor(response: any) {
super(response);
this.id = this.getResponseProperty("Id");
this.name = this.getResponseProperty("Name");
this.revisionDate = this.getResponseProperty("RevisionDate");
}
}

View File

@@ -1,5 +1,6 @@
import { CipherResponse } from "../../vault/models/response/cipher.response";
import { BaseResponse } from "./base.response";
import { CipherResponse } from "./cipher.response";
import { CollectionResponse } from "./collection.response";
export class OrganizationExportResponse extends BaseResponse {

View File

@@ -1,12 +0,0 @@
import { BaseResponse } from "./base.response";
export class PasswordHistoryResponse extends BaseResponse {
password: string;
lastUsedDate: string;
constructor(response: any) {
super(response);
this.password = this.getResponseProperty("Password");
this.lastUsedDate = this.getResponseProperty("LastUsedDate");
}
}

View File

@@ -1,57 +0,0 @@
import { BaseResponse } from "./base.response";
import { CipherResponse } from "./cipher.response";
import { CollectionDetailsResponse } from "./collection.response";
import { DomainsResponse } from "./domains.response";
import { FolderResponse } from "./folder.response";
import { PolicyResponse } from "./policy.response";
import { ProfileResponse } from "./profile.response";
import { SendResponse } from "./send.response";
export class SyncResponse extends BaseResponse {
profile?: ProfileResponse;
folders: FolderResponse[] = [];
collections: CollectionDetailsResponse[] = [];
ciphers: CipherResponse[] = [];
domains?: DomainsResponse;
policies?: PolicyResponse[] = [];
sends: SendResponse[] = [];
constructor(response: any) {
super(response);
const profile = this.getResponseProperty("Profile");
if (profile != null) {
this.profile = new ProfileResponse(profile);
}
const folders = this.getResponseProperty("Folders");
if (folders != null) {
this.folders = folders.map((f: any) => new FolderResponse(f));
}
const collections = this.getResponseProperty("Collections");
if (collections != null) {
this.collections = collections.map((c: any) => new CollectionDetailsResponse(c));
}
const ciphers = this.getResponseProperty("Ciphers");
if (ciphers != null) {
this.ciphers = ciphers.map((c: any) => new CipherResponse(c));
}
const domains = this.getResponseProperty("Domains");
if (domains != null) {
this.domains = new DomainsResponse(domains);
}
const policies = this.getResponseProperty("Policies");
if (policies != null) {
this.policies = policies.map((p: any) => new PolicyResponse(p));
}
const sends = this.getResponseProperty("Sends");
if (sends != null) {
this.sends = sends.map((s: any) => new SendResponse(s));
}
}
}

View File

@@ -1,42 +0,0 @@
import { Jsonify } from "type-fest";
import { Attachment } from "../domain/attachment";
import { SymmetricCryptoKey } from "../domain/symmetric-crypto-key";
import { View } from "./view";
export class AttachmentView implements View {
id: string = null;
url: string = null;
size: string = null;
sizeName: string = null;
fileName: string = null;
key: SymmetricCryptoKey = null;
constructor(a?: Attachment) {
if (!a) {
return;
}
this.id = a.id;
this.url = a.url;
this.size = a.size;
this.sizeName = a.sizeName;
}
get fileSize(): number {
try {
if (this.size != null) {
return parseInt(this.size, null);
}
} catch {
// Invalid file size.
}
return 0;
}
static fromJSON(obj: Partial<Jsonify<AttachmentView>>): AttachmentView {
const key = obj.key == null ? null : SymmetricCryptoKey.fromJSON(obj.key);
return Object.assign(new AttachmentView(), obj, { key: key });
}
}

View File

@@ -1,84 +0,0 @@
import { Jsonify } from "type-fest";
import { CardLinkedId as LinkedId } from "../../enums/linkedIdType";
import { linkedFieldOption } from "../../misc/linkedFieldOption.decorator";
import { ItemView } from "./item.view";
export class CardView extends ItemView {
@linkedFieldOption(LinkedId.CardholderName)
cardholderName: string = null;
@linkedFieldOption(LinkedId.ExpMonth, "expirationMonth")
expMonth: string = null;
@linkedFieldOption(LinkedId.ExpYear, "expirationYear")
expYear: string = null;
@linkedFieldOption(LinkedId.Code, "securityCode")
code: string = null;
private _brand: string = null;
private _number: string = null;
private _subTitle: string = null;
get maskedCode(): string {
return this.code != null ? "•".repeat(this.code.length) : null;
}
get maskedNumber(): string {
return this.number != null ? "•".repeat(this.number.length) : null;
}
@linkedFieldOption(LinkedId.Brand)
get brand(): string {
return this._brand;
}
set brand(value: string) {
this._brand = value;
this._subTitle = null;
}
@linkedFieldOption(LinkedId.Number)
get number(): string {
return this._number;
}
set number(value: string) {
this._number = value;
this._subTitle = null;
}
get subTitle(): string {
if (this._subTitle == null) {
this._subTitle = this.brand;
if (this.number != null && this.number.length >= 4) {
if (this._subTitle != null && this._subTitle !== "") {
this._subTitle += ", ";
} else {
this._subTitle = "";
}
// Show last 5 on amex, last 4 for all others
const count =
this.number.length >= 5 && this.number.match(new RegExp("^3[47]")) != null ? 5 : 4;
this._subTitle += "*" + this.number.substr(this.number.length - count);
}
}
return this._subTitle;
}
get expiration(): string {
if (!this.expMonth && !this.expYear) {
return null;
}
let exp = this.expMonth != null ? ("0" + this.expMonth).slice(-2) : "__";
exp += " / " + (this.expYear != null ? this.formatYear(this.expYear) : "____");
return exp;
}
private formatYear(year: string): string {
return year.length === 2 ? "20" + year : year;
}
static fromJSON(obj: Partial<Jsonify<CardView>>): CardView {
return Object.assign(new CardView(), obj);
}
}

View File

@@ -1,179 +0,0 @@
import { Jsonify } from "type-fest";
import { CipherRepromptType } from "../../enums/cipherRepromptType";
import { CipherType } from "../../enums/cipherType";
import { LinkedIdType } from "../../enums/linkedIdType";
import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface";
import { InitializerKey } from "../../services/cryptography/initializer-key";
import { LocalData } from "../data/local.data";
import { Cipher } from "../domain/cipher";
import { AttachmentView } from "./attachment.view";
import { CardView } from "./card.view";
import { FieldView } from "./field.view";
import { IdentityView } from "./identity.view";
import { LoginView } from "./login.view";
import { PasswordHistoryView } from "./password-history.view";
import { SecureNoteView } from "./secure-note.view";
import { View } from "./view";
export class CipherView implements View, InitializerMetadata {
readonly initializerKey = InitializerKey.CipherView;
id: string = null;
organizationId: string = null;
folderId: string = null;
name: string = null;
notes: string = null;
type: CipherType = null;
favorite = false;
organizationUseTotp = false;
edit = false;
viewPassword = true;
localData: LocalData;
login = new LoginView();
identity = new IdentityView();
card = new CardView();
secureNote = new SecureNoteView();
attachments: AttachmentView[] = null;
fields: FieldView[] = null;
passwordHistory: PasswordHistoryView[] = null;
collectionIds: string[] = null;
revisionDate: Date = null;
creationDate: Date = null;
deletedDate: Date = null;
reprompt: CipherRepromptType = CipherRepromptType.None;
constructor(c?: Cipher) {
if (!c) {
return;
}
this.id = c.id;
this.organizationId = c.organizationId;
this.folderId = c.folderId;
this.favorite = c.favorite;
this.organizationUseTotp = c.organizationUseTotp;
this.edit = c.edit;
this.viewPassword = c.viewPassword;
this.type = c.type;
this.localData = c.localData;
this.collectionIds = c.collectionIds;
this.revisionDate = c.revisionDate;
this.creationDate = c.creationDate;
this.deletedDate = c.deletedDate;
// Old locally stored ciphers might have reprompt == null. If so set it to None.
this.reprompt = c.reprompt ?? CipherRepromptType.None;
}
private get item() {
switch (this.type) {
case CipherType.Login:
return this.login;
case CipherType.SecureNote:
return this.secureNote;
case CipherType.Card:
return this.card;
case CipherType.Identity:
return this.identity;
default:
break;
}
return null;
}
get subTitle(): string {
return this.item.subTitle;
}
get hasPasswordHistory(): boolean {
return this.passwordHistory && this.passwordHistory.length > 0;
}
get hasAttachments(): boolean {
return this.attachments && this.attachments.length > 0;
}
get hasOldAttachments(): boolean {
if (this.hasAttachments) {
for (let i = 0; i < this.attachments.length; i++) {
if (this.attachments[i].key == null) {
return true;
}
}
}
return false;
}
get hasFields(): boolean {
return this.fields && this.fields.length > 0;
}
get passwordRevisionDisplayDate(): Date {
if (this.type !== CipherType.Login || this.login == null) {
return null;
} else if (this.login.password == null || this.login.password === "") {
return null;
}
return this.login.passwordRevisionDate;
}
get isDeleted(): boolean {
return this.deletedDate != null;
}
get linkedFieldOptions() {
return this.item.linkedFieldOptions;
}
linkedFieldValue(id: LinkedIdType) {
const linkedFieldOption = this.linkedFieldOptions?.get(id);
if (linkedFieldOption == null) {
return null;
}
const item = this.item;
return this.item[linkedFieldOption.propertyKey as keyof typeof item];
}
linkedFieldI18nKey(id: LinkedIdType): string {
return this.linkedFieldOptions.get(id)?.i18nKey;
}
static fromJSON(obj: Partial<Jsonify<CipherView>>): CipherView {
const view = new CipherView();
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) => AttachmentView.fromJSON(a));
const fields = obj.fields?.map((f: any) => FieldView.fromJSON(f));
const passwordHistory = obj.passwordHistory?.map((ph: any) => PasswordHistoryView.fromJSON(ph));
Object.assign(view, obj, {
revisionDate: revisionDate,
deletedDate: deletedDate,
attachments: attachments,
fields: fields,
passwordHistory: passwordHistory,
});
switch (obj.type) {
case CipherType.Card:
view.card = CardView.fromJSON(obj.card);
break;
case CipherType.Identity:
view.identity = IdentityView.fromJSON(obj.identity);
break;
case CipherType.Login:
view.login = LoginView.fromJSON(obj.login);
break;
case CipherType.SecureNote:
view.secureNote = SecureNoteView.fromJSON(obj.secureNote);
break;
default:
break;
}
return view;
}
}

View File

@@ -1,34 +0,0 @@
import { Jsonify } from "type-fest";
import { FieldType } from "../../enums/fieldType";
import { LinkedIdType } from "../../enums/linkedIdType";
import { Field } from "../domain/field";
import { View } from "./view";
export class FieldView implements View {
name: string = null;
value: string = null;
type: FieldType = null;
newField = false; // Marks if the field is new and hasn't been saved
showValue = false;
showCount = false;
linkedId: LinkedIdType = null;
constructor(f?: Field) {
if (!f) {
return;
}
this.type = f.type;
this.linkedId = f.linkedId;
}
get maskedValue(): string {
return this.value != null ? "••••••••" : null;
}
static fromJSON(obj: Partial<Jsonify<FieldView>>): FieldView {
return Object.assign(new FieldView(), obj);
}
}

View File

@@ -1,26 +0,0 @@
import { Jsonify } from "type-fest";
import { Folder } from "../domain/folder";
import { ITreeNodeObject } from "../domain/tree-node";
import { View } from "./view";
export class FolderView implements View, ITreeNodeObject {
id: string = null;
name: string = null;
revisionDate: Date = null;
constructor(f?: Folder) {
if (!f) {
return;
}
this.id = f.id;
this.revisionDate = f.revisionDate;
}
static fromJSON(obj: Jsonify<FolderView>) {
const revisionDate = obj.revisionDate == null ? null : new Date(obj.revisionDate);
return Object.assign(new FolderView(), obj, { revisionDate });
}
}

View File

@@ -1,148 +0,0 @@
import { Jsonify } from "type-fest";
import { IdentityLinkedId as LinkedId } from "../../enums/linkedIdType";
import { linkedFieldOption } from "../../misc/linkedFieldOption.decorator";
import { Utils } from "../../misc/utils";
import { ItemView } from "./item.view";
export class IdentityView extends ItemView {
@linkedFieldOption(LinkedId.Title)
title: string = null;
@linkedFieldOption(LinkedId.MiddleName)
middleName: string = null;
@linkedFieldOption(LinkedId.Address1)
address1: string = null;
@linkedFieldOption(LinkedId.Address2)
address2: string = null;
@linkedFieldOption(LinkedId.Address3)
address3: string = null;
@linkedFieldOption(LinkedId.City, "cityTown")
city: string = null;
@linkedFieldOption(LinkedId.State, "stateProvince")
state: string = null;
@linkedFieldOption(LinkedId.PostalCode, "zipPostalCode")
postalCode: string = null;
@linkedFieldOption(LinkedId.Country)
country: string = null;
@linkedFieldOption(LinkedId.Company)
company: string = null;
@linkedFieldOption(LinkedId.Email)
email: string = null;
@linkedFieldOption(LinkedId.Phone)
phone: string = null;
@linkedFieldOption(LinkedId.Ssn)
ssn: string = null;
@linkedFieldOption(LinkedId.Username)
username: string = null;
@linkedFieldOption(LinkedId.PassportNumber)
passportNumber: string = null;
@linkedFieldOption(LinkedId.LicenseNumber)
licenseNumber: string = null;
private _firstName: string = null;
private _lastName: string = null;
private _subTitle: string = null;
constructor() {
super();
}
@linkedFieldOption(LinkedId.FirstName)
get firstName(): string {
return this._firstName;
}
set firstName(value: string) {
this._firstName = value;
this._subTitle = null;
}
@linkedFieldOption(LinkedId.LastName)
get lastName(): string {
return this._lastName;
}
set lastName(value: string) {
this._lastName = value;
this._subTitle = null;
}
get subTitle(): string {
if (this._subTitle == null && (this.firstName != null || this.lastName != null)) {
this._subTitle = "";
if (this.firstName != null) {
this._subTitle = this.firstName;
}
if (this.lastName != null) {
if (this._subTitle !== "") {
this._subTitle += " ";
}
this._subTitle += this.lastName;
}
}
return this._subTitle;
}
@linkedFieldOption(LinkedId.FullName)
get fullName(): string {
if (
this.title != null ||
this.firstName != null ||
this.middleName != null ||
this.lastName != null
) {
let name = "";
if (this.title != null) {
name += this.title + " ";
}
if (this.firstName != null) {
name += this.firstName + " ";
}
if (this.middleName != null) {
name += this.middleName + " ";
}
if (this.lastName != null) {
name += this.lastName;
}
return name.trim();
}
return null;
}
get fullAddress(): string {
let address = this.address1;
if (!Utils.isNullOrWhitespace(this.address2)) {
if (!Utils.isNullOrWhitespace(address)) {
address += ", ";
}
address += this.address2;
}
if (!Utils.isNullOrWhitespace(this.address3)) {
if (!Utils.isNullOrWhitespace(address)) {
address += ", ";
}
address += this.address3;
}
return address;
}
get fullAddressPart2(): string {
if (this.city == null && this.state == null && this.postalCode == null) {
return null;
}
const city = this.city || "-";
const state = this.state;
const postalCode = this.postalCode || "-";
let addressPart2 = city;
if (!Utils.isNullOrWhitespace(state)) {
addressPart2 += ", " + state;
}
addressPart2 += ", " + postalCode;
return addressPart2;
}
static fromJSON(obj: Partial<Jsonify<IdentityView>>): IdentityView {
return Object.assign(new IdentityView(), obj);
}
}

View File

@@ -1,8 +0,0 @@
import { LinkedMetadata } from "../../misc/linkedFieldOption.decorator";
import { View } from "./view";
export abstract class ItemView implements View {
linkedFieldOptions: Map<number, LinkedMetadata>;
abstract get subTitle(): string;
}

View File

@@ -1,133 +0,0 @@
import { Jsonify } from "type-fest";
import { UriMatchType } from "../../enums/uriMatchType";
import { Utils } from "../../misc/utils";
import { LoginUri } from "../domain/login-uri";
import { View } from "./view";
const CanLaunchWhitelist = [
"https://",
"http://",
"ssh://",
"ftp://",
"sftp://",
"irc://",
"vnc://",
// https://docs.microsoft.com/en-us/windows-server/remote/remote-desktop-services/clients/remote-desktop-uri
"rdp://", // Legacy RDP URI scheme
"ms-rd:", // Preferred RDP URI scheme
"chrome://",
"iosapp://",
"androidapp://",
];
export class LoginUriView implements View {
match: UriMatchType = null;
private _uri: string = null;
private _domain: string = null;
private _hostname: string = null;
private _host: string = null;
private _canLaunch: boolean = null;
constructor(u?: LoginUri) {
if (!u) {
return;
}
this.match = u.match;
}
get uri(): string {
return this._uri;
}
set uri(value: string) {
this._uri = value;
this._domain = null;
this._canLaunch = null;
}
get domain(): string {
if (this._domain == null && this.uri != null) {
this._domain = Utils.getDomain(this.uri);
if (this._domain === "") {
this._domain = null;
}
}
return this._domain;
}
get hostname(): string {
if (this.match === UriMatchType.RegularExpression) {
return null;
}
if (this._hostname == null && this.uri != null) {
this._hostname = Utils.getHostname(this.uri);
if (this._hostname === "") {
this._hostname = null;
}
}
return this._hostname;
}
get host(): string {
if (this.match === UriMatchType.RegularExpression) {
return null;
}
if (this._host == null && this.uri != null) {
this._host = Utils.getHost(this.uri);
if (this._host === "") {
this._host = null;
}
}
return this._host;
}
get hostnameOrUri(): string {
return this.hostname != null ? this.hostname : this.uri;
}
get hostOrUri(): string {
return this.host != null ? this.host : this.uri;
}
get isWebsite(): boolean {
return (
this.uri != null &&
(this.uri.indexOf("http://") === 0 ||
this.uri.indexOf("https://") === 0 ||
(this.uri.indexOf("://") < 0 && !Utils.isNullOrWhitespace(Utils.getDomain(this.uri))))
);
}
get canLaunch(): boolean {
if (this._canLaunch != null) {
return this._canLaunch;
}
if (this.uri != null && this.match !== UriMatchType.RegularExpression) {
const uri = this.launchUri;
for (let i = 0; i < CanLaunchWhitelist.length; i++) {
if (uri.indexOf(CanLaunchWhitelist[i]) === 0) {
this._canLaunch = true;
return this._canLaunch;
}
}
}
this._canLaunch = false;
return this._canLaunch;
}
get launchUri(): string {
return this.uri.indexOf("://") < 0 && !Utils.isNullOrWhitespace(Utils.getDomain(this.uri))
? "http://" + this.uri
: this.uri;
}
static fromJSON(obj: Partial<Jsonify<LoginUriView>>): LoginUriView {
return Object.assign(new LoginUriView(), obj);
}
}

View File

@@ -1,76 +0,0 @@
import { Jsonify } from "type-fest";
import { LoginLinkedId as LinkedId } from "../../enums/linkedIdType";
import { linkedFieldOption } from "../../misc/linkedFieldOption.decorator";
import { Utils } from "../../misc/utils";
import { Login } from "../domain/login";
import { ItemView } from "./item.view";
import { LoginUriView } from "./login-uri.view";
export class LoginView extends ItemView {
@linkedFieldOption(LinkedId.Username)
username: string = null;
@linkedFieldOption(LinkedId.Password)
password: string = null;
passwordRevisionDate?: Date = null;
totp: string = null;
uris: LoginUriView[] = null;
autofillOnPageLoad: boolean = null;
constructor(l?: Login) {
super();
if (!l) {
return;
}
this.passwordRevisionDate = l.passwordRevisionDate;
this.autofillOnPageLoad = l.autofillOnPageLoad;
}
get uri(): string {
return this.hasUris ? this.uris[0].uri : null;
}
get maskedPassword(): string {
return this.password != null ? "••••••••" : null;
}
get subTitle(): string {
return this.username;
}
get canLaunch(): boolean {
return this.hasUris && this.uris.some((u) => u.canLaunch);
}
get hasTotp(): boolean {
return !Utils.isNullOrWhitespace(this.totp);
}
get launchUri(): string {
if (this.hasUris) {
const uri = this.uris.find((u) => u.canLaunch);
if (uri != null) {
return uri.launchUri;
}
}
return null;
}
get hasUris(): boolean {
return this.uris != null && this.uris.length > 0;
}
static fromJSON(obj: Partial<Jsonify<LoginView>>): LoginView {
const passwordRevisionDate =
obj.passwordRevisionDate == null ? null : new Date(obj.passwordRevisionDate);
const uris = obj.uris?.map((uri: any) => LoginUriView.fromJSON(uri));
return Object.assign(new LoginView(), obj, {
passwordRevisionDate: passwordRevisionDate,
uris: uris,
});
}
}

View File

@@ -1,26 +0,0 @@
import { Jsonify } from "type-fest";
import { Password } from "../domain/password";
import { View } from "./view";
export class PasswordHistoryView implements View {
password: string = null;
lastUsedDate: Date = null;
constructor(ph?: Password) {
if (!ph) {
return;
}
this.lastUsedDate = ph.lastUsedDate;
}
static fromJSON(obj: Partial<Jsonify<PasswordHistoryView>>): PasswordHistoryView {
const lastUsedDate = obj.lastUsedDate == null ? null : new Date(obj.lastUsedDate);
return Object.assign(new PasswordHistoryView(), obj, {
lastUsedDate: lastUsedDate,
});
}
}

View File

@@ -1,27 +0,0 @@
import { Jsonify } from "type-fest";
import { SecureNoteType } from "../../enums/secureNoteType";
import { SecureNote } from "../domain/secure-note";
import { ItemView } from "./item.view";
export class SecureNoteView extends ItemView {
type: SecureNoteType = null;
constructor(n?: SecureNote) {
super();
if (!n) {
return;
}
this.type = n.type;
}
get subTitle(): string {
return null;
}
static fromJSON(obj: Partial<Jsonify<SecureNoteView>>): SecureNoteView {
return Object.assign(new SecureNoteView(), obj);
}
}