Skip to content

Commit

Permalink
Use 'Expires' header to time-limit URLs
Browse files Browse the repository at this point in the history
  • Loading branch information
markuscolourbox committed Mar 14, 2022
1 parent b6a4f88 commit 247f335
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
26 changes: 26 additions & 0 deletions source/image-handler/image-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export class ImageRequest {
imageRequestInfo = { ...imageRequestInfo, ...originalImage };

imageRequestInfo.headers = this.parseImageHeaders(event, imageRequestInfo.requestType);
this.validateRequestExpires(imageRequestInfo);

// If the original image is SVG file and it has any edits but no output format, change the format to WebP.
if (imageRequestInfo.contentType === 'image/svg+xml' && imageRequestInfo.edits && Object.keys(imageRequestInfo.edits).length > 0 && !imageRequestInfo.edits.toFormat) {
Expand Down Expand Up @@ -443,4 +444,29 @@ export class ImageRequest {
}
}
}

private validateRequestExpires(requestInfo: ImageRequestInfo): void {
try {
const expires = requestInfo.headers?.expires;
if (expires !== undefined) {
const parsedDate = new Date(expires);
if (isNaN(parsedDate.getTime())) {
throw new ImageHandlerError(StatusCodes.BAD_REQUEST, 'ImageRequestExpiryFormat', 'Request has invalid expiry date.');
}
const now = new Date();
if (now > parsedDate) {
throw new ImageHandlerError(StatusCodes.FORBIDDEN, 'ImageRequestExpired', 'Request has expired.');
}
}
} catch (error) {
if (error.code === 'ImageRequestExpired') {
throw error;
}
if (error.code === 'ImageRequestExpiryFormat') {
throw error;
}
console.error('Error occurred while checking expiry.', error);
throw new ImageHandlerError(StatusCodes.INTERNAL_SERVER_ERROR, 'ExpiryDateCheckFailure', 'Expiry date check failed.');
}
}
}
40 changes: 40 additions & 0 deletions source/image-handler/test/image-request.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,46 @@ describe('setup()', () => {
expect(imageRequestInfo).toEqual(expectedResult);
});
});

describe('011/expiryDate', () => {
it.each([
{
path: '/eyJidWNrZXQiOiJ0ZXN0IiwicmVxdWVzdFR5cGUiOiJEZWZhdWx0Iiwia2V5IjoidGVzdC5wbmciLCJoZWFkZXJzIjp7ImV4cGlyZXMiOiJUaHUsIDAxIEphbiAxOTcwIDAwOjAwOjAwIEdNVCJ9fQ==',
error: {
code: 'ImageRequestExpired',
message: 'Request has expired.',
status: StatusCodes.FORBIDDEN,
},
},
{
path: '/eyJidWNrZXQiOiJ0ZXN0IiwicmVxdWVzdFR5cGUiOiJEZWZhdWx0Iiwia2V5IjoidGVzdC5wbmciLCJoZWFkZXJzIjp7ImV4cGlyZXMiOiJpbnZhbGlkS2V5In19',
error: {
code: 'ImageRequestExpiryFormat',
message: 'Request has invalid expiry date.',
status: StatusCodes.BAD_REQUEST,
}
}
])("Should throw an error when $error.message", (async ({ path, error: expectedError }) => {
// Arrange
const event = {
path,
};
// Mock
mockAwsS3.getObject.mockImplementationOnce(() => ({
promise() {
return Promise.resolve({ Body: Buffer.from('SampleImageContent\n') });
}
}));
// Act
const imageRequest = new ImageRequest(s3Client, secretProvider);
try {
await imageRequest.setup(event);
} catch (error) {
// Assert
expect(error).toMatchObject(expectedError);
}
}));
});
});

describe('getOriginalImage()', () => {
Expand Down

0 comments on commit 247f335

Please sign in to comment.