Comparing version 0.3.0 to 1.0.0
69
index.js
@@ -1,34 +0,27 @@ | ||
var badArgumentsError = new Error('hpkp must be called with a maxAge and at least two SHA-256s (one actually used and another kept as a backup).'); | ||
var badArgumentsError = new Error('hpkp must be called with a maxAge and at least two SHA-256s (one actually used and another kept as a backup).') | ||
module.exports = function hpkp(passedOptions) { | ||
var options = parseOptions(passedOptions); | ||
var headerKey = getHeaderKey(options); | ||
var headerValue = getHeaderValue(options); | ||
module.exports = function hpkp (passedOptions) { | ||
var options = parseOptions(passedOptions) | ||
var headerKey = getHeaderKey(options) | ||
var headerValue = getHeaderValue(options) | ||
return function hpkp(req, res, next) { | ||
res.setHeader(headerKey, headerValue); | ||
next(); | ||
}; | ||
}; | ||
return function hpkp (req, res, next) { | ||
res.setHeader(headerKey, headerValue) | ||
next() | ||
} | ||
} | ||
function parseOptions(options) { | ||
if (!options) { throw badArgumentsError; } | ||
function parseOptions (options) { | ||
if (!options) { throw badArgumentsError } | ||
if (options.maxage && options.maxAge) { throw badArgumentsError; } | ||
if (options.maxage && options.maxAge) { throw badArgumentsError } | ||
var maxAge = options.maxAge || options.maxage; | ||
var sha256s = options.sha256s; | ||
var maxAge = options.maxAge | ||
var sha256s = options.sha256s | ||
if (!maxAge || maxAge <= 0) { throw badArgumentsError; } | ||
if (!sha256s || sha256s.length < 2) { throw badArgumentsError; } | ||
if (!maxAge || maxAge <= 0) { throw badArgumentsError } | ||
if (!sha256s || sha256s.length < 2) { throw badArgumentsError } | ||
var reportOnly; | ||
if (options.reportOnly === undefined) { | ||
reportOnly = Boolean(options.reportUri); | ||
} else { | ||
reportOnly = options.reportOnly; | ||
} | ||
if (options.reportOnly && !options.reportUri) { throw badArgumentsError } | ||
if (reportOnly && !options.reportUri) { throw badArgumentsError; } | ||
return { | ||
@@ -39,26 +32,26 @@ maxAge: maxAge, | ||
reportUri: options.reportUri, | ||
reportOnly: reportOnly | ||
}; | ||
reportOnly: options.reportOnly | ||
} | ||
} | ||
function getHeaderKey(options) { | ||
var header = 'Public-Key-Pins'; | ||
function getHeaderKey (options) { | ||
var header = 'Public-Key-Pins' | ||
if (options.reportOnly) { | ||
header += '-Report-Only'; | ||
header += '-Report-Only' | ||
} | ||
return header; | ||
return header | ||
} | ||
function getHeaderValue(options) { | ||
function getHeaderValue (options) { | ||
var result = options.sha256s.map(function (sha) { | ||
return 'pin-sha256="' + sha + '"'; | ||
}); | ||
result.push('max-age=' + Math.round(options.maxAge / 1000)); | ||
return 'pin-sha256="' + sha + '"' | ||
}) | ||
result.push('max-age=' + Math.round(options.maxAge / 1000)) | ||
if (options.includeSubdomains) { | ||
result.push('includeSubdomains'); | ||
result.push('includeSubdomains') | ||
} | ||
if (options.reportUri) { | ||
result.push('report-uri="' + options.reportUri + '"'); | ||
result.push('report-uri="' + options.reportUri + '"') | ||
} | ||
return result.join('; '); | ||
return result.join('; ') | ||
} |
@@ -10,3 +10,3 @@ { | ||
"description": "HTTP Public Key Pinning (HPKP) middleware", | ||
"version": "0.3.0", | ||
"version": "1.0.0", | ||
"keywords": [ | ||
@@ -28,9 +28,17 @@ "helmet", | ||
"scripts": { | ||
"test": "mocha" | ||
"test": "standard && mocha" | ||
}, | ||
"devDependencies": { | ||
"connect": "^3.3.4", | ||
"mocha": "^2.1.0", | ||
"supertest": "^0.15.0" | ||
"connect": "^3.4.0", | ||
"mocha": "^2.3.4", | ||
"standard": "^5.4.1", | ||
"supertest": "^1.1.0" | ||
}, | ||
"standard": { | ||
"global": [ | ||
"beforeEach", | ||
"describe", | ||
"it" | ||
] | ||
} | ||
} |
@@ -1,2 +0,5 @@ | ||
# HTTP Public Key Pinning (HPKP) middleware | ||
HTTP Public Key Pinning (HPKP) middleware | ||
========================================= | ||
[![Build Status](https://travis-ci.org/helmetjs/hpkp.svg?branch=master)](https://travis-ci.org/helmetjs/hpkp) | ||
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/) | ||
@@ -8,8 +11,8 @@ Adds Public Key Pinning headers to Express/Connect applications. To learn more about HPKP, check out [the spec](https://tools.ietf.org/html/rfc7469), [the article on MDN](https://developer.mozilla.org/en-US/docs/Web/Security/Public_Key_Pinning), and [this tutorial](https://timtaubert.de/blog/2014/10/http-public-key-pinning-explained/). | ||
```js | ||
var express = require('express'); | ||
var hpkp = require('hpkp'); | ||
var express = require('express') | ||
var hpkp = require('hpkp') | ||
var app = express(); | ||
var app = express() | ||
var ninetyDaysInMilliseconds = 7776000000; | ||
var ninetyDaysInMilliseconds = 7776000000 | ||
app.use(hpkp({ | ||
@@ -20,5 +23,6 @@ maxAge: ninetyDaysInMilliseconds, | ||
reportUri: 'http://example.com' // optional | ||
})); | ||
reportOnly: false // optional | ||
})) | ||
``` | ||
Specifying a `report-uri` changes the header from `Public-Key-Pins` to `Public-Key-Pins-Report-Only`. To reverse this, set another option: `reportOnly: false`. This behavior will change in the 1.0 release. | ||
Setting `reportOnly` to `true` will change the header from `Public-Key-Pins` to `Public-Key-Pins-Report-Only`. |
@@ -1,18 +0,16 @@ | ||
var hpkp = require('..'); | ||
var hpkp = require('..') | ||
var connect = require('connect'); | ||
var request = require('supertest'); | ||
var assert = require('assert'); | ||
var connect = require('connect') | ||
var request = require('supertest') | ||
var assert = require('assert') | ||
describe('hpkp', function () { | ||
describe('with proper input', function () { | ||
function test() { | ||
var app = connect(); | ||
app.use(hpkp.apply(null, arguments)); | ||
function test () { | ||
var app = connect() | ||
app.use(hpkp.apply(null, arguments)) | ||
app.use(function (req, res) { | ||
res.end('Hello world!'); | ||
}); | ||
return request(app).get('/'); | ||
res.end('Hello world!') | ||
}) | ||
return request(app).get('/') | ||
} | ||
@@ -22,73 +20,82 @@ | ||
test({ maxAge: 10000, sha256s: ['abc123', 'xyz456'] }) | ||
.expect('Public-Key-Pins', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=10', done); | ||
}); | ||
.expect('Public-Key-Pins', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=10', done) | ||
}) | ||
it('allows lowercase "maxage"', function (done) { | ||
test({ maxage: 10000, sha256s: ['abc123', 'xyz456'] }) | ||
.expect('Public-Key-Pins', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=10', done); | ||
}); | ||
it('can include subdomains', function (done) { | ||
test({ maxage: 10000, sha256s: ['abc123', 'xyz456'], includeSubdomains: true }) | ||
.expect('Public-Key-Pins', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=10; includeSubdomains', done); | ||
}); | ||
test({ maxAge: 10000, sha256s: ['abc123', 'xyz456'], includeSubdomains: true }) | ||
.expect('Public-Key-Pins', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=10; includeSubdomains', done) | ||
}) | ||
it('changes the header when using a report URI', function (done) { | ||
test({ maxage: 10000, sha256s: ['abc123', 'xyz456'], reportUri: 'http://example.com' }) | ||
.expect('Public-Key-Pins-Report-Only', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=10; report-uri="http://example.com"', done); | ||
}); | ||
it('can set a report-uri', function (done) { | ||
test({ | ||
maxAge: 10000, | ||
sha256s: ['abc123', 'xyz456'], | ||
reportUri: 'http://example.com' | ||
}) | ||
.expect('Public-Key-Pins', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=10; report-uri="http://example.com"', done) | ||
}) | ||
it('can disable Report-Only with a report URI', function (done) { | ||
it('can enable Report-Only header', function (done) { | ||
test({ | ||
maxage: 10000, | ||
maxAge: 10000, | ||
sha256s: ['abc123', 'xyz456'], | ||
reportUri: 'http://example.com', | ||
reportOnly: false | ||
reportOnly: true | ||
}) | ||
.expect('Public-Key-Pins', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=10; report-uri="http://example.com"', done); | ||
}); | ||
.expect('Public-Key-Pins-Report-Only', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=10; report-uri="http://example.com"', done) | ||
}) | ||
it('changes the header when using a report URI and includes subdomains', function (done) { | ||
test({ maxage: 10000, sha256s: ['abc123', 'xyz456'], reportUri: 'http://example.com', includeSubdomains: true }) | ||
.expect('Public-Key-Pins-Report-Only', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=10; includeSubdomains; report-uri="http://example.com"', done); | ||
}); | ||
it('can use a report URI and include subdomains', function (done) { | ||
test({ | ||
maxAge: 10000, | ||
sha256s: ['abc123', 'xyz456'], | ||
reportUri: 'http://example.com', | ||
includeSubdomains: true | ||
}) | ||
.expect('Public-Key-Pins', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=10; includeSubdomains; report-uri="http://example.com"', done) | ||
}) | ||
it('rounds down to the nearest second', function (done) { | ||
test({ maxAge: 1234, sha256s: ['abc123', 'xyz456'] }) | ||
.expect('Public-Key-Pins', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=1', done); | ||
}); | ||
.expect('Public-Key-Pins', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=1', done) | ||
}) | ||
it('rounds up to the nearest second', function (done) { | ||
test({ maxAge: 1567, sha256s: ['abc123', 'xyz456'] }) | ||
.expect('Public-Key-Pins', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=2', done); | ||
}); | ||
.expect('Public-Key-Pins', 'pin-sha256="abc123"; pin-sha256="xyz456"; max-age=2', done) | ||
}) | ||
}) | ||
}); | ||
it('names its function and middleware', function () { | ||
assert.equal(hpkp.name, 'hpkp'); | ||
assert.equal(hpkp.name, hpkp({ maxAge: 10000, sha256s: ['abc123', 'xyz456'] }).name); | ||
}); | ||
assert.equal(hpkp.name, 'hpkp') | ||
assert.equal(hpkp.name, hpkp({ maxAge: 10000, sha256s: ['abc123', 'xyz456'] }).name) | ||
}) | ||
describe('with improper input', function () { | ||
function callWith() { | ||
var args = arguments; | ||
function callWith () { | ||
var args = arguments | ||
return function () { | ||
return hpkp.apply(this, args); | ||
}; | ||
return hpkp.apply(this, args) | ||
} | ||
} | ||
it('fails if called with no arguments', function () { | ||
assert.throws(callWith()); | ||
}); | ||
assert.throws(callWith()) | ||
}) | ||
it('fails if called with an empty object', function () { | ||
assert.throws(callWith({})); | ||
}); | ||
assert.throws(callWith({})) | ||
}) | ||
it('fails if called without a max-age', function () { | ||
assert.throws(callWith({ sha256s: ['abc123', 'xyz456'] })); | ||
}); | ||
assert.throws(callWith({ sha256s: ['abc123', 'xyz456'] })) | ||
}) | ||
it('fails if called with a lowercase "maxage" option', function () { | ||
assert.throws(callWith({ | ||
maxage: 10000, | ||
sha256s: ['abc123', 'xyz456'] | ||
})) | ||
}) | ||
it('fails if called with fewer than 2 SHAs', function () { | ||
@@ -102,28 +109,26 @@ [ | ||
].forEach(function (value) { | ||
assert.throws(callWith({ maxAge: 10000, sha256s: value })); | ||
}); | ||
}); | ||
assert.throws(callWith({ maxAge: 10000, sha256s: value })) | ||
}) | ||
}) | ||
it('fails if called with a zero maxAge', function () { | ||
assert.throws(callWith({ maxAge: 0, sha256s: ['abc123', 'xyz456'] })); | ||
}); | ||
assert.throws(callWith({ maxAge: 0, sha256s: ['abc123', 'xyz456'] })) | ||
}) | ||
it('fails if called with a negative maxAge', function () { | ||
assert.throws(callWith({ maxAge: -1000, sha256s: ['abc123', 'xyz456'] })); | ||
}); | ||
assert.throws(callWith({ maxAge: -1000, sha256s: ['abc123', 'xyz456'] })) | ||
}) | ||
it('fails if called with both types of maxAge argument', function () { | ||
assert.throws(callWith({ maxAge: 1000, maxage: 1000, sha256s: ['abc123', 'xyz456'] })); | ||
}); | ||
assert.throws(callWith({ maxAge: 1000, maxage: 1000, sha256s: ['abc123', 'xyz456'] })) | ||
}) | ||
it('fails if called with reportOnly: true but no reportUri', function () { | ||
assert.throws(callWith({ | ||
maxage: 10000, | ||
maxAge: 10000, | ||
sha256s: ['abc123', 'xyz456'], | ||
reportOnly: true | ||
})); | ||
}); | ||
}); | ||
}); | ||
})) | ||
}) | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
9068
158
1
27
4
1