Skip to content

Commit

Permalink
Merge pull request #6 from dantheman213/feature/custom-options
Browse files Browse the repository at this point in the history
Custom options and improved readme
  • Loading branch information
dantheman213 authored Mar 11, 2019
2 parents 0c5c5db + aabc363 commit e6dac8b
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 26 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.DS_Store
[Tt]humbs.db

.idea/
.idea/

node_modules/
84 changes: 82 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ https://www.npmjs.com/package/hapi-modern-cors

### Description

This plugin adds cors support for your hapi project. There was a major refactor of the hapi project in v17+ that
This plugin adds cors support for your [hapi](https://github.com/hapijs/hapi) project. There was a major refactor of the hapi project in v17+ that
broke previously working paradigms. This plugin supports the very latest versions of hapi.

### Requirements
Expand Down Expand Up @@ -41,7 +41,7 @@ Add `cors` reference and add the register plugin code to your hapi initializatio
// register plugin code here
await server.register({
plugin: cors,
options: {},
options: {}, // Can leave empty. To customize, see `Custom Options` below
});

await server.start();
Expand All @@ -58,8 +58,88 @@ Add `cors` reference and add the register plugin code to your hapi initializatio

`Access-Control-Max-Age` : `1728000`

### Custom Options

All fields are optional and don't need to be included if you're not customizing that value. If a value is not present
then the corresponding default value is used.

###### Sample:

{
allowCreds: <boolean>,
allowMethods: "<string>",
allowHeaders: "<string>",
allowOriginResponse: <boolean>,
overrideOrigin: "<string>",
maxAge: <int>,
}

###### Full Example:

await server.register({
plugin: cors,
options: {
maxAge: 500,
allowCreds: false,
allowOriginResponse: false
},
});

##### allowCreds

Allow credentials to be passed?

###### Example:

true

##### allowMethods

What methods do you want to allow?

###### Example:

'GET,POST'

##### allowHeaders

What headers do you want to allow in your CORS responses?

###### Example:

'Accept, Content-Type'

##### allowOriginResponse

If a request has an `origin` attached to it should your response attach it as the allowed `origin`?

###### Example:

false

By default, if a request has an `origin` attached, it will be passed back as the allowed `origin` in the response and
credentials will be allowed.

##### overrideOrigin

Do you want to set an explicit origin, always?

'https://google.com'

##### maxAge

How long should these CORS headers be cached?

###### Example:

600

### FAQs

##### Is Boom supported?

[Boom](https://github.com/hapijs/boom) is fully supported.

##### How do CORS pre-flight work?

Before requests can begin to use CORS a pre-flight request is typically sent to the server at the same path you're
Expand Down
74 changes: 52 additions & 22 deletions cors.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
const defaultCorsHeaders = [{
key: 'Access-Control-Allow-Methods',
value: 'GET,POST,PUT,DELETE',
}, {
key: 'Access-Control-Allow-Headers',
value: 'Accept, Authorization, Content-Type, If-None-Match, X-Requested-With',
}, {
key: 'Access-Control-Max-Age',
value: 1728000,
}];
let customOptions;

function init(server) {
// setup the CORS pre-flight request paths on all available endpoints

const routes = server.table().map(item => item.path);

// if there is a GET and POST, etc then remove dupes at same path.
const dedupeRoutes = [...(new Set(routes))];

Expand All @@ -22,10 +13,10 @@ function init(server) {
path: route,
config: {
cors: {
maxAge: 1728000,
maxAge: customOptions.maxAge || 1728000,
headers: ['Origin', 'Accept', 'X-Requested-With', 'Content-Type'],
credentials: false,
origin: ['*'],
credentials: customOptions.allowCreds || false,
origin: [customOptions.overrideOrigin || '*'],
},
handler() {
return {
Expand All @@ -37,33 +28,72 @@ function init(server) {
}
}

function setConfig(o) {
customOptions = {};

if (o) {
if (o.allowCreds) {
customOptions.allowCreds = o.allowCreds;
}

if (o.allowMethods) {
customOptions.allowMethods = o.allowMethods;
}

if (o.allowHeaders) {
customOptions.allowHeaders = o.allowHeaders;
}

if (o.allowOriginResponse) {
customOptions.allowOriginResponse = o.allowOriginResponse;
}

if (o.overrideOrigin) {
customOptions.overrideOrigin = o.overrideOrigin;
}

if (o.maxAge) {
customOptions.maxAge = o.maxAge;
}
}
}

async function appendHeaders(request, h) {
let origin = '*';
let allowCreds = false;

if (request.headers.origin) {
if (customOptions.overrideOrigin || (request.headers.origin && customOptions.allowOriginResponse)) {
if (customOptions.overrideOrigin) {
origin = customOptions.overrideOrigin;
} else if(request.headers.origin && customOptions.allowOriginResponse) {
origin = request.headers.origin;
}

allowCreds = customOptions.allowCreds || true;

// CORS spec requires 'Allow-Credentials' header can't be set
// to 'true' when using '*" in 'Allow-Origin' for security purposes.
origin = request.headers.origin; // eslint-disable-line prefer-destructuring
allowCreds = true;
if (origin === '*' && allowCreds)
allowCreds = false;
}

// boom requests handles response obj differently
const response = request.response.isBoom ? request.response.output : request.response;

response.headers['Access-Control-Allow-Origin'] = origin;
response.headers['Access-Control-Allow-Credentials'] = allowCreds;
for (const defaultHeader of defaultCorsHeaders) {
response.headers[defaultHeader.key] = defaultHeader.value;
}
response.headers['Access-Control-Allow-Methods'] = customOptions.allowMethods || 'GET,POST,PUT,DELETE';
response.headers['Access-Control-Allow-Headers'] = customOptions.allowHeaders || 'Accept, Authorization, Content-Type, If-None-Match, X-Requested-With';
response.headers['Access-Control-Max-Age'] = customOptions.maxAge || 1728000;

return h.continue;
}

const cors = {
name: 'cors',
version: '1.0.3',
async register(server) {
version: '1.1.0',
async register(server, options) {
setConfig(options);
init(server);
server.ext('onPreResponse', appendHeaders);
},
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hapi-modern-cors",
"version": "1.0.3",
"version": "1.1.0",
"description": "Enables cors for a hapijs v17+ app after hapijs was refactored.",
"main": "cors.js",
"author": "Daniel Gillespie <[email protected]>",
Expand Down

0 comments on commit e6dac8b

Please sign in to comment.