diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index 628575226..cc4afb2c0 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -75,9 +75,6 @@ const ListContainer = styled.div<{columns: number}>` } `; -const PAGE_SIZE = 12; -const COLUMNS = 3; - export default function Gallery() { const router = useRouter(); const [loading, setLoading] = useState(false); diff --git a/src/services/fileService.ts b/src/services/fileService.ts index ce1e45074..a14379235 100644 --- a/src/services/fileService.ts +++ b/src/services/fileService.ts @@ -161,14 +161,74 @@ export const getPreview = async (token: string, file: file) => { } export const getFile = async (token: string, file: file) => { - const resp = await HTTPService.get( - `${ENDPOINT}/files/download/${file.id}`, - { token }, null, { responseType: 'arraybuffer' }, - ); const worker = await new CryptoWorker(); - const decrypted: any = await worker.decryptFile( - new Uint8Array(resp.data), - await worker.fromB64(file.file.decryptionHeader), - file.key); - return URL.createObjectURL(new Blob([decrypted])); + if (file.metadata.fileType === 0) { + const resp = await HTTPService.get( + `${ENDPOINT}/files/download/${file.id}`, + { token }, null, { responseType: 'arraybuffer' }, + ); + const decrypted: any = await worker.decryptFile( + new Uint8Array(resp.data), + await worker.fromB64(file.file.decryptionHeader), + file.key, + ); + return URL.createObjectURL(new Blob([decrypted])); + } else { + const source = new MediaSource(); + source.addEventListener('sourceopen', async () => { + if (!source.sourceBuffers.length) { + const sourceBuffer = source.addSourceBuffer('video/mp4; codecs="avc1.64000d,mp4a.40.2"'); + const resp = await fetch(`${ENDPOINT}/files/download/${file.id}?token=${token}`); + const reader = resp.body.getReader(); + new ReadableStream({ + async start() { + let { pullState, decryptionChunkSize, tag } = await worker.initDecryption( + await worker.fromB64(file.file.decryptionHeader), + file.key + ); + console.log(pullState, decryptionChunkSize, tag); + let data = new Uint8Array(); + // The following function handles each data chunk + function push() { + // "done" is a Boolean and value a "Uint8Array" + reader.read().then(async ({ done, value }) => { + // Is there more data to read? + if (!done) { + const buffer = new Uint8Array(data.byteLength + value.byteLength); + buffer.set(new Uint8Array(data), 0); + buffer.set(new Uint8Array(value), data.byteLength); + if (buffer.length > decryptionChunkSize) { + const fileData = buffer.slice(0, decryptionChunkSize); + const { decryptedData, newTag } = await worker.decryptChunk(fileData, pullState); + sourceBuffer.appendBuffer(decryptedData); + tag = newTag; + data = buffer.slice(decryptionChunkSize); + console.log('>', decryptionChunkSize, data.length, tag); + } else { + data = buffer; + push(); + } + } else { + console.log('end', value.length); + source.endOfStream(); + } + }); + }; + + sourceBuffer.addEventListener('updateend', () => { + console.log('appended'); + push(); + }); + + push(); + } + }); + } + }); + + source.addEventListener('sourceended', () => { + console.log('sourceend'); + }); + return URL.createObjectURL(source); + } } diff --git a/src/utils/crypto/libsodium.ts b/src/utils/crypto/libsodium.ts index e1a44c53c..1b2ae6fc2 100644 --- a/src/utils/crypto/libsodium.ts +++ b/src/utils/crypto/libsodium.ts @@ -1,4 +1,4 @@ -import sodium from 'libsodium-wrappers'; +import sodium, { StateAddress } from 'libsodium-wrappers'; const encryptionChunkSize = 4 * 1024 * 1024; @@ -33,6 +33,28 @@ export async function decryptChaCha(data: Uint8Array, header: Uint8Array, key: U return Uint8Array.from(decryptedData); } +export async function initChunkDecryption(header: Uint8Array, key: Uint8Array) { + await sodium.ready; + const pullState = sodium.crypto_secretstream_xchacha20poly1305_init_pull(header, key); + const decryptionChunkSize = + encryptionChunkSize + sodium.crypto_secretstream_xchacha20poly1305_ABYTES; + const tag = sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE; + return { pullState, decryptionChunkSize, tag }; +} + +export async function decryptChunk(data: Uint8Array, pullState: StateAddress) { + await sodium.ready; + var decryptedData = []; + // var chunkSize = decryptionChunkSize; + // if (bytesRead + chunkSize > data.length) { + // chunkSize = data.length - bytesRead; + // } + // const buffer = data.slice(bytesRead, bytesRead + chunkSize); + const pullResult = sodium.crypto_secretstream_xchacha20poly1305_pull(pullState, data); + const newTag = pullResult.tag; + return { decryptedData: pullResult.message, newTag }; +} + export async function encryptToB64(data: string, key: string) { await sodium.ready; var bKey: Uint8Array; diff --git a/src/worker/crypto.worker.js b/src/worker/crypto.worker.js index 47c2ed44f..9770f83b8 100644 --- a/src/worker/crypto.worker.js +++ b/src/worker/crypto.worker.js @@ -24,6 +24,14 @@ export class Crypto { key); } + async initDecryption(header, key) { + return libsodium.initChunkDecryption(header, key); + } + + async decryptChunk(fileData, pullState) { + return libsodium.decryptChunk(fileData, pullState); + } + async encrypt(data, key) { return libsodium.encrypt(data, key); }