Verified Commit 04be0936 authored by Aral Balkan's avatar Aral Balkan
Browse files

Implement _createTLSServerWithGloballyTrustedCertificate (untested)

parent 5c6fc0be
const http = require('http')
const https = require('https')
const fs = require('fs')
const express = require('express')
const morgan = require('morgan')
const path = require('path')
const os = require('os')
const childProcess = require('child_process')
const express = require('express')
const morgan = require('morgan')
const Greenlock = require('greenlock')
const redirectHTTPS = require('redirect-https')
// Requiring nodecert ensures that locally-trusted TLS certificates exist.
require('@ind.ie/nodecert')
......@@ -18,25 +22,9 @@ if (!fs.existsSync(nodecertDirectory)) {
class HttpsServer {
// Create and return a TLS server with a locally-trusted certificate.
createTLSServerWithLocallyTrustedCertificate (options = {}, requestListener = undefined) {
console.log('[https-server] Using local certificates.')
const defaultOptions = {
key: fs.readFileSync(path.join(nodecertDirectory, 'localhost-key.pem')),
cert: fs.readFileSync(path.join(nodecertDirectory, 'localhost.pem'))
}
Object.assign(options, defaultOptions)
return https.createServer(options, requestListener)
}
// Create and return a TLS server with a globally-trusted certificate.
createTLSServerWithGloballyTrustedCertificate () {
console.log('[https-server] Using global certificates. TODO')
// TODO
}
//
// Public.
//
// Returns an https server instance – the same as you’d get with
// require('https').createServer – configured with your nodecert certificates.
......@@ -46,10 +34,10 @@ class HttpsServer {
// ===== or use Greenlock on production to ensure that we have Let’s Encrypt
// certificates set up.
if (options.certificateType === 'global') {
return this.createTLSServerWithGloballyTrustedCertificate (options, requestListener)
return this._createTLSServerWithGloballyTrustedCertificate (options, requestListener)
} else {
// Default to using local certificates.
return this.createTLSServerWithLocallyTrustedCertificate(options, requestListener)
return this._createTLSServerWithLocallyTrustedCertificate(options, requestListener)
}
}
......@@ -64,7 +52,7 @@ class HttpsServer {
callback = null
}
this.ensureWeCanBindToPort(port, pathToServe)
this._ensureWeCanBindToPort(port, pathToServe)
// If a callback isn’t provided, fallback to a default one that gives a status update.
if (callback === null) {
......@@ -95,6 +83,70 @@ class HttpsServer {
}
//
// Private.
//
_createTLSServerWithLocallyTrustedCertificate (options, requestListener = undefined) {
console.log('[https-server] Using locally-trusted certificates.')
const defaultOptions = {
key: fs.readFileSync(path.join(nodecertDirectory, 'localhost-key.pem')),
cert: fs.readFileSync(path.join(nodecertDirectory, 'localhost.pem'))
}
Object.assign(options, defaultOptions)
return https.createServer(options, requestListener)
}
_createTLSServerWithGloballyTrustedCertificate (options, requestListener = undefined) {
console.log('[https-server] Using globally-trusted certificates.')
if (options.email === undefined) {
throw new Error('Globally-trusted certificates require a valid email value in the options object. This is a Let’s Encrypt requirement.')
}
const email = options.email
delete options.email // Let’s be nice and not pollute that object.
// Certificates are automatically obtained for the hostname and the www. subdomain of the hostname
// for the machine that we are running on.
const hostname = os.hostname()
const greenlock = Greenlock.create({
// Note: while testing, you might want to use the staging server at:
// ===== https://acme-staging-v02.api.letsencrypt.org/directory
server: 'https://acme-v02.api.letsencrypt.org/directory',
version: 'draft-11',
configDir: `~/.nodecert/${hostname}/`,
approvedDomains: [hostname, `www.${hostname}`],
agreeTos: true,
telemetry: false,
communityMember: false,
app,
email,
})
// Create an HTTP server to handle redirects for the Let’s Encrypt ACME HTTP-01 challenge method that we use.
const httpsRedirectionMiddleware = redirectHTTPS()
const httpServer = http.createServer(greenlock.middleware(httpsRedirectionMiddleware))
httpServer.listen(80, () => {
console.log('[https-server] (Globally-trusted TLS) HTTP → HTTPS redirection active.')
})
// Debug
console.log('greenlock.tlsOptions', greenlock.tlsOptions)
// Add the TLS options from Greenlock to any existing options that might have been passed in.
Object.assign(options, greenlock.tlsOptions)
// Create and return the HTTPS server.
return https.createServer(options, requestListener)
}
// If we’re on Linux and the requested port is < 1024 ensure that we can bind to it.
// (As of macOS Mojave, privileged ports are only an issue on Linux. Good riddance too,
// as these so-called privileged ports are a relic from the days of mainframes and they
......@@ -105,7 +157,7 @@ class HttpsServer {
// ===== current app is in index.js and that it can be forked. This might be an issue if a
// process manager is already being used, etc. Worth keeping an eye on and possibly
// making this method an optional part of server startup.
ensureWeCanBindToPort (port, pathToServe) {
_ensureWeCanBindToPort (port, pathToServe) {
if (port < 1024 && os.platform() === 'linux') {
const options = {env: process.env}
try {
......
{
"name": "@ind.ie/https-server",
"version": "2.0.0",
"version": "3.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@coolaj86/urequest": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/@coolaj86/urequest/-/urequest-1.3.7.tgz",
"integrity": "sha512-PPrVYra9aWvZjSCKl/x1pJ9ZpXda1652oJrPBYy5rQumJJMkmTBN3ux+sK2xAUwVvv2wnewDlaQaHLxLwSHnIA=="
},
"@ind.ie/nodecert": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@ind.ie/nodecert/-/nodecert-1.0.6.tgz",
......@@ -21,6 +26,34 @@
"negotiator": "0.6.1"
}
},
"acme": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/acme/-/acme-1.2.0.tgz",
"integrity": "sha512-lG9Wq0Ol2OLpVrusq5OQ+KCT06rXaGjbHcDhKtNO6Hr3J3swISaCYi0slwLpEA9DGV+QhDkAnZ6qsXAo86SM5Q==",
"requires": {
"acme-v2": "^1.3.1"
}
},
"acme-v2": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/acme-v2/-/acme-v2-1.5.2.tgz",
"integrity": "sha512-Ux0cFCxHeaGGeGyPGMLHBLIGF05OYaxuh4TvaVzwkVVRib/gPpioa50CGj2pnQimH/MRkg0VtWCEdfE45MV/0g==",
"requires": {
"@coolaj86/urequest": "^1.3.6",
"rsa-compat": "^1.9.2"
},
"dependencies": {
"rsa-compat": {
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/rsa-compat/-/rsa-compat-1.9.2.tgz",
"integrity": "sha512-XY4I/74W+QENMd99zVsyHQcxYxWTXd0EihVXsI4oeb1bz7DYxEKasQrjyzYPnR1tZT7fTPu5HP/vTKfs9lzdGA==",
"requires": {
"node-forge": "^0.7.6",
"ursa-optional": "^0.9.10"
}
}
}
},
"ansi-escape-sequences": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-4.0.1.tgz",
......@@ -56,6 +89,20 @@
"safe-buffer": "5.1.2"
}
},
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"optional": true,
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"bluebird": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz",
"integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw=="
},
"body-parser": {
"version": "1.18.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz",
......@@ -88,6 +135,11 @@
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
},
"cert-info": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/cert-info/-/cert-info-1.5.1.tgz",
"integrity": "sha512-eoQC/yAgW3gKTKxjzyClvi+UzuY97YCjcl+lSqbsGIy7HeGaWxCPOQFivhUYm27hgsBMhsJJFya3kGvK6PMIcQ=="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
......@@ -235,6 +287,12 @@
"vary": "~1.1.2"
}
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"optional": true
},
"finalhandler": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
......@@ -294,6 +352,20 @@
"path-is-absolute": "^1.0.0"
}
},
"greenlock": {
"version": "2.6.8",
"resolved": "https://registry.npmjs.org/greenlock/-/greenlock-2.6.8.tgz",
"integrity": "sha512-TYm9XrbtGkcFIwfonCzuAGCJXteyZRQxoaHYlDG2OPAihtVAlsM+KAVKsLlzLJ+oVEWj5XPLBnWU9NtwLrRX+Q==",
"requires": {
"acme": "^1.2.0",
"acme-v2": "^1.5.0",
"cert-info": "^1.5.1",
"le-challenge-fs": "^2.0.2",
"le-sni-auto": "^2.1.3",
"le-store-certbot": "^2.1.7",
"rsa-compat": "^2.0.3"
}
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
......@@ -378,6 +450,32 @@
"has-symbols": "^1.0.0"
}
},
"le-challenge-fs": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/le-challenge-fs/-/le-challenge-fs-2.0.8.tgz",
"integrity": "sha1-ttRYo38JfoffPYtf9nATc3q51aI=",
"requires": {
"mkdirp": "^0.5.1"
}
},
"le-sni-auto": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/le-sni-auto/-/le-sni-auto-2.1.6.tgz",
"integrity": "sha512-LcfkF2yQ1nrep+ZfyG+SfR3pHphKFD3zMZ9FKervGfTfvgScCv/XGbX+vxsGZEKZjvzxKbFZ/5LdSCXuLXUU6A==",
"requires": {
"bluebird": "^3.5.1"
}
},
"le-store-certbot": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/le-store-certbot/-/le-store-certbot-2.2.1.tgz",
"integrity": "sha512-BhljZjTULhbNBAT6RBiv4TeZegFraMxURYEvh3WRUI048zmXf4ZfC8gwbdu5fnD2tTCsS9fbsCOAQyrFBl4jlA==",
"requires": {
"mkdirp": "^0.5.1",
"pyconf": "^1.1.5",
"safe-replace": "^1.0.3"
}
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
......@@ -425,6 +523,21 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
},
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
}
}
},
"morgan": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz",
......@@ -442,11 +555,23 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"nan": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz",
"integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==",
"optional": true
},
"negotiator": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
},
"node-forge": {
"version": "0.7.6",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz",
"integrity": "sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw==",
"optional": true
},
"object-inspect": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz",
......@@ -512,6 +637,14 @@
"ipaddr.js": "1.8.0"
}
},
"pyconf": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/pyconf/-/pyconf-1.1.6.tgz",
"integrity": "sha512-4ujjwqch6nViWduSLc3/QFrDdJJAvAE7NRBarSGLANwh0tNW0MbXeJE8ZziJZvzRnUEN5scYwsS+ItYU1uj6dQ==",
"requires": {
"safe-replace": "^1.0.2"
}
},
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
......@@ -533,6 +666,14 @@
"unpipe": "1.0.0"
}
},
"redirect-https": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/redirect-https/-/redirect-https-1.3.0.tgz",
"integrity": "sha512-9GzwI/+Cqw3jlSg0CW6TgBQbhiVhkHSDvW8wjgRQ9IK34wtxS71YJiQeazSCSEqbvowHCJuQZgmQFl1xUHKEgg==",
"requires": {
"escape-html": "^1.0.3"
}
},
"resolve": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
......@@ -551,11 +692,21 @@
"through": "~2.3.4"
}
},
"rsa-compat": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/rsa-compat/-/rsa-compat-2.0.3.tgz",
"integrity": "sha512-oMEiSfk8KTKleNO7OEahZtrZTcjV+fzBm8jpt2bXBgyhbgO3bJdwawm4BkJe+2LfdK8kaKqMIO8pHZ/UmybQ7w=="
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safe-replace": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz",
"integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
......@@ -664,6 +815,16 @@
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"ursa-optional": {
"version": "0.9.10",
"resolved": "https://registry.npmjs.org/ursa-optional/-/ursa-optional-0.9.10.tgz",
"integrity": "sha512-RvEbhnxlggX4MXon7KQulTFiJQtLJZpSb9ZSa7ZTkOW0AzqiVTaLjI4vxaSzJBDH9dwZ3ltZadFiBaZslp6haA==",
"optional": true,
"requires": {
"bindings": "^1.3.0",
"nan": "^2.11.1"
}
},
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
......
......@@ -22,8 +22,10 @@
"@ind.ie/nodecert": "^1.0.6",
"ansi-escape-sequences": "^4.0.1",
"express": "^4.16.4",
"greenlock": "^2.6.8",
"minimist": "^1.2.0",
"morgan": "^1.9.1"
"morgan": "^1.9.1",
"redirect-https": "^1.3.0"
},
"devDependencies": {
"tape": "^4.10.1"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment