Great, got it working. Thanks for all your assistance!
For anyone looking for the answer - I’ve setup CORS but limited to the domain:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>http://localhost:3000</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
This ensures that you can only upload from this domain. To keep the files private, you have to set the ACL in the Slingshot directive to private:
/* Init STS */
const sts = new AWS.STS(); // Using the AWS SDK to retrieve temporary credentials.
Slingshot.createDirective('documentUploads', Slingshot.S3Storage.TempCredentials, {
bucket: Meteor.settings.AWSBucket,
acl: 'private',
temporaryCredentials: Meteor.wrapAsync(function (expire, callback) {
//AWS dictates that the minimum duration must be 900 seconds:
const duration = Math.max(Math.round(expire / 1000), 900);
sts.getSessionToken({
DurationSeconds: duration
}, function (error, result) {
callback(error, result && result.Credentials);
});
}),
authorize: function() {
if (!this.userId) {
throw new Meteor.Error(403, 'Unauthorised. Please login.');
}
return true;
},
key: function(file) {
const user = Meteor.users.findOne(this.userId);
return user.username + '/' + new Date().getTime() + '_' + file.name;
}
});
This ensures nobody but you can access the bucket unless they have temporary credentials. To download these uploaded files, you have to get a signed URL from AWS:
// Client / Blaze template events
'click .docDownload': function(event, instance) {
/* Prevent default */
event.preventDefault();
/* Open window */
let win = window.open('');
/* Get key */
const $this = $(event.target);
const url = $this.attr('href'); // Holds the full unsigned URL
/* Call method to get signed url */
Meteor.call('getSignedUrl', url, function(err, result) {
if (!err) {
win.location = result;
win.focus();
}
});
}