Open jodinathan opened 2 years ago
I know that there are some differences between "standard signing" and signing used for S3 buckets and to be honest, I'm not sure whether it can be used for S3 out of the box.
I'll try to check this out within the next days and I'll let you know once I know the status.
For the moment being I am using this function from a repo that is not maintained anymore:
// presigning higher method https://github.com/nbspou/dospace/blob/63711b66aff79e6a431999aec07a1952c07e4081/lib/src/dospace_bucket.dart#L175
// signing internals https://github.com/nbspou/dospace/blob/63711b66aff79e6a431999aec07a1952c07e4081/lib/src/dospace_client.dart#L78
Dunno if this can help you figure it out
Can you try run something like this (remember to check TODO lines)?
import 'package:aws_auth/aws_auth.dart';
AWSRequest createPresignS3Request(
AWS4Signer signer,
Duration expires,
String bucketName,
String bucketPath
) {
// create request
final req = AWSRequest(
'https://$bucketName.s3.${signer.region}.amazonaws.com${bucketPath}',
);
// presign the request
signer.presign(req, expires: expires);
return req;
}
void main() async {
// TODO: provide your AWS config and region
final AWS_ACCESS_KEY_ID = '<redacted>';
final AWS_SECRET_ACCESS_KEY = '<redacted>';
final AWS_REGION = 'eu-central-1';
// create credentials object
final credentialsProvider = AWSStaticCredentialsProvider(
AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY,
sessionToken: null,
);
final signer = AWS4Signer(
credentialsProvider,
region: AWS_REGION,
serviceName: 's3',
);
final presignedReq = createPresignS3Request(
signer,
Duration(minutes: 5),
// TODO: bucket name
'my-bucket-name',
// TODO: path with leading slash
'/images/my-image.png',
);
print(presignedReq.url);
}
It actually worked out of the box on my test AWS account but I'd check if it works properly in case there are some special characters in the path.
One thing cause I didn't ask about this... Do you want to use presigning for fetching objects from non-public S3 bucket or providing a way to upload new objects? The solution above assumes the first use case.
providing a way to upload new objects.
Do you think it is possible?
It looks like it's just a matter of HTTP method used. If you want to create a presigned upload url, you have to use PUT
instead of GET
, so in the code above change:
final req = AWSRequest(
'https://$bucketName.s3.${signer.region}.amazonaws.com${bucketPath}',
);
to
final req = AWSRequest(
'https://$bucketName.s3.${signer.region}.amazonaws.com${bucketPath}',
method: 'PUT',
);
With such a link, I was able to upload a file using e.g. this curl command:
curl -X PUT "<GENERATED_LINK>" -d 'example file content'
That should work for your case unless you have some special characters in the object path. I'll try to look into it next week.
it worked, however there a couple things:
headers: { 'x-amz-acl': 'public-read' }
to the AWSRequest
but it ended up with this error when uploading: <?xml version="1.0" encoding="UTF-8"?><Error><Code>SignatureDoesNotMatch</Code><RequestId>tx00000000000000728a944-0061eca222-20531e59-nyc3b</RequestId><HostId>20531e59-nyc3b-nyc-zg02</HostId></Error>
@jodinathan thanks for the PR!
BTW, did you manage to get it working with x-amz-acl
header?
yes.
you add it to the request in the server to generate the URL and also add an entry to the header of the client request
I am not expert in AWS API so sorry if this is a noob question, but would be able to create a S3 presigned URL with this lib?