/* Prerequisite: meteor add peerlibrary:aws-sdk Terminology: AWS: Amazon web services S3: Simple storage service (one of the above.) Create a bucket on S3. Use AWS Identity and Access Manager to create a user that your app can log in as . Attach a policy to that user giving it the appropriate level of access to your bucket. Once the meteor package is installed, aws-sdk will make a global AWS variable available to you. You need to configure it with key and secret generated for your app user (don't put these in your repo. Either use Meteor.settings or environment variables.) You can then define a meteor method (sample below) to take file content and use the aws sdk to upload it to s3 into a bucket and filename of your choosing. To use folders inside the bucket, use file names like "folder1/folder2/myfile.jpg". S3 will auto-create the folder for you if it's not already there. */ // get AWS access data AWS.config.update({ accessKeyId: proc.env.AWS_KEY, secretAccessKey: proc.env.AWS_SECRET }); //The main upload function Meteor.methods({ "uploadToS3":function(fileName, bucket, fileData){ s3 = new AWS.S3({endpoint:"s3.amazonaws.com"}); s3.putObject( { Bucket: bucket, ACL:'public-read', Key: fileName, ContentType: "image/jpeg", Body:fileData }, function(err, data) { if(err){ console.log('upload error:',err); }else{ console.log('upload was succesful',data); /* At this point you know the upload succeeded and "data" contains an ETag The file is public-accessible at https://s3.amazonaws.com/bucket/fileName where bucket and fileName are the values passed to this function. If securty is a concern, you may need to take a slightly different approach, such as storing the file privately, and using additional calls to create temporary urls for the file as and when you need to display it in your app. For just preventing slurping you could probably get away with randomized file names. S3 won't allow your folders to be browsed even if the files are public. */ } } ); } }); /* Creating "bodyData" to upload from a client-side file input */ Template.uploadForm.events({ 'submit' : function(event){ event.preventDefault(); var inp = document.getElementById('file-select'); var fileName = inp.value; // Massage filename. Remove C:\fakedata nonsense. // Remove spaces and add a timestamp // Change this for your requirements obv. // Remember not to trust user input. fileName = new Date().getTime() + "_" + fileName.replace(/^.*\\/, ""); fileName = fileName.replace(/[^0-9a-z.]/ig, "_"); fileName = fileName.replace(/__+/g, "_"); var file = inp.files[0]; if (file) { var reader = new FileReader(); reader.readAsBinaryString(file); /* reader will fire the onloadend once it's read all of the file. So you can call the upload function in a handler for that event. */ reader.onloadend = function(){ Meteor.call("uploadToS3", fileName, reader.result); }; } } }); /* Creating "bodyData" from a device camera with the mdg:camera package */ /* The MeteorCamera.getPicture([options], callback) function that mdg:camera provides calls your callback with a reference to the photo data as a base 64 format data uri. You need to read that data and convert it into something you can upload to s3 as a file. */ function dataURItoBinary(dataURI) { var binary = atob(dataURI.split(',')[1]); var array = []; for(var i = 0; i < binary.length; i++) { array.push(binary.charCodeAt(i)); } return new Uint8Array(array); } Template.takePhoto.events({ 'click .capture': function(){ MeteorCamera.getPicture({}, function(error, data){ var photoData = dataURItoBinary(data); // Think about how you'll name your files.... var fileName = 'app_' + new Date().getTime() + ".jpg"; Meteor.call("uploadToS3", fileName, photoData); } });