Compare commits
	
		
			No commits in common. "v2.0.5" and "master" have entirely different histories.
		
	
	
		
	
		
							
								
								
									
										7
									
								
								.prettierrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.prettierrc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |   "bracketSpacing": true, | ||||||
|  |   "printWidth": 120, | ||||||
|  |   "tabWidth": 4, | ||||||
|  |   "trailingComma": "none", | ||||||
|  |   "useTabs": false | ||||||
|  | } | ||||||
							
								
								
									
										212
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										212
									
								
								README.md
									
									
									
									
									
								
							| @ -1,47 +1,68 @@ | |||||||
| <!-- BANNER_TPL_BEGIN --> | # Replaced: Use Greenlock Express v3 | ||||||
| 
 | 
 | ||||||
| About Daplie: We're taking back the Internet! | See https://git.rootprojects.org/root/greenlock-express.js | ||||||
| -------------- |  | ||||||
| 
 | 
 | ||||||
| Down with Google, Apple, and Facebook! | ```js | ||||||
|  | "use strict"; | ||||||
| 
 | 
 | ||||||
| We're re-decentralizing the web and making it read-write again - one home cloud system at a time. | var pkg = require("./package.json"); | ||||||
|  | require("greenlock-express") | ||||||
|  |     .init(function getConfig() { | ||||||
|  |         // Greenlock Config | ||||||
| 
 | 
 | ||||||
| Tired of serving the Empire? Come join the Rebel Alliance: |         return { | ||||||
|  |             package: { name: pkg.name, version: pkg.version }, | ||||||
|  |             maintainerEmail: pkg.author, | ||||||
| 
 | 
 | ||||||
| <a href="mailto:jobs@daplie.com">jobs@daplie.com</a> | [Invest in Daplie on Wefunder](https://daplie.com/invest/) | [Pre-order Cloud](https://daplie.com/preorder/), The World's First Home Server for Everyone |             // put cluster on full throttle! | ||||||
|  |             cloudnative: true | ||||||
|  |             webscale: true | ||||||
|  |             cluster: true | ||||||
|  |         }; | ||||||
|  |     }) | ||||||
|  |     .serve(httpsWorker); | ||||||
| 
 | 
 | ||||||
| <!-- BANNER_TPL_END --> | function httpsWorker(glx) { | ||||||
|  |     // Serves on 80 and 443 | ||||||
|  |     // Get's SSL certificates magically! | ||||||
| 
 | 
 | ||||||
| [](https://gitter.im/Daplie/letsencrypt-express?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) |     glx.serveApp(function(req, res) { | ||||||
|  |         res.end("Hello, Encrypted World!"); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| | [greenlock (lib)](https://git.daplie.com/Daplie/node-greenlock) | # OLD STUFF BELOW | ||||||
| | [greenlock-cli](https://git.daplie.com/Daplie/greenlock-cli) | 
 | ||||||
| | [greenlock-express](https://git.daplie.com/Daplie/greenlock-express) | # (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) | ||||||
|  | | [greenlock-express](https://git.coolaj86.com/coolaj86/greenlock-express.js) | ||||||
| | **greenlock-cluster** | | **greenlock-cluster** | ||||||
| | [greenlock-koa](https://git.daplie.com/Daplie/greenlock-koa) | | [greenlock-koa](https://git.coolaj86.com/coolaj86/greenlock-koa.js) | ||||||
| | [greenlock-hapi](https://git.daplie.com/Daplie/greenlock-hapi) | | [greenlock-hapi](https://git.coolaj86.com/coolaj86/greenlock-hapi.js) | ||||||
| | | | | ||||||
| 
 | 
 | ||||||
| greenlock-cluster (letsencrypt-cluster) | # greenlock-cluster | ||||||
| =================== | 
 | ||||||
|  | (previously letsencrypt-cluster) | ||||||
| 
 | 
 | ||||||
| Use automatic letsencrypt with node on multiple cores or even multiple machines. | Use automatic letsencrypt with node on multiple cores or even multiple machines. | ||||||
| 
 | 
 | ||||||
| * Take advantage of multi-core computing | -   Take advantage of multi-core computing | ||||||
| * Process certificates in master | -   Process certificates in master | ||||||
| * Serve https from multiple workers | -   Serve https from multiple workers | ||||||
| * Can work with any clustering strategy [#1](https://github.com/Daplie/letsencrypt-cluster/issues/1) | -   Can work with any clustering strategy [#1](https://github.com/Daplie/letsencrypt-cluster/issues/1) | ||||||
| 
 | 
 | ||||||
| Install | # Install | ||||||
| ======= |  | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| npm install --save greenlock-cluster@2.x | npm install --save greenlock-cluster@2.x | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Usage | # Usage | ||||||
| ===== |  | ||||||
| 
 | 
 | ||||||
| In a cluster environment you have some main file that boots your app | In a cluster environment you have some main file that boots your app | ||||||
| and then conditionally loads certain code based on whether that fork | and then conditionally loads certain code based on whether that fork | ||||||
| @ -51,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: | to be shared between both the master and the worker, like this: | ||||||
| 
 | 
 | ||||||
| `boot.js`: | `boot.js`: | ||||||
| ```javascript |  | ||||||
| 'use strict'; |  | ||||||
| 
 | 
 | ||||||
