From 9169fb1ff4a1ac103524e879d1744c32bf4fab16 Mon Sep 17 00:00:00 2001 From: Jack Carlisle Date: Thu, 15 Sep 2016 17:40:38 +0100 Subject: [PATCH 01/11] builds vanilla requests to backend and s3 #22 --- examples/direct-upload/lib/routes.js | 1 + examples/direct-upload/public/client.js | 138 +++++++++++++++-------- examples/direct-upload/public/index.html | 7 +- 3 files changed, 98 insertions(+), 48 deletions(-) diff --git a/examples/direct-upload/lib/routes.js b/examples/direct-upload/lib/routes.js index 4e45543..336c4dc 100644 --- a/examples/direct-upload/lib/routes.js +++ b/examples/direct-upload/lib/routes.js @@ -22,6 +22,7 @@ module.exports = [ path: '/s3_credentials', handler: function (request, reply) { if (request.query.filename) { + console.log('***************', request.query.filename) var filename = crypto.randomBytes(8).toString('hex') + path.extname(request.query.filename) diff --git a/examples/direct-upload/public/client.js b/examples/direct-upload/public/client.js index 7f57f2a..6781158 100644 --- a/examples/direct-upload/public/client.js +++ b/examples/direct-upload/public/client.js @@ -1,50 +1,98 @@ -// Requires jQuery and blueimp's jQuery.fileUpload +var uploadDemo = (function () { + // Requires jQuery and blueimp's jQuery.fileUpload -// client-side validation by fileUpload should match the policy -// restrictions so that the checks fail early -var acceptFileType = /.*/i; -var maxFileSize = 1000; -// The URL to your endpoint that maps to s3Credentials function -var credentialsUrl = '/s3_credentials'; -// The URL to your endpoint to register the uploaded file -var uploadUrl = '/upload'; + // client-side validation by fileUpload should match the policy + // restrictions so that the checks fail early + var acceptFileType = /.*/i; + var maxFileSize = 1000; + // The URL to your endpoint that maps to s3Credentials function + var credentialsUrl = '/s3_credentials'; + // The URL to your endpoint to register the uploaded file + var uploadUrl = '/upload'; + var filename -window.initS3FileUpload = function($fileInput) { - $fileInput.fileupload({ - // acceptFileTypes: acceptFileType, - // maxFileSize: maxFileSize, - paramName: 'file', - add: s3add, - dataType: 'xml', - done: onS3Done - }); -}; + window.initS3FileUpload = function($fileInput) { + $fileInput.fileupload({ + // acceptFileTypes: acceptFileType, + // maxFileSize: maxFileSize, + paramName: 'file', + add: s3add, + dataType: 'xml', + done: onS3Done + }); + }; -// This function retrieves s3 parameters from our server API and appends them -// to the upload form. -function s3add(e, data) { - var filename = data.files[0].name; - var params = []; - $.ajax({ - url: credentialsUrl, - type: 'GET', - dataType: 'json', - data: { - filename: filename - }, - success: function(s3Data) { - data.url = s3Data.endpoint_url; - data.formData = s3Data.params; - data.submit(); + function saveFile (file) { + console.log('<------------>', file[0].name) + filename = file[0].name + } + + function submitFile () { + console.log('++++++++++++++', filename) + getCredentialsFromServer() + } + + function getCredentialsFromServer () { + var xhttp = new XMLHttpRequest() + xhttp.onreadystatechange = function () { + if (this.readyState === 4 && this.status === 200) { + var s3Data = JSON.parse(xhttp.responseText) + console.log('GET RESPONSE', s3Data) + var form = document.querySelector('form') + var keyInput = document.createElement('input') + keyInput.setAttribute('type', 'hidden') + keyInput.setAttribute('name', 'key') + keyInput.setAttribute('value', `${filename}`) + form.setAttribute('method', 'post') + form.setAttribute('action', s3Data.endpoint_url) + form.setAttribute('enctype', 'multipart/form-data') + form.insertBefore(keyInput, form.firstChild) + form.url = s3Data.endpoint_url + form.formData = s3Data.params + form.submit() + var successMessage = document.createElement('h2') + successMessage.innerHTML = 'Image Successfully Uploaded!' + document.body.appendChild(successMessage) + } } - }); - return params; -}; + xhttp.open('GET', `/s3_credentials?filename=${filename}`, true) + xhttp.send() + } + // This function retrieves s3 parameters from our server API and appends them + // to the upload form. + function s3add(e, data) { + var filename = data.files[0].name; + console.log('file name', data) + var params = []; + $.ajax({ + url: credentialsUrl, + type: 'GET', + dataType: 'json', + data: { + filename: filename + }, + success: function(s3Data) { + data.url = s3Data.endpoint_url; + data.formData = s3Data.params; + console.log(s3Data.params); + data.submit(); + } + }); + console.log('PARAMS', params); + return params; + }; + + function onS3Done(e, data) { + var s3Url = $(data.jqXHR.responseXML).find('Location').text(); + var s3Key = $(data.jqXHR.responseXML).find('Key').text(); + // Typically, after uploading a file to S3, you want to register that file with + // your backend. Remember that we did not persist anything before the upload. + console.log($('').attr('href', s3Url).text(s3Url).appendTo($('body'))); + }; -function onS3Done(e, data) { - var s3Url = $(data.jqXHR.responseXML).find('Location').text(); - var s3Key = $(data.jqXHR.responseXML).find('Key').text(); - // Typically, after uploading a file to S3, you want to register that file with - // your backend. Remember that we did not persist anything before the upload. - console.log($('').attr('href', s3Url).text(s3Url).appendTo($('body'))); -}; + return { + saveFile, + submitFile + // all tje other stuff you need publicly + } +}()) diff --git a/examples/direct-upload/public/index.html b/examples/direct-upload/public/index.html index 76d3a90..f5bd60e 100644 --- a/examples/direct-upload/public/index.html +++ b/examples/direct-upload/public/index.html @@ -7,16 +7,17 @@ - -->

