-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Direct S3 upload and Node signing example
Taylor Ackley edited this page Sep 9, 2016
·
4 revisions
Simple direct S3 upload with using Node to generate policy and signature
<input type="file" ngf-select ngf-change="onFileSelect($files)">
$scope.onFileSelect = function(files) {
if (files.length > 0) {
var filename = files[0].name;
var type = files[0].type;
var query = {
filename: filename,
type: type
};
$http.post('/signing', query)
.success(function(result) {
Upload.upload({
url: result.url, //s3Url
transformRequest: function(data, headersGetter) {
var headers = headersGetter();
delete headers.Authorization;
return data;
},
fields: result.fields, //credentials
method: 'POST',
file: files[0]
}).progress(function(evt) {
console.log('progress: ' + parseInt(100.0 * evt.loaded / evt.total));
}).success(function(data, status, headers, config) {
// file is uploaded successfully
console.log('file ' + config.file.name + 'is uploaded successfully. Response: ' + data);
}).error(function() {
});
})
.error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}
};
If removing headers does not work from the example above (Angular 1.4), a more reliable method may be to add an interceptor in your config block. Here is a simple example that strips out the authorization header if your url contains "amazonaws".
angular
.module('myApp', [
'ngFileUpload'
])
.config(config);
config.$inject = ['$httpProvider'];
function config($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
}
angular
.module('myApp')
.factory('authInterceptor', authInterceptor);
authInterceptor.$inject = ['$rootScope', '$q', '$location'];
function authInterceptor($rootScope, $q, $location) {
return {
// intercept every request
request: function(config) {
var foreignUrl = config.url.indexOf('amazonaws') > -1;
if(foreignUrl) {
config.headers['Authorization'] = undefined;
}
return config;
}
};
}
var aws = 'path to credentials';
var crypto = require('crypto');
var moment = require('moment');
var s3Url = 'https://' + aws.bucket + '.s3-' + aws.region + '.amazonaws.com';
exports.signing = function(req, res) {
var request = req.body;
var fileName = request.filename
var path = 'somedirectory in s3' + fileName;
var readType = 'private';
var expiration = moment().add(5, 'm').toDate(); //15 minutes
var s3Policy = {
'expiration': expiration,
'conditions': [{
'bucket': aws.bucket
},
['starts-with', '$key', path],
{
'acl': readType
},
{
'success_action_status': '201'
},
['starts-with', '$Content-Type', request.type],
['content-length-range', 2048, 10485760], //min and max
]
};
var stringPolicy = JSON.stringify(s3Policy);
var base64Policy = new Buffer(stringPolicy, 'utf-8').toString('base64');
// sign policy
var signature = crypto.createHmac('sha1', aws.secret)
.update(new Buffer(base64Policy, 'utf-8')).digest('base64');
var credentials = {
url: s3Url,
fields: {
key: path,
AWSAccessKeyId: aws.key,
acl: readType,
policy: base64Policy,
signature: signature,
'Content-Type': request.type,
success_action_status: 201
}
};
res.jsonp(credentials);
};