Skip to content

Commit

Permalink
add s3 url signing to redirects
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremydaly committed Aug 15, 2018
1 parent 7988df7 commit 38b3477
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 14 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ api.get('/redirectToGithub', (req,res) => {
```

### redirect([status,] path)
The `redirect` convenience method triggers a redirection and ends the current API execution. This method is similar to the `location()` method, but it automatically sets the status code and calls `send()`. The redirection URL (relative/absolute path OR a FQDN) can be specified as the only parameter or as a second parameter when a valid `3xx` status code is supplied as the first parameter. The status code is set to `302` by default, but can be changed to `300`, `301`, `302`, `303`, `307`, or `308` by adding it as the first parameter.
The `redirect` convenience method triggers a redirection and ends the current API execution. This method is similar to the `location()` method, but it automatically sets the status code and calls `send()`. The redirection URL (relative/absolute path, a FQDN, or an S3 path reference) can be specified as the only parameter or as a second parameter when a valid `3xx` status code is supplied as the first parameter. The status code is set to `302` by default, but can be changed to `300`, `301`, `302`, `303`, `307`, or `308` by adding it as the first parameter.

```javascript
api.get('/redirectToHome', (req,res) => {
Expand All @@ -490,6 +490,11 @@ api.get('/redirectToHome', (req,res) => {
api.get('/redirectToGithub', (req,res) => {
res.redirect(301,'https://github.com')
})

// This will redirect a signed URL using the getLink method
api.get('/redirectToS3File', (req,res) => {
res.redirect('s3://my-bucket/someFile.pdf')
})
```

### cors([options])
Expand Down
34 changes: 21 additions & 13 deletions lib/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,24 +108,32 @@ class RESPONSE {
}

// Convenience method for Redirect
redirect(path) {
async redirect(path) {
let statusCode = 302 // default

// If status code is provided
if (arguments.length === 2) {
if ([300,301,302,303,307,308].includes(arguments[0])) {
statusCode = arguments[0]
path = arguments[1]
} else {
throw new Error(arguments[0] + ' is an invalid redirect status code')
try {
// If status code is provided
if (arguments.length === 2) {
if ([300,301,302,303,307,308].includes(arguments[0])) {
statusCode = arguments[0]
path = arguments[1]
} else {
throw new Error(arguments[0] + ' is an invalid redirect status code')
}
}
}

let url = UTILS.escapeHtml(path)
// Auto convert S3 paths to signed URLs
if (UTILS.isS3(path)) path = await this.getLink(path)

let url = UTILS.escapeHtml(path)

this.location(path)
.status(statusCode)
.html(`<p>${statusCode} Redirecting to <a href="${url}">${url}</a></p>`)
this.location(path)
.status(statusCode)
.html(`<p>${statusCode} Redirecting to <a href="${url}">${url}</a></p>`)

} catch(e) {
this.error(e)
}
} // end redirect

// Convenience method for retrieving a signed link to an S3 bucket object
Expand Down
35 changes: 35 additions & 0 deletions test/responses.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
'use strict';

const expect = require('chai').expect // Assertion library
const sinon = require('sinon') // Require Sinon.js library
const AWS = require('aws-sdk') // AWS SDK (automatically available in Lambda)
const S3 = require('../lib/s3-service') // Init S3 Service

// Init API instance
const api = require('../index')({ version: 'v1.0' })
Expand Down Expand Up @@ -77,12 +80,25 @@ api.get('/redirectHTML', function(req,res) {
res.redirect('http://www.github.com?foo=bar&bat=baz<script>alert(\'not good\')</script>')
})

api.get('/s3Path', function(req,res) {
stub.callsArgWith(2, null, 'https://s3.amazonaws.com/my-test-bucket/test/test.txt?AWSAccessKeyId=AKXYZ&Expires=1534290845&Signature=XYZ')
res.redirect('s3://my-test-bucket/test/test.txt')
})


/******************************************************************************/
/*** BEGIN TESTS ***/
/******************************************************************************/

let stub

describe('Response Tests:', function() {

before(function() {
// Stub getSignedUrl
stub = sinon.stub(S3,'getSignedUrl')
})

it('Object response: convert to string', async function() {
let _event = Object.assign({},event,{ path: '/testObjectResponse'})
let result = await new Promise(r => api.run(_event,{},(e,res) => { r(res) }))
Expand Down Expand Up @@ -173,4 +189,23 @@ describe('Response Tests:', function() {
expect(result).to.deep.equal({ headers: { 'content-type': 'text/html', 'location': 'http://www.github.com?foo=bar&bat=baz%3Cscript%3Ealert(\'not%20good\')%3C/script%3E' }, statusCode: 302, body: '<p>302 Redirecting to <a href=\"http://www.github.com?foo=bar&amp;bat=baz&lt;script&gt;alert(&#39;not good&#39;)&lt;/script&gt;\">http://www.github.com?foo=bar&amp;bat=baz&lt;script&gt;alert(&#39;not good&#39;)&lt;/script&gt;</a></p>', isBase64Encoded: false })
}) // end it

it('S3 Path', async function() {
let _event = Object.assign({},event,{ path: '/s3Path' })
let result = await new Promise(r => api.run(_event,{},(e,res) => { r(res) }))
expect(result).to.deep.equal({
headers: {
'content-type': 'text/html',
'location': 'https://s3.amazonaws.com/my-test-bucket/test/test.txt?AWSAccessKeyId=AKXYZ&Expires=1534290845&Signature=XYZ'
},
statusCode: 302,
body: '<p>302 Redirecting to <a href="https://s3.amazonaws.com/my-test-bucket/test/test.txt?AWSAccessKeyId=AKXYZ&amp;Expires=1534290845&amp;Signature=XYZ">https://s3.amazonaws.com/my-test-bucket/test/test.txt?AWSAccessKeyId=AKXYZ&amp;Expires=1534290845&amp;Signature=XYZ</a></p>',
isBase64Encoded: false
})
expect(stub.lastCall.args[1]).to.deep.equal({ Bucket: 'my-test-bucket', Key: 'test/test.txt', Expires: 900 })
}) // end it

after(function() {
stub.restore()
})

}) // end ERROR HANDLING tests

0 comments on commit 38b3477

Please sign in to comment.