S3 Direct Upload Demo

- +
+ From 91fd190a06d7c95a26d09cde85e64c571eda5225 Mon Sep 17 00:00:00 2001 From: Jack Carlisle Date: Thu, 15 Sep 2016 18:13:18 +0100 Subject: [PATCH 02/11] adds success message after upload to s3 #22 --- examples/direct-upload/public/client.js | 45 +++++++++++++++--------- examples/direct-upload/public/index.html | 3 ++ 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/examples/direct-upload/public/client.js b/examples/direct-upload/public/client.js index 6781158..e1f9e86 100644 --- a/examples/direct-upload/public/client.js +++ b/examples/direct-upload/public/client.js @@ -29,35 +29,46 @@ var uploadDemo = (function () { function submitFile () { console.log('++++++++++++++', filename) - getCredentialsFromServer() + getCredentialsFromServer(filename) } - function getCredentialsFromServer () { + function getCredentialsFromServer (filename) { var xhttp = new XMLHttpRequest() xhttp.onreadystatechange = function () { if (this.readyState === 4 && this.status === 200) { var s3Data = JSON.parse(xhttp.responseText) console.log('GET RESPONSE', s3Data) - var form = document.querySelector('form') - var keyInput = document.createElement('input') - keyInput.setAttribute('type', 'hidden') - keyInput.setAttribute('name', 'key') - keyInput.setAttribute('value', `${filename}`) - form.setAttribute('method', 'post') - form.setAttribute('action', s3Data.endpoint_url) - form.setAttribute('enctype', 'multipart/form-data') - form.insertBefore(keyInput, form.firstChild) - form.url = s3Data.endpoint_url - form.formData = s3Data.params - form.submit() - var successMessage = document.createElement('h2') - successMessage.innerHTML = 'Image Successfully Uploaded!' - document.body.appendChild(successMessage) + buildAndSubmitForm(s3Data) + var successMessage = document.createElement('h4') + successMessage.innerHTML = 'Image Successfully Uploaded at: ' + var link = `https://dwyl-direct-upload.s3.amazonaws.com/${filename}` + var imageATag = document.querySelector('a') + imageATag.setAttribute('href', link) + var imageLink = document.createElement('h4') + imageLink.innerHTML = link + var div = document.querySelector('div') + div.insertBefore(successMessage, div.firstChild) + imageATag.appendChild(imageLink) } } xhttp.open('GET', `/s3_credentials?filename=${filename}`, true) xhttp.send() } + + function buildAndSubmitForm (s3Data) { + var form = document.querySelector('form') + var keyInput = document.createElement('input') + keyInput.setAttribute('type', 'hidden') + keyInput.setAttribute('name', 'key') + keyInput.setAttribute('value', `${filename}`) + form.setAttribute('method', 'post') + form.setAttribute('action', s3Data.endpoint_url) + form.setAttribute('enctype', 'multipart/form-data') + form.insertBefore(keyInput, form.firstChild) + form.url = s3Data.endpoint_url + form.formData = s3Data.params + form.submit() + } // This function retrieves s3 parameters from our server API and appends them // to the upload form. function s3add(e, data) { diff --git a/examples/direct-upload/public/index.html b/examples/direct-upload/public/index.html index f5bd60e..629d2a7 100644 --- a/examples/direct-upload/public/index.html +++ b/examples/direct-upload/public/index.html @@ -19,5 +19,8 @@

