Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

create-servers

Package Overview
Dependencies
Maintainers
6
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

create-servers - npm Package Compare versions

Comparing version 2.5.0 to 2.6.0

test/fixtures/example-ca-cert.pem

92

index.js

@@ -13,3 +13,5 @@ 'use strict';

https = require('https'),
tls = require('tls'),
path = require('path'),
constants = require('constants'),
connected = require('connected'),

@@ -40,2 +42,4 @@ errs = require('errs'),

var secureOptions = constants.SSL_OP_NO_SSLv3;
/**

@@ -125,3 +129,3 @@ * function createServers (dispatch, options, callback)

//
function createHttps(next) {
function createHttps() {
if (typeof options.https === 'undefined') {

@@ -134,19 +138,6 @@ log('https | no options.https; no server');

port = !isNaN(ssl.port) ? +ssl.port : 443, // accepts string or number
ciphers = ssl.ciphers || CIPHERS,
timeout = options.timeout || ssl.timeout,
ca = ssl.ca,
server,
args;
//
// Remark: If an array is passed in lets join it like we do the defaults
//
if (Array.isArray(ciphers)) {
ciphers = ciphers.join(':');
}
if (ca && !Array.isArray(ca)) {
ca = [ca];
}
var finalHttpsOptions = assign({}, ssl, {

@@ -158,3 +149,3 @@ //

cert: normalizeCertContent(ssl.root, ssl.cert, ssl.key),
ca: ca && ca.map(normalizePEMContent.bind(null, ssl.root)),
ca: normalizeCA(ssl.root, ssl.ca),
//

@@ -164,3 +155,3 @@ // Properly expose ciphers for an A+ SSL rating:

//
ciphers: ciphers,
ciphers: normalizeCiphers(ssl.ciphers),
honorCipherOrder: !!ssl.honorCipherOrder,

@@ -172,5 +163,9 @@ //

secureProtocol: 'SSLv23_method',
secureOptions: require('constants').SSL_OP_NO_SSLv3
secureOptions: secureOptions
});
if (ssl.sni && !finalHttpsOptions.SNICallback) {
finalHttpsOptions.SNICallback = getSNIHandler(ssl)
}
log('https | listening on %d', port);

@@ -229,2 +224,9 @@ server = https.createServer(finalHttpsOptions, ssl.handler || handler);

function normalizeCA(root, ca) {
if (ca && !Array.isArray(ca)) {
ca = [ca];
}
return ca && ca.map(normalizePEMContent.bind(null, root));
}
/**

@@ -250,1 +252,57 @@ * function normalizePEMContent(root, file)

}
function normalizeCiphers(ciphers) {
ciphers = ciphers || CIPHERS;
//
// Remark: If an array is passed in lets join it like we do the defaults
//
if (Array.isArray(ciphers)) {
ciphers = ciphers.join(':');
}
return ciphers;
}
function getSNIHandler(sslOpts) {
var sniHosts = Object.keys(sslOpts.sni);
// Pre-compile regexps for the hostname
var hostRegexps = sniHosts.map(function (host) {
return new RegExp(
'^' +
host
.replace('.', '\\.') // Match dots, not wildcards
.replace('*\\.', '(?:.*\\.)?') + // Handle optional wildcard sub-domains
'$',
'i'
);
});
// Prepare secure context params ahead-of-time
var hostTlsOpts = sniHosts.map(function (host) {
var hostOpts = sslOpts.sni[host];
var root = hostOpts.root || sslOpts.root;
return assign({}, sslOpts, hostOpts, {
key: normalizePEMContent(root, hostOpts.key),
cert: normalizeCertContent(root, hostOpts.cert),
ca: normalizeCA(root, hostOpts.ca || sslOpts.ca),
ciphers: normalizeCiphers(hostOpts.ciphers || sslOpts.ciphers),
honorCipherOrder: !!(hostOpts.honorCipherOrder || sslOpts.honorCipherOrder),
secureProtocol: 'SSLv23_method',
secureOptions: secureOptions
});
});
return function (hostname, cb) {
var matchingHostIdx = sniHosts.findIndex(function(candidate, i) {
return hostRegexps[i].test(hostname);
});
if (matchingHostIdx === -1) {
return void cb(new Error('Unrecognized hostname: ' + hostname));
}
cb(null, tls.createSecureContext(hostTlsOpts[matchingHostIdx]));
};
}

3

package.json
{
"name": "create-servers",
"version": "2.5.0",
"version": "2.6.0",
"description": "Create an http AND/OR an https server and call the same request handler.",

@@ -30,2 +30,3 @@ "main": "index.js",

"devDependencies": {
"evil-dns": "^0.2.0",
"sinon": "^5.0.7",

@@ -32,0 +33,0 @@ "tape": "~4.9.0"

@@ -30,2 +30,3 @@ # create-servers

| `https.ca` | Cert or array of certs specifying trusted authorities for peer certificates. Only required if your server accepts client certificate connections signed by authorities that are not trusted by default. See [Certificate normalization](#certificate-normalization) for more details. |
| `https.sni` | See [SNI Support](#sni-support). |
| `https.handler` | Handler for HTTPS requests. If you want to share a handler with all servers, use a top-level `handler` config property instead. |

@@ -42,3 +43,3 @@ | `https.*` | Any other properties supported by [https.createServer](https://nodejs.org/dist/latest-v8.x/docs/api/https.html#https_https_createserver_options_requestlistener) can be added to the https object, except `secureProtocol` and `secureOptions` which are set to recommended values. |

### Certificate normalization
### Certificate Normalization

@@ -104,2 +105,57 @@ `create-servers` provides some conveniences for `https.ca`, `https.key`, and

### SNI Support
[Server Name Indication](https://en.wikipedia.org/wiki/Server_Name_Indication),
or SNI, lets HTTPS clients announce which hostname they wish to connect to
before the server sends its certificate, enabling the use of the same server for
multiple hosts. Although `SNICallback` can be used to support this, you lose the
convenient certificate normalization provided by `create-servers`. The `sni`
config option provides an easier way.
The `sni` option is an object with each key being a supported hostname and each
value being a subset of the HTTPS settings listed above. HTTPS settings defined
at the top level are used as defaults for the hostname-specific settings.
```js
const createServers = require('create-servers');
createServers(
{
https: {
port: 443,
sni: {
'example1.com': {
key: '/certs/private/example1.com.key',
cert: '/certs/public/example1.com.crt'
},
'example2.com': {
key: '/certs/private/example2.com.key',
cert: '/certs/public/example2.com.crt'
}
}
},
handler: function (req, res) {
res.end('Hello');
}
},
function (errs) {
if (errs) {
return console.log(errs.https);
}
console.log('Listening on 443');
}
);
```
Use `*` in the hostname for wildcard certs. Example: `*.example.com`. The
following settings are supported in the host-specific configuration:
* key
* cert
* ca
* ciphers
* honorCipherOrder
* Anything else supported by [`tls.createSecureContext`](https://nodejs.org/dist/latest-v8.x/docs/api/tls.html#tls_tls_createsecurecontext_options)
## NOTE on Security

@@ -106,0 +162,0 @@ Inspired by [`iojs`][iojs] and a well written [article][article], we have defaulted

@@ -10,8 +10,15 @@ /*

fs = require('fs'),
url = require('url'),
http = require('http'),
https = require('https'),
{ promisify } = require('util'),
test = require('tape'),
sinon = require('sinon'),
evilDNS = require('evil-dns'),
createServers = require('../');
const createServersAsync = promisify(createServers);
const ca = fs.readFileSync(path.join(__dirname, './fixtures/example-ca-cert.pem'));
//

@@ -24,2 +31,25 @@ // Immediately end a response.

//
// Request and download response from a URL
//
async function download(httpsURL) {
return new Promise((resolve, reject) => {
const req = https.get({
...url.parse(httpsURL),
ca
}, res => {
const chunks = [];
res
.on('data', chunk => chunks.push(chunk))
.once('end', () => {
resolve(chunks.map(chunk => chunk.toString('utf8')).join(''));
})
.once('aborted', reject)
.once('close', reject)
.once('error', reject)
});
req.once('error', reject);
});
}
test('only http', function (t) {

@@ -326,1 +356,56 @@ t.plan(3);

});
test('supports SNI', async t => {
t.plan(1);
const hostNames = [
'example.com',
'example.net',
'foo.example.org',
];
let httpsServer;
try {
const servers = await createServersAsync({
https: {
port: 3456,
root: path.join(__dirname, 'fixtures'),
sni: {
'example.com': {
key: 'example-com-key.pem',
cert: 'example-com-cert.pem'
},
'example.net': {
key: 'example-net-key.pem',
cert: 'example-net-cert.pem'
},
'*.example.org': {
key: 'example-org-key.pem',
cert: 'example-org-cert.pem'
}
}
},
handler: (req, res) => {
res.write('Hello');
res.end();
}
});
httpsServer = servers.https;
hostNames.forEach(host => evilDNS.add(host, '0.0.0.0'));
const responses = await Promise.all(hostNames
.map(hostname => download(`https://${hostname}:3456/`)));
t.equals(
responses.every(str => str === 'Hello'),
true,
'responses are as expected');
} catch (err) {
return void t.error(err);
} finally {
httpsServer && httpsServer.close();
evilDNS.clear();
}
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc