diff --git a/source/image-handler/image-request.ts b/source/image-handler/image-request.ts index 06ac23cf3..643cdf333 100644 --- a/source/image-handler/image-request.ts +++ b/source/image-handler/image-request.ts @@ -101,7 +101,7 @@ export class ImageRequest { imageRequestInfo.requestType = this.parseRequestType(event); imageRequestInfo.bucket = this.parseImageBucket(event, imageRequestInfo.requestType); - imageRequestInfo.key = this.parseImageKey(event, imageRequestInfo.requestType); + imageRequestInfo.key = this.parseImageKey(event, imageRequestInfo.requestType, imageRequestInfo.bucket); imageRequestInfo.edits = this.parseImageEdits(event, imageRequestInfo.requestType); const originalImage = await this.getOriginalImage(imageRequestInfo.bucket, imageRequestInfo.key); @@ -223,6 +223,16 @@ export class ImageRequest { } else if (requestType === RequestTypes.THUMBOR || requestType === RequestTypes.CUSTOM) { // Use the default image source bucket env var const sourceBuckets = this.getAllowedSourceBuckets(); + // Take the path and split it at "/" to get each "word" in the url as array + let potentialBucket = event.path + .split("/") + .filter(e => e.startsWith('s3:')) + .map(e => e.replace("s3:", "")); + // filter out all parts that are not an bucket-url + potentialBucket = potentialBucket.filter(e => sourceBuckets.includes(e)); + // return the first match + if (potentialBucket.length > 0) return potentialBucket[0]; + return sourceBuckets[0]; } else { throw new ImageHandlerError( @@ -265,7 +275,7 @@ export class ImageRequest { * @param requestType Type of the request. * @returns The name of the appropriate Amazon S3 key. */ - public parseImageKey(event: ImageHandlerEvent, requestType: RequestTypes): string { + public parseImageKey(event: ImageHandlerEvent, requestType: RequestTypes, bucket: string = null): string { if (requestType === RequestTypes.DEFAULT) { // Decode the image request and return the image key const { key } = this.decodeRequest(event); @@ -299,6 +309,7 @@ export class ImageRequest { .replace(/\/fit-in(?=\/)/g, "") .replace(/^\/+/g, "") .replace(/^\/+/, "") + .replace(new RegExp("s3:" + bucket + "\/"), '') ); } diff --git a/source/image-handler/test/image-request/parse-image-bucket.spec.ts b/source/image-handler/test/image-request/parse-image-bucket.spec.ts index d3173dd50..e55897dcb 100644 --- a/source/image-handler/test/image-request/parse-image-bucket.spec.ts +++ b/source/image-handler/test/image-request/parse-image-bucket.spec.ts @@ -126,4 +126,43 @@ describe("parseImageBucket", () => { }); } }); + + it("should parse bucket-name from first part in thumbor request but fail since it's not allowed", () => { + // Arrange + const event = { path: "/filters:grayscale()/s3:test-bucket/test-image-001.jpg" }; + process.env.SOURCE_BUCKETS = "allowedBucket001, allowedBucket002"; + + // Act + const imageRequest = new ImageRequest(s3Client, secretProvider); + + const bucket = imageRequest.parseImageBucket(event, RequestTypes.THUMBOR); + // Assert + expect(bucket).toEqual("allowedBucket001") + }) + + it("should parse bucket-name from first part in thumbor request and return it", () => { + // Arrange + const event = { path: "/filters:grayscale()/s3:test-bucket/test-image-001.jpg" }; + process.env.SOURCE_BUCKETS = "allowedBucket001, test-bucket"; + + // Act + const imageRequest = new ImageRequest(s3Client, secretProvider); + + const bucket = imageRequest.parseImageBucket(event, RequestTypes.THUMBOR); + // Assert + expect(bucket).toEqual("test-bucket") + }) + + it("should take bucket-name from env-variable if not present in the URL", () => { + // Arrange + const event = { path: "/filters:grayscale()/test-image-001.jpg" }; + process.env.SOURCE_BUCKETS = "allowedBucket001, test-bucket"; + + // Act + const imageRequest = new ImageRequest(s3Client, secretProvider); + + const bucket = imageRequest.parseImageBucket(event, RequestTypes.THUMBOR); + // Assert + expect(bucket).toEqual("allowedBucket001") + }) });