From 43fb444900bbcdaeb9f45d2fdce37aae9ea441e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Klocek?= Date: Thu, 29 Jun 2023 15:10:34 +0200 Subject: [PATCH] [lib][keyserver] Use blobURI based on client version Summary: The last part of [[ https://linear.app/comm/issue/ENG-3966/rename-the-holder-message-field-to-bloburi | ENG-3966 ]]. Details are described in the comments (regarding pt. 4) This diff introduces a utility function, that constructs a multimedia message based on client version. Depends on D8373 Test Plan: CI should finally pass here. Tested as follows: - Enabled blob service uploads on both web and native - Added some console logs to `encryptedMediaBlobURI()` to display if there's a `holder` or `blobURI`. - On keyserver side, there should always be `blobURI`. - The same on web (dev console) - On native, there should be old format (`holder`) when `minCodeVersion` is set to something not yet released (`FUTURE_CODE_VERSION`) and use `blobURI` otherwise. Also tested the following: - Uploading and displaying encrypted media on Web (both video and images) - Uploading and displaying encrypted media on Native (both video and images) - Displaying thread media gallery media on both web and native Reviewers: ashoat, atul Reviewed By: ashoat Subscribers: tomek Differential Revision: https://phab.comm.dev/D8374 --- keyserver/src/fetchers/upload-fetchers.js | 14 ++--- lib/media/media-utils.js | 54 +++++++++++++++++++ .../messages/multimedia-message-spec.js | 28 ++++++---- 3 files changed, 78 insertions(+), 18 deletions(-) diff --git a/keyserver/src/fetchers/upload-fetchers.js b/keyserver/src/fetchers/upload-fetchers.js index a779a4f562..f6144f240d 100644 --- a/keyserver/src/fetchers/upload-fetchers.js +++ b/keyserver/src/fetchers/upload-fetchers.js @@ -139,7 +139,7 @@ function imagesFromRow(row: Object): Image | EncryptedImage { return { id, type: 'encrypted_photo', - holder: uri, + blobURI: uri, dimensions, thumbHash, encryptionKey: uploadExtra.encryptionKey, @@ -223,7 +223,7 @@ async function fetchMediaForThread( return { type: 'encrypted_photo', id: uploadID.toString(), - holder: uri, + blobURI: uri, encryptionKey, dimensions, thumbHash, @@ -254,11 +254,11 @@ async function fetchMediaForThread( return { type: 'encrypted_video', id: uploadID.toString(), - holder: uri, + blobURI: uri, encryptionKey, dimensions, thumbnailID, - thumbnailHolder: thumbnailURI, + thumbnailBlobURI: thumbnailURI, thumbnailEncryptionKey, thumbnailThumbHash, }; @@ -334,7 +334,7 @@ function constructMediaFromMediaMessageContentsAndUploadRows( media.push({ type: 'encrypted_photo', id: primaryUploadID, - holder: primaryUploadURI, + blobURI: primaryUploadURI, encryptionKey, dimensions, thumbHash, @@ -367,11 +367,11 @@ function constructMediaFromMediaMessageContentsAndUploadRows( const video = { type: 'encrypted_video', id: primaryUploadID, - holder: primaryUploadURI, + blobURI: primaryUploadURI, encryptionKey, dimensions, thumbnailID: thumbnailUploadID, - thumbnailHolder: thumbnailUploadURI, + thumbnailBlobURI: thumbnailUploadURI, thumbnailEncryptionKey: thumbnailUploadExtra.encryptionKey, thumbnailThumbHash, }; diff --git a/lib/media/media-utils.js b/lib/media/media-utils.js index 9faeadfcd7..a2ed4507ec 100644 --- a/lib/media/media-utils.js +++ b/lib/media/media-utils.js @@ -2,6 +2,11 @@ import invariant from 'invariant'; +import { + FUTURE_CODE_VERSION, + hasMinCodeVersion, +} from '../shared/version-utils.js'; +import type { PlatformDetails } from '../types/device-types.js'; import type { EncryptedImage, EncryptedVideo, @@ -11,6 +16,7 @@ import type { MultimediaMessageInfo, RawMultimediaMessageInfo, } from '../types/message-types.js'; +import type { RawMediaMessageInfo } from '../types/messages/media.js'; import { isBlobServiceURI, getBlobFetchableURL, @@ -56,6 +62,53 @@ function isMediaBlobServiceHosted(media: Media): boolean { ); } +/** Clients before FUTURE_CODE_VERSION understand only `holder` + * and `thumbnailHolder` fields, while newer clients understand `blobURI` + * and `thumbnailBlobURI`. This function formats the multimedia message + * to be understandable by clients based on their version + */ +function versionSpecificMediaMessageFormat( + rawMessageInfo: RawMediaMessageInfo, + platformDetails: ?PlatformDetails, +): RawMediaMessageInfo { + const isBlobURISupported = hasMinCodeVersion(platformDetails, { + native: FUTURE_CODE_VERSION, + }); + const media = rawMessageInfo.media.map(singleMedia => { + if (singleMedia.type === 'photo' || singleMedia.type === 'video') { + return singleMedia; + } + + if (singleMedia.type === 'encrypted_photo') { + const { blobURI, holder, ...photoMedia } = singleMedia; + const mediaURI = encryptedMediaBlobURI(singleMedia); + return isBlobURISupported + ? { ...photoMedia, blobURI: mediaURI } + : { ...photoMedia, holder: mediaURI }; + } + + // encrypted_video + const { + blobURI, + holder, + thumbnailBlobURI, + thumbnailHolder, + ...videoMedia + } = singleMedia; + const mediaURI = encryptedMediaBlobURI(singleMedia); + const thumbnailURI = encryptedVideoThumbnailBlobURI(singleMedia); + + return isBlobURISupported + ? { ...videoMedia, blobURI: mediaURI, thumbnailBlobURI: thumbnailURI } + : { ...videoMedia, holder: mediaURI, thumbnailHolder: thumbnailURI }; + }); + + return { + ...rawMessageInfo, + media, + }; +} + function fetchableMediaURI(uri: string): string { if (isBlobServiceURI(uri)) { const blobHash = blobHashFromBlobServiceURI(uri); @@ -107,6 +160,7 @@ export { multimediaMessagePreview, isLocalUploadID, isMediaBlobServiceHosted, + versionSpecificMediaMessageFormat, getNextLocalUploadID, fetchableMediaURI, encryptedMediaBlobURI, diff --git a/lib/shared/messages/multimedia-message-spec.js b/lib/shared/messages/multimedia-message-spec.js index f94a32c678..a0447c5176 100644 --- a/lib/shared/messages/multimedia-message-spec.js +++ b/lib/shared/messages/multimedia-message-spec.js @@ -10,6 +10,7 @@ import { } from './message-spec.js'; import { joinResult } from './utils.js'; import { + versionSpecificMediaMessageFormat, isMediaBlobServiceHosted, contentStringForMediaArray, multimediaMessagePreview, @@ -214,10 +215,15 @@ export const multimediaMessageSpec: MessageSpec< return rawMessageInfo; } - const containsBlobServiceMedia = rawMessageInfo.media.some( + const messageInfo = versionSpecificMediaMessageFormat( + rawMessageInfo, + platformDetails, + ); + + const containsBlobServiceMedia = messageInfo.media.some( isMediaBlobServiceHosted, ); - const containsEncryptedMedia = rawMessageInfo.media.some( + const containsEncryptedMedia = messageInfo.media.some( media => media.type === 'encrypted_photo' || media.type === 'encrypted_video', ); @@ -226,28 +232,28 @@ export const multimediaMessageSpec: MessageSpec< !containsEncryptedMedia && hasMinCodeVersion(platformDetails, { native: 158 }) ) { - return rawMessageInfo; + return messageInfo; } if ( !containsBlobServiceMedia && hasMinCodeVersion(platformDetails, { native: 205 }) ) { - return rawMessageInfo; + return messageInfo; } if (hasMinCodeVersion(platformDetails, { native: FUTURE_CODE_VERSION })) { - return rawMessageInfo; + return messageInfo; } - const { id } = rawMessageInfo; + const { id } = messageInfo; invariant(id !== null && id !== undefined, 'id should be set on server'); return { type: messageTypes.UNSUPPORTED, id, - threadID: rawMessageInfo.threadID, - creatorID: rawMessageInfo.creatorID, - time: rawMessageInfo.time, - robotext: multimediaMessagePreview(rawMessageInfo), - unsupportedMessageInfo: rawMessageInfo, + threadID: messageInfo.threadID, + creatorID: messageInfo.creatorID, + time: messageInfo.time, + robotext: multimediaMessagePreview(messageInfo), + unsupportedMessageInfo: messageInfo, }; },