Update file decryption mechanism
This commit is contained in:
parent
3ab1d890e3
commit
01e57a212b
3 changed files with 88 additions and 73 deletions
|
@ -2,68 +2,93 @@ import { getEndpoint } from "utils/common/apiUtil";
|
|||
import HTTPService from "./HTTPService";
|
||||
import * as Comlink from "comlink";
|
||||
|
||||
const CryptoWorker:any = typeof window !== 'undefined'
|
||||
const CryptoWorker: any = typeof window !== 'undefined'
|
||||
&& Comlink.wrap(new Worker("worker/crypto.worker.js", { type: 'module' }));
|
||||
const ENDPOINT = getEndpoint();
|
||||
|
||||
export interface decryptionParams {
|
||||
encryptedKey: string;
|
||||
keyDecryptionNonce: string;
|
||||
header: string;
|
||||
nonce: string;
|
||||
};
|
||||
export interface fileData {
|
||||
id: number;
|
||||
file: {
|
||||
decryptionParams: decryptionParams;
|
||||
},
|
||||
thumbnail: {
|
||||
decryptionParams: decryptionParams;
|
||||
},
|
||||
metadata: {
|
||||
currentTime: number;
|
||||
modificationTime: number;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
title: string;
|
||||
deviceFolder: string;
|
||||
};
|
||||
src: string,
|
||||
w: number,
|
||||
h: number,
|
||||
data?: string;
|
||||
export interface fileAttribute {
|
||||
encryptedData: string;
|
||||
decryptionHeader: string;
|
||||
};
|
||||
|
||||
const getFileMetaDataUsingWorker = async (data: any, key: string) => {
|
||||
const worker = await new CryptoWorker();
|
||||
return worker.decryptMetadata({ data, key });
|
||||
export interface collection {
|
||||
id: number;
|
||||
ownerID: number;
|
||||
key: string;
|
||||
name: string;
|
||||
type: string;
|
||||
creationTime: number;
|
||||
}
|
||||
|
||||
const getFileUsingWorker = async (data: any, key: string) => {
|
||||
export interface file {
|
||||
id: number;
|
||||
collectionID: number;
|
||||
file: fileAttribute;
|
||||
thumbnail: fileAttribute;
|
||||
metadata: fileAttribute;
|
||||
encryptedKey: string;
|
||||
keyDecryptionNonce: string;
|
||||
key: Uint8Array;
|
||||
src: string;
|
||||
w: number;
|
||||
h: number;
|
||||
};
|
||||
|
||||
const getCollectionKeyUsingWorker = async (collection: any, key: Uint8Array) => {
|
||||
const worker = await new CryptoWorker();
|
||||
return worker.decryptThumbnail({ data, key });
|
||||
const collectionKey = await worker.decrypt(
|
||||
await worker.fromB64(collection.encryptedKey),
|
||||
await worker.fromB64(collection.keyDecryptionNonce),
|
||||
key);
|
||||
return {
|
||||
...collection,
|
||||
key: collectionKey
|
||||
};
|
||||
}
|
||||
|
||||
const getCollections = async (token: string, key: Uint8Array): Promise<collection[]> => {
|
||||
const resp = await HTTPService.get(`${ENDPOINT}/collections/owned`, {
|
||||
token
|
||||
});
|
||||
|
||||
const promises: Promise<collection>[] = resp.data.collections.map(
|
||||
(collection: collection) => getCollectionKeyUsingWorker(collection, key));
|
||||
return await Promise.all(promises);
|
||||
}
|
||||
|
||||
export const getFiles = async (sinceTime: string, token: string, limit: string, key: string) => {
|
||||
const resp = await HTTPService.get(`${ENDPOINT}/encrypted-files/diff`, {
|
||||
const worker = await new CryptoWorker();
|
||||
|
||||
const collections = await getCollections(token, await worker.fromB64(key));
|
||||
const collectionMap = {}
|
||||
for (const collectionIndex in collections) {
|
||||
collectionMap[collections[collectionIndex].id] = collections[collectionIndex];
|
||||
}
|
||||
const resp = await HTTPService.get(`${ENDPOINT}/files/diff`, {
|
||||
sinceTime, token, limit,
|
||||
});
|
||||
|
||||
const promises: Promise<fileData>[] = resp.data.diff.map((data) => getFileMetaDataUsingWorker(data, key));
|
||||
const decrypted = await Promise.all(promises);
|
||||
|
||||
return decrypted;
|
||||
const promises: Promise<file>[] = resp.data.diff.map(
|
||||
async (file: file) => {
|
||||
file.key = await worker.decrypt(
|
||||
await worker.fromB64(file.encryptedKey),
|
||||
await worker.fromB64(file.keyDecryptionNonce),
|
||||
collectionMap[file.collectionID].key)
|
||||
file.metadata = await worker.decryptMetadata(file);
|
||||
return file;
|
||||
});
|
||||
return await Promise.all(promises);
|
||||
}
|
||||
|
||||
export const getPreview = async (token: string, data: fileData, key: string) => {
|
||||
export const getPreview = async (token: string, file: file) => {
|
||||
const resp = await HTTPService.get(
|
||||
`${ENDPOINT}/encrypted-files/preview/${data.id}`,
|
||||
`${ENDPOINT}/files/preview/${file.id}`,
|
||||
{ token }, null, { responseType: 'arraybuffer' },
|
||||
);
|
||||
const decrypted: any = await getFileUsingWorker({
|
||||
...data,
|
||||
file: resp.data,
|
||||
}, key);
|
||||
const url = URL.createObjectURL(new Blob([decrypted.data]));
|
||||
return url;
|
||||
const worker = await new CryptoWorker();
|
||||
const decrypted: any = await worker.decryptFile(
|
||||
new Uint8Array(resp.data),
|
||||
await worker.fromB64(file.thumbnail.decryptionHeader),
|
||||
file.key);
|
||||
return URL.createObjectURL(new Blob([decrypted]));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import sodium from 'libsodium-wrappers';
|
||||
|
||||
export async function decryptChaCha(data: Uint8Array, header: Uint8Array, key: Uint8Array) {
|
||||
await sodium.ready;
|
||||
const pullState = sodium.crypto_secretstream_xchacha20poly1305_init_pull(header, key);
|
||||
const pullResult = sodium.crypto_secretstream_xchacha20poly1305_pull(pullState, data, null);
|
||||
return pullResult.message;
|
||||
}
|
||||
|
||||
export async function encryptToB64(data: string, key: string) {
|
||||
await sodium.ready;
|
||||
var bKey: Uint8Array;
|
||||
|
|
|
@ -2,36 +2,19 @@ import * as Comlink from 'comlink';
|
|||
import * as libsodium from 'utils/crypto/libsodium';
|
||||
|
||||
export class Crypto {
|
||||
async decryptMetadata(event) {
|
||||
const { data } = event;
|
||||
const key = await libsodium.decryptToB64(
|
||||
data.metadata.decryptionParams.encryptedKey,
|
||||
data.metadata.decryptionParams.keyDecryptionNonce,
|
||||
event.key);
|
||||
const metadata = await libsodium.fromB64(await libsodium.decryptToB64(
|
||||
data.metadata.encryptedData,
|
||||
data.metadata.decryptionParams.nonce,
|
||||
key));
|
||||
return {
|
||||
...data,
|
||||
metadata: JSON.parse(new TextDecoder().decode(metadata))
|
||||
};
|
||||
async decryptMetadata(file) {
|
||||
const encodedMetadata = await libsodium.decryptChaCha(
|
||||
await libsodium.fromB64(file.metadata.encryptedData),
|
||||
await libsodium.fromB64(file.metadata.decryptionHeader),
|
||||
file.key);
|
||||
return JSON.parse(new TextDecoder().decode(encodedMetadata));
|
||||
}
|
||||
|
||||
async decryptThumbnail(event) {
|
||||
const { data } = event;
|
||||
const key = await libsodium.decryptToB64(
|
||||
data.thumbnail.decryptionParams.encryptedKey,
|
||||
data.thumbnail.decryptionParams.keyDecryptionNonce,
|
||||
event.key);
|
||||
const thumbnail = await libsodium.decrypt(
|
||||
new Uint8Array(data.file),
|
||||
await libsodium.fromB64(data.thumbnail.decryptionParams.nonce),
|
||||
await libsodium.fromB64(key));
|
||||
return {
|
||||
id: data.id,
|
||||
data: thumbnail,
|
||||
};
|
||||
async decryptFile(fileData, header, key) {
|
||||
return libsodium.decryptChaCha(
|
||||
fileData,
|
||||
header,
|
||||
key);
|
||||
}
|
||||
|
||||
async encrypt(data, key) {
|
||||
|
|
Loading…
Add table
Reference in a new issue