S3 Direct Upload Demo

+
+ +
From 55fb2dd5810d9fc30ad578a71cc7743de94cbd0a Mon Sep 17 00:00:00 2001 From: Jack Carlisle Date: Fri, 16 Sep 2016 11:12:15 +0100 Subject: [PATCH 03/11] adds client side code to demo for upload #22 --- examples/direct-upload/README.md | 160 +++++++++++++++++- .../direct-upload/generate-credentials.js | 49 +++--- examples/direct-upload/lib/routes.js | 1 - examples/direct-upload/public/client.js | 55 ------ examples/direct-upload/public/index.html | 8 - 5 files changed, 184 insertions(+), 89 deletions(-) diff --git a/examples/direct-upload/README.md b/examples/direct-upload/README.md index 74b7906..5e69603 100644 --- a/examples/direct-upload/README.md +++ b/examples/direct-upload/README.md @@ -438,6 +438,164 @@ server.start((err) => { } console.log(`✅ Server running at: ${server.info.uri}`) ``` + #### We now have a server that can our index.html can communicate with! -### Step 5 - Write the client side code to send our requests to the backend and to S3 +### Step 5 - Write the client side code to send our requests to the backend and then to S3 + ++ Create a `public` directory in the root of your project. Inside this new folder +create two new files `index.html` and `client.js` + +Insert the following into your `index.html`: + +```html + + + + S3 Upload Demo + // optional stylesheet + + // include your client.js file that we are going to write + + + +

S3 Direct Upload Demo

