Support actions via presigned urls
Closed this issue · 3 comments
You can create presignedUrls with s3.getSignedUrl method.
A url looks like this: http://localhost:3001/file-uploads-temporary/de456c2c-0f93-4df7-ad82-0c2943e447f0.jpeg?AWSAccessKeyId=123&Content-Type=image%2Fjpeg&Expires=1519727198&Signature=L0RMhVZCyfrp37sDZbVfSLCuOSU%3D&x-amz-acl=private
Currently the metadata (aka Content-Type Content-Type=image%2Fjpeg
) is not added to the .dummys3_metadata
file.
I would suggest that we check for the Content-Type
param and if present simply use that as the value for the objects content-type.
The current workaround is to add the header to your request e.g.
"use strict";
const fetch = require("node-fetch");
const S3 = require("aws-sdk");
const s3 = new S3(config);
const s3Params = {
Bucket: "some-bucket-name",
Key: "my-file.jpeg",
ContentType: "image/jpeg",
ACL: "private"
};
s3
.getSignedUrl("putObject", s3Params)
.promise()
.then(uploadUrl => {
const readStream = fs.createReadStream("my-local-image.jpeg");
return fetch(uploadUrl, {
method: `PUT`,
body: readStream,
// On AWS you do not have to specify this. The Header is taken from the presigned url
headers: {
"Content-Type": "image/jpeg"
}
});
});
What do you think? @specialkk @leontastic?
If you agree I would come up with a PR for this.
This just means that we need to support options and metadata specified through query parameters instead of headers right? What happens to metadata specified through HTTP headers? I'm guessing that normally S3 responds with a 403
because the signature won't match, but we don't do signing yet.
Hey, I finally had some time to research (and look into implementing) this, but I think the specific example you gave with Content-Type
doesn't actually work due to how request signing works. Omitting custom metadata works fine, but traditional headers (like Content-Type
or Content-Disposition
) must be specified as headers or else S3 will throw SignatureDoesNotMatch
.
Anyway, if this sounds incorrect let me know. My plan is do perform faux-signature matching by ensuring that the metadata specified in query params match those specified in headers, with the exception of omitted x-amz-*
headers.
This is actually more nuanced than I expected. So far I've determined the following behavior (most of it can be derived from here):
For a field in the query params starting with x-amz-*
- use the value specified in the query params, ignore matching fields specified in the request headers
For a field in the query params or request headers not starting with x-amz-*
(except for Content-Type
and Content-MD5
)
- (interestingly) completely ignore them in signature verification
- AWS doesn't include these headers when calculating the signature since adding/removing these fields from both query params and headers has no effect on the validity of the signature
For Content-MD5
and Content-Type
in query params
- values are ignored, AWS will only consider the values specified in request headers
- reports
SignatureDoesNotMatch
if there isn't an exact match in the request headers- This includes omitting the header if the signature is calculated without
Content-Type
header
- This includes omitting the header if the signature is calculated without
For a field in the request headers starting with x-amz-*
- only report a mismatch if it was present in the signed canonical request but not included as a query param
- ignore the value if the field is present as a query param
Once this is done I'll probably open a new issue tracking proper verification of request signatures.