From 6fcabb9946dd53055048a1316bc7636fe466bd66 Mon Sep 17 00:00:00 2001 From: Andrey Sobolev Date: Fri, 31 May 2024 13:38:49 +0700 Subject: [PATCH] Support S3 presign URI expire (#5706) Signed-off-by: Andrey Sobolev --- packages/core/src/classes.ts | 1 + server/s3/src/index.ts | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/core/src/classes.ts b/packages/core/src/classes.ts index 92b4faf5f1..f62952f7bb 100644 --- a/packages/core/src/classes.ts +++ b/packages/core/src/classes.ts @@ -567,6 +567,7 @@ export interface Blob extends Doc { export interface BlobLookup extends Blob { // An URL document could be downloaded from, with ${id} to put blobId into downloadUrl: string + downloadUrlExpire?: number // A URL document could be updated at uploadUrl?: string // A URL document could be previewed at diff --git a/server/s3/src/index.ts b/server/s3/src/index.ts index 51750bed69..f2f95c3bd8 100644 --- a/server/s3/src/index.ts +++ b/server/s3/src/index.ts @@ -62,7 +62,10 @@ export interface S3Config extends StorageConfig { // Defaults: ['avif', 'webp', 'heif', 'jpeg'] formats?: string - allowPresign?: boolean + // If not specified will be enabled + allowPresign?: string + // Expire time for presigned URIs + expireTime?: string } /** @@ -70,6 +73,7 @@ export interface S3Config extends StorageConfig { */ export class S3Service implements StorageAdapter { static config = 's3' + expireTime: number client: S3 constructor (readonly opt: S3Config) { this.client = new S3({ @@ -80,6 +84,8 @@ export class S3Service implements StorageAdapter { }, region: opt.region ?? 'auto' }) + + this.expireTime = parseInt(this.opt.expireTime ?? '168') * 3600 // use 7 * 24 - hours as default value for expireF } /** @@ -102,6 +108,7 @@ export class S3Service implements StorageAdapter { lookups: [], updates: new Map() } + const now = Date.now() for (const d of docs) { // Let's add current from URI for previews. const bl = d as BlobLookup @@ -109,8 +116,14 @@ export class S3Service implements StorageAdapter { Bucket: this.getBucketId(workspaceId), Key: this.getDocumentKey(workspaceId, d.storageId) }) - if (bl.downloadUrl === undefined && (this.opt.allowPresign ?? true)) { - bl.downloadUrl = await getSignedUrl(this.client, command) + if ( + (bl.downloadUrl === undefined || (bl.downloadUrlExpire ?? 0) > now) && + (this.opt.allowPresign ?? 'true') === 'true' + ) { + bl.downloadUrl = await getSignedUrl(this.client, command, { + expiresIn: this.expireTime + }) + bl.downloadUrlExpire = now + this.expireTime * 1000 result.updates?.set(bl._id, { downloadUrl: bl.downloadUrl })