+ // simple form with a file input (we'll be adding more later dynamically) +
+ // onchange gets fired when a file is selected so we want to save the file + +
+ // button that will submit our file + + // container for the success message and link to our image +
+ +
+ + +``` +In your `client.js` file add the following: + +```js +// wrap everything in an IIFE (immediately invoked function expression) to contain +// global variables +var uploadDemo = (function () { + // 'global' variable used to store our filename + var filename + + /** + * Saves the filename to our global variable when a file has been selected + * @param {Object} file - file from our file input tag + **/ + function saveFile (file) { + filename = file[0].name + } + + /** + * Calls our getCredentialsFromServer function with the global filename + **/ + function submitFile () { + getCredentialsFromServer(filename) + } + + // function that retrieves our S3 credentials from our server + /** + * Saves the filename to our global variable when a file has been selected + * @param {string} filename - name of the file we want to upload + **/ + function getCredentialsFromServer (filename) { + var xhttp = new XMLHttpRequest() + xhttp.onreadystatechange = function () { + if (this.readyState === 4 && this.status === 200) { + // after we've received a response we want to assign it to a variable + var s3Data = JSON.parse(xhttp.responseText) + // call our buildAndSubmitForm function + buildAndSubmitForm(s3Data) + // return a success message after the image has been uploaded along with + // link to image + var successMessage = document.createElement('h4') + successMessage.innerHTML = 'Image Successfully Uploaded at: ' + var link = `https://.s3.amazonaws.com/${filename}` + var imageATag = document.querySelector('a') + imageATag.setAttribute('href', link) + var imageLink = document.createElement('h4') + imageLink.innerHTML = link + var div = document.querySelector('div') + div.insertBefore(successMessage, div.firstChild) + imageATag.appendChild(imageLink) + } + } + // open the GET request to our endpoint with our filename attached + xhttp.open('GET', `/s3_credentials?filename=${filename}`, true) + // send the GET request + xhttp.send() + } + + /** + * Dynamically creates and submits our form to S3 + * @param {Object} s3Data - endpoint_url and params sent back from our server + **/ + function buildAndSubmitForm (s3Data) { + // access the form in our index.html + var form = document.querySelector('form') + // create a new input element + var keyInput = document.createElement('input') + // set its type attribute to hidden + keyInput.setAttribute('type', 'hidden') + // set its name attribute to key + keyInput.setAttribute('name', 'key') + // set its value attribute to our filename + keyInput.setAttribute('value', `${filename}`) + // set the method of the form to POST + form.setAttribute('method', 'post') + // set the action attribute to be our endpoint_url from our server + form.setAttribute('action', s3Data.endpoint_url) + // set the encoding type to multipart/form-data + form.setAttribute('enctype', 'multipart/form-data') + // our file input **must** be the last input in the form, therefore we need + // to insert our keyInput before the first child of the form otherwise it will + // throw an error + form.insertBefore(keyInput, form.firstChild) + // set the form url to be our endpoint_url from our server + form.url = s3Data.endpoint_url + // set the form data to be our S3 params from our server + form.formData = s3Data.params + // submit the form + form.submit() + } + // return functions from our IIFE that we'll need to expose to our index.html + return { + saveFile, + submitFile + } +}()) +``` +#### We've now written the neccessary code needed to upload directly to S3! + +##### Let's take it for a spin! + ++ In your terminal run the following command to start the server: +`$ node lib/index.js` + ++ Navigate to localhost:8000. You should see the following screen. Click on **Choose File**: + +![demo](https://cloud.githubusercontent.com/assets/12450298/18581819/27ac5dac-7bfa-11e6-987f-8aef76c7243c.png) + ++ Choose the file you wish to upload and click **open**: + +![choose file](https://cloud.githubusercontent.com/assets/12450298/18582392/afcb9598-7bfc-11e6-940d-9f1c85f44c67.png) + ++ Then click the **Submit** button + +![submit](https://cloud.githubusercontent.com/assets/12450298/18582412/d15503ca-7bfc-11e6-8bd8-52548bf29e2e.png) + ++ You should then see the success message with the link to where the image is being hosted (*this can now be used as an img src*). Click on the link: + +![success](https://cloud.githubusercontent.com/assets/12450298/18582441/fc24f646-7bfc-11e6-89e8-5dcdaa49ffef.png) + ++ This should start an automatic download. Click on the download and you should see your image! + +![image download](https://cloud.githubusercontent.com/assets/12450298/18582455/1f080edc-7bfd-11e6-8280-881ef2462e92.png) +![one does not simply](https://cloud.githubusercontent.com/assets/12450298/18582475/4d75e28a-7bfd-11e6-83a0-2c7029cb9830.png) + +# 🎉 We've successfully uploaded an image directly to S3! diff --git a/examples/direct-upload/generate-credentials.js b/examples/direct-upload/generate-credentials.js index 2218bd4..4d336d6 100644 --- a/examples/direct-upload/generate-credentials.js +++ b/examples/direct-upload/generate-credentials.js @@ -1,16 +1,16 @@ -var crypto = require('crypto'); +var crypto = require('crypto') -function getS3Credentials(config, filename) { +function getS3Credentials (config, filename) { return { - endpoint_url: "https://" + config.bucket + ".s3.amazonaws.com", + endpoint_url: 'https://' + config.bucket + '.s3.amazonaws.com', params: buildS3Params(config, filename) } } -function buildS3Params(config, filename) { - var credential = formatAmzCredential(config); - var policy = buildS3UploadPolicy(config, filename, credential); - var policyBase64 = new Buffer(JSON.stringify(policy)).toString('base64'); +function buildS3Params (config, filename) { + var credential = formatAmzCredential(config) + var policy = buildS3UploadPolicy(config, filename, credential) + var policyBase64 = new Buffer(JSON.stringify(policy)).toString('base64') return { key: filename, acl: 'public-read', @@ -23,43 +23,44 @@ function buildS3Params(config, filename) { } } -function formatAmzCredential(config) { +function formatAmzCredential (config) { return [config.accessKey, dateString(), config.region, 's3/aws4_request'].join('/') } -function buildS3UploadPolicy(config, filename, credential) { +function buildS3UploadPolicy (config, filename, credential) { return { - expiration: new Date((new Date).getTime() + (3 * 60 * 1000)).toISOString(), + expiration: new Date((new Date()).getTime() + (3 * 60 * 1000)).toISOString(), conditions: [ { bucket: config.bucket }, { key: filename }, { acl: 'public-read' }, { success_action_status: '201' }, + {'Content-Type': 'image/*'}, ['content-length-range', 0, 100000000000], { 'x-amz-algorithm': 'AWS4-HMAC-SHA256' }, { 'x-amz-credential': credential }, { 'x-amz-date': dateString() + 'T000000Z' } - ], + ] } } -function dateString() { - var date = new Date().toISOString(); - return date.substr(0, 4) + date.substr(5, 2) + date.substr(8, 2); +function dateString () { + var date = new Date().toISOString() + return date.substr(0, 4) + date.substr(5, 2) + date.substr(8, 2) } -function buildS3UploadSignature(config, policyBase64, credential) { - var dateKey = hmac('AWS4' + config.secretKey, dateString()); - var dateRegionKey = hmac(dateKey, config.region); - var dateRegionServiceKey = hmac(dateRegionKey, 's3'); - var signingKey = hmac(dateRegionServiceKey, 'aws4_request'); - return hmac(signingKey, policyBase64).toString('hex'); +function buildS3UploadSignature (config, policyBase64, credential) { + var dateKey = hmac('AWS4' + config.secretKey, dateString()) + var dateRegionKey = hmac(dateKey, config.region) + var dateRegionServiceKey = hmac(dateRegionKey, 's3') + var signingKey = hmac(dateRegionServiceKey, 'aws4_request') + return hmac(signingKey, policyBase64).toString('hex') } -function hmac(key, string) { - var hmac = require('crypto').createHmac('sha256', key); - hmac.end(string); - return hmac.read(); +function hmac (key, string) { + var hmac = crypto.createHmac('sha256', key) + hmac.end(string) + return hmac.read() } module.exports = { diff --git a/examples/direct-upload/lib/routes.js b/examples/direct-upload/lib/routes.js index 336c4dc..4e45543 100644 --- a/examples/direct-upload/lib/routes.js +++ b/examples/direct-upload/lib/routes.js @@ -22,7 +22,6 @@ module.exports = [ path: '/s3_credentials', handler: function (request, reply) { if (request.query.filename) { - console.log('***************', request.query.filename) var filename = crypto.randomBytes(8).toString('hex') + path.extname(request.query.filename) diff --git a/examples/direct-upload/public/client.js b/examples/direct-upload/public/client.js index e1f9e86..59dbdf2 100644 --- a/examples/direct-upload/public/client.js +++ b/examples/direct-upload/public/client.js @@ -1,34 +1,11 @@ var uploadDemo = (function () { - // Requires jQuery and blueimp's jQuery.fileUpload - - // client-side validation by fileUpload should match the policy - // restrictions so that the checks fail early - var acceptFileType = /.*/i; - var maxFileSize = 1000; - // The URL to your endpoint that maps to s3Credentials function - var credentialsUrl = '/s3_credentials'; - // The URL to your endpoint to register the uploaded file - var uploadUrl = '/upload'; var filename - window.initS3FileUpload = function($fileInput) { - $fileInput.fileupload({ - // acceptFileTypes: acceptFileType, - // maxFileSize: maxFileSize, - paramName: 'file', - add: s3add, - dataType: 'xml', - done: onS3Done - }); - }; - function saveFile (file) { - console.log('<------------>', file[0].name) filename = file[0].name } function submitFile () { - console.log('++++++++++++++', filename) getCredentialsFromServer(filename) } @@ -69,41 +46,9 @@ var uploadDemo = (function () { form.formData = s3Data.params form.submit() } - // This function retrieves s3 parameters from our server API and appends them - // to the upload form. - function s3add(e, data) { - var filename = data.files[0].name; - console.log('file name', data) - var params = []; - $.ajax({ - url: credentialsUrl, - type: 'GET', - dataType: 'json', - data: { - filename: filename - }, - success: function(s3Data) { - data.url = s3Data.endpoint_url; - data.formData = s3Data.params; - console.log(s3Data.params); - data.submit(); - } - }); - console.log('PARAMS', params); - return params; - }; - - function onS3Done(e, data) { - var s3Url = $(data.jqXHR.responseXML).find('Location').text(); - var s3Key = $(data.jqXHR.responseXML).find('Key').text(); - // Typically, after uploading a file to S3, you want to register that file with - // your backend. Remember that we did not persist anything before the upload. - console.log($('').attr('href', s3Url).text(s3Url).appendTo($('body'))); - }; return { saveFile, submitFile - // all tje other stuff you need publicly } }()) diff --git a/examples/direct-upload/public/index.html b/examples/direct-upload/public/index.html index 629d2a7..f4a175a 100644 --- a/examples/direct-upload/public/index.html +++ b/examples/direct-upload/public/index.html @@ -3,15 +3,7 @@ S3 Upload Demo - - - -

