I’m working on an application that allows users to upload files directly to AWS S3 using pre-signed URLs. I’m using the AWS SDK for JavaScript and the getSignedUrl()
function to generate the pre-signed URLs.
My current implementation is as follows:
userRouter.js
userRoutes.post("/get-presigned-upload-url", validateJwtToken,
validateRequest(userValidators.uploadFileSchema),
awsS3Controller.getPresignedDownloadUrl);
awsS3Controller.js
const awsS3Service = new AWSS3Service();
export const getPresignedDownloadUrl = async (req, res) => {
try {
const { folderPath, fileMetadata } = req.body;
const { contentType, originalFileName, size, ChecksumSHA256 } = fileMetadata;
const uniqueFileName = awsS3Service.generateUniqueFileName(originalFileName);
const key = `users/${req.user.id}/${!folderPath ? "" : folderPath}${uniqueFileName}`;
const presignedUrl = await awsS3Service.generatePresignedUploadUrl(
key,
contentType,
{
metadata: { originalFileName, size, ChecksumSHA256 },
checksumSHA256: ChecksumSHA256
}
);
res.status(HttpStatus.OK).json({ message: "File uploaded successfully", presignedUrl: presignedUrl });
} catch (error) {
res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ message: error.message });
}
}
awsS3Service.js
class AWSS3Service {
async generatePresignedUploadUrl(key, contentType, options = {}) {
try {
const command = new PutObjectCommand({
Bucket: this.bucketName,
Key: key,
ContentType: contentType,
Metadata: options.metadata,
ACL: options.acl || 'private',
ChecksumAlgorithm: options.checksumAlgorithm || "SHA256",
ChecksumSHA256: options.checksumSHA256,
});
return await getSignedUrl(this.s3Client, command, {
expiresIn: options.expiresIn || this.defaultExpiry,
signableHeaders: new Set(['host', 'x-amz-sdk-checksum-algorithm', 'x-amz-checksum-sha256', 'content-type'])
});
} catch (error) {
console.error('Presigned URL Generation Error:', error);
throw new Error(`Failed to generate presigned URL: ${error.message}`);
}
}
}
The issue I’m facing is that I want to ensure the file being uploaded to the pre-signed URL is the same as the one used to generate the pre-signed URL. In other words, I want to verify the file integrity between the pre-signed URL generation and the actual file upload.
I’ve tried using the ChecksumSHA256
option in the PutObjectCommand
and the signableHeaders
option in the getSignedUrl()
function, but I’m still not sure if this is the correct approach. For example, I’ve also read that I have to turn on checksums in S3.
What is the correct/complete way to achieve this verification?