diff --git a/src/background.js b/src/background.js index 52afb715..ba85b466 100644 --- a/src/background.js +++ b/src/background.js @@ -1,5 +1,6 @@ import LockService from './services/lockService.js'; import UtilsService from './services/utils.service'; +import * as models from './models/models'; var bg_isBackground = true, bg_utilsService, diff --git a/src/models/api/requestModels.js b/src/models/api/requestModels.js index b2f5a422..866b949e 100644 --- a/src/models/api/requestModels.js +++ b/src/models/api/requestModels.js @@ -68,72 +68,3 @@ window.CipherRequest = function (cipher) { } } }; - -window.FolderRequest = function (folder) { - this.name = folder.name ? folder.name.encryptedString : null; -}; - -window.TokenRequest = function (email, masterPasswordHash, provider, token, remember, device) { - this.email = email; - this.masterPasswordHash = masterPasswordHash; - this.token = token; - this.provider = provider; - this.remember = remember === true; - this.device = null; - if (device) { - this.device = device; - } -}; - -window.TokenRequest.prototype.toIdentityToken = function () { - var obj = { - grant_type: 'password', - username: this.email, - password: this.masterPasswordHash, - scope: 'api offline_access', - client_id: 'browser' - }; - - if (this.device) { - obj.deviceType = this.device.type; - obj.deviceIdentifier = this.device.identifier; - obj.deviceName = this.device.name; - obj.devicePushToken = this.device.pushToken; - } - - if (this.token && this.provider !== null && (typeof this.provider !== 'undefined')) { - obj.twoFactorToken = this.token; - obj.twoFactorProvider = this.provider; - obj.twoFactorRemember = this.remember ? '1' : '0'; - } - - return obj; -}; - -window.RegisterRequest = function (email, masterPasswordHash, masterPasswordHint, key) { - this.name = null; - this.email = email; - this.masterPasswordHash = masterPasswordHash; - this.masterPasswordHint = masterPasswordHint ? masterPasswordHint : null; - this.key = key; -}; - -window.PasswordHintRequest = function (email) { - this.email = email; -}; - -window.TwoFactorEmailRequest = function (email, masterPasswordHash) { - this.email = email; - this.masterPasswordHash = masterPasswordHash; -}; - -window.DeviceTokenRequest = function () { - this.pushToken = null; -}; - -window.DeviceRequest = function (appId, utilsService) { - this.type = utilsService.getDeviceType(); - this.name = utilsService.getBrowser(); - this.identifier = appId; - this.pushToken = null; -}; diff --git a/src/models/api/responseModels.js b/src/models/api/responseModels.js deleted file mode 100644 index 75f3a8fc..00000000 --- a/src/models/api/responseModels.js +++ /dev/null @@ -1,169 +0,0 @@ -window.CipherResponse = function (response) { - this.id = response.Id; - this.organizationId = response.OrganizationId; - this.folderId = response.FolderId; - this.type = response.Type; - this.favorite = response.Favorite; - this.edit = response.Edit; - this.organizationUseTotp = response.OrganizationUseTotp; - this.data = response.Data; - this.revisionDate = response.RevisionDate; - - if (response.Attachments) { - this.attachments = []; - for (var i = 0; i < response.Attachments.length; i++) { - this.attachments.push(new AttachmentResponse(response.Attachments[i])); - } - } -}; - -window.FolderResponse = function (response) { - this.id = response.Id; - this.name = response.Name; - this.revisionDate = response.RevisionDate; -}; - -window.ProfileResponse = function (response) { - this.id = response.Id; - this.name = response.Name; - this.email = response.Email; - this.emailVerified = response.EmailVerified; - this.masterPasswordHint = response.MasterPasswordHint; - this.premium = response.Premium; - this.culture = response.Culture; - this.twoFactorEnabled = response.TwoFactorEnabled; - this.key = response.Key; - this.privateKey = response.PrivateKey; - this.securityStamp = response.SecurityStamp; - - this.organizations = []; - if (response.Organizations) { - for (var i = 0; i < response.Organizations.length; i++) { - this.organizations.push(new ProfileOrganizationResponse(response.Organizations[i])); - } - } -}; - -window.KeysResponse = function (response) { - this.privateKey = response.PrivateKey; - this.publicKey = response.PublicKey; -}; - -window.ProfileOrganizationResponse = function (response) { - this.id = response.Id; - this.name = response.Name; - this.useGroups = response.UseGroups; - this.useDirectory = response.UseDirectory; - this.useTotp = response.UseTotp; - this.seats = response.Seats; - this.maxCollections = response.MaxCollections; - this.maxStorageGb = response.MaxStorageGb; - this.key = response.Key; - this.status = response.Status; - this.type = response.Type; -}; - -window.AttachmentResponse = function (response) { - this.id = response.Id; - this.url = response.Url; - this.fileName = response.FileName; - this.size = response.Size; - this.sizeName = response.SizeName; -}; - -window.IdentityTokenResponse = function (response) { - this.accessToken = response.access_token; - this.expiresIn = response.expires_in; - this.refreshToken = response.refresh_token; - this.tokenType = response.token_type; - - this.privateKey = response.PrivateKey; - this.key = response.Key; - this.twoFactorToken = response.TwoFactorToken; -}; - -window.ListResponse = function (data) { - this.data = data; -}; - -window.ErrorResponse = function (response, identityResponse) { - var errorModel = null; - if (identityResponse && identityResponse === true && response.responseJSON && response.responseJSON.ErrorModel) { - errorModel = response.responseJSON.ErrorModel; - } - else if (response.responseJSON) { - errorModel = response.responseJSON; - } - else if (response.responseText && response.responseText.indexOf('{') === 0) { - errorModel = JSON.parse(response.responseText); - } - - if (errorModel) { - this.message = errorModel.Message; - this.validationErrors = errorModel.ValidationErrors; - } - this.statusCode = response.status; -}; - -window.DeviceResponse = function (response) { - this.id = response.Id; - this.name = response.Name; - this.identifier = response.Identifier; - this.type = response.Type; - this.creationDate = response.CreationDate; -}; - -window.CipherHistoryResponse = function (response) { - this.revised = []; - - var revised = response.Revised; - for (var i = 0; i < revised.length; i++) { - this.revised.push(new CipherResponse(revised[i])); - } - - this.deleted = response.Deleted; -}; - -window.DomainsResponse = function (response) { - var GlobalDomainResponse = function (response) { - this.type = response.Type; - this.domains = response.Domains; - this.excluded = response.Excluded; - }; - - this.equivalentDomains = response.EquivalentDomains; - this.globalEquivalentDomains = []; - - var globalEquivalentDomains = response.GlobalEquivalentDomains; - if (!globalEquivalentDomains) { - return; - } - for (var i = 0; i < globalEquivalentDomains.length; i++) { - this.globalEquivalentDomains.push(new GlobalDomainResponse(globalEquivalentDomains[i])); - } -}; - -window.SyncResponse = function (response) { - if (response.Profile) { - this.profile = new ProfileResponse(response.Profile); - } - - var i; - this.folders = []; - if (response.Folders) { - for (i = 0; i < response.Folders.length; i++) { - this.folders.push(new FolderResponse(response.Folders[i])); - } - } - - this.ciphers = []; - if (response.Ciphers) { - for (i = 0; i < response.Ciphers.length; i++) { - this.ciphers.push(new CipherResponse(response.Ciphers[i])); - } - } - - if (response.Domains) { - this.domains = new DomainsResponse(response.Domains); - } -}; diff --git a/src/models/data/attachmentData.ts b/src/models/data/attachmentData.ts new file mode 100644 index 00000000..2ff3ab42 --- /dev/null +++ b/src/models/data/attachmentData.ts @@ -0,0 +1,20 @@ +import { AttachmentResponse } from '../response/attachmentResponse'; + +class AttachmentData { + id: string; + url: string; + fileName: string; + size: number; + sizeName: string; + + constructor(response: AttachmentResponse) { + this.id = response.id; + this.url = response.url; + this.fileName = response.fileName; + this.size = response.size; + this.sizeName = response.sizeName; + } +} + +export { AttachmentData }; +(window as any).AttachmentData = AttachmentData; diff --git a/src/models/data/cardData.ts b/src/models/data/cardData.ts new file mode 100644 index 00000000..f0b9f63f --- /dev/null +++ b/src/models/data/cardData.ts @@ -0,0 +1,20 @@ +class CardData { + 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; + } +} + +export { CardData }; +(window as any).CardData = CardData; diff --git a/src/models/data/cipherData.ts b/src/models/data/cipherData.ts new file mode 100644 index 00000000..175fb794 --- /dev/null +++ b/src/models/data/cipherData.ts @@ -0,0 +1,79 @@ +import { AttachmentData } from './attachmentData'; +import { CardData } from './cardData'; +import { FieldData } from './fieldData'; +import { IdentityData } from './identityData'; +import { LoginData } from './loginData'; +import { SecureNoteData } from './secureNoteData'; + +import { CipherResponse } from '../response/cipherResponse'; + +class CipherData { + id: string; + organizationId: string; + folderId: string; + userId: string; + edit: boolean; + organizationUseTotp: boolean; + favorite: boolean; + revisionDate: string; + type: number; // TODO: enum + sizeName: string; + name: string; + notes: string; + login?: LoginData; + secureNote?: SecureNoteData; + card?: CardData; + identity?: IdentityData; + fields?: FieldData[]; + attachments?: AttachmentData[]; + + constructor(response: CipherResponse, userId: string) { + this.id = response.id; + this.organizationId = response.organizationId; + this.folderId = response.folderId; + this.userId = userId; + this.edit = response.edit; + this.organizationUseTotp = response.organizationUseTotp; + this.favorite = response.favorite; + this.revisionDate = response.revisionDate; + this.type = response.type; + + this.name = response.data.Name; + this.notes = response.data.Notes; + + const constantsService = chrome.extension.getBackgroundPage().bg_constantsService; // TODO: enum + switch (this.type) { + case constantsService.cipherType.login: + this.login = new LoginData(response.data); + break; + case constantsService.cipherType.secureNote: + this.secureNote = new SecureNoteData(response.data); + break; + case constantsService.cipherType.card: + this.card = new CardData(response.data); + break; + case constantsService.cipherType.identity: + this.identity = new IdentityData(response.data); + break; + default: + break; + } + + if (response.data.Fields) { + this.fields = []; + for (const field of response.data.Fields) { + this.fields.push(new FieldData(field)); + } + } + + if (response.attachments) { + this.attachments = []; + for (const attachment of response.attachments) { + this.attachments.push(new AttachmentData(attachment)); + } + } + } +} + +export { CipherData }; +(window as any).CipherData = CipherData; diff --git a/src/models/data/dataModels.ts b/src/models/data/dataModels.ts new file mode 100644 index 00000000..6cb0d533 --- /dev/null +++ b/src/models/data/dataModels.ts @@ -0,0 +1,8 @@ +import { AttachmentData } from './attachmentData'; +import { CardData } from './cardData'; +import { CipherData } from './cipherData'; +import { FieldData } from './fieldData'; +import { FolderData } from './folderData'; +import { IdentityData } from './identityData'; +import { LoginData } from './loginData'; +import { SecureNoteData } from './secureNoteData'; diff --git a/src/models/data/fieldData.ts b/src/models/data/fieldData.ts new file mode 100644 index 00000000..5349b852 --- /dev/null +++ b/src/models/data/fieldData.ts @@ -0,0 +1,14 @@ +class FieldData { + type: number; // TODO: enum + name: string; + value: string; + + constructor(response: any) { + this.type = response.Type; + this.name = response.Name; + this.value = response.Value; + } +} + +export { FieldData }; +(window as any).FieldData = FieldData; diff --git a/src/models/data/folderData.ts b/src/models/data/folderData.ts new file mode 100644 index 00000000..6f03781c --- /dev/null +++ b/src/models/data/folderData.ts @@ -0,0 +1,18 @@ +import { FolderResponse } from '../response/folderResponse'; + +class FolderData { + id: string; + userId: string; + name: string; + revisionDate: string; + + constructor(response: FolderResponse, userId: string) { + this.userId = userId; + this.name = response.name; + this.id = response.id; + this.revisionDate = response.revisionDate; + } +} + +export { FolderData }; +(window as any).FolderData = FolderData; diff --git a/src/models/data/identityData.ts b/src/models/data/identityData.ts new file mode 100644 index 00000000..ee849166 --- /dev/null +++ b/src/models/data/identityData.ts @@ -0,0 +1,44 @@ +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: 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; + } +} + +export { IdentityData }; +(window as any).IdentityData = IdentityData; diff --git a/src/models/data/loginData.ts b/src/models/data/loginData.ts new file mode 100644 index 00000000..de0aecc1 --- /dev/null +++ b/src/models/data/loginData.ts @@ -0,0 +1,16 @@ +class LoginData { + uri: string; + username: string; + password: string; + totp: string; + + constructor(data: any) { + this.uri = data.Uri; + this.username = data.Username; + this.password = data.Password; + this.totp = data.Totp; + } +} + +export { LoginData }; +(window as any).LoginData = LoginData; diff --git a/src/models/data/secureNoteData.ts b/src/models/data/secureNoteData.ts new file mode 100644 index 00000000..70e55800 --- /dev/null +++ b/src/models/data/secureNoteData.ts @@ -0,0 +1,10 @@ +class SecureNoteData { + type: number; // TODO: enum + + constructor(data: any) { + this.type = data.Type; + } +} + +export { SecureNoteData }; +(window as any).SecureNoteData = SecureNoteData; diff --git a/src/models/dataModels.js b/src/models/dataModels.js deleted file mode 100644 index 6c86b094..00000000 --- a/src/models/dataModels.js +++ /dev/null @@ -1,119 +0,0 @@ -var FolderData = function (response, userId) { - this.id = response.id; - this.userId = userId; - - if (response instanceof FolderResponse) { - this.name = response.name; - } - else if (response instanceof CipherResponse) { - this.name = response.data.Name; - } - else { - throw 'unsupported instance'; - } - - this.revisionDate = response.revisionDate; -}; - -var CipherData = function (response, userId) { - this.id = response.id; - this.organizationId = response.organizationId; - this.folderId = response.folderId; - this.userId = userId; - this.edit = response.edit; - this.organizationUseTotp = response.organizationUseTotp; - this.favorite = response.favorite; - this.revisionDate = response.revisionDate; - this.type = response.type; - - this.name = response.data.Name; - this.notes = response.notes = response.data.Notes; - - var constantsService = chrome.extension.getBackgroundPage().bg_constantsService; - switch (this.type) { - case constantsService.cipherType.login: - this.login = new LoginData(response.data); - break; - case constantsService.cipherType.secureNote: - this.secureNote = new SecureNoteData(response.data); - break; - case constantsService.cipherType.card: - this.card = new CardData(response.data); - break; - case constantsService.cipherType.identity: - this.identity = new IdentityData(response.data); - break; - default: - break; - } - - var i; - if (response.data.Fields) { - this.fields = []; - for (i = 0; i < response.data.Fields.length; i++) { - this.fields.push(new FieldData(response.data.Fields[i])); - } - } - - if (response.attachments) { - this.attachments = []; - for (i = 0; i < response.attachments.length; i++) { - this.attachments.push(new AttachmentData(response.attachments[i])); - } - } -}; - -var AttachmentData = function (response) { - this.id = response.id; - this.url = response.url; - this.fileName = response.fileName; - this.size = response.size; - this.sizeName = response.sizeName; -}; - -var FieldData = function (response) { - this.type = response.Type; - this.name = response.Name; - this.value = response.Value; -}; - -var LoginData = function (data) { - this.uri = data.Uri; - this.username = data.Username; - this.password = data.Password; - this.totp = data.Totp; -}; - -var IdentityData = function (data) { - 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; -}; - -var SecureNoteData = function (data) { - this.type = data.Type; -}; - -var CardData = function (data) { - this.cardholderName = data.CardholderName; - this.brand = data.Brand; - this.number = data.Number; - this.expMonth = data.ExpMonth; - this.expYear = data.ExpYear; - this.code = data.Code; -}; diff --git a/src/models/domain/cipherString.ts b/src/models/domain/cipherString.ts new file mode 100644 index 00000000..3abb2109 --- /dev/null +++ b/src/models/domain/cipherString.ts @@ -0,0 +1,113 @@ +class CipherString { + encryptedString?: string; + encryptionType?: number; // TODO: enum + decryptedValue?: string; + cipherText?: string; + initializationVector?: string; + mac?: string; + cryptoService: any; // TODO: type + + constructor() { + this.cryptoService = chrome.extension.getBackgroundPage().bg_cryptoService; + const constants = chrome.extension.getBackgroundPage().bg_constantsService; + + if (arguments.length >= 2) { + // ct and header + this.encryptedString = arguments[0] + '.' + arguments[1]; + + // iv + if (arguments.length > 2 && arguments[2]) { + this.encryptedString += ('|' + arguments[2]); + } + + // mac + if (arguments.length > 3 && arguments[3]) { + this.encryptedString += ('|' + arguments[3]); + } + + this.encryptionType = arguments[0]; + this.cipherText = arguments[1]; + this.initializationVector = arguments[2] || null; + this.mac = arguments[3] || null; + + return; + } else if (arguments.length !== 1) { + return; + } + + this.encryptedString = arguments[0]; + if (!this.encryptedString) { + return; + } + + const headerPieces = this.encryptedString.split('.'); + let encPieces: string[] = null; + + if (headerPieces.length === 2) { + try { + this.encryptionType = parseInt(headerPieces[0], null); + encPieces = headerPieces[1].split('|'); + } catch (e) { + return; + } + } else { + encPieces = this.encryptedString.split('|'); + this.encryptionType = encPieces.length === 3 ? constants.encType.AesCbc128_HmacSha256_B64 : + constants.encType.AesCbc256_B64; + } + + switch (this.encryptionType) { + case constants.encType.AesCbc128_HmacSha256_B64: + case constants.encType.AesCbc256_HmacSha256_B64: + if (encPieces.length !== 3) { + return; + } + + this.initializationVector = encPieces[0]; + this.cipherText = encPieces[1]; + this.mac = encPieces[2]; + break; + case constants.encType.AesCbc256_B64: + if (encPieces.length !== 2) { + return; + } + + this.initializationVector = encPieces[0]; + this.cipherText = encPieces[1]; + break; + case constants.encType.Rsa2048_OaepSha256_B64: + case constants.encType.Rsa2048_OaepSha1_B64: + if (encPieces.length !== 1) { + return; + } + + this.cipherText = encPieces[0]; + break; + default: + return; + } + } + + decrypt(orgId: string) { + const self = this; + + if (this.decryptedValue) { + return new Promise((resolve) => { + resolve(self.decryptedValue); + }); + } + + return self.cryptoService.getOrgKey(orgId).then((orgKey: any) => { + return self.cryptoService.decrypt(self, orgKey); + }).then((decValue: any) => { + self.decryptedValue = decValue; + return self.decryptedValue; + }).catch(() => { + self.decryptedValue = '[error: cannot decrypt]'; + return self.decryptedValue; + }); + } +} + +export { CipherString }; +(window as any).CipherString = CipherString; diff --git a/src/models/domain/domainModels.ts b/src/models/domain/domainModels.ts new file mode 100644 index 00000000..f4b00943 --- /dev/null +++ b/src/models/domain/domainModels.ts @@ -0,0 +1 @@ +import { CipherString } from './cipherString'; diff --git a/src/models/domainModels.js b/src/models/domainModels.js index 7d321747..04d60ce3 100644 --- a/src/models/domainModels.js +++ b/src/models/domainModels.js @@ -1,94 +1,3 @@ -var CipherString = function () { - this.encryptedString = null; - this.encryptionType = null; - this.decryptedValue = null; - this.cipherText = null; - this.initializationVector = null; - this.mac = null; - this.cryptoService = chrome.extension.getBackgroundPage().bg_cryptoService; - - var constants = chrome.extension.getBackgroundPage().bg_constantsService; - - if (arguments.length >= 2) { - // ct and header - this.encryptedString = arguments[0] + '.' + arguments[1]; - - // iv - if (arguments.length > 2 && arguments[2]) { - this.encryptedString += ('|' + arguments[2]); - } - - // mac - if (arguments.length > 3 && arguments[3]) { - this.encryptedString += ('|' + arguments[3]); - } - - this.encryptionType = arguments[0]; - this.cipherText = arguments[1]; - this.initializationVector = arguments[2] || null; - this.mac = arguments[3] || null; - - return; - } - else if (arguments.length !== 1) { - return; - } - - this.encryptedString = arguments[0]; - if (!this.encryptedString) { - return; - } - - var headerPieces = this.encryptedString.split('.'), - encPieces; - - if (headerPieces.length === 2) { - try { - this.encryptionType = parseInt(headerPieces[0]); - encPieces = headerPieces[1].split('|'); - } - catch (e) { - return; - } - } - else { - encPieces = this.encryptedString.split('|'); - this.encryptionType = encPieces.length === 3 ? constants.encType.AesCbc128_HmacSha256_B64 : - constants.encType.AesCbc256_B64; - } - - switch (this.encryptionType) { - case constants.encType.AesCbc128_HmacSha256_B64: - case constants.encType.AesCbc256_HmacSha256_B64: - if (encPieces.length !== 3) { - return; - } - - this.initializationVector = encPieces[0]; - this.cipherText = encPieces[1]; - this.mac = encPieces[2]; - break; - case constants.encType.AesCbc256_B64: - if (encPieces.length !== 2) { - return; - } - - this.initializationVector = encPieces[0]; - this.cipherText = encPieces[1]; - break; - case constants.encType.Rsa2048_OaepSha256_B64: - case constants.encType.Rsa2048_OaepSha1_B64: - if (encPieces.length !== 1) { - return; - } - - this.cipherText = encPieces[0]; - break; - default: - return; - } -}; - var Cipher = function (obj, alreadyEncrypted, localData) { this.constantsService = chrome.extension.getBackgroundPage().bg_constantsService; this.utilsService = chrome.extension.getBackgroundPage().bg_utilsService; @@ -234,23 +143,6 @@ function buildDomainModel(model, obj, map, alreadyEncrypted, notEncList) { } (function () { - CipherString.prototype.decrypt = function (orgId) { - if (this.decryptedValue) { - return Q(this.decryptedValue); - } - - var self = this; - return self.cryptoService.getOrgKey(orgId).then(function (orgKey) { - return self.cryptoService.decrypt(self, orgKey); - }).then(function (decValue) { - self.decryptedValue = decValue; - return self.decryptedValue; - }).catch(function () { - self.decryptedValue = '[error: cannot decrypt]'; - return self.decryptedValue; - }); - }; - Cipher.prototype.decrypt = function () { var self = this; diff --git a/src/models/models.ts b/src/models/models.ts new file mode 100644 index 00000000..42bb593a --- /dev/null +++ b/src/models/models.ts @@ -0,0 +1,4 @@ +import * as dataModels from './data/dataModels'; +import * as domainModels from './domain/domainModels'; +import * as requestModels from './request/requestModels'; +import * as responseModels from './response/responseModels'; diff --git a/src/models/request/deviceRequest.ts b/src/models/request/deviceRequest.ts new file mode 100644 index 00000000..a7a44144 --- /dev/null +++ b/src/models/request/deviceRequest.ts @@ -0,0 +1,16 @@ +class DeviceRequest { + type: number; // TODO: enum + name: string; + identifier: string; + pushToken?: string; + + constructor(appId: string, utilsService: any) { // TODO: utils service type + this.type = utilsService.getDeviceType(); + this.name = utilsService.getBrowser(); + this.identifier = appId; + this.pushToken = null; + } +} + +export { DeviceRequest }; +(window as any).DeviceRequest = DeviceRequest; diff --git a/src/models/request/deviceTokenRequest.ts b/src/models/request/deviceTokenRequest.ts new file mode 100644 index 00000000..69ef20bb --- /dev/null +++ b/src/models/request/deviceTokenRequest.ts @@ -0,0 +1,10 @@ +class DeviceTokenRequest { + pushToken: string; + + constructor() { + this.pushToken = null; + } +} + +export { DeviceTokenRequest }; +(window as any).DeviceTokenRequest = DeviceTokenRequest; diff --git a/src/models/request/folderRequest.ts b/src/models/request/folderRequest.ts new file mode 100644 index 00000000..f9362b73 --- /dev/null +++ b/src/models/request/folderRequest.ts @@ -0,0 +1,10 @@ +class FolderRequest { + name: string; + + constructor(folder: any) { // TODO: folder type + this.name = folder.name ? folder.name.encryptedString : null; + } +} + +export { FolderRequest }; +(window as any).FolderRequest = FolderRequest; diff --git a/src/models/request/passwordHintRequest.ts b/src/models/request/passwordHintRequest.ts new file mode 100644 index 00000000..4feb9294 --- /dev/null +++ b/src/models/request/passwordHintRequest.ts @@ -0,0 +1,10 @@ +class PasswordHintRequest { + email: string; + + constructor(email: string) { + this.email = email; + } +} + +export { PasswordHintRequest }; +(window as any).PasswordHintRequest = PasswordHintRequest; diff --git a/src/models/request/registerRequest.ts b/src/models/request/registerRequest.ts new file mode 100644 index 00000000..4b80fb78 --- /dev/null +++ b/src/models/request/registerRequest.ts @@ -0,0 +1,18 @@ +class RegisterRequest { + name: string; + email: string; + masterPasswordHash: string; + masterPasswordHint: string; + key: string; + + constructor(email: string, masterPasswordHash: string, masterPasswordHint: string, key: string) { + this.name = null; + this.email = email; + this.masterPasswordHash = masterPasswordHash; + this.masterPasswordHint = masterPasswordHint ? masterPasswordHint : null; + this.key = key; + } +} + +export { RegisterRequest }; +(window as any).RegisterRequest = RegisterRequest; diff --git a/src/models/request/requestModels.ts b/src/models/request/requestModels.ts new file mode 100644 index 00000000..706ae5fd --- /dev/null +++ b/src/models/request/requestModels.ts @@ -0,0 +1,7 @@ +import { DeviceRequest } from './deviceRequest'; +import { DeviceTokenRequest } from './deviceTokenRequest'; +import { FolderRequest } from './folderRequest'; +import { PasswordHintRequest } from './passwordHintRequest'; +import { RegisterRequest } from './registerRequest'; +import { TokenRequest } from './tokenRequest'; +import { TwoFactorEmailRequest } from './twoFactorEmailRequest'; diff --git a/src/models/request/tokenRequest.ts b/src/models/request/tokenRequest.ts new file mode 100644 index 00000000..b24bd9c3 --- /dev/null +++ b/src/models/request/tokenRequest.ts @@ -0,0 +1,46 @@ +class TokenRequest { + email: string; + masterPasswordHash: string; + token: string; + provider: number; + remember: boolean; + device?: any; + + constructor(email: string, masterPasswordHash: string, provider: number, + token: string, remember: boolean, device?: any) { + this.email = email; + this.masterPasswordHash = masterPasswordHash; + this.token = token; + this.provider = provider; + this.remember = remember; + this.device = device ? device : null; + } + + toIdentityToken() { + const obj: any = { + grant_type: 'password', + username: this.email, + password: this.masterPasswordHash, + scope: 'api offline_access', + client_id: 'browser', + }; + + if (this.device) { + obj.deviceType = this.device.type; + obj.deviceIdentifier = this.device.identifier; + obj.deviceName = this.device.name; + obj.devicePushToken = this.device.pushToken; + } + + if (this.token && this.provider !== null && (typeof this.provider !== 'undefined')) { + obj.twoFactorToken = this.token; + obj.twoFactorProvider = this.provider; + obj.twoFactorRemember = this.remember ? '1' : '0'; + } + + return obj; + } +} + +export { TokenRequest }; +(window as any).TokenRequest = TokenRequest; diff --git a/src/models/request/twoFactorEmailRequest.ts b/src/models/request/twoFactorEmailRequest.ts new file mode 100644 index 00000000..d540b08e --- /dev/null +++ b/src/models/request/twoFactorEmailRequest.ts @@ -0,0 +1,12 @@ +class TwoFactorEmailRequest { + email: string; + masterPasswordHash: string; + + constructor(email: string, masterPasswordHash: string) { + this.email = email; + this.masterPasswordHash = masterPasswordHash; + } +} + +export { TwoFactorEmailRequest }; +(window as any).TwoFactorEmailRequest = TwoFactorEmailRequest; diff --git a/src/models/response/attachmentResponse.ts b/src/models/response/attachmentResponse.ts new file mode 100644 index 00000000..df513865 --- /dev/null +++ b/src/models/response/attachmentResponse.ts @@ -0,0 +1,18 @@ +class AttachmentResponse { + id: string; + url: string; + fileName: string; + size: number; + sizeName: string; + + constructor(response: any) { + this.id = response.Id; + this.url = response.Url; + this.fileName = response.FileName; + this.size = response.Size; + this.sizeName = response.SizeName; + } +} + +export { AttachmentResponse }; +(window as any).AttachmentResponse = AttachmentResponse; diff --git a/src/models/response/cipherResponse.ts b/src/models/response/cipherResponse.ts new file mode 100644 index 00000000..28aea787 --- /dev/null +++ b/src/models/response/cipherResponse.ts @@ -0,0 +1,35 @@ +import { AttachmentResponse } from './attachmentResponse'; + +class CipherResponse { + id: string; + organizationId: string; + folderId: string; + type: number; + favorite: boolean; + edit: boolean; + organizationUseTotp: boolean; + data: any; + revisionDate: string; + attachments: AttachmentResponse[] = []; + + constructor(response: any) { + this.id = response.Id; + this.organizationId = response.OrganizationId; + this.folderId = response.FolderId; + this.type = response.Type; + this.favorite = response.Favorite; + this.edit = response.Edit; + this.organizationUseTotp = response.OrganizationUseTotp; + this.data = response.Data; + this.revisionDate = response.RevisionDate; + + if (response.Attachments) { + for (const attachment of response.Attachments) { + this.attachments.push(new AttachmentResponse(attachment)); + } + } + } +} + +export { CipherResponse }; +(window as any).CipherResponse = CipherResponse; diff --git a/src/models/response/deviceResponse.ts b/src/models/response/deviceResponse.ts new file mode 100644 index 00000000..3491df3b --- /dev/null +++ b/src/models/response/deviceResponse.ts @@ -0,0 +1,18 @@ +class DeviceResponse { + id: string; + name: number; + identifier: string; + type: number; // TODO: Convert to enum + creationDate: string; + + constructor(response: any) { + this.id = response.Id; + this.name = response.Name; + this.identifier = response.Identifier; + this.type = response.Type; + this.creationDate = response.CreationDate; + } +} + +export { DeviceResponse }; +(window as any).DeviceResponse = DeviceResponse; diff --git a/src/models/response/domainsResponse.ts b/src/models/response/domainsResponse.ts new file mode 100644 index 00000000..87b6794c --- /dev/null +++ b/src/models/response/domainsResponse.ts @@ -0,0 +1,20 @@ +import { GlobalDomainResponse } from './globalDomainResponse'; + +class DomainsResponse { + equivalentDomains: string[][]; + globalEquivalentDomains: GlobalDomainResponse[] = []; + + constructor(response: any) { + this.equivalentDomains = response.EquivalentDomains; + + this.globalEquivalentDomains = []; + if (response.GlobalEquivalentDomains) { + for (const domain of response.GlobalEquivalentDomains) { + this.globalEquivalentDomains.push(new GlobalDomainResponse(domain)); + } + } + } +} + +export { DomainsResponse }; +(window as any).DomainsResponse = DomainsResponse; diff --git a/src/models/response/errorResponse.ts b/src/models/response/errorResponse.ts new file mode 100644 index 00000000..6426e448 --- /dev/null +++ b/src/models/response/errorResponse.ts @@ -0,0 +1,25 @@ +class ErrorResponse { + message: string; + validationErrors: { [key: string]: string[]; }; + statusCode: number; + + constructor(response: any, identityResponse?: boolean) { + let errorModel = null; + if (identityResponse && response.responseJSON && response.responseJSON.ErrorModel) { + errorModel = response.responseJSON.ErrorModel; + } else if (response.responseJSON) { + errorModel = response.responseJSON; + } else if (response.responseText && response.responseText.indexOf('{') === 0) { + errorModel = JSON.parse(response.responseText); + } + + if (errorModel) { + this.message = errorModel.Message; + this.validationErrors = errorModel.ValidationErrors; + } + this.statusCode = response.status; + } +} + +export { ErrorResponse }; +(window as any).ErrorResponse = ErrorResponse; diff --git a/src/models/response/folderResponse.ts b/src/models/response/folderResponse.ts new file mode 100644 index 00000000..c5ff0ada --- /dev/null +++ b/src/models/response/folderResponse.ts @@ -0,0 +1,14 @@ +class FolderResponse { + id: string; + name: string; + revisionDate: string; + + constructor(response: any) { + this.id = response.Id; + this.name = response.Name; + this.revisionDate = response.RevisionDate; + } +} + +export { FolderResponse }; +(window as any).FolderResponse = FolderResponse; diff --git a/src/models/response/globalDomainResponse.ts b/src/models/response/globalDomainResponse.ts new file mode 100644 index 00000000..8e9a45df --- /dev/null +++ b/src/models/response/globalDomainResponse.ts @@ -0,0 +1,14 @@ +class GlobalDomainResponse { + type: number; + domains: string[]; + excluded: number[]; + + constructor(response: any) { + this.type = response.Type; + this.domains = response.Domains; + this.excluded = response.Excluded; + } +} + +export { GlobalDomainResponse }; +(window as any).GlobalDomainResponse = GlobalDomainResponse; diff --git a/src/models/response/identityTokenResponse.ts b/src/models/response/identityTokenResponse.ts new file mode 100644 index 00000000..2d188707 --- /dev/null +++ b/src/models/response/identityTokenResponse.ts @@ -0,0 +1,24 @@ +class IdentityTokenResponse { + accessToken: string; + expiresIn: number; + refreshToken: string; + tokenType: string; + + privateKey: string; + key: string; + twoFactorToken: string; + + constructor(response: any) { + this.accessToken = response.access_token; + this.expiresIn = response.expires_in; + this.refreshToken = response.refresh_token; + this.tokenType = response.token_type; + + this.privateKey = response.PrivateKey; + this.key = response.Key; + this.twoFactorToken = response.TwoFactorToken; + } +} + +export { IdentityTokenResponse }; +(window as any).IdentityTokenResponse = IdentityTokenResponse; diff --git a/src/models/response/keysResponse.ts b/src/models/response/keysResponse.ts new file mode 100644 index 00000000..cb96dad5 --- /dev/null +++ b/src/models/response/keysResponse.ts @@ -0,0 +1,12 @@ +class KeysResponse { + privateKey: string; + publicKey: string; + + constructor(response: any) { + this.privateKey = response.PrivateKey; + this.publicKey = response.PublicKey; + } +} + +export { KeysResponse }; +(window as any).KeysResponse = KeysResponse; diff --git a/src/models/response/listResponse.ts b/src/models/response/listResponse.ts new file mode 100644 index 00000000..9cf5455a --- /dev/null +++ b/src/models/response/listResponse.ts @@ -0,0 +1,10 @@ +class ListResponse { + data: any; + + constructor(data: any) { + this.data = data; + } +} + +export { ListResponse }; +(window as any).ListResponse = ListResponse; diff --git a/src/models/response/profileOrganizationResponse.ts b/src/models/response/profileOrganizationResponse.ts new file mode 100644 index 00000000..48485774 --- /dev/null +++ b/src/models/response/profileOrganizationResponse.ts @@ -0,0 +1,30 @@ +class ProfileOrganizationResponse { + id: string; + name: string; + useGroups: boolean; + useDirectory: boolean; + useTotp: boolean; + seats: number; + maxCollections: number; + maxStorageGb?: number; + key: string; + status: number; // TODO: map to enum + type: number; // TODO: map to enum + + constructor(response: any) { + this.id = response.Id; + this.name = response.Name; + this.useGroups = response.UseGroups; + this.useDirectory = response.UseDirectory; + this.useTotp = response.UseTotp; + this.seats = response.Seats; + this.maxCollections = response.MaxCollections; + this.maxStorageGb = response.MaxStorageGb; + this.key = response.Key; + this.status = response.Status; + this.type = response.Type; + } +} + +export { ProfileOrganizationResponse }; +(window as any).ProfileOrganizationResponse = ProfileOrganizationResponse; diff --git a/src/models/response/profileResponse.ts b/src/models/response/profileResponse.ts new file mode 100644 index 00000000..16131451 --- /dev/null +++ b/src/models/response/profileResponse.ts @@ -0,0 +1,39 @@ +import { ProfileOrganizationResponse } from './profileOrganizationResponse'; + +class ProfileResponse { + id: string; + name: string; + email: string; + emailVerified: boolean; + masterPasswordHint: string; + premium: boolean; + culture: string; + twoFactorEnabled: boolean; + key: string; + privateKey: string; + securityStamp: string; + organizations: ProfileOrganizationResponse[] = []; + + constructor(response: any) { + this.id = response.Id; + this.name = response.Name; + this.email = response.Email; + this.emailVerified = response.EmailVerified; + this.masterPasswordHint = response.MasterPasswordHint; + this.premium = response.Premium; + this.culture = response.Culture; + this.twoFactorEnabled = response.TwoFactorEnabled; + this.key = response.Key; + this.privateKey = response.PrivateKey; + this.securityStamp = response.SecurityStamp; + + if (response.Organizations) { + for (const org of response.Organizations) { + this.organizations.push(new ProfileOrganizationResponse(org)); + } + } + } +} + +export { ProfileResponse }; +(window as any).ProfileResponse = ProfileResponse; diff --git a/src/models/response/responseModels.ts b/src/models/response/responseModels.ts new file mode 100644 index 00000000..aa8812a0 --- /dev/null +++ b/src/models/response/responseModels.ts @@ -0,0 +1,13 @@ +import { AttachmentResponse } from './attachmentResponse'; +import { CipherResponse } from './cipherResponse'; +import { DeviceResponse } from './deviceResponse'; +import { DomainsResponse } from './domainsResponse'; +import { ErrorResponse } from './errorResponse'; +import { FolderResponse } from './folderResponse'; +import { GlobalDomainResponse } from './globalDomainResponse'; +import { IdentityTokenResponse } from './identityTokenResponse'; +import { KeysResponse } from './keysResponse'; +import { ListResponse } from './listResponse'; +import { ProfileOrganizationResponse } from './profileOrganizationResponse'; +import { ProfileResponse } from './profileResponse'; +import { SyncResponse } from './syncResponse'; diff --git a/src/models/response/syncResponse.ts b/src/models/response/syncResponse.ts new file mode 100644 index 00000000..45e9e5e8 --- /dev/null +++ b/src/models/response/syncResponse.ts @@ -0,0 +1,36 @@ +import { CipherResponse } from './cipherResponse'; +import { DomainsResponse } from './domainsResponse'; +import { FolderResponse } from './folderResponse'; +import { ProfileResponse } from './profileResponse'; + +class SyncResponse { + profile?: ProfileResponse; + folders: FolderResponse[] = []; + ciphers: CipherResponse[] = []; + domains?: DomainsResponse; + + constructor(response: any) { + if (response.Profile) { + this.profile = new ProfileResponse(response.Profile); + } + + if (response.Folders) { + for (const folder of response.Folders) { + this.folders.push(new FolderResponse(folder)); + } + } + + if (response.Ciphers) { + for (const cipher of response.Ciphers) { + this.ciphers.push(new CipherResponse(cipher)); + } + } + + if (response.Domains) { + this.domains = new DomainsResponse(response.Domains); + } + } +} + +export { SyncResponse }; +(window as any).SyncResponse = SyncResponse; diff --git a/src/popup/app/app.js b/src/popup/app/app.js index 13523659..ccf6c94f 100644 --- a/src/popup/app/app.js +++ b/src/popup/app/app.js @@ -22,8 +22,6 @@ require('../../scripts/duo.js'); require('../../scripts/u2f.js'); require('../../models/api/requestModels.js'); -require('../../models/api/responseModels.js'); -require('../../models/dataModels.js'); require('../../models/domainModels.js'); require('../less/libs.less'); @@ -31,6 +29,8 @@ require('../less/popup.less'); import ComponentsModule from './components/components.module'; +import * as models from '../../models/models'; + angular .module('bit', [ 'ui.router', @@ -103,6 +103,6 @@ require('./lock/lockModule.js'); require('./lock/lockController.js'); // Bootstrap the angular application -angular.element(function() { +angular.element(function () { angular.bootstrap(document, ['bit']); });