Skip to content

Commit

Permalink
Filter Preflight only headers + allowCredentials option (#42)
Browse files Browse the repository at this point in the history
* send preflight headers only for OPTIONS request
* add config for Access-Control-Allow-Credentials
* test new behavior
  • Loading branch information
infernalmaster authored and tim-phillips committed Oct 5, 2018
1 parent 7181703 commit f017b7d
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 50 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ default: `['POST','GET','PUT','PATCH','DELETE','OPTIONS']`

default: `['X-Requested-With','Access-Control-Allow-Origin','X-HTTP-Method-Override','Content-Type','Authorization','Accept']`

##### `allowCredentials`

default: `true`

##### `exposeHeaders`

default: `[]`
Expand Down
20 changes: 13 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,31 @@ const DEFAULT_ALLOW_HEADERS = [

const DEFAULT_MAX_AGE_SECONDS = 60 * 60 * 24 // 24 hours

const cors = options => handler => (req, res, ...restArgs) => {
const cors = (options = {}) => handler => (req, res, ...restArgs) => {
const {
origin = '*',
maxAge = DEFAULT_MAX_AGE_SECONDS,
allowMethods = DEFAULT_ALLOW_METHODS,
allowHeaders = DEFAULT_ALLOW_HEADERS,
allowCredentials = true,
exposeHeaders = []
} = (options || {})
} = options

res.setHeader('Access-Control-Allow-Credentials', 'true')
res.setHeader('Access-Control-Max-Age', String(maxAge))
res.setHeader('Access-Control-Allow-Origin', origin)
res.setHeader('Access-Control-Allow-Methods', allowMethods.join(','))
res.setHeader('Access-Control-Allow-Headers', allowHeaders.join(','))

if (allowCredentials) {
res.setHeader('Access-Control-Allow-Credentials', 'true')
}
if (exposeHeaders.length) {
res.setHeader('Access-Control-Expose-Headers', exposeHeaders.join(','))
}

const preFlight = req.method === 'OPTIONS'
if (preFlight) {
res.setHeader('Access-Control-Allow-Methods', allowMethods.join(','))
res.setHeader('Access-Control-Allow-Headers', allowHeaders.join(','))
res.setHeader('Access-Control-Max-Age', String(maxAge))
}

return handler(req, res, ...restArgs)
}

Expand Down
108 changes: 65 additions & 43 deletions src/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const methods = [
'OPTIONS'
]

test('adds default max age header', async t => {
test('adds default max age header only for OPTIONS request', async t => {
const cors = microCors()
const router = micro(cors(() => ({})))
const url = await listen(router)
Expand All @@ -36,8 +36,12 @@ test('adds default max age header', async t => {
...testRequestOptions
})

const maxAgeHeader = response.headers['access-control-max-age']
t.deepEqual(maxAgeHeader, '86400')
if (method === 'OPTIONS') {
const maxAgeHeader = response.headers['access-control-max-age']
t.deepEqual(maxAgeHeader, '86400')
} else {
t.false(Object.keys(response.headers).includes('access-control-max-age'))
}
}
})

Expand All @@ -46,16 +50,14 @@ test('adds configured max age header', async t => {
const router = micro(cors(() => ({})))
const url = await listen(router)

for (let method of methods) {
const response = await request({
url,
method,
...testRequestOptions
})
const response = await request({
url,
method: 'OPTIONS',
...testRequestOptions
})

const maxAgeHeader = response.headers['access-control-max-age']
t.deepEqual(maxAgeHeader, 'foo')
}
const maxAgeHeader = response.headers['access-control-max-age']
t.deepEqual(maxAgeHeader, 'foo')
})

test('adds default allow origin header', async t => {
Expand Down Expand Up @@ -94,7 +96,7 @@ test('adds configured allow origin header', async t => {
}
})

test('adds default allow methods header', async t => {
test('adds default allow methods header only for OPTIONS request', async t => {
const cors = microCors()
const router = micro(cors(() => ({})))
const url = await listen(router)
Expand All @@ -106,8 +108,12 @@ test('adds default allow methods header', async t => {
...testRequestOptions
})

const allowMethodsHeader = response.headers['access-control-allow-methods']
t.deepEqual(allowMethodsHeader, 'POST,GET,PUT,PATCH,DELETE,OPTIONS')
if (method === 'OPTIONS') {
const allowMethodsHeader = response.headers['access-control-allow-methods']
t.deepEqual(allowMethodsHeader, 'POST,GET,PUT,PATCH,DELETE,OPTIONS')
} else {
t.false(Object.keys(response.headers).includes('access-control-allow-methods'))
}
}
})

Expand All @@ -116,19 +122,17 @@ test('adds configured allow methods header', async t => {
const router = micro(cors(() => ({})))
const url = await listen(router)

for (let method of methods) {
const response = await request({
url,
method,
...testRequestOptions
})
const response = await request({
url,
method: 'OPTIONS',
...testRequestOptions
})

const allowMethodsHeader = response.headers['access-control-allow-methods']
t.deepEqual(allowMethodsHeader, 'FOO')
}
const allowMethodsHeader = response.headers['access-control-allow-methods']
t.deepEqual(allowMethodsHeader, 'FOO')
})

test('adds default allow headers header', async t => {
test('adds default allow headers header only for OPTIONS request', async t => {
const cors = microCors()
const router = micro(cors(() => ({})))
const url = await listen(router)
Expand All @@ -140,11 +144,15 @@ test('adds default allow headers header', async t => {
...testRequestOptions
})

const allowMethodsHeader = response.headers['access-control-allow-headers']
t.deepEqual(
allowMethodsHeader,
'X-Requested-With,Access-Control-Allow-Origin,X-HTTP-Method-Override,Content-Type,Authorization,Accept'
)
if (method === 'OPTIONS') {
const allowMethodsHeader = response.headers['access-control-allow-headers']
t.deepEqual(
allowMethodsHeader,
'X-Requested-With,Access-Control-Allow-Origin,X-HTTP-Method-Override,Content-Type,Authorization,Accept'
)
} else {
t.false(Object.keys(response.headers).includes('access-control-allow-headers'))
}
}
})

Expand All @@ -153,19 +161,17 @@ test('adds configured allow headers header', async t => {
const router = micro(cors(() => ({})))
const url = await listen(router)

for (let method of methods) {
const response = await request({
url,
method,
...testRequestOptions
})
const response = await request({
url,
method: 'OPTIONS',
...testRequestOptions
})

const allowMethodsHeader = response.headers['access-control-allow-headers']
t.deepEqual(
allowMethodsHeader,
'BAR'
)
}
const allowMethodsHeader = response.headers['access-control-allow-headers']
t.deepEqual(
allowMethodsHeader,
'BAR'
)
})

test('allows configured expose headers header', async t => {
Expand All @@ -188,7 +194,7 @@ test('allows configured expose headers header', async t => {
}
})

test('adds allow credentials header', async t => {
test('adds allow credentials header by default', async t => {
const cors = microCors()
const router = micro(cors(() => ({})))
const url = await listen(router)
Expand All @@ -206,6 +212,22 @@ test('adds allow credentials header', async t => {
}
})

test('allows remove allow credentials header', async t => {
const cors = microCors({ allowCredentials: false })
const router = micro(cors(() => ({})))
const url = await listen(router)

for (let method of methods) {
const response = await request({
url,
method,
...testRequestOptions
})

t.false(Object.keys(response.headers).includes('access-control-allow-credentials'))
}
})

test('responds to OPTIONS requests', async t => {
const cors = microCors()
const router = micro(cors(() => ({})))
Expand Down

0 comments on commit f017b7d

Please sign in to comment.