Skip to content

Instantly share code, notes, and snippets.

@mikefrey
Created July 20, 2016 14:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikefrey/841339fd18d3e9344243479d14491bf4 to your computer and use it in GitHub Desktop.
Save mikefrey/841339fd18d3e9344243479d14491bf4 to your computer and use it in GitHub Desktop.
Angular S3 browser upload with hapi
{
plugin: {
register: './app/plugins/s3-upload-token',
options: {
accessKey: 'YOURACCESSKEY',
secretKey: 'YOURSECRETKEY',
photoBucket: 'YOURBUCKET',
s3Policy: {
expiration: 10 * 60 * 1000, // 10 min
conditions: [
{'acl': 'public-read'},
['starts-with', '$key', 'uploads/'],
['starts-with', '$filename', 'uploads/'],
['starts-with', '$Content-Type', ''],
['content-length-range', 0, 5242880]
]
}
}
}
}
// Angular 1.x service for uploading to S3
angular.module('ngS3upload', []).
service('S3Uploader', function($http, $q) {
this.uploads = 0
const self = this
this.getUploadOptions = function(uri) {
return $q((resolve, reject) => {
$http.get(uri)
.success(response => resolve(response))
.error(error => reject(error))
})
}
this.upload = function(uri, key, acl, type, accessKey, policy, signature, file) {
const deferred = $q.defer()
const fd = new FormData()
fd.append('key', key)
fd.append('acl', acl)
fd.append('Content-Type', file.type)
fd.append('AWSAccessKeyId', accessKey)
fd.append('policy', policy)
fd.append('signature', signature)
fd.append('file', file)
const xhr = new XMLHttpRequest()
xhr.upload.addEventListener('progress', uploadProgress, false)
xhr.addEventListener('load', uploadComplete, false)
xhr.addEventListener('error', uploadFailed, false)
xhr.addEventListener('abort', uploadCanceled, false)
// Define event handlers
function uploadProgress(e) {
if (typeof deferred.notify !== 'function') return
let progress = 'unable to compute'
if (e.lengthComputable) {
progress = Math.round(e.loaded * 100 / e.total)
}
const msg = { type: 'progress', value: progress }
deferred.notify(msg)
}
function uploadComplete(e) {
const xhr = e.srcElement || e.target
self.uploads--
if (xhr.status === 204) // successful upload
return deferred.resolve(xhr)
deferred.reject(xhr)
}
function uploadFailed(e) {
const xhr = e.srcElement || e.target
self.uploads--
deferred.reject(xhr)
}
function uploadCanceled(e) {
const xhr = e.srcElement || e.target
self.uploads--
deferred.reject(xhr)
}
// Send the file
this.uploads++
xhr.open('POST', uri, true)
xhr.send(fd)
return deferred.promise
}
this.isUploading = function() {
return this.uploads > 0
}
})
// hapi.js plugin for generating a S3 upload token
'use strict'
const _ = require('lodash')
const crypto = require('crypto')
exports.register = function(server, options, next) {
server.route({
method: 'GET',
path: '/api/s3/uploadtoken',
config: {
handler: function(request, reply) {
let policyDoc = _.clone(options.s3Policy)
policyDoc.expiration = new Date(Date.now() + policyDoc.expiration).toISOString()
policyDoc.conditions.push({ bucket: options.photoBucket })
let policy = new Buffer(JSON.stringify(policyDoc)).toString('base64')
let hmac = crypto.createHmac('sha1', options.secretKey)
hmac.update(policy)
let signature = hmac.digest('base64')
reply({
key: options.accessKey,
bucket: options.photoBucket,
policy: policy,
signature: signature
})
}
}
})
next()
}
exports.register.attributes = {
name: 's3-upload-token',
version: '1.0.0'
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment