diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..d306351 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "bracketSpacing": true, + "printWidth": 120, + "tabWidth": 4, + "trailingComma": "none", + "useTabs": false +} diff --git a/README.md b/README.md index 9e36395..5554b85 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,41 @@ +# Replaced: Use Greenlock Express v3 + +See https://git.rootprojects.org/root/greenlock-express.js + +```js +"use strict"; + +var pkg = require("./package.json"); +require("greenlock-express") + .init(function getConfig() { + // Greenlock Config + + return { + package: { name: pkg.name, version: pkg.version }, + maintainerEmail: pkg.author, + + // put cluster on full throttle! + cloudnative: true + webscale: true + cluster: true + }; + }) + .serve(httpsWorker); + +function httpsWorker(glx) { + // Serves on 80 and 443 + // Get's SSL certificates magically! + + glx.serveApp(function(req, res) { + res.end("Hello, Encrypted World!"); + }); +} +``` + +# OLD STUFF BELOW + +# (Preserved for historical reference) + | A [Root](https://therootcompany.com) Project | [greenlock (lib)](https://git.coolaj86.com/coolaj86/greenlock.js) | [greenlock-cli](https://git.coolaj86.com/coolaj86/greenlock-cli.js) @@ -7,27 +45,24 @@ | [greenlock-hapi](https://git.coolaj86.com/coolaj86/greenlock-hapi.js) | +# greenlock-cluster -greenlock-cluster -=================== (previously letsencrypt-cluster) Use automatic letsencrypt with node on multiple cores or even multiple machines. -* Take advantage of multi-core computing -* Process certificates in master -* Serve https from multiple workers -* Can work with any clustering strategy [#1](https://github.com/Daplie/letsencrypt-cluster/issues/1) +- Take advantage of multi-core computing +- Process certificates in master +- Serve https from multiple workers +- Can work with any clustering strategy [#1](https://github.com/Daplie/letsencrypt-cluster/issues/1) -Install -======= +# Install ```bash npm install --save greenlock-cluster@2.x ``` -Usage -===== +# Usage In a cluster environment you have some main file that boots your app and then conditionally loads certain code based on whether that fork @@ -37,35 +72,34 @@ In such a file you might want to define some of the options that need to be shared between both the master and the worker, like this: `boot.js`: -```javascript -'use strict'; -var cluster = require('cluster'); -var path = require('path'); -var os = require('os'); +```javascript +"use strict"; + +var cluster = require("cluster"); +var path = require("path"); +var os = require("os"); var main; var sharedOptions = { - webrootPath: path.join(os.tmpdir(), 'acme-challenge') // /tmp/acme-challenge - // used by le-challenge-fs, the default plugin + webrootPath: path.join(os.tmpdir(), "acme-challenge"), // /tmp/acme-challenge + // used by le-challenge-fs, the default plugin -, renewWithin: 14 * 24 * 60 * 60 * 1000 // 10 days before expiration + renewWithin: 14 * 24 * 60 * 60 * 1000, // 10 days before expiration -, debug: true + debug: true }; if (cluster.isMaster) { - main = require('./master'); -} -else { - main = require('./worker'); + main = require("./master"); +} else { + main = require("./worker"); } main.init(sharedOptions); ``` -Master ------- +## Master We think it makes the most sense to load greenlock in master. This can prevent race conditions (see [node-letsencrypt#45](https://github.com/Daplie/node-letsencrypt/issues/45)) @@ -78,6 +112,7 @@ The master takes **the same arguments** as `node-greenlock` (`challenge`, `store plus a few extra (`approveDomains`... okay, just one extra): `master.js`: + ```javascript 'use strict'; @@ -120,75 +155,75 @@ All options are passed directly to `node-greenlock` (in other works, `leMaster` is a `greenlock` instance), but a few are only actually used by `greenlock-cluster`. -* `leOptions.approveDomains(options, certs, cb)` is special for `greenlock-cluster`, but will probably be included in `node-greenlock` in the future (no API change). +- `leOptions.approveDomains(options, certs, cb)` is special for `greenlock-cluster`, but will probably be included in `node-greenlock` in the future (no API change). -* `leMaster.addWorker(worker)` is added by `greenlock-cluster` and **must be called** for each new worker. +- `leMaster.addWorker(worker)` is added by `greenlock-cluster` and **must be called** for each new worker. -Worker ------- +## Worker -The worker takes *similar* arguments to `node-greenlock`, +The worker takes _similar_ arguments to `node-greenlock`, but only ones that are useful for determining certificate renewal and for `le.challenge.get`. -If you want to a non-default `le.challenge` +If you want to a non-default `le.challenge` `worker.js`: + ```javascript -'use strict'; +"use strict"; -module.exports.init = function (sharedOpts) { - var leWorker = require('greenlock-cluster/worker').create({ - debug: sharedOpts.debug +module.exports.init = function(sharedOpts) { + var leWorker = require("greenlock-cluster/worker").create({ + debug: sharedOpts.debug, - , renewWithin: sharedOpts.renewWithin + renewWithin: sharedOpts.renewWithin, - , webrootPath: sharedOpts.webrootPath + webrootPath: sharedOpts.webrootPath, - // , challenge: require('le-challenge-fs').create({ webrootPath: '...', ... }) + // , challenge: require('le-challenge-fs').create({ webrootPath: '...', ... }) - , approveDomains: function (workerOptions, certs, cb) { - // opts = { domains, email, agreeTos, tosUrl } - // certs = { subject, altnames, expiresAt, issuedAt } + approveDomains: function(workerOptions, certs, cb) { + // opts = { domains, email, agreeTos, tosUrl } + // certs = { subject, altnames, expiresAt, issuedAt } - var results = { - domain: workerOptions.domains[0] - , options: { - domains: workerOptions.domains + var results = { + domain: workerOptions.domains[0], + options: { + domains: workerOptions.domains + }, + certs: certs + }; + + if (certs) { + // modify opts.domains to match the original request + // email is not necessary, because the account already exists + // this will only fail if the account has become corrupt + results.options.domains = certs.altnames; + cb(null, results); + return; + } + + // This is where one would check one's application-specific database: + // 1. Lookup the domain to see which email it belongs to + // 2. Assign a default email if it isn't in the system + // 3. If the email has no le account, `agreeToTerms` will fire unless `agreeTos` is preset + + results.options.email = "john.doe@example.com"; + results.options.agreeTos = true; // causes agreeToTerms to be skipped + cb(null, results); } - , certs: certs - }; + }); - if (certs) { - // modify opts.domains to match the original request - // email is not necessary, because the account already exists - // this will only fail if the account has become corrupt - results.options.domains = certs.altnames; - cb(null, results); - return; - } - - // This is where one would check one's application-specific database: - // 1. Lookup the domain to see which email it belongs to - // 2. Assign a default email if it isn't in the system - // 3. If the email has no le account, `agreeToTerms` will fire unless `agreeTos` is preset - - results.options.email = 'john.doe@example.com' - results.options.agreeTos = true // causes agreeToTerms to be skipped - cb(null, results); + function app(req, res) { + res.end("Hello, World!"); } - }); - function app(req, res) { - res.end("Hello, World!"); - } + var redirectHttps = require("redirect-https")(); + var plainServer = require("http").createServer(leWorker.middleware(redirectHttps)); + plainServer.listen(80); - var redirectHttps = require('redirect-https')(); - var plainServer = require('http').createServer(leWorker.middleware(redirectHttps)); - plainServer.listen(80); - - var server = require('https').createServer(leWorker.httpsOptions, leWorker.middleware(app)); - server.listen(443); + var server = require("https").createServer(leWorker.httpsOptions, leWorker.middleware(app)); + server.listen(443); }; ``` @@ -197,16 +232,15 @@ module.exports.init = function (sharedOpts) { `node-greenlock` is **not used** directly by the worker, but certain options are shared because certain logic is duplicated. -* `leOptions.renewWithin` is shared so that the worker knows how earlier to request a new cert -* `leOptions.renewBy` is passed to `le-sni-auto` so that it staggers renewals between `renewWithin` (latest) and `renewBy` (earlier) -* `leWorker.middleware(nextApp)` uses `greenlock/middleware` for GET-ing `http-01`, hence `sharedOptions.webrootPath` -* `leWorker.httpsOptions` has a default localhost certificate and the `SNICallback`. +- `leOptions.renewWithin` is shared so that the worker knows how earlier to request a new cert +- `leOptions.renewBy` is passed to `le-sni-auto` so that it staggers renewals between `renewWithin` (latest) and `renewBy` (earlier) +- `leWorker.middleware(nextApp)` uses `greenlock/middleware` for GET-ing `http-01`, hence `sharedOptions.webrootPath` +- `leWorker.httpsOptions` has a default localhost certificate and the `SNICallback`. There are a few options that aren't shown in these examples, so if you need to change something that isn't shown here, look at the code (it's not that much) or open an issue. -Message Passing ---------------- +## Message Passing The master and workers will communicate through `process.on('message', fn)`, `process.send({})`, `worker.on('message', fn)`and `worker.send({})`. diff --git a/examples/README.md b/examples/README.md index d7fb299..19143ce 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,5 +1,4 @@ -greenlock cluster examples -------------------- +## greenlock cluster examples First you need to change the email address in `examples/worker.js`. diff --git a/examples/master.js b/examples/master.js index de3dcd8..83ddfdf 100644 --- a/examples/master.js +++ b/examples/master.js @@ -1,35 +1,29 @@ -'use strict'; +"use strict"; -var cluster = require('cluster'); +var cluster = require("cluster"); -module.exports.init = function (sharedOpts) { - var numCores = 2; // // Math.max(2, require('os').cpus().length) - var i; - var master = require('../master').create({ - debug: true +module.exports.init = function(sharedOpts) { + var numCores = 2; // // Math.max(2, require('os').cpus().length) + var i; + var master = require("../master").create({ + debug: true, + server: "staging", + webrootPath: sharedOpts.webrootPath, + approveDomains: function(masterOptions, certs, cb) { + // Depending on your setup it may be more efficient + // for you to implement the approveDomains function + // in your master or in your workers. + // + // Since we implement it in the worker (below) in this example + // we'll give it an immediate approval here in the master + var results = { domain: masterOptions.domain, options: masterOptions, certs: certs }; + cb(null, results); + } + }); - , server: 'staging' - , webrootPath: sharedOpts.webrootPath - - - - , approveDomains: function (masterOptions, certs, cb) { - // Depending on your setup it may be more efficient - // for you to implement the approveDomains function - // in your master or in your workers. - // - // Since we implement it in the worker (below) in this example - // we'll give it an immediate approval here in the master - var results = { domain: masterOptions.domain, options: masterOptions, certs: certs }; - cb(null, results); + for (i = 0; i < numCores; i += 1) { + master.addWorker(cluster.fork()); } - }); - - - - for (i = 0; i < numCores; i += 1) { - master.addWorker(cluster.fork()); - } }; diff --git a/examples/serve.js b/examples/serve.js index 0ce210f..9b8caca 100644 --- a/examples/serve.js +++ b/examples/serve.js @@ -1,33 +1,27 @@ -'use strict'; +"use strict"; -var cluster = require('cluster'); +var cluster = require("cluster"); var main; - - // You'll often see examples where people use cluster // master and worker all in the same file, which is fine, // but in order to conserve memory and especially to be // less confusing, I'm splitting the code into two files if (cluster.isMaster) { - main = require('./master'); + main = require("./master"); +} else { + main = require("./worker"); } -else { - main = require('./worker'); -} - - // this is nothing greenlock-cluster specific // I'm just arbitrarily choosing to share some configuration // that I know I'm going to use in both places main.init({ + // Depending on the strategy, the whole le-challenge-<> + // could be shared between worker and server, but since I'm just + // using using le-challenge-fs (as you'll see), I'm only sharing the webrootPath + webrootPath: require("os").tmpdir() + require("path").sep + "acme-challenge", - // Depending on the strategy, the whole le-challenge-<> - // could be shared between worker and server, but since I'm just - // using using le-challenge-fs (as you'll see), I'm only sharing the webrootPath - webrootPath: require('os').tmpdir() + require('path').sep + 'acme-challenge' - - // this is used both by node-greenlock (master) and le-sni-auto (worker) -, renewWithin: 15 * 24 * 60 * 60 * 1000 + // this is used both by node-greenlock (master) and le-sni-auto (worker) + renewWithin: 15 * 24 * 60 * 60 * 1000 }); diff --git a/examples/worker.js b/examples/worker.js index e84726c..42f72fa 100644 --- a/examples/worker.js +++ b/examples/worker.js @@ -1,24 +1,18 @@ -'use strict'; +"use strict"; -module.exports.init = function (sharedOpts) { - var worker = require('../worker').create({ - debug: true +module.exports.init = function(sharedOpts) { + var worker = require("../worker").create({ + debug: true, + // We want both to renew well before the expiration date + // and also to stagger the renewals, just a touch + // here we specify to renew between 10 and 15 days + renewWithin: sharedOpts.renewWithin, + renewBy: 10 * 24 * 60 * 60 * 1000, // optional + webrootPath: sharedOpts.webrootPath, - // We want both to renew well before the expiration date - // and also to stagger the renewals, just a touch - // here we specify to renew between 10 and 15 days - , renewWithin: sharedOpts.renewWithin - , renewBy: 10 * 24 * 60 * 60 * 1000 // optional - - - - , webrootPath: sharedOpts.webrootPath - - - - /* + /* challenge: { get: function (ignored, domain, token, cb) { cb(null, keyAuthorization); @@ -33,55 +27,48 @@ module.exports.init = function (sharedOpts) { } */ + // There are two approval processes: + // 1. emails are tied to private keys (accounts) which must agree to the tos url + // 2. domains are tied to accounts (and should be verifiable via loopback) + approveDomains: function(workerOptions, certs, cb) { + // opts = { domains, email, agreeTos, tosUrl } + // certs = { subject, altnames, expiresAt, issuedAt } + var results = { + domain: workerOptions.domains[0], + options: { + domains: (certs && certs.altnames) || workerOptions.domains, + email: "john.doe@example.com", + agreeTos: true + }, + certs: certs + }; - // There are two approval processes: - // 1. emails are tied to private keys (accounts) which must agree to the tos url - // 2. domains are tied to accounts (and should be verifiable via loopback) - , approveDomains: function (workerOptions, certs, cb) { - // opts = { domains, email, agreeTos, tosUrl } - // certs = { subject, altnames, expiresAt, issuedAt } - var results = { - domain: workerOptions.domains[0] - , options: { - domains: certs && certs.altnames || workerOptions.domains - , email: 'john.doe@example.com' - , agreeTos: true + // We might want to do a check to make sure that all of the domains + // specified in altnames are still approved to be renewed and have + // the correct dns entries, but generally speaking it's probably okay + // for renewals to be automatic + if (certs) { + // modify opts.domains to overwrite certs.altnames in renewal + cb(null, results); + return; + } + + // This is where we would check our database to make sure that + // this user (specified by email address) has agreed to the terms + // and do some check that they have access to this domain + cb(null, results); } - , certs: certs - }; + }); - - - // We might want to do a check to make sure that all of the domains - // specified in altnames are still approved to be renewed and have - // the correct dns entries, but generally speaking it's probably okay - // for renewals to be automatic - if (certs) { - // modify opts.domains to overwrite certs.altnames in renewal - cb(null, results); - return; - } - - - - - // This is where we would check our database to make sure that - // this user (specified by email address) has agreed to the terms - // and do some check that they have access to this domain - cb(null, results); + function app(req, res) { + res.end("Hello, World!"); } - }); - function app(req, res) { - res.end("Hello, World!"); - } - - - // worker.handleAcmeOrRedirectToHttps() - // worker.handleAcmeOrUse(app) - var redirectHttps = require('redirect-https')(); - var plainServer = require('http').createServer(worker.middleware(redirectHttps)); - var server = require('https').createServer(worker.httpsOptions, worker.middleware(app)); - plainServer.listen(80); - server.listen(443); + // worker.handleAcmeOrRedirectToHttps() + // worker.handleAcmeOrUse(app) + var redirectHttps = require("redirect-https")(); + var plainServer = require("http").createServer(worker.middleware(redirectHttps)); + var server = require("https").createServer(worker.httpsOptions, worker.middleware(app)); + plainServer.listen(80); + server.listen(443); }; diff --git a/index.js b/index.js index f79c65f..8ced508 100644 --- a/index.js +++ b/index.js @@ -1,12 +1,3 @@ -'use strict'; +"use strict"; -console.error(""); -console.error("One does not simply require('greenlock-cluster');"); -console.error(""); -console.error("Usage:"); -console.error("\trequire('greenlock-cluster/master').create({ ... });"); -console.error("\trequire('greenlock-cluster/worker').create({ ... });"); -console.error(""); -console.error(""); - -process.exit(1); +module.exports = require("@root/greenlock-express"); diff --git a/master.js b/master.js index 0987035..515a364 100644 --- a/master.js +++ b/master.js @@ -1,58 +1,60 @@ -'use strict'; +"use strict"; // opts.addWorker(worker) // opts.approveDomains(options, certs, cb) -module.exports.create = function (opts) { - opts = opts || { }; - opts._workers = []; - opts.webrootPath = opts.webrootPath || require('os').tmpdir() + require('path').sep + 'acme-challenge'; - if (!opts.greenlock) { opts.greenlock = require('greenlock').create(opts); } - if ('function' !== typeof opts.approveDomains) { - throw new Error("You must provide opts.approveDomains(domain, certs, callback) to approve certificates"); - } - - function log(debug) { - if (!debug) { - return; +module.exports.create = function(opts) { + opts = opts || {}; + opts._workers = []; + opts.webrootPath = opts.webrootPath || require("os").tmpdir() + require("path").sep + "acme-challenge"; + if (!opts.greenlock) { + opts.greenlock = require("greenlock").create(opts); + } + if ("function" !== typeof opts.approveDomains) { + throw new Error("You must provide opts.approveDomains(domain, certs, callback) to approve certificates"); } - var args = Array.prototype.slice.call(arguments); - args.shift(); - args.unshift("[le/lib/core.js]"); - console.log.apply(console, args); - } - - opts.addWorker = function (worker) { - opts._workers.push(worker); - - worker.on('online', function () { - log(opts.debug, 'worker is up'); - }); - - worker.on('message', function (msg) { - log(opts.debug, 'Message from worker ' + worker.id); - if ('LE_REQUEST' !== (msg && msg.type)) { - log(opts.debug, 'Ignoring irrelevant message'); - log(opts.debug, msg); - return; - } - - log(opts.debug, 'about to approveDomains'); - opts.approveDomains(msg.options, msg.certs, function (err, results) { - if (err) { - log(opts.debug, 'Approval got ERROR', err.stack || err); - worker.send({ - type: 'LE_RESPONSE' - , domain: msg.domain - , error: { message: err.message, code: err.code, stack: err.stack } - }); - return; + function log(debug) { + if (!debug) { + return; } - var promise; + var args = Array.prototype.slice.call(arguments); + args.shift(); + args.unshift("[le/lib/core.js]"); + console.log.apply(console, args); + } - // - /* + opts.addWorker = function(worker) { + opts._workers.push(worker); + + worker.on("online", function() { + log(opts.debug, "worker is up"); + }); + + worker.on("message", function(msg) { + log(opts.debug, "Message from worker " + worker.id); + if ("LE_REQUEST" !== (msg && msg.type)) { + log(opts.debug, "Ignoring irrelevant message"); + log(opts.debug, msg); + return; + } + + log(opts.debug, "about to approveDomains"); + opts.approveDomains(msg.options, msg.certs, function(err, results) { + if (err) { + log(opts.debug, "Approval got ERROR", err.stack || err); + worker.send({ + type: "LE_RESPONSE", + domain: msg.domain, + error: { message: err.message, code: err.code, stack: err.stack } + }); + return; + } + + var promise; + + // + /* var certs = require('localhost.example.com-certificates').merge({ subject: msg.domain , altnames: [ msg.domain ] @@ -66,26 +68,28 @@ module.exports.create = function (opts) { return; // */ - if (results.certs) { - promise = opts.greenlock.renew(results.options, results.certs); - } - else { - promise = opts.greenlock.register(results.options); - } + if (results.certs) { + promise = opts.greenlock.renew(results.options, results.certs); + } else { + promise = opts.greenlock.register(results.options); + } - promise.then(function (certs) { - log(opts.debug, 'Approval got certs', certs); - // certs = { subject, domains, issuedAt, expiresAt, privkey, cert, chain }; - opts._workers.forEach(function (w) { - w.send({ type: 'LE_RESPONSE', domain: msg.domain, certs: certs }); - }); - }, function (err) { - log(opts.debug, 'Approval got ERROR', err.stack || err); - worker.send({ type: 'LE_RESPONSE', domain: msg.domain, error: err }); + promise.then( + function(certs) { + log(opts.debug, "Approval got certs", certs); + // certs = { subject, domains, issuedAt, expiresAt, privkey, cert, chain }; + opts._workers.forEach(function(w) { + w.send({ type: "LE_RESPONSE", domain: msg.domain, certs: certs }); + }); + }, + function(err) { + log(opts.debug, "Approval got ERROR", err.stack || err); + worker.send({ type: "LE_RESPONSE", domain: msg.domain, error: err }); + } + ); + }); }); - }); - }); - }; + }; - return opts; + return opts; }; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..e1beb5c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,149 @@ +{ + "name": "greenlock-cluster", + "version": "3.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@root/acme": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@root/acme/-/acme-3.0.8.tgz", + "integrity": "sha512-VmBvLvWdCDkolkanI9Dzm1ouSWPaAa2eCCwcDZcVQbWoNiUIOqbbd57fcMA/gZxLyuJPStD2WXFuEuSMPDxcww==", + "requires": { + "@root/encoding": "^1.0.1", + "@root/keypairs": "^0.9.0", + "@root/pem": "^1.0.4", + "@root/request": "^1.3.11", + "@root/x509": "^0.7.2" + } + }, + "@root/asn1": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@root/asn1/-/asn1-1.0.0.tgz", + "integrity": "sha512-0lfZNuOULKJDJmdIkP8V9RnbV3XaK6PAHD3swnFy4tZwtlMDzLKoM/dfNad7ut8Hu3r91wy9uK0WA/9zym5mig==", + "requires": { + "@root/encoding": "^1.0.1" + } + }, + "@root/csr": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@root/csr/-/csr-0.8.1.tgz", + "integrity": "sha512-hKl0VuE549TK6SnS2Yn9nRvKbFZXn/oAg+dZJU/tlKl/f/0yRXeuUzf8akg3JjtJq+9E592zDqeXZ7yyrg8fSQ==", + "requires": { + "@root/asn1": "^1.0.0", + "@root/pem": "^1.0.4", + "@root/x509": "^0.7.2" + } + }, + "@root/encoding": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@root/encoding/-/encoding-1.0.1.tgz", + "integrity": "sha512-OaEub02ufoU038gy6bsNHQOjIn8nUjGiLcaRmJ40IUykneJkIW5fxDqKxQx48cszuNflYldsJLPPXCrGfHs8yQ==" + }, + "@root/greenlock": { + "version": "3.0.25", + "resolved": "https://registry.npmjs.org/@root/greenlock/-/greenlock-3.0.25.tgz", + "integrity": "sha512-VC8H9MTkbqxlB2LGntmcq5cstkE0TdZLvxm25SO5i7c6abJBVMQafhTD415OXwoGimnmWTn6SZ93Fj73d9QX/w==", + "requires": { + "@root/acme": "^3.0.8", + "@root/csr": "^0.8.1", + "@root/keypairs": "^0.9.0", + "@root/mkdirp": "^1.0.0", + "@root/request": "^1.3.10", + "acme-http-01-standalone": "^3.0.5", + "cert-info": "^1.5.1", + "greenlock-manager-fs": "^3.0.1", + "greenlock-store-fs": "^3.2.0", + "safe-replace": "^1.1.0" + } + }, + "@root/greenlock-express": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@root/greenlock-express/-/greenlock-express-3.0.13.tgz", + "integrity": "sha512-SgFsP4rBDPRBp52yqb8kONw7ZCkgyYrBFJLg4xhfIMbsMct4dfqB+N5eJbeF/exJh4+BHM7tppvf31Xuz6EO2Q==", + "requires": { + "@root/greenlock": "^3.0.25", + "redirect-https": "^1.1.5" + } + }, + "@root/keypairs": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@root/keypairs/-/keypairs-0.9.0.tgz", + "integrity": "sha512-NXE2L9Gv7r3iC4kB/gTPZE1vO9Ox/p14zDzAJ5cGpTpytbWOlWF7QoHSJbtVX4H7mRG/Hp7HR3jWdWdb2xaaXg==", + "requires": { + "@root/encoding": "^1.0.1", + "@root/pem": "^1.0.4", + "@root/x509": "^0.7.2" + } + }, + "@root/mkdirp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz", + "integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA==" + }, + "@root/pem": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@root/pem/-/pem-1.0.4.tgz", + "integrity": "sha512-rEUDiUsHtild8GfIjFE9wXtcVxeS+ehCJQBwbQQ3IVfORKHK93CFnRtkr69R75lZFjcmKYVc+AXDB+AeRFOULA==" + }, + "@root/request": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@root/request/-/request-1.4.2.tgz", + "integrity": "sha512-J8FM4+SJuc7WRC+Jz17m+VT2lgI7HtatHhxN1F2ck5aIKUAxJEaR4u/gLBsgT60mVHevKCjKN0O8115UtJjwLw==" + }, + "@root/x509": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@root/x509/-/x509-0.7.2.tgz", + "integrity": "sha512-ENq3LGYORK5NiMFHEVeNMt+fTXaC7DTS6sQXoqV+dFdfT0vmiL5cDLjaXQhaklJQq0NiwicZegzJRl1ZOTp3WQ==", + "requires": { + "@root/asn1": "^1.0.0", + "@root/encoding": "^1.0.1" + } + }, + "acme-http-01-standalone": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/acme-http-01-standalone/-/acme-http-01-standalone-3.0.5.tgz", + "integrity": "sha512-W4GfK+39GZ+u0mvxRVUcVFCG6gposfzEnSBF20T/NUwWAKG59wQT1dUbS1NixRIAsRuhpGc4Jx659cErFQH0Pg==" + }, + "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==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "greenlock-manager-fs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/greenlock-manager-fs/-/greenlock-manager-fs-3.0.1.tgz", + "integrity": "sha512-vZfGFq1TTKxaAqdGDUwNservrNzXx0xCwT/ovG/N378GrhS+U5S8B8LUlNtQU7Fdw6RToMiBcm22OOxSrvZ2zw==", + "requires": { + "@root/mkdirp": "^1.0.0", + "safe-replace": "^1.1.0" + } + }, + "greenlock-store-fs": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/greenlock-store-fs/-/greenlock-store-fs-3.2.0.tgz", + "integrity": "sha512-zqcPnF+173oYq5qU7FoGtuqeG8dmmvAiSnz98kEHAHyvgRF9pE1T0MM0AuqDdj45I3kXlCj2gZBwutnRi37J3g==", + "requires": { + "@root/mkdirp": "^1.0.0", + "safe-replace": "^1.1.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" + } + }, + "safe-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz", + "integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw==" + } + } +} diff --git a/package.json b/package.json index 4f76ff4..c393bab 100644 --- a/package.json +++ b/package.json @@ -1,44 +1,40 @@ { - "name": "greenlock-cluster", - "version": "2.1.0", - "description": "Use automatic letsencrypt (free ssl certs) on multiple cores or even multiple machines", - "main": "index.js", - "directories": { - "example": "examples" - }, - "dependencies": { - "le-sni-auto": "^2.0.1", - "greenlock": "^2.0.4", - "redirect-https": "^1.1.0" - }, - "devDependencies": {}, - "scripts": { - "test": "node examples/serve.js" - }, - "repository": { - "type": "git", - "url": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js.git" - }, - "keywords": [ - "cluster", - "acme", - "le", - "multi-core", - "cloud", - "scale", - "free", - "ssl", - "https", - "tls", - "letsencrypt", - "node", - "greenlock", - "node.js" - ], - "author": "AJ ONeal (https://coolaj86.com/)", - "license": "(MIT OR Apache-2.0)", - "bugs": { - "url": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js/issues" - }, - "homepage": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js" + "name": "greenlock-cluster", + "version": "3.0.0", + "description": "Use automatic letsencrypt (free ssl certs) on multiple cores or even multiple machines", + "main": "index.js", + "directories": { + "example": "examples" + }, + "dependencies": { + "@root/greenlock-express": "^3.0.13" + }, + "devDependencies": {}, + "scripts": {}, + "repository": { + "type": "git", + "url": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js.git" + }, + "keywords": [ + "cluster", + "acme", + "le", + "multi-core", + "cloud", + "scale", + "free", + "ssl", + "https", + "tls", + "letsencrypt", + "node", + "greenlock", + "node.js" + ], + "author": "AJ ONeal (https://coolaj86.com/)", + "license": "MPL-2.0", + "bugs": { + "url": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js/issues" + }, + "homepage": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js" } diff --git a/worker.js b/worker.js index 842c853..1618752 100644 --- a/worker.js +++ b/worker.js @@ -1,88 +1,78 @@ -'use strict'; +"use strict"; function log(debug) { - if (!debug) { - return; - } + if (!debug) { + return; + } - var args = Array.prototype.slice.call(arguments); - args.shift(); - args.unshift("[le/lib/core.js]"); - console.log.apply(console, args); + var args = Array.prototype.slice.call(arguments); + args.shift(); + args.unshift("[le/lib/core.js]"); + console.log.apply(console, args); } - - -module.exports.create = function (opts) { - - // if another worker updates the certs, - // receive a copy from master here as well - // and update the sni cache manually - process.on('message', function (msg) { - if ('LE_RESPONSE' === msg.type && msg.certs) { - opts.sni.cacheCerts(msg.certs); - } - }); - - opts.sni = require('le-sni-auto').create({ - renewWithin: opts.renewWithin || (10 * 24 * 60 * 60 * 1000) - , renewBy: opts.renewBy || (5 * 24 * 60 * 60 * 1000) - , getCertificates: function (domain, certs, cb) { - var workerOptions = { domains: [ domain ] }; - opts.approveDomains(workerOptions, certs, function (_err, results) { - if (_err) { - cb(_err); - return; +module.exports.create = function(opts) { + // if another worker updates the certs, + // receive a copy from master here as well + // and update the sni cache manually + process.on("message", function(msg) { + if ("LE_RESPONSE" === msg.type && msg.certs) { + opts.sni.cacheCerts(msg.certs); } + }); - process.send({ type: 'LE_REQUEST', domain: domain, options: results.options, certs: results.certs }); + opts.sni = require("le-sni-auto").create({ + renewWithin: opts.renewWithin || 10 * 24 * 60 * 60 * 1000, + renewBy: opts.renewBy || 5 * 24 * 60 * 60 * 1000, + getCertificates: function(domain, certs, cb) { + var workerOptions = { domains: [domain] }; + opts.approveDomains(workerOptions, certs, function(_err, results) { + if (_err) { + cb(_err); + return; + } - process.on('message', function (msg) { - var err = new Error("___MESSAGE___"); + process.send({ type: "LE_REQUEST", domain: domain, options: results.options, certs: results.certs }); - log(opts.debug, 'Message from master'); - log(opts.debug, msg); + process.on("message", function(msg) { + var err = new Error("___MESSAGE___"); - if (msg.domain !== domain) { - return; - } + log(opts.debug, "Message from master"); + log(opts.debug, msg); - if (msg.error) { - err.message = msg.error.message || "unknown error sent from cluster master to worker"; - err.stack.replace("___MESSAGE___", err.message); - err = { - message: err.message - , stack: err.stack - , data: { options: workerOptions, certs: certs } - }; - } else { - err = null; - } + if (msg.domain !== domain) { + return; + } - cb(err, msg.certs); - }); - }); - } - }); + if (msg.error) { + err.message = msg.error.message || "unknown error sent from cluster master to worker"; + err.stack.replace("___MESSAGE___", err.message); + err = { + message: err.message, + stack: err.stack, + data: { options: workerOptions, certs: certs } + }; + } else { + err = null; + } + cb(err, msg.certs); + }); + }); + } + }); + opts.httpsOptions = { SNICallback: opts.sni.sniCallback }; - opts.httpsOptions = { SNICallback: opts.sni.sniCallback }; + opts.challenge = { + get: + opts.getChallenge || + (opts.challenge && opts.challenge.get) || + require("le-challenge-fs").create({ webrootPath: opts.webrootPath }).get + }; + // opts.challenge.get, opts.acmeChallengePrefix + opts.middleware = require("greenlock/lib/middleware").create(opts); - - opts.challenge = { - get: opts.getChallenge - || (opts.challenge && opts.challenge.get) - || require('le-challenge-fs').create({ webrootPath: opts.webrootPath }).get - }; - - - - // opts.challenge.get, opts.acmeChallengePrefix - opts.middleware = require('greenlock/lib/middleware').create(opts); - - - - return opts; + return opts; };