made requested changes to collectionService

This commit is contained in:
Abhinav-grd 2021-02-08 22:32:28 +05:30
parent 5250b97891
commit bf6dc99c5c

View file

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