S3 Direct Upload Demo

From e302a3c9145a5467634f6ea45eeb57f08bf7021d Mon Sep 17 00:00:00 2001 From: Jack Carlisle Date: Fri, 16 Sep 2016 11:30:35 +0100 Subject: [PATCH 04/11] adds s3 validation screenshots #22 --- examples/direct-upload/README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/examples/direct-upload/README.md b/examples/direct-upload/README.md index 5e69603..5bed272 100644 --- a/examples/direct-upload/README.md +++ b/examples/direct-upload/README.md @@ -593,9 +593,18 @@ var uploadDemo = (function () { ![success](https://cloud.githubusercontent.com/assets/12450298/18582441/fc24f646-7bfc-11e6-89e8-5dcdaa49ffef.png) -+ This should start an automatic download. Click on the download and you should see your image! ++ This should start an automatic download. Click on the download: ![image download](https://cloud.githubusercontent.com/assets/12450298/18582455/1f080edc-7bfd-11e6-8280-881ef2462e92.png) + ++ You should see your image! ![one does not simply](https://cloud.githubusercontent.com/assets/12450298/18582475/4d75e28a-7bfd-11e6-83a0-2c7029cb9830.png) -# 🎉 We've successfully uploaded an image directly to S3! ++ Let's check our S3 console so that we know *for sure* that our image is there. Navigate back to your S3 buckets and click on the one you uploaded to: +![s3 buckets](https://cloud.githubusercontent.com/assets/12450298/18583007/098154ee-7c00-11e6-931e-4dec223cf95d.png) + ++ You should be able to see the image that you just uploaded: +![image uploaded](https://cloud.githubusercontent.com/assets/12450298/18583075/5132dc9a-7c00-11e6-91f4-8e1103d3e49a.png) + + +# 🎉 We've successfully uploaded an image directly to S3! From 3dfeec4c92f98e54b6d95b2f9177ad03ff5a8818 Mon Sep 17 00:00:00 2001 From: Jack Carlisle Date: Fri, 16 Sep 2016 12:53:59 +0100 Subject: [PATCH 05/11] adds contents and learning resources to readme #18 --- examples/direct-upload/README.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/examples/direct-upload/README.md b/examples/direct-upload/README.md index 5bed272..b827368 100644 --- a/examples/direct-upload/README.md +++ b/examples/direct-upload/README.md @@ -3,6 +3,15 @@ We are going to implement a simple solution for uploading images to an S3 bucket via a POST request from the browser. +### Contents +- [Creating an S3 Bucket](#creating-the-bucket) +- [Creating IAM User with S3 Permissions](#creating-an-iam-user-with-s3-permissions) +- [Generate a Signed S3 Policy](#generate-a-signed-s3-policy) +- [Create a Server](#create-a-server-to-facilitate-the-credential-creation) +- [Server and S3 Requests](#write-the-client-side-code-to-send-our-requests-to-the-backend-and-then-to-s3) +- [Take it for a Spin](#take-it-for-a-spin!) +- [Learning Resources](#learning-resources) + ### Step 1 - Creating the bucket + Create an S3 bucket on [Amazon Web Services](aws.amazon.co.uk). To do so you'll need to @@ -572,7 +581,7 @@ var uploadDemo = (function () { ``` #### We've now written the neccessary code needed to upload directly to S3! -##### Let's take it for a spin! +##### Take it for a spin! + In your terminal run the following command to start the server: `$ node lib/index.js` @@ -608,3 +617,11 @@ var uploadDemo = (function () { # 🎉 We've successfully uploaded an image directly to S3! + +### Learning Resources + +- Amazon documentation - [Browser-Based Upload using HTTP POST (Using AWS Signature Version 4)](http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html) +- Leonid Shevtsov - [Demystifying direct uploads from the browser to Amazon S3](https://leonid.shevtsov.me/post/demystifying-s3-browser-upload/) +- Stackoverflow Q - [Amazon S3 POST api, and signing a policy with NodeJS](http://stackoverflow.com/questions/18476217/amazon-s3-post-api-and-signing-a-policy-with-nodejs) +- AWS Articles - [Browser Uploads to S3 using HTML POST Forms +](https://aws.amazon.com/articles/1434) From 4e5c6e1cc5f6ad4b4afe64814e193eed5bea51e8 Mon Sep 17 00:00:00 2001 From: Jack Carlisle Date: Fri, 16 Sep 2016 15:26:50 +0100 Subject: [PATCH 06/11] adds css to the demo #18 --- examples/direct-upload/public/index.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/direct-upload/public/index.html b/examples/direct-upload/public/index.html index f4a175a..3fb23f8 100644 --- a/examples/direct-upload/public/index.html +++ b/examples/direct-upload/public/index.html @@ -7,10 +7,12 @@

