chore(server): update sign domain description (#11407)

This commit is contained in:
darkskygit
2025-04-02 12:58:03 +00:00
parent 1386a66579
commit 0f18585631
4 changed files with 92 additions and 43 deletions

View File

@@ -352,13 +352,23 @@
"type": "string", "type": "string",
"description": "The account id for the cloudflare r2 storage provider." "description": "The account id for the cloudflare r2 storage provider."
}, },
"signDomain": { "usePresignedURL": {
"type": "string", "type": "object",
"description": "The presigned domain for the cloudflare r2 storage provider." "description": "The presigned url config for the cloudflare r2 storage provider.",
}, "properties": {
"signKey": { "enabled": {
"type": "string", "type": "boolean",
"description": "The presigned key for the cloudflare r2 storage provider." "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", "type": "string",
"description": "The account id for the cloudflare r2 storage provider." "description": "The account id for the cloudflare r2 storage provider."
}, },
"signDomain": { "usePresignedURL": {
"type": "string", "type": "object",
"description": "The presigned domain for the cloudflare r2 storage provider." "description": "The presigned url config for the cloudflare r2 storage provider.",
}, "properties": {
"signKey": { "enabled": {
"type": "string", "type": "boolean",
"description": "The presigned key for the cloudflare r2 storage provider." "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", "type": "string",
"description": "The account id for the cloudflare r2 storage provider." "description": "The account id for the cloudflare r2 storage provider."
}, },
"signDomain": { "usePresignedURL": {
"type": "string", "type": "object",
"description": "The presigned domain for the cloudflare r2 storage provider." "description": "The presigned url config for the cloudflare r2 storage provider.",
}, "properties": {
"signKey": { "enabled": {
"type": "string", "type": "boolean",
"description": "The presigned key for the cloudflare r2 storage provider." "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."
}
}
} }
} }
} }

View File

@@ -105,15 +105,27 @@ export const StorageJSONSchema: JSONSchema = {
description: description:
'The account id for the cloudflare r2 storage provider.', 'The account id for the cloudflare r2 storage provider.',
}, },
signDomain: { usePresignedURL: {
type: 'string' as const, type: 'object' as const,
description: description:
'The presigned domain for the cloudflare r2 storage provider.', 'The presigned url config for the cloudflare r2 storage provider.',
}, properties: {
signKey: { enabled: {
type: 'string' as const, type: 'boolean' as const,
description: description:
'The presigned key for the cloudflare r2 storage provider.', '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.',
},
},
}, },
}, },
}, },

View File

@@ -8,11 +8,11 @@ import { S3StorageConfig, S3StorageProvider } from './s3';
export interface R2StorageConfig extends S3StorageConfig { export interface R2StorageConfig extends S3StorageConfig {
accountId: string; accountId: string;
// r2 public domain with verification usePresignedURL?: {
// see https://developers.cloudflare.com/waf/custom-rules/use-cases/configure-token-authentication/ to configure it enabled: boolean;
// example rule: is_timed_hmac_valid_v0("your_secret", http.request.uri, 10800, http.request.timestamp.sec, 6) urlPrefix?: string;
signDomain?: string; signKey?: string;
signKey?: string; };
} }
export class R2StorageProvider extends S3StorageProvider { export class R2StorageProvider extends S3StorageProvider {
@@ -36,7 +36,7 @@ export class R2StorageProvider extends S3StorageProvider {
bucket bucket
); );
this.logger = new Logger(`${R2StorageProvider.name}:${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<string> { private async signUrl(url: URL): Promise<string> {
@@ -67,10 +67,10 @@ export class R2StorageProvider extends S3StorageProvider {
metadata?: GetObjectMetadata; metadata?: GetObjectMetadata;
redirectUrl?: string; redirectUrl?: string;
}> { }> {
const { signDomain } = this.config; const { usePresignedURL: { enabled, urlPrefix } = {} } = this.config;
if (signedUrl && signDomain) { if (signedUrl && enabled && urlPrefix) {
const metadata = await this.head(key); 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) { if (metadata) {
return { return {
redirectUrl: url.toString(), redirectUrl: url.toString(),
@@ -82,7 +82,7 @@ export class R2StorageProvider extends S3StorageProvider {
return {}; return {};
} }
// fallback to s3 presigned url if signDomain is not configured // fallback to s3 get
return super.get(key, signDomain ? false : signedUrl); return super.get(key, signedUrl);
} }
} }

View File

@@ -24,24 +24,31 @@ import {
} from './provider'; } from './provider';
import { autoMetadata, SIGNED_URL_EXPIRED, toBuffer } from './utils'; 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 { export class S3StorageProvider implements StorageProvider {
protected logger: Logger; protected logger: Logger;
protected client: S3Client; protected client: S3Client;
private readonly usePresignedURL: boolean;
constructor( constructor(
config: S3StorageConfig, config: S3StorageConfig,
public readonly bucket: string public readonly bucket: string
) { ) {
const { usePresignedURL, ...clientConfig } = config;
this.client = new S3Client({ this.client = new S3Client({
region: 'auto', region: 'auto',
// s3 client uses keep-alive by default to accelerate requests, and max requests queue is 50. // 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. // 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. // By default no timeout is set for requests or connections, so we set them here.
requestHandler: { requestTimeout: 60_000, connectionTimeout: 10_000 }, requestHandler: { requestTimeout: 60_000, connectionTimeout: 10_000 },
...config, ...clientConfig,
}); });
this.usePresignedURL = usePresignedURL?.enabled ?? false;
this.logger = new Logger(`${S3StorageProvider.name}:${bucket}`); this.logger = new Logger(`${S3StorageProvider.name}:${bucket}`);
} }
@@ -122,7 +129,7 @@ export class S3StorageProvider implements StorageProvider {
Key: key, Key: key,
}); });
if (signedUrl) { if (this.usePresignedURL && signedUrl) {
const metadata = await this.head(key); const metadata = await this.head(key);
if (metadata) { if (metadata) {
const url = await getSignedUrl( const url = await getSignedUrl(