Edgee:slingshot and security

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();
		}
	});
    }