Page MenuHomePhabricator

D7268.diff
No OneTemporary

D7268.diff

diff --git a/web/media/encryption-utils.js b/web/media/encryption-utils.js
new file mode 100644
--- /dev/null
+++ b/web/media/encryption-utils.js
@@ -0,0 +1,149 @@
+// @flow
+
+import invariant from 'invariant';
+
+import { hexToUintArray } from 'lib/media/data-utils.js';
+import { fileInfoFromData } from 'lib/media/file-utils.js';
+import type { MediaMissionFailure } from 'lib/types/media-types.js';
+import { getMessageForException } from 'lib/utils/errors.js';
+import { unpad } from 'lib/utils/pkcs7-padding.js';
+
+import * as AES from './aes-crypto-utils.js';
+
+const PADDING_THRESHOLD = 5000000; // 5MB
+
+type DecryptFileStep =
+ | {
+ +step: 'fetch_buffer',
+ +url: string,
+ +time: number,
+ +success: boolean,
+ +exceptionMessage: ?string,
+ }
+ | {
+ +step: 'decrypt_data',
+ +dataSize: number,
+ +time: number,
+ +isPadded: boolean,
+ +success: boolean,
+ +exceptionMessage: ?string,
+ }
+ | {
+ +step: 'save_blob',
+ +objectURL: ?string,
+ +mimeType: string,
+ +time: number,
+ +success: boolean,
+ +exceptionMessage: ?string,
+ };
+type DecryptionFailure =
+ | MediaMissionFailure
+ | {
+ +success: false,
+ +reason: 'decrypt_data_failed' | 'save_blob_failed',
+ };
+
+/**
+ * Fetches the encrypted media for given {@link holder}, decrypts it,
+ * and stores it in a blob. Returns the object URL of the blob.
+ *
+ * The returned object URL should be revoked when the media is no longer needed.
+ */
+async function decryptMedia(
+ holder: string,
+ encryptionKey: string,
+): Promise<{
+ steps: $ReadOnlyArray<DecryptFileStep>,
+ result: { success: true, uri: string } | DecryptionFailure,
+}> {
+ let success = true;
+ let exceptionMessage;
+ const steps: DecryptFileStep[] = [];
+
+ // Step 1 - Fetch the encrypted media and convert it to a Uint8Array
+ let data;
+ const fetchStartTime = Date.now();
+ try {
+ const response = await fetch(holder);
+ const buffer = await response.arrayBuffer();
+ data = new Uint8Array(buffer);
+ } catch (e) {
+ success = false;
+ exceptionMessage = getMessageForException(e);
+ }
+ steps.push({
+ step: 'fetch_buffer',
+ url: holder,
+ time: Date.now() - fetchStartTime,
+ success,
+ exceptionMessage,
+ });
+ if (!success || !data) {
+ return {
+ steps,
+ result: { success: false, reason: 'fetch_failed' },
+ };
+ }
+
+ // Step 2 - Decrypt the data
+ let decryptedData;
+ const decryptStartTime = Date.now();
+ try {
+ const keyBytes = hexToUintArray(encryptionKey);
+ const plaintext = await AES.decrypt(keyBytes, data);
+ decryptedData =
+ plaintext.byteLength > PADDING_THRESHOLD ? plaintext : unpad(plaintext);
+ } catch (e) {
+ success = false;
+ exceptionMessage = getMessageForException(e);
+ }
+ steps.push({
+ step: 'decrypt_data',
+ dataSize: decryptedData?.byteLength ?? -1,
+ time: Date.now() - decryptStartTime,
+ isPadded: data.byteLength > PADDING_THRESHOLD,
+ success,
+ exceptionMessage,
+ });
+ if (!success || !decryptedData) {
+ return { steps, result: { success: false, reason: 'decrypt_data_failed' } };
+ }
+
+ // Step 3 - Create a blob from the decrypted data and return it
+ const saveStartTime = Date.now();
+ const { mime } = fileInfoFromData(decryptedData);
+ if (!mime) {
+ return {
+ steps,
+ result: { success: false, reason: 'mime_check_failed', mime },
+ };
+ }
+
+ let objectURL;
+ try {
+ invariant(mime, 'mime type should be defined');
+ const decryptedBlob = new Blob([decryptedData], { type: mime });
+ objectURL = URL.createObjectURL(decryptedBlob);
+ } catch (e) {
+ success = false;
+ exceptionMessage = getMessageForException(e);
+ }
+ steps.push({
+ step: 'save_blob',
+ objectURL,
+ mimeType: mime,
+ time: Date.now() - saveStartTime,
+ success,
+ exceptionMessage,
+ });
+ if (!success || !objectURL) {
+ return {
+ steps,
+ result: { success: false, reason: 'save_blob_failed' },
+ };
+ }
+
+ return { steps, result: { success: true, uri: objectURL } };
+}
+
+export { decryptMedia };

File Metadata

Mime Type
text/plain
Expires
Sun, Dec 22, 11:18 PM (18 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2692843
Default Alt Text
D7268.diff (4 KB)

Event Timeline