Skip to content

Commit

Permalink
fix: No defining any CORS in the now.json just fully disable CORS checks
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasdao committed Jan 17, 2018
1 parent 2d2c67d commit 84a1ade
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 28 deletions.
42 changes: 22 additions & 20 deletions src/cors.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
const url = require('url')

const getRequiredResponseHeaders = (config={}) => {
const headers = config.headers || {}
Expand Down Expand Up @@ -33,27 +34,29 @@ const getAllowedMethods = (config={}) =>

const setResponseHeaders = (res, responseHeaders=[]) => responseHeaders.forEach(header => res.set(header.key, header.value))

const validateCORS = (req, res, config={}, allowedOrigins={}, allowedMethods={}) => {
const noConfig = !config.headers
const origin = new String(req.headers.origin).toLowerCase()
const referer = new String(req.headers.referer).toLowerCase()
const method = new String(req.method).toLowerCase()
const sameOrigin = referer.indexOf(origin) == 0
const getRequestOrigin = req => {
const origin = (req.headers.origin || '').toLowerCase()
const host = (req.headers.host || '').toLowerCase()
const referer = (req.headers.referer || req.headers.referrer || '').toLowerCase()
const https = req.secure !== undefined ? req.secure : (req.url || '').trim().match(/^https:/)
const refUrl = url.parse(referer)

if (noConfig) {
if (!sameOrigin) {
res.status(403).send(`Forbidden - CORS issue. Origin '${origin}' is not allowed.`)
return false
}
if (origin)
return origin
else if (host)
return `${https ? 'https:' : 'http:'}//${host}`
else if (referer && refUrl.host)
return refUrl.protocol ? `${refUrl.protocol}//${refUrl.host}` : `${https ? 'https:' : 'http:'}//${refUrl.host}`
else
return null
}

if (method != 'head' && method != 'get' && method != 'options' && method != 'post') {
res.status(403).send(`Forbidden - CORS issue. Method '${method.toUpperCase()}' is not allowed.`)
return false
}
}
const validateCORS = (req, res, allowedOrigins={}, allowedMethods={}) => {
const origin = getRequestOrigin(req)
const method = (req.method || '').toLowerCase()

if (!allowedOrigins['*'] && Object.keys(allowedOrigins).length > 0 && !(origin in allowedOrigins)) {
res.status(403).send(`Forbidden - CORS issue. Origin '${origin}' is not allowed.`)
res.status(403).send(`Forbidden - CORS issue. Origin '${origin || 'undefined'}' is not allowed.`)
return false
}

Expand All @@ -75,12 +78,10 @@ const cors = (options={}) => {
const allowedOrigins = getAllowedOrigins(options)
const allowedMethods = getAllowedMethods(options)
const setHeaders = requiredHeaders.length > 0 ? res => setResponseHeaders(res, requiredHeaders) : () => null
const corsSetUp = Object.keys(allowedOrigins).length > 0 || Object.keys(allowedMethods).length > 0
const config = { headers: corsSetUp ? {} : null }

return (req, res, next) => {
setHeaders(res)
validateCORS(req, res, config, allowedOrigins, allowedMethods)
validateCORS(req, res, allowedOrigins, allowedMethods)
next()
}
}
Expand All @@ -91,5 +92,6 @@ module.exports = {
getAllowedMethods,
setResponseHeaders,
validateCORS,
getRequestOrigin,
cors
}
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ const processEvent = (req, res, config={}, endpoints=[], handlers=[], requiredHe
.then(() => {
if (!res.headersSent && !_preEventErr) {
// 5.1. Validate CORS
if (!validateCORS(req, res, config, allowedOrigins, allowedMethods))
if (!validateCORS(req, res, allowedOrigins, allowedMethods))
return

// 5.2. Stop if this is a HEAD or OPTIONS request
Expand Down
41 changes: 40 additions & 1 deletion test/cors.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
const { assert } = require('chai')
const httpMocks = require('node-mocks-http')
const { app, cors } = require('../src/index')
const { getRequestOrigin } = require('../src/cors')

/*eslint-disable */
describe('cors', () =>
Expand Down Expand Up @@ -95,4 +96,42 @@ describe('cors', () =>
})

return Promise.all([result_01, result_02, result_03])
}))
}))

/*eslint-disable */
describe('cors', () =>
describe('getRequestOrigin', () =>
it(`Should retrieves the request's origin even if it is not explecitely defined (look for referer, host, ...).`, () => {
/*eslint-enable */
const requests = [
httpMocks.createRequest({
headers: {
origin: 'http://localhost:8080'
}
}),
httpMocks.createRequest({
headers: {
referer: 'http://localhost:8080'
}
}),
httpMocks.createRequest({
headers: {
host: 'localhost:8080'
},
secure: false
}),
httpMocks.createRequest({
headers: {
host: 'localhost:8080'
},
url: 'http://localhost:8080'
})]

requests.forEach(req => {
const v = getRequestOrigin(req)
assert.equal(v, 'http://localhost:8080')
})
})))



12 changes: 6 additions & 6 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ describe('app', () =>
/*eslint-disable */
describe('app', () =>
describe('#handleEvent: 02', () =>
it('Should fail if no CORS settings have been set up and the same origin policy if NOT satisfied.', () => {
it('Should not fail if no CORS settings have been set up and the same origin policy if NOT satisfied.', () => {
/*eslint-enable */
const req = httpMocks.createRequest({
method: 'GET',
Expand All @@ -95,8 +95,8 @@ describe('app', () =>
app.get((req, res) => res.status(200).send('Hello World'))
return app.handleEvent()(req, res).then(() => {
assert.isOk(req)
assert.equal(res.statusCode, 403)
assert.equal(res._getData(), 'Forbidden - CORS issue. Origin \'http://localhost:8080\' is not allowed.')
assert.equal(res.statusCode, 200)
assert.equal(res._getData(), 'Hello World')
})
})))

Expand Down Expand Up @@ -291,7 +291,7 @@ describe('app', () =>
/*eslint-disable */
describe('app', () =>
describe('#handleEvent: 09', () =>
it('Should fail if a PUT request if sent and no CORS settings have been set up.', () => {
it('Should not fail if a PUT request if sent and no CORS settings have been set up.', () => {
/*eslint-enable */
const req = httpMocks.createRequest({
method: 'PUT',
Expand All @@ -308,8 +308,8 @@ describe('app', () =>
app.all((req, res) => res.status(200).send('Hello World'))
return app.handleEvent()(req, res).then(() => {
assert.isOk(req)
assert.equal(res.statusCode, 403)
assert.equal(res._getData(), 'Forbidden - CORS issue. Method \'PUT\' is not allowed.')
assert.equal(res.statusCode, 200)
assert.equal(res._getData(), 'Hello World')
})
})))

Expand Down

0 comments on commit 84a1ade

Please sign in to comment.