whitespace
This commit is contained in:
		
							parent
							
								
									b80537f07b
								
							
						
					
					
						commit
						61fb942dda
					
				| @ -1,7 +1,7 @@ | |||||||
| { | { | ||||||
|   "bracketSpacing": true, |   "bracketSpacing": true, | ||||||
|   "printWidth": 120, |   "printWidth": 120, | ||||||
|   "tabWidth": 2, |   "tabWidth": 4, | ||||||
|   "trailingComma": "none", |   "trailingComma": "none", | ||||||
|   "useTabs": true |   "useTabs": false | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										182
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										182
									
								
								README.md
									
									
									
									
									
								
							| @ -22,26 +22,26 @@ Greenlock Express is a **Web Server** with **Fully Automated HTTPS** and renewal | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| function httpsWorker(glx) { | function httpsWorker(glx) { | ||||||
| 	// Serves on 80 and 443 |     // Serves on 80 and 443 | ||||||
| 	// Get's SSL certificates magically! |     // Get's SSL certificates magically! | ||||||
| 
 | 
 | ||||||
| 	glx.serveApp(function(req, res) { |     glx.serveApp(function(req, res) { | ||||||
| 		res.end("Hello, Encrypted World!"); |         res.end("Hello, Encrypted World!"); | ||||||
| 	}); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var pkg = require("./package.json"); | var pkg = require("./package.json"); | ||||||
| require("greenlock-express") | require("greenlock-express") | ||||||
| 	.init(function getConfig() { |     .init(function getConfig() { | ||||||
| 		// Greenlock Config |         // Greenlock Config | ||||||
| 
 | 
 | ||||||
| 		return { |         return { | ||||||
| 			package: { name: pkg.name, version: pkg.version }, |             package: { name: pkg.name, version: pkg.version }, | ||||||
| 			maintainerEmail: pkg.author, |             maintainerEmail: pkg.author, | ||||||
| 			cluster: false |             cluster: false | ||||||
| 		}; |         }; | ||||||
| 	}) |     }) | ||||||
| 	.serve(httpsWorker); |     .serve(httpsWorker); | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Manage via API or the config file: | Manage via API or the config file: | ||||||
| @ -50,44 +50,44 @@ Manage via API or the config file: | |||||||
| 
 | 
 | ||||||
| ```json | ```json | ||||||
| { | { | ||||||
| 	"subscriberEmail": "letsencrypt-test@therootcompany.com", |     "subscriberEmail": "letsencrypt-test@therootcompany.com", | ||||||
| 	"agreeToTerms": true, |     "agreeToTerms": true, | ||||||
| 	"sites": { |     "sites": { | ||||||
| 		"example.com": { |         "example.com": { | ||||||
| 			"subject": "example.com", |             "subject": "example.com", | ||||||
| 			"altnames": ["example.com", "www.example.com"] |             "altnames": ["example.com", "www.example.com"] | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| # Let's Encrypt for... | # Let's Encrypt for... | ||||||
| 
 | 
 | ||||||
| - IoT | -   IoT | ||||||
| - Enterprise On-Prem | -   Enterprise On-Prem | ||||||
| - Local Development | -   Local Development | ||||||
| - Home Servers | -   Home Servers | ||||||
| - Quitting Heroku | -   Quitting Heroku | ||||||
| 
 | 
 | ||||||
| # Features | # Features | ||||||
| 
 | 
 | ||||||
| - [x] Let's Encrypt v2 (November 2019) | -   [x] Let's Encrypt v2 (November 2019) | ||||||
|   - [x] ACME Protocol (RFC 8555) |     -   [x] ACME Protocol (RFC 8555) | ||||||
|   - [x] HTTP Validation (HTTP-01) |     -   [x] HTTP Validation (HTTP-01) | ||||||
|   - [x] DNS Validation (DNS-01) |     -   [x] DNS Validation (DNS-01) | ||||||
|   - [ ] ALPN Validation (TLS-ALPN-01) |     -   [ ] ALPN Validation (TLS-ALPN-01) | ||||||
|     - Need ALPN validation? [contact us](mailto:greenlock-support@therootcompany.com) |         -   Need ALPN validation? [contact us](mailto:greenlock-support@therootcompany.com) | ||||||
| - [x] Automated HTTPS | -   [x] Automated HTTPS | ||||||
|   - [x] Fully Automatic Renewals every 45 days |     -   [x] Fully Automatic Renewals every 45 days | ||||||
|   - [x] Free SSL |     -   [x] Free SSL | ||||||
|   - [x] **Wildcard** SSL |     -   [x] **Wildcard** SSL | ||||||
|   - [x] **Localhost** certificates |     -   [x] **Localhost** certificates | ||||||
|   - [x] HTTPS-enabled Secure **WebSockets** (`wss://`) |     -   [x] HTTPS-enabled Secure **WebSockets** (`wss://`) | ||||||
| - [x] Fully customizable | -   [x] Fully customizable | ||||||
|   - [x] **Reasonable defaults** |     -   [x] **Reasonable defaults** | ||||||
|   - [x] Domain Management |     -   [x] Domain Management | ||||||
|   - [x] Key and Certificate Management |     -   [x] Key and Certificate Management | ||||||
|   - [x] ACME Challenge Plugins |     -   [x] ACME Challenge Plugins | ||||||
| 
 | 
 | ||||||
| # QuickStart Guide | # QuickStart Guide | ||||||
| 
 | 
 | ||||||
| @ -127,7 +127,7 @@ works with everything. | |||||||
| // A plain, node-style app | // A plain, node-style app | ||||||
| 
 | 
 | ||||||
| function myPlainNodeHttpApp(req, res) { | function myPlainNodeHttpApp(req, res) { | ||||||
| 	res.end("Hello, Encrypted World!"); |     res.end("Hello, Encrypted World!"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Wrap that plain app in express, | // Wrap that plain app in express, | ||||||
| @ -152,9 +152,9 @@ module.exports = app; | |||||||
| 
 | 
 | ||||||
| Greenlock Express is designed with these goals in mind: | Greenlock Express is designed with these goals in mind: | ||||||
| 
 | 
 | ||||||
| - Simplicity and ease-of-use | -   Simplicity and ease-of-use | ||||||
| - Performance and scalability | -   Performance and scalability | ||||||
| - Configurability and control | -   Configurability and control | ||||||
| 
 | 
 | ||||||
| You can start with **near-zero configuration** and | You can start with **near-zero configuration** and | ||||||
| slowly add options for greater performance and customization | slowly add options for greater performance and customization | ||||||
| @ -164,21 +164,21 @@ later, if you need them. | |||||||
| 
 | 
 | ||||||
| ```js | ```js | ||||||
| require("greenlock-express") | require("greenlock-express") | ||||||
| 	.init(getConfig) |     .init(getConfig) | ||||||
| 	.serve(worker); |     .serve(worker); | ||||||
| 
 | 
 | ||||||
| function getConfig() { | function getConfig() { | ||||||
| 	return { |     return { | ||||||
| 		// uses name and version as part of the ACME client user-agent |         // uses name and version as part of the ACME client user-agent | ||||||
| 		// uses author as the contact for support notices |         // uses author as the contact for support notices | ||||||
| 		package: require("./package.json") |         package: require("./package.json") | ||||||
| 	}; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function worker(server) { | function worker(server) { | ||||||
| 	// Works with any Node app (Express, etc) |     // Works with any Node app (Express, etc) | ||||||
| 	var app = require("my-express-app.js"); |     var app = require("my-express-app.js"); | ||||||
| 	server.serveApp(app); |     server.serveApp(app); | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| @ -222,14 +222,14 @@ This will update the config file (assuming the default fs-based management plugi | |||||||
| 
 | 
 | ||||||
| ```json | ```json | ||||||
| { | { | ||||||
| 	"subscriberEmail": "letsencrypt-test@therootcompany.com", |     "subscriberEmail": "letsencrypt-test@therootcompany.com", | ||||||
| 	"agreeToTerms": true, |     "agreeToTerms": true, | ||||||
| 	"sites": { |     "sites": { | ||||||
| 		"example.com": { |         "example.com": { | ||||||
| 			"subject": "example.com", |             "subject": "example.com", | ||||||
| 			"altnames": ["example.com", "www.example.com"] |             "altnames": ["example.com", "www.example.com"] | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| @ -269,10 +269,10 @@ npx greenlock add --subject example.com --altnames example.com,www.example.com | |||||||
| Note: **Localhost**, **Wildcard**, and Certificates for Private Networks require | Note: **Localhost**, **Wildcard**, and Certificates for Private Networks require | ||||||
| [**DNS validation**](https://git.rootprojects.org/root/greenlock-exp). | [**DNS validation**](https://git.rootprojects.org/root/greenlock-exp). | ||||||
| 
 | 
 | ||||||
| - DNS Validation | -   DNS Validation | ||||||
|   - [**Wildcards**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/wildcards/) (coming soon) |     -   [**Wildcards**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/wildcards/) (coming soon) | ||||||
|   - [**Localhost**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/localhost/) (coming soon) |     -   [**Localhost**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/localhost/) (coming soon) | ||||||
|   - [**CI/CD**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/ci-cd/) (coming soon) |     -   [**CI/CD**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/ci-cd/) (coming soon) | ||||||
| 
 | 
 | ||||||
| </details> | </details> | ||||||
| 
 | 
 | ||||||
| @ -280,17 +280,17 @@ Note: **Localhost**, **Wildcard**, and Certificates for Private Networks require | |||||||
| 
 | 
 | ||||||
| **These are in-progress** Check back tomorrow (Nov 2nd, 2019). | **These are in-progress** Check back tomorrow (Nov 2nd, 2019). | ||||||
| 
 | 
 | ||||||
| - [greenlock-express.js/examples/](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples) | -   [greenlock-express.js/examples/](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples) | ||||||
|   - [Express](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/express/) |     -   [Express](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/express/) | ||||||
|   - [Node's **http2**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/http2/) |     -   [Node's **http2**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/http2/) | ||||||
|   - [Node's https](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/https/) |     -   [Node's https](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/https/) | ||||||
|   - [**WebSockets**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/websockets/) |     -   [**WebSockets**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/websockets/) | ||||||
|   - [Socket.IO](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/socket-io/) |     -   [Socket.IO](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/socket-io/) | ||||||
|   - [Cluster](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/cluster/) |     -   [Cluster](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/cluster/) | ||||||
|   - [**Wildcards**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/wildcards/) (coming soon) |     -   [**Wildcards**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/wildcards/) (coming soon) | ||||||
|   - [**Localhost**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/localhost/) (coming soon) |     -   [**Localhost**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/localhost/) (coming soon) | ||||||
|   - [**CI/CD**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/ci-cd/) (coming soon) |     -   [**CI/CD**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/ci-cd/) (coming soon) | ||||||
|   - [HTTP Proxy](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/http-proxy/) |     -   [HTTP Proxy](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/http-proxy/) | ||||||
| 
 | 
 | ||||||
| # Easy to Customize | # Easy to Customize | ||||||
| 
 | 
 | ||||||
| @ -300,10 +300,10 @@ Note: **Localhost**, **Wildcard**, and Certificates for Private Networks require | |||||||
| - [greenlock.js/examples/](https://git.rootprojects.org/root/greenlock.js/src/branch/master/examples) | - [greenlock.js/examples/](https://git.rootprojects.org/root/greenlock.js/src/branch/master/examples) | ||||||
| --> | --> | ||||||
| 
 | 
 | ||||||
| - [Custom Domain Management](https://git.rootprojects.org/root/greenlock-manager-test.js) | -   [Custom Domain Management](https://git.rootprojects.org/root/greenlock-manager-test.js) | ||||||
| - [Custom Key & Cert Storage](https://git.rootprojects.org/root/greenlock-store-test.js) | -   [Custom Key & Cert Storage](https://git.rootprojects.org/root/greenlock-store-test.js) | ||||||
| - [Custom ACME HTTP-01 Challenges](https://git.rootprojects.org/root/acme-http-01-test.js) | -   [Custom ACME HTTP-01 Challenges](https://git.rootprojects.org/root/acme-http-01-test.js) | ||||||
| - [Custom ACME DNS-01 Challenges](https://git.rootprojects.org/root/acme-dns-01-test.js) | -   [Custom ACME DNS-01 Challenges](https://git.rootprojects.org/root/acme-dns-01-test.js) | ||||||
| 
 | 
 | ||||||
| # Ready-made Integrations | # Ready-made Integrations | ||||||
| 
 | 
 | ||||||
| @ -345,12 +345,12 @@ We're working on more comprehensive documentation for this newly released versio | |||||||
| 
 | 
 | ||||||
| Do you need... | Do you need... | ||||||
| 
 | 
 | ||||||
| - training? | -   training? | ||||||
| - specific features? | -   specific features? | ||||||
| - different integrations? | -   different integrations? | ||||||
| - bugfixes, on _your_ timeline? | -   bugfixes, on _your_ timeline? | ||||||
| - custom code, built by experts? | -   custom code, built by experts? | ||||||
| - commercial support and licensing? | -   commercial support and licensing? | ||||||
| 
 | 
 | ||||||
| You're welcome to [contact us](mailto:aj@therootcompany.com) in regards to IoT, On-Prem, | You're welcome to [contact us](mailto:aj@therootcompany.com) in regards to IoT, On-Prem, | ||||||
| Enterprise, and Internal installations, integrations, and deployments. | Enterprise, and Internal installations, integrations, and deployments. | ||||||
|  | |||||||
							
								
								
									
										28
									
								
								config.js
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								config.js
									
									
									
									
									
								
							| @ -2,19 +2,19 @@ | |||||||
| 
 | 
 | ||||||
| var path = require("path"); | var path = require("path"); | ||||||
| module.exports = { | module.exports = { | ||||||
| 	email: "jon.doe@example.com", |     email: "jon.doe@example.com", | ||||||
| 	configDir: path.join(__dirname, "acme"), |     configDir: path.join(__dirname, "acme"), | ||||||
| 	srv: "/srv/www/", |     srv: "/srv/www/", | ||||||
| 	api: "/srv/api/", |     api: "/srv/api/", | ||||||
| 	proxy: { |     proxy: { | ||||||
| 		"example.com": "http://localhost:4080", |         "example.com": "http://localhost:4080", | ||||||
| 		"*.example.com": "http://localhost:4080" |         "*.example.com": "http://localhost:4080" | ||||||
| 	}, |     }, | ||||||
| 
 | 
 | ||||||
| 	// DNS-01 challenges only
 |     // DNS-01 challenges only
 | ||||||
| 	challenges: { |     challenges: { | ||||||
| 		"*.example.com": require("acme-dns-01-YOUR_DNS_HOST").create({ |         "*.example.com": require("acme-dns-01-YOUR_DNS_HOST").create({ | ||||||
| 			token: "xxxx" |             token: "xxxx" | ||||||
| 		}) |         }) | ||||||
| 	} |     } | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										48
									
								
								demo.js
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								demo.js
									
									
									
									
									
								
							| @ -1,35 +1,35 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| require("./") | require("./") | ||||||
| 	.init(initialize) |     .init(initialize) | ||||||
| 	.serve(worker) |     .serve(worker) | ||||||
| 	.master(function() { |     .master(function() { | ||||||
| 		console.log("Hello from master"); |         console.log("Hello from master"); | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| function initialize() { | function initialize() { | ||||||
| 	var pkg = require("./package.json"); |     var pkg = require("./package.json"); | ||||||
| 	var config = { |     var config = { | ||||||
| 		package: { |         package: { | ||||||
| 			name: "Greenlock_Express_Demo", |             name: "Greenlock_Express_Demo", | ||||||
| 			version: pkg.version, |             version: pkg.version, | ||||||
| 			author: pkg.author |             author: pkg.author | ||||||
| 		}, |         }, | ||||||
| 		staging: true, |         staging: true, | ||||||
| 		cluster: true, |         cluster: true, | ||||||
| 
 | 
 | ||||||
| 		notify: function(ev, params) { |         notify: function(ev, params) { | ||||||
| 			console.info(ev, params); |             console.info(ev, params); | ||||||
| 		} |         } | ||||||
| 	}; |     }; | ||||||
| 	return config; |     return config; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function worker(glx) { | function worker(glx) { | ||||||
| 	console.info(); |     console.info(); | ||||||
| 	console.info("Hello from worker #" + glx.id()); |     console.info("Hello from worker #" + glx.id()); | ||||||
| 
 | 
 | ||||||
| 	glx.serveApp(function(req, res) { |     glx.serveApp(function(req, res) { | ||||||
| 		res.end("Hello, Encrypted World!"); |         res.end("Hello, Encrypted World!"); | ||||||
| 	}); |     }); | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,37 +3,37 @@ | |||||||
| var pkg = require("../../package.json"); | var pkg = require("../../package.json"); | ||||||
| //require("greenlock-express")
 | //require("greenlock-express")
 | ||||||
| require("../../") | require("../../") | ||||||
| 	.init(function getConfig() { |     .init(function getConfig() { | ||||||
| 		// Greenlock Config
 |         // Greenlock Config
 | ||||||
| 
 | 
 | ||||||
| 		return { |         return { | ||||||
| 			package: { name: "websocket-example", version: pkg.version }, |             package: { name: "websocket-example", version: pkg.version }, | ||||||
| 			maintainerEmail: "jon@example.com", |             maintainerEmail: "jon@example.com", | ||||||
| 
 | 
 | ||||||
| 			// When you're ready to go full cloud scale, you just change this to true:
 |             // When you're ready to go full cloud scale, you just change this to true:
 | ||||||
| 			// Note: in cluster you CANNOT use in-memory state (see below)
 |             // Note: in cluster you CANNOT use in-memory state (see below)
 | ||||||
| 			cluster: true, |             cluster: true, | ||||||
| 
 | 
 | ||||||
| 			// This will default to the number of workers being equal to
 |             // This will default to the number of workers being equal to
 | ||||||
| 			// n-1 cpus, with a minimum of 2
 |             // n-1 cpus, with a minimum of 2
 | ||||||
| 			workers: 4 |             workers: 4 | ||||||
| 		}; |         }; | ||||||
| 	}) |     }) | ||||||
| 	.serve(httpsWorker); |     .serve(httpsWorker); | ||||||
| 
 | 
 | ||||||
| function httpsWorker(glx) { | function httpsWorker(glx) { | ||||||
| 	// WRONG
 |     // WRONG
 | ||||||
| 	// This won't work like you
 |     // This won't work like you
 | ||||||
| 	// think because EACH worker
 |     // think because EACH worker
 | ||||||
| 	// has ITS OWN `count`.
 |     // has ITS OWN `count`.
 | ||||||
| 	var count = 0; |     var count = 0; | ||||||
| 
 | 
 | ||||||
| 	var app = function(req, res) { |     var app = function(req, res) { | ||||||
| 		res.end("Hello... how many times now? Oh, " + count + " times"); |         res.end("Hello... how many times now? Oh, " + count + " times"); | ||||||
| 		count += 1; |         count += 1; | ||||||
| 	}; |     }; | ||||||
| 
 | 
 | ||||||
| 	// Serves on 80 and 443... for each worker
 |     // Serves on 80 and 443... for each worker
 | ||||||
| 	// Get's SSL certificates magically!
 |     // Get's SSL certificates magically!
 | ||||||
| 	glx.serveApp(app); |     glx.serveApp(app); | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,13 +4,13 @@ var express = require("express"); | |||||||
| var app = express(); | var app = express(); | ||||||
| 
 | 
 | ||||||
| app.use("/", function(req, res) { | app.use("/", function(req, res) { | ||||||
| 	res.setHeader("Content-Type", "text/html; charset=utf-8"); |     res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||||
| 	res.end("Hello, World!\n\n💚 🔒.js"); |     res.end("Hello, World!\n\n💚 🔒.js"); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| // DO NOT DO app.listen() unless we're testing this directly
 | // DO NOT DO app.listen() unless we're testing this directly
 | ||||||
| if (require.main === module) { | if (require.main === module) { | ||||||
| 	app.listen(3000); |     app.listen(3000); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Instead do export the app:
 | // Instead do export the app:
 | ||||||
|  | |||||||
| @ -1,27 +1,27 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| function httpsWorker(glx) { | function httpsWorker(glx) { | ||||||
| 	var app = require("./my-express-app.js"); |     var app = require("./my-express-app.js"); | ||||||
| 
 | 
 | ||||||
| 	app.get("/hello", function(req, res) { |     app.get("/hello", function(req, res) { | ||||||
| 		res.end("Hello, Encrypted World!"); |         res.end("Hello, Encrypted World!"); | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	// Serves on 80 and 443
 |     // Serves on 80 and 443
 | ||||||
| 	// Get's SSL certificates magically!
 |     // Get's SSL certificates magically!
 | ||||||
| 	glx.serveApp(app); |     glx.serveApp(app); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var pkg = require("../../package.json"); | var pkg = require("../../package.json"); | ||||||
| //require("greenlock-express")
 | //require("greenlock-express")
 | ||||||
| require("../../") | require("../../") | ||||||
| 	.init(function getConfig() { |     .init(function getConfig() { | ||||||
| 		// Greenlock Config
 |         // Greenlock Config
 | ||||||
| 
 | 
 | ||||||
| 		return { |         return { | ||||||
| 			package: { name: "http2-example", version: pkg.version }, |             package: { name: "http2-example", version: pkg.version }, | ||||||
| 			maintainerEmail: "jon@example.com", |             maintainerEmail: "jon@example.com", | ||||||
| 			cluster: false |             cluster: false | ||||||
| 		}; |         }; | ||||||
| 	}) |     }) | ||||||
| 	.serve(httpsWorker); |     .serve(httpsWorker); | ||||||
|  | |||||||
| @ -1,44 +1,44 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| function httpsWorker(glx) { | function httpsWorker(glx) { | ||||||
| 	// we need the raw https server
 |     // we need the raw https server
 | ||||||
| 	var server = glx.httpsServer(); |     var server = glx.httpsServer(); | ||||||
| 	var proxy = require("http-proxy").createProxyServer({ xfwd: true }); |     var proxy = require("http-proxy").createProxyServer({ xfwd: true }); | ||||||
| 
 | 
 | ||||||
| 	// catches error events during proxying
 |     // catches error events during proxying
 | ||||||
| 	proxy.on("error", function(err, req, res) { |     proxy.on("error", function(err, req, res) { | ||||||
| 		console.error(err); |         console.error(err); | ||||||
| 		res.statusCode = 500; |         res.statusCode = 500; | ||||||
| 		res.end(); |         res.end(); | ||||||
| 		return; |         return; | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	// We'll proxy websockets too
 |     // We'll proxy websockets too
 | ||||||
| 	server.on("upgrade", function(req, socket, head) { |     server.on("upgrade", function(req, socket, head) { | ||||||
| 		proxy.ws(req, socket, head, { |         proxy.ws(req, socket, head, { | ||||||
| 			ws: true, |             ws: true, | ||||||
| 			target: "ws://localhost:3000" |             target: "ws://localhost:3000" | ||||||
| 		}); |         }); | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	// servers a node app that proxies requests to a localhost
 |     // servers a node app that proxies requests to a localhost
 | ||||||
| 	glx.serveApp(function(req, res) { |     glx.serveApp(function(req, res) { | ||||||
| 		proxy.web(req, res, { |         proxy.web(req, res, { | ||||||
| 			target: "http://localhost:3000" |             target: "http://localhost:3000" | ||||||
| 		}); |         }); | ||||||
| 	}); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var pkg = require("../../package.json"); | var pkg = require("../../package.json"); | ||||||
| //require("greenlock-express")
 | //require("greenlock-express")
 | ||||||
| require("../../") | require("../../") | ||||||
| 	.init(function getConfig() { |     .init(function getConfig() { | ||||||
| 		// Greenlock Config
 |         // Greenlock Config
 | ||||||
| 
 | 
 | ||||||
| 		return { |         return { | ||||||
| 			package: { name: "http-proxy-example", version: pkg.version }, |             package: { name: "http-proxy-example", version: pkg.version }, | ||||||
| 			maintainerEmail: "jon@example.com", |             maintainerEmail: "jon@example.com", | ||||||
| 			cluster: false |             cluster: false | ||||||
| 		}; |         }; | ||||||
| 	}) |     }) | ||||||
| 	.serve(httpsWorker); |     .serve(httpsWorker); | ||||||
|  | |||||||
| @ -11,32 +11,32 @@ var pkg = require("../../package.json"); | |||||||
| // Use glx.httpServer(redirectToHttps) instead.
 | // Use glx.httpServer(redirectToHttps) instead.
 | ||||||
| 
 | 
 | ||||||
| function httpsWorker(glx) { | function httpsWorker(glx) { | ||||||
| 	//
 |     //
 | ||||||
| 	// HTTP can only be used for ACME HTTP-01 Challenges
 |     // HTTP can only be used for ACME HTTP-01 Challenges
 | ||||||
| 	// (and it is not required for DNS-01 challenges)
 |     // (and it is not required for DNS-01 challenges)
 | ||||||
| 	//
 |     //
 | ||||||
| 
 | 
 | ||||||
| 	// Get the raw http server:
 |     // Get the raw http server:
 | ||||||
| 	var httpServer = glx.httpServer(function(req, res) { |     var httpServer = glx.httpServer(function(req, res) { | ||||||
| 		res.statusCode = 301; |         res.statusCode = 301; | ||||||
| 		res.setHeader("Location", "https://" + req.headers.host + req.path); |         res.setHeader("Location", "https://" + req.headers.host + req.path); | ||||||
| 		res.end("Insecure connections are not allowed. Redirecting..."); |         res.end("Insecure connections are not allowed. Redirecting..."); | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	httpServer.listen(80, "0.0.0.0", function() { |     httpServer.listen(80, "0.0.0.0", function() { | ||||||
| 		console.info("Listening on ", httpServer.address()); |         console.info("Listening on ", httpServer.address()); | ||||||
| 	}); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //require("greenlock-express")
 | //require("greenlock-express")
 | ||||||
| require("../../") | require("../../") | ||||||
| 	.init(function getConfig() { |     .init(function getConfig() { | ||||||
| 		// Greenlock Config
 |         // Greenlock Config
 | ||||||
| 
 | 
 | ||||||
| 		return { |         return { | ||||||
| 			package: { name: "plain-http-example", version: pkg.version }, |             package: { name: "plain-http-example", version: pkg.version }, | ||||||
| 			maintainerEmail: "jon@example.com", |             maintainerEmail: "jon@example.com", | ||||||
| 			cluster: false |             cluster: false | ||||||
| 		}; |         }; | ||||||
| 	}) |     }) | ||||||
| 	.serve(httpsWorker); |     .serve(httpsWorker); | ||||||
|  | |||||||
| @ -11,38 +11,38 @@ var pkg = require("../../package.json"); | |||||||
| // Use glx.httpsServer(tlsOptions, app) instead.
 | // Use glx.httpsServer(tlsOptions, app) instead.
 | ||||||
| 
 | 
 | ||||||
| function httpsWorker(glx) { | function httpsWorker(glx) { | ||||||
| 	//
 |     //
 | ||||||
| 	// HTTP2 would have been the default httpsServer for node v12+
 |     // HTTP2 would have been the default httpsServer for node v12+
 | ||||||
| 	// However... https://github.com/expressjs/express/issues/3388
 |     // However... https://github.com/expressjs/express/issues/3388
 | ||||||
| 	//
 |     //
 | ||||||
| 
 | 
 | ||||||
| 	// Get the raw http2 server:
 |     // Get the raw http2 server:
 | ||||||
| 	var http2Server = glx.http2Server(function(req, res) { |     var http2Server = glx.http2Server(function(req, res) { | ||||||
| 		res.end("Hello, Encrypted World!"); |         res.end("Hello, Encrypted World!"); | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	http2Server.listen(443, "0.0.0.0", function() { |     http2Server.listen(443, "0.0.0.0", function() { | ||||||
| 		console.info("Listening on ", http2Server.address()); |         console.info("Listening on ", http2Server.address()); | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	// Note:
 |     // Note:
 | ||||||
| 	// You must ALSO listen on port 80 for ACME HTTP-01 Challenges
 |     // You must ALSO listen on port 80 for ACME HTTP-01 Challenges
 | ||||||
| 	// (the ACME and http->https middleware are loaded by glx.httpServer)
 |     // (the ACME and http->https middleware are loaded by glx.httpServer)
 | ||||||
| 	var httpServer = glx.httpServer(); |     var httpServer = glx.httpServer(); | ||||||
| 	httpServer.listen(80, "0.0.0.0", function() { |     httpServer.listen(80, "0.0.0.0", function() { | ||||||
| 		console.info("Listening on ", httpServer.address()); |         console.info("Listening on ", httpServer.address()); | ||||||
| 	}); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //require("greenlock-express")
 | //require("greenlock-express")
 | ||||||
| require("../../") | require("../../") | ||||||
| 	.init(function getConfig() { |     .init(function getConfig() { | ||||||
| 		// Greenlock Config
 |         // Greenlock Config
 | ||||||
| 
 | 
 | ||||||
| 		return { |         return { | ||||||
| 			package: { name: "http2-example", version: pkg.version }, |             package: { name: "http2-example", version: pkg.version }, | ||||||
| 			maintainerEmail: "jon@example.com", |             maintainerEmail: "jon@example.com", | ||||||
| 			cluster: false |             cluster: false | ||||||
| 		}; |         }; | ||||||
| 	}) |     }) | ||||||
| 	.serve(httpsWorker); |     .serve(httpsWorker); | ||||||
|  | |||||||
| @ -11,38 +11,38 @@ var pkg = require("../../package.json"); | |||||||
| // Use glx.httpsServer(tlsOptions, app) instead.
 | // Use glx.httpsServer(tlsOptions, app) instead.
 | ||||||
| 
 | 
 | ||||||
| function httpsWorker(glx) { | function httpsWorker(glx) { | ||||||
| 	//
 |     //
 | ||||||
| 	// HTTPS 1.1 is the default
 |     // HTTPS 1.1 is the default
 | ||||||
| 	// (HTTP2 would be the default but... https://github.com/expressjs/express/issues/3388)
 |     // (HTTP2 would be the default but... https://github.com/expressjs/express/issues/3388)
 | ||||||
| 	//
 |     //
 | ||||||
| 
 | 
 | ||||||
| 	// Get the raw https server:
 |     // Get the raw https server:
 | ||||||
| 	var httpsServer = glx.httpsServer(null, function(req, res) { |     var httpsServer = glx.httpsServer(null, function(req, res) { | ||||||
| 		res.end("Hello, Encrypted World!"); |         res.end("Hello, Encrypted World!"); | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	httpsServer.listen(443, "0.0.0.0", function() { |     httpsServer.listen(443, "0.0.0.0", function() { | ||||||
| 		console.info("Listening on ", httpsServer.address()); |         console.info("Listening on ", httpsServer.address()); | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	// Note:
 |     // Note:
 | ||||||
| 	// You must ALSO listen on port 80 for ACME HTTP-01 Challenges
 |     // You must ALSO listen on port 80 for ACME HTTP-01 Challenges
 | ||||||
| 	// (the ACME and http->https middleware are loaded by glx.httpServer)
 |     // (the ACME and http->https middleware are loaded by glx.httpServer)
 | ||||||
| 	var httpServer = glx.httpServer(); |     var httpServer = glx.httpServer(); | ||||||
| 	httpServer.listen(80, "0.0.0.0", function() { |     httpServer.listen(80, "0.0.0.0", function() { | ||||||
| 		console.info("Listening on ", httpServer.address()); |         console.info("Listening on ", httpServer.address()); | ||||||
| 	}); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //require("greenlock-express")
 | //require("greenlock-express")
 | ||||||
| require("../../") | require("../../") | ||||||
| 	.init(function getConfig() { |     .init(function getConfig() { | ||||||
| 		// Greenlock Config
 |         // Greenlock Config
 | ||||||
| 
 | 
 | ||||||
| 		return { |         return { | ||||||
| 			package: { name: "https1-example", version: pkg.version }, |             package: { name: "https1-example", version: pkg.version }, | ||||||
| 			maintainerEmail: "jon@example.com", |             maintainerEmail: "jon@example.com", | ||||||
| 			cluster: false |             cluster: false | ||||||
| 		}; |         }; | ||||||
| 	}) |     }) | ||||||
| 	.serve(httpsWorker); |     .serve(httpsWorker); | ||||||
|  | |||||||
							
								
								
									
										75
									
								
								examples/old-demo.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								examples/old-demo.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | |||||||
|  | "use strict"; | ||||||
|  | 
 | ||||||
|  | // npm install spdy@3.x
 | ||||||
|  | 
 | ||||||
|  | //var Greenlock = require('greenlock-express')
 | ||||||
|  | var Greenlock = require("../"); | ||||||
|  | 
 | ||||||
|  | var greenlock = Greenlock.create({ | ||||||
|  |     // Let's Encrypt v2 is ACME draft 11
 | ||||||
|  |     version: "draft-11", | ||||||
|  | 
 | ||||||
|  |     server: "https://acme-v02.api.letsencrypt.org/directory", | ||||||
|  |     // Note: If at first you don't succeed, stop and switch to staging
 | ||||||
|  |     // https://acme-staging-v02.api.letsencrypt.org/directory
 | ||||||
|  | 
 | ||||||
|  |     // You MUST change this to a valid email address
 | ||||||
|  |     email: "jon@example.com", | ||||||
|  | 
 | ||||||
|  |     // You MUST NOT build clients that accept the ToS without asking the user
 | ||||||
|  |     agreeTos: true, | ||||||
|  | 
 | ||||||
|  |     // You MUST change these to valid domains
 | ||||||
|  |     // NOTE: all domains will validated and listed on the certificate
 | ||||||
|  |     approvedDomains: ["example.com", "www.example.com"], | ||||||
|  | 
 | ||||||
|  |     // You MUST have access to write to directory where certs are saved
 | ||||||
|  |     // ex: /home/foouser/acme/etc
 | ||||||
|  |     configDir: "~/.config/acme/", | ||||||
|  | 
 | ||||||
|  |     // Get notified of important updates and help me make greenlock better
 | ||||||
|  |     communityMember: true | ||||||
|  | 
 | ||||||
|  |     //, debug: true
 | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | ////////////////////////
 | ||||||
|  | // http-01 Challenges //
 | ||||||
|  | ////////////////////////
 | ||||||
|  | 
 | ||||||
|  | // http-01 challenge happens over http/1.1, not http2
 | ||||||
|  | var redirectHttps = require("redirect-https")(); | ||||||
|  | var acmeChallengeHandler = greenlock.middleware(function(req, res) { | ||||||
|  |     res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||||
|  |     res.end( | ||||||
|  |         "<h1>Hello, ⚠️ Insecure World!</h1><a>Visit Secure Site</a>" + | ||||||
|  |             '<script>document.querySelector("a").href=window.location.href.replace(/^http/i, "https");</script>' | ||||||
|  |     ); | ||||||
|  | }); | ||||||
|  | require("http") | ||||||
|  |     .createServer(acmeChallengeHandler) | ||||||
|  |     .listen(80, function() { | ||||||
|  |         console.log("Listening for ACME http-01 challenges on", this.address()); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  | ////////////////////////
 | ||||||
|  | // http2 via SPDY h2  //
 | ||||||
|  | ////////////////////////
 | ||||||
|  | 
 | ||||||
|  | // spdy is a drop-in replacement for the https API
 | ||||||
|  | var spdyOptions = Object.assign({}, greenlock.tlsOptions); | ||||||
|  | spdyOptions.spdy = { protocols: ["h2", "http/1.1"], plain: false }; | ||||||
|  | var server = require("spdy").createServer( | ||||||
|  |     spdyOptions, | ||||||
|  |     require("express")().use("/", function(req, res) { | ||||||
|  |         res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||||
|  |         res.end("<h1>Hello, 🔐 Secure World!</h1>"); | ||||||
|  |     }) | ||||||
|  | ); | ||||||
|  | server.on("error", function(err) { | ||||||
|  |     console.error(err); | ||||||
|  | }); | ||||||
|  | server.on("listening", function() { | ||||||
|  |     console.log("Listening for SPDY/http2/https requests on", this.address()); | ||||||
|  | }); | ||||||
|  | server.listen(443); | ||||||
							
								
								
									
										30
									
								
								examples/old-force-renew.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								examples/old-force-renew.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | "use strict"; | ||||||
|  | 
 | ||||||
|  | //require('greenlock-express')
 | ||||||
|  | require("../") | ||||||
|  |     .create({ | ||||||
|  |         // Let's Encrypt v2 is ACME draft 11
 | ||||||
|  |         version: "draft-11", | ||||||
|  | 
 | ||||||
|  |         server: "https://acme-v02.api.letsencrypt.org/directory", | ||||||
|  |         // Note: If at first you don't succeed, stop and switch to staging
 | ||||||
|  |         // https://acme-staging-v02.api.letsencrypt.org/directory
 | ||||||
|  | 
 | ||||||
|  |         email: "john.doe@example.com", | ||||||
|  | 
 | ||||||
|  |         agreeTos: true, | ||||||
|  | 
 | ||||||
|  |         approvedDomains: ["example.com", "www.example.com"], | ||||||
|  | 
 | ||||||
|  |         app: require("express")().use("/", function(req, res) { | ||||||
|  |             res.end("Hello, World!"); | ||||||
|  |         }), | ||||||
|  | 
 | ||||||
|  |         renewWithin: 91 * 24 * 60 * 60 * 1000, | ||||||
|  |         renewBy: 90 * 24 * 60 * 60 * 1000, | ||||||
|  | 
 | ||||||
|  |         // Get notified of important updates and help me make greenlock better
 | ||||||
|  |         communityMember: true, | ||||||
|  |         debug: true | ||||||
|  |     }) | ||||||
|  |     .listen(80, 443); | ||||||
							
								
								
									
										104
									
								
								examples/old-remote-access.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								examples/old-remote-access.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | |||||||
|  | "use strict"; | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | // WARNING: Not for noobs
 | ||||||
|  | // Try the simple example first
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | // This demo is used with tunnel-server.js and tunnel-client.js
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | var email = "john.doe@gmail.com"; | ||||||
|  | var domains = ["example.com"]; | ||||||
|  | var agreeLeTos = true; | ||||||
|  | //var secret = "My Little Brony";
 | ||||||
|  | var secret = require("crypto") | ||||||
|  |     .randomBytes(16) | ||||||
|  |     .toString("hex"); | ||||||
|  | 
 | ||||||
|  | require("../") | ||||||
|  |     .create({ | ||||||
|  |         version: "draft-11", | ||||||
|  | 
 | ||||||
|  |         server: "https://acme-v02.api.letsencrypt.org/directory", | ||||||
|  |         // Note: If at first you don't succeed, stop and switch to staging
 | ||||||
|  |         // https://acme-staging-v02.api.letsencrypt.org/directory
 | ||||||
|  | 
 | ||||||
|  |         email: email, | ||||||
|  |         agreeTos: agreeLeTos, | ||||||
|  |         approveDomains: domains, | ||||||
|  |         configDir: "~/.config/acme/", | ||||||
|  |         app: remoteAccess(secret), | ||||||
|  |         // Get notified of important updates and help me make greenlock better
 | ||||||
|  |         communityMember: true | ||||||
|  |         //, debug: true
 | ||||||
|  |     }) | ||||||
|  |     .listen(3000, 8443); | ||||||
|  | 
 | ||||||
|  | function remoteAccess(secret) { | ||||||
|  |     var express = require("express"); | ||||||
|  |     var basicAuth = require("express-basic-auth"); | ||||||
|  |     var serveIndex = require("serve-index"); | ||||||
|  | 
 | ||||||
|  |     var rootIndex = serveIndex("/", { hidden: true, icons: true, view: "details" }); | ||||||
|  |     var rootFs = express.static("/", { dotfiles: "allow", redirect: true, index: false }); | ||||||
|  | 
 | ||||||
|  |     var userIndex = serveIndex(require("os").homedir(), { hidden: true, icons: true, view: "details" }); | ||||||
|  |     var userFs = express.static(require("os").homedir(), { dotfiles: "allow", redirect: true, index: false }); | ||||||
|  | 
 | ||||||
|  |     var app = express(); | ||||||
|  |     var realm = "Login Required"; | ||||||
|  | 
 | ||||||
|  |     var myAuth = basicAuth({ | ||||||
|  |         users: { root: secret, user: secret }, | ||||||
|  |         challenge: true, | ||||||
|  |         realm: realm, | ||||||
|  |         unauthorizedResponse: function(/*req*/) { | ||||||
|  |             return 'Unauthorized <a href="/">Home</a>'; | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     app.get("/", function(req, res) { | ||||||
|  |         res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||||
|  |         res.end('<a href="/browse/">View Files</a>' + "  |  " + '<a href="/logout/">Logout</a>'); | ||||||
|  |     }); | ||||||
|  |     app.use("/logout", function(req, res) { | ||||||
|  |         res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||||
|  |         res.setHeader("WWW-Authenticate", 'Basic realm="' + realm + '"'); | ||||||
|  |         res.statusCode = 401; | ||||||
|  |         //res.setHeader('Location', '/');
 | ||||||
|  |         res.end('Logged out   |   <a href="/">Home</a>'); | ||||||
|  |     }); | ||||||
|  |     app.use("/browse", myAuth); | ||||||
|  |     app.use("/browse", function(req, res, next) { | ||||||
|  |         if ("root" === req.auth.user) { | ||||||
|  |             rootFs(req, res, function() { | ||||||
|  |                 rootIndex(req, res, next); | ||||||
|  |             }); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         if ("user" === req.auth.user) { | ||||||
|  |             userFs(req, res, function() { | ||||||
|  |                 userIndex(req, res, next); | ||||||
|  |             }); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         res.end("Sad Panda"); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     console.log(""); | ||||||
|  |     console.log(""); | ||||||
|  |     console.log("Usernames are\n"); | ||||||
|  |     console.log("\troot"); | ||||||
|  |     console.log("\tuser"); | ||||||
|  |     console.log(""); | ||||||
|  |     console.log("Password (for both) is\n"); | ||||||
|  |     console.log("\t" + secret); | ||||||
|  |     console.log(""); | ||||||
|  |     console.log("Shhhh... It's a secret to everybody!"); | ||||||
|  |     console.log(""); | ||||||
|  |     console.log(""); | ||||||
|  | 
 | ||||||
|  |     return app; | ||||||
|  | } | ||||||
							
								
								
									
										134
									
								
								examples/old-vhost.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								examples/old-vhost.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,134 @@ | |||||||
|  | #!/usr/bin/env node
 | ||||||
|  | "use strict"; | ||||||
|  | 
 | ||||||
|  | ///////////////////
 | ||||||
|  | // vhost example //
 | ||||||
|  | ///////////////////
 | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | // virtual hosting example
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | // The prefix where sites go by name.
 | ||||||
|  | // For example: whatever.com may live in /srv/www/whatever.com, thus /srv/www is our path
 | ||||||
|  | var srv = process.argv[3] || "/srv/www/"; | ||||||
|  | 
 | ||||||
|  | var path = require("path"); | ||||||
|  | var fs = require("fs").promises; | ||||||
|  | var finalhandler = require("finalhandler"); | ||||||
|  | var serveStatic = require("serve-static"); | ||||||
|  | 
 | ||||||
|  | //var glx = require('greenlock-express')
 | ||||||
|  | var glx = require("./").create({ | ||||||
|  |     version: "draft-11", // Let's Encrypt v2 is ACME draft 11
 | ||||||
|  | 
 | ||||||
|  |     server: "https://acme-v02.api.letsencrypt.org/directory", // If at first you don't succeed, stop and switch to staging
 | ||||||
|  |     // https://acme-staging-v02.api.letsencrypt.org/directory
 | ||||||
|  | 
 | ||||||
|  |     configDir: process.argv[4] || "~/.config/acme/", // You MUST have access to write to directory where certs
 | ||||||
|  |     // are saved. ex: /home/foouser/.config/acme
 | ||||||
|  | 
 | ||||||
|  |     approveDomains: myApproveDomains, // Greenlock's wraps around tls.SNICallback. Check the
 | ||||||
|  |     // domain name here and reject invalid ones
 | ||||||
|  | 
 | ||||||
|  |     app: myVhostApp, // Any node-style http app (i.e. express, koa, hapi, rill)
 | ||||||
|  | 
 | ||||||
|  |     /* CHANGE TO A VALID EMAIL */ | ||||||
|  |     email: process.argv[2] || "jon.doe@example.com", // Email for Let's Encrypt account and Greenlock Security
 | ||||||
|  |     agreeTos: true // Accept Let's Encrypt ToS
 | ||||||
|  |     //, communityMember: true                                   // Join Greenlock to get important updates, no spam
 | ||||||
|  | 
 | ||||||
|  |     //, debug: true
 | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | var server = glx.listen(80, 443); | ||||||
|  | server.on("listening", function() { | ||||||
|  |     console.info(server.type + " listening on", server.address()); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | function myApproveDomains(opts, certs, cb) { | ||||||
|  |     console.log("sni:", opts.domain); | ||||||
|  |     // In this example the filesystem is our "database".
 | ||||||
|  |     // We check in /srv/www for whatever.com and if it exists, it's allowed
 | ||||||
|  | 
 | ||||||
|  |     // SECURITY Greenlock validates opts.domains ahead-of-time so you don't have to
 | ||||||
|  |     return checkWwws(opts.domains[0]) | ||||||
|  |         .then(function() { | ||||||
|  |             //opts.email = email;
 | ||||||
|  |             opts.agreeTos = true; | ||||||
|  |             cb(null, { options: opts, certs: certs }); | ||||||
|  |         }) | ||||||
|  |         .catch(cb); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function checkWwws(_hostname) { | ||||||
|  |     if (!_hostname) { | ||||||
|  |         // SECURITY, don't allow access to the 'srv' root
 | ||||||
|  |         // (greenlock-express uses middleware to check '..', etc)
 | ||||||
|  |         return ""; | ||||||
|  |     } | ||||||
|  |     var hostname = _hostname; | ||||||
|  |     var _hostdir = path.join(srv, hostname); | ||||||
|  |     var hostdir = _hostdir; | ||||||
|  |     // TODO could test for www/no-www both in directory
 | ||||||
|  |     return fs | ||||||
|  |         .readdir(hostdir) | ||||||
|  |         .then(function() { | ||||||
|  |             // TODO check for some sort of htaccess.json and use email in that
 | ||||||
|  |             // NOTE: you can also change other options such as `challengeType` and `challenge`
 | ||||||
|  |             // opts.challengeType = 'http-01';
 | ||||||
|  |             // opts.challenge = require('le-challenge-fs').create({});
 | ||||||
|  |             return hostname; | ||||||
|  |         }) | ||||||
|  |         .catch(function() { | ||||||
|  |             if ("www." === hostname.slice(0, 4)) { | ||||||
|  |                 // Assume we'll redirect to non-www if it's available.
 | ||||||
|  |                 hostname = hostname.slice(4); | ||||||
|  |                 hostdir = path.join(srv, hostname); | ||||||
|  |                 return fs.readdir(hostdir).then(function() { | ||||||
|  |                     // TODO list both domains?
 | ||||||
|  |                     return hostname; | ||||||
|  |                 }); | ||||||
|  |             } else { | ||||||
|  |                 // Or check and see if perhaps we should redirect non-www to www
 | ||||||
|  |                 hostname = "www." + hostname; | ||||||
|  |                 hostdir = path.join(srv, hostname); | ||||||
|  |                 return fs.readdir(hostdir).then(function() { | ||||||
|  |                     // TODO list both domains?
 | ||||||
|  |                     return hostname; | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .catch(function() { | ||||||
|  |             throw new Error("rejecting '" + _hostname + "' because '" + _hostdir + "' could not be read"); | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function myVhostApp(req, res) { | ||||||
|  |     // SECURITY greenlock pre-sanitizes hostnames to prevent unauthorized fs access so you don't have to
 | ||||||
|  |     // (also: only domains approved above will get here)
 | ||||||
|  |     console.log("vhost:", req.headers.host); | ||||||
|  |     if (!req.headers.host) { | ||||||
|  |         // SECURITY, don't allow access to the 'srv' root
 | ||||||
|  |         // (greenlock-express uses middleware to check '..', etc)
 | ||||||
|  |         return res.end(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // We could cache wether or not a host exists for some amount of time
 | ||||||
|  |     var fin = finalhandler(req, res); | ||||||
|  |     return checkWwws(req.headers.host) | ||||||
|  |         .then(function(hostname) { | ||||||
|  |             if (hostname !== req.headers.host) { | ||||||
|  |                 res.statusCode = 302; | ||||||
|  |                 res.setHeader("Location", "https://" + hostname); | ||||||
|  |                 // SECURITY this is safe only because greenlock disallows invalid hostnames
 | ||||||
|  |                 res.end("<!-- redirecting to https://" + hostname + "-->"); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             var serve = serveStatic(path.join(srv, hostname), { redirect: true }); | ||||||
|  |             serve(req, res, fin); | ||||||
|  |         }) | ||||||
|  |         .catch(function() { | ||||||
|  |             fin(); | ||||||
|  |         }); | ||||||
|  | } | ||||||
							
								
								
									
										77
									
								
								examples/old-wildcard.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								examples/old-wildcard.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,77 @@ | |||||||
|  | #!/usr/bin/env node
 | ||||||
|  | "use strict"; | ||||||
|  | /*global Promise*/ | ||||||
|  | 
 | ||||||
|  | ///////////////////////
 | ||||||
|  | // wildcard example //
 | ||||||
|  | //////////////////////
 | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | // wildcard example
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | //var glx = require('greenlock-express')
 | ||||||
|  | var glx = require("../").create({ | ||||||
|  |     version: "draft-11", // Let's Encrypt v2 is ACME draft 11
 | ||||||
|  | 
 | ||||||
|  |     server: "https://acme-staging-v02.api.letsencrypt.org/directory", | ||||||
|  |     //, server: 'https://acme-v02.api.letsencrypt.org/directory'  // If at first you don't succeed, stop and switch to staging
 | ||||||
|  |     // https://acme-staging-v02.api.letsencrypt.org/directory
 | ||||||
|  | 
 | ||||||
|  |     configDir: "~/acme/", // You MUST have access to write to directory where certs
 | ||||||
|  |     // are saved. ex: /home/foouser/.config/acme
 | ||||||
|  | 
 | ||||||
|  |     approveDomains: myApproveDomains, // Greenlock's wraps around tls.SNICallback. Check the
 | ||||||
|  |     // domain name here and reject invalid ones
 | ||||||
|  | 
 | ||||||
|  |     app: require("./my-express-app.js"), // Any node-style http app (i.e. express, koa, hapi, rill)
 | ||||||
|  | 
 | ||||||
|  |     /* CHANGE TO A VALID EMAIL */ | ||||||
|  |     email: "jon.doe@example.com", // Email for Let's Encrypt account and Greenlock Security
 | ||||||
|  |     agreeTos: true, // Accept Let's Encrypt ToS
 | ||||||
|  |     communityMember: true, // Join Greenlock to (very rarely) get important updates
 | ||||||
|  | 
 | ||||||
|  |     //, debug: true
 | ||||||
|  |     store: require("le-store-fs") | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | var server = glx.listen(80, 443); | ||||||
|  | server.on("listening", function() { | ||||||
|  |     console.info(server.type + " listening on", server.address()); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | function myApproveDomains(opts) { | ||||||
|  |     console.log("sni:", opts.domain); | ||||||
|  | 
 | ||||||
|  |     // must be 'example.com' or start with 'example.com'
 | ||||||
|  |     if ( | ||||||
|  |         "example.com" !== opts.domain && | ||||||
|  |         "example.com" !== | ||||||
|  |             opts.domain | ||||||
|  |                 .split(".") | ||||||
|  |                 .slice(1) | ||||||
|  |                 .join(".") | ||||||
|  |     ) { | ||||||
|  |         return Promise.reject(new Error("we don't serve your kind here: " + opts.domain)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // the primary domain for the cert
 | ||||||
|  |     opts.subject = "example.com"; | ||||||
|  |     // the altnames (including the primary)
 | ||||||
|  |     opts.domains = [opts.subject, "*.example.com"]; | ||||||
|  | 
 | ||||||
|  |     if (!opts.challenges) { | ||||||
|  |         opts.challenges = {}; | ||||||
|  |     } | ||||||
|  |     opts.challenges["http-01"] = require("le-challenge-fs").create({}); | ||||||
|  |     // Note: When implementing a dns-01 plugin you should make it check in a loop
 | ||||||
|  |     // until it can positively confirm that the DNS changes have propagated.
 | ||||||
|  |     // That could take several seconds to a few minutes.
 | ||||||
|  |     opts.challenges["dns-01"] = require("le-challenge-dns").create({}); | ||||||
|  | 
 | ||||||
|  |     // explicitly set account id and certificate.id
 | ||||||
|  |     opts.account = { id: opts.email }; | ||||||
|  |     opts.certificate = { id: opts.subject }; | ||||||
|  | 
 | ||||||
|  |     return Promise.resolve(opts); | ||||||
|  | } | ||||||
| @ -10,13 +10,13 @@ Manage via API or the config file: | |||||||
| 
 | 
 | ||||||
| ```json | ```json | ||||||
| { | { | ||||||
| 	"subscriberEmail": "letsencrypt-test@therootcompany.com", |     "subscriberEmail": "letsencrypt-test@therootcompany.com", | ||||||
| 	"agreeToTerms": true, |     "agreeToTerms": true, | ||||||
| 	"sites": { |     "sites": { | ||||||
| 		"example.com": { |         "example.com": { | ||||||
| 			"subject": "example.com", |             "subject": "example.com", | ||||||
| 			"altnames": ["example.com", "www.example.com"] |             "altnames": ["example.com", "www.example.com"] | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  | |||||||
| @ -1,32 +1,32 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| function httpsWorker(glx) { | function httpsWorker(glx) { | ||||||
| 	// This can be a node http app (shown),
 |     // This can be a node http app (shown),
 | ||||||
| 	// an Express app, or Hapi, Koa, Rill, etc
 |     // an Express app, or Hapi, Koa, Rill, etc
 | ||||||
| 	var app = function(req, res) { |     var app = function(req, res) { | ||||||
| 		res.end("Hello, Encrypted World!"); |         res.end("Hello, Encrypted World!"); | ||||||
| 	}; |     }; | ||||||
| 
 | 
 | ||||||
| 	// Serves on 80 and 443
 |     // Serves on 80 and 443
 | ||||||
| 	// Get's SSL certificates magically!
 |     // Get's SSL certificates magically!
 | ||||||
| 	glx.serveApp(app); |     glx.serveApp(app); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var pkg = require("../../package.json"); | var pkg = require("../../package.json"); | ||||||
| //require("greenlock-express")
 | //require("greenlock-express")
 | ||||||
| require("../../") | require("../../") | ||||||
| 	.init(function getConfig() { |     .init(function getConfig() { | ||||||
| 		// Greenlock Config
 |         // Greenlock Config
 | ||||||
| 
 | 
 | ||||||
| 		return { |         return { | ||||||
| 			// Package name+version is used for ACME client user agent
 |             // Package name+version is used for ACME client user agent
 | ||||||
| 			package: { name: "websocket-example", version: pkg.version }, |             package: { name: "websocket-example", version: pkg.version }, | ||||||
| 
 | 
 | ||||||
| 			// Maintainer email is the contact for critical bug and security notices
 |             // Maintainer email is the contact for critical bug and security notices
 | ||||||
| 			maintainerEmail: "jon@example.com", |             maintainerEmail: "jon@example.com", | ||||||
| 
 | 
 | ||||||
| 			// Change to true when you're ready to make your app cloud-scale
 |             // Change to true when you're ready to make your app cloud-scale
 | ||||||
| 			cluster: false |             cluster: false | ||||||
| 		}; |         }; | ||||||
| 	}) |     }) | ||||||
| 	.serve(httpsWorker); |     .serve(httpsWorker); | ||||||
|  | |||||||
| @ -9,41 +9,41 @@ | |||||||
| //       (see the websocket example)
 | //       (see the websocket example)
 | ||||||
| 
 | 
 | ||||||
| function httpsWorker(glx) { | function httpsWorker(glx) { | ||||||
| 	var socketio = require("socket.io"); |     var socketio = require("socket.io"); | ||||||
| 	var io; |     var io; | ||||||
| 
 | 
 | ||||||
| 	// we need the raw https server
 |     // we need the raw https server
 | ||||||
| 	var server = glx.httpsServer(); |     var server = glx.httpsServer(); | ||||||
| 
 | 
 | ||||||
| 	io = socketio(server); |     io = socketio(server); | ||||||
| 
 | 
 | ||||||
| 	// Then you do your socket.io stuff
 |     // Then you do your socket.io stuff
 | ||||||
| 	io.on("connection", function(socket) { |     io.on("connection", function(socket) { | ||||||
| 		console.log("a user connected"); |         console.log("a user connected"); | ||||||
| 		socket.emit("Welcome"); |         socket.emit("Welcome"); | ||||||
| 
 | 
 | ||||||
| 		socket.on("chat message", function(msg) { |         socket.on("chat message", function(msg) { | ||||||
| 			socket.broadcast.emit("chat message", msg); |             socket.broadcast.emit("chat message", msg); | ||||||
| 		}); |         }); | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	// servers a node app that proxies requests to a localhost
 |     // servers a node app that proxies requests to a localhost
 | ||||||
| 	glx.serveApp(function(req, res) { |     glx.serveApp(function(req, res) { | ||||||
| 		res.setHeader("Content-Type", "text/html; charset=utf-8"); |         res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||||
| 		res.end("Hello, World!\n\n💚 🔒.js"); |         res.end("Hello, World!\n\n💚 🔒.js"); | ||||||
| 	}); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var pkg = require("../../package.json"); | var pkg = require("../../package.json"); | ||||||
| //require("greenlock-express")
 | //require("greenlock-express")
 | ||||||
| require("../../") | require("../../") | ||||||
| 	.init(function getConfig() { |     .init(function getConfig() { | ||||||
| 		// Greenlock Config
 |         // Greenlock Config
 | ||||||
| 
 | 
 | ||||||
| 		return { |         return { | ||||||
| 			package: { name: "socket-io-example", version: pkg.version }, |             package: { name: "socket-io-example", version: pkg.version }, | ||||||
| 			maintainerEmail: "jon@example.com", |             maintainerEmail: "jon@example.com", | ||||||
| 			cluster: false |             cluster: false | ||||||
| 		}; |         }; | ||||||
| 	}) |     }) | ||||||
| 	.serve(httpsWorker); |     .serve(httpsWorker); | ||||||
|  | |||||||
| @ -1,42 +1,42 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| function httpsWorker(glx) { | function httpsWorker(glx) { | ||||||
| 	// we need the raw https server
 |     // we need the raw https server
 | ||||||
| 	var server = glx.httpsServer(); |     var server = glx.httpsServer(); | ||||||
| 	var WebSocket = require("ws"); |     var WebSocket = require("ws"); | ||||||
| 	var ws = new WebSocket.Server({ server: server }); |     var ws = new WebSocket.Server({ server: server }); | ||||||
| 	ws.on("connection", function(ws, req) { |     ws.on("connection", function(ws, req) { | ||||||
| 		// inspect req.headers.authorization (or cookies) for session info
 |         // inspect req.headers.authorization (or cookies) for session info
 | ||||||
| 		ws.send( |         ws.send( | ||||||
| 			"[Secure Echo Server] Hello!\nAuth: '" + |             "[Secure Echo Server] Hello!\nAuth: '" + | ||||||
| 				(req.headers.authorization || "none") + |                 (req.headers.authorization || "none") + | ||||||
| 				"'\n" + |                 "'\n" + | ||||||
| 				"Cookie: '" + |                 "Cookie: '" + | ||||||
| 				(req.headers.cookie || "none") + |                 (req.headers.cookie || "none") + | ||||||
| 				"'\n" |                 "'\n" | ||||||
| 		); |         ); | ||||||
| 		ws.on("message", function(data) { |         ws.on("message", function(data) { | ||||||
| 			ws.send(data); |             ws.send(data); | ||||||
| 		}); |         }); | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	// servers a node app that proxies requests to a localhost
 |     // servers a node app that proxies requests to a localhost
 | ||||||
| 	glx.serveApp(function(req, res) { |     glx.serveApp(function(req, res) { | ||||||
| 		res.setHeader("Content-Type", "text/html; charset=utf-8"); |         res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||||
| 		res.end("Hello, World!\n\n💚 🔒.js"); |         res.end("Hello, World!\n\n💚 🔒.js"); | ||||||
| 	}); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var pkg = require("../../package.json"); | var pkg = require("../../package.json"); | ||||||
| //require("greenlock-express")
 | //require("greenlock-express")
 | ||||||
| require("../../") | require("../../") | ||||||
| 	.init(function getConfig() { |     .init(function getConfig() { | ||||||
| 		// Greenlock Config
 |         // Greenlock Config
 | ||||||
| 
 | 
 | ||||||
| 		return { |         return { | ||||||
| 			package: { name: "websocket-example", version: pkg.version }, |             package: { name: "websocket-example", version: pkg.version }, | ||||||
| 			maintainerEmail: "jon@example.com", |             maintainerEmail: "jon@example.com", | ||||||
| 			cluster: false |             cluster: false | ||||||
| 		}; |         }; | ||||||
| 	}) |     }) | ||||||
| 	.serve(httpsWorker); |     .serve(httpsWorker); | ||||||
|  | |||||||
| @ -17,28 +17,28 @@ var GLE = module.exports; | |||||||
| // under the hood. That's the hope, anyway.
 | // under the hood. That's the hope, anyway.
 | ||||||
| 
 | 
 | ||||||
| GLE.init = function(fn) { | GLE.init = function(fn) { | ||||||
| 	if (cluster.isWorker) { |     if (cluster.isWorker) { | ||||||
| 		// ignore the init function and launch the worker
 |         // ignore the init function and launch the worker
 | ||||||
| 		return require("./worker.js").create(); |         return require("./worker.js").create(); | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	var opts = fn(); |     var opts = fn(); | ||||||
| 	if (!opts || "object" !== typeof opts) { |     if (!opts || "object" !== typeof opts) { | ||||||
| 		throw new Error( |         throw new Error( | ||||||
| 			"the `Greenlock.init(fn)` function should return an object `{ maintainerEmail, packageAgent, notify }`" |             "the `Greenlock.init(fn)` function should return an object `{ maintainerEmail, packageAgent, notify }`" | ||||||
| 		); |         ); | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	// just for ironic humor
 |     // just for ironic humor
 | ||||||
| 	["cloudnative", "cloudscale", "webscale", "distributed", "blockchain"].forEach(function(k) { |     ["cloudnative", "cloudscale", "webscale", "distributed", "blockchain"].forEach(function(k) { | ||||||
| 		if (opts[k]) { |         if (opts[k]) { | ||||||
| 			opts.cluster = true; |             opts.cluster = true; | ||||||
| 		} |         } | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	if (opts.cluster) { |     if (opts.cluster) { | ||||||
| 		return require("./master.js").create(opts); |         return require("./master.js").create(opts); | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	return require("./single.js").create(opts); |     return require("./single.js").create(opts); | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										104
									
								
								greenlock.js
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								greenlock.js
									
									
									
									
									
								
							| @ -1,29 +1,29 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| module.exports.create = function(opts) { | module.exports.create = function(opts) { | ||||||
| 	opts = parsePackage(opts); |     opts = parsePackage(opts); | ||||||
| 	opts.packageAgent = addGreenlockAgent(opts); |     opts.packageAgent = addGreenlockAgent(opts); | ||||||
| 
 | 
 | ||||||
| 	var Greenlock = require("@root/greenlock"); |     var Greenlock = require("@root/greenlock"); | ||||||
| 	var greenlock = Greenlock.create(opts); |     var greenlock = Greenlock.create(opts); | ||||||
| 
 | 
 | ||||||
| 	// re-export as top-level function to simplify rpc with workers
 |     // re-export as top-level function to simplify rpc with workers
 | ||||||
| 	greenlock.getAcmeHttp01ChallengeResponse = function(opts) { |     greenlock.getAcmeHttp01ChallengeResponse = function(opts) { | ||||||
| 		return greenlock.challenges.get(opts); |         return greenlock.challenges.get(opts); | ||||||
| 	}; |     }; | ||||||
| 
 | 
 | ||||||
| 	return greenlock; |     return greenlock; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| function addGreenlockAgent(opts) { | function addGreenlockAgent(opts) { | ||||||
| 	// Add greenlock as part of Agent, unless this is greenlock
 |     // Add greenlock as part of Agent, unless this is greenlock
 | ||||||
| 	var packageAgent = opts.packageAgent || ""; |     var packageAgent = opts.packageAgent || ""; | ||||||
| 	if (!/greenlock(-express|-pro)?/i.test(packageAgent)) { |     if (!/greenlock(-express|-pro)?/i.test(packageAgent)) { | ||||||
| 		var pkg = require("./package.json"); |         var pkg = require("./package.json"); | ||||||
| 		packageAgent += " Greenlock_Express/" + pkg.version; |         packageAgent += " Greenlock_Express/" + pkg.version; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	return packageAgent.trim(); |     return packageAgent.trim(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ex: "John Doe <john@example.com> (https://john.doe)"
 | // ex: "John Doe <john@example.com> (https://john.doe)"
 | ||||||
| @ -32,46 +32,46 @@ function addGreenlockAgent(opts) { | |||||||
| // ex: "john@example.com"
 | // ex: "john@example.com"
 | ||||||
| var looseEmailRe = /(^|[\s<])([^'" <>:;`]+@[^'" <>:;`]+\.[^'" <>:;`]+)/; | var looseEmailRe = /(^|[\s<])([^'" <>:;`]+@[^'" <>:;`]+\.[^'" <>:;`]+)/; | ||||||
| function parsePackage(opts) { | function parsePackage(opts) { | ||||||
| 	// 'package' is sometimes a reserved word
 |     // 'package' is sometimes a reserved word
 | ||||||
| 	var pkg = opts.package || opts.pkg; |     var pkg = opts.package || opts.pkg; | ||||||
| 	if (!pkg) { |     if (!pkg) { | ||||||
| 		opts.maintainerEmail = parseMaintainer(opts.maintainerEmail); |         opts.maintainerEmail = parseMaintainer(opts.maintainerEmail); | ||||||
| 		return opts; |         return opts; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	if (!opts.packageAgent) { |     if (!opts.packageAgent) { | ||||||
| 		var err = "missing `package.THING`, which is used for the ACME client user agent string"; |         var err = "missing `package.THING`, which is used for the ACME client user agent string"; | ||||||
| 		if (!pkg.name) { |         if (!pkg.name) { | ||||||
| 			throw new Error(err.replace("THING", "name")); |             throw new Error(err.replace("THING", "name")); | ||||||
| 		} |         } | ||||||
| 		if (!pkg.version) { |         if (!pkg.version) { | ||||||
| 			throw new Error(err.replace("THING", "version")); |             throw new Error(err.replace("THING", "version")); | ||||||
| 		} |         } | ||||||
| 		opts.packageAgent = pkg.name + "/" + pkg.version; |         opts.packageAgent = pkg.name + "/" + pkg.version; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	if (!opts.maintainerEmail) { |     if (!opts.maintainerEmail) { | ||||||
| 		try { |         try { | ||||||
| 			opts.maintainerEmail = pkg.author.email || pkg.author.match(looseEmailRe)[2]; |             opts.maintainerEmail = pkg.author.email || pkg.author.match(looseEmailRe)[2]; | ||||||
| 		} catch (e) {} |         } catch (e) {} | ||||||
| 	} |     } | ||||||
| 	if (!opts.maintainerEmail) { |     if (!opts.maintainerEmail) { | ||||||
| 		throw new Error("missing or malformed `package.author`, which is used as the contact for support notices"); |         throw new Error("missing or malformed `package.author`, which is used as the contact for support notices"); | ||||||
| 	} |     } | ||||||
| 	opts.package = undefined; |     opts.package = undefined; | ||||||
| 	opts.maintainerEmail = parseMaintainer(opts.maintainerEmail); |     opts.maintainerEmail = parseMaintainer(opts.maintainerEmail); | ||||||
| 
 | 
 | ||||||
| 	return opts; |     return opts; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function parseMaintainer(maintainerEmail) { | function parseMaintainer(maintainerEmail) { | ||||||
| 	try { |     try { | ||||||
| 		maintainerEmail = maintainerEmail.match(looseEmailRe)[2]; |         maintainerEmail = maintainerEmail.match(looseEmailRe)[2]; | ||||||
| 	} catch (e) { |     } catch (e) { | ||||||
| 		maintainerEmail = null; |         maintainerEmail = null; | ||||||
| 	} |     } | ||||||
| 	if (!maintainerEmail) { |     if (!maintainerEmail) { | ||||||
| 		throw new Error("missing or malformed `maintainerEmail`, which is used as the contact for support notices"); |         throw new Error("missing or malformed `maintainerEmail`, which is used as the contact for support notices"); | ||||||
| 	} |     } | ||||||
| 	return maintainerEmail; |     return maintainerEmail; | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,102 +5,102 @@ var servernameRe = /^[a-z0-9\.\-]+$/i; | |||||||
| var challengePrefix = "/.well-known/acme-challenge/"; | var challengePrefix = "/.well-known/acme-challenge/"; | ||||||
| 
 | 
 | ||||||
| HttpMiddleware.create = function(gl, defaultApp) { | HttpMiddleware.create = function(gl, defaultApp) { | ||||||
| 	if (defaultApp && "function" !== typeof defaultApp) { |     if (defaultApp && "function" !== typeof defaultApp) { | ||||||
| 		throw new Error("use greenlock.httpMiddleware() or greenlock.httpMiddleware(function (req, res) {})"); |         throw new Error("use greenlock.httpMiddleware() or greenlock.httpMiddleware(function (req, res) {})"); | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	return function(req, res, next) { |     return function(req, res, next) { | ||||||
| 		var hostname = HttpMiddleware.sanitizeHostname(req); |         var hostname = HttpMiddleware.sanitizeHostname(req); | ||||||
| 
 | 
 | ||||||
| 		req.on("error", function(err) { |         req.on("error", function(err) { | ||||||
| 			explainError(gl, err, "http_01_middleware_socket", hostname); |             explainError(gl, err, "http_01_middleware_socket", hostname); | ||||||
| 		}); |         }); | ||||||
| 
 | 
 | ||||||
| 		if (skipIfNeedBe(req, res, next, defaultApp, hostname)) { |         if (skipIfNeedBe(req, res, next, defaultApp, hostname)) { | ||||||
| 			return; |             return; | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		var token = req.url.slice(challengePrefix.length); |         var token = req.url.slice(challengePrefix.length); | ||||||
| 
 | 
 | ||||||
| 		gl.getAcmeHttp01ChallengeResponse({ type: "http-01", servername: hostname, token: token }) |         gl.getAcmeHttp01ChallengeResponse({ type: "http-01", servername: hostname, token: token }) | ||||||
| 			.catch(function(err) { |             .catch(function(err) { | ||||||
| 				respondToError(gl, res, err, "http_01_middleware_challenge_response", hostname); |                 respondToError(gl, res, err, "http_01_middleware_challenge_response", hostname); | ||||||
| 				return { __done: true }; |                 return { __done: true }; | ||||||
| 			}) |             }) | ||||||
| 			.then(function(result) { |             .then(function(result) { | ||||||
| 				if (result && result.__done) { |                 if (result && result.__done) { | ||||||
| 					return; |                     return; | ||||||
| 				} |                 } | ||||||
| 				return respondWithGrace(res, result, hostname, token); |                 return respondWithGrace(res, result, hostname, token); | ||||||
| 			}); |             }); | ||||||
| 	}; |     }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| function skipIfNeedBe(req, res, next, defaultApp, hostname) { | function skipIfNeedBe(req, res, next, defaultApp, hostname) { | ||||||
| 	if (!hostname || 0 !== req.url.indexOf(challengePrefix)) { |     if (!hostname || 0 !== req.url.indexOf(challengePrefix)) { | ||||||
| 		if ("function" === typeof defaultApp) { |         if ("function" === typeof defaultApp) { | ||||||
| 			defaultApp(req, res, next); |             defaultApp(req, res, next); | ||||||
| 		} else if ("function" === typeof next) { |         } else if ("function" === typeof next) { | ||||||
| 			next(); |             next(); | ||||||
| 		} else { |         } else { | ||||||
| 			res.statusCode = 500; |             res.statusCode = 500; | ||||||
| 			res.end("[500] Developer Error: app.use('/', greenlock.httpMiddleware()) or greenlock.httpMiddleware(app)"); |             res.end("[500] Developer Error: app.use('/', greenlock.httpMiddleware()) or greenlock.httpMiddleware(app)"); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function respondWithGrace(res, result, hostname, token) { | function respondWithGrace(res, result, hostname, token) { | ||||||
| 	var keyAuth = result && result.keyAuthorization; |     var keyAuth = result && result.keyAuthorization; | ||||||
| 	if (keyAuth && "string" === typeof keyAuth) { |     if (keyAuth && "string" === typeof keyAuth) { | ||||||
| 		res.setHeader("Content-Type", "text/plain; charset=utf-8"); |         res.setHeader("Content-Type", "text/plain; charset=utf-8"); | ||||||
| 		res.end(keyAuth); |         res.end(keyAuth); | ||||||
| 		return; |         return; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	res.statusCode = 404; |     res.statusCode = 404; | ||||||
| 	res.setHeader("Content-Type", "application/json; charset=utf-8"); |     res.setHeader("Content-Type", "application/json; charset=utf-8"); | ||||||
| 	res.end(JSON.stringify({ error: { message: "domain '" + hostname + "' has no token '" + token + "'." } })); |     res.end(JSON.stringify({ error: { message: "domain '" + hostname + "' has no token '" + token + "'." } })); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function explainError(gl, err, ctx, hostname) { | function explainError(gl, err, ctx, hostname) { | ||||||
| 	if (!err.servername) { |     if (!err.servername) { | ||||||
| 		err.servername = hostname; |         err.servername = hostname; | ||||||
| 	} |     } | ||||||
| 	if (!err.context) { |     if (!err.context) { | ||||||
| 		err.context = ctx; |         err.context = ctx; | ||||||
| 	} |     } | ||||||
| 	(gl.notify || gl._notify)("error", err); |     (gl.notify || gl._notify)("error", err); | ||||||
| 	return err; |     return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function respondToError(gl, res, err, ctx, hostname) { | function respondToError(gl, res, err, ctx, hostname) { | ||||||
| 	err = explainError(gl, err, ctx, hostname); |     err = explainError(gl, err, ctx, hostname); | ||||||
| 	res.statusCode = 500; |     res.statusCode = 500; | ||||||
| 	res.end("Internal Server Error: See logs for details."); |     res.end("Internal Server Error: See logs for details."); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| HttpMiddleware.getHostname = function(req) { | HttpMiddleware.getHostname = function(req) { | ||||||
| 	return req.hostname || req.headers["x-forwarded-host"] || (req.headers.host || ""); |     return req.hostname || req.headers["x-forwarded-host"] || (req.headers.host || ""); | ||||||
| }; | }; | ||||||
| HttpMiddleware.sanitizeHostname = function(req) { | HttpMiddleware.sanitizeHostname = function(req) { | ||||||
| 	// we can trust XFH because spoofing causes no ham in this limited use-case scenario
 |     // we can trust XFH because spoofing causes no ham in this limited use-case scenario
 | ||||||
| 	// (and only telebit would be legitimately setting XFH)
 |     // (and only telebit would be legitimately setting XFH)
 | ||||||
| 	var servername = HttpMiddleware.getHostname(req) |     var servername = HttpMiddleware.getHostname(req) | ||||||
| 		.toLowerCase() |         .toLowerCase() | ||||||
| 		.replace(/:.*/, ""); |         .replace(/:.*/, ""); | ||||||
| 	try { |     try { | ||||||
| 		req.hostname = servername; |         req.hostname = servername; | ||||||
| 	} catch (e) { |     } catch (e) { | ||||||
| 		// read-only express property
 |         // read-only express property
 | ||||||
| 	} |     } | ||||||
| 	if (req.headers["x-forwarded-host"]) { |     if (req.headers["x-forwarded-host"]) { | ||||||
| 		req.headers["x-forwarded-host"] = servername; |         req.headers["x-forwarded-host"] = servername; | ||||||
| 	} |     } | ||||||
| 	try { |     try { | ||||||
| 		req.headers.host = servername; |         req.headers.host = servername; | ||||||
| 	} catch (e) { |     } catch (e) { | ||||||
| 		// TODO is this a possible error?
 |         // TODO is this a possible error?
 | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	return (servernameRe.test(servername) && -1 === servername.indexOf("..") && servername) || ""; |     return (servernameRe.test(servername) && -1 === servername.indexOf("..") && servername) || ""; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -4,56 +4,56 @@ var SanitizeHost = module.exports; | |||||||
| var HttpMiddleware = require("./http-middleware.js"); | var HttpMiddleware = require("./http-middleware.js"); | ||||||
| 
 | 
 | ||||||
| SanitizeHost.create = function(gl, app) { | SanitizeHost.create = function(gl, app) { | ||||||
| 	return function(req, res, next) { |     return function(req, res, next) { | ||||||
| 		function realNext() { |         function realNext() { | ||||||
| 			if ("function" === typeof app) { |             if ("function" === typeof app) { | ||||||
| 				app(req, res); |                 app(req, res); | ||||||
| 			} else if ("function" === typeof next) { |             } else if ("function" === typeof next) { | ||||||
| 				next(); |                 next(); | ||||||
| 			} else { |             } else { | ||||||
| 				res.statusCode = 500; |                 res.statusCode = 500; | ||||||
| 				res.end("Error: no middleware assigned"); |                 res.end("Error: no middleware assigned"); | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		var hostname = HttpMiddleware.getHostname(req); |         var hostname = HttpMiddleware.getHostname(req); | ||||||
| 		// Replace the hostname, and get the safe version
 |         // Replace the hostname, and get the safe version
 | ||||||
| 		var safehost = HttpMiddleware.sanitizeHostname(req); |         var safehost = HttpMiddleware.sanitizeHostname(req); | ||||||
| 
 | 
 | ||||||
| 		// if no hostname, move along
 |         // if no hostname, move along
 | ||||||
| 		if (!hostname) { |         if (!hostname) { | ||||||
| 			realNext(); |             realNext(); | ||||||
| 			return; |             return; | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		// if there were unallowed characters, complain
 |         // if there were unallowed characters, complain
 | ||||||
| 		if (safehost.length !== hostname.length) { |         if (safehost.length !== hostname.length) { | ||||||
| 			res.statusCode = 400; |             res.statusCode = 400; | ||||||
| 			res.end("Malformed HTTP Header: 'Host: " + hostname + "'"); |             res.end("Malformed HTTP Header: 'Host: " + hostname + "'"); | ||||||
| 			return; |             return; | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		// Note: This sanitize function is also called on plain sockets, which don't need Domain Fronting checks
 |         // Note: This sanitize function is also called on plain sockets, which don't need Domain Fronting checks
 | ||||||
| 		if (req.socket.encrypted) { |         if (req.socket.encrypted) { | ||||||
| 			if (req.socket && "string" === typeof req.socket.servername) { |             if (req.socket && "string" === typeof req.socket.servername) { | ||||||
| 				// Workaround for https://github.com/nodejs/node/issues/22389
 |                 // Workaround for https://github.com/nodejs/node/issues/22389
 | ||||||
| 				if (!SanitizeHost._checkServername(safehost, req.socket)) { |                 if (!SanitizeHost._checkServername(safehost, req.socket)) { | ||||||
| 					res.statusCode = 400; |                     res.statusCode = 400; | ||||||
| 					res.setHeader("Content-Type", "text/html; charset=utf-8"); |                     res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||||
| 					res.end( |                     res.end( | ||||||
| 						"<h1>Domain Fronting Error</h1>" + |                         "<h1>Domain Fronting Error</h1>" + | ||||||
| 							"<p>This connection was secured using TLS/SSL for '" + |                             "<p>This connection was secured using TLS/SSL for '" + | ||||||
| 							(req.socket.servername || "").toLowerCase() + |                             (req.socket.servername || "").toLowerCase() + | ||||||
| 							"'</p>" + |                             "'</p>" + | ||||||
| 							"<p>The HTTP request specified 'Host: " + |                             "<p>The HTTP request specified 'Host: " + | ||||||
| 							safehost + |                             safehost + | ||||||
| 							"', which is (obviously) different.</p>" + |                             "', which is (obviously) different.</p>" + | ||||||
| 							"<p>Because this looks like a domain fronting attack, the connection has been terminated.</p>" |                             "<p>Because this looks like a domain fronting attack, the connection has been terminated.</p>" | ||||||
| 					); |                     ); | ||||||
| 					return; |                     return; | ||||||
| 				} |                 } | ||||||
| 			} |             } | ||||||
| 			/* |             /* | ||||||
|       else if (safehost && !gl._skip_fronting_check) { |       else if (safehost && !gl._skip_fronting_check) { | ||||||
| 
 | 
 | ||||||
| 				// We used to print a log message here, but it turns out that it's
 | 				// We used to print a log message here, but it turns out that it's
 | ||||||
| @ -66,74 +66,74 @@ SanitizeHost.create = function(gl, app) { | |||||||
| 				//gl._skip_fronting_check = true;
 | 				//gl._skip_fronting_check = true;
 | ||||||
| 			} | 			} | ||||||
|       */ |       */ | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		// carry on
 |         // carry on
 | ||||||
| 		realNext(); |         realNext(); | ||||||
| 	}; |     }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| var warnDomainFronting = true; | var warnDomainFronting = true; | ||||||
| var warnUnexpectedError = true; | var warnUnexpectedError = true; | ||||||
| SanitizeHost._checkServername = function(safeHost, tlsSocket) { | SanitizeHost._checkServername = function(safeHost, tlsSocket) { | ||||||
| 	var servername = (tlsSocket.servername || "").toLowerCase(); |     var servername = (tlsSocket.servername || "").toLowerCase(); | ||||||
| 
 | 
 | ||||||
| 	// acceptable: older IoT devices may lack SNI support
 |     // acceptable: older IoT devices may lack SNI support
 | ||||||
| 	if (!servername) { |     if (!servername) { | ||||||
| 		return true; |         return true; | ||||||
| 	} |     } | ||||||
| 	// acceptable: odd... but acceptable
 |     // acceptable: odd... but acceptable
 | ||||||
| 	if (!safeHost) { |     if (!safeHost) { | ||||||
| 		return true; |         return true; | ||||||
| 	} |     } | ||||||
| 	if (safeHost === servername) { |     if (safeHost === servername) { | ||||||
| 		return true; |         return true; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	if ("function" !== typeof tlsSocket.getCertificate) { |     if ("function" !== typeof tlsSocket.getCertificate) { | ||||||
| 		// domain fronting attacks allowed
 |         // domain fronting attacks allowed
 | ||||||
| 		if (warnDomainFronting) { |         if (warnDomainFronting) { | ||||||
| 			// https://github.com/nodejs/node/issues/24095
 |             // https://github.com/nodejs/node/issues/24095
 | ||||||
| 			console.warn( |             console.warn( | ||||||
| 				"Warning: node " + |                 "Warning: node " + | ||||||
| 					process.version + |                     process.version + | ||||||
| 					" is vulnerable to domain fronting attacks. Please use node v11.2.0 or greater." |                     " is vulnerable to domain fronting attacks. Please use node v11.2.0 or greater." | ||||||
| 			); |             ); | ||||||
| 			warnDomainFronting = false; |             warnDomainFronting = false; | ||||||
| 		} |         } | ||||||
| 		return true; |         return true; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	// connection established with servername and session is re-used for allowed name
 |     // connection established with servername and session is re-used for allowed name
 | ||||||
| 	// See https://github.com/nodejs/node/issues/24095
 |     // See https://github.com/nodejs/node/issues/24095
 | ||||||
| 	var cert = tlsSocket.getCertificate(); |     var cert = tlsSocket.getCertificate(); | ||||||
| 	try { |     try { | ||||||
| 		// TODO optimize / cache?
 |         // TODO optimize / cache?
 | ||||||
| 		// *should* always have a string, right?
 |         // *should* always have a string, right?
 | ||||||
| 		// *should* always be lowercase already, right?
 |         // *should* always be lowercase already, right?
 | ||||||
| 		//console.log(safeHost, cert.subject.CN, cert.subjectaltname);
 |         //console.log(safeHost, cert.subject.CN, cert.subjectaltname);
 | ||||||
| 		var isSubject = (cert.subject.CN || "").toLowerCase() === safeHost; |         var isSubject = (cert.subject.CN || "").toLowerCase() === safeHost; | ||||||
| 		if (isSubject) { |         if (isSubject) { | ||||||
| 			return true; |             return true; | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		var dnsnames = (cert.subjectaltname || "").split(/,\s+/); |         var dnsnames = (cert.subjectaltname || "").split(/,\s+/); | ||||||
| 		var inSanList = dnsnames.some(function(name) { |         var inSanList = dnsnames.some(function(name) { | ||||||
| 			// always prefixed with "DNS:"
 |             // always prefixed with "DNS:"
 | ||||||
| 			return safeHost === name.slice(4).toLowerCase(); |             return safeHost === name.slice(4).toLowerCase(); | ||||||
| 		}); |         }); | ||||||
| 
 | 
 | ||||||
| 		if (inSanList) { |         if (inSanList) { | ||||||
| 			return true; |             return true; | ||||||
| 		} |         } | ||||||
| 	} catch (e) { |     } catch (e) { | ||||||
| 		// not sure what else to do in this situation...
 |         // not sure what else to do in this situation...
 | ||||||
| 		if (warnUnexpectedError) { |         if (warnUnexpectedError) { | ||||||
| 			console.warn("Warning: encoutered error while performing domain fronting check: " + e.message); |             console.warn("Warning: encoutered error while performing domain fronting check: " + e.message); | ||||||
| 			warnUnexpectedError = false; |             warnUnexpectedError = false; | ||||||
| 		} |         } | ||||||
| 		return true; |         return true; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	return false; |     return false; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -1,37 +1,37 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| function requireBluebird() { | function requireBluebird() { | ||||||
| 	try { |     try { | ||||||
| 		return require("bluebird"); |         return require("bluebird"); | ||||||
| 	} catch (e) { |     } catch (e) { | ||||||
| 		console.error(""); |         console.error(""); | ||||||
| 		console.error("DON'T PANIC. You're running an old version of node with incomplete Promise support."); |         console.error("DON'T PANIC. You're running an old version of node with incomplete Promise support."); | ||||||
| 		console.error("EASY FIX: `npm install --save bluebird`"); |         console.error("EASY FIX: `npm install --save bluebird`"); | ||||||
| 		console.error(""); |         console.error(""); | ||||||
| 		throw e; |         throw e; | ||||||
| 	} |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| if ("undefined" === typeof Promise) { | if ("undefined" === typeof Promise) { | ||||||
| 	global.Promise = requireBluebird(); |     global.Promise = requireBluebird(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| if ("function" !== typeof require("util").promisify) { | if ("function" !== typeof require("util").promisify) { | ||||||
| 	require("util").promisify = requireBluebird().promisify; |     require("util").promisify = requireBluebird().promisify; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| if (!console.debug) { | if (!console.debug) { | ||||||
| 	console.debug = console.log; |     console.debug = console.log; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var fs = require("fs"); | var fs = require("fs"); | ||||||
| var fsAsync = {}; | var fsAsync = {}; | ||||||
| Object.keys(fs).forEach(function(key) { | Object.keys(fs).forEach(function(key) { | ||||||
| 	var fn = fs[key]; |     var fn = fs[key]; | ||||||
| 	if ("function" !== typeof fn || !/[a-z]/.test(key[0])) { |     if ("function" !== typeof fn || !/[a-z]/.test(key[0])) { | ||||||
| 		return; |         return; | ||||||
| 	} |     } | ||||||
| 	fsAsync[key] = require("util").promisify(fn); |     fsAsync[key] = require("util").promisify(fn); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| exports.fsAsync = fsAsync; | exports.fsAsync = fsAsync; | ||||||
|  | |||||||
							
								
								
									
										20
									
								
								main.js
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								main.js
									
									
									
									
									
								
							| @ -13,20 +13,20 @@ _hasSetSecureContext = !!require("https").createServer({}, function() {}).setSec | |||||||
| 
 | 
 | ||||||
| // TODO document in issues
 | // TODO document in issues
 | ||||||
| if (!_hasSetSecureContext) { | if (!_hasSetSecureContext) { | ||||||
| 	// TODO this isn't necessary if greenlock options are set with options.cert
 |     // TODO this isn't necessary if greenlock options are set with options.cert
 | ||||||
| 	console.warn("Warning: node " + process.version + " is missing tlsSocket.setSecureContext()."); |     console.warn("Warning: node " + process.version + " is missing tlsSocket.setSecureContext()."); | ||||||
| 	console.warn("         The default certificate may not be set."); |     console.warn("         The default certificate may not be set."); | ||||||
| 	shouldUpgrade = true; |     shouldUpgrade = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| if (major < 11 || (11 === major && minor < 2)) { | if (major < 11 || (11 === major && minor < 2)) { | ||||||
| 	// https://github.com/nodejs/node/issues/24095
 |     // https://github.com/nodejs/node/issues/24095
 | ||||||
| 	console.warn("Warning: node " + process.version + " is missing tlsSocket.getCertificate()."); |     console.warn("Warning: node " + process.version + " is missing tlsSocket.getCertificate()."); | ||||||
| 	console.warn("         This is necessary to guard against domain fronting attacks."); |     console.warn("         This is necessary to guard against domain fronting attacks."); | ||||||
| 	shouldUpgrade = true; |     shouldUpgrade = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| if (shouldUpgrade) { | if (shouldUpgrade) { | ||||||
| 	console.warn("Warning: Please upgrade to node v11.2.0 or greater."); |     console.warn("Warning: Please upgrade to node v11.2.0 or greater."); | ||||||
| 	console.warn(); |     console.warn(); | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										244
									
								
								master.js
									
									
									
									
									
								
							
							
						
						
									
										244
									
								
								master.js
									
									
									
									
									
								
							| @ -9,152 +9,152 @@ var os = require("os"); | |||||||
| var msgPrefix = "greenlock:"; | var msgPrefix = "greenlock:"; | ||||||
| 
 | 
 | ||||||
| Master.create = function(opts) { | Master.create = function(opts) { | ||||||
| 	var resolveCb; |     var resolveCb; | ||||||
| 	var _readyCb; |     var _readyCb; | ||||||
| 	var _kicked = false; |     var _kicked = false; | ||||||
| 
 | 
 | ||||||
| 	var greenlock = require("./greenlock.js").create(opts); |     var greenlock = require("./greenlock.js").create(opts); | ||||||
| 
 | 
 | ||||||
| 	var ready = new Promise(function(resolve) { |     var ready = new Promise(function(resolve) { | ||||||
| 		resolveCb = resolve; |         resolveCb = resolve; | ||||||
| 	}).then(function(fn) { |     }).then(function(fn) { | ||||||
| 		_readyCb = fn; |         _readyCb = fn; | ||||||
| 		return fn; |         return fn; | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	function kickoff() { |     function kickoff() { | ||||||
| 		if (_kicked) { |         if (_kicked) { | ||||||
| 			return; |             return; | ||||||
| 		} |         } | ||||||
| 		_kicked = true; |         _kicked = true; | ||||||
| 
 | 
 | ||||||
| 		Master._spawnWorkers(opts, greenlock); |         Master._spawnWorkers(opts, greenlock); | ||||||
| 
 | 
 | ||||||
| 		ready.then(function(fn) { |         ready.then(function(fn) { | ||||||
| 			// not sure what this API should be yet
 |             // not sure what this API should be yet
 | ||||||
| 			fn(); |             fn(); | ||||||
| 		}); |         }); | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	var master = { |     var master = { | ||||||
| 		serve: function() { |         serve: function() { | ||||||
| 			kickoff(); |             kickoff(); | ||||||
| 			return master; |             return master; | ||||||
| 		}, |         }, | ||||||
| 		master: function(fn) { |         master: function(fn) { | ||||||
| 			if (_readyCb) { |             if (_readyCb) { | ||||||
| 				throw new Error("can't call master twice"); |                 throw new Error("can't call master twice"); | ||||||
| 			} |             } | ||||||
| 			kickoff(); |             kickoff(); | ||||||
| 			resolveCb(fn); |             resolveCb(fn); | ||||||
| 			return master; |             return master; | ||||||
| 		} |         } | ||||||
| 	}; |     }; | ||||||
| 	return master; |     return master; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| function range(n) { | function range(n) { | ||||||
| 	n = parseInt(n, 10); |     n = parseInt(n, 10); | ||||||
| 	if (!n) { |     if (!n) { | ||||||
| 		return []; |         return []; | ||||||
| 	} |     } | ||||||
| 	return new Array(n).join(",").split(","); |     return new Array(n).join(",").split(","); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Master._spawnWorkers = function(opts, greenlock) { | Master._spawnWorkers = function(opts, greenlock) { | ||||||
| 	var numCpus = parseInt(process.env.NUMBER_OF_PROCESSORS, 10) || os.cpus().length; |     var numCpus = parseInt(process.env.NUMBER_OF_PROCESSORS, 10) || os.cpus().length; | ||||||
| 
 | 
 | ||||||
| 	// process rpc messages
 |     // process rpc messages
 | ||||||
| 	// start when dead
 |     // start when dead
 | ||||||
| 	var numWorkers = parseInt(opts.workers || opts.numWorkers, 10); |     var numWorkers = parseInt(opts.workers || opts.numWorkers, 10); | ||||||
| 	if (!numWorkers) { |     if (!numWorkers) { | ||||||
| 		if (numCpus <= 2) { |         if (numCpus <= 2) { | ||||||
| 			numWorkers = 2; |             numWorkers = 2; | ||||||
| 		} else { |         } else { | ||||||
| 			numWorkers = numCpus - 1; |             numWorkers = numCpus - 1; | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	cluster.once("exit", function() { |     cluster.once("exit", function() { | ||||||
| 		setTimeout(function() { |         setTimeout(function() { | ||||||
| 			process.exit(3); |             process.exit(3); | ||||||
| 		}, 100); |         }, 100); | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	var workers = range(numWorkers); |     var workers = range(numWorkers); | ||||||
| 	function next() { |     function next() { | ||||||
| 		if (!workers.length) { |         if (!workers.length) { | ||||||
| 			return; |             return; | ||||||
| 		} |         } | ||||||
| 		workers.pop(); |         workers.pop(); | ||||||
| 
 | 
 | ||||||
| 		// for a nice aesthetic
 |         // for a nice aesthetic
 | ||||||
| 		setTimeout(function() { |         setTimeout(function() { | ||||||
| 			Master._spawnWorker(opts, greenlock); |             Master._spawnWorker(opts, greenlock); | ||||||
| 			next(); |             next(); | ||||||
| 		}, 250); |         }, 250); | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	next(); |     next(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Master._spawnWorker = function(opts, greenlock) { | Master._spawnWorker = function(opts, greenlock) { | ||||||
| 	var w = cluster.fork(); |     var w = cluster.fork(); | ||||||
| 	// automatically added to master's `cluster.workers`
 |     // automatically added to master's `cluster.workers`
 | ||||||
| 	w.once("exit", function(code, signal) { |     w.once("exit", function(code, signal) { | ||||||
| 		// TODO handle failures
 |         // TODO handle failures
 | ||||||
| 		// Should test if the first starts successfully
 |         // Should test if the first starts successfully
 | ||||||
| 		// Should exit if failures happen too quickly
 |         // Should exit if failures happen too quickly
 | ||||||
| 
 | 
 | ||||||
| 		// For now just kill all when any die
 |         // For now just kill all when any die
 | ||||||
| 		if (signal) { |         if (signal) { | ||||||
| 			console.error("worker was killed by signal:", signal); |             console.error("worker was killed by signal:", signal); | ||||||
| 		} else if (code !== 0) { |         } else if (code !== 0) { | ||||||
| 			console.error("worker exited with error code:", code); |             console.error("worker exited with error code:", code); | ||||||
| 		} else { |         } else { | ||||||
| 			console.error("worker unexpectedly quit without exit code or signal"); |             console.error("worker unexpectedly quit without exit code or signal"); | ||||||
| 		} |         } | ||||||
| 		process.exit(2); |         process.exit(2); | ||||||
| 
 | 
 | ||||||
| 		//addWorker();
 |         //addWorker();
 | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	function handleMessage(msg) { |     function handleMessage(msg) { | ||||||
| 		if (0 !== (msg._id || "").indexOf(msgPrefix)) { |         if (0 !== (msg._id || "").indexOf(msgPrefix)) { | ||||||
| 			return; |             return; | ||||||
| 		} |         } | ||||||
| 		if ("string" !== typeof msg._funcname) { |         if ("string" !== typeof msg._funcname) { | ||||||
| 			// TODO developer error
 |             // TODO developer error
 | ||||||
| 			return; |             return; | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		function rpc() { |         function rpc() { | ||||||
| 			return greenlock[msg._funcname](msg._input) |             return greenlock[msg._funcname](msg._input) | ||||||
| 				.then(function(result) { |                 .then(function(result) { | ||||||
| 					w.send({ |                     w.send({ | ||||||
| 						_id: msg._id, |                         _id: msg._id, | ||||||
| 						_result: result |                         _result: result | ||||||
| 					}); |                     }); | ||||||
| 				}) |                 }) | ||||||
| 				.catch(function(e) { |                 .catch(function(e) { | ||||||
| 					var error = new Error(e.message); |                     var error = new Error(e.message); | ||||||
| 					Object.getOwnPropertyNames(e).forEach(function(k) { |                     Object.getOwnPropertyNames(e).forEach(function(k) { | ||||||
| 						error[k] = e[k]; |                         error[k] = e[k]; | ||||||
| 					}); |                     }); | ||||||
| 					w.send({ |                     w.send({ | ||||||
| 						_id: msg._id, |                         _id: msg._id, | ||||||
| 						_error: error |                         _error: error | ||||||
| 					}); |                     }); | ||||||
| 				}); |                 }); | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		try { |         try { | ||||||
| 			rpc(); |             rpc(); | ||||||
| 		} catch (e) { |         } catch (e) { | ||||||
| 			console.error("Unexpected and uncaught greenlock." + msg._funcname + " error:"); |             console.error("Unexpected and uncaught greenlock." + msg._funcname + " error:"); | ||||||
| 			console.error(e); |             console.error(e); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	w.on("message", handleMessage); |     w.on("message", handleMessage); | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										276
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										276
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -1,140 +1,140 @@ | |||||||
| { | { | ||||||
| 	"name": "@root/greenlock-express", |     "name": "@root/greenlock-express", | ||||||
| 	"version": "3.0.11", |     "version": "3.0.13", | ||||||
| 	"lockfileVersion": 1, |     "lockfileVersion": 1, | ||||||
| 	"requires": true, |     "requires": true, | ||||||
| 	"dependencies": { |     "dependencies": { | ||||||
| 		"@root/acme": { |         "@root/acme": { | ||||||
| 			"version": "3.0.8", |             "version": "3.0.8", | ||||||
| 			"resolved": "https://registry.npmjs.org/@root/acme/-/acme-3.0.8.tgz", |             "resolved": "https://registry.npmjs.org/@root/acme/-/acme-3.0.8.tgz", | ||||||
| 			"integrity": "sha512-VmBvLvWdCDkolkanI9Dzm1ouSWPaAa2eCCwcDZcVQbWoNiUIOqbbd57fcMA/gZxLyuJPStD2WXFuEuSMPDxcww==", |             "integrity": "sha512-VmBvLvWdCDkolkanI9Dzm1ouSWPaAa2eCCwcDZcVQbWoNiUIOqbbd57fcMA/gZxLyuJPStD2WXFuEuSMPDxcww==", | ||||||
| 			"requires": { |             "requires": { | ||||||
| 				"@root/encoding": "^1.0.1", |                 "@root/encoding": "^1.0.1", | ||||||
| 				"@root/keypairs": "^0.9.0", |                 "@root/keypairs": "^0.9.0", | ||||||
| 				"@root/pem": "^1.0.4", |                 "@root/pem": "^1.0.4", | ||||||
| 				"@root/request": "^1.3.11", |                 "@root/request": "^1.3.11", | ||||||
| 				"@root/x509": "^0.7.2" |                 "@root/x509": "^0.7.2" | ||||||
| 			} |             } | ||||||
| 		}, |         }, | ||||||
| 		"@root/asn1": { |         "@root/asn1": { | ||||||
| 			"version": "1.0.0", |             "version": "1.0.0", | ||||||
| 			"resolved": "https://registry.npmjs.org/@root/asn1/-/asn1-1.0.0.tgz", |             "resolved": "https://registry.npmjs.org/@root/asn1/-/asn1-1.0.0.tgz", | ||||||
| 			"integrity": "sha512-0lfZNuOULKJDJmdIkP8V9RnbV3XaK6PAHD3swnFy4tZwtlMDzLKoM/dfNad7ut8Hu3r91wy9uK0WA/9zym5mig==", |             "integrity": "sha512-0lfZNuOULKJDJmdIkP8V9RnbV3XaK6PAHD3swnFy4tZwtlMDzLKoM/dfNad7ut8Hu3r91wy9uK0WA/9zym5mig==", | ||||||
| 			"requires": { |             "requires": { | ||||||
| 				"@root/encoding": "^1.0.1" |                 "@root/encoding": "^1.0.1" | ||||||
| 			} |             } | ||||||
| 		}, |         }, | ||||||
| 		"@root/csr": { |         "@root/csr": { | ||||||
| 			"version": "0.8.1", |             "version": "0.8.1", | ||||||
| 			"resolved": "https://registry.npmjs.org/@root/csr/-/csr-0.8.1.tgz", |             "resolved": "https://registry.npmjs.org/@root/csr/-/csr-0.8.1.tgz", | ||||||
| 			"integrity": "sha512-hKl0VuE549TK6SnS2Yn9nRvKbFZXn/oAg+dZJU/tlKl/f/0yRXeuUzf8akg3JjtJq+9E592zDqeXZ7yyrg8fSQ==", |             "integrity": "sha512-hKl0VuE549TK6SnS2Yn9nRvKbFZXn/oAg+dZJU/tlKl/f/0yRXeuUzf8akg3JjtJq+9E592zDqeXZ7yyrg8fSQ==", | ||||||
| 			"requires": { |             "requires": { | ||||||
| 				"@root/asn1": "^1.0.0", |                 "@root/asn1": "^1.0.0", | ||||||
| 				"@root/pem": "^1.0.4", |                 "@root/pem": "^1.0.4", | ||||||
| 				"@root/x509": "^0.7.2" |                 "@root/x509": "^0.7.2" | ||||||
| 			} |             } | ||||||
| 		}, |         }, | ||||||
| 		"@root/encoding": { |         "@root/encoding": { | ||||||
| 			"version": "1.0.1", |             "version": "1.0.1", | ||||||
| 			"resolved": "https://registry.npmjs.org/@root/encoding/-/encoding-1.0.1.tgz", |             "resolved": "https://registry.npmjs.org/@root/encoding/-/encoding-1.0.1.tgz", | ||||||
| 			"integrity": "sha512-OaEub02ufoU038gy6bsNHQOjIn8nUjGiLcaRmJ40IUykneJkIW5fxDqKxQx48cszuNflYldsJLPPXCrGfHs8yQ==" |             "integrity": "sha512-OaEub02ufoU038gy6bsNHQOjIn8nUjGiLcaRmJ40IUykneJkIW5fxDqKxQx48cszuNflYldsJLPPXCrGfHs8yQ==" | ||||||
| 		}, |         }, | ||||||
| 		"@root/greenlock": { |         "@root/greenlock": { | ||||||
| 			"version": "3.0.25", |             "version": "3.0.25", | ||||||
| 			"resolved": "https://registry.npmjs.org/@root/greenlock/-/greenlock-3.0.25.tgz", |             "resolved": "https://registry.npmjs.org/@root/greenlock/-/greenlock-3.0.25.tgz", | ||||||
| 			"integrity": "sha512-VC8H9MTkbqxlB2LGntmcq5cstkE0TdZLvxm25SO5i7c6abJBVMQafhTD415OXwoGimnmWTn6SZ93Fj73d9QX/w==", |             "integrity": "sha512-VC8H9MTkbqxlB2LGntmcq5cstkE0TdZLvxm25SO5i7c6abJBVMQafhTD415OXwoGimnmWTn6SZ93Fj73d9QX/w==", | ||||||
| 			"requires": { |             "requires": { | ||||||
| 				"@root/acme": "^3.0.8", |                 "@root/acme": "^3.0.8", | ||||||
| 				"@root/csr": "^0.8.1", |                 "@root/csr": "^0.8.1", | ||||||
| 				"@root/keypairs": "^0.9.0", |                 "@root/keypairs": "^0.9.0", | ||||||
| 				"@root/mkdirp": "^1.0.0", |                 "@root/mkdirp": "^1.0.0", | ||||||
| 				"@root/request": "^1.3.10", |                 "@root/request": "^1.3.10", | ||||||
| 				"acme-http-01-standalone": "^3.0.5", |                 "acme-http-01-standalone": "^3.0.5", | ||||||
| 				"cert-info": "^1.5.1", |                 "cert-info": "^1.5.1", | ||||||
| 				"greenlock-manager-fs": "^3.0.1", |                 "greenlock-manager-fs": "^3.0.1", | ||||||
| 				"greenlock-store-fs": "^3.2.0", |                 "greenlock-store-fs": "^3.2.0", | ||||||
| 				"safe-replace": "^1.1.0" |                 "safe-replace": "^1.1.0" | ||||||
| 			} |             } | ||||||
| 		}, |         }, | ||||||
| 		"@root/keypairs": { |         "@root/keypairs": { | ||||||
| 			"version": "0.9.0", |             "version": "0.9.0", | ||||||
| 			"resolved": "https://registry.npmjs.org/@root/keypairs/-/keypairs-0.9.0.tgz", |             "resolved": "https://registry.npmjs.org/@root/keypairs/-/keypairs-0.9.0.tgz", | ||||||
| 			"integrity": "sha512-NXE2L9Gv7r3iC4kB/gTPZE1vO9Ox/p14zDzAJ5cGpTpytbWOlWF7QoHSJbtVX4H7mRG/Hp7HR3jWdWdb2xaaXg==", |             "integrity": "sha512-NXE2L9Gv7r3iC4kB/gTPZE1vO9Ox/p14zDzAJ5cGpTpytbWOlWF7QoHSJbtVX4H7mRG/Hp7HR3jWdWdb2xaaXg==", | ||||||
| 			"requires": { |             "requires": { | ||||||
| 				"@root/encoding": "^1.0.1", |                 "@root/encoding": "^1.0.1", | ||||||
| 				"@root/pem": "^1.0.4", |                 "@root/pem": "^1.0.4", | ||||||
| 				"@root/x509": "^0.7.2" |                 "@root/x509": "^0.7.2" | ||||||
| 			} |             } | ||||||
| 		}, |         }, | ||||||
| 		"@root/mkdirp": { |         "@root/mkdirp": { | ||||||
| 			"version": "1.0.0", |             "version": "1.0.0", | ||||||
| 			"resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz", |             "resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz", | ||||||
| 			"integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA==" |             "integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA==" | ||||||
| 		}, |         }, | ||||||
| 		"@root/pem": { |         "@root/pem": { | ||||||
| 			"version": "1.0.4", |             "version": "1.0.4", | ||||||
| 			"resolved": "https://registry.npmjs.org/@root/pem/-/pem-1.0.4.tgz", |             "resolved": "https://registry.npmjs.org/@root/pem/-/pem-1.0.4.tgz", | ||||||
| 			"integrity": "sha512-rEUDiUsHtild8GfIjFE9wXtcVxeS+ehCJQBwbQQ3IVfORKHK93CFnRtkr69R75lZFjcmKYVc+AXDB+AeRFOULA==" |             "integrity": "sha512-rEUDiUsHtild8GfIjFE9wXtcVxeS+ehCJQBwbQQ3IVfORKHK93CFnRtkr69R75lZFjcmKYVc+AXDB+AeRFOULA==" | ||||||
| 		}, |         }, | ||||||
| 		"@root/request": { |         "@root/request": { | ||||||
| 			"version": "1.4.2", |             "version": "1.4.2", | ||||||
| 			"resolved": "https://registry.npmjs.org/@root/request/-/request-1.4.2.tgz", |             "resolved": "https://registry.npmjs.org/@root/request/-/request-1.4.2.tgz", | ||||||
| 			"integrity": "sha512-J8FM4+SJuc7WRC+Jz17m+VT2lgI7HtatHhxN1F2ck5aIKUAxJEaR4u/gLBsgT60mVHevKCjKN0O8115UtJjwLw==" |             "integrity": "sha512-J8FM4+SJuc7WRC+Jz17m+VT2lgI7HtatHhxN1F2ck5aIKUAxJEaR4u/gLBsgT60mVHevKCjKN0O8115UtJjwLw==" | ||||||
| 		}, |         }, | ||||||
| 		"@root/x509": { |         "@root/x509": { | ||||||
| 			"version": "0.7.2", |             "version": "0.7.2", | ||||||
| 			"resolved": "https://registry.npmjs.org/@root/x509/-/x509-0.7.2.tgz", |             "resolved": "https://registry.npmjs.org/@root/x509/-/x509-0.7.2.tgz", | ||||||
| 			"integrity": "sha512-ENq3LGYORK5NiMFHEVeNMt+fTXaC7DTS6sQXoqV+dFdfT0vmiL5cDLjaXQhaklJQq0NiwicZegzJRl1ZOTp3WQ==", |             "integrity": "sha512-ENq3LGYORK5NiMFHEVeNMt+fTXaC7DTS6sQXoqV+dFdfT0vmiL5cDLjaXQhaklJQq0NiwicZegzJRl1ZOTp3WQ==", | ||||||
| 			"requires": { |             "requires": { | ||||||
| 				"@root/asn1": "^1.0.0", |                 "@root/asn1": "^1.0.0", | ||||||
| 				"@root/encoding": "^1.0.1" |                 "@root/encoding": "^1.0.1" | ||||||
| 			} |             } | ||||||
| 		}, |         }, | ||||||
| 		"acme-http-01-standalone": { |         "acme-http-01-standalone": { | ||||||
| 			"version": "3.0.5", |             "version": "3.0.5", | ||||||
| 			"resolved": "https://registry.npmjs.org/acme-http-01-standalone/-/acme-http-01-standalone-3.0.5.tgz", |             "resolved": "https://registry.npmjs.org/acme-http-01-standalone/-/acme-http-01-standalone-3.0.5.tgz", | ||||||
| 			"integrity": "sha512-W4GfK+39GZ+u0mvxRVUcVFCG6gposfzEnSBF20T/NUwWAKG59wQT1dUbS1NixRIAsRuhpGc4Jx659cErFQH0Pg==" |             "integrity": "sha512-W4GfK+39GZ+u0mvxRVUcVFCG6gposfzEnSBF20T/NUwWAKG59wQT1dUbS1NixRIAsRuhpGc4Jx659cErFQH0Pg==" | ||||||
| 		}, |         }, | ||||||
| 		"cert-info": { |         "cert-info": { | ||||||
| 			"version": "1.5.1", |             "version": "1.5.1", | ||||||
| 			"resolved": "https://registry.npmjs.org/cert-info/-/cert-info-1.5.1.tgz", |             "resolved": "https://registry.npmjs.org/cert-info/-/cert-info-1.5.1.tgz", | ||||||
| 			"integrity": "sha512-eoQC/yAgW3gKTKxjzyClvi+UzuY97YCjcl+lSqbsGIy7HeGaWxCPOQFivhUYm27hgsBMhsJJFya3kGvK6PMIcQ==" |             "integrity": "sha512-eoQC/yAgW3gKTKxjzyClvi+UzuY97YCjcl+lSqbsGIy7HeGaWxCPOQFivhUYm27hgsBMhsJJFya3kGvK6PMIcQ==" | ||||||
| 		}, |         }, | ||||||
| 		"escape-html": { |         "escape-html": { | ||||||
| 			"version": "1.0.3", |             "version": "1.0.3", | ||||||
| 			"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", |             "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", | ||||||
| 			"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" |             "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" | ||||||
| 		}, |         }, | ||||||
| 		"greenlock-manager-fs": { |         "greenlock-manager-fs": { | ||||||
| 			"version": "3.0.1", |             "version": "3.0.1", | ||||||
| 			"resolved": "https://registry.npmjs.org/greenlock-manager-fs/-/greenlock-manager-fs-3.0.1.tgz", |             "resolved": "https://registry.npmjs.org/greenlock-manager-fs/-/greenlock-manager-fs-3.0.1.tgz", | ||||||
| 			"integrity": "sha512-vZfGFq1TTKxaAqdGDUwNservrNzXx0xCwT/ovG/N378GrhS+U5S8B8LUlNtQU7Fdw6RToMiBcm22OOxSrvZ2zw==", |             "integrity": "sha512-vZfGFq1TTKxaAqdGDUwNservrNzXx0xCwT/ovG/N378GrhS+U5S8B8LUlNtQU7Fdw6RToMiBcm22OOxSrvZ2zw==", | ||||||
| 			"requires": { |             "requires": { | ||||||
| 				"@root/mkdirp": "^1.0.0", |                 "@root/mkdirp": "^1.0.0", | ||||||
| 				"safe-replace": "^1.1.0" |                 "safe-replace": "^1.1.0" | ||||||
| 			} |             } | ||||||
| 		}, |         }, | ||||||
| 		"greenlock-store-fs": { |         "greenlock-store-fs": { | ||||||
| 			"version": "3.2.0", |             "version": "3.2.0", | ||||||
| 			"resolved": "https://registry.npmjs.org/greenlock-store-fs/-/greenlock-store-fs-3.2.0.tgz", |             "resolved": "https://registry.npmjs.org/greenlock-store-fs/-/greenlock-store-fs-3.2.0.tgz", | ||||||
| 			"integrity": "sha512-zqcPnF+173oYq5qU7FoGtuqeG8dmmvAiSnz98kEHAHyvgRF9pE1T0MM0AuqDdj45I3kXlCj2gZBwutnRi37J3g==", |             "integrity": "sha512-zqcPnF+173oYq5qU7FoGtuqeG8dmmvAiSnz98kEHAHyvgRF9pE1T0MM0AuqDdj45I3kXlCj2gZBwutnRi37J3g==", | ||||||
| 			"requires": { |             "requires": { | ||||||
| 				"@root/mkdirp": "^1.0.0", |                 "@root/mkdirp": "^1.0.0", | ||||||
| 				"safe-replace": "^1.1.0" |                 "safe-replace": "^1.1.0" | ||||||
| 			} |             } | ||||||
| 		}, |         }, | ||||||
| 		"redirect-https": { |         "redirect-https": { | ||||||
| 			"version": "1.3.0", |             "version": "1.3.0", | ||||||
| 			"resolved": "https://registry.npmjs.org/redirect-https/-/redirect-https-1.3.0.tgz", |             "resolved": "https://registry.npmjs.org/redirect-https/-/redirect-https-1.3.0.tgz", | ||||||
| 			"integrity": "sha512-9GzwI/+Cqw3jlSg0CW6TgBQbhiVhkHSDvW8wjgRQ9IK34wtxS71YJiQeazSCSEqbvowHCJuQZgmQFl1xUHKEgg==", |             "integrity": "sha512-9GzwI/+Cqw3jlSg0CW6TgBQbhiVhkHSDvW8wjgRQ9IK34wtxS71YJiQeazSCSEqbvowHCJuQZgmQFl1xUHKEgg==", | ||||||
| 			"requires": { |             "requires": { | ||||||
| 				"escape-html": "^1.0.3" |                 "escape-html": "^1.0.3" | ||||||
| 			} |             } | ||||||
| 		}, |         }, | ||||||
| 		"safe-replace": { |         "safe-replace": { | ||||||
| 			"version": "1.1.0", |             "version": "1.1.0", | ||||||
| 			"resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz", |             "resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz", | ||||||
| 			"integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw==" |             "integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw==" | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										98
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										98
									
								
								package.json
									
									
									
									
									
								
							| @ -1,51 +1,51 @@ | |||||||
| { | { | ||||||
| 	"name": "@root/greenlock-express", |     "name": "@root/greenlock-express", | ||||||
| 	"version": "3.0.12", |     "version": "3.0.13", | ||||||
| 	"description": "Free SSL and managed or automatic HTTPS for node.js with Express, Koa, Connect, Hapi, and all other middleware systems.", |     "description": "Free SSL and managed or automatic HTTPS for node.js with Express, Koa, Connect, Hapi, and all other middleware systems.", | ||||||
| 	"main": "greenlock-express.js", |     "main": "greenlock-express.js", | ||||||
| 	"homepage": "https://greenlock.domains", |     "homepage": "https://greenlock.domains", | ||||||
| 	"files": [ |     "files": [ | ||||||
| 		"*.js", |         "*.js", | ||||||
| 		"lib", |         "lib", | ||||||
| 		"scripts" |         "scripts" | ||||||
| 	], |     ], | ||||||
| 	"scripts": { |     "scripts": { | ||||||
| 		"start": "node_todo server.js ./config.js", |         "start": "node_todo server.js ./config.js", | ||||||
| 		"test": "node_todo test/greenlock.js" |         "test": "node_todo test/greenlock.js" | ||||||
| 	}, |     }, | ||||||
| 	"directories": { |     "directories": { | ||||||
| 		"example": "examples" |         "example": "examples" | ||||||
| 	}, |     }, | ||||||
| 	"dependencies": { |     "dependencies": { | ||||||
| 		"@root/greenlock": "^3.0.25", |         "@root/greenlock": "^3.0.25", | ||||||
| 		"redirect-https": "^1.1.5" |         "redirect-https": "^1.1.5" | ||||||
| 	}, |     }, | ||||||
| 	"trulyOptionalDependencies": { |     "trulyOptionalDependencies": { | ||||||
| 		"http-proxy": "^1.17.0", |         "http-proxy": "^1.17.0", | ||||||
| 		"express": "^4.16.3", |         "express": "^4.16.3", | ||||||
| 		"express-basic-auth": "^1.2.0", |         "express-basic-auth": "^1.2.0", | ||||||
| 		"finalhandler": "^1.1.1", |         "finalhandler": "^1.1.1", | ||||||
| 		"serve-index": "^1.9.1", |         "serve-index": "^1.9.1", | ||||||
| 		"serve-static": "^1.13.2", |         "serve-static": "^1.13.2", | ||||||
| 		"ws": "^5.2.1" |         "ws": "^5.2.1" | ||||||
| 	}, |     }, | ||||||
| 	"devDependencies": {}, |     "devDependencies": {}, | ||||||
| 	"repository": { |     "repository": { | ||||||
| 		"type": "git", |         "type": "git", | ||||||
| 		"url": "https://git.rootprojects.org/root/greenlock-express.js.git" |         "url": "https://git.rootprojects.org/root/greenlock-express.js.git" | ||||||
| 	}, |     }, | ||||||
| 	"keywords": [ |     "keywords": [ | ||||||
| 		"Let's Encrypt", |         "Let's Encrypt", | ||||||
| 		"ACME", |         "ACME", | ||||||
| 		"greenlock", |         "greenlock", | ||||||
| 		"Free SSL", |         "Free SSL", | ||||||
| 		"Automated HTTPS", |         "Automated HTTPS", | ||||||
| 		"https", |         "https", | ||||||
| 		"tls" |         "tls" | ||||||
| 	], |     ], | ||||||
| 	"author": "AJ ONeal <coolaj86@gmail.com> (https://solderjs.com/)", |     "author": "AJ ONeal <coolaj86@gmail.com> (https://solderjs.com/)", | ||||||
| 	"license": "MPL-2.0", |     "license": "MPL-2.0", | ||||||
| 	"bugs": { |     "bugs": { | ||||||
| 		"url": "https://git.rootprojects.org/root/greenlock-express.js/issues" |         "url": "https://git.rootprojects.org/root/greenlock-express.js/issues" | ||||||
| 	} |     } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										236
									
								
								servers.js
									
									
									
									
									
								
							
							
						
						
									
										236
									
								
								servers.js
									
									
									
									
									
								
							| @ -9,148 +9,152 @@ var sni = require("./sni.js"); | |||||||
| var cluster = require("cluster"); | var cluster = require("cluster"); | ||||||
| 
 | 
 | ||||||
| Servers.create = function(greenlock) { | Servers.create = function(greenlock) { | ||||||
| 	var servers = {}; |     var servers = {}; | ||||||
| 	var _httpServer; |     var _httpServer; | ||||||
| 	var _httpsServer; |     var _httpsServer; | ||||||
| 
 | 
 | ||||||
| 	function startError(e) { |     function startError(e) { | ||||||
| 		explainError(e); |         explainError(e); | ||||||
| 		process.exit(1); |         process.exit(1); | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	servers.httpServer = function(defaultApp) { |     servers.httpServer = function(defaultApp) { | ||||||
| 		if (_httpServer) { |         if (_httpServer) { | ||||||
| 			return _httpServer; |             return _httpServer; | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		_httpServer = http.createServer(HttpMiddleware.create(greenlock, defaultApp)); |         _httpServer = http.createServer(HttpMiddleware.create(greenlock, defaultApp)); | ||||||
| 		_httpServer.once("error", startError); |         _httpServer.once("error", startError); | ||||||
| 
 | 
 | ||||||
| 		return _httpServer; |         return _httpServer; | ||||||
| 	}; |     }; | ||||||
| 
 | 
 | ||||||
| 	var _middlewareApp; |     var _middlewareApp; | ||||||
| 
 | 
 | ||||||
| 	servers.http2Server = function(secureOpts, defaultApp) { |     servers.http2Server = function(secureOpts, defaultApp) { | ||||||
| 		return servers._httpsServer(secureOpts, defaultApp, function(secureOpts, fn) { |         return servers._httpsServer(secureOpts, defaultApp, function(secureOpts, fn) { | ||||||
| 			secureOpts.allowHTTP1 = true; |             secureOpts.allowHTTP1 = true; | ||||||
| 			return require("http2").createSecureServer(secureOpts, fn); |             return require("http2").createSecureServer(secureOpts, fn); | ||||||
| 		}); |         }); | ||||||
| 	}; |     }; | ||||||
| 	servers.httpsServer = function(secureOpts, defaultApp) { |     servers.httpsServer = function(secureOpts, defaultApp) { | ||||||
| 		return servers._httpsServer(secureOpts, defaultApp, function(secureOpts, fn) { |         return servers._httpsServer(secureOpts, defaultApp, function(secureOpts, fn) { | ||||||
| 			return require("https").createServer(secureOpts, fn); |             return require("https").createServer(secureOpts, fn); | ||||||
| 		}); |         }); | ||||||
| 	}; |     }; | ||||||
| 	servers._httpsServer = function(secureOpts, defaultApp, createSecureServer) { |     servers._httpsServer = function(secureOpts, defaultApp, createSecureServer) { | ||||||
| 		if (defaultApp) { |         if (defaultApp) { | ||||||
| 			// TODO guard against being set twice?
 |             // TODO guard against being set twice?
 | ||||||
| 			_middlewareApp = defaultApp; |             _middlewareApp = defaultApp; | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		if (_httpsServer) { |         if (_httpsServer) { | ||||||
| 			if (secureOpts && Object.keys(secureOpts).length) { |             if (secureOpts && Object.keys(secureOpts).length) { | ||||||
| 				throw new Error("Call glx.httpsServer(tlsOptions) before calling glx.serveApp(app)"); |                 throw new Error("Call glx.httpsServer(tlsOptions) before calling glx.serveApp(app)"); | ||||||
| 			} |             } | ||||||
| 			return _httpsServer; |             return _httpsServer; | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		if (!secureOpts) { |         if (!secureOpts) { | ||||||
| 			secureOpts = {}; |             secureOpts = {}; | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		_httpsServer = createSecureServer( |         _httpsServer = createSecureServer( | ||||||
| 			wrapDefaultSniCallback(greenlock, secureOpts), |             wrapDefaultSniCallback(greenlock, secureOpts), | ||||||
| 			HttpsMiddleware.create(greenlock, function(req, res) { |             HttpsMiddleware.create(greenlock, function(req, res) { | ||||||
| 				if (!_middlewareApp) { |                 if (!_middlewareApp) { | ||||||
| 					throw new Error("Set app with `glx.serveApp(app)` or `glx.httpsServer(tlsOptions, app)`"); |                     throw new Error("Set app with `glx.serveApp(app)` or `glx.httpsServer(tlsOptions, app)`"); | ||||||
| 				} |                 } | ||||||
| 				_middlewareApp(req, res); |                 _middlewareApp(req, res); | ||||||
| 			}) |             }) | ||||||
| 		); |         ); | ||||||
| 		_httpsServer.once("error", startError); |         _httpsServer.once("error", startError); | ||||||
| 
 | 
 | ||||||
| 		return _httpsServer; |         return _httpsServer; | ||||||
| 	}; |     }; | ||||||
| 
 | 
 | ||||||
| 	servers.id = function() { |     servers.id = function() { | ||||||
| 		return (cluster.isWorker && cluster.worker.id) || "0"; |         return (cluster.isWorker && cluster.worker.id) || "0"; | ||||||
| 	}; |     }; | ||||||
| 	servers.serveApp = function(app) { |     servers.serveApp = function(app) { | ||||||
| 		return new Promise(function(resolve, reject) { |         return new Promise(function(resolve, reject) { | ||||||
| 			if ("function" !== typeof app) { |             if ("function" !== typeof app) { | ||||||
| 				reject(new Error("glx.serveApp(app) expects a node/express app in the format `function (req, res) { ... }`")); |                 reject( | ||||||
| 				return; |                     new Error( | ||||||
| 			} |                         "glx.serveApp(app) expects a node/express app in the format `function (req, res) { ... }`" | ||||||
|  |                     ) | ||||||
|  |                 ); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
| 			var id = cluster.isWorker && cluster.worker.id; |             var id = cluster.isWorker && cluster.worker.id; | ||||||
| 			var idstr = (id && "#" + id + " ") || ""; |             var idstr = (id && "#" + id + " ") || ""; | ||||||
| 			var plainServer = servers.httpServer(require("redirect-https")()); |             var plainServer = servers.httpServer(require("redirect-https")()); | ||||||
| 			var plainAddr = "0.0.0.0"; |             var plainAddr = "0.0.0.0"; | ||||||
| 			var plainPort = 80; |             var plainPort = 80; | ||||||
| 			plainServer.listen(plainPort, plainAddr, function() { |             plainServer.listen(plainPort, plainAddr, function() { | ||||||
| 				console.info( |                 console.info( | ||||||
| 					idstr + "Listening on", |                     idstr + "Listening on", | ||||||
| 					plainAddr + ":" + plainPort, |                     plainAddr + ":" + plainPort, | ||||||
| 					"for ACME challenges, and redirecting to HTTPS" |                     "for ACME challenges, and redirecting to HTTPS" | ||||||
| 				); |                 ); | ||||||
| 
 | 
 | ||||||
| 				// TODO fetch greenlock.servername
 |                 // TODO fetch greenlock.servername
 | ||||||
| 				_middlewareApp = app || _middlewareApp; |                 _middlewareApp = app || _middlewareApp; | ||||||
| 				var secureServer = servers.httpsServer(null, app); |                 var secureServer = servers.httpsServer(null, app); | ||||||
| 				var secureAddr = "0.0.0.0"; |                 var secureAddr = "0.0.0.0"; | ||||||
| 				var securePort = 443; |                 var securePort = 443; | ||||||
| 				secureServer.listen(securePort, secureAddr, function() { |                 secureServer.listen(securePort, secureAddr, function() { | ||||||
| 					console.info(idstr + "Listening on", secureAddr + ":" + securePort, "for secure traffic"); |                     console.info(idstr + "Listening on", secureAddr + ":" + securePort, "for secure traffic"); | ||||||
| 
 | 
 | ||||||
| 					plainServer.removeListener("error", startError); |                     plainServer.removeListener("error", startError); | ||||||
| 					secureServer.removeListener("error", startError); |                     secureServer.removeListener("error", startError); | ||||||
| 					resolve(); |                     resolve(); | ||||||
| 				}); |                 }); | ||||||
| 			}); |             }); | ||||||
| 		}); |         }); | ||||||
| 	}; |     }; | ||||||
| 
 | 
 | ||||||
| 	return servers; |     return servers; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| function explainError(e) { | function explainError(e) { | ||||||
| 	console.error(); |     console.error(); | ||||||
| 	console.error("Error: " + e.message); |     console.error("Error: " + e.message); | ||||||
| 	if ("EACCES" === e.errno) { |     if ("EACCES" === e.errno) { | ||||||
| 		console.error("You don't have prmission to access '" + e.address + ":" + e.port + "'."); |         console.error("You don't have prmission to access '" + e.address + ":" + e.port + "'."); | ||||||
| 		console.error('You probably need to use "sudo" or "sudo setcap \'cap_net_bind_service=+ep\' $(which node)"'); |         console.error('You probably need to use "sudo" or "sudo setcap \'cap_net_bind_service=+ep\' $(which node)"'); | ||||||
| 	} else if ("EADDRINUSE" === e.errno) { |     } else if ("EADDRINUSE" === e.errno) { | ||||||
| 		console.error("'" + e.address + ":" + e.port + "' is already being used by some other program."); |         console.error("'" + e.address + ":" + e.port + "' is already being used by some other program."); | ||||||
| 		console.error("You probably need to stop that program or restart your computer."); |         console.error("You probably need to stop that program or restart your computer."); | ||||||
| 	} else { |     } else { | ||||||
| 		console.error(e.code + ": '" + e.address + ":" + e.port + "'"); |         console.error(e.code + ": '" + e.address + ":" + e.port + "'"); | ||||||
| 	} |     } | ||||||
| 	console.error(); |     console.error(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function wrapDefaultSniCallback(greenlock, secureOpts) { | function wrapDefaultSniCallback(greenlock, secureOpts) { | ||||||
| 	// I'm not sure yet if the original SNICallback
 |     // I'm not sure yet if the original SNICallback
 | ||||||
| 	// should be called before or after, so I'm just
 |     // should be called before or after, so I'm just
 | ||||||
| 	// going to delay making that choice until I have the use case
 |     // going to delay making that choice until I have the use case
 | ||||||
| 	/* |     /* | ||||||
| 		if (!secureOpts.SNICallback) { | 		if (!secureOpts.SNICallback) { | ||||||
| 			secureOpts.SNICallback = function(servername, cb) { | 			secureOpts.SNICallback = function(servername, cb) { | ||||||
| 				cb(null, null); | 				cb(null, null); | ||||||
| 			}; | 			}; | ||||||
| 		} | 		} | ||||||
|   */ |   */ | ||||||
| 	if (secureOpts.SNICallback) { |     if (secureOpts.SNICallback) { | ||||||
| 		console.warn(); |         console.warn(); | ||||||
| 		console.warn("[warning] Ignoring the given tlsOptions.SNICallback function."); |         console.warn("[warning] Ignoring the given tlsOptions.SNICallback function."); | ||||||
| 		console.warn(); |         console.warn(); | ||||||
| 		console.warn("          We're very open to implementing support for this,"); |         console.warn("          We're very open to implementing support for this,"); | ||||||
| 		console.warn("          we just don't understand the use case yet."); |         console.warn("          we just don't understand the use case yet."); | ||||||
| 		console.warn("          Please open an issue to discuss. We'd love to help."); |         console.warn("          Please open an issue to discuss. We'd love to help."); | ||||||
| 		console.warn(); |         console.warn(); | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	// TODO greenlock.servername for workers
 |     // TODO greenlock.servername for workers
 | ||||||
| 	secureOpts.SNICallback = sni.create(greenlock, secureOpts); |     secureOpts.SNICallback = sni.create(greenlock, secureOpts); | ||||||
| 	return secureOpts; |     return secureOpts; | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										28
									
								
								single.js
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								single.js
									
									
									
									
									
								
							| @ -6,20 +6,20 @@ var Single = module.exports; | |||||||
| var Servers = require("./servers.js"); | var Servers = require("./servers.js"); | ||||||
| 
 | 
 | ||||||
| Single.create = function(opts) { | Single.create = function(opts) { | ||||||
| 	var greenlock = require("./greenlock.js").create(opts); |     var greenlock = require("./greenlock.js").create(opts); | ||||||
| 
 | 
 | ||||||
| 	var servers = Servers.create(greenlock); |     var servers = Servers.create(greenlock); | ||||||
| 
 | 
 | ||||||
| 	var single = { |     var single = { | ||||||
| 		serve: function(fn) { |         serve: function(fn) { | ||||||
| 			fn(servers); |             fn(servers); | ||||||
| 			return single; |             return single; | ||||||
| 		}, |         }, | ||||||
| 		master: function(/*fn*/) { |         master: function(/*fn*/) { | ||||||
| 			// ignore
 |             // ignore
 | ||||||
| 			//fn(master);
 |             //fn(master);
 | ||||||
| 			return single; |             return single; | ||||||
| 		} |         } | ||||||
| 	}; |     }; | ||||||
| 	return single; |     return single; | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										296
									
								
								sni.js
									
									
									
									
									
								
							
							
						
						
									
										296
									
								
								sni.js
									
									
									
									
									
								
							| @ -13,182 +13,182 @@ var smallStagger = Math.round(Math.PI * (30 * 1000)); | |||||||
| 
 | 
 | ||||||
| //secureOpts.SNICallback = sni.create(greenlock, secureOpts);
 | //secureOpts.SNICallback = sni.create(greenlock, secureOpts);
 | ||||||
| sni.create = function(greenlock, secureOpts) { | sni.create = function(greenlock, secureOpts) { | ||||||
| 	var _cache = {}; |     var _cache = {}; | ||||||
| 	var defaultServername = greenlock.servername || ""; |     var defaultServername = greenlock.servername || ""; | ||||||
| 
 | 
 | ||||||
| 	if (secureOpts.cert) { |     if (secureOpts.cert) { | ||||||
| 		// Note: it's fine if greenlock.servername is undefined,
 |         // Note: it's fine if greenlock.servername is undefined,
 | ||||||
| 		// but if the caller wants this to auto-renew, they should define it
 |         // but if the caller wants this to auto-renew, they should define it
 | ||||||
| 		_cache[defaultServername] = { |         _cache[defaultServername] = { | ||||||
| 			refreshAt: 0, |             refreshAt: 0, | ||||||
| 			secureContext: tls.createSecureContext(secureOpts) |             secureContext: tls.createSecureContext(secureOpts) | ||||||
| 		}; |         }; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	return getSecureContext; |     return getSecureContext; | ||||||
| 
 | 
 | ||||||
| 	function notify(ev, args) { |     function notify(ev, args) { | ||||||
| 		try { |         try { | ||||||
| 			// TODO _notify() or notify()?
 |             // TODO _notify() or notify()?
 | ||||||
| 			(greenlock.notify || greenlock._notify)(ev, args); |             (greenlock.notify || greenlock._notify)(ev, args); | ||||||
| 		} catch (e) { |         } catch (e) { | ||||||
| 			console.error(e); |             console.error(e); | ||||||
| 			console.error(ev, args); |             console.error(ev, args); | ||||||
| 		} |         } | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	function getSecureContext(servername, cb) { |     function getSecureContext(servername, cb) { | ||||||
| 		//console.log("debug sni", servername);
 |         //console.log("debug sni", servername);
 | ||||||
| 		if ("string" !== typeof servername) { |         if ("string" !== typeof servername) { | ||||||
| 			// this will never happen... right? but stranger things have...
 |             // this will never happen... right? but stranger things have...
 | ||||||
| 			console.error("[sanity fail] non-string servername:", servername); |             console.error("[sanity fail] non-string servername:", servername); | ||||||
| 			cb(new Error("invalid servername"), null); |             cb(new Error("invalid servername"), null); | ||||||
| 			return; |             return; | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		var secureContext = getCachedContext(servername); |         var secureContext = getCachedContext(servername); | ||||||
| 		if (secureContext) { |         if (secureContext) { | ||||||
| 			//console.log("debug sni got cached context", servername, getCachedMeta(servername));
 |             //console.log("debug sni got cached context", servername, getCachedMeta(servername));
 | ||||||
| 			cb(null, secureContext); |             cb(null, secureContext); | ||||||
| 			return; |             return; | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		getFreshContext(servername) |         getFreshContext(servername) | ||||||
| 			.then(function(secureContext) { |             .then(function(secureContext) { | ||||||
| 				if (secureContext) { |                 if (secureContext) { | ||||||
| 					//console.log("debug sni got fresh context", servername, getCachedMeta(servername));
 |                     //console.log("debug sni got fresh context", servername, getCachedMeta(servername));
 | ||||||
| 					cb(null, secureContext); |                     cb(null, secureContext); | ||||||
| 					return; |                     return; | ||||||
| 				} |                 } | ||||||
| 				// Note: this does not replace tlsSocket.setSecureContext()
 |                 // Note: this does not replace tlsSocket.setSecureContext()
 | ||||||
| 				// as it only works when SNI has been sent
 |                 // as it only works when SNI has been sent
 | ||||||
| 				//console.log("debug sni got default context", servername, getCachedMeta(servername));
 |                 //console.log("debug sni got default context", servername, getCachedMeta(servername));
 | ||||||
| 				cb(null, getDefaultContext()); |                 cb(null, getDefaultContext()); | ||||||
| 			}) |             }) | ||||||
| 			.catch(function(err) { |             .catch(function(err) { | ||||||
| 				if (!err.context) { |                 if (!err.context) { | ||||||
| 					err.context = "sni_callback"; |                     err.context = "sni_callback"; | ||||||
| 				} |                 } | ||||||
| 				notify("error", err); |                 notify("error", err); | ||||||
| 				//console.log("debug sni error", servername, err);
 |                 //console.log("debug sni error", servername, err);
 | ||||||
| 				cb(err); |                 cb(err); | ||||||
| 			}); |             }); | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	function getCachedMeta(servername) { |     function getCachedMeta(servername) { | ||||||
| 		var meta = _cache[servername]; |         var meta = _cache[servername]; | ||||||
| 		if (!meta) { |         if (!meta) { | ||||||
| 			if (!_cache[wildname(servername)]) { |             if (!_cache[wildname(servername)]) { | ||||||
| 				return null; |                 return null; | ||||||
| 			} |             } | ||||||
| 		} |         } | ||||||
| 		return meta; |         return meta; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	function getCachedContext(servername) { |     function getCachedContext(servername) { | ||||||
| 		var meta = getCachedMeta(servername); |         var meta = getCachedMeta(servername); | ||||||
| 		if (!meta) { |         if (!meta) { | ||||||
| 			return null; |             return null; | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		// always renew in background
 |         // always renew in background
 | ||||||
| 		if (!meta.refreshAt || Date.now() >= meta.refreshAt) { |         if (!meta.refreshAt || Date.now() >= meta.refreshAt) { | ||||||
| 			getFreshContext(servername).catch(function(e) { |             getFreshContext(servername).catch(function(e) { | ||||||
| 				if (!e.context) { |                 if (!e.context) { | ||||||
| 					e.context = "sni_background_refresh"; |                     e.context = "sni_background_refresh"; | ||||||
| 				} |                 } | ||||||
| 				notify("error", e); |                 notify("error", e); | ||||||
| 			}); |             }); | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		// under normal circumstances this would never be expired
 |         // under normal circumstances this would never be expired
 | ||||||
| 		// and, if it is expired, something is so wrong it's probably
 |         // and, if it is expired, something is so wrong it's probably
 | ||||||
| 		// not worth wating for the renewal - it has probably failed
 |         // not worth wating for the renewal - it has probably failed
 | ||||||
| 		return meta.secureContext; |         return meta.secureContext; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	function getFreshContext(servername) { |     function getFreshContext(servername) { | ||||||
| 		var meta = getCachedMeta(servername); |         var meta = getCachedMeta(servername); | ||||||
| 		if (!meta && !validServername(servername)) { |         if (!meta && !validServername(servername)) { | ||||||
| 			return Promise.resolve(null); |             return Promise.resolve(null); | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		if (meta) { |         if (meta) { | ||||||
| 			// prevent stampedes
 |             // prevent stampedes
 | ||||||
| 			meta.refreshAt = Date.now() + randomRefreshOffset(); |             meta.refreshAt = Date.now() + randomRefreshOffset(); | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		// TODO don't get unknown certs at all, rely on auto-updates from greenlock
 |         // TODO don't get unknown certs at all, rely on auto-updates from greenlock
 | ||||||
| 		// Note: greenlock.get() will return an existing fresh cert or issue a new one
 |         // Note: greenlock.get() will return an existing fresh cert or issue a new one
 | ||||||
| 		return greenlock.get({ servername: servername }).then(function(result) { |         return greenlock.get({ servername: servername }).then(function(result) { | ||||||
| 			var meta = getCachedMeta(servername); |             var meta = getCachedMeta(servername); | ||||||
| 			if (!meta) { |             if (!meta) { | ||||||
| 				meta = _cache[servername] = { secureContext: { _valid: false } }; |                 meta = _cache[servername] = { secureContext: { _valid: false } }; | ||||||
| 			} |             } | ||||||
| 			// prevent from being punked by bot trolls
 |             // prevent from being punked by bot trolls
 | ||||||
| 			meta.refreshAt = Date.now() + smallStagger; |             meta.refreshAt = Date.now() + smallStagger; | ||||||
| 
 | 
 | ||||||
| 			// nothing to do
 |             // nothing to do
 | ||||||
| 			if (!result) { |             if (!result) { | ||||||
| 				return null; |                 return null; | ||||||
| 			} |             } | ||||||
| 
 | 
 | ||||||
| 			// we only care about the first one
 |             // we only care about the first one
 | ||||||
| 			var pems = result.pems; |             var pems = result.pems; | ||||||
| 			var site = result.site; |             var site = result.site; | ||||||
| 			if (!pems || !pems.cert) { |             if (!pems || !pems.cert) { | ||||||
| 				// nothing to do
 |                 // nothing to do
 | ||||||
| 				// (and the error should have been reported already)
 |                 // (and the error should have been reported already)
 | ||||||
| 				return null; |                 return null; | ||||||
| 			} |             } | ||||||
| 
 | 
 | ||||||
| 			meta = { |             meta = { | ||||||
| 				refreshAt: Date.now() + randomRefreshOffset(), |                 refreshAt: Date.now() + randomRefreshOffset(), | ||||||
| 				secureContext: tls.createSecureContext({ |                 secureContext: tls.createSecureContext({ | ||||||
| 					// TODO support passphrase-protected privkeys
 |                     // TODO support passphrase-protected privkeys
 | ||||||
| 					key: pems.privkey, |                     key: pems.privkey, | ||||||
| 					cert: pems.cert + "\n" + pems.chain + "\n" |                     cert: pems.cert + "\n" + pems.chain + "\n" | ||||||
| 				}) |                 }) | ||||||
| 			}; |             }; | ||||||
| 			meta.secureContext._valid = true; |             meta.secureContext._valid = true; | ||||||
| 
 | 
 | ||||||
| 			// copy this same object into every place
 |             // copy this same object into every place
 | ||||||
| 			(result.altnames || site.altnames || [result.subject || site.subject]).forEach(function(altname) { |             (result.altnames || site.altnames || [result.subject || site.subject]).forEach(function(altname) { | ||||||
| 				_cache[altname] = meta; |                 _cache[altname] = meta; | ||||||
| 			}); |             }); | ||||||
| 
 | 
 | ||||||
| 			return meta.secureContext; |             return meta.secureContext; | ||||||
| 		}); |         }); | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 	function getDefaultContext() { |     function getDefaultContext() { | ||||||
| 		return getCachedContext(defaultServername); |         return getCachedContext(defaultServername); | ||||||
| 	} |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // whenever we need to know when to refresh next
 | // whenever we need to know when to refresh next
 | ||||||
| function randomRefreshOffset() { | function randomRefreshOffset() { | ||||||
| 	var stagger = Math.round(refreshStagger / 2) - Math.round(Math.random() * refreshStagger); |     var stagger = Math.round(refreshStagger / 2) - Math.round(Math.random() * refreshStagger); | ||||||
| 	return refreshOffset + stagger; |     return refreshOffset + stagger; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function validServername(servername) { | function validServername(servername) { | ||||||
| 	// format and (lightly) sanitize sni so that users can be naive
 |     // format and (lightly) sanitize sni so that users can be naive
 | ||||||
| 	// and not have to worry about SQL injection or fs discovery
 |     // and not have to worry about SQL injection or fs discovery
 | ||||||
| 
 | 
 | ||||||
| 	servername = (servername || "").toLowerCase(); |     servername = (servername || "").toLowerCase(); | ||||||
| 	// hostname labels allow a-z, 0-9, -, and are separated by dots
 |     // hostname labels allow a-z, 0-9, -, and are separated by dots
 | ||||||
| 	// _ is sometimes allowed, but not as a "hostname", and not by Let's Encrypt ACME
 |     // _ is sometimes allowed, but not as a "hostname", and not by Let's Encrypt ACME
 | ||||||
| 	// REGEX // https://www.codeproject.com/Questions/1063023/alphanumeric-validation-javascript-without-regex
 |     // REGEX // https://www.codeproject.com/Questions/1063023/alphanumeric-validation-javascript-without-regex
 | ||||||
| 	return servernameRe.test(servername) && -1 === servername.indexOf(".."); |     return servernameRe.test(servername) && -1 === servername.indexOf(".."); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function wildname(servername) { | function wildname(servername) { | ||||||
| 	return ( |     return ( | ||||||
| 		"*." + |         "*." + | ||||||
| 		servername |         servername | ||||||
| 			.split(".") |             .split(".") | ||||||
| 			.slice(1) |             .slice(1) | ||||||
| 			.join(".") |             .join(".") | ||||||
| 	); |     ); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,83 +1,83 @@ | |||||||
| #!/usr/bin/env node
 | #!/usr/bin/env node
 | ||||||
| var Greenlock = require("../"); | var Greenlock = require("../"); | ||||||
| var greenlock = Greenlock.create({ | var greenlock = Greenlock.create({ | ||||||
| 	version: "draft-11", |     version: "draft-11", | ||||||
| 	server: "https://acme-staging-v02.api.letsencrypt.org/directory", |     server: "https://acme-staging-v02.api.letsencrypt.org/directory", | ||||||
| 	agreeTos: true, |     agreeTos: true, | ||||||
| 	approvedDomains: ["example.com", "www.example.com"], |     approvedDomains: ["example.com", "www.example.com"], | ||||||
| 	configDir: require("path").join(require("os").tmpdir(), "acme"), |     configDir: require("path").join(require("os").tmpdir(), "acme"), | ||||||
| 
 | 
 | ||||||
| 	app: require("express")().use("/", function(req, res) { |     app: require("express")().use("/", function(req, res) { | ||||||
| 		res.setHeader("Content-Type", "text/html; charset=utf-8"); |         res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||||
| 		res.end("Hello, World!\n\n💚 🔒.js"); |         res.end("Hello, World!\n\n💚 🔒.js"); | ||||||
| 	}) |     }) | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| var server1 = greenlock.listen(5080, 5443); | var server1 = greenlock.listen(5080, 5443); | ||||||
| server1.on("listening", function() { | server1.on("listening", function() { | ||||||
| 	console.log("### THREE 3333 - All is well server1", this.address()); |     console.log("### THREE 3333 - All is well server1", this.address()); | ||||||
| 	setTimeout(function() { |     setTimeout(function() { | ||||||
| 		// so that the address() object doesn't disappear
 |         // so that the address() object doesn't disappear
 | ||||||
| 		server1.close(); |         server1.close(); | ||||||
| 		server1.unencrypted.close(); |         server1.unencrypted.close(); | ||||||
| 	}, 10); |     }, 10); | ||||||
| }); | }); | ||||||
| setTimeout(function() { | setTimeout(function() { | ||||||
| 	var server2 = greenlock.listen(6080, 6443, function() { |     var server2 = greenlock.listen(6080, 6443, function() { | ||||||
| 		console.log("### FIVE 55555 - Started server 2!"); |         console.log("### FIVE 55555 - Started server 2!"); | ||||||
| 		setTimeout(function() { |         setTimeout(function() { | ||||||
| 			server2.close(); |             server2.close(); | ||||||
| 			server2.unencrypted.close(); |             server2.unencrypted.close(); | ||||||
| 			server6.close(); |             server6.close(); | ||||||
| 			server6.unencrypted.close(); |             server6.unencrypted.close(); | ||||||
| 			server7.close(); |             server7.close(); | ||||||
| 			server7.unencrypted.close(); |             server7.unencrypted.close(); | ||||||
| 			setTimeout(function() { |             setTimeout(function() { | ||||||
| 				// TODO greenlock needs a close event (and to listen to its server's close event)
 |                 // TODO greenlock needs a close event (and to listen to its server's close event)
 | ||||||
| 				process.exit(0); |                 process.exit(0); | ||||||
| 			}, 1000); |             }, 1000); | ||||||
| 		}, 1000); |         }, 1000); | ||||||
| 	}); |     }); | ||||||
| 	server2.on("listening", function() { |     server2.on("listening", function() { | ||||||
| 		console.log("### FOUR 44444 - All is well server2", server2.address()); |         console.log("### FOUR 44444 - All is well server2", server2.address()); | ||||||
| 	}); |     }); | ||||||
| }, 1000); | }, 1000); | ||||||
| 
 | 
 | ||||||
| var server3 = greenlock.listen( | var server3 = greenlock.listen( | ||||||
| 	22, |     22, | ||||||
| 	22, |     22, | ||||||
| 	function() { |     function() { | ||||||
| 		console.error("Error: expected to get an error when launching plain server on port 22"); |         console.error("Error: expected to get an error when launching plain server on port 22"); | ||||||
| 	}, |     }, | ||||||
| 	function() { |     function() { | ||||||
| 		console.error("Error: expected to get an error when launching " + server3.type + " server on port 22"); |         console.error("Error: expected to get an error when launching " + server3.type + " server on port 22"); | ||||||
| 	} |     } | ||||||
| ); | ); | ||||||
| server3.unencrypted.on("error", function() { | server3.unencrypted.on("error", function() { | ||||||
| 	console.log("Success: caught expected (plain) error"); |     console.log("Success: caught expected (plain) error"); | ||||||
| }); | }); | ||||||
| server3.on("error", function() { | server3.on("error", function() { | ||||||
| 	console.log("Success: caught expected " + server3.type + " error"); |     console.log("Success: caught expected " + server3.type + " error"); | ||||||
| 	//server3.close();
 |     //server3.close();
 | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| var server4 = greenlock.listen( | var server4 = greenlock.listen( | ||||||
| 	7080, |     7080, | ||||||
| 	7443, |     7443, | ||||||
| 	function() { |     function() { | ||||||
| 		console.log("Success: server4: plain"); |         console.log("Success: server4: plain"); | ||||||
| 		server4.unencrypted.close(); |         server4.unencrypted.close(); | ||||||
| 	}, |     }, | ||||||
| 	function() { |     function() { | ||||||
| 		console.log("Success: server4: " + server4.type); |         console.log("Success: server4: " + server4.type); | ||||||
| 		server4.close(); |         server4.close(); | ||||||
| 	} |     } | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| var server5 = greenlock.listen(10080, 10443, function() { | var server5 = greenlock.listen(10080, 10443, function() { | ||||||
| 	console.log("Server 5 with one fn", this.address()); |     console.log("Server 5 with one fn", this.address()); | ||||||
| 	server5.close(); |     server5.close(); | ||||||
| 	server5.unencrypted.close(); |     server5.unencrypted.close(); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| var server6 = greenlock.listen("[::]:11080", "[::1]:11443"); | var server6 = greenlock.listen("[::]:11080", "[::1]:11443"); | ||||||
|  | |||||||
							
								
								
									
										92
									
								
								worker.js
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								worker.js
									
									
									
									
									
								
							| @ -6,57 +6,57 @@ var messageTimeout = 30 * 1000; | |||||||
| var msgPrefix = "greenlock:"; | var msgPrefix = "greenlock:"; | ||||||
| 
 | 
 | ||||||
| Worker.create = function() { | Worker.create = function() { | ||||||
| 	var greenlock = {}; |     var greenlock = {}; | ||||||
| 	["getAcmeHttp01ChallengeResponse", "get", "notify"].forEach(function(k) { |     ["getAcmeHttp01ChallengeResponse", "get", "notify"].forEach(function(k) { | ||||||
| 		greenlock[k] = function(args) { |         greenlock[k] = function(args) { | ||||||
| 			return rpc(k, args); |             return rpc(k, args); | ||||||
| 		}; |         }; | ||||||
| 	}); |     }); | ||||||
| 
 | 
 | ||||||
| 	var worker = { |     var worker = { | ||||||
| 		serve: function(fn) { |         serve: function(fn) { | ||||||
| 			var servers = require("./servers.js").create(greenlock); |             var servers = require("./servers.js").create(greenlock); | ||||||
| 			fn(servers); |             fn(servers); | ||||||
| 			return worker; |             return worker; | ||||||
| 		}, |         }, | ||||||
| 		master: function() { |         master: function() { | ||||||
| 			// ignore
 |             // ignore
 | ||||||
| 			return worker; |             return worker; | ||||||
| 		} |         } | ||||||
| 	}; |     }; | ||||||
| 	return worker; |     return worker; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| function rpc(funcname, msg) { | function rpc(funcname, msg) { | ||||||
| 	return new Promise(function(resolve, reject) { |     return new Promise(function(resolve, reject) { | ||||||
| 		var rnd = Math.random() |         var rnd = Math.random() | ||||||
| 			.toString() |             .toString() | ||||||
| 			.slice(2) |             .slice(2) | ||||||
| 			.toString(16); |             .toString(16); | ||||||
| 		var id = msgPrefix + rnd; |         var id = msgPrefix + rnd; | ||||||
| 		var timeout; |         var timeout; | ||||||
| 
 | 
 | ||||||
| 		function getResponse(msg) { |         function getResponse(msg) { | ||||||
| 			if (msg._id !== id) { |             if (msg._id !== id) { | ||||||
| 				return; |                 return; | ||||||
| 			} |             } | ||||||
| 			process.removeListener("message", getResponse); |             process.removeListener("message", getResponse); | ||||||
| 			clearTimeout(timeout); |             clearTimeout(timeout); | ||||||
| 			resolve(msg._result); |             resolve(msg._result); | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 		// TODO keep a single listener than just responds
 |         // TODO keep a single listener than just responds
 | ||||||
| 		// via a collection of callbacks? or leave as is?
 |         // via a collection of callbacks? or leave as is?
 | ||||||
| 		process.on("message", getResponse); |         process.on("message", getResponse); | ||||||
| 		process.send({ |         process.send({ | ||||||
| 			_id: id, |             _id: id, | ||||||
| 			_funcname: funcname, |             _funcname: funcname, | ||||||
| 			_input: msg |             _input: msg | ||||||
| 		}); |         }); | ||||||
| 
 | 
 | ||||||
| 		timeout = setTimeout(function() { |         timeout = setTimeout(function() { | ||||||
| 			process.removeListener("message", getResponse); |             process.removeListener("message", getResponse); | ||||||
| 			reject(new Error("worker rpc request timeout")); |             reject(new Error("worker rpc request timeout")); | ||||||
| 		}, messageTimeout); |         }, messageTimeout); | ||||||
| 	}); |     }); | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user