mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 16:53:34 +00:00
Move to libs
This commit is contained in:
35
libs/common/src/models/view/attachmentView.ts
Normal file
35
libs/common/src/models/view/attachmentView.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Attachment } from "../domain/attachment";
|
||||
import { SymmetricCryptoKey } from "../domain/symmetricCryptoKey";
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
82
libs/common/src/models/view/cardView.ts
Normal file
82
libs/common/src/models/view/cardView.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { CardLinkedId as LinkedId } from "../../enums/linkedIdType";
|
||||
import { linkedFieldOption } from "../../misc/linkedFieldOption.decorator";
|
||||
|
||||
import { ItemView } from "./itemView";
|
||||
|
||||
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;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
134
libs/common/src/models/view/cipherView.ts
Normal file
134
libs/common/src/models/view/cipherView.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import { CipherRepromptType } from "../../enums/cipherRepromptType";
|
||||
import { CipherType } from "../../enums/cipherType";
|
||||
import { LinkedIdType } from "../../enums/linkedIdType";
|
||||
import { Cipher } from "../domain/cipher";
|
||||
|
||||
import { AttachmentView } from "./attachmentView";
|
||||
import { CardView } from "./cardView";
|
||||
import { FieldView } from "./fieldView";
|
||||
import { IdentityView } from "./identityView";
|
||||
import { LoginView } from "./loginView";
|
||||
import { PasswordHistoryView } from "./passwordHistoryView";
|
||||
import { SecureNoteView } from "./secureNoteView";
|
||||
import { View } from "./view";
|
||||
|
||||
export class CipherView implements View {
|
||||
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: any;
|
||||
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;
|
||||
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.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;
|
||||
}
|
||||
}
|
||||
28
libs/common/src/models/view/collectionView.ts
Normal file
28
libs/common/src/models/view/collectionView.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Collection } from "../domain/collection";
|
||||
import { ITreeNodeObject } from "../domain/treeNode";
|
||||
import { CollectionGroupDetailsResponse } from "../response/collectionResponse";
|
||||
|
||||
import { View } from "./view";
|
||||
|
||||
export class CollectionView implements View, ITreeNodeObject {
|
||||
id: string = null;
|
||||
organizationId: string = null;
|
||||
name: string = null;
|
||||
externalId: string = null;
|
||||
readOnly: boolean = null;
|
||||
hidePasswords: boolean = null;
|
||||
|
||||
constructor(c?: Collection | CollectionGroupDetailsResponse) {
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.id = c.id;
|
||||
this.organizationId = c.organizationId;
|
||||
this.externalId = c.externalId;
|
||||
if (c instanceof Collection) {
|
||||
this.readOnly = c.readOnly;
|
||||
this.hidePasswords = c.hidePasswords;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
libs/common/src/models/view/eventView.ts
Normal file
29
libs/common/src/models/view/eventView.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { EventType } from "../../enums/eventType";
|
||||
|
||||
export class EventView {
|
||||
message: string;
|
||||
humanReadableMessage: string;
|
||||
appIcon: string;
|
||||
appName: string;
|
||||
userId: string;
|
||||
userName: string;
|
||||
userEmail: string;
|
||||
date: string;
|
||||
ip: string;
|
||||
type: EventType;
|
||||
installationId: string;
|
||||
|
||||
constructor(data: Required<EventView>) {
|
||||
this.message = data.message;
|
||||
this.humanReadableMessage = data.humanReadableMessage;
|
||||
this.appIcon = data.appIcon;
|
||||
this.appName = data.appName;
|
||||
this.userId = data.userId;
|
||||
this.userName = data.userName;
|
||||
this.userEmail = data.userEmail;
|
||||
this.date = data.date;
|
||||
this.ip = data.ip;
|
||||
this.type = data.type;
|
||||
this.installationId = data.installationId;
|
||||
}
|
||||
}
|
||||
28
libs/common/src/models/view/fieldView.ts
Normal file
28
libs/common/src/models/view/fieldView.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
19
libs/common/src/models/view/folderView.ts
Normal file
19
libs/common/src/models/view/folderView.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Folder } from "../domain/folder";
|
||||
import { ITreeNodeObject } from "../domain/treeNode";
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
142
libs/common/src/models/view/identityView.ts
Normal file
142
libs/common/src/models/view/identityView.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import { IdentityLinkedId as LinkedId } from "../../enums/linkedIdType";
|
||||
import { linkedFieldOption } from "../../misc/linkedFieldOption.decorator";
|
||||
import { Utils } from "../../misc/utils";
|
||||
|
||||
import { ItemView } from "./itemView";
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
8
libs/common/src/models/view/itemView.ts
Normal file
8
libs/common/src/models/view/itemView.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { LinkedMetadata } from "../../misc/linkedFieldOption.decorator";
|
||||
|
||||
import { View } from "./view";
|
||||
|
||||
export abstract class ItemView implements View {
|
||||
linkedFieldOptions: Map<number, LinkedMetadata>;
|
||||
abstract get subTitle(): string;
|
||||
}
|
||||
127
libs/common/src/models/view/loginUriView.ts
Normal file
127
libs/common/src/models/view/loginUriView.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import { UriMatchType } from "../../enums/uriMatchType";
|
||||
import { Utils } from "../../misc/utils";
|
||||
import { LoginUri } from "../domain/loginUri";
|
||||
|
||||
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.tldEndingRegex.test(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.tldEndingRegex.test(this.uri)
|
||||
? "http://" + this.uri
|
||||
: this.uri;
|
||||
}
|
||||
}
|
||||
63
libs/common/src/models/view/loginView.ts
Normal file
63
libs/common/src/models/view/loginView.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
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 "./itemView";
|
||||
import { LoginUriView } from "./loginUriView";
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
16
libs/common/src/models/view/passwordHistoryView.ts
Normal file
16
libs/common/src/models/view/passwordHistoryView.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
21
libs/common/src/models/view/secureNoteView.ts
Normal file
21
libs/common/src/models/view/secureNoteView.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { SecureNoteType } from "../../enums/secureNoteType";
|
||||
import { SecureNote } from "../domain/secureNote";
|
||||
|
||||
import { ItemView } from "./itemView";
|
||||
|
||||
export class SecureNoteView extends ItemView {
|
||||
type: SecureNoteType = null;
|
||||
|
||||
constructor(n?: SecureNote) {
|
||||
super();
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.type = n.type;
|
||||
}
|
||||
|
||||
get subTitle(): string {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
27
libs/common/src/models/view/sendAccessView.ts
Normal file
27
libs/common/src/models/view/sendAccessView.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { SendType } from "../../enums/sendType";
|
||||
import { SendAccess } from "../domain/sendAccess";
|
||||
|
||||
import { SendFileView } from "./sendFileView";
|
||||
import { SendTextView } from "./sendTextView";
|
||||
import { View } from "./view";
|
||||
|
||||
export class SendAccessView implements View {
|
||||
id: string = null;
|
||||
name: string = null;
|
||||
type: SendType = null;
|
||||
text = new SendTextView();
|
||||
file = new SendFileView();
|
||||
expirationDate: Date = null;
|
||||
creatorIdentifier: string = null;
|
||||
|
||||
constructor(s?: SendAccess) {
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.id = s.id;
|
||||
this.type = s.type;
|
||||
this.expirationDate = s.expirationDate;
|
||||
this.creatorIdentifier = s.creatorIdentifier;
|
||||
}
|
||||
}
|
||||
31
libs/common/src/models/view/sendFileView.ts
Normal file
31
libs/common/src/models/view/sendFileView.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { SendFile } from "../domain/sendFile";
|
||||
|
||||
import { View } from "./view";
|
||||
|
||||
export class SendFileView implements View {
|
||||
id: string = null;
|
||||
size: string = null;
|
||||
sizeName: string = null;
|
||||
fileName: string = null;
|
||||
|
||||
constructor(f?: SendFile) {
|
||||
if (!f) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.id = f.id;
|
||||
this.size = f.size;
|
||||
this.sizeName = f.sizeName;
|
||||
}
|
||||
|
||||
get fileSize(): number {
|
||||
try {
|
||||
if (this.size != null) {
|
||||
return parseInt(this.size, null);
|
||||
}
|
||||
} catch {
|
||||
// Invalid file size.
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
20
libs/common/src/models/view/sendTextView.ts
Normal file
20
libs/common/src/models/view/sendTextView.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { SendText } from "../domain/sendText";
|
||||
|
||||
import { View } from "./view";
|
||||
|
||||
export class SendTextView implements View {
|
||||
text: string = null;
|
||||
hidden: boolean;
|
||||
|
||||
constructor(t?: SendText) {
|
||||
if (!t) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.hidden = t.hidden;
|
||||
}
|
||||
|
||||
get maskedText(): string {
|
||||
return this.text != null ? "••••••••" : null;
|
||||
}
|
||||
}
|
||||
68
libs/common/src/models/view/sendView.ts
Normal file
68
libs/common/src/models/view/sendView.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { SendType } from "../../enums/sendType";
|
||||
import { Utils } from "../../misc/utils";
|
||||
import { Send } from "../domain/send";
|
||||
import { SymmetricCryptoKey } from "../domain/symmetricCryptoKey";
|
||||
|
||||
import { SendFileView } from "./sendFileView";
|
||||
import { SendTextView } from "./sendTextView";
|
||||
import { View } from "./view";
|
||||
|
||||
export class SendView implements View {
|
||||
id: string = null;
|
||||
accessId: string = null;
|
||||
name: string = null;
|
||||
notes: string = null;
|
||||
key: ArrayBuffer;
|
||||
cryptoKey: SymmetricCryptoKey;
|
||||
type: SendType = null;
|
||||
text = new SendTextView();
|
||||
file = new SendFileView();
|
||||
maxAccessCount?: number = null;
|
||||
accessCount = 0;
|
||||
revisionDate: Date = null;
|
||||
deletionDate: Date = null;
|
||||
expirationDate: Date = null;
|
||||
password: string = null;
|
||||
disabled = false;
|
||||
hideEmail = false;
|
||||
|
||||
constructor(s?: Send) {
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.id = s.id;
|
||||
this.accessId = s.accessId;
|
||||
this.type = s.type;
|
||||
this.maxAccessCount = s.maxAccessCount;
|
||||
this.accessCount = s.accessCount;
|
||||
this.revisionDate = s.revisionDate;
|
||||
this.deletionDate = s.deletionDate;
|
||||
this.expirationDate = s.expirationDate;
|
||||
this.disabled = s.disabled;
|
||||
this.password = s.password;
|
||||
this.hideEmail = s.hideEmail;
|
||||
}
|
||||
|
||||
get urlB64Key(): string {
|
||||
return Utils.fromBufferToUrlB64(this.key);
|
||||
}
|
||||
|
||||
get maxAccessCountReached(): boolean {
|
||||
if (this.maxAccessCount == null) {
|
||||
return false;
|
||||
}
|
||||
return this.accessCount >= this.maxAccessCount;
|
||||
}
|
||||
|
||||
get expired(): boolean {
|
||||
if (this.expirationDate == null) {
|
||||
return false;
|
||||
}
|
||||
return this.expirationDate <= new Date();
|
||||
}
|
||||
|
||||
get pendingDelete(): boolean {
|
||||
return this.deletionDate <= new Date();
|
||||
}
|
||||
}
|
||||
104
libs/common/src/models/view/ssoConfigView.ts
Normal file
104
libs/common/src/models/view/ssoConfigView.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import {
|
||||
OpenIdConnectRedirectBehavior,
|
||||
Saml2BindingType,
|
||||
Saml2NameIdFormat,
|
||||
Saml2SigningBehavior,
|
||||
SsoType,
|
||||
} from "../../enums/ssoEnums";
|
||||
import { SsoConfigApi } from "../api/ssoConfigApi";
|
||||
|
||||
import { View } from "./view";
|
||||
|
||||
export class SsoConfigView extends View {
|
||||
configType: SsoType;
|
||||
|
||||
keyConnectorEnabled: boolean;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
openId: {
|
||||
authority: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
metadataAddress: string;
|
||||
redirectBehavior: OpenIdConnectRedirectBehavior;
|
||||
getClaimsFromUserInfoEndpoint: boolean;
|
||||
additionalScopes: string;
|
||||
additionalUserIdClaimTypes: string;
|
||||
additionalEmailClaimTypes: string;
|
||||
additionalNameClaimTypes: string;
|
||||
acrValues: string;
|
||||
expectedReturnAcrValue: string;
|
||||
};
|
||||
|
||||
saml: {
|
||||
spNameIdFormat: Saml2NameIdFormat;
|
||||
spOutboundSigningAlgorithm: string;
|
||||
spSigningBehavior: Saml2SigningBehavior;
|
||||
spMinIncomingSigningAlgorithm: boolean;
|
||||
spWantAssertionsSigned: boolean;
|
||||
spValidateCertificates: boolean;
|
||||
|
||||
idpEntityId: string;
|
||||
idpBindingType: Saml2BindingType;
|
||||
idpSingleSignOnServiceUrl: string;
|
||||
idpSingleLogoutServiceUrl: string;
|
||||
idpX509PublicCert: string;
|
||||
idpOutboundSigningAlgorithm: string;
|
||||
idpAllowUnsolicitedAuthnResponse: boolean;
|
||||
idpAllowOutboundLogoutRequests: boolean;
|
||||
idpWantAuthnRequestsSigned: boolean;
|
||||
};
|
||||
|
||||
constructor(api: SsoConfigApi) {
|
||||
super();
|
||||
if (api == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.configType = api.configType;
|
||||
|
||||
this.keyConnectorEnabled = api.keyConnectorEnabled;
|
||||
this.keyConnectorUrl = api.keyConnectorUrl;
|
||||
|
||||
if (this.configType === SsoType.OpenIdConnect) {
|
||||
this.openId = {
|
||||
authority: api.authority,
|
||||
clientId: api.clientId,
|
||||
clientSecret: api.clientSecret,
|
||||
metadataAddress: api.metadataAddress,
|
||||
redirectBehavior: api.redirectBehavior,
|
||||
getClaimsFromUserInfoEndpoint: api.getClaimsFromUserInfoEndpoint,
|
||||
additionalScopes: api.additionalScopes,
|
||||
additionalUserIdClaimTypes: api.additionalUserIdClaimTypes,
|
||||
additionalEmailClaimTypes: api.additionalEmailClaimTypes,
|
||||
additionalNameClaimTypes: api.additionalNameClaimTypes,
|
||||
acrValues: api.acrValues,
|
||||
expectedReturnAcrValue: api.expectedReturnAcrValue,
|
||||
};
|
||||
} else if (this.configType === SsoType.Saml2) {
|
||||
this.saml = {
|
||||
spNameIdFormat: api.spNameIdFormat,
|
||||
spOutboundSigningAlgorithm: api.spOutboundSigningAlgorithm,
|
||||
spSigningBehavior: api.spSigningBehavior,
|
||||
spMinIncomingSigningAlgorithm: api.spMinIncomingSigningAlgorithm,
|
||||
spWantAssertionsSigned: api.spWantAssertionsSigned,
|
||||
spValidateCertificates: api.spValidateCertificates,
|
||||
|
||||
idpEntityId: api.idpEntityId,
|
||||
idpBindingType: api.idpBindingType,
|
||||
idpSingleSignOnServiceUrl: api.idpSingleSignOnServiceUrl,
|
||||
idpSingleLogoutServiceUrl: api.idpSingleLogoutServiceUrl,
|
||||
idpX509PublicCert: api.idpX509PublicCert,
|
||||
idpOutboundSigningAlgorithm: api.idpOutboundSigningAlgorithm,
|
||||
idpAllowUnsolicitedAuthnResponse: api.idpAllowUnsolicitedAuthnResponse,
|
||||
idpWantAuthnRequestsSigned: api.idpWantAuthnRequestsSigned,
|
||||
|
||||
// Value is inverted in the view model (allow instead of disable)
|
||||
idpAllowOutboundLogoutRequests:
|
||||
api.idpDisableOutboundLogoutRequests == null
|
||||
? null
|
||||
: !api.idpDisableOutboundLogoutRequests,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
1
libs/common/src/models/view/view.ts
Normal file
1
libs/common/src/models/view/view.ts
Normal file
@@ -0,0 +1 @@
|
||||
export class View {}
|
||||
Reference in New Issue
Block a user