refactor for login uris and response model changes

This commit is contained in:
Kyle Spearrin 2018-03-01 23:44:29 -05:00
parent 52f3ea58d1
commit 063bb010db
27 changed files with 405 additions and 102 deletions

View File

@ -5,3 +5,4 @@ export { FieldType } from './fieldType';
export { LogLevelType } from './logLevelType'; export { LogLevelType } from './logLevelType';
export { SecureNoteType } from './secureNoteType'; export { SecureNoteType } from './secureNoteType';
export { TwoFactorProviderType } from './twoFactorProviderType'; export { TwoFactorProviderType } from './twoFactorProviderType';
export { UriMatchType } from './uriMatchType';

View File

@ -0,0 +1,8 @@
export enum UriMatchType {
BaseDomain = 0,
FullHostname = 1,
StartsWith = 2,
Exact = 3,
RegularExpression = 4,
Never = 5,
}

17
src/models/api/cardApi.ts Normal file
View File

@ -0,0 +1,17 @@
export class CardApi {
cardholderName: string;
brand: string;
number: string;
expMonth: string;
expYear: string;
code: string;
constructor(data: any) {
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

@ -0,0 +1,13 @@
import { FieldType } from '../../enums/fieldType';
export class FieldApi {
name: string;
value: string;
type: FieldType;
constructor(response: any) {
this.type = response.Type;
this.name = response.Name;
this.value = response.Value;
}
}

View File

@ -0,0 +1,41 @@
export class IdentityApi {
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: any) {
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

@ -0,0 +1,21 @@
import { LoginUriApi } from './loginUriApi';
export class LoginApi {
uris: LoginUriApi[];
username: string;
password: string;
totp: string;
constructor(data: any) {
this.username = data.Username;
this.password = data.Password;
this.totp = data.Totp;
if (data.Uris) {
this.uris = [];
data.Uris.forEach((u: any) => {
this.uris.push(new LoginUriApi(u));
});
}
}
}

View File

@ -0,0 +1,11 @@
import { UriMatchType } from '../../enums/uriMatchType';
export class LoginUriApi {
uri: string;
match: UriMatchType = null;
constructor(data: any) {
this.uri = data.Uri;
this.match = data.Match ? data.Match : null;
}
}

View File

@ -0,0 +1,9 @@
import { SecureNoteType } from '../../enums/secureNoteType';
export class SecureNoteApi {
type: SecureNoteType;
constructor(data: any) {
this.type = data.Type;
}
}

View File

@ -1,3 +1,5 @@
import { CardApi } from '../api/cardApi';
export class CardData { export class CardData {
cardholderName: string; cardholderName: string;
brand: string; brand: string;
@ -6,12 +8,12 @@ export class CardData {
expYear: string; expYear: string;
code: string; code: string;
constructor(data: any) { constructor(data: CardApi) {
this.cardholderName = data.CardholderName; this.cardholderName = data.cardholderName;
this.brand = data.Brand; this.brand = data.brand;
this.number = data.Number; this.number = data.number;
this.expMonth = data.ExpMonth; this.expMonth = data.expMonth;
this.expYear = data.ExpYear; this.expYear = data.expYear;
this.code = data.Code; this.code = data.code;
} }
} }

View File

@ -40,6 +40,8 @@ export class CipherData {
this.favorite = response.favorite; this.favorite = response.favorite;
this.revisionDate = response.revisionDate; this.revisionDate = response.revisionDate;
this.type = response.type; this.type = response.type;
this.name = response.name;
this.notes = response.notes;
if (collectionIds != null) { if (collectionIds != null) {
this.collectionIds = collectionIds; this.collectionIds = collectionIds;
@ -47,29 +49,26 @@ export class CipherData {
this.collectionIds = response.collectionIds; this.collectionIds = response.collectionIds;
} }
this.name = response.data.Name;
this.notes = response.data.Notes;
switch (this.type) { switch (this.type) {
case CipherType.Login: case CipherType.Login:
this.login = new LoginData(response.data); this.login = new LoginData(response.login);
break; break;
case CipherType.SecureNote: case CipherType.SecureNote:
this.secureNote = new SecureNoteData(response.data); this.secureNote = new SecureNoteData(response.secureNote);
break; break;
case CipherType.Card: case CipherType.Card:
this.card = new CardData(response.data); this.card = new CardData(response.card);
break; break;
case CipherType.Identity: case CipherType.Identity:
this.identity = new IdentityData(response.data); this.identity = new IdentityData(response.identity);
break; break;
default: default:
break; break;
} }
if (response.data.Fields != null) { if (response.fields != null) {
this.fields = []; this.fields = [];
response.data.Fields.forEach((field: any) => { response.fields.forEach((field) => {
this.fields.push(new FieldData(field)); this.fields.push(new FieldData(field));
}); });
} }

View File

@ -1,13 +1,15 @@
import { FieldType } from '../../enums/fieldType'; import { FieldType } from '../../enums/fieldType';
import { FieldApi } from '../api/fieldApi';
export class FieldData { export class FieldData {
type: FieldType; type: FieldType;
name: string; name: string;
value: string; value: string;
constructor(response: any) { constructor(response: FieldApi) {
this.type = response.Type; this.type = response.type;
this.name = response.Name; this.name = response.name;
this.value = response.Value; this.value = response.value;
} }
} }

View File

@ -1,3 +1,5 @@
import { IdentityApi } from '../api/identityApi';
export class IdentityData { export class IdentityData {
title: string; title: string;
firstName: string; firstName: string;
@ -18,24 +20,24 @@ export class IdentityData {
passportNumber: string; passportNumber: string;
licenseNumber: string; licenseNumber: string;
constructor(data: any) { constructor(data: IdentityApi) {
this.title = data.Title; this.title = data.title;
this.firstName = data.FirstName; this.firstName = data.firstName;
this.middleName = data.MiddleName; this.middleName = data.middleName;
this.lastName = data.LastName; this.lastName = data.lastName;
this.address1 = data.Address1; this.address1 = data.address1;
this.address2 = data.Address2; this.address2 = data.address2;
this.address3 = data.Address3; this.address3 = data.address3;
this.city = data.City; this.city = data.city;
this.state = data.State; this.state = data.state;
this.postalCode = data.PostalCode; this.postalCode = data.postalCode;
this.country = data.Country; this.country = data.country;
this.company = data.Company; this.company = data.company;
this.email = data.Email; this.email = data.email;
this.phone = data.Phone; this.phone = data.phone;
this.ssn = data.SSN; this.ssn = data.ssn;
this.username = data.Username; this.username = data.username;
this.passportNumber = data.PassportNumber; this.passportNumber = data.passportNumber;
this.licenseNumber = data.LicenseNumber; this.licenseNumber = data.licenseNumber;
} }
} }

View File

@ -6,4 +6,5 @@ export { FieldData } from './fieldData';
export { FolderData } from './folderData'; export { FolderData } from './folderData';
export { IdentityData } from './identityData'; export { IdentityData } from './identityData';
export { LoginData } from './loginData'; export { LoginData } from './loginData';
export { LoginUriData } from './loginUriData';
export { SecureNoteData } from './secureNoteData'; export { SecureNoteData } from './secureNoteData';

View File

@ -1,13 +1,24 @@
import { LoginApi } from '../api/loginApi';
import { LoginUriApi } from '../api/loginUriApi';
import { LoginUriData } from './loginUriData';
export class LoginData { export class LoginData {
uri: string; uris: LoginUriData[];
username: string; username: string;
password: string; password: string;
totp: string; totp: string;
constructor(data: any) { constructor(data: LoginApi) {
this.uri = data.Uri; this.username = data.username;
this.username = data.Username; this.password = data.password;
this.password = data.Password; this.totp = data.totp;
this.totp = data.Totp;
if (data.uris) {
this.uris = [];
data.uris.forEach((u) => {
this.uris.push(new LoginUriData(u));
});
}
} }
} }

View File

@ -0,0 +1,13 @@
import { UriMatchType } from '../../enums/uriMatchType';
import { LoginUriApi } from '../api/loginUriApi';
export class LoginUriData {
uri: string;
match: UriMatchType = null;
constructor(data: LoginUriApi) {
this.uri = data.uri;
this.match = data.match;
}
}

View File

@ -1,9 +1,11 @@
import { SecureNoteType } from '../../enums/secureNoteType'; import { SecureNoteType } from '../../enums/secureNoteType';
import { SecureNoteApi } from '../api/secureNoteApi';
export class SecureNoteData { export class SecureNoteData {
type: SecureNoteType; type: SecureNoteType;
constructor(data: any) { constructor(data: SecureNoteApi) {
this.type = data.Type; this.type = data.type;
} }
} }

View File

@ -9,7 +9,7 @@ import { FieldView } from '../view/fieldView';
export class Field extends Domain { export class Field extends Domain {
name: CipherString; name: CipherString;
vault: CipherString; value: CipherString;
type: FieldType; type: FieldType;
constructor(obj?: FieldData, alreadyEncrypted: boolean = false) { constructor(obj?: FieldData, alreadyEncrypted: boolean = false) {

View File

@ -10,6 +10,7 @@ export { Field } from './field';
export { Folder } from './folder'; export { Folder } from './folder';
export { Identity } from './identity'; export { Identity } from './identity';
export { Login } from './login'; export { Login } from './login';
export { LoginUri } from './loginUri';
export { PasswordHistory } from './passwordHistory'; export { PasswordHistory } from './passwordHistory';
export { SecureNote } from './secureNote'; export { SecureNote } from './secureNote';
export { SymmetricCryptoKey } from './symmetricCryptoKey'; export { SymmetricCryptoKey } from './symmetricCryptoKey';

View File

@ -1,12 +1,15 @@
import { LoginUri } from './loginUri';
import { LoginData } from '../data/loginData'; import { LoginData } from '../data/loginData';
import { LoginUriView } from '../view/loginUriView';
import { LoginView } from '../view/loginView'; import { LoginView } from '../view/loginView';
import { CipherString } from './cipherString'; import { CipherString } from './cipherString';
import Domain from './domain'; import Domain from './domain';
export class Login extends Domain { export class Login extends Domain {
uri: CipherString; uris: LoginUri[];
username: CipherString; username: CipherString;
password: CipherString; password: CipherString;
totp: CipherString; totp: CipherString;
@ -18,19 +21,34 @@ export class Login extends Domain {
} }
this.buildDomainModel(this, obj, { this.buildDomainModel(this, obj, {
uri: null,
username: null, username: null,
password: null, password: null,
totp: null, totp: null,
}, alreadyEncrypted, []); }, alreadyEncrypted, []);
if (obj.uris) {
this.uris = [];
obj.uris.forEach((u) => {
this.uris.push(new LoginUri(u, alreadyEncrypted));
});
}
} }
decrypt(orgId: string): Promise<LoginView> { async decrypt(orgId: string): Promise<LoginView> {
return this.decryptObj(new LoginView(this), { const view = await this.decryptObj(new LoginView(this), {
uri: null,
username: null, username: null,
password: null, password: null,
totp: null, totp: null,
}, orgId); }, orgId);
if (this.uris != null) {
view.uris = [];
for (let i = 0; i < this.uris.length; i++) {
const uri = await this.uris[i].decrypt(orgId);
view.uris.push(uri);
}
}
return view;
} }
} }

View File

@ -0,0 +1,31 @@
import { UriMatchType } from '../../enums/uriMatchType';
import { LoginUriData } from '../data/loginUriData';
import { LoginUriView } from '../view/loginUriView';
import { CipherString } from './cipherString';
import Domain from './domain';
export class LoginUri extends Domain {
uri: CipherString;
match: UriMatchType;
constructor(obj?: LoginUriData, alreadyEncrypted: boolean = false) {
super();
if (obj == null) {
return;
}
this.match = obj.match;
this.buildDomainModel(this, obj, {
uri: null,
}, alreadyEncrypted, []);
}
decrypt(orgId: string): Promise<LoginUriView> {
return this.decryptObj(new LoginUriView(this), {
uri: null,
}, orgId);
}
}

View File

@ -1,5 +1,14 @@
import { CipherType } from '../../enums/cipherType'; import { CipherType } from '../../enums/cipherType';
import { Cipher } from '../domain/cipher';
import { Field } from '../domain/field';
import { CardApi } from '../api/cardApi';
import { FieldApi } from '../api/fieldApi';
import { IdentityApi } from '../api/identityApi';
import { LoginApi } from '../api/loginApi';
import { SecureNoteApi } from '../api/secureNoteApi';
export class CipherRequest { export class CipherRequest {
type: CipherType; type: CipherType;
folderId: string; folderId: string;
@ -7,13 +16,13 @@ export class CipherRequest {
name: string; name: string;
notes: string; notes: string;
favorite: boolean; favorite: boolean;
login: any; login: LoginApi;
secureNote: any; secureNote: SecureNoteApi;
card: any; card: CardApi;
identity: any; identity: IdentityApi;
fields: any[]; fields: FieldApi[];
constructor(cipher: any) { constructor(cipher: Cipher) {
this.type = cipher.type; this.type = cipher.type;
this.folderId = cipher.folderId; this.folderId = cipher.folderId;
this.organizationId = cipher.organizationId; this.organizationId = cipher.organizationId;
@ -24,11 +33,21 @@ export class CipherRequest {
switch (this.type) { switch (this.type) {
case CipherType.Login: case CipherType.Login:
this.login = { this.login = {
uri: cipher.login.uri ? cipher.login.uri.encryptedString : null, uris: null,
username: cipher.login.username ? cipher.login.username.encryptedString : null, username: cipher.login.username ? cipher.login.username.encryptedString : null,
password: cipher.login.password ? cipher.login.password.encryptedString : null, password: cipher.login.password ? cipher.login.password.encryptedString : null,
totp: cipher.login.totp ? cipher.login.totp.encryptedString : null, totp: cipher.login.totp ? cipher.login.totp.encryptedString : null,
}; };
if (cipher.login.uris) {
this.login.uris = [];
cipher.login.uris.forEach((u) => {
this.login.uris.push({
uri: u.uri ? u.uri.encryptedString : null,
match: u.match ? u.match : null,
});
});
}
break; break;
case CipherType.SecureNote: case CipherType.SecureNote:
this.secureNote = { this.secureNote = {
@ -74,7 +93,7 @@ export class CipherRequest {
if (cipher.fields) { if (cipher.fields) {
this.fields = []; this.fields = [];
cipher.fields.forEach((field: any) => { cipher.fields.forEach((field) => {
this.fields.push({ this.fields.push({
type: field.type, type: field.type,
name: field.name ? field.name.encryptedString : null, name: field.name ? field.name.encryptedString : null,

View File

@ -1,14 +1,26 @@
import { AttachmentResponse } from './attachmentResponse'; import { AttachmentResponse } from './attachmentResponse';
import { CardApi } from '../api/cardApi';
import { FieldApi } from '../api/fieldApi';
import { IdentityApi } from '../api/identityApi';
import { LoginApi } from '../api/loginApi';
import { SecureNoteApi } from '../api/secureNoteApi';
export class CipherResponse { export class CipherResponse {
id: string; id: string;
organizationId: string; organizationId: string;
folderId: string; folderId: string;
type: number; type: number;
name: string;
notes: string;
fields: FieldApi[];
login: LoginApi;
card: CardApi;
identity: IdentityApi;
secureNote: SecureNoteApi;
favorite: boolean; favorite: boolean;
edit: boolean; edit: boolean;
organizationUseTotp: boolean; organizationUseTotp: boolean;
data: any;
revisionDate: string; revisionDate: string;
attachments: AttachmentResponse[]; attachments: AttachmentResponse[];
collectionIds: string[]; collectionIds: string[];
@ -18,12 +30,36 @@ export class CipherResponse {
this.organizationId = response.OrganizationId; this.organizationId = response.OrganizationId;
this.folderId = response.FolderId; this.folderId = response.FolderId;
this.type = response.Type; this.type = response.Type;
this.name = response.Name;
this.notes = response.Notes;
this.favorite = response.Favorite; this.favorite = response.Favorite;
this.edit = response.Edit; this.edit = response.Edit;
this.organizationUseTotp = response.OrganizationUseTotp; this.organizationUseTotp = response.OrganizationUseTotp;
this.data = response.Data;
this.revisionDate = response.RevisionDate; this.revisionDate = response.RevisionDate;
if (response.Login != null) {
this.login = new LoginApi(response.Login);
}
if (response.Card != null) {
this.card = new CardApi(response.Card);
}
if (response.Identity != null) {
this.identity = new IdentityApi(response.Identity);
}
if (response.SecureNote != null) {
this.secureNote = new SecureNoteApi(response.SecureNote);
}
if (response.Fields != null) {
this.fields = [];
response.Fields.forEach((field: any) => {
this.fields.push(new FieldApi(field));
});
}
if (response.Attachments != null) { if (response.Attachments != null) {
this.attachments = []; this.attachments = [];
response.Attachments.forEach((attachment: any) => { response.Attachments.forEach((attachment: any) => {

View File

@ -69,8 +69,4 @@ export class CipherView implements View {
get login_username(): string { get login_username(): string {
return this.login != null ? this.login.username : null; return this.login != null ? this.login.username : null;
} }
get login_uri(): string {
return this.login != null ? this.login.uri : null;
}
} }

View File

@ -3,6 +3,7 @@ export { CardView } from './cardView';
export { CipherView } from './cipherView'; export { CipherView } from './cipherView';
export { FieldView } from './fieldView'; export { FieldView } from './fieldView';
export { IdentityView } from './identityView'; export { IdentityView } from './identityView';
export { LoginUriView } from './loginUriView';
export { LoginView } from './loginView'; export { LoginView } from './loginView';
export { SecureNoteView } from './secureNoteView'; export { SecureNoteView } from './secureNoteView';
export { View } from './view'; export { View } from './view';

View File

@ -0,0 +1,61 @@
import { UriMatchType } from '../../enums/uriMatchType';
import { View } from './view';
import { LoginUri } from '../domain/loginUri';
import { PlatformUtilsService } from '../../abstractions/platformUtils.service';
export class LoginUriView implements View {
match: UriMatchType = null;
// tslint:disable
private _uri: string;
private _domain: string;
// tslint:enable
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;
}
get domain(): string {
if (this._domain == null && this.uri != null) {
const containerService = (window as any).bitwardenContainerService;
if (containerService) {
const platformUtilsService: PlatformUtilsService = containerService.getPlatformUtilsService();
this._domain = platformUtilsService.getDomain(this.uri);
if (this._domain === '') {
this._domain = null;
}
} else {
throw new Error('window.bitwardenContainerService not initialized.');
}
}
return this._domain;
}
get domainOrUri(): string {
return this.domain != null ? this.domain : this.uri;
}
get isWebsite(): boolean {
return this.uri != null && (this.uri.indexOf('http://') === 0 || this.uri.indexOf('https://') === 0);
}
get canLaunch(): boolean {
return this.uri != null && this.uri.indexOf('://') > -1;
}
}

View File

@ -1,3 +1,4 @@
import { LoginUriView } from './loginUriView';
import { View } from './view'; import { View } from './view';
import { Login } from '../domain/login'; import { Login } from '../domain/login';
@ -7,12 +8,11 @@ import { PlatformUtilsService } from '../../abstractions/platformUtils.service';
export class LoginView implements View { export class LoginView implements View {
username: string; username: string;
totp: string; totp: string;
uris: LoginUriView[];
// tslint:disable // tslint:disable
private _uri: string;
private _username: string; private _username: string;
private _password: string; private _password: string;
private _domain: string;
private _maskedPassword: string; private _maskedPassword: string;
// tslint:enable // tslint:enable
@ -20,14 +20,6 @@ export class LoginView implements View {
// ctor // ctor
} }
get uri(): string {
return this._uri;
}
set uri(value: string) {
this._uri = value;
this._domain = null;
}
get password(): string { get password(): string {
return this._password; return this._password;
} }
@ -36,21 +28,8 @@ export class LoginView implements View {
this._maskedPassword = null; this._maskedPassword = null;
} }
get domain(): string { get uri(): string {
if (this._domain == null && this.uri != null) { return this.hasUris ? this.uris[0].uri : null;
const containerService = (window as any).bitwardenContainerService;
if (containerService) {
const platformUtilsService: PlatformUtilsService = containerService.getPlatformUtilsService();
this._domain = platformUtilsService.getDomain(this.uri);
if (this._domain === '') {
this._domain = null;
}
} else {
throw new Error('window.bitwardenContainerService not initialized.');
}
}
return this._domain;
} }
get maskedPassword(): string { get maskedPassword(): string {
@ -68,15 +47,11 @@ export class LoginView implements View {
return this.username; return this.username;
} }
get domainOrUri(): string {
return this.domain != null ? this.domain : this.uri;
}
get isWebsite(): boolean {
return this.uri != null && (this.uri.indexOf('http://') === 0 || this.uri.indexOf('https://') === 0);
}
get canLaunch(): boolean { get canLaunch(): boolean {
return this.uri != null && this.uri.indexOf('://') > -1; return this.hasUris && this.uris[0].canLaunch;
}
get hasUris(): boolean {
return this.uris != null && this.uris.length > 0;
} }
} }

View File

@ -9,6 +9,7 @@ import Domain from '../models/domain/domain';
import { Field } from '../models/domain/field'; import { Field } from '../models/domain/field';
import { Identity } from '../models/domain/identity'; import { Identity } from '../models/domain/identity';
import { Login } from '../models/domain/login'; import { Login } from '../models/domain/login';
import { LoginUri } from '../models/domain/loginUri';
import { SecureNote } from '../models/domain/secureNote'; import { SecureNote } from '../models/domain/secureNote';
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey'; import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
@ -487,11 +488,22 @@ export class CipherService implements CipherServiceAbstraction {
case CipherType.Login: case CipherType.Login:
cipher.login = new Login(); cipher.login = new Login();
await this.encryptObjProperty(model.login, cipher.login, { await this.encryptObjProperty(model.login, cipher.login, {
uri: null,
username: null, username: null,
password: null, password: null,
totp: null, totp: null,
}, key); }, key);
if (model.login.uris != null) {
cipher.login.uris = [];
for (let i = 0; i < model.login.uris.length; i++) {
const loginUri = new LoginUri();
loginUri.match = model.login.uris[i].match;
await this.encryptObjProperty(model.login.uris[i], loginUri, {
uri: null,
}, key);
cipher.login.uris.push(loginUri);
}
}
return; return;
case CipherType.SecureNote: case CipherType.SecureNote:
cipher.secureNote = new SecureNote(); cipher.secureNote = new SecureNote();