Last active
August 29, 2015 14:14
-
-
Save seriousben/60ec66ef67805239f320 to your computer and use it in GitHub Desktop.
Better Generation of S3 Policy with Tests (From: https://github.com/javiersuweijie/s3policy)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Better https://github.com/javiersuweijie/s3policy | |
var crypto = require('crypto'); | |
var path = require('path'); | |
var _ = require('lodash'); | |
var uuid = require('node-uuid'); | |
var mimetype = require('mimetype'); | |
var AWS = require('aws-sdk'); | |
var debug = require('debug')('s3policy'); | |
function getAwsConfig() { | |
if (!AWS.config.credentials) { | |
console.error('AWS Credentials are not configured correctly. Missing IAM Role or ENV variables.'); | |
var e = new Error('Internal Error: Missing authentication information to generate policy.'); | |
e.status = 500; | |
throw e; | |
} | |
return { | |
accessKey: AWS.config.credentials.accessKeyId, | |
secretKey: AWS.config.credentials.secretAccessKey | |
}; | |
} | |
// Makes it easy to follow http://docs.aws.amazon.com/AmazonS3/latest/dev/request-rate-perf-considerations.html | |
function buildKey(context, filename) { | |
var environment = process.env.NODE_ENV || 'development'; | |
var contextPath = _.isEmpty(context) ? '' : context + '/'; | |
return path.join(environment + '/' + contextPath + uuid.v1() + '/' + filename); | |
} | |
var DEFAULT_WRITE_OPTIONS = { | |
expireInSec: 120, | |
maxSizeInMb: 10, | |
context: undefined, | |
acl: 'public-read' | |
}; | |
module.exports = { | |
getWritePolicy: function(filename, bucket, redirectUrl, options, cb) { | |
try { | |
if (_.isFunction(options)) { | |
cb = options; | |
options = DEFAULT_WRITE_OPTIONS; | |
} else { | |
_.defaults(options, DEFAULT_WRITE_OPTIONS); | |
} | |
var awsConfig = getAwsConfig(); | |
debug('Generating write policy:', options); | |
var key = buildKey(options.context, filename); | |
var duration = options.expireInSec; | |
var filesize = options.maxSizeInMb; | |
var acl = options.acl; | |
var dateObj = new Date(); | |
var dateExp = new Date(dateObj.getTime() + duration * 1000); | |
var policy = { | |
'expiration': dateExp.toISOString(), | |
'conditions': [ | |
{ | |
bucket: bucket | |
}, | |
{ | |
key: key, | |
}, | |
{ | |
'success_action_redirect': redirectUrl | |
}, | |
{ | |
acl: acl | |
}, | |
['content-length-range', 0, filesize * 1024 * 1024], | |
['starts-with', '$Content-Type', 'image'] | |
] | |
}; | |
var policyString = JSON.stringify(policy); | |
var policyBase64 = new Buffer(policyString).toString('base64'); | |
var signature = crypto.createHmac('sha1', awsConfig.secretKey).update(policyBase64); | |
var s3Credentials = { | |
url: 'http://' + bucket + '.s3.amazonaws.com', | |
redirectUrl: redirectUrl, | |
key: key, | |
policy: policyBase64, | |
signature: signature.digest('base64'), | |
accessKey: awsConfig.accessKey, | |
acl: acl, | |
mimetype: mimetype.lookup(filename) | |
}; | |
debug('Generated write policy:', s3Credentials); | |
cb(undefined, s3Credentials); | |
} catch (e) { | |
cb(e); | |
} | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var path = require('path'); | |
var fs = require('fs'); | |
var request = require('supertest'); | |
var FormData = require('form-data'); | |
var s3policy = require('s3policy'); | |
var expect = require('chai').expect; | |
var filename = 'avatar_1.jpg'; | |
var pathToMedia = path.resolve(__dirname, './fixtures/media/', filename); | |
describe('Upload an image using UploadPolicy', function() { | |
it('upload', function(done) { | |
s3policy.getUploadPolicy(filename, function(err, policy) { | |
expect(err).to.not.exist(); | |
expect(policy, 'policy required').to.exist(); | |
var form = new FormData(); | |
form.append('AWSAccessKeyId', policy.accessKey); | |
form.append('key', policy.key); | |
form.append('policy', policy.policy); | |
form.append('signature', policy.signature); | |
form.append('acl', policy.acl); | |
form.append('success_action_redirect', policy.redirectUrl); | |
form.append('Content-Type', policy.mimetype); | |
form.append('file', fs.createReadStream(pathToMedia)); | |
form.submit(policy.url, function(err, res) { | |
if (err) { | |
return done(err); | |
} | |
expect(res.statusCode).to.equal(303); | |
if (res.statusCode === 303 && res.headers.location) { | |
expect(res.headers.location).to.include(helper.config.targetServer); | |
request(res.headers.location) | |
.get('').end(function(err, res) { | |
if (err) { | |
return done(err); | |
} | |
expect(res.body).to.be.an.instanceOf(Object); | |
expect(res.body).to.have.property('bucket'); | |
done(); | |
}); | |
return; | |
} | |
// debugging information only! When failing! | |
var data = ''; | |
res.on('data', function(chunk) { | |
data += chunk; | |
}); | |
res.on('end', function() { | |
expect(data).to.not.be.empty(); | |
expect(false).to.be.true(); | |
done(); | |
}); | |
res.resume(); | |
}); | |
}); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment