diff --git a/lib/shared/message-utils.js b/lib/shared/message-utils.js --- a/lib/shared/message-utils.js +++ b/lib/shared/message-utils.js @@ -255,7 +255,7 @@ let allMediaArePhotos = true; const photoMedia = []; for (const singleMedia of input.media) { - if (singleMedia.type === 'video') { + if (singleMedia.type !== 'photo') { allMediaArePhotos = false; break; } else { diff --git a/lib/types/media-types.js b/lib/types/media-types.js --- a/lib/types/media-types.js +++ b/lib/types/media-types.js @@ -19,6 +19,15 @@ +localMediaSelection?: NativeMediaSelection, }; +export type EncryptedImage = { + +id: string, + // a media URI for keyserver uploads / blob holder for Blob service uploads + +holder: string, + +encryptionKey: string, + +type: 'encrypted_photo', + +dimensions: Dimensions, +}; + export type Video = { +id: string, +uri: string, @@ -31,7 +40,20 @@ +localMediaSelection?: NativeMediaSelection, }; -export type Media = Image | Video; +export type EncryptedVideo = { + +id: string, + // a media URI for keyserver uploads / blob holder for Blob service uploads + +holder: string, + +encryptionKey: string, + +type: 'encrypted_video', + +dimensions: Dimensions, + +loop?: boolean, + +thumbnailID: string, + +thumbnailHolder: string, + +thumbnailEncryptionKey: string, +}; + +export type Media = Image | Video | EncryptedImage | EncryptedVideo; export type ClientDBMediaInfo = { +id: string, @@ -55,6 +77,14 @@ | { ...Video, +index: number, + } + | { + ...EncryptedImage, + +index: number, + } + | { + ...EncryptedVideo, + +index: number, }; export type UploadMultimediaResult = { diff --git a/lib/types/messages/media.js b/lib/types/messages/media.js --- a/lib/types/messages/media.js +++ b/lib/types/messages/media.js @@ -60,15 +60,16 @@ media: $ReadOnlyArray, ): $ReadOnlyArray { return media.map(m => { - if (m.type === 'photo') { + if (m.type === 'photo' || m.type === 'encrypted_photo') { return { type: 'photo', uploadID: m.id }; - } else { + } else if (m.type === 'video' || m.type === 'encrypted_video') { return { type: 'video', uploadID: m.id, thumbnailUploadID: m.thumbnailID, }; } + throw new Error(`Unexpected media type: ${m.type}`); }); } diff --git a/lib/utils/message-ops-utils.js b/lib/utils/message-ops-utils.js --- a/lib/utils/message-ops-utils.js +++ b/lib/utils/message-ops-utils.js @@ -1,5 +1,6 @@ // @flow +import invariant from 'invariant'; import _keyBy from 'lodash/fp/keyBy.js'; import { messageID } from '../shared/message-utils.js'; @@ -25,6 +26,10 @@ ): $ReadOnlyArray { const clientDBMediaInfos = []; for (const m of media) { + invariant( + m.type === 'photo' || m.type === 'video', + 'unimplemented media type', + ); clientDBMediaInfos.push({ id: m.id, uri: m.uri, diff --git a/native/input/input-state-container.react.js b/native/input/input-state-container.react.js --- a/native/input/input-state-container.react.js +++ b/native/input/input-state-container.react.js @@ -1156,6 +1156,11 @@ const updateMedia = (media: $ReadOnlyArray): T[] => media.map(singleMedia => { + invariant( + singleMedia.type === 'photo' || singleMedia.type === 'video', + 'Retry selection must be unencrypted', + ); + let updatedMedia = singleMedia; const oldMediaID = updatedMedia.id; diff --git a/native/media/image-modal.react.js b/native/media/image-modal.react.js --- a/native/media/image-modal.react.js +++ b/native/media/image-modal.react.js @@ -1142,6 +1142,11 @@ save = () => { const { mediaInfo, item } = this.props.route.params; + invariant( + mediaInfo.type === 'photo' || mediaInfo.type === 'video', + 'saving media of type ' + mediaInfo.type + ' is not supported', + ); + const { id: uploadID, uri } = mediaInfo; const { id: messageServerID, localID: messageLocalID } = item.messageInfo; const ids = { uploadID, messageServerID, messageLocalID }; diff --git a/native/media/multimedia.react.js b/native/media/multimedia.react.js --- a/native/media/multimedia.react.js +++ b/native/media/multimedia.react.js @@ -30,6 +30,12 @@ constructor(props: Props) { super(props); + + invariant( + props.mediaInfo.type === 'image' || props.mediaInfo.type === 'video', + ' supports only unencrypted images and videos', + ); + this.state = { currentURI: props.mediaInfo.type === 'video' @@ -60,6 +66,11 @@ componentDidUpdate(prevProps: Props, prevState: State) { const { inputState } = this; + invariant( + this.props.mediaInfo.type === 'image' || + this.props.mediaInfo.type === 'video', + ' supports only unencrypted images and videos', + ); const newURI = this.props.mediaInfo.type === 'video' diff --git a/web/chat/multimedia-message.react.js b/web/chat/multimedia-message.react.js --- a/web/chat/multimedia-message.react.js +++ b/web/chat/multimedia-message.react.js @@ -35,6 +35,11 @@ const pendingUploads = localID ? inputState.assignedUploads[localID] : null; const multimedia = []; for (const singleMedia of media) { + invariant( + singleMedia.type === 'photo' || singleMedia.type === 'video', + ' supports only unencrypted images and videos', + ); + const pendingUpload = pendingUploads ? pendingUploads.find(upload => upload.localID === singleMedia.id) : null; diff --git a/web/modals/threads/gallery/thread-settings-media-gallery.react.js b/web/modals/threads/gallery/thread-settings-media-gallery.react.js --- a/web/modals/threads/gallery/thread-settings-media-gallery.react.js +++ b/web/modals/threads/gallery/thread-settings-media-gallery.react.js @@ -1,5 +1,6 @@ // @flow +import invariant from 'invariant'; import * as React from 'react'; import { fetchThreadMedia } from 'lib/actions/thread-actions.js'; @@ -48,6 +49,10 @@ const onClick = React.useCallback( (media: Media) => { + invariant( + media.type === 'photo' || media.type === 'video', + ' supports only unencrypted images and videos', + ); pushModal(); }, [pushModal],