diff --git a/migration/1611547387175-objectStorageS3ForcePathStyle.ts b/migration/1611547387175-objectStorageS3ForcePathStyle.ts new file mode 100644 index 0000000000..1506a29007 --- /dev/null +++ b/migration/1611547387175-objectStorageS3ForcePathStyle.ts @@ -0,0 +1,14 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class objectStorageS3ForcePathStyle1611547387175 implements MigrationInterface { + name = 'objectStorageS3ForcePathStyle1611547387175' + + public async up(queryRunner: QueryRunner): Promise<void> { + await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageS3ForcePathStyle" boolean NOT NULL DEFAULT true`); + } + + public async down(queryRunner: QueryRunner): Promise<void> { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageS3ForcePathStyle"`); + } + +} diff --git a/src/client/pages/instance/settings.vue b/src/client/pages/instance/settings.vue index 761044b011..cea621ba2d 100644 --- a/src/client/pages/instance/settings.vue +++ b/src/client/pages/instance/settings.vue @@ -175,6 +175,7 @@ <MkSwitch v-model:value="objectStorageUseSSL" :disabled="!useObjectStorage">{{ $ts.objectStorageUseSSL }}<template #desc>{{ $ts.objectStorageUseSSLDesc }}</template></MkSwitch> <MkSwitch v-model:value="objectStorageUseProxy" :disabled="!useObjectStorage">{{ $ts.objectStorageUseProxy }}<template #desc>{{ $ts.objectStorageUseProxyDesc }}</template></MkSwitch> <MkSwitch v-model:value="objectStorageSetPublicRead" :disabled="!useObjectStorage">{{ $ts.objectStorageSetPublicRead }}</MkSwitch> + <MkSwitch v-model:value="objectStorageS3ForcePathStyle" :disabled="!useObjectStorage">s3ForcePathStyle</MkSwitch> </template> </div> <div class="_footer"> @@ -325,6 +326,7 @@ export default defineComponent({ objectStorageUseSSL: false, objectStorageUseProxy: false, objectStorageSetPublicRead: false, + objectStorageS3ForcePathStyle: true, enableTwitterIntegration: false, twitterConsumerKey: null, twitterConsumerSecret: null, @@ -393,6 +395,7 @@ export default defineComponent({ this.objectStorageUseSSL = this.meta.objectStorageUseSSL; this.objectStorageUseProxy = this.meta.objectStorageUseProxy; this.objectStorageSetPublicRead = this.meta.objectStorageSetPublicRead; + this.objectStorageS3ForcePathStyle = this.meta.objectStorageS3ForcePathStyle; this.enableTwitterIntegration = this.meta.enableTwitterIntegration; this.twitterConsumerKey = this.meta.twitterConsumerKey; this.twitterConsumerSecret = this.meta.twitterConsumerSecret; @@ -547,6 +550,7 @@ export default defineComponent({ objectStorageUseSSL: this.objectStorageUseSSL, objectStorageUseProxy: this.objectStorageUseProxy, objectStorageSetPublicRead: this.objectStorageSetPublicRead, + objectStorageS3ForcePathStyle: this.objectStorageS3ForcePathStyle, enableTwitterIntegration: this.enableTwitterIntegration, twitterConsumerKey: this.twitterConsumerKey, twitterConsumerSecret: this.twitterConsumerSecret, diff --git a/src/models/entities/meta.ts b/src/models/entities/meta.ts index 72a8b97978..f013169f86 100644 --- a/src/models/entities/meta.ts +++ b/src/models/entities/meta.ts @@ -399,4 +399,9 @@ export class Meta { default: false, }) public objectStorageSetPublicRead: boolean; + + @Column('boolean', { + default: true, + }) + public objectStorageS3ForcePathStyle: boolean; } diff --git a/src/server/api/endpoints/admin/update-meta.ts b/src/server/api/endpoints/admin/update-meta.ts index d3addaba8a..163d7a2519 100644 --- a/src/server/api/endpoints/admin/update-meta.ts +++ b/src/server/api/endpoints/admin/update-meta.ts @@ -438,7 +438,11 @@ export const meta = { objectStorageSetPublicRead: { validator: $.optional.bool - } + }, + + objectStorageS3ForcePathStyle: { + validator: $.optional.bool + }, } }; @@ -713,6 +717,10 @@ export default define(meta, async (ps, me) => { set.objectStorageSetPublicRead = ps.objectStorageSetPublicRead; } + if (ps.objectStorageS3ForcePathStyle !== undefined) { + set.objectStorageS3ForcePathStyle = ps.objectStorageS3ForcePathStyle; + } + await getConnection().transaction(async transactionalEntityManager => { const meta = await transactionalEntityManager.findOne(Meta, { order: { diff --git a/src/server/api/endpoints/meta.ts b/src/server/api/endpoints/meta.ts index 81053b26a3..3b647e21cd 100644 --- a/src/server/api/endpoints/meta.ts +++ b/src/server/api/endpoints/meta.ts @@ -205,6 +205,7 @@ export default define(meta, async (ps, me) => { response.objectStorageUseSSL = instance.objectStorageUseSSL; response.objectStorageUseProxy = instance.objectStorageUseProxy; response.objectStorageSetPublicRead = instance.objectStorageSetPublicRead; + response.objectStorageS3ForcePathStyle = instance.objectStorageS3ForcePathStyle; } } diff --git a/src/services/drive/s3.ts b/src/services/drive/s3.ts index abe3c166a5..f419f09377 100644 --- a/src/services/drive/s3.ts +++ b/src/services/drive/s3.ts @@ -13,7 +13,9 @@ export function getS3(meta: Meta) { secretAccessKey: meta.objectStorageSecretKey!, region: meta.objectStorageRegion || undefined, sslEnabled: meta.objectStorageUseSSL, - s3ForcePathStyle: !!meta.objectStorageEndpoint, + s3ForcePathStyle: !meta.objectStorageEndpoint // AWS with endPoint omitted + ? false + : meta.objectStorageS3ForcePathStyle, httpOptions: { agent: getAgentByUrl(new URL(u), !meta.objectStorageUseProxy) }