diff --git a/lib/utils/services-utils.js b/lib/utils/services-utils.js --- a/lib/utils/services-utils.js +++ b/lib/utils/services-utils.js @@ -21,8 +21,18 @@ return `Bearer ${base64EncodedPayload}`; } +function createDefaultHTTPRequestHeaders(authMetadata: AuthMetadata): { + [string]: string, +} { + const authorization = createHTTPAuthorizationHeader(authMetadata); + return { + Authorization: authorization, + }; +} + export { handleHTTPResponseError, usingCommServicesAccessToken, createHTTPAuthorizationHeader, + createDefaultHTTPRequestHeaders, }; diff --git a/native/media/encrypted-image.react.js b/native/media/encrypted-image.react.js --- a/native/media/encrypted-image.react.js +++ b/native/media/encrypted-image.react.js @@ -5,6 +5,7 @@ import { MediaCacheContext } from 'lib/components/media-cache-provider.react.js'; import { connectionSelector } from 'lib/selectors/keyserver-selectors.js'; +import { IdentityClientContext } from 'lib/shared/identity-client-context.js'; import { ashoatKeyserverID } from 'lib/utils/validation-utils.js'; import { decryptBase64, fetchAndDecryptMedia } from './encryption-utils.js'; @@ -34,6 +35,10 @@ thumbHash: encryptedThumbHash, } = props; + const identityContext = React.useContext(IdentityClientContext); + invariant(identityContext, 'Identity context should be set'); + const { getAuthMetadata } = identityContext; + const mediaCache = React.useContext(MediaCacheContext); const [source, setSource] = React.useState(null); @@ -77,9 +82,15 @@ return; } - const { result } = await fetchAndDecryptMedia(blobURI, encryptionKey, { - destination: 'data_uri', - }); + const authMetadata = await getAuthMetadata(); + const { result } = await fetchAndDecryptMedia( + blobURI, + encryptionKey, + authMetadata, + { + destination: 'data_uri', + }, + ); if (isMounted) { if (result.success) { @@ -96,7 +107,7 @@ return () => { isMounted = false; }; - }, [attempt, blobURI, encryptionKey, mediaCache]); + }, [attempt, blobURI, encryptionKey, mediaCache, getAuthMetadata]); const onLoad = React.useCallback(() => { onLoadProp && onLoadProp(blobURI); 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 @@ -10,14 +10,17 @@ readableFilename, pathFromURI, } from 'lib/media/file-utils.js'; +import type { AuthMetadata } from 'lib/shared/identity-client-context.js'; import type { MediaMissionFailure, MediaMissionStep, DecryptFileMediaMissionStep, EncryptFileMediaMissionStep, } from 'lib/types/media-types.js'; +import { isBlobServiceURI } from 'lib/utils/blob-service.js'; import { getMessageForException } from 'lib/utils/errors.js'; import { pad, unpad, calculatePaddedLength } from 'lib/utils/pkcs7-padding.js'; +import { createDefaultHTTPRequestHeaders } from 'lib/utils/services-utils.js'; import { temporaryDirectoryPath } from './file-utils.js'; import { getFetchableURI } from './identifier-utils.js'; @@ -248,6 +251,7 @@ async function fetchAndDecryptMedia( blobURI: string, encryptionKey: string, + authMetadata: AuthMetadata, options: { +destination: 'file' | 'data_uri', +destinationDirectory?: string, @@ -261,10 +265,15 @@ const steps: DecryptFileMediaMissionStep[] = []; // Step 1. Fetch the file and convert it to a Uint8Array + let headers; + if (isBlobServiceURI(blobURI)) { + headers = createDefaultHTTPRequestHeaders(authMetadata); + } + const fetchStartTime = Date.now(); let data; try { - const response = await fetch(getFetchableURI(blobURI)); + const response = await fetch(getFetchableURI(blobURI), { headers }); if (!response.ok) { throw new Error(`HTTP error ${response.status}: ${response.statusText}`); } diff --git a/native/media/save-media.js b/native/media/save-media.js --- a/native/media/save-media.js +++ b/native/media/save-media.js @@ -42,6 +42,7 @@ type FetchFileInfoResult, } from './file-utils.js'; import { getMediaLibraryIdentifier } from './identifier-utils.js'; +import { commCoreModule } from '../native-modules.js'; import { displayActionResultModal } from '../navigation/action-result-modal.js'; import { requestAndroidPermission } from '../utils/android-permissions.js'; @@ -377,8 +378,10 @@ ): Promise { const steps: Array = []; if (encryptionKey) { + const authMetadata = await commCoreModule.getCommServicesAuthMetadata(); + const { steps: decryptionSteps, result: decryptionResult } = - await fetchAndDecryptMedia(inputURI, encryptionKey, { + await fetchAndDecryptMedia(inputURI, encryptionKey, authMetadata, { destination: 'file', destinationDirectory: directory, }); diff --git a/native/media/video-playback-modal.react.js b/native/media/video-playback-modal.react.js --- a/native/media/video-playback-modal.react.js +++ b/native/media/video-playback-modal.react.js @@ -16,6 +16,7 @@ import Video from 'react-native-video'; import { MediaCacheContext } from 'lib/components/media-cache-provider.react.js'; +import { IdentityClientContext } from 'lib/shared/identity-client-context.js'; import { useIsAppBackgroundedOrInactive } from 'lib/shared/lifecycle-utils.js'; import type { MediaInfo } from 'lib/types/media-types.js'; @@ -99,6 +100,10 @@ const mediaCache = React.useContext(MediaCacheContext); + const identityContext = React.useContext(IdentityClientContext); + invariant(identityContext, 'Identity context should be set'); + const { getAuthMetadata } = identityContext; + React.useEffect(() => { // skip for unencrypted videos if (!blobURI || !encryptionKey) { @@ -116,9 +121,15 @@ return; } - const { result } = await fetchAndDecryptMedia(blobURI, encryptionKey, { - destination: 'file', - }); + const authMetadata = await getAuthMetadata(); + const { result } = await fetchAndDecryptMedia( + blobURI, + encryptionKey, + authMetadata, + { + destination: 'file', + }, + ); if (result.success) { const { uri } = result; const cacheSetPromise = mediaCache?.set(blobURI, uri); @@ -142,7 +153,7 @@ filesystem.unlink(uriToDispose); } }; - }, [blobURI, encryptionKey, mediaCache]); + }, [blobURI, encryptionKey, mediaCache, getAuthMetadata]); const closeButtonX = useValue(-1); const closeButtonY = useValue(-1);