koa-helmet 3.3.0 → 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +39 -0
- package/.travis.yml +2 -2
- package/README.md +14 -9
- package/lib/koa-helmet.js +18 -18
- package/lib/promisify.js +8 -8
- package/package.json +19 -10
- package/test/.eslintrc.js +5 -0
- package/test/koa-helmet.spec.js +116 -82
- package/test/promisify.spec.js +30 -25
- package/yarn.lock +0 -2783
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
"env": {
|
|
3
|
+
"es6": true,
|
|
4
|
+
"node": true
|
|
5
|
+
},
|
|
6
|
+
"extends": [
|
|
7
|
+
"eslint:recommended",
|
|
8
|
+
"plugin:node/recommended"
|
|
9
|
+
],
|
|
10
|
+
"parserOptions": {
|
|
11
|
+
"ecmaVersion": 2017,
|
|
12
|
+
"sourceType": "module"
|
|
13
|
+
},
|
|
14
|
+
"plugins": [
|
|
15
|
+
"node"
|
|
16
|
+
],
|
|
17
|
+
"rules": {
|
|
18
|
+
"indent": [
|
|
19
|
+
"error",
|
|
20
|
+
2
|
|
21
|
+
],
|
|
22
|
+
"linebreak-style": [
|
|
23
|
+
"error",
|
|
24
|
+
"unix"
|
|
25
|
+
],
|
|
26
|
+
"quotes": [
|
|
27
|
+
"error",
|
|
28
|
+
"single"
|
|
29
|
+
],
|
|
30
|
+
"semi": [
|
|
31
|
+
"error",
|
|
32
|
+
"always"
|
|
33
|
+
],
|
|
34
|
+
"space-before-function-paren": [
|
|
35
|
+
"error",
|
|
36
|
+
"always"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
};
|
package/.travis.yml
CHANGED
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ koa-helmet
|
|
|
5
5
|
[](https://travis-ci.org/venables/koa-helmet)
|
|
6
6
|
[](https://coveralls.io/github/venables/koa-helmet)
|
|
7
7
|
[](https://david-dm.org/venables/koa-helmet)
|
|
8
|
-
[](https://github.com/Flet/semistandard)
|
|
9
9
|
[](https://www.npmjs.com/package/koa-helmet)
|
|
10
10
|
|
|
11
11
|
koa-helmet is a wrapper for [helmet](https://github.com/helmetjs/helmet) to work with [koa](https://github.com/koajs/koa). It provides important security headers to make your app more secure by default.
|
|
@@ -28,12 +28,15 @@ Usage
|
|
|
28
28
|
|
|
29
29
|
Usage is the same as [helmet](https://github.com/helmetjs/helmet)
|
|
30
30
|
|
|
31
|
-
Helmet offers
|
|
31
|
+
Helmet offers 14 security middleware functions:
|
|
32
32
|
|
|
33
33
|
| Module | Default? |
|
|
34
34
|
|---|---|
|
|
35
35
|
| [contentSecurityPolicy](https://helmetjs.github.io/docs/csp/) for setting Content Security Policy | |
|
|
36
|
+
| [permittedCrossDomainPolicies](https://helmetjs.github.io/docs/crossdomain/) for handling Adobe products' crossdomain requests | |
|
|
36
37
|
| [dnsPrefetchControl](https://helmetjs.github.io/docs/dns-prefetch-control) controls browser DNS prefetching | ✓ |
|
|
38
|
+
| [expectCt](https://helmetjs.github.io/docs/expect-ct/) for handling Certificate Transparency | |
|
|
39
|
+
| [featurePolicy](https://helmetjs.github.io/docs/feature-policy/) to limit your site's features | |
|
|
37
40
|
| [frameguard](https://helmetjs.github.io/docs/frameguard/) to prevent clickjacking | ✓ |
|
|
38
41
|
| [hidePoweredBy](https://helmetjs.github.io/docs/hide-powered-by) to remove the X-Powered-By header | ✓ |
|
|
39
42
|
| [hpkp](https://helmetjs.github.io/docs/hpkp/) for HTTP Public Key Pinning | |
|
|
@@ -57,17 +60,19 @@ Example
|
|
|
57
60
|
-------
|
|
58
61
|
|
|
59
62
|
```js
|
|
60
|
-
|
|
61
|
-
const helmet = require('koa-helmet')
|
|
62
|
-
const app = new Koa()
|
|
63
|
+
"use strict";
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
const Koa = require("koa");
|
|
66
|
+
const helmet = require("koa-helmet");
|
|
67
|
+
const app = new Koa();
|
|
68
|
+
|
|
69
|
+
app.use(helmet());
|
|
65
70
|
|
|
66
71
|
app.use((ctx) => {
|
|
67
|
-
ctx.body =
|
|
68
|
-
})
|
|
72
|
+
ctx.body = "Hello World"
|
|
73
|
+
});
|
|
69
74
|
|
|
70
|
-
app.listen(4000)
|
|
75
|
+
app.listen(4000);
|
|
71
76
|
```
|
|
72
77
|
|
|
73
78
|
|
package/lib/koa-helmet.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
'use strict'
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
|
-
const helmet = require('helmet')
|
|
4
|
-
const promisify = require('./promisify')
|
|
3
|
+
const helmet = require('helmet');
|
|
4
|
+
const promisify = require('./promisify');
|
|
5
5
|
|
|
6
6
|
const koaHelmet = function () {
|
|
7
|
-
const helmetPromise = promisify(helmet.apply(null, arguments))
|
|
7
|
+
const helmetPromise = promisify(helmet.apply(null, arguments));
|
|
8
8
|
|
|
9
9
|
const middleware = (ctx, next) => {
|
|
10
|
-
ctx.req.secure = ctx.request.secure
|
|
11
|
-
return helmetPromise(ctx.req, ctx.res).then(next)
|
|
12
|
-
}
|
|
13
|
-
middleware._name = 'helmet'
|
|
14
|
-
return middleware
|
|
15
|
-
}
|
|
10
|
+
ctx.req.secure = ctx.request.secure;
|
|
11
|
+
return helmetPromise(ctx.req, ctx.res).then(next);
|
|
12
|
+
};
|
|
13
|
+
middleware._name = 'helmet';
|
|
14
|
+
return middleware;
|
|
15
|
+
};
|
|
16
16
|
|
|
17
17
|
Object.keys(helmet).forEach(function (helmetMethod) {
|
|
18
18
|
koaHelmet[helmetMethod] = function () {
|
|
19
|
-
const method = helmet[helmetMethod]
|
|
20
|
-
const methodPromise = promisify(method.apply(null, arguments))
|
|
19
|
+
const method = helmet[helmetMethod];
|
|
20
|
+
const methodPromise = promisify(method.apply(null, arguments));
|
|
21
21
|
|
|
22
22
|
return (ctx, next) => {
|
|
23
|
-
ctx.req.secure = ctx.request.secure
|
|
24
|
-
return methodPromise(ctx.req, ctx.res).then(next)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
})
|
|
23
|
+
ctx.req.secure = ctx.request.secure;
|
|
24
|
+
return methodPromise(ctx.req, ctx.res).then(next);
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
28
|
|
|
29
|
-
module.exports = koaHelmet
|
|
29
|
+
module.exports = koaHelmet;
|
package/lib/promisify.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
'use strict'
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Takes an express-style middleware and returns a promise-based version (returning a Promise,
|
|
@@ -7,18 +7,18 @@
|
|
|
7
7
|
* @param {Function} middleware - The middleware to promisify
|
|
8
8
|
* @returns {Function} - The middleware function updated to return a Promise, not call a callback
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
function koaHelmetPromisify (middleware) {
|
|
11
11
|
return function (req, res) {
|
|
12
12
|
return new Promise(function (resolve, reject) {
|
|
13
13
|
middleware(req, res, function (err) {
|
|
14
14
|
if (err) {
|
|
15
|
-
return reject(err)
|
|
15
|
+
return reject(err);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
return resolve()
|
|
19
|
-
})
|
|
20
|
-
})
|
|
21
|
-
}
|
|
18
|
+
return resolve();
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
module.exports =
|
|
24
|
+
module.exports = koaHelmetPromisify;
|
package/package.json
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
"author": "Matt Venables <mattvenables@gmail.com>",
|
|
4
4
|
"description": "Security header middleware collection for koa",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "
|
|
6
|
+
"version": "4.2.1",
|
|
7
7
|
"main": "lib/koa-helmet.js",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"
|
|
9
|
+
"format": "eslint lib test --fix",
|
|
10
|
+
"lint": "eslint lib test",
|
|
11
|
+
"test": "eslint lib test && nyc ava",
|
|
10
12
|
"coverage": "nyc report --reporter=text-lcov | coveralls"
|
|
11
13
|
},
|
|
12
14
|
"keywords": [
|
|
@@ -21,17 +23,24 @@
|
|
|
21
23
|
"url": "git://github.com/venables/koa-helmet.git"
|
|
22
24
|
},
|
|
23
25
|
"engines": {
|
|
24
|
-
"node": ">=
|
|
26
|
+
"node": ">= 6.0.0"
|
|
25
27
|
},
|
|
26
28
|
"dependencies": {
|
|
27
|
-
"helmet": "^3.
|
|
29
|
+
"helmet": "^3.15.1"
|
|
28
30
|
},
|
|
29
31
|
"devDependencies": {
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
32
|
+
"ava": "^1.3.1",
|
|
33
|
+
"coveralls": "^3.0.3",
|
|
34
|
+
"eslint": "^5.15.1",
|
|
35
|
+
"eslint-plugin-node": "^8.0.1",
|
|
36
|
+
"koa": "^2.7.0",
|
|
37
|
+
"nyc": "^13.3.0",
|
|
38
|
+
"supertest": "^4.0.0"
|
|
39
|
+
},
|
|
40
|
+
"nyc": {
|
|
41
|
+
"reporter": [
|
|
42
|
+
"lcov",
|
|
43
|
+
"text"
|
|
44
|
+
]
|
|
36
45
|
}
|
|
37
46
|
}
|
package/test/koa-helmet.spec.js
CHANGED
|
@@ -1,84 +1,118 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const helmet = require('../');
|
|
4
|
+
const Koa = require('koa');
|
|
5
|
+
const request = require('supertest');
|
|
6
|
+
const test = require('ava');
|
|
7
|
+
|
|
8
|
+
test('it works with the default helmet call', t => {
|
|
9
|
+
const app = new Koa();
|
|
10
|
+
app.use(helmet());
|
|
11
|
+
app.use((ctx) => {
|
|
12
|
+
ctx.body = 'Hello world!';
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
request(app.listen())
|
|
17
|
+
.get('/')
|
|
18
|
+
|
|
19
|
+
// dnsPrefetchControl
|
|
20
|
+
.expect('X-DNS-Prefetch-Control', 'off')
|
|
21
|
+
|
|
22
|
+
// frameguard
|
|
23
|
+
.expect('X-Frame-Options', 'SAMEORIGIN')
|
|
24
|
+
|
|
25
|
+
// hsts: Not enabled in HTTP
|
|
26
|
+
.expect('Strict-Transport-Security', 'max-age=15552000; includeSubDomains')
|
|
27
|
+
|
|
28
|
+
// ieNoOpen
|
|
29
|
+
.expect('X-Download-Options', 'noopen')
|
|
30
|
+
|
|
31
|
+
// noSniff
|
|
32
|
+
.expect('X-Content-Type-Options', 'nosniff')
|
|
33
|
+
|
|
34
|
+
// xssFilter
|
|
35
|
+
.expect('X-XSS-Protection', '1; mode=block')
|
|
36
|
+
.expect(200)
|
|
37
|
+
.then(() => t.pass())
|
|
38
|
+
.catch(err => t.fail(err))
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('it sets individual headers properly', t => {
|
|
43
|
+
const app = new Koa();
|
|
44
|
+
app.use(
|
|
45
|
+
helmet.hsts({
|
|
46
|
+
force: true
|
|
38
47
|
})
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
return request(app.listen())
|
|
62
|
-
.get('/')
|
|
63
|
-
// noCache
|
|
64
|
-
.expect('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate')
|
|
65
|
-
.expect('Pragma', 'no-cache')
|
|
66
|
-
.expect('Expires', '0')
|
|
67
|
-
|
|
68
|
-
// hsts
|
|
69
|
-
.expect('Strict-Transport-Security', 'max-age=15552000; includeSubDomains')
|
|
70
|
-
|
|
71
|
-
// xssFilter
|
|
72
|
-
.expect('X-XSS-Protection', '1; mode=block')
|
|
73
|
-
|
|
74
|
-
// frameguard
|
|
75
|
-
.expect('X-Frame-Options', 'SAMEORIGIN')
|
|
76
|
-
|
|
77
|
-
// noSniff
|
|
78
|
-
.expect('X-Content-Type-Options', 'nosniff')
|
|
79
|
-
|
|
80
|
-
// hpkp
|
|
81
|
-
.expect('Public-Key-Pins', 'pin-sha256="AbCdEf123="; pin-sha256="ZyXwVu456="; max-age=1000; includeSubDomains; report-uri="http://example.com"')
|
|
48
|
+
);
|
|
49
|
+
app.use(helmet.noCache());
|
|
50
|
+
app.use(helmet.xssFilter());
|
|
51
|
+
app.use(helmet.frameguard('deny'));
|
|
52
|
+
app.use(helmet.noSniff());
|
|
53
|
+
app.use(helmet.permittedCrossDomainPolicies());
|
|
54
|
+
app.use(helmet.expectCt());
|
|
55
|
+
app.use(helmet.featurePolicy({
|
|
56
|
+
features: {
|
|
57
|
+
fullscreen: ['\'self\''],
|
|
58
|
+
notifications: ['\'none\''],
|
|
59
|
+
vibrate: ['\'none\'']
|
|
60
|
+
}
|
|
61
|
+
}));
|
|
62
|
+
app.use(
|
|
63
|
+
helmet.hpkp({
|
|
64
|
+
maxAge: 1000,
|
|
65
|
+
sha256s: ['AbCdEf123=', 'ZyXwVu456='],
|
|
66
|
+
includeSubdomains: true,
|
|
67
|
+
reportUri: 'http://example.com'
|
|
82
68
|
})
|
|
83
|
-
|
|
84
|
-
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
app.use(ctx => {
|
|
72
|
+
ctx.body = 'Hello world!';
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
request(app.listen())
|
|
77
|
+
.get('/')
|
|
78
|
+
// noCache
|
|
79
|
+
.expect(
|
|
80
|
+
'Cache-Control',
|
|
81
|
+
'no-store, no-cache, must-revalidate, proxy-revalidate'
|
|
82
|
+
)
|
|
83
|
+
.expect('Pragma', 'no-cache')
|
|
84
|
+
.expect('Expires', '0')
|
|
85
|
+
|
|
86
|
+
// hsts
|
|
87
|
+
.expect(
|
|
88
|
+
'Strict-Transport-Security',
|
|
89
|
+
'max-age=15552000; includeSubDomains'
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
// xssFilter
|
|
93
|
+
.expect('X-XSS-Protection', '1; mode=block')
|
|
94
|
+
|
|
95
|
+
// frameguard
|
|
96
|
+
.expect('X-Frame-Options', 'SAMEORIGIN')
|
|
97
|
+
|
|
98
|
+
// noSniff
|
|
99
|
+
.expect('X-Content-Type-Options', 'nosniff')
|
|
100
|
+
|
|
101
|
+
// permittedCrossDomainPolicies
|
|
102
|
+
.expect('X-Permitted-Cross-Domain-Policies', 'none')
|
|
103
|
+
|
|
104
|
+
// expectCt
|
|
105
|
+
.expect('Expect-CT', 'max-age=0')
|
|
106
|
+
|
|
107
|
+
// featurePolicy
|
|
108
|
+
.expect('Feature-Policy', 'fullscreen \'self\';notifications \'none\';vibrate \'none\'')
|
|
109
|
+
|
|
110
|
+
// hpkp
|
|
111
|
+
.expect(
|
|
112
|
+
'Public-Key-Pins',
|
|
113
|
+
'pin-sha256="AbCdEf123="; pin-sha256="ZyXwVu456="; max-age=1000; includeSubDomains; report-uri="http://example.com"'
|
|
114
|
+
)
|
|
115
|
+
.then(() => t.pass())
|
|
116
|
+
.catch(err => t.fail(err))
|
|
117
|
+
);
|
|
118
|
+
});
|
package/test/promisify.spec.js
CHANGED
|
@@ -1,33 +1,38 @@
|
|
|
1
|
-
'use strict'
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const promisify = require('../lib/promisify')
|
|
3
|
+
const promisify = require('../lib/promisify');
|
|
4
|
+
const test = require('ava');
|
|
6
5
|
|
|
7
6
|
function passingMiddleware (req, res, next) {
|
|
8
|
-
return next()
|
|
7
|
+
return next();
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
function failingMiddleware (req, res, next) {
|
|
12
|
-
return next(new Error('Expected Failure'))
|
|
11
|
+
return next(new Error('Expected Failure'));
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
14
|
+
test('returns a promisified version of the middleware which resolves the Promise on success', t => {
|
|
15
|
+
let middleware = promisify(passingMiddleware);
|
|
16
|
+
|
|
17
|
+
return middleware().then(
|
|
18
|
+
() => {
|
|
19
|
+
t.pass();
|
|
20
|
+
},
|
|
21
|
+
err => {
|
|
22
|
+
t.fail(err);
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('returns a promisified version of the middleware which rejects the Promise on failure', t => {
|
|
28
|
+
let middleware = promisify(failingMiddleware);
|
|
29
|
+
|
|
30
|
+
return middleware().then(
|
|
31
|
+
() => {
|
|
32
|
+
t.fail('Unexpected Success!');
|
|
33
|
+
},
|
|
34
|
+
() => {
|
|
35
|
+
t.pass();
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
});
|