| var cluster = require('cluster'); | ```javascript | ||||||
| var path = require('path'); | "use strict"; | ||||||
| var os = require('os'); | 
 | ||||||
|  | var cluster = require("cluster"); | ||||||
|  | var path = require("path"); | ||||||
|  | var os = require("os"); | ||||||
| 
 | 
 | ||||||
| var main; | var main; | ||||||
| var sharedOptions = { | var sharedOptions = { | ||||||
|   webrootPath: path.join(os.tmpdir(), 'acme-challenge')			// /tmp/acme-challenge |     webrootPath: path.join(os.tmpdir(), "acme-challenge"), // /tmp/acme-challenge | ||||||
|                                                             // used by le-challenge-fs, the default plugin |     // used by le-challenge-fs, the default plugin | ||||||
| 
 | 
 | ||||||
| , renewWithin: 10 * 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) { | if (cluster.isMaster) { | ||||||
|   main = require('./master'); |     main = require("./master"); | ||||||
| } | } else { | ||||||
| else { |     main = require("./worker"); | ||||||
|   main = require('./worker'); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| main.init(sharedOptions); | main.init(sharedOptions); | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Master | ## Master | ||||||
| ------ |  | ||||||
| 
 | 
 | ||||||
| We think it makes the most sense to load greenlock in 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)) | This can prevent race conditions (see [node-letsencrypt#45](https://github.com/Daplie/node-letsencrypt/issues/45)) | ||||||
| @ -92,6 +112,7 @@ The master takes **the same arguments** as `node-greenlock` (`challenge`, `store | |||||||
| plus a few extra (`approveDomains`... okay, just one extra): | plus a few extra (`approveDomains`... okay, just one extra): | ||||||
| 
 | 
 | ||||||
| `master.js`: | `master.js`: | ||||||
|  | 
 | ||||||
