Added web worker for parallel decryption.

This commit is contained in:
Pushkar Anand 2020-09-20 02:50:10 +05:30
parent bbe3286150
commit 8e76f6b5bd
14 changed files with 1864 additions and 29 deletions

View file

@ -1,3 +1,16 @@
const WorkerPlugin = require('worker-plugin');
module.exports = {
target: 'serverless'
target: 'serverless',
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
if (!isServer) {
config.plugins.push(
new WorkerPlugin({
// use "self" as the global object when receiving hot updates.
globalObject: 'self',
})
)
}
return config
},
};

View file

@ -14,6 +14,7 @@
"formik": "^2.1.5",
"http-proxy-middleware": "^1.0.5",
"next": "9.5.3",
"node-forge": "^0.10.0",
"react": "16.13.1",
"react-bootstrap": "^1.3.0",
"react-dom": "16.13.1",
@ -28,6 +29,7 @@
"@types/yup": "^0.29.7",
"babel-plugin-styled-components": "^1.11.1",
"next-on-netlify": "^2.4.0",
"typescript": "^4.0.2"
"typescript": "^4.0.2",
"worker-plugin": "^5.0.0"
}
}

View file

@ -0,0 +1,18 @@
import React from 'react';
import Card from 'react-bootstrap/Card';
import { fileData } from 'services/fileService';
interface IProps {
data: fileData,
}
export default function PreviewCard(props: IProps) {
const { data } = props;
return (<Card>
<Card.Body>
<div>ID: {data?.id}</div>
<div>MetaData: {JSON.stringify(data?.metadata)}</div>
</Card.Body>
</Card>);
}

View file

