From 0f185856317c67105b1d1cdf22a1d6a25fe54824 Mon Sep 17 00:00:00 2001 From: darkskygit Date: Wed, 2 Apr 2025 12:58:03 +0000 Subject: [PATCH] chore(server): update sign domain description (#11407) --- .docker/selfhost/schema.json | 72 +++++++++++++------ .../src/base/storage/providers/index.ts | 28 +++++--- .../server/src/base/storage/providers/r2.ts | 22 +++--- .../server/src/base/storage/providers/s3.ts | 13 +++- 4 files changed, 92 insertions(+), 43 deletions(-) diff --git a/.docker/selfhost/schema.json b/.docker/selfhost/schema.json index 81e7900dab..fd61542d17 100644 --- a/.docker/selfhost/schema.json +++ b/.docker/selfhost/schema.json @@ -352,13 +352,23 @@ "type": "string", "description": "The account id for the cloudflare r2 storage provider." }, - "signDomain": { - "type": "string", - "description": "The presigned domain for the cloudflare r2 storage provider." - }, - "signKey": { - "type": "string", - "description": "The presigned key for the cloudflare r2 storage provider." + "usePresignedURL": { + "type": "object", + "description": "The presigned url config for the cloudflare r2 storage provider.", + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether to use presigned url for the cloudflare r2 storage provider." + }, + "urlPrefix": { + "type": "string", + "description": "The presigned url prefix for the cloudflare r2 storage provider.\nsee https://developers.cloudflare.com/waf/custom-rules/use-cases/configure-token-authentication/ to configure it.\nExample value: \"https://storage.example.com\"\nExample rule: is_timed_hmac_valid_v0(\"your_secret\", http.request.uri, 10800, http.request.timestamp.sec, 6)" + }, + "signKey": { + "type": "string", + "description": "The presigned key for the cloudflare r2 storage provider." + } + } } } } @@ -463,13 +473,23 @@ "type": "string", "description": "The account id for the cloudflare r2 storage provider." }, - "signDomain": { - "type": "string", - "description": "The presigned domain for the cloudflare r2 storage provider." - }, - "signKey": { - "type": "string", - "description": "The presigned key for the cloudflare r2 storage provider." + "usePresignedURL": { + "type": "object", + "description": "The presigned url config for the cloudflare r2 storage provider.", + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether to use presigned url for the cloudflare r2 storage provider." + }, + "urlPrefix": { + "type": "string", + "description": "The presigned url prefix for the cloudflare r2 storage provider.\nsee https://developers.cloudflare.com/waf/custom-rules/use-cases/configure-token-authentication/ to configure it.\nExample value: \"https://storage.example.com\"\nExample rule: is_timed_hmac_valid_v0(\"your_secret\", http.request.uri, 10800, http.request.timestamp.sec, 6)" + }, + "signKey": { + "type": "string", + "description": "The presigned key for the cloudflare r2 storage provider." + } + } } } } @@ -717,13 +737,23 @@ "type": "string", "description": "The account id for the cloudflare r2 storage provider." }, - "signDomain": { - "type": "string", - "description": "The presigned domain for the cloudflare r2 storage provider." - }, - "signKey": { - "type": "string", - "description": "The presigned key for the cloudflare r2 storage provider." + "usePresignedURL": { + "type": "object", + "description": "The presigned url config for the cloudflare r2 storage provider.", + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether to use presigned url for the cloudflare r2 storage provider." + }, + "urlPrefix": { + "type": "string", + "description": "The presigned url prefix for the cloudflare r2 storage provider.\nsee https://developers.cloudflare.com/waf/custom-rules/use-cases/configure-token-authentication/ to configure it.\nExample value: \"https://storage.example.com\"\nExample rule: is_timed_hmac_valid_v0(\"your_secret\", http.request.uri, 10800, http.request.timestamp.sec, 6)" + }, + "signKey": { + "type": "string", + "description": "The presigned key for the cloudflare r2 storage provider." + } + } } } } diff --git a/packages/backend/server/src/base/storage/providers/index.ts b/packages/backend/server/src/base/storage/providers/index.ts index 9521f83833..fa8b868973 100644 --- a/packages/backend/server/src/base/storage/providers/index.ts +++ b/packages/backend/server/src/base/storage/providers/index.ts @@ -105,15 +105,27 @@ export const StorageJSONSchema: JSONSchema = { description: 'The account id for the cloudflare r2 storage provider.', }, - signDomain: { - type: 'string' as const, + usePresignedURL: { + type: 'object' as const, description: - 'The presigned domain for the cloudflare r2 storage provider.', - }, - signKey: { - type: 'string' as const, - description: - 'The presigned key for the cloudflare r2 storage provider.', + 'The presigned url config for the cloudflare r2 storage provider.', + properties: { + enabled: { + type: 'boolean' as const, + description: + 'Whether to use presigned url for the cloudflare r2 storage provider.', + }, + urlPrefix: { + type: 'string' as const, + description: + 'The presigned url prefix for the cloudflare r2 storage provider.\nsee https://developers.cloudflare.com/waf/custom-rules/use-cases/configure-token-authentication/ to configure it.\nExample value: "https://storage.example.com"\nExample rule: is_timed_hmac_valid_v0("your_secret", http.request.uri, 10800, http.request.timestamp.sec, 6)', + }, + signKey: { + type: 'string' as const, + description: + 'The presigned key for the cloudflare r2 storage provider.', + }, + }, }, }, }, diff --git a/packages/backend/server/src/base/storage/providers/r2.ts b/packages/backend/server/src/base/storage/providers/r2.ts index be8fc337ba..e89c745226 100644 --- a/packages/backend/server/src/base/storage/providers/r2.ts +++ b/packages/backend/server/src/base/storage/providers/r2.ts @@ -8,11 +8,11 @@ import { S3StorageConfig, S3StorageProvider } from './s3'; export interface R2StorageConfig extends S3StorageConfig { accountId: string; - // r2 public domain with verification - // see https://developers.cloudflare.com/waf/custom-rules/use-cases/configure-token-authentication/ to configure it - // example rule: is_timed_hmac_valid_v0("your_secret", http.request.uri, 10800, http.request.timestamp.sec, 6) - signDomain?: string; - signKey?: string; + usePresignedURL?: { + enabled: boolean; + urlPrefix?: string; + signKey?: string; + }; } export class R2StorageProvider extends S3StorageProvider { @@ -36,7 +36,7 @@ export class R2StorageProvider extends S3StorageProvider { bucket ); this.logger = new Logger(`${R2StorageProvider.name}:${bucket}`); - this.key = this.encoder.encode(config.signKey); + this.key = this.encoder.encode(config.usePresignedURL?.signKey ?? ''); } private async signUrl(url: URL): Promise { @@ -67,10 +67,10 @@ export class R2StorageProvider extends S3StorageProvider { metadata?: GetObjectMetadata; redirectUrl?: string; }> { - const { signDomain } = this.config; - if (signedUrl && signDomain) { + const { usePresignedURL: { enabled, urlPrefix } = {} } = this.config; + if (signedUrl && enabled && urlPrefix) { const metadata = await this.head(key); - const url = await this.signUrl(new URL(`/${key}`, signDomain)); + const url = await this.signUrl(new URL(`/${key}`, urlPrefix)); if (metadata) { return { redirectUrl: url.toString(), @@ -82,7 +82,7 @@ export class R2StorageProvider extends S3StorageProvider { return {}; } - // fallback to s3 presigned url if signDomain is not configured - return super.get(key, signDomain ? false : signedUrl); + // fallback to s3 get + return super.get(key, signedUrl); } } diff --git a/packages/backend/server/src/base/storage/providers/s3.ts b/packages/backend/server/src/base/storage/providers/s3.ts index b918fed8d6..188a1c18de 100644 --- a/packages/backend/server/src/base/storage/providers/s3.ts +++ b/packages/backend/server/src/base/storage/providers/s3.ts @@ -24,24 +24,31 @@ import { } from './provider'; import { autoMetadata, SIGNED_URL_EXPIRED, toBuffer } from './utils'; -export type S3StorageConfig = S3ClientConfig; +export interface S3StorageConfig extends S3ClientConfig { + usePresignedURL?: { + enabled: boolean; + }; +} export class S3StorageProvider implements StorageProvider { protected logger: Logger; protected client: S3Client; + private readonly usePresignedURL: boolean; constructor( config: S3StorageConfig, public readonly bucket: string ) { + const { usePresignedURL, ...clientConfig } = config; this.client = new S3Client({ region: 'auto', // s3 client uses keep-alive by default to accelerate requests, and max requests queue is 50. // If some of them are long holding or dead without response, the whole queue will block. // By default no timeout is set for requests or connections, so we set them here. requestHandler: { requestTimeout: 60_000, connectionTimeout: 10_000 }, - ...config, + ...clientConfig, }); + this.usePresignedURL = usePresignedURL?.enabled ?? false; this.logger = new Logger(`${S3StorageProvider.name}:${bucket}`); } @@ -122,7 +129,7 @@ export class S3StorageProvider implements StorageProvider { Key: key, }); - if (signedUrl) { + if (this.usePresignedURL && signedUrl) { const metadata = await this.head(key); if (metadata) { const url = await getSignedUrl(