| ```javascript | ```javascript | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| @ -102,7 +123,9 @@ module.exports.init = function (sharedOpts) { | |||||||
|   var leMaster = require('greenlock-cluster/master').create({ |   var leMaster = require('greenlock-cluster/master').create({ | ||||||
|     debug: sharedOpts.debug |     debug: sharedOpts.debug | ||||||
| 
 | 
 | ||||||
|   , server: 'staging'                                                       // CHANGE TO PRODUCTION |     // You MUST change this to 'https://acme-v02.api.letsencrypt.org/directory' in production | ||||||
|  |     server: 'https://acme-staging-v02.api.letsencrypt.org/directory' | ||||||
|  |   , version: 'draft-11' // Let's Encrypt v2 | ||||||
| 
 | 
 | ||||||
|   , renewWithin: sharedOpts.renewWithin |   , renewWithin: sharedOpts.renewWithin | ||||||
| 
 | 
 | ||||||
| @ -132,75 +155,75 @@ All options are passed directly to `node-greenlock` | |||||||
| (in other works, `leMaster` is a `greenlock` instance), | (in other works, `leMaster` is a `greenlock` instance), | ||||||
| but a few are only actually used by `greenlock-cluster`. | 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 | but only ones that are useful for determining certificate | ||||||
| renewal and for `le.challenge.get`. | 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`: | `worker.js`: | ||||||
|  | 
 | ||||||
| ```javascript | ```javascript | ||||||
| 'use strict'; | "use strict"; | ||||||
| 
 | 
 | ||||||
| module.exports.init = function (sharedOpts) { | module.exports.init = function(sharedOpts) { | ||||||
|   var leWorker = require('greenlock-cluster/worker').create({ |     var leWorker = require("greenlock-cluster/worker").create({ | ||||||
|     debug: sharedOpts.debug |         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) { |         approveDomains: function(workerOptions, certs, cb) { | ||||||
|       // opts = { domains, email, agreeTos, tosUrl } |             // opts = { domains, email, agreeTos, tosUrl } | ||||||
|       // certs = { subject, altnames, expiresAt, issuedAt } |             // certs = { subject, altnames, expiresAt, issuedAt } | ||||||
| 
 | 
 | ||||||
|       var results = { |             var results = { | ||||||
|         domain: workerOptions.domains[0] |                 domain: workerOptions.domains[0], | ||||||
|       , options: { |                 options: { | ||||||
|           domains: workerOptions.domains |                     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) { |     function app(req, res) { | ||||||
|         // modify opts.domains to match the original request |         res.end("Hello, World!"); | ||||||
|         // 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) { |     var redirectHttps = require("redirect-https")(); | ||||||
|     res.end("Hello, World!"); |     var plainServer = require("http").createServer(leWorker.middleware(redirectHttps)); | ||||||
|   } |     plainServer.listen(80); | ||||||
| 
 | 
 | ||||||
|   var redirectHttps = require('redirect-https')(); |     var server = require("https").createServer(leWorker.httpsOptions, leWorker.middleware(app)); | ||||||
|   var plainServer = require('http').createServer(leWorker.middleware(redirectHttps)); |     server.listen(443); | ||||||
|   plainServer.listen(80); |  | ||||||
| 
 |  | ||||||
|   var server = require('https').createServer(leWorker.httpsOptions, leWorker.middleware(app)); |  | ||||||
|   server.listen(443); |  | ||||||
| }; | }; | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| @ -209,16 +232,15 @@ module.exports.init = function (sharedOpts) { | |||||||
| `node-greenlock` is **not used** directly by the worker, | `node-greenlock` is **not used** directly by the worker, | ||||||
| but certain options are shared because certain logic is duplicated. | 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.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) | -   `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.middleware(nextApp)` uses `greenlock/middleware` for GET-ing `http-01`, hence `sharedOptions.webrootPath` | ||||||
| * `leWorker.httpsOptions` has a default localhost certificate and the `SNICallback`. | -   `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 | 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. | 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({})`, | The master and workers will communicate through `process.on('message', fn)`, `process.send({})`, | ||||||
| `worker.on('message', fn)`and `worker.send({})`. | `worker.on('message', fn)`and `worker.send({})`. | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| greenlock cluster examples | ## greenlock cluster examples | ||||||
| ------------------- |  | ||||||
| 
 | 
 | ||||||
| First you need to change the email address in `examples/worker.js`. | First you need to change the email address in `examples/worker.js`. | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,35 +1,29 @@ | |||||||
| 'use strict'; | "use strict"; | ||||||
| 
 | 
 | ||||||
| var cluster = require('cluster'); | var cluster = require("cluster"); | ||||||
| 
 | 
 | ||||||
| module.exports.init = function (sharedOpts) { | module.exports.init = function(sharedOpts) { | ||||||
|   var numCores = 2; // // Math.max(2, require('os').cpus().length)
 |     var numCores = 2; // // Math.max(2, require('os').cpus().length)
 | ||||||
|   var i; |     var i; | ||||||
|   var master = require('../master').create({ |     var master = require("../master").create({ | ||||||
|     debug: true |         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' |     for (i = 0; i < numCores; i += 1) { | ||||||
|   , webrootPath: sharedOpts.webrootPath |         master.addWorker(cluster.fork()); | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   , 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()); |  | ||||||
|   } |  | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -1,33 +1,27 @@ | |||||||
| 'use strict'; | "use strict"; | ||||||
| 
 | 
 | ||||||
| var cluster = require('cluster'); | var cluster = require("cluster"); | ||||||
| var main; | var main; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // You'll often see examples where people use cluster
 | // You'll often see examples where people use cluster
 | ||||||
| // master and worker all in the same file, which is fine,
 | // master and worker all in the same file, which is fine,
 | ||||||
| // but in order to conserve memory and especially to be
 | // but in order to conserve memory and especially to be
 | ||||||
| // less confusing, I'm splitting the code into two files
 | // less confusing, I'm splitting the code into two files
 | ||||||
| if (cluster.isMaster) { | if (cluster.isMaster) { | ||||||
|   main = require('./master'); |     main = require("./master"); | ||||||
|  | } else { | ||||||
|  |     main = require("./worker"); | ||||||
| } | } | ||||||
| else { |  | ||||||
|   main = require('./worker'); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| // this is nothing greenlock-cluster specific
 | // this is nothing greenlock-cluster specific
 | ||||||
| // I'm just arbitrarily choosing to share some configuration
 | // I'm just arbitrarily choosing to share some configuration
 | ||||||
| // that I know I'm going to use in both places
 | // that I know I'm going to use in both places
 | ||||||
| main.init({ | main.init({ | ||||||
|  |     // Depending on the strategy, the whole le-challenge-<<strategy>>
 | ||||||
|  |     // 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-<<strategy>>
 |     // this is used both by node-greenlock (master) and le-sni-auto (worker)
 | ||||||
|   // could be shared between worker and server, but since I'm just
 |     renewWithin: 15 * 24 * 60 * 60 * 1000 | ||||||
|   // 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 |  | ||||||
| }); | }); | ||||||
|  | |||||||
| @ -1,24 +1,18 @@ | |||||||
| 'use strict'; | "use strict"; | ||||||
| 
 | 
 | ||||||
| module.exports.init = function (sharedOpts) { | module.exports.init = function(sharedOpts) { | ||||||
|   var worker = require('../worker').create({ |     var worker = require("../worker").create({ | ||||||
|     debug: true |         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: { |     challenge: { | ||||||
|       get: function (ignored, domain, token, cb) { |       get: function (ignored, domain, token, cb) { | ||||||
|         cb(null, keyAuthorization); |         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:
 |             // We might want to do a check to make sure that all of the domains
 | ||||||
|     // 1. emails are tied to private keys (accounts) which must agree to the tos url
 |             // specified in altnames are still approved to be renewed and have
 | ||||||
|     // 2. domains are tied to accounts (and should be verifiable via loopback)
 |             // the correct dns entries, but generally speaking it's probably okay
 | ||||||
|   , approveDomains: function (workerOptions, certs, cb) { |             // for renewals to be automatic
 | ||||||
|       // opts = { domains, email, agreeTos, tosUrl }
 |             if (certs) { | ||||||
|       // certs = { subject, altnames, expiresAt, issuedAt }
 |                 // modify opts.domains to overwrite certs.altnames in renewal
 | ||||||
|       var results = { |                 cb(null, results); | ||||||
|         domain: workerOptions.domains[0] |                 return; | ||||||
|       , options: { |             } | ||||||
|           domains: certs && certs.altnames || workerOptions.domains | 
 | ||||||
|         , email: 'john.doe@example.com' |             // This is where we would check our database to make sure that
 | ||||||
|         , agreeTos: true |             // 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 |     }); | ||||||
|       }; |  | ||||||
| 
 | 
 | ||||||
| 
 |     function app(req, res) { | ||||||
| 
 |         res.end("Hello, World!"); | ||||||
|       // 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) { |     // worker.handleAcmeOrRedirectToHttps()
 | ||||||
|     res.end("Hello, World!"); |     // 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)); | ||||||
|   // worker.handleAcmeOrRedirectToHttps()
 |     plainServer.listen(80); | ||||||
|   // worker.handleAcmeOrUse(app)
 |     server.listen(443); | ||||||
|   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); |  | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								index.js
									
									
									
									
									
								
							| @ -1,12 +1,3 @@ | |||||||
| 'use strict'; | "use strict"; | ||||||
| 
 | 
 | ||||||
| console.error(""); | module.exports = require("@root/greenlock-express"); | ||||||
| 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); |  | ||||||
|  | |||||||
							
								
								
									
										138
									
								
								master.js
									
									
									
									
									
								
							
							
						
						
									
										138
									
								
								master.js
									
									
									
									
									
								
							| @ -1,59 +1,61 @@ | |||||||
| 'use strict'; | "use strict"; | ||||||
| 
 | 
 | ||||||
| // opts.addWorker(worker)
 | // opts.addWorker(worker)
 | ||||||
| // opts.approveDomains(options, certs, cb)
 | // opts.approveDomains(options, certs, cb)
 | ||||||
| module.exports.create = function (opts) { | module.exports.create = function(opts) { | ||||||
|   opts = opts || { }; |     opts = opts || {}; | ||||||
|   opts._workers = []; |     opts._workers = []; | ||||||
|   opts.webrootPath = opts.webrootPath || require('os').tmpdir() + require('path').sep + 'acme-challenge'; |     opts.webrootPath = opts.webrootPath || require("os").tmpdir() + require("path").sep + "acme-challenge"; | ||||||
|   if (!opts.greenlock) { opts.greenlock = require('greenlock').create(opts); } |     if (!opts.greenlock) { | ||||||
|   if ('function' !== typeof opts.approveDomains) { |         opts.greenlock = require("greenlock").create(opts); | ||||||
|     throw new Error("You must provide opts.approveDomains(domain, certs, callback) to approve certificates"); |     } | ||||||
|   } |     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; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     var args = Array.prototype.slice.call(arguments); |     function log(debug) { | ||||||
|     args.shift(); |         if (!debug) { | ||||||
|     args.unshift("[le/lib/core.js]"); |             return; | ||||||
|     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 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); | ||||||
|         var certs = require('localhost.daplie.com-certificates').merge({ | 
 | ||||||
|  |         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 |           subject: msg.domain | ||||||
|         , altnames: [ msg.domain ] |         , altnames: [ msg.domain ] | ||||||
|         , issuedAt: Date.now() |         , issuedAt: Date.now() | ||||||
| @ -66,26 +68,28 @@ module.exports.create = function (opts) { | |||||||
|         return; |         return; | ||||||
|         // */
 |         // */
 | ||||||
| 
 | 
 | ||||||
|         if (results.certs) { |                 if (results.certs) { | ||||||
|           promise = opts.greenlock.renew(results.options, results.certs); |                     promise = opts.greenlock.renew(results.options, results.certs); | ||||||
|         } |                 } else { | ||||||
|         else { |                     promise = opts.greenlock.register(results.options); | ||||||
|           promise = opts.greenlock.register(results.options); |                 } | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         promise.then(function (certs) { |                 promise.then( | ||||||
|           log(opts.debug, 'Approval got certs', certs); |                     function(certs) { | ||||||
|           // certs = { subject, domains, issuedAt, expiresAt, privkey, cert, chain };
 |                         log(opts.debug, "Approval got certs", certs); | ||||||
|           opts._workers.forEach(function (w) { |                         // certs = { subject, domains, issuedAt, expiresAt, privkey, cert, chain };
 | ||||||
|             w.send({ type: 'LE_RESPONSE', domain: msg.domain, certs: certs }); |                         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 }); |                     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; | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										149
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -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==" | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										81
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								package.json
									
									
									
									
									
								
							| @ -1,45 +1,40 @@ | |||||||
| { | { | ||||||
|   "name": "greenlock-cluster", |     "name": "greenlock-cluster", | ||||||
|   "version": "2.0.5", |     "version": "3.0.0", | ||||||
|   "description": "Use automatic letsencrypt (free ssl certs) on multiple cores or even multiple machines", |     "description": "Use automatic letsencrypt (free ssl certs) on multiple cores or even multiple machines", | ||||||
|   "main": "index.js", |     "main": "index.js", | ||||||
|   "directories": { |     "directories": { | ||||||
|     "example": "examples" |         "example": "examples" | ||||||
|   }, |     }, | ||||||
|   "dependencies": { |     "dependencies": { | ||||||
|     "le-sni-auto": "^2.0.1", |         "@root/greenlock-express": "^3.0.13" | ||||||
|     "greenlock": "^2.0.4", |     }, | ||||||
|     "localhost.daplie.com-certificates": "^1.2.3", |     "devDependencies": {}, | ||||||
|     "redirect-https": "^1.1.0" |     "scripts": {}, | ||||||
|   }, |     "repository": { | ||||||
|   "devDependencies": {}, |         "type": "git", | ||||||
|   "scripts": { |         "url": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js.git" | ||||||
|     "test": "node examples/serve.js" |     }, | ||||||
|   }, |     "keywords": [ | ||||||
|   "repository": { |         "cluster", | ||||||
|     "type": "git", |         "acme", | ||||||
|     "url": "git+https://git.daplie.com/Daplie/greenlock-cluster.git" |         "le", | ||||||
|   }, |         "multi-core", | ||||||
|   "keywords": [ |         "cloud", | ||||||
|     "cluster", |         "scale", | ||||||
|     "acme", |         "free", | ||||||
|     "le", |         "ssl", | ||||||
|     "multi-core", |         "https", | ||||||
|     "cloud", |         "tls", | ||||||
|     "scale", |         "letsencrypt", | ||||||
|     "free", |         "node", | ||||||
|     "ssl", |         "greenlock", | ||||||
|     "https", |         "node.js" | ||||||
|     "tls", |     ], | ||||||
|     "letsencrypt", |     "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)", | ||||||
|     "node", |     "license": "MPL-2.0", | ||||||
|     "greenlock", |     "bugs": { | ||||||
|     "node.js" |         "url": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js/issues" | ||||||
|   ], |     }, | ||||||
|   "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)", |     "homepage": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js" | ||||||
|   "license": "(MIT OR Apache-2.0)", |  | ||||||
|   "bugs": { |  | ||||||
|     "url": "https://git.daplie.com/Daplie/greenlock-cluster/issues" |  | ||||||
|   }, |  | ||||||
|   "homepage": "https://git.daplie.com/Daplie/greenlock-cluster#readme" |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										129
									
								
								worker.js
									
									
									
									
									
								
							
							
						
						
									
										129
									
								
								worker.js
									
									
									
									
									
								
							| @ -1,87 +1,78 @@ | |||||||
| 'use strict'; | "use strict"; | ||||||
| 
 | 
 | ||||||
| function log(debug) { | function log(debug) { | ||||||
| 	if (!debug) { |     if (!debug) { | ||||||
| 		return; |         return; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	var args = Array.prototype.slice.call(arguments); |     var args = Array.prototype.slice.call(arguments); | ||||||
| 	args.shift(); |     args.shift(); | ||||||
| 	args.unshift("[le/lib/core.js]"); |     args.unshift("[le/lib/core.js]"); | ||||||
| 	console.log.apply(console, args); |     console.log.apply(console, args); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | module.exports.create = function(opts) { | ||||||
| 
 |     // if another worker updates the certs,
 | ||||||
| module.exports.create = function (opts) { |     // receive a copy from master here as well
 | ||||||
| 
 |     // and update the sni cache manually
 | ||||||
|   // if another worker updates the certs,
 |     process.on("message", function(msg) { | ||||||
|   // receive a copy from master here as well
 |         if ("LE_RESPONSE" === msg.type && msg.certs) { | ||||||
|   // and update the sni cache manually
 |             opts.sni.cacheCerts(msg.certs); | ||||||
|   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; |  | ||||||
|         } |         } | ||||||
|  |     }); | ||||||
| 
 | 
 | ||||||
|         var err = new Error("___MESSAGE___"); |     opts.sni = require("le-sni-auto").create({ | ||||||
|         process.send({ type: 'LE_REQUEST', domain: domain, options: results.options, certs: results.certs }); |         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) { |                 process.send({ type: "LE_REQUEST", domain: domain, options: results.options, certs: results.certs }); | ||||||
|           log(opts.debug, 'Message from master'); |  | ||||||
|           log(opts.debug, msg); |  | ||||||
| 
 | 
 | ||||||
|           if (msg.domain !== domain) { |                 process.on("message", function(msg) { | ||||||
|             return; |                     var err = new Error("___MESSAGE___"); | ||||||
|           } |  | ||||||
| 
 | 
 | ||||||
|           if (msg.error) { |                     log(opts.debug, "Message from master"); | ||||||
|             err.message = msg.error.message || "unknown error sent from cluster master to worker"; |                     log(opts.debug, msg); | ||||||
|             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); |                     if (msg.domain !== domain) { | ||||||
|         }); |                         return; | ||||||
|       }); |                     } | ||||||
|     } |  | ||||||
|   }); |  | ||||||
| 
 | 
 | ||||||
|  |                     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 = require('localhost.daplie.com-certificates').merge({ 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 = { |     return opts; | ||||||
|     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; |  | ||||||
| }; | }; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user