diff --git a/native/media/encryption-utils.js b/native/media/encryption-utils.js --- a/native/media/encryption-utils.js +++ b/native/media/encryption-utils.js @@ -268,6 +268,9 @@ let data; try { const response = await fetch(getFetchableURI(holder)); + if (!response.ok) { + throw new Error(`HTTP error ${response.status}: ${response.statusText}`); + } const buf = await response.arrayBuffer(); data = new Uint8Array(buf); } catch (e) { diff --git a/native/media/identifier-utils.js b/native/media/identifier-utils.js --- a/native/media/identifier-utils.js +++ b/native/media/identifier-utils.js @@ -1,5 +1,11 @@ // @flow +import { + getBlobFetchableURL, + holderFromBlobServiceURI, + isBlobServiceURI, +} from 'lib/utils/blob-service.js'; + function getCompatibleMediaURI(uri: string, ext: ?string): string { if (!ext) { return uri; @@ -42,6 +48,11 @@ } function getFetchableURI(inputURI: string): string { + if (isBlobServiceURI(inputURI)) { + const holder = holderFromBlobServiceURI(inputURI); + return getBlobFetchableURL(holder); + } + // React Native always resolves Apple's assets-library:// and FBMediaKit's // ph:// scheme as an image so that the Image component can render thumbnails // of videos. In order to force fetch() to return a blob of the video, we need diff --git a/web/media/encryption-utils.js b/web/media/encryption-utils.js --- a/web/media/encryption-utils.js +++ b/web/media/encryption-utils.js @@ -12,6 +12,7 @@ import { calculatePaddedLength, pad, unpad } from 'lib/utils/pkcs7-padding.js'; import * as AES from './aes-crypto-utils.js'; +import { fetchableMediaURI } from './media-utils.js'; const PADDING_THRESHOLD = 5000000; // 5MB @@ -139,8 +140,12 @@ // Step 1 - Fetch the encrypted media and convert it to a Uint8Array let data; const fetchStartTime = Date.now(); + const url = fetchableMediaURI(holder); try { - const response = await fetch(holder); + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP error ${response.status}: ${response.statusText}`); + } const buffer = await response.arrayBuffer(); data = new Uint8Array(buffer); } catch (e) { @@ -149,7 +154,7 @@ } steps.push({ step: 'fetch_buffer', - url: holder, + url, time: Date.now() - fetchStartTime, success, exceptionMessage, diff --git a/web/media/media-utils.js b/web/media/media-utils.js --- a/web/media/media-utils.js +++ b/web/media/media-utils.js @@ -6,6 +6,11 @@ MediaMissionStep, MediaMissionFailure, } from 'lib/types/media-types.js'; +import { + isBlobServiceURI, + getBlobFetchableURL, + holderFromBlobServiceURI, +} from 'lib/utils/blob-service.js'; import { getMessageForException } from 'lib/utils/errors.js'; import { probeFile } from './blob-utils.js'; @@ -193,4 +198,13 @@ }; } -export { preloadImage, validateFile }; +function fetchableMediaURI(uri: string): string { + if (isBlobServiceURI(uri)) { + const holder = holderFromBlobServiceURI(uri); + return getBlobFetchableURL(holder); + } + + return uri; +} + +export { preloadImage, validateFile, fetchableMediaURI }; diff --git a/web/media/multimedia-modal.react.js b/web/media/multimedia-modal.react.js --- a/web/media/multimedia-modal.react.js +++ b/web/media/multimedia-modal.react.js @@ -8,6 +8,7 @@ import type { EncryptedMediaType, MediaType } from 'lib/types/media-types.js'; import EncryptedMultimedia from './encrypted-multimedia.react.js'; +import { fetchableMediaURI } from './media-utils.js'; import css from './media.css'; type MediaInfo = @@ -42,11 +43,13 @@ let mediaModalItem; const { media } = this.props; if (media.type === 'photo') { - mediaModalItem = ; + const uri = fetchableMediaURI(media.uri); + mediaModalItem = ; } else if (media.type === 'video') { + const uri = fetchableMediaURI(media.uri); mediaModalItem = ( ); } else { diff --git a/web/media/multimedia.react.js b/web/media/multimedia.react.js --- a/web/media/multimedia.react.js +++ b/web/media/multimedia.react.js @@ -17,6 +17,7 @@ import type { MediaType, EncryptedMediaType } from 'lib/types/media-types.js'; import EncryptedMultimedia from './encrypted-multimedia.react.js'; +import { fetchableMediaURI } from './media-utils.js'; import css from './media.css'; import MultimediaModal from './multimedia-modal.react.js'; import Button from '../components/button.react.js'; @@ -118,11 +119,13 @@ // Media element is the actual image or video element (or encrypted version) let mediaElement; if (mediaSource.type === 'photo') { - mediaElement = ; + const uri = fetchableMediaURI(mediaSource.uri); + mediaElement = ; } else if (mediaSource.type === 'video') { + const uri = fetchableMediaURI(mediaSource.uri); mediaElement = ( ); } else if (