From 11edb0261bb6afffd6c4dfd885b6f13b40e5ac1a Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Sat, 4 Nov 2017 21:09:26 -0400 Subject: [PATCH] folder service to ts --- src/background.html | 1 - src/background.js | 3 + src/models/domain/domain.ts | 42 +++++++++ src/models/domain/folder.ts | 35 ++++++++ src/popup/app/app.js | 2 + src/services/folder.service.ts | 153 +++++++++++++++++++++++++++++++++ 6 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 src/models/domain/domain.ts create mode 100644 src/models/domain/folder.ts create mode 100644 src/services/folder.service.ts diff --git a/src/background.html b/src/background.html index a9e418fd9f..d353afbb00 100644 --- a/src/background.html +++ b/src/background.html @@ -5,7 +5,6 @@ - diff --git a/src/background.js b/src/background.js index c573fd6860..04f720c46d 100644 --- a/src/background.js +++ b/src/background.js @@ -4,6 +4,7 @@ import AppIdService from './services/appId.service'; import ConstantsService from './services/constants.service'; import CryptoService from './services/crypto.service'; import EnvironmentService from './services/environment.service'; +import FolderService from './services/folder.service'; import i18nService from './services/i18nService.js'; import LockService from './services/lockService.js'; import PasswordGenerationService from './services/passwordGeneration.service'; @@ -14,6 +15,8 @@ import UserService from './services/user.service'; import UtilsService from './services/utils.service'; // Model imports +import { Folder } from './models/domain/folder'; + import { AttachmentData } from './models/data/attachmentData'; import { CardData } from './models/data/cardData'; import { CipherData } from './models/data/cipherData'; diff --git a/src/models/domain/domain.ts b/src/models/domain/domain.ts new file mode 100644 index 0000000000..4c565967bf --- /dev/null +++ b/src/models/domain/domain.ts @@ -0,0 +1,42 @@ +import { CipherString } from '../domain/cipherString'; + +export default abstract class Domain { + protected buildDomainModel(model: any, obj: any, map: any, alreadyEncrypted: boolean, notEncList: any = []) { + for (var prop in map) { + if (map.hasOwnProperty(prop)) { + var objProp = obj[(map[prop] || prop)]; + if (alreadyEncrypted === true || notEncList.indexOf(prop) > -1) { + model[prop] = objProp ? objProp : null; + } else { + model[prop] = objProp ? new CipherString(objProp) : null; + } + } + } + } + + protected async decryptObj(model: any, self: any, map: any, orgId: string) { + var promises = []; + for (let prop in map) { + if (!map.hasOwnProperty(prop)) { + continue; + } + + (function (theProp) { + let promise = Promise.resolve().then(function () { + var mapProp = map[theProp] || theProp; + if (self[mapProp]) { + return self[mapProp].decrypt(orgId); + } + return null; + }).then(function (val) { + model[theProp] = val; + return; + }); + promises.push(promise); + })(prop); + } + + await Promise.all(promises); + return model; + } +} \ No newline at end of file diff --git a/src/models/domain/folder.ts b/src/models/domain/folder.ts new file mode 100644 index 0000000000..7c8ca2a254 --- /dev/null +++ b/src/models/domain/folder.ts @@ -0,0 +1,35 @@ +import { CipherString } from './cipherString'; +import { FolderData } from '../data/folderData' + +import Domain from './domain' + +class Folder extends Domain { + id: string; + name: CipherString; + + constructor(obj?: FolderData, alreadyEncrypted: boolean = false) { + super(); + if(obj == null) { + return; + } + + this.buildDomainModel(this, obj, { + id: null, + name: null + }, alreadyEncrypted, ['id']); + } + + async decrypt(): Promise { + var self = this; + var model = { + id: self.id + }; + + return await this.decryptObj(model, this, { + name: null + }, null); + } +} + +export { Folder }; +(window as any).Folder = Folder; diff --git a/src/popup/app/app.js b/src/popup/app/app.js index 34c4c36e54..a49b67c03c 100644 --- a/src/popup/app/app.js +++ b/src/popup/app/app.js @@ -32,6 +32,8 @@ import ServicesModule from './services/services.module'; import LockModule from './lock/lock.module'; // Model imports +import { Folder } from './models/domain/folder'; + import { AttachmentData } from '../../models/data/attachmentData'; import { CardData } from '../../models/data/cardData'; import { CipherData } from '../../models/data/cipherData'; diff --git a/src/services/folder.service.ts b/src/services/folder.service.ts new file mode 100644 index 0000000000..7761a1b68e --- /dev/null +++ b/src/services/folder.service.ts @@ -0,0 +1,153 @@ +import { CipherString } from '../models/domain/cipherString'; +import { Folder } from '../models/domain/folder'; +import { FolderData } from '../models/data/folderData'; +import { FolderResponse } from '../models/response/folderResponse'; +import { FolderRequest } from '../models/request/folderRequest'; + +import ApiService from './api.service'; +import ConstantsService from './constants.service'; +import CryptoService from './crypto.service'; +import UserService from './user.service'; +import UtilsService from './utils.service'; + +const Keys = { + foldersPrefix: 'folders_' +}; + +export default class FolderService { + decryptedFolderCache: any[]; + + constructor(private cryptoService: CryptoService, private userService: UserService, private i18nService: any, private apiService: ApiService) { + + } + + clearCache(): void { + this.decryptedFolderCache = null; + } + + async encrypt(model: any): Promise { + const folder = new Folder(); + folder.name = await this.cryptoService.encrypt(model.name); + return folder; + } + + async get(id:string): Promise { + const userId = await this.userService.getUserId(); + const folders = await UtilsService.getObjFromStorage>(Keys.foldersPrefix + userId); + if(folders == null || !folders.has(id)) { + return null; + } + + return new Folder(folders.get(id)); + } + + async getAll(): Promise { + const userId = await this.userService.getUserId(); + const folders = await UtilsService.getObjFromStorage>(Keys.foldersPrefix + userId); + const response:Folder[] = []; + folders.forEach((folder) => { + response.push(new Folder(folder)); + }); + return response; + } + + async getAllDecrypted(): Promise { + if (this.decryptedFolderCache != null) { + return this.decryptedFolderCache; + } + + const decFolders: any[] = [{ + id: null, + name: this.i18nService.noneFolder + }]; + + const key = await this.cryptoService.getKey(); + if(key == null) { + throw new Error('No key.'); + } + + const promises = []; + const folders = await this.getAll(); + for(const folder of folders) { + promises.push(folder.decrypt().then((f: any) => { + decFolders.push(f); + })); + } + + await Promise.all(promises); + this.decryptedFolderCache = decFolders; + return this.decryptedFolderCache; + } + + async saveWithServer (folder: Folder): Promise { + const request = new FolderRequest(folder); + + let response: FolderResponse; + if(folder.id == null) { + response = await this.apiService.postFolder(request); + folder.id = response.id; + } else { + response = await this.apiService.putFolder(folder.id, request); + } + + const userId = await this.userService.getUserId(); + const data = new FolderData(response, userId); + await this.upsert(data); + } + + async upsert(folder: FolderData | FolderData[]): Promise { + const userId = await this.userService.getUserId(); + let folders = await UtilsService.getObjFromStorage>(Keys.foldersPrefix + userId); + if(folders == null) { + folders = new Map(); + } + + if(folder instanceof FolderData) { + const f = folder as FolderData; + folders.set(f.id, f); + } else { + for(const f of (folder as FolderData[])) { + folders.set(f.id, f); + } + } + + await UtilsService.saveObjToStorage(Keys.foldersPrefix + userId, folders); + this.decryptedFolderCache = null; + } + + async replace (folders: FolderData[]): Promise { + const userId = await this.userService.getUserId(); + await UtilsService.saveObjToStorage(Keys.foldersPrefix + userId, folders); + this.decryptedFolderCache = null; + } + + async clear(userId: string): Promise { + await UtilsService.removeFromStorage(Keys.foldersPrefix + userId); + this.decryptedFolderCache = null; + } + + async delete(id: string | string[]): Promise { + const userId = await this.userService.getUserId(); + let folders = await UtilsService.getObjFromStorage>(Keys.foldersPrefix + userId); + if(folders == null) { + return; + } + + if(id instanceof String) { + const i = id as string; + folders.delete(i); + } else { + for(const i of (id as string[])) { + folders.delete(i); + } + } + + await UtilsService.saveObjToStorage(Keys.foldersPrefix + userId, folders); + this.decryptedFolderCache = null; + } + + async deleteWithServer(id: string): Promise { + await this.apiService.deleteFolder(id); + await this.delete(id); + } +}