diff --git a/keyserver/src/fetchers/thread-fetchers.js b/keyserver/src/fetchers/thread-fetchers.js --- a/keyserver/src/fetchers/thread-fetchers.js +++ b/keyserver/src/fetchers/thread-fetchers.js @@ -18,7 +18,7 @@ } from 'lib/types/thread-types.js'; import { ServerError } from 'lib/utils/errors.js'; -import { getUploadURL } from './upload-fetchers.js'; +import { getUploadURL, makeUploadURI } from './upload-fetchers.js'; import { dbQuery, SQL, mergeAndConditions } from '../database/database.js'; import type { SQLStatementType } from '../database/types.js'; import type { Viewer } from '../session/viewer.js'; @@ -113,7 +113,7 @@ t.source_message, t.replies_count, t.avatar, t.pinned_count, m.user, m.role, m.permissions, m.subscription, m.last_read_message < m.last_message AS unread, m.sender, - up.id AS upload_id, up.secret AS upload_secret + up.id AS upload_id, up.secret AS upload_secret, up.extra AS upload_extra ` .append(primaryFetchClause) .append( @@ -158,11 +158,15 @@ if (threadsRow.avatar) { const avatar: AvatarDBContent = JSON.parse(threadsRow.avatar); let clientAvatar: ?ClientAvatar; - if (avatar && avatar.type !== 'image') { + if ( + avatar && + avatar.type !== 'image' && + avatar.type !== 'encrypted-image' + ) { clientAvatar = avatar; } else if ( avatar && - avatar.type === 'image' && + (avatar.type === 'image' || avatar.type === 'encrypted-image') && threadsRow.upload_id && threadsRow.upload_secret ) { @@ -171,10 +175,24 @@ uploadID === avatar.uploadID, `uploadID of upload should match uploadID of image avatar`, ); - clientAvatar = { - type: 'image', - uri: getUploadURL(uploadID, threadsRow.upload_secret), - }; + if (avatar.type === 'encrypted-image' && threadsRow.upload_extra) { + const uploadExtra = JSON.parse(threadsRow.upload_extra); + clientAvatar = { + type: 'encrypted-image', + blobURI: makeUploadURI( + uploadExtra.blobHash, + uploadID, + threadsRow.upload_secret, + ), + encryptionKey: uploadExtra.encryptionKey, + thumbHash: uploadExtra.thumbHash, + }; + } else { + clientAvatar = { + type: 'image', + uri: getUploadURL(uploadID, threadsRow.upload_secret), + }; + } } threadInfos[threadID] = { diff --git a/keyserver/src/fetchers/user-fetchers.js b/keyserver/src/fetchers/user-fetchers.js --- a/keyserver/src/fetchers/user-fetchers.js +++ b/keyserver/src/fetchers/user-fetchers.js @@ -22,7 +22,7 @@ } from 'lib/types/user-types.js'; import { ServerError } from 'lib/utils/errors.js'; -import { getUploadURL } from './upload-fetchers.js'; +import { getUploadURL, makeUploadURI } from './upload-fetchers.js'; import { dbQuery, SQL } from '../database/database.js'; import type { Viewer } from '../session/viewer.js'; @@ -35,7 +35,7 @@ const query = SQL` SELECT u.id, u.username, u.avatar, - up.id AS upload_id, up.secret AS upload_secret + up.id AS upload_id, up.secret AS upload_secret, up.extra AS upload_extra FROM users u LEFT JOIN uploads up ON up.container = u.id @@ -49,11 +49,15 @@ const avatar: ?AvatarDBContent = row.avatar ? JSON.parse(row.avatar) : null; let clientAvatar: ?ClientAvatar; - if (avatar && avatar.type !== 'image') { + if ( + avatar && + avatar.type !== 'image' && + avatar.type !== 'encrypted-image' + ) { clientAvatar = avatar; } else if ( avatar && - avatar.type === 'image' && + (avatar.type === 'image' || avatar.type === 'encrypted-image') && row.upload_id && row.upload_secret ) { @@ -62,10 +66,24 @@ uploadID === avatar.uploadID, 'uploadID of upload should match uploadID of image avatar', ); - clientAvatar = { - type: 'image', - uri: getUploadURL(uploadID, row.upload_secret), - }; + if (avatar.type === 'encrypted-image' && row.upload_extra) { + const uploadExtra = JSON.parse(row.upload_extra); + clientAvatar = { + type: 'encrypted-image', + blobURI: makeUploadURI( + uploadExtra.blobHash, + uploadID, + row.upload_secret, + ), + encryptionKey: uploadExtra.encryptionKey, + thumbHash: uploadExtra.thumbHash, + }; + } else { + clientAvatar = { + type: 'image', + uri: getUploadURL(uploadID, row.upload_secret), + }; + } } userInfos[id] = clientAvatar @@ -106,8 +124,8 @@ const query = SQL` SELECT ru.user1, ru.user2, u.username, u.avatar, ru.status AS undirected_status, rd1.status AS user1_directed_status, rd2.status AS user2_directed_status, - up1.id AS user1_upload_id, up1.secret AS user1_upload_secret, - up2.id AS user2_upload_id, up2.secret AS user2_upload_secret + up1.id AS user1_upload_id, up1.secret AS user1_upload_secret, up1.extra AS user1_upload_extra, + up2.id AS user2_upload_id, up2.secret AS user2_upload_secret, up2.extra AS user2_upload_extra FROM relationships_undirected ru LEFT JOIN relationships_directed rd1 ON rd1.user1 = ru.user1 AND rd1.user2 = ru.user2 @@ -135,8 +153,8 @@ CAST(NULL AS UNSIGNED) AS undirected_status, CAST(NULL AS UNSIGNED) AS user1_directed_status, CAST(NULL AS UNSIGNED) AS user2_directed_status, - up.id AS user1_upload_id, up.secret AS user1_upload_secret, - NULL AS user2_upload_id, NULL AS user2_upload_secret + up.id AS user1_upload_id, up.secret AS user1_upload_secret, up.extra AS user1_upload_extra, + NULL AS user2_upload_id, NULL AS user2_upload_secret, NULL AS user2_upload_extra FROM users u LEFT JOIN uploads up ON up.container = u.id @@ -153,11 +171,15 @@ const avatar: ?AvatarDBContent = row.avatar ? JSON.parse(row.avatar) : null; let clientAvatar: ?ClientAvatar; - if (avatar && avatar.type !== 'image') { + if ( + avatar && + avatar.type !== 'image' && + avatar.type !== 'encrypted-image' + ) { clientAvatar = avatar; } else if ( avatar && - avatar.type === 'image' && + (avatar.type === 'image' || avatar.type === 'encrypted-image') && row.user1_upload_id && row.user1_upload_secret ) { @@ -166,13 +188,27 @@ uploadID === avatar.uploadID, 'uploadID of upload should match uploadID of image avatar', ); - clientAvatar = { - type: 'image', - uri: getUploadURL(uploadID, row.user1_upload_secret), - }; + if (avatar.type === 'encrypted-image' && row.user1_upload_extra) { + const uploadExtra = JSON.parse(row.user1_upload_extra); + clientAvatar = { + type: 'encrypted-image', + blobURI: makeUploadURI( + uploadExtra.blobHash, + uploadID, + row.user1_upload_secret, + ), + encryptionKey: uploadExtra.encryptionKey, + thumbHash: uploadExtra.thumbHash, + }; + } else { + clientAvatar = { + type: 'image', + uri: getUploadURL(uploadID, row.user1_upload_secret), + }; + } } else if ( avatar && - avatar.type === 'image' && + (avatar.type === 'image' || avatar.type === 'encrypted-image') && row.user2_upload_id && row.user2_upload_secret ) { @@ -181,10 +217,24 @@ uploadID === avatar.uploadID, 'uploadID of upload should match uploadID of image avatar', ); - clientAvatar = { - type: 'image', - uri: getUploadURL(uploadID, row.user2_upload_secret), - }; + if (avatar.type === 'encrypted-image' && row.user2_upload_extra) { + const uploadExtra = JSON.parse(row.user2_upload_extra); + clientAvatar = { + type: 'encrypted-image', + blobURI: makeUploadURI( + uploadExtra.blobHash, + uploadID, + row.user2_upload_secret, + ), + encryptionKey: uploadExtra.encryptionKey, + thumbHash: uploadExtra.thumbHash, + }; + } else { + clientAvatar = { + type: 'image', + uri: getUploadURL(uploadID, row.user2_upload_secret), + }; + } } const userInfo = clientAvatar @@ -290,7 +340,7 @@ ): Promise { const userQuery = SQL` SELECT u.id, u.username, u.avatar, - up.id AS upload_id, up.secret AS upload_secret + up.id AS upload_id, up.secret AS upload_secret, up.extra AS upload_extra FROM users u LEFT JOIN uploads up ON up.container = u.id @@ -314,7 +364,7 @@ } const id = userRow.id.toString(); - const { username, upload_id, upload_secret } = userRow; + const { username, upload_id, upload_secret, upload_extra } = userRow; let loggedInUserInfo: LoggedInUserInfo = { id, @@ -326,18 +376,33 @@ : null; let clientAvatar: ?ClientAvatar; - if (avatar && avatar.type !== 'image') { + if (avatar && avatar.type !== 'image' && avatar.type !== 'encrypted-image') { clientAvatar = avatar; - } else if (avatar && avatar.type === 'image' && upload_id && upload_secret) { + } else if ( + avatar && + (avatar.type === 'image' || avatar.type === 'encrypted-image') && + upload_id && + upload_secret + ) { const uploadID = upload_id.toString(); invariant( uploadID === avatar.uploadID, 'uploadID of upload should match uploadID of image avatar', ); - clientAvatar = { - type: 'image', - uri: getUploadURL(uploadID, upload_secret), - }; + if (avatar.type === 'encrypted-image' && upload_extra) { + const uploadExtra = JSON.parse(upload_extra); + clientAvatar = { + type: 'encrypted-image', + blobURI: makeUploadURI(uploadExtra.blobHash, uploadID, upload_secret), + encryptionKey: uploadExtra.encryptionKey, + thumbHash: uploadExtra.thumbHash, + }; + } else { + clientAvatar = { + type: 'image', + uri: getUploadURL(uploadID, upload_secret), + }; + } } if (avatar) { diff --git a/keyserver/src/updaters/account-updaters.js b/keyserver/src/updaters/account-updaters.js --- a/keyserver/src/updaters/account-updaters.js +++ b/keyserver/src/updaters/account-updaters.js @@ -30,7 +30,7 @@ import { createUpdates } from '../creators/update-creator.js'; import { dbQuery, SQL } from '../database/database.js'; -import { getUploadURL } from '../fetchers/upload-fetchers.js'; +import { getUploadURL, makeUploadURI } from '../fetchers/upload-fetchers.js'; import { fetchKnownUserInfos } from '../fetchers/user-fetchers.js'; import type { Viewer } from '../session/viewer.js'; @@ -131,7 +131,10 @@ const newAvatarValue = request.type === 'remove' ? null : JSON.stringify(request); - const mediaID = request.type === 'image' ? request.uploadID : null; + const mediaID = + request.type === 'image' || request.type === 'encrypted-image' + ? request.uploadID + : null; const query = SQL` START TRANSACTION; @@ -176,7 +179,7 @@ COMMIT; - SELECT id AS upload_id, secret AS upload_secret + SELECT id AS upload_id, secret AS upload_secret, extra AS upload_extra FROM uploads WHERE id = ${mediaID} AND uploader = ${viewer.userID} @@ -201,16 +204,24 @@ if (request.type === 'remove') { return null; - } else if (request.type !== 'image') { + } else if (request.type !== 'image' && request.type !== 'encrypted-image') { return request; } else { - const [{ upload_id, upload_secret }] = selectResult; + const [{ upload_id, upload_secret, upload_extra }] = selectResult; const uploadID = upload_id.toString(); invariant( uploadID === request.uploadID, 'uploadID of upload should match uploadID of UpdateUserAvatarRequest', ); - + if (request.type === 'encrypted-image') { + const uploadExtra = JSON.parse(upload_extra); + return { + type: 'encrypted-image', + blobURI: makeUploadURI(uploadExtra.blobHash, uploadID, upload_secret), + encryptionKey: uploadExtra.encryptionKey, + thumbHash: uploadExtra.thumbHash, + }; + } return { type: 'image', uri: getUploadURL(uploadID, upload_secret), diff --git a/keyserver/src/updaters/thread-updaters.js b/keyserver/src/updaters/thread-updaters.js --- a/keyserver/src/updaters/thread-updaters.js +++ b/keyserver/src/updaters/thread-updaters.js @@ -636,7 +636,9 @@ if (avatarUpdate !== undefined) { const avatarUploadID = - avatar && avatar.type === 'image' ? avatar.uploadID : null; + avatar && (avatar.type === 'image' || avatar.type === 'encrypted-image') + ? avatar.uploadID + : null; const avatarUpdateQuery = SQL` START TRANSACTION; diff --git a/lib/components/base-edit-thread-avatar-provider.react.js b/lib/components/base-edit-thread-avatar-provider.react.js --- a/lib/components/base-edit-thread-avatar-provider.react.js +++ b/lib/components/base-edit-thread-avatar-provider.react.js @@ -79,7 +79,10 @@ }, }; const action = changeThreadSettingsActionTypes.started; - if (avatarRequest.type === 'image') { + if ( + avatarRequest.type === 'image' || + avatarRequest.type === 'encrypted-image' + ) { updateThreadAvatarMediaUploadInProgress(false); } const promise = changeThreadSettingsCall(updateThreadRequest); diff --git a/lib/components/edit-user-avatar-provider.react.js b/lib/components/edit-user-avatar-provider.react.js --- a/lib/components/edit-user-avatar-provider.react.js +++ b/lib/components/edit-user-avatar-provider.react.js @@ -72,7 +72,7 @@ const baseSetUserAvatar = React.useCallback( async (request: UpdateUserAvatarRequest) => { const promise = (async () => { - if (request.type === 'image') { + if (request.type === 'image' || request.type === 'encrypted-image') { setUserAvatarMediaUploadInProgress(false); } return await updateUserAvatarCall(request); diff --git a/native/account/registration/avatar-selection.react.js b/native/account/registration/avatar-selection.react.js --- a/native/account/registration/avatar-selection.react.js +++ b/native/account/registration/avatar-selection.react.js @@ -91,7 +91,8 @@ } else if (selection.updateUserAvatarRequest.type !== 'remove') { const clientRequest = selection.updateUserAvatarRequest; invariant( - clientRequest.type !== 'image', + clientRequest.type !== 'image' && + clientRequest.type !== 'encrypted-image', 'image avatars need to be uploaded', ); const newAvatarData = {