@ -1,34 +1,36 @@
import React, { useContext, useEffect } from 'react';
import React, { useLayoutEffect, useState } from 'react';
import { useRouter } from 'next/router';
import Container from 'components/Container';
import Card from 'react-bootstrap/Card';
import Button from 'react-bootstrap/Button';
import { clearData } from 'utils/storage/localStorage';
import { clearKeys, getKey, SESSION_KEYS } from 'utils/storage/sessionStorage';
import Spinner from 'react-bootstrap/Spinner';
import { getKey, SESSION_KEYS } from 'utils/storage/sessionStorage';
import { fileData, getFiles } from 'services/fileService';
import { getData, LS_KEYS } from 'utils/storage/localStorage';
import PreviewCard from './components/PreviewCard';
import { getActualKey } from 'utils/common/key';
export default function Gallery() {
const router = useRouter();
const [loading, setLoading] = useState(false);
const [data, setData] = useState<fileData[]>();
useEffect(() => {
useLayoutEffect(() => {
const key = getKey(SESSION_KEYS.ENCRYPTION_KEY);
const token = getData(LS_KEYS.USER).token;
if (!key) {
router.push("/");
}
const main = async () => {
setLoading(true);
const encryptionKey = await getActualKey();
const resp = await getFiles("0", token, "100", encryptionKey);
setLoading(false);
setData(resp);
};
main();
}, []);
const logout = () => {
clearKeys();
clearData();
router.push('/');
if (!data || loading) {
return <Spinner animation="border" variant="primary"/>;
}
return (<Container>
<Card className="text-center">
<Card.Body>
Imagine a very nice and secure gallery of your memories here.<br/>
<br/>
<Button block onClick={logout}>Logout</Button>
</Card.Body>
</Card>
</Container>);
return (data || []).map(item => <PreviewCard key={item.id} data={item} />);
}

View file

@ -0,0 +1,33 @@
import { getEndpoint } from "utils/common/apiUtil";
import HTTPService from "./HTTPService";
const ENDPOINT = getEndpoint();
export interface fileData {
id: number;
metadata: {
currentTimestamp: number,
},
};
const getFileDataUsingWorker = (data: any, key: string) => {
return new Promise((resolve) => {
const worker = new Worker('worker/decrypt.worker.js', { type: 'module' });
const onWorkerMessage = (event) => resolve(event.data);
worker.addEventListener('message', onWorkerMessage);
worker.postMessage({ data, key });
});
}
export const getFiles = async (sinceTimestamp: string, token: string, limit: string, key: string) => {
const resp = await HTTPService.get(`${ENDPOINT}/encrypted-files/diff`, {
sinceTimestamp, token, limit,
});
const promises: Promise<fileData>[] = resp.data.diff.map((data) => getFileDataUsingWorker(data, key));
console.time('Metadata Parsing');
const decrypted = await Promise.all(promises);
console.timeEnd('Metadata Parsing');
return decrypted;
}

View file

@ -1,9 +1,8 @@
import HTTPService from './HTTPService';
import { keyAttributes } from 'types';
import { getEndpoint } from 'utils/common/apiUtil';
const dev = process.env.NODE_ENV === 'development';
const API_ENDPOINT = process.env.NEXT_PUBLIC_ENTE_ENDPOINT || "https://api.staging.ente.io";
const ENDPOINT = !dev ? API_ENDPOINT : '/api'
const ENDPOINT = getEndpoint();
export const getOtt = (email: string) => {
return HTTPService.get(`${ENDPOINT}/users/ott`, { email })

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,21 @@
import { resolve } from 'path';
import { aescrypt } from './aescrypt';
const decrypt = (file: Uint8Array, password: String, binaryResponse: Boolean = false) => {
return new Promise((resolve, reject) => {
try {
aescrypt.decrypt(file, password, !binaryResponse, ({ data, error}) => {
if (error) {
reject(error);
}
resolve(data);
});
} catch (e) {
reject(e);
}
});
}
export default {
decrypt,
}

View file

@ -0,0 +1,6 @@
export const getEndpoint = () => {
const dev = process.env.NODE_ENV === 'development';
const apiEndpoint = process.env.NEXT_PUBLIC_ENTE_ENDPOINT || "https://api.staging.ente.io";
const endpoint = !dev ? apiEndpoint : '/api';
return endpoint;
}

9
src/utils/common/key.ts Normal file
View file

@ -0,0 +1,9 @@
import { decrypt } from "utils/crypto/aes";
import { getData, LS_KEYS } from "utils/storage/localStorage";
import { getKey, SESSION_KEYS } from "utils/storage/sessionStorage";
export const getActualKey = async () => {
const key = getKey(SESSION_KEYS.ENCRYPTION_KEY).encryptionKey;
const session = getData(LS_KEYS.SESSION);
return await decrypt(key, session.sessionKey, session.sessionIV);
}

View file

@ -13,7 +13,7 @@ export async function encrypt(data: string, key: string, iv: string) {
false, ['encrypt', 'decrypt']
);
const result = await window.crypto.subtle.encrypt(
const result = await crypto.subtle.encrypt(
{
name: "AES-CBC",
iv: base64ToUint8(iv),
@ -38,7 +38,7 @@ export async function decrypt(data: string, key: string, iv: string) {
false, ['encrypt', 'decrypt']
);
const result = await window.crypto.subtle.decrypt(
const result = await crypto.subtle.decrypt(
{
name: "AES-CBC",
iv: base64ToUint8(iv),

View file

@ -0,0 +1,22 @@
import { decrypt } from "utils/crypto/aes";
import { base64ToUint8 } from "utils/crypto/common";
import aescrypt from 'utils/aescrypt';
function decryptFile(event) {
const main = async () => {
const data = event.data.data;
const key = event.data.key;
const password = await decrypt(data.encryptedPassword, key, data.encryptedPasswordIV);
const metadata = await aescrypt.decrypt(base64ToUint8(data.encryptedMetadata), atob(password));
self.postMessage({
id: data.id,
ownerId: data.ownerId,
updationTime: data.updationTime,
password,
metadata: JSON.parse(metadata),
});
}
main();
}
self.addEventListener('message', decryptFile);

View file

@ -4,7 +4,8 @@
"lib": [
"dom",
"dom.iterable",
"esnext"
"esnext",
"webworker"
],
"allowJs": true,
"skipLibCheck": true,

View file

@ -3473,7 +3473,7 @@ loader-utils@2.0.0, loader-utils@^2.0.0:
emojis-list "^3.0.0"
json5 "^2.1.2"
loader-utils@^1.2.3:
loader-utils@^1.1.0, loader-utils@^1.2.3:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
@ -3893,6 +3893,11 @@ node-fetch@2.6.0:
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
node-forge@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==
node-gyp-build@^4.2.2:
version "4.2.3"
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.3.tgz#ce6277f853835f718829efb47db20f3e4d9c4739"
@ -5630,6 +5635,13 @@ worker-farm@^1.7.0:
dependencies:
errno "~0.1.7"
worker-plugin@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/worker-plugin/-/worker-plugin-5.0.0.tgz#113b5fe1f4a5d6a957cecd29915bedafd70bb537"
integrity sha512-AXMUstURCxDD6yGam2r4E34aJg6kW85IiaeX72hi+I1cxyaMUtrvVY6sbfpGKAj5e7f68Acl62BjQF5aOOx2IQ==
dependencies:
loader-utils "^1.1.0"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"