S3 Direct Upload Demo

+
- +
- +
+
From 9f32c36a62f85ff55abe019df5bb59a29235f67b Mon Sep 17 00:00:00 2001 From: Jack Carlisle Date: Fri, 16 Sep 2016 15:32:10 +0100 Subject: [PATCH 07/11] adds screenshot of demo to the readme #18 --- examples/direct-upload/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/direct-upload/README.md b/examples/direct-upload/README.md index b827368..b669625 100644 --- a/examples/direct-upload/README.md +++ b/examples/direct-upload/README.md @@ -3,6 +3,8 @@ We are going to implement a simple solution for uploading images to an S3 bucket via a POST request from the browser. +![upload example](https://cloud.githubusercontent.com/assets/12450298/18589369/593617dc-7c22-11e6-899d-00ffdc15ac73.png) + ### Contents - [Creating an S3 Bucket](#creating-the-bucket) - [Creating IAM User with S3 Permissions](#creating-an-iam-user-with-s3-permissions) @@ -14,8 +16,7 @@ via a POST request from the browser. ### Step 1 - Creating the bucket -+ Create an S3 bucket on [Amazon Web Services](aws.amazon.co.uk). To do so you'll need to -create an account if you haven't got one already. ++ Create an S3 bucket on [Amazon Web Services](aws.amazon.co.uk). To do so you'll need to create an account if you haven't got one already. ![sign up](https://cloud.githubusercontent.com/assets/12450298/18392395/86991fb8-76a9-11e6-83d8-f16d7751b41d.png) From ccaad492a711316a8a322c8a4a857b54f52c42be Mon Sep 17 00:00:00 2001 From: Jack Carlisle Date: Fri, 16 Sep 2016 15:37:44 +0100 Subject: [PATCH 08/11] adds favicon to demo #18 --- examples/direct-upload/public/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/direct-upload/public/index.html b/examples/direct-upload/public/index.html index 3fb23f8..1346838 100644 --- a/examples/direct-upload/public/index.html +++ b/examples/direct-upload/public/index.html @@ -2,6 +2,7 @@ S3 Upload Demo + From 77968f3d44edde38cd4e0de5315f9a356e1421b7 Mon Sep 17 00:00:00 2001 From: Jack Carlisle Date: Fri, 16 Sep 2016 17:17:26 +0100 Subject: [PATCH 09/11] changes the title of the readme #18 --- examples/direct-upload/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/direct-upload/README.md b/examples/direct-upload/README.md index b669625..6688656 100644 --- a/examples/direct-upload/README.md +++ b/examples/direct-upload/README.md @@ -1,4 +1,4 @@ -## Direct Upload Example +## Direct Upload to S3 - A Complete Guide We are going to implement a simple solution for uploading images to an S3 bucket via a POST request from the browser. From edd52ad4890214fdd3850959496efd526cc5f9e3 Mon Sep 17 00:00:00 2001 From: Jack Carlisle Date: Fri, 16 Sep 2016 17:18:36 +0100 Subject: [PATCH 10/11] changes the title to a main header #18 --- examples/direct-upload/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/direct-upload/README.md b/examples/direct-upload/README.md index 6688656..ce3b9ea 100644 --- a/examples/direct-upload/README.md +++ b/examples/direct-upload/README.md @@ -1,4 +1,4 @@ -## Direct Upload to S3 - A Complete Guide +# Direct Upload to S3 - A Complete Guide We are going to implement a simple solution for uploading images to an S3 bucket via a POST request from the browser. From bdc03eb25722a01414f6e056a13f6da78af002b1 Mon Sep 17 00:00:00 2001 From: Jack Carlisle Date: Fri, 16 Sep 2016 17:21:49 +0100 Subject: [PATCH 11/11] fixes the anchor links in contents #18 --- examples/direct-upload/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/direct-upload/README.md b/examples/direct-upload/README.md index ce3b9ea..9e054fd 100644 --- a/examples/direct-upload/README.md +++ b/examples/direct-upload/README.md @@ -6,12 +6,12 @@ via a POST request from the browser. ![upload example](https://cloud.githubusercontent.com/assets/12450298/18589369/593617dc-7c22-11e6-899d-00ffdc15ac73.png) ### Contents -- [Creating an S3 Bucket](#creating-the-bucket) -- [Creating IAM User with S3 Permissions](#creating-an-iam-user-with-s3-permissions) -- [Generate a Signed S3 Policy](#generate-a-signed-s3-policy) -- [Create a Server](#create-a-server-to-facilitate-the-credential-creation) -- [Server and S3 Requests](#write-the-client-side-code-to-send-our-requests-to-the-backend-and-then-to-s3) -- [Take it for a Spin](#take-it-for-a-spin!) +- [Creating an S3 Bucket](#step-1---creating-the-bucket) +- [Creating IAM User with S3 Permissions](#step-2---creating-an-iam-user-with-s3-permissions) +- [Generate a Signed S3 Policy](#step-3---generate-a-signed-s3-policy) +- [Create a Server](#step-4---create-a-server-to-facilitate-the-credential-creation) +- [Server and S3 Requests](#step-5---write-the-client-side-code-to-send-our-requests-to-the-backend-and-then-to-s3) +- [Take it for a Spin](#take-it-for-a-spin) - [Learning Resources](#learning-resources) ### Step 1 - Creating the bucket @@ -582,7 +582,7 @@ var uploadDemo = (function () { ``` #### We've now written the neccessary code needed to upload directly to S3! -##### Take it for a spin! +### Take it for a spin! + In your terminal run the following command to start the server: `$ node lib/index.js`