diff --git a/lib/actions/upload-actions.js b/lib/actions/upload-actions.js --- a/lib/actions/upload-actions.js +++ b/lib/actions/upload-actions.js @@ -22,6 +22,7 @@ import { makeBlobServiceEndpointURL, makeBlobServiceURI, + generateBlobHolder, } from '../utils/blob-service.js'; import { getMessageForException } from '../utils/errors.js'; import { @@ -169,7 +170,7 @@ const { uploadInput, callbacks, keyserverOrThreadID } = input; const { encryptionKey, loop, dimensions, thumbHash, blobInput } = uploadInput; - const blobHolder = uuid.v4(); + const blobHolder = await generateBlobHolder(); const blobHash = toBase64URL(uploadInput.blobHash); const defaultHeaders = createDefaultHTTPRequestHeaders(authMetadata); diff --git a/lib/utils/blob-service.js b/lib/utils/blob-service.js --- a/lib/utils/blob-service.js +++ b/lib/utils/blob-service.js @@ -1,7 +1,10 @@ // @flow import invariant from 'invariant'; +import uuid from 'uuid'; +import { toBase64URL } from './base64.js'; +import { getContentSigningKey } from './crypto-utils.js'; import { replacePathParams, type URLPathParams } from './url-utils.js'; import type { BlobServiceHTTPEndpoint } from '../facts/blob-service.js'; import blobServiceConfig from '../facts/blob-service.js'; @@ -50,11 +53,26 @@ }); } +/** + * Generates random blob holder prefixed by current device ID + */ +async function generateBlobHolder(): Promise { + const randomID = uuid.v4(); + try { + const deviceID = await getContentSigningKey(); + const urlSafeDeviceID = toBase64URL(deviceID); + return `${urlSafeDeviceID}:${randomID}`; + } catch { + return randomID; + } +} + export { makeBlobServiceURI, isBlobServiceURI, blobHashFromURI, blobHashFromBlobServiceURI, + generateBlobHolder, getBlobFetchableURL, makeBlobServiceEndpointURL, };