From b2c7a2bf149086d40af3130da26769bebfbf24a3 Mon Sep 17 00:00:00 2001 From: aiden_lu Date: Mon, 6 Jan 2025 17:17:22 +0800 Subject: [PATCH] feat(core): support custom endpoint and addressing style for S3 Add support for configurable S3 endpoint and addressing style (path-style/virtual-hosted) to improve compatibility with S3-compatible storage services. - Add forcePathStyle option to control URL addressing style - Fix custom endpoint support implementation - Improve URL generation logic for different configurations Resolves: [#6920] Signed-off-by: aiden_lu --- .changeset/afraid-otters-crash.md | 5 ++++ packages/core/src/utils/storage/index.ts | 3 ++- packages/core/src/utils/storage/s3-storage.ts | 25 +++++++++++++++++++ packages/schemas/src/types/system.ts | 1 + 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 .changeset/afraid-otters-crash.md diff --git a/.changeset/afraid-otters-crash.md b/.changeset/afraid-otters-crash.md new file mode 100644 index 00000000000..24d4e5c9e23 --- /dev/null +++ b/.changeset/afraid-otters-crash.md @@ -0,0 +1,5 @@ +--- +"@logto/core": patch +--- + +support custom endpoint and addressing style for S3 diff --git a/packages/core/src/utils/storage/index.ts b/packages/core/src/utils/storage/index.ts index fdbe2bb9382..0baa1578a32 100644 --- a/packages/core/src/utils/storage/index.ts +++ b/packages/core/src/utils/storage/index.ts @@ -19,7 +19,7 @@ export const buildUploadFile = (config: StorageProviderData): UploadFile | Uploa return storage.uploadFile; } - const { endpoint, bucket, accessKeyId, accessSecretKey, region } = config; + const { endpoint, bucket, accessKeyId, forcePathStyle, accessSecretKey, region } = config; const storage = buildS3Storage({ endpoint, @@ -27,6 +27,7 @@ export const buildUploadFile = (config: StorageProviderData): UploadFile | Uploa accessKeyId, secretAccessKey: accessSecretKey, region, + forcePathStyle, }); return storage.uploadFile; diff --git a/packages/core/src/utils/storage/s3-storage.ts b/packages/core/src/utils/storage/s3-storage.ts index 994c459f792..8f6a1aa2ab4 100644 --- a/packages/core/src/utils/storage/s3-storage.ts +++ b/packages/core/src/utils/storage/s3-storage.ts @@ -16,6 +16,7 @@ type BuildS3StorageParameters = { secretAccessKey: string; region?: string; endpoint?: string; + forcePathStyle?: boolean; }; export const buildS3Storage = ({ @@ -24,6 +25,7 @@ export const buildS3Storage = ({ secretAccessKey, region, endpoint, + forcePathStyle, }: BuildS3StorageParameters) => { if (!region && !endpoint) { throw new Error('Either region or endpoint must be provided'); @@ -35,6 +37,7 @@ export const buildS3Storage = ({ const client = new S3Client({ region: finalRegion, endpoint, + forcePathStyle, credentials: { accessKeyId, secretAccessKey, @@ -56,6 +59,28 @@ export const buildS3Storage = ({ return { url: `${publicUrl}/${objectKey}` }; } + if (endpoint) { + // Custom endpoint URL construction + if (forcePathStyle) { + // Path-style URL: https://endpoint/bucket/key + return { + url: `${endpoint}/${bucket}/${objectKey}`, + }; + } + // Virtual-hosted style URL: https://bucket.endpoint/key + return { + url: `${endpoint.replace(/^(https?:\/\/)/, `$1${bucket}.`)}/${objectKey}`, + }; + } + + // AWS S3 standard URL construction + if (forcePathStyle) { + // Path-style URL: https://s3.region.amazonaws.com/bucket/key + return { + url: `https://s3.${finalRegion}.amazonaws.com/${bucket}/${objectKey}`, + }; + } + // Virtual-hosted style URL: https://bucket.s3.region.amazonaws.com/key return { url: `https://${bucket}.s3.${finalRegion}.amazonaws.com/${objectKey}`, }; diff --git a/packages/schemas/src/types/system.ts b/packages/schemas/src/types/system.ts index d69d0930968..3434db204fb 100644 --- a/packages/schemas/src/types/system.ts +++ b/packages/schemas/src/types/system.ts @@ -44,6 +44,7 @@ export const storageProviderDataGuard = z.discriminatedUnion('provider', [ endpoint: z.string().optional(), region: z.string().optional(), bucket: z.string(), + forcePathStyle: z.boolean().optional(), accessKeyId: z.string(), accessSecretKey: z.string(), ...basicConfig,