From bf6dc99c5c6be87b85fe0dd3967d0fb4c1a4c809 Mon Sep 17 00:00:00 2001 From: Abhinav-grd Date: Mon, 8 Feb 2021 22:32:28 +0530 Subject: [PATCH] made requested changes to collectionService --- src/services/collectionService.ts | 294 +++++++++++++++++++----------- 1 file changed, 191 insertions(+), 103 deletions(-) diff --git a/src/services/collectionService.ts b/src/services/collectionService.ts index d1258d394..2982a5868 100644 --- a/src/services/collectionService.ts +++ b/src/services/collectionService.ts @@ -1,26 +1,28 @@ -import { getEndpoint } from "utils/common/apiUtil"; -import { getData, LS_KEYS } from "utils/storage/localStorage"; -import { file, user, getFiles } from "./fileService"; +import { getEndpoint } from 'utils/common/apiUtil'; +import { getData, LS_KEYS } from 'utils/storage/localStorage'; +import { file, user, getFiles } from './fileService'; import localForage from 'localforage'; -import HTTPService from "./HTTPService"; +import HTTPService from './HTTPService'; import * as Comlink from 'comlink'; -import { keyEncryptionResult } from "./uploadService"; -import { getActualKey, getToken } from "utils/common/key"; - +import { keyEncryptionResult } from './uploadService'; +import { getActualKey, getToken } from 'utils/common/key'; const CryptoWorker: any = typeof window !== 'undefined' && Comlink.wrap(new Worker('worker/crypto.worker.js', { type: 'module' })); const ENDPOINT = getEndpoint(); - enum CollectionType { - folder = "folder", - favorites = "favorites", - album = "album", + folder = 'folder', + favorites = 'favorites', + album = 'album', } +const COLLECTION_UPDATION_TIME = 'collection-updation-time'; +const FAV_COLLECTION = 'fav-collection'; +const COLLECTIONS = 'collections'; + export interface collection { id: number; owner: user; @@ -29,7 +31,7 @@ export interface collection { encryptedName?: string; nameDecryptionNonce?: string; type: string; - attributes: collectionAttributes + attributes: collectionAttributes; sharees: user[]; updationTime: number; encryptedKey: string; @@ -39,16 +41,18 @@ export interface collection { interface collectionAttributes { encryptedPath?: string; - pathDecryptionNonce?: string -}; + pathDecryptionNonce?: string; +} export interface collectionLatestFile { - collection: collection + collection: collection; file: file; } - -const getCollectionSecrets = async (collection: collection, masterKey: string) => { +const getCollectionSecrets = async ( + collection: collection, + masterKey: string +) => { const worker = await new CryptoWorker(); const userID = getData(LS_KEYS.USER).id; let decryptedKey: string; @@ -58,7 +62,6 @@ const getCollectionSecrets = async (collection: collection, masterKey: string) = collection.keyDecryptionNonce, masterKey ); - } else { const keyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES); const secretKey = await worker.decryptB64( @@ -72,10 +75,13 @@ const getCollectionSecrets = async (collection: collection, masterKey: string) = secretKey ); } - collection.name = collection.name || await worker.decryptString( - collection.encryptedName, - collection.nameDecryptionNonce, - decryptedKey); + collection.name = + collection.name || + (await worker.decryptString( + collection.encryptedName, + collection.nameDecryptionNonce, + decryptedKey + )); return { ...collection, key: decryptedKey, @@ -88,50 +94,66 @@ const getCollections = async ( key: string ): Promise => { try { - const resp = await HTTPService.get(`${ENDPOINT}/collections`, { - sinceTime: sinceTime, - }, { 'X-Auth-Token': token, }); + const resp = await HTTPService.get( + `${ENDPOINT}/collections`, + { + sinceTime: sinceTime, + }, + { 'X-Auth-Token': token } + ); const promises: Promise[] = resp.data.collections.map( (collection: collection) => getCollectionSecrets(collection, key) ); return await Promise.all(promises); - } - catch (e) { - console.log("getCollections failed- " + e); + } catch (e) { + console.log('getCollections failed- ' + e); } }; export const getLocalCollections = async (): Promise => { - const collections = await localForage.getItem('collections') as collection[] ?? []; + const collections = + ((await localForage.getItem(COLLECTIONS)) as collection[]) ?? []; return collections; -} +}; + export const syncCollections = async (token: string, key: string) => { const localCollections = await getLocalCollections(); - const lastCollectionUpdateTime = await localForage.getItem('collection-update-time')??"0"; - const updatedCollections = await getCollections(token, lastCollectionUpdateTime, key) || []; - - if(updatedCollections.length==0){ + const lastCollectionUpdationTime = + (await localForage.getItem(COLLECTION_UPDATION_TIME)) ?? '0'; + const updatedCollections = + (await getCollections(token, lastCollectionUpdationTime, key)) || []; + + if (updatedCollections.length == 0) { return localCollections; } - const favCollection = await localForage.getItem('fav-collection') as collection[] ?? updatedCollections.filter(collection => collection.type === CollectionType.favorites); - const allCollectionsInstances = [...localCollections, ...updatedCollections]; + setLocalFavoriteCollection(updatedCollections); + const allCollectionsInstances = [ + ...localCollections, + ...updatedCollections, + ]; var latestCollectionsInstances = new Map(); allCollectionsInstances.forEach((collection) => { - if (!latestCollectionsInstances.has(collection.id) || latestCollectionsInstances.get(collection.id).updationTime < collection.updationTime) { + if ( + !latestCollectionsInstances.has(collection.id) || + latestCollectionsInstances.get(collection.id).updationTime < + collection.updationTime + ) { latestCollectionsInstances.set(collection.id, collection); } }); - let collections = [],updationTime= await localForage.getItem('collection-update-time'); + let collections = [], + updationTime = await localForage.getItem( + COLLECTION_UPDATION_TIME + ); for (const [_, collection] of latestCollectionsInstances) { - if (!collection.isDeleted){ + if (!collection.isDeleted) { collections.push(collection); - updationTime=Math.max(updationTime,collection.updationTime); + updationTime = Math.max(updationTime, collection.updationTime); } } - await localForage.setItem('fav-collection', favCollection); - await localForage.setItem('collection-update-time',updationTime); - await localForage.setItem('collections', collections); + await localForage.setItem(COLLECTION_UPDATION_TIME, updationTime); + await localForage.setItem(COLLECTIONS, collections); return collections; }; @@ -142,40 +164,61 @@ export const getCollectionLatestFile = ( const latestFile = new Map(); const collectionMap = new Map(); - collections.forEach(collection => collectionMap.set(Number(collection.id), collection)); - files.forEach(file => { + collections.forEach((collection) => + collectionMap.set(Number(collection.id), collection) + ); + files.forEach((file) => { if (!latestFile.has(file.collectionID)) { - latestFile.set(file.collectionID, file) + latestFile.set(file.collectionID, file); } }); let allCollectionLatestFile: collectionLatestFile[] = []; for (const [collectionID, file] of latestFile) { - allCollectionLatestFile.push({ collection: collectionMap.get(collectionID), file }); + allCollectionLatestFile.push({ + collection: collectionMap.get(collectionID), + file, + }); } return allCollectionLatestFile; -} +}; export const getFavItemIds = async (files: file[]): Promise> => { + let favCollection = await localForage.getItem(FAV_COLLECTION); + if (!favCollection) return new Set(); - let favCollection: collection = (await localForage.getItem('fav-collection'))[0]; - if (!favCollection) - return new Set(); - - return new Set(files.filter(file => file.collectionID === Number(favCollection.id)).map((file): number => file.id)); -} + return new Set( + files + .filter((file) => file.collectionID === Number(favCollection.id)) + .map((file): number => file.id) + ); +}; export const createAlbum = async (albumName: string) => { return AddCollection(albumName, CollectionType.album); -} +}; - -export const AddCollection = async (collectionName: string, type: CollectionType) => { +export const AddCollection = async ( + collectionName: string, + type: CollectionType +) => { const worker = await new CryptoWorker(); const encryptionKey = await getActualKey(); const token = getToken(); const collectionKey: string = await worker.generateMasterKey(); - const { encryptedData: encryptedKey, nonce: keyDecryptionNonce }: keyEncryptionResult = await worker.encryptToB64(collectionKey, encryptionKey); - const { encryptedData: encryptedName, nonce: nameDecryptionNonce }: keyEncryptionResult = await worker.encryptToB64(collectionName, collectionKey); + const { + encryptedData: encryptedKey, + nonce: keyDecryptionNonce, + }: keyEncryptionResult = await worker.encryptToB64( + collectionKey, + encryptionKey + ); + const { + encryptedData: encryptedName, + nonce: nameDecryptionNonce, + }: keyEncryptionResult = await worker.encryptToB64( + collectionName, + collectionKey + ); const newCollection: collection = { id: null, owner: null, @@ -187,76 +230,121 @@ export const AddCollection = async (collectionName: string, type: CollectionType attributes: {}, sharees: null, updationTime: null, - isDeleted: false + isDeleted: false, }; - let createdCollection: collection = await createCollection(newCollection, token); - createdCollection = await getCollectionSecrets(createdCollection, encryptionKey); + let createdCollection: collection = await createCollection( + newCollection, + token + ); + createdCollection = await getCollectionSecrets( + createdCollection, + encryptionKey + ); return createdCollection; -} +}; -const createCollection = async (collectionData: collection, token: string): Promise => { +const createCollection = async ( + collectionData: collection, + token: string +): Promise => { try { - const response = await HTTPService.post(`${ENDPOINT}/collections`, collectionData, null, { 'X-Auth-Token': token }); + const response = await HTTPService.post( + `${ENDPOINT}/collections`, + collectionData, + null, + { 'X-Auth-Token': token } + ); return response.data.collection; } catch (e) { - console.log("create Collection failed " + e); + console.log('create Collection failed ' + e); } -} +}; export const addToFavorites = async (file: file) => { - let favCollection: collection = (await localForage.getItem('fav-collection'))[0]; + let favCollection: collection = await localForage.getItem( + FAV_COLLECTION + ); if (!favCollection) { - favCollection = await AddCollection("Favorites", CollectionType.favorites); - await localForage.setItem('fav-collection', favCollection); + favCollection = await AddCollection( + 'Favorites', + CollectionType.favorites + ); + await localForage.setItem(FAV_COLLECTION, favCollection); } - await addtoCollection(favCollection, [file]) -} + await addtoCollection(favCollection, [file]); +}; export const removeFromFavorites = async (file: file) => { - let favCollection: collection = (await localForage.getItem('fav-collection'))[0]; - await removeFromCollection(favCollection, [file]) -} + let favCollection: collection = await localForage.getItem(FAV_COLLECTION); + await removeFromCollection(favCollection, [file]); +}; const addtoCollection = async (collection: collection, files: file[]) => { try { const params = new Object(); const worker = await new CryptoWorker(); const token = getToken(); - params["collectionID"] = collection.id; - await Promise.all(files.map(async file => { - file.collectionID = Number(collection.id); - const newEncryptedKey: keyEncryptionResult = await worker.encryptToB64(file.key, collection.key); - file.encryptedKey = newEncryptedKey.encryptedData; - file.keyDecryptionNonce = newEncryptedKey.nonce; - if (params["files"] == undefined) { - params["files"] = []; - } - params["files"].push({ - id: file.id, - encryptedKey: file.encryptedKey, - keyDecryptionNonce: file.keyDecryptionNonce + params['collectionID'] = collection.id; + await Promise.all( + files.map(async (file) => { + file.collectionID = Number(collection.id); + const newEncryptedKey: keyEncryptionResult = await worker.encryptToB64( + file.key, + collection.key + ); + file.encryptedKey = newEncryptedKey.encryptedData; + file.keyDecryptionNonce = newEncryptedKey.nonce; + if (params['files'] == undefined) { + params['files'] = []; + } + params['files'].push({ + id: file.id, + encryptedKey: file.encryptedKey, + keyDecryptionNonce: file.keyDecryptionNonce, + }); + return file; }) - return file; - })); - await HTTPService.post(`${ENDPOINT}/collections/add-files`, params, null, { 'X-Auth-Token': token }); + ); + await HTTPService.post( + `${ENDPOINT}/collections/add-files`, + params, + null, + { 'X-Auth-Token': token } + ); } catch (e) { - console.log("Add to collection Failed " + e); + console.log('Add to collection Failed ' + e); } -} +}; const removeFromCollection = async (collection: collection, files: file[]) => { try { const params = new Object(); const token = getToken(); - params["collectionID"] = collection.id; - await Promise.all(files.map(async file => { - if (params["fileIDs"] == undefined) { - params["fileIDs"] = []; - } - params["fileIDs"].push(file.id); - })); - await HTTPService.post(`${ENDPOINT}/collections/remove-files`, params, null, { 'X-Auth-Token': token }); + params['collectionID'] = collection.id; + await Promise.all( + files.map(async (file) => { + if (params['fileIDs'] == undefined) { + params['fileIDs'] = []; + } + params['fileIDs'].push(file.id); + }) + ); + await HTTPService.post( + `${ENDPOINT}/collections/remove-files`, + params, + null, + { 'X-Auth-Token': token } + ); } catch (e) { - console.log("remove from collection failed " + e); + console.log('remove from collection failed ' + e); } -} +}; +const setLocalFavoriteCollection = async (collections: collection[]) => { + const localFavCollection = await localForage.getItem(FAV_COLLECTION); + if (localFavCollection) return; + const favCollection = collections.filter( + (collection) => collection.type == CollectionType.favorites + ); + if (favCollection.length > 0) + await localForage.setItem(FAV_COLLECTION, favCollection[0]); +};