whitespace
This commit is contained in:
		
							parent
							
								
									b80537f07b
								
							
						
					
					
						commit
						61fb942dda
					
				| @ -1,7 +1,7 @@ | ||||
| { | ||||
|   "bracketSpacing": true, | ||||
|   "printWidth": 120, | ||||
|   "tabWidth": 2, | ||||
|   "tabWidth": 4, | ||||
|   "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"; | ||||
| 
 | ||||
| function httpsWorker(glx) { | ||||
| 	// Serves on 80 and 443 | ||||
| 	// Get's SSL certificates magically! | ||||
|     // Serves on 80 and 443 | ||||
|     // Get's SSL certificates magically! | ||||
| 
 | ||||
| 	glx.serveApp(function(req, res) { | ||||
| 		res.end("Hello, Encrypted World!"); | ||||
| 	}); | ||||
|     glx.serveApp(function(req, res) { | ||||
|         res.end("Hello, Encrypted World!"); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| var pkg = require("./package.json"); | ||||
| require("greenlock-express") | ||||
| 	.init(function getConfig() { | ||||
| 		// Greenlock Config | ||||
|     .init(function getConfig() { | ||||
|         // Greenlock Config | ||||
| 
 | ||||
| 		return { | ||||
| 			package: { name: pkg.name, version: pkg.version }, | ||||
| 			maintainerEmail: pkg.author, | ||||
| 			cluster: false | ||||
| 		}; | ||||
| 	}) | ||||
| 	.serve(httpsWorker); | ||||
|         return { | ||||
|             package: { name: pkg.name, version: pkg.version }, | ||||
|             maintainerEmail: pkg.author, | ||||
|             cluster: false | ||||
|         }; | ||||
|     }) | ||||
|     .serve(httpsWorker); | ||||
| ``` | ||||
| 
 | ||||
| Manage via API or the config file: | ||||
| @ -50,44 +50,44 @@ Manage via API or the config file: | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
| 	"subscriberEmail": "letsencrypt-test@therootcompany.com", | ||||
| 	"agreeToTerms": true, | ||||
| 	"sites": { | ||||
| 		"example.com": { | ||||
| 			"subject": "example.com", | ||||
| 			"altnames": ["example.com", "www.example.com"] | ||||
| 		} | ||||
| 	} | ||||
|     "subscriberEmail": "letsencrypt-test@therootcompany.com", | ||||
|     "agreeToTerms": true, | ||||
|     "sites": { | ||||
|         "example.com": { | ||||
|             "subject": "example.com", | ||||
|             "altnames": ["example.com", "www.example.com"] | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| # Let's Encrypt for... | ||||
| 
 | ||||
| - IoT | ||||
| - Enterprise On-Prem | ||||
| - Local Development | ||||
| - Home Servers | ||||
| - Quitting Heroku | ||||
| -   IoT | ||||
| -   Enterprise On-Prem | ||||
| -   Local Development | ||||
| -   Home Servers | ||||
| -   Quitting Heroku | ||||
| 
 | ||||
| # Features | ||||
| 
 | ||||
| - [x] Let's Encrypt v2 (November 2019) | ||||
|   - [x] ACME Protocol (RFC 8555) | ||||
|   - [x] HTTP Validation (HTTP-01) | ||||
|   - [x] DNS Validation (DNS-01) | ||||
|   - [ ] ALPN Validation (TLS-ALPN-01) | ||||
|     - Need ALPN validation? [contact us](mailto:greenlock-support@therootcompany.com) | ||||
| - [x] Automated HTTPS | ||||
|   - [x] Fully Automatic Renewals every 45 days | ||||
|   - [x] Free SSL | ||||
|   - [x] **Wildcard** SSL | ||||
|   - [x] **Localhost** certificates | ||||
|   - [x] HTTPS-enabled Secure **WebSockets** (`wss://`) | ||||
| - [x] Fully customizable | ||||
|   - [x] **Reasonable defaults** | ||||
|   - [x] Domain Management | ||||
|   - [x] Key and Certificate Management | ||||
|   - [x] ACME Challenge Plugins | ||||
| -   [x] Let's Encrypt v2 (November 2019) | ||||
|     -   [x] ACME Protocol (RFC 8555) | ||||
|     -   [x] HTTP Validation (HTTP-01) | ||||
|     -   [x] DNS Validation (DNS-01) | ||||
|     -   [ ] ALPN Validation (TLS-ALPN-01) | ||||
|         -   Need ALPN validation? [contact us](mailto:greenlock-support@therootcompany.com) | ||||
| -   [x] Automated HTTPS | ||||
|     -   [x] Fully Automatic Renewals every 45 days | ||||
|     -   [x] Free SSL | ||||
|     -   [x] **Wildcard** SSL | ||||
|     -   [x] **Localhost** certificates | ||||
|     -   [x] HTTPS-enabled Secure **WebSockets** (`wss://`) | ||||
| -   [x] Fully customizable | ||||
|     -   [x] **Reasonable defaults** | ||||
|     -   [x] Domain Management | ||||
|     -   [x] Key and Certificate Management | ||||
|     -   [x] ACME Challenge Plugins | ||||
| 
 | ||||
| # QuickStart Guide | ||||
| 
 | ||||
| @ -127,7 +127,7 @@ works with everything. | ||||
| // A plain, node-style app | ||||
| 
 | ||||
| function myPlainNodeHttpApp(req, res) { | ||||
| 	res.end("Hello, Encrypted World!"); | ||||
|     res.end("Hello, Encrypted World!"); | ||||
| } | ||||
| 
 | ||||
| // Wrap that plain app in express, | ||||
| @ -152,9 +152,9 @@ module.exports = app; | ||||
| 
 | ||||
| Greenlock Express is designed with these goals in mind: | ||||
| 
 | ||||
| - Simplicity and ease-of-use | ||||
| - Performance and scalability | ||||
| - Configurability and control | ||||
| -   Simplicity and ease-of-use | ||||
| -   Performance and scalability | ||||
| -   Configurability and control | ||||
| 
 | ||||
| You can start with **near-zero configuration** and | ||||
| slowly add options for greater performance and customization | ||||
| @ -164,21 +164,21 @@ later, if you need them. | ||||
| 
 | ||||
| ```js | ||||
| require("greenlock-express") | ||||
| 	.init(getConfig) | ||||
| 	.serve(worker); | ||||
|     .init(getConfig) | ||||
|     .serve(worker); | ||||
| 
 | ||||
| function getConfig() { | ||||
| 	return { | ||||
| 		// uses name and version as part of the ACME client user-agent | ||||
| 		// uses author as the contact for support notices | ||||
| 		package: require("./package.json") | ||||
| 	}; | ||||
|     return { | ||||
|         // uses name and version as part of the ACME client user-agent | ||||
|         // uses author as the contact for support notices | ||||
|         package: require("./package.json") | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| function worker(server) { | ||||
| 	// Works with any Node app (Express, etc) | ||||
| 	var app = require("my-express-app.js"); | ||||
| 	server.serveApp(app); | ||||
|     // Works with any Node app (Express, etc) | ||||
|     var app = require("my-express-app.js"); | ||||
|     server.serveApp(app); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| @ -222,14 +222,14 @@ This will update the config file (assuming the default fs-based management plugi | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
| 	"subscriberEmail": "letsencrypt-test@therootcompany.com", | ||||
| 	"agreeToTerms": true, | ||||
| 	"sites": { | ||||
| 		"example.com": { | ||||
| 			"subject": "example.com", | ||||
| 			"altnames": ["example.com", "www.example.com"] | ||||
| 		} | ||||
| 	} | ||||
|     "subscriberEmail": "letsencrypt-test@therootcompany.com", | ||||
|     "agreeToTerms": true, | ||||
|     "sites": { | ||||
|         "example.com": { | ||||
|             "subject": "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 | ||||
| [**DNS validation**](https://git.rootprojects.org/root/greenlock-exp). | ||||
| 
 | ||||
| - DNS Validation | ||||
|   - [**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) | ||||
|   - [**CI/CD**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/ci-cd/) (coming soon) | ||||
| -   DNS Validation | ||||
|     -   [**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) | ||||
|     -   [**CI/CD**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/ci-cd/) (coming soon) | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| @ -280,17 +280,17 @@ Note: **Localhost**, **Wildcard**, and Certificates for Private Networks require | ||||
| 
 | ||||
| **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) | ||||
|   - [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 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/) | ||||
|   - [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/) | ||||
|   - [**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) | ||||
|   - [**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/) | ||||
| -   [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/) | ||||
|     -   [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/) | ||||
|     -   [**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/) | ||||
|     -   [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) | ||||
|     -   [**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) | ||||
|     -   [HTTP Proxy](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/http-proxy/) | ||||
| 
 | ||||
| # 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) | ||||
| --> | ||||
| 
 | ||||
| - [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 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 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 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) | ||||
| 
 | ||||
| # Ready-made Integrations | ||||
| 
 | ||||
| @ -345,12 +345,12 @@ We're working on more comprehensive documentation for this newly released versio | ||||
| 
 | ||||
| Do you need... | ||||
| 
 | ||||
| - training? | ||||
| - specific features? | ||||
| - different integrations? | ||||
| - bugfixes, on _your_ timeline? | ||||
| - custom code, built by experts? | ||||
| - commercial support and licensing? | ||||
| -   training? | ||||
| -   specific features? | ||||
| -   different integrations? | ||||
| -   bugfixes, on _your_ timeline? | ||||
| -   custom code, built by experts? | ||||
| -   commercial support and licensing? | ||||
| 
 | ||||
| You're welcome to [contact us](mailto:aj@therootcompany.com) in regards to IoT, On-Prem, | ||||
| Enterprise, and Internal installations, integrations, and deployments. | ||||
|  | ||||
							
								
								
									
										28
									
								
								config.js
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								config.js
									
									
									
									
									
								
							| @ -2,19 +2,19 @@ | ||||
| 
 | ||||
| var path = require("path"); | ||||
| module.exports = { | ||||
| 	email: "jon.doe@example.com", | ||||
| 	configDir: path.join(__dirname, "acme"), | ||||
| 	srv: "/srv/www/", | ||||
| 	api: "/srv/api/", | ||||
| 	proxy: { | ||||
| 		"example.com": "http://localhost:4080", | ||||
| 		"*.example.com": "http://localhost:4080" | ||||
| 	}, | ||||
|     email: "jon.doe@example.com", | ||||
|     configDir: path.join(__dirname, "acme"), | ||||
|     srv: "/srv/www/", | ||||
|     api: "/srv/api/", | ||||
|     proxy: { | ||||
|         "example.com": "http://localhost:4080", | ||||
|         "*.example.com": "http://localhost:4080" | ||||
|     }, | ||||
| 
 | ||||
| 	// DNS-01 challenges only
 | ||||
| 	challenges: { | ||||
| 		"*.example.com": require("acme-dns-01-YOUR_DNS_HOST").create({ | ||||
| 			token: "xxxx" | ||||
| 		}) | ||||
| 	} | ||||
|     // DNS-01 challenges only
 | ||||
|     challenges: { | ||||
|         "*.example.com": require("acme-dns-01-YOUR_DNS_HOST").create({ | ||||
|             token: "xxxx" | ||||
|         }) | ||||
|     } | ||||
| }; | ||||
|  | ||||
							
								
								
									
										48
									
								
								demo.js
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								demo.js
									
									
									
									
									
								
							| @ -1,35 +1,35 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| require("./") | ||||
| 	.init(initialize) | ||||
| 	.serve(worker) | ||||
| 	.master(function() { | ||||
| 		console.log("Hello from master"); | ||||
| 	}); | ||||
|     .init(initialize) | ||||
|     .serve(worker) | ||||
|     .master(function() { | ||||
|         console.log("Hello from master"); | ||||
|     }); | ||||
| 
 | ||||
| function initialize() { | ||||
| 	var pkg = require("./package.json"); | ||||
| 	var config = { | ||||
| 		package: { | ||||
| 			name: "Greenlock_Express_Demo", | ||||
| 			version: pkg.version, | ||||
| 			author: pkg.author | ||||
| 		}, | ||||
| 		staging: true, | ||||
| 		cluster: true, | ||||
|     var pkg = require("./package.json"); | ||||
|     var config = { | ||||
|         package: { | ||||
|             name: "Greenlock_Express_Demo", | ||||
|             version: pkg.version, | ||||
|             author: pkg.author | ||||
|         }, | ||||
|         staging: true, | ||||
|         cluster: true, | ||||
| 
 | ||||
| 		notify: function(ev, params) { | ||||
| 			console.info(ev, params); | ||||
| 		} | ||||
| 	}; | ||||
| 	return config; | ||||
|         notify: function(ev, params) { | ||||
|             console.info(ev, params); | ||||
|         } | ||||
|     }; | ||||
|     return config; | ||||
| } | ||||
| 
 | ||||
| function worker(glx) { | ||||
| 	console.info(); | ||||
| 	console.info("Hello from worker #" + glx.id()); | ||||
|     console.info(); | ||||
|     console.info("Hello from worker #" + glx.id()); | ||||
| 
 | ||||
| 	glx.serveApp(function(req, res) { | ||||
| 		res.end("Hello, Encrypted World!"); | ||||
| 	}); | ||||
|     glx.serveApp(function(req, res) { | ||||
|         res.end("Hello, Encrypted World!"); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| @ -3,37 +3,37 @@ | ||||
| var pkg = require("../../package.json"); | ||||
| //require("greenlock-express")
 | ||||
| require("../../") | ||||
| 	.init(function getConfig() { | ||||
| 		// Greenlock Config
 | ||||
|     .init(function getConfig() { | ||||
|         // Greenlock Config
 | ||||
| 
 | ||||
| 		return { | ||||
| 			package: { name: "websocket-example", version: pkg.version }, | ||||
| 			maintainerEmail: "jon@example.com", | ||||
|         return { | ||||
|             package: { name: "websocket-example", version: pkg.version }, | ||||
|             maintainerEmail: "jon@example.com", | ||||
| 
 | ||||
| 			// 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)
 | ||||
| 			cluster: 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)
 | ||||
|             cluster: true, | ||||
| 
 | ||||
| 			// This will default to the number of workers being equal to
 | ||||
| 			// n-1 cpus, with a minimum of 2
 | ||||
| 			workers: 4 | ||||
| 		}; | ||||
| 	}) | ||||
| 	.serve(httpsWorker); | ||||
|             // This will default to the number of workers being equal to
 | ||||
|             // n-1 cpus, with a minimum of 2
 | ||||
|             workers: 4 | ||||
|         }; | ||||
|     }) | ||||
|     .serve(httpsWorker); | ||||
| 
 | ||||
| function httpsWorker(glx) { | ||||
| 	// WRONG
 | ||||
| 	// This won't work like you
 | ||||
| 	// think because EACH worker
 | ||||
| 	// has ITS OWN `count`.
 | ||||
| 	var count = 0; | ||||
|     // WRONG
 | ||||
|     // This won't work like you
 | ||||
|     // think because EACH worker
 | ||||
|     // has ITS OWN `count`.
 | ||||
|     var count = 0; | ||||
| 
 | ||||
| 	var app = function(req, res) { | ||||
| 		res.end("Hello... how many times now? Oh, " + count + " times"); | ||||
| 		count += 1; | ||||
| 	}; | ||||
|     var app = function(req, res) { | ||||
|         res.end("Hello... how many times now? Oh, " + count + " times"); | ||||
|         count += 1; | ||||
|     }; | ||||
| 
 | ||||
| 	// Serves on 80 and 443... for each worker
 | ||||
| 	// Get's SSL certificates magically!
 | ||||
| 	glx.serveApp(app); | ||||
|     // Serves on 80 and 443... for each worker
 | ||||
|     // Get's SSL certificates magically!
 | ||||
|     glx.serveApp(app); | ||||
| } | ||||
|  | ||||
| @ -4,13 +4,13 @@ var express = require("express"); | ||||
| var app = express(); | ||||
| 
 | ||||
| app.use("/", function(req, res) { | ||||
| 	res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||
| 	res.end("Hello, World!\n\n💚 🔒.js"); | ||||
|     res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||
|     res.end("Hello, World!\n\n💚 🔒.js"); | ||||
| }); | ||||
| 
 | ||||
| // DO NOT DO app.listen() unless we're testing this directly
 | ||||
| if (require.main === module) { | ||||
| 	app.listen(3000); | ||||
|     app.listen(3000); | ||||
| } | ||||
| 
 | ||||
| // Instead do export the app:
 | ||||
|  | ||||
| @ -1,27 +1,27 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| function httpsWorker(glx) { | ||||
| 	var app = require("./my-express-app.js"); | ||||
|     var app = require("./my-express-app.js"); | ||||
| 
 | ||||
| 	app.get("/hello", function(req, res) { | ||||
| 		res.end("Hello, Encrypted World!"); | ||||
| 	}); | ||||
|     app.get("/hello", function(req, res) { | ||||
|         res.end("Hello, Encrypted World!"); | ||||
|     }); | ||||
| 
 | ||||
| 	// Serves on 80 and 443
 | ||||
| 	// Get's SSL certificates magically!
 | ||||
| 	glx.serveApp(app); | ||||
|     // Serves on 80 and 443
 | ||||
|     // Get's SSL certificates magically!
 | ||||
|     glx.serveApp(app); | ||||
| } | ||||
| 
 | ||||
| var pkg = require("../../package.json"); | ||||
| //require("greenlock-express")
 | ||||
| require("../../") | ||||
| 	.init(function getConfig() { | ||||
| 		// Greenlock Config
 | ||||
|     .init(function getConfig() { | ||||
|         // Greenlock Config
 | ||||
| 
 | ||||
| 		return { | ||||
| 			package: { name: "http2-example", version: pkg.version }, | ||||
| 			maintainerEmail: "jon@example.com", | ||||
| 			cluster: false | ||||
| 		}; | ||||
| 	}) | ||||
| 	.serve(httpsWorker); | ||||
|         return { | ||||
|             package: { name: "http2-example", version: pkg.version }, | ||||
|             maintainerEmail: "jon@example.com", | ||||
|             cluster: false | ||||
|         }; | ||||
|     }) | ||||
|     .serve(httpsWorker); | ||||
|  | ||||
| @ -1,44 +1,44 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| function httpsWorker(glx) { | ||||
| 	// we need the raw https server
 | ||||
| 	var server = glx.httpsServer(); | ||||
| 	var proxy = require("http-proxy").createProxyServer({ xfwd: true }); | ||||
|     // we need the raw https server
 | ||||
|     var server = glx.httpsServer(); | ||||
|     var proxy = require("http-proxy").createProxyServer({ xfwd: true }); | ||||
| 
 | ||||
| 	// catches error events during proxying
 | ||||
| 	proxy.on("error", function(err, req, res) { | ||||
| 		console.error(err); | ||||
| 		res.statusCode = 500; | ||||
| 		res.end(); | ||||
| 		return; | ||||
| 	}); | ||||
|     // catches error events during proxying
 | ||||
|     proxy.on("error", function(err, req, res) { | ||||
|         console.error(err); | ||||
|         res.statusCode = 500; | ||||
|         res.end(); | ||||
|         return; | ||||
|     }); | ||||
| 
 | ||||
| 	// We'll proxy websockets too
 | ||||
| 	server.on("upgrade", function(req, socket, head) { | ||||
| 		proxy.ws(req, socket, head, { | ||||
| 			ws: true, | ||||
| 			target: "ws://localhost:3000" | ||||
| 		}); | ||||
| 	}); | ||||
|     // We'll proxy websockets too
 | ||||
|     server.on("upgrade", function(req, socket, head) { | ||||
|         proxy.ws(req, socket, head, { | ||||
|             ws: true, | ||||
|             target: "ws://localhost:3000" | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
| 	// servers a node app that proxies requests to a localhost
 | ||||
| 	glx.serveApp(function(req, res) { | ||||
| 		proxy.web(req, res, { | ||||
| 			target: "http://localhost:3000" | ||||
| 		}); | ||||
| 	}); | ||||
|     // servers a node app that proxies requests to a localhost
 | ||||
|     glx.serveApp(function(req, res) { | ||||
|         proxy.web(req, res, { | ||||
|             target: "http://localhost:3000" | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| var pkg = require("../../package.json"); | ||||
| //require("greenlock-express")
 | ||||
| require("../../") | ||||
| 	.init(function getConfig() { | ||||
| 		// Greenlock Config
 | ||||
|     .init(function getConfig() { | ||||
|         // Greenlock Config
 | ||||
| 
 | ||||
| 		return { | ||||
| 			package: { name: "http-proxy-example", version: pkg.version }, | ||||
| 			maintainerEmail: "jon@example.com", | ||||
| 			cluster: false | ||||
| 		}; | ||||
| 	}) | ||||
| 	.serve(httpsWorker); | ||||
|         return { | ||||
|             package: { name: "http-proxy-example", version: pkg.version }, | ||||
|             maintainerEmail: "jon@example.com", | ||||
|             cluster: false | ||||
|         }; | ||||
|     }) | ||||
|     .serve(httpsWorker); | ||||
|  | ||||
| @ -11,32 +11,32 @@ var pkg = require("../../package.json"); | ||||
| // Use glx.httpServer(redirectToHttps) instead.
 | ||||
| 
 | ||||
| function httpsWorker(glx) { | ||||
| 	//
 | ||||
| 	// HTTP can only be used for ACME HTTP-01 Challenges
 | ||||
| 	// (and it is not required for DNS-01 challenges)
 | ||||
| 	//
 | ||||
|     //
 | ||||
|     // HTTP can only be used for ACME HTTP-01 Challenges
 | ||||
|     // (and it is not required for DNS-01 challenges)
 | ||||
|     //
 | ||||
| 
 | ||||
| 	// Get the raw http server:
 | ||||
| 	var httpServer = glx.httpServer(function(req, res) { | ||||
| 		res.statusCode = 301; | ||||
| 		res.setHeader("Location", "https://" + req.headers.host + req.path); | ||||
| 		res.end("Insecure connections are not allowed. Redirecting..."); | ||||
| 	}); | ||||
|     // Get the raw http server:
 | ||||
|     var httpServer = glx.httpServer(function(req, res) { | ||||
|         res.statusCode = 301; | ||||
|         res.setHeader("Location", "https://" + req.headers.host + req.path); | ||||
|         res.end("Insecure connections are not allowed. Redirecting..."); | ||||
|     }); | ||||
| 
 | ||||
| 	httpServer.listen(80, "0.0.0.0", function() { | ||||
| 		console.info("Listening on ", httpServer.address()); | ||||
| 	}); | ||||
|     httpServer.listen(80, "0.0.0.0", function() { | ||||
|         console.info("Listening on ", httpServer.address()); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| //require("greenlock-express")
 | ||||
| require("../../") | ||||
| 	.init(function getConfig() { | ||||
| 		// Greenlock Config
 | ||||
|     .init(function getConfig() { | ||||
|         // Greenlock Config
 | ||||
| 
 | ||||
| 		return { | ||||
| 			package: { name: "plain-http-example", version: pkg.version }, | ||||
| 			maintainerEmail: "jon@example.com", | ||||
| 			cluster: false | ||||
| 		}; | ||||
| 	}) | ||||
| 	.serve(httpsWorker); | ||||
|         return { | ||||
|             package: { name: "plain-http-example", version: pkg.version }, | ||||
|             maintainerEmail: "jon@example.com", | ||||
|             cluster: false | ||||
|         }; | ||||
|     }) | ||||
|     .serve(httpsWorker); | ||||
|  | ||||
| @ -11,38 +11,38 @@ var pkg = require("../../package.json"); | ||||
| // Use glx.httpsServer(tlsOptions, app) instead.
 | ||||
| 
 | ||||
| function httpsWorker(glx) { | ||||
| 	//
 | ||||
| 	// HTTP2 would have been the default httpsServer for node v12+
 | ||||
| 	// However... https://github.com/expressjs/express/issues/3388
 | ||||
| 	//
 | ||||
|     //
 | ||||
|     // HTTP2 would have been the default httpsServer for node v12+
 | ||||
|     // However... https://github.com/expressjs/express/issues/3388
 | ||||
|     //
 | ||||
| 
 | ||||
| 	// Get the raw http2 server:
 | ||||
| 	var http2Server = glx.http2Server(function(req, res) { | ||||
| 		res.end("Hello, Encrypted World!"); | ||||
| 	}); | ||||
|     // Get the raw http2 server:
 | ||||
|     var http2Server = glx.http2Server(function(req, res) { | ||||
|         res.end("Hello, Encrypted World!"); | ||||
|     }); | ||||
| 
 | ||||
| 	http2Server.listen(443, "0.0.0.0", function() { | ||||
| 		console.info("Listening on ", http2Server.address()); | ||||
| 	}); | ||||
|     http2Server.listen(443, "0.0.0.0", function() { | ||||
|         console.info("Listening on ", http2Server.address()); | ||||
|     }); | ||||
| 
 | ||||
| 	// Note:
 | ||||
| 	// You must ALSO listen on port 80 for ACME HTTP-01 Challenges
 | ||||
| 	// (the ACME and http->https middleware are loaded by glx.httpServer)
 | ||||
| 	var httpServer = glx.httpServer(); | ||||
| 	httpServer.listen(80, "0.0.0.0", function() { | ||||
| 		console.info("Listening on ", httpServer.address()); | ||||
| 	}); | ||||
|     // Note:
 | ||||
|     // You must ALSO listen on port 80 for ACME HTTP-01 Challenges
 | ||||
|     // (the ACME and http->https middleware are loaded by glx.httpServer)
 | ||||
|     var httpServer = glx.httpServer(); | ||||
|     httpServer.listen(80, "0.0.0.0", function() { | ||||
|         console.info("Listening on ", httpServer.address()); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| //require("greenlock-express")
 | ||||
| require("../../") | ||||
| 	.init(function getConfig() { | ||||
| 		// Greenlock Config
 | ||||
|     .init(function getConfig() { | ||||
|         // Greenlock Config
 | ||||
| 
 | ||||
| 		return { | ||||
| 			package: { name: "http2-example", version: pkg.version }, | ||||
| 			maintainerEmail: "jon@example.com", | ||||
| 			cluster: false | ||||
| 		}; | ||||
| 	}) | ||||
| 	.serve(httpsWorker); | ||||
|         return { | ||||
|             package: { name: "http2-example", version: pkg.version }, | ||||
|             maintainerEmail: "jon@example.com", | ||||
|             cluster: false | ||||
|         }; | ||||
|     }) | ||||
|     .serve(httpsWorker); | ||||
|  | ||||
| @ -11,38 +11,38 @@ var pkg = require("../../package.json"); | ||||
| // Use glx.httpsServer(tlsOptions, app) instead.
 | ||||
| 
 | ||||
| function httpsWorker(glx) { | ||||
| 	//
 | ||||
| 	// HTTPS 1.1 is the default
 | ||||
| 	// (HTTP2 would be the default but... https://github.com/expressjs/express/issues/3388)
 | ||||
| 	//
 | ||||
|     //
 | ||||
|     // HTTPS 1.1 is the default
 | ||||
|     // (HTTP2 would be the default but... https://github.com/expressjs/express/issues/3388)
 | ||||
|     //
 | ||||
| 
 | ||||
| 	// Get the raw https server:
 | ||||
| 	var httpsServer = glx.httpsServer(null, function(req, res) { | ||||
| 		res.end("Hello, Encrypted World!"); | ||||
| 	}); | ||||
|     // Get the raw https server:
 | ||||
|     var httpsServer = glx.httpsServer(null, function(req, res) { | ||||
|         res.end("Hello, Encrypted World!"); | ||||
|     }); | ||||
| 
 | ||||
| 	httpsServer.listen(443, "0.0.0.0", function() { | ||||
| 		console.info("Listening on ", httpsServer.address()); | ||||
| 	}); | ||||
|     httpsServer.listen(443, "0.0.0.0", function() { | ||||
|         console.info("Listening on ", httpsServer.address()); | ||||
|     }); | ||||
| 
 | ||||
| 	// Note:
 | ||||
| 	// You must ALSO listen on port 80 for ACME HTTP-01 Challenges
 | ||||
| 	// (the ACME and http->https middleware are loaded by glx.httpServer)
 | ||||
| 	var httpServer = glx.httpServer(); | ||||
| 	httpServer.listen(80, "0.0.0.0", function() { | ||||
| 		console.info("Listening on ", httpServer.address()); | ||||
| 	}); | ||||
|     // Note:
 | ||||
|     // You must ALSO listen on port 80 for ACME HTTP-01 Challenges
 | ||||
|     // (the ACME and http->https middleware are loaded by glx.httpServer)
 | ||||
|     var httpServer = glx.httpServer(); | ||||
|     httpServer.listen(80, "0.0.0.0", function() { | ||||
|         console.info("Listening on ", httpServer.address()); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| //require("greenlock-express")
 | ||||
| require("../../") | ||||
| 	.init(function getConfig() { | ||||
| 		// Greenlock Config
 | ||||
|     .init(function getConfig() { | ||||
|         // Greenlock Config
 | ||||
| 
 | ||||
| 		return { | ||||
| 			package: { name: "https1-example", version: pkg.version }, | ||||
| 			maintainerEmail: "jon@example.com", | ||||
| 			cluster: false | ||||
| 		}; | ||||
| 	}) | ||||
| 	.serve(httpsWorker); | ||||
|         return { | ||||
|             package: { name: "https1-example", version: pkg.version }, | ||||
|             maintainerEmail: "jon@example.com", | ||||
|             cluster: false | ||||
|         }; | ||||
|     }) | ||||
|     .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 | ||||
| { | ||||
| 	"subscriberEmail": "letsencrypt-test@therootcompany.com", | ||||
| 	"agreeToTerms": true, | ||||
| 	"sites": { | ||||
| 		"example.com": { | ||||
| 			"subject": "example.com", | ||||
| 			"altnames": ["example.com", "www.example.com"] | ||||
| 		} | ||||
| 	} | ||||
|     "subscriberEmail": "letsencrypt-test@therootcompany.com", | ||||
|     "agreeToTerms": true, | ||||
|     "sites": { | ||||
|         "example.com": { | ||||
|             "subject": "example.com", | ||||
|             "altnames": ["example.com", "www.example.com"] | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| @ -1,32 +1,32 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| function httpsWorker(glx) { | ||||
| 	// This can be a node http app (shown),
 | ||||
| 	// an Express app, or Hapi, Koa, Rill, etc
 | ||||
| 	var app = function(req, res) { | ||||
| 		res.end("Hello, Encrypted World!"); | ||||
| 	}; | ||||
|     // This can be a node http app (shown),
 | ||||
|     // an Express app, or Hapi, Koa, Rill, etc
 | ||||
|     var app = function(req, res) { | ||||
|         res.end("Hello, Encrypted World!"); | ||||
|     }; | ||||
| 
 | ||||
| 	// Serves on 80 and 443
 | ||||
| 	// Get's SSL certificates magically!
 | ||||
| 	glx.serveApp(app); | ||||
|     // Serves on 80 and 443
 | ||||
|     // Get's SSL certificates magically!
 | ||||
|     glx.serveApp(app); | ||||
| } | ||||
| 
 | ||||
| var pkg = require("../../package.json"); | ||||
| //require("greenlock-express")
 | ||||
| require("../../") | ||||
| 	.init(function getConfig() { | ||||
| 		// Greenlock Config
 | ||||
|     .init(function getConfig() { | ||||
|         // Greenlock Config
 | ||||
| 
 | ||||
| 		return { | ||||
| 			// Package name+version is used for ACME client user agent
 | ||||
| 			package: { name: "websocket-example", version: pkg.version }, | ||||
|         return { | ||||
|             // Package name+version is used for ACME client user agent
 | ||||
|             package: { name: "websocket-example", version: pkg.version }, | ||||
| 
 | ||||
| 			// Maintainer email is the contact for critical bug and security notices
 | ||||
| 			maintainerEmail: "jon@example.com", | ||||
|             // Maintainer email is the contact for critical bug and security notices
 | ||||
|             maintainerEmail: "jon@example.com", | ||||
| 
 | ||||
| 			// Change to true when you're ready to make your app cloud-scale
 | ||||
| 			cluster: false | ||||
| 		}; | ||||
| 	}) | ||||
| 	.serve(httpsWorker); | ||||
|             // Change to true when you're ready to make your app cloud-scale
 | ||||
|             cluster: false | ||||
|         }; | ||||
|     }) | ||||
|     .serve(httpsWorker); | ||||
|  | ||||
| @ -9,41 +9,41 @@ | ||||
| //       (see the websocket example)
 | ||||
| 
 | ||||
| function httpsWorker(glx) { | ||||
| 	var socketio = require("socket.io"); | ||||
| 	var io; | ||||
|     var socketio = require("socket.io"); | ||||
|     var io; | ||||
| 
 | ||||
| 	// we need the raw https server
 | ||||
| 	var server = glx.httpsServer(); | ||||
|     // we need the raw https server
 | ||||
|     var server = glx.httpsServer(); | ||||
| 
 | ||||
| 	io = socketio(server); | ||||
|     io = socketio(server); | ||||
| 
 | ||||
| 	// Then you do your socket.io stuff
 | ||||
| 	io.on("connection", function(socket) { | ||||
| 		console.log("a user connected"); | ||||
| 		socket.emit("Welcome"); | ||||
|     // Then you do your socket.io stuff
 | ||||
|     io.on("connection", function(socket) { | ||||
|         console.log("a user connected"); | ||||
|         socket.emit("Welcome"); | ||||
| 
 | ||||
| 		socket.on("chat message", function(msg) { | ||||
| 			socket.broadcast.emit("chat message", msg); | ||||
| 		}); | ||||
| 	}); | ||||
|         socket.on("chat message", function(msg) { | ||||
|             socket.broadcast.emit("chat message", msg); | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
| 	// servers a node app that proxies requests to a localhost
 | ||||
| 	glx.serveApp(function(req, res) { | ||||
| 		res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||
| 		res.end("Hello, World!\n\n💚 🔒.js"); | ||||
| 	}); | ||||
|     // servers a node app that proxies requests to a localhost
 | ||||
|     glx.serveApp(function(req, res) { | ||||
|         res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||
|         res.end("Hello, World!\n\n💚 🔒.js"); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| var pkg = require("../../package.json"); | ||||
| //require("greenlock-express")
 | ||||
| require("../../") | ||||
| 	.init(function getConfig() { | ||||
| 		// Greenlock Config
 | ||||
|     .init(function getConfig() { | ||||
|         // Greenlock Config
 | ||||
| 
 | ||||
| 		return { | ||||
| 			package: { name: "socket-io-example", version: pkg.version }, | ||||
| 			maintainerEmail: "jon@example.com", | ||||
| 			cluster: false | ||||
| 		}; | ||||
| 	}) | ||||
| 	.serve(httpsWorker); | ||||
|         return { | ||||
|             package: { name: "socket-io-example", version: pkg.version }, | ||||
|             maintainerEmail: "jon@example.com", | ||||
|             cluster: false | ||||
|         }; | ||||
|     }) | ||||
|     .serve(httpsWorker); | ||||
|  | ||||
| @ -1,42 +1,42 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| function httpsWorker(glx) { | ||||
| 	// we need the raw https server
 | ||||
| 	var server = glx.httpsServer(); | ||||
| 	var WebSocket = require("ws"); | ||||
| 	var ws = new WebSocket.Server({ server: server }); | ||||
| 	ws.on("connection", function(ws, req) { | ||||
| 		// inspect req.headers.authorization (or cookies) for session info
 | ||||
| 		ws.send( | ||||
| 			"[Secure Echo Server] Hello!\nAuth: '" + | ||||
| 				(req.headers.authorization || "none") + | ||||
| 				"'\n" + | ||||
| 				"Cookie: '" + | ||||
| 				(req.headers.cookie || "none") + | ||||
| 				"'\n" | ||||
| 		); | ||||
| 		ws.on("message", function(data) { | ||||
| 			ws.send(data); | ||||
| 		}); | ||||
| 	}); | ||||
|     // we need the raw https server
 | ||||
|     var server = glx.httpsServer(); | ||||
|     var WebSocket = require("ws"); | ||||
|     var ws = new WebSocket.Server({ server: server }); | ||||
|     ws.on("connection", function(ws, req) { | ||||
|         // inspect req.headers.authorization (or cookies) for session info
 | ||||
|         ws.send( | ||||
|             "[Secure Echo Server] Hello!\nAuth: '" + | ||||
|                 (req.headers.authorization || "none") + | ||||
|                 "'\n" + | ||||
|                 "Cookie: '" + | ||||
|                 (req.headers.cookie || "none") + | ||||
|                 "'\n" | ||||
|         ); | ||||
|         ws.on("message", function(data) { | ||||
|             ws.send(data); | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
| 	// servers a node app that proxies requests to a localhost
 | ||||
| 	glx.serveApp(function(req, res) { | ||||
| 		res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||
| 		res.end("Hello, World!\n\n💚 🔒.js"); | ||||
| 	}); | ||||
|     // servers a node app that proxies requests to a localhost
 | ||||
|     glx.serveApp(function(req, res) { | ||||
|         res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||
|         res.end("Hello, World!\n\n💚 🔒.js"); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| var pkg = require("../../package.json"); | ||||
| //require("greenlock-express")
 | ||||
| require("../../") | ||||
| 	.init(function getConfig() { | ||||
| 		// Greenlock Config
 | ||||
|     .init(function getConfig() { | ||||
|         // Greenlock Config
 | ||||
| 
 | ||||
| 		return { | ||||
| 			package: { name: "websocket-example", version: pkg.version }, | ||||
| 			maintainerEmail: "jon@example.com", | ||||
| 			cluster: false | ||||
| 		}; | ||||
| 	}) | ||||
| 	.serve(httpsWorker); | ||||
|         return { | ||||
|             package: { name: "websocket-example", version: pkg.version }, | ||||
|             maintainerEmail: "jon@example.com", | ||||
|             cluster: false | ||||
|         }; | ||||
|     }) | ||||
|     .serve(httpsWorker); | ||||
|  | ||||
| @ -17,28 +17,28 @@ var GLE = module.exports; | ||||
| // under the hood. That's the hope, anyway.
 | ||||
| 
 | ||||
| GLE.init = function(fn) { | ||||
| 	if (cluster.isWorker) { | ||||
| 		// ignore the init function and launch the worker
 | ||||
| 		return require("./worker.js").create(); | ||||
| 	} | ||||
|     if (cluster.isWorker) { | ||||
|         // ignore the init function and launch the worker
 | ||||
|         return require("./worker.js").create(); | ||||
|     } | ||||
| 
 | ||||
| 	var opts = fn(); | ||||
| 	if (!opts || "object" !== typeof opts) { | ||||
| 		throw new Error( | ||||
| 			"the `Greenlock.init(fn)` function should return an object `{ maintainerEmail, packageAgent, notify }`" | ||||
| 		); | ||||
| 	} | ||||
|     var opts = fn(); | ||||
|     if (!opts || "object" !== typeof opts) { | ||||
|         throw new Error( | ||||
|             "the `Greenlock.init(fn)` function should return an object `{ maintainerEmail, packageAgent, notify }`" | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
| 	// just for ironic humor
 | ||||
| 	["cloudnative", "cloudscale", "webscale", "distributed", "blockchain"].forEach(function(k) { | ||||
| 		if (opts[k]) { | ||||
| 			opts.cluster = true; | ||||
| 		} | ||||
| 	}); | ||||
|     // just for ironic humor
 | ||||
|     ["cloudnative", "cloudscale", "webscale", "distributed", "blockchain"].forEach(function(k) { | ||||
|         if (opts[k]) { | ||||
|             opts.cluster = true; | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
| 	if (opts.cluster) { | ||||
| 		return require("./master.js").create(opts); | ||||
| 	} | ||||
|     if (opts.cluster) { | ||||
|         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"; | ||||
| 
 | ||||
| module.exports.create = function(opts) { | ||||
| 	opts = parsePackage(opts); | ||||
| 	opts.packageAgent = addGreenlockAgent(opts); | ||||
|     opts = parsePackage(opts); | ||||
|     opts.packageAgent = addGreenlockAgent(opts); | ||||
| 
 | ||||
| 	var Greenlock = require("@root/greenlock"); | ||||
| 	var greenlock = Greenlock.create(opts); | ||||
|     var Greenlock = require("@root/greenlock"); | ||||
|     var greenlock = Greenlock.create(opts); | ||||
| 
 | ||||
| 	// re-export as top-level function to simplify rpc with workers
 | ||||
| 	greenlock.getAcmeHttp01ChallengeResponse = function(opts) { | ||||
| 		return greenlock.challenges.get(opts); | ||||
| 	}; | ||||
|     // re-export as top-level function to simplify rpc with workers
 | ||||
|     greenlock.getAcmeHttp01ChallengeResponse = function(opts) { | ||||
|         return greenlock.challenges.get(opts); | ||||
|     }; | ||||
| 
 | ||||
| 	return greenlock; | ||||
|     return greenlock; | ||||
| }; | ||||
| 
 | ||||
| function addGreenlockAgent(opts) { | ||||
| 	// Add greenlock as part of Agent, unless this is greenlock
 | ||||
| 	var packageAgent = opts.packageAgent || ""; | ||||
| 	if (!/greenlock(-express|-pro)?/i.test(packageAgent)) { | ||||
| 		var pkg = require("./package.json"); | ||||
| 		packageAgent += " Greenlock_Express/" + pkg.version; | ||||
| 	} | ||||
|     // Add greenlock as part of Agent, unless this is greenlock
 | ||||
|     var packageAgent = opts.packageAgent || ""; | ||||
|     if (!/greenlock(-express|-pro)?/i.test(packageAgent)) { | ||||
|         var pkg = require("./package.json"); | ||||
|         packageAgent += " Greenlock_Express/" + pkg.version; | ||||
|     } | ||||
| 
 | ||||
| 	return packageAgent.trim(); | ||||
|     return packageAgent.trim(); | ||||
| } | ||||
| 
 | ||||
| // ex: "John Doe <john@example.com> (https://john.doe)"
 | ||||
| @ -32,46 +32,46 @@ function addGreenlockAgent(opts) { | ||||
| // ex: "john@example.com"
 | ||||
| var looseEmailRe = /(^|[\s<])([^'" <>:;`]+@[^'" <>:;`]+\.[^'" <>:;`]+)/; | ||||
| function parsePackage(opts) { | ||||
| 	// 'package' is sometimes a reserved word
 | ||||
| 	var pkg = opts.package || opts.pkg; | ||||
| 	if (!pkg) { | ||||
| 		opts.maintainerEmail = parseMaintainer(opts.maintainerEmail); | ||||
| 		return opts; | ||||
| 	} | ||||
|     // 'package' is sometimes a reserved word
 | ||||
|     var pkg = opts.package || opts.pkg; | ||||
|     if (!pkg) { | ||||
|         opts.maintainerEmail = parseMaintainer(opts.maintainerEmail); | ||||
|         return opts; | ||||
|     } | ||||
| 
 | ||||
| 	if (!opts.packageAgent) { | ||||
| 		var err = "missing `package.THING`, which is used for the ACME client user agent string"; | ||||
| 		if (!pkg.name) { | ||||
| 			throw new Error(err.replace("THING", "name")); | ||||
| 		} | ||||
| 		if (!pkg.version) { | ||||
| 			throw new Error(err.replace("THING", "version")); | ||||
| 		} | ||||
| 		opts.packageAgent = pkg.name + "/" + pkg.version; | ||||
| 	} | ||||
|     if (!opts.packageAgent) { | ||||
|         var err = "missing `package.THING`, which is used for the ACME client user agent string"; | ||||
|         if (!pkg.name) { | ||||
|             throw new Error(err.replace("THING", "name")); | ||||
|         } | ||||
|         if (!pkg.version) { | ||||
|             throw new Error(err.replace("THING", "version")); | ||||
|         } | ||||
|         opts.packageAgent = pkg.name + "/" + pkg.version; | ||||
|     } | ||||
| 
 | ||||
| 	if (!opts.maintainerEmail) { | ||||
| 		try { | ||||
| 			opts.maintainerEmail = pkg.author.email || pkg.author.match(looseEmailRe)[2]; | ||||
| 		} catch (e) {} | ||||
| 	} | ||||
| 	if (!opts.maintainerEmail) { | ||||
| 		throw new Error("missing or malformed `package.author`, which is used as the contact for support notices"); | ||||
| 	} | ||||
| 	opts.package = undefined; | ||||
| 	opts.maintainerEmail = parseMaintainer(opts.maintainerEmail); | ||||
|     if (!opts.maintainerEmail) { | ||||
|         try { | ||||
|             opts.maintainerEmail = pkg.author.email || pkg.author.match(looseEmailRe)[2]; | ||||
|         } catch (e) {} | ||||
|     } | ||||
|     if (!opts.maintainerEmail) { | ||||
|         throw new Error("missing or malformed `package.author`, which is used as the contact for support notices"); | ||||
|     } | ||||
|     opts.package = undefined; | ||||
|     opts.maintainerEmail = parseMaintainer(opts.maintainerEmail); | ||||
| 
 | ||||
| 	return opts; | ||||
|     return opts; | ||||
| } | ||||
| 
 | ||||
| function parseMaintainer(maintainerEmail) { | ||||
| 	try { | ||||
| 		maintainerEmail = maintainerEmail.match(looseEmailRe)[2]; | ||||
| 	} catch (e) { | ||||
| 		maintainerEmail = null; | ||||
| 	} | ||||
| 	if (!maintainerEmail) { | ||||
| 		throw new Error("missing or malformed `maintainerEmail`, which is used as the contact for support notices"); | ||||
| 	} | ||||
| 	return maintainerEmail; | ||||
|     try { | ||||
|         maintainerEmail = maintainerEmail.match(looseEmailRe)[2]; | ||||
|     } catch (e) { | ||||
|         maintainerEmail = null; | ||||
|     } | ||||
|     if (!maintainerEmail) { | ||||
|         throw new Error("missing or malformed `maintainerEmail`, which is used as the contact for support notices"); | ||||
|     } | ||||
|     return maintainerEmail; | ||||
| } | ||||
|  | ||||
| @ -5,102 +5,102 @@ var servernameRe = /^[a-z0-9\.\-]+$/i; | ||||
| var challengePrefix = "/.well-known/acme-challenge/"; | ||||
| 
 | ||||
| HttpMiddleware.create = function(gl, defaultApp) { | ||||
| 	if (defaultApp && "function" !== typeof defaultApp) { | ||||
| 		throw new Error("use greenlock.httpMiddleware() or greenlock.httpMiddleware(function (req, res) {})"); | ||||
| 	} | ||||
|     if (defaultApp && "function" !== typeof defaultApp) { | ||||
|         throw new Error("use greenlock.httpMiddleware() or greenlock.httpMiddleware(function (req, res) {})"); | ||||
|     } | ||||
| 
 | ||||
| 	return function(req, res, next) { | ||||
| 		var hostname = HttpMiddleware.sanitizeHostname(req); | ||||
|     return function(req, res, next) { | ||||
|         var hostname = HttpMiddleware.sanitizeHostname(req); | ||||
| 
 | ||||
| 		req.on("error", function(err) { | ||||
| 			explainError(gl, err, "http_01_middleware_socket", hostname); | ||||
| 		}); | ||||
|         req.on("error", function(err) { | ||||
|             explainError(gl, err, "http_01_middleware_socket", hostname); | ||||
|         }); | ||||
| 
 | ||||
| 		if (skipIfNeedBe(req, res, next, defaultApp, hostname)) { | ||||
| 			return; | ||||
| 		} | ||||
|         if (skipIfNeedBe(req, res, next, defaultApp, hostname)) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| 		var token = req.url.slice(challengePrefix.length); | ||||
|         var token = req.url.slice(challengePrefix.length); | ||||
| 
 | ||||
| 		gl.getAcmeHttp01ChallengeResponse({ type: "http-01", servername: hostname, token: token }) | ||||
| 			.catch(function(err) { | ||||
| 				respondToError(gl, res, err, "http_01_middleware_challenge_response", hostname); | ||||
| 				return { __done: true }; | ||||
| 			}) | ||||
| 			.then(function(result) { | ||||
| 				if (result && result.__done) { | ||||
| 					return; | ||||
| 				} | ||||
| 				return respondWithGrace(res, result, hostname, token); | ||||
| 			}); | ||||
| 	}; | ||||
|         gl.getAcmeHttp01ChallengeResponse({ type: "http-01", servername: hostname, token: token }) | ||||
|             .catch(function(err) { | ||||
|                 respondToError(gl, res, err, "http_01_middleware_challenge_response", hostname); | ||||
|                 return { __done: true }; | ||||
|             }) | ||||
|             .then(function(result) { | ||||
|                 if (result && result.__done) { | ||||
|                     return; | ||||
|                 } | ||||
|                 return respondWithGrace(res, result, hostname, token); | ||||
|             }); | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| function skipIfNeedBe(req, res, next, defaultApp, hostname) { | ||||
| 	if (!hostname || 0 !== req.url.indexOf(challengePrefix)) { | ||||
| 		if ("function" === typeof defaultApp) { | ||||
| 			defaultApp(req, res, next); | ||||
| 		} else if ("function" === typeof next) { | ||||
| 			next(); | ||||
| 		} else { | ||||
| 			res.statusCode = 500; | ||||
| 			res.end("[500] Developer Error: app.use('/', greenlock.httpMiddleware()) or greenlock.httpMiddleware(app)"); | ||||
| 		} | ||||
| 	} | ||||
|     if (!hostname || 0 !== req.url.indexOf(challengePrefix)) { | ||||
|         if ("function" === typeof defaultApp) { | ||||
|             defaultApp(req, res, next); | ||||
|         } else if ("function" === typeof next) { | ||||
|             next(); | ||||
|         } else { | ||||
|             res.statusCode = 500; | ||||
|             res.end("[500] Developer Error: app.use('/', greenlock.httpMiddleware()) or greenlock.httpMiddleware(app)"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function respondWithGrace(res, result, hostname, token) { | ||||
| 	var keyAuth = result && result.keyAuthorization; | ||||
| 	if (keyAuth && "string" === typeof keyAuth) { | ||||
| 		res.setHeader("Content-Type", "text/plain; charset=utf-8"); | ||||
| 		res.end(keyAuth); | ||||
| 		return; | ||||
| 	} | ||||
|     var keyAuth = result && result.keyAuthorization; | ||||
|     if (keyAuth && "string" === typeof keyAuth) { | ||||
|         res.setHeader("Content-Type", "text/plain; charset=utf-8"); | ||||
|         res.end(keyAuth); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
| 	res.statusCode = 404; | ||||
| 	res.setHeader("Content-Type", "application/json; charset=utf-8"); | ||||
| 	res.end(JSON.stringify({ error: { message: "domain '" + hostname + "' has no token '" + token + "'." } })); | ||||
|     res.statusCode = 404; | ||||
|     res.setHeader("Content-Type", "application/json; charset=utf-8"); | ||||
|     res.end(JSON.stringify({ error: { message: "domain '" + hostname + "' has no token '" + token + "'." } })); | ||||
| } | ||||
| 
 | ||||
| function explainError(gl, err, ctx, hostname) { | ||||
| 	if (!err.servername) { | ||||
| 		err.servername = hostname; | ||||
| 	} | ||||
| 	if (!err.context) { | ||||
| 		err.context = ctx; | ||||
| 	} | ||||
| 	(gl.notify || gl._notify)("error", err); | ||||
| 	return err; | ||||
|     if (!err.servername) { | ||||
|         err.servername = hostname; | ||||
|     } | ||||
|     if (!err.context) { | ||||
|         err.context = ctx; | ||||
|     } | ||||
|     (gl.notify || gl._notify)("error", err); | ||||
|     return err; | ||||
| } | ||||
| 
 | ||||
| function respondToError(gl, res, err, ctx, hostname) { | ||||
| 	err = explainError(gl, err, ctx, hostname); | ||||
| 	res.statusCode = 500; | ||||
| 	res.end("Internal Server Error: See logs for details."); | ||||
|     err = explainError(gl, err, ctx, hostname); | ||||
|     res.statusCode = 500; | ||||
|     res.end("Internal Server Error: See logs for details."); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	// we can trust XFH because spoofing causes no ham in this limited use-case scenario
 | ||||
| 	// (and only telebit would be legitimately setting XFH)
 | ||||
| 	var servername = HttpMiddleware.getHostname(req) | ||||
| 		.toLowerCase() | ||||
| 		.replace(/:.*/, ""); | ||||
| 	try { | ||||
| 		req.hostname = servername; | ||||
| 	} catch (e) { | ||||
| 		// read-only express property
 | ||||
| 	} | ||||
| 	if (req.headers["x-forwarded-host"]) { | ||||
| 		req.headers["x-forwarded-host"] = servername; | ||||
| 	} | ||||
| 	try { | ||||
| 		req.headers.host = servername; | ||||
| 	} catch (e) { | ||||
| 		// TODO is this a possible error?
 | ||||
| 	} | ||||
|     // we can trust XFH because spoofing causes no ham in this limited use-case scenario
 | ||||
|     // (and only telebit would be legitimately setting XFH)
 | ||||
|     var servername = HttpMiddleware.getHostname(req) | ||||
|         .toLowerCase() | ||||
|         .replace(/:.*/, ""); | ||||
|     try { | ||||
|         req.hostname = servername; | ||||
|     } catch (e) { | ||||
|         // read-only express property
 | ||||
|     } | ||||
|     if (req.headers["x-forwarded-host"]) { | ||||
|         req.headers["x-forwarded-host"] = servername; | ||||
|     } | ||||
|     try { | ||||
|         req.headers.host = servername; | ||||
|     } catch (e) { | ||||
|         // 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"); | ||||
| 
 | ||||
| SanitizeHost.create = function(gl, app) { | ||||
| 	return function(req, res, next) { | ||||
| 		function realNext() { | ||||
| 			if ("function" === typeof app) { | ||||
| 				app(req, res); | ||||
| 			} else if ("function" === typeof next) { | ||||
| 				next(); | ||||
| 			} else { | ||||
| 				res.statusCode = 500; | ||||
| 				res.end("Error: no middleware assigned"); | ||||
| 			} | ||||
| 		} | ||||
|     return function(req, res, next) { | ||||
|         function realNext() { | ||||
|             if ("function" === typeof app) { | ||||
|                 app(req, res); | ||||
|             } else if ("function" === typeof next) { | ||||
|                 next(); | ||||
|             } else { | ||||
|                 res.statusCode = 500; | ||||
|                 res.end("Error: no middleware assigned"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 		var hostname = HttpMiddleware.getHostname(req); | ||||
| 		// Replace the hostname, and get the safe version
 | ||||
| 		var safehost = HttpMiddleware.sanitizeHostname(req); | ||||
|         var hostname = HttpMiddleware.getHostname(req); | ||||
|         // Replace the hostname, and get the safe version
 | ||||
|         var safehost = HttpMiddleware.sanitizeHostname(req); | ||||
| 
 | ||||
| 		// if no hostname, move along
 | ||||
| 		if (!hostname) { | ||||
| 			realNext(); | ||||
| 			return; | ||||
| 		} | ||||
|         // if no hostname, move along
 | ||||
|         if (!hostname) { | ||||
|             realNext(); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| 		// if there were unallowed characters, complain
 | ||||
| 		if (safehost.length !== hostname.length) { | ||||
| 			res.statusCode = 400; | ||||
| 			res.end("Malformed HTTP Header: 'Host: " + hostname + "'"); | ||||
| 			return; | ||||
| 		} | ||||
|         // if there were unallowed characters, complain
 | ||||
|         if (safehost.length !== hostname.length) { | ||||
|             res.statusCode = 400; | ||||
|             res.end("Malformed HTTP Header: 'Host: " + hostname + "'"); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| 		// Note: This sanitize function is also called on plain sockets, which don't need Domain Fronting checks
 | ||||
| 		if (req.socket.encrypted) { | ||||
| 			if (req.socket && "string" === typeof req.socket.servername) { | ||||
| 				// Workaround for https://github.com/nodejs/node/issues/22389
 | ||||
| 				if (!SanitizeHost._checkServername(safehost, req.socket)) { | ||||
| 					res.statusCode = 400; | ||||
| 					res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||
| 					res.end( | ||||
| 						"<h1>Domain Fronting Error</h1>" + | ||||
| 							"<p>This connection was secured using TLS/SSL for '" + | ||||
| 							(req.socket.servername || "").toLowerCase() + | ||||
| 							"'</p>" + | ||||
| 							"<p>The HTTP request specified 'Host: " + | ||||
| 							safehost + | ||||
| 							"', which is (obviously) different.</p>" + | ||||
| 							"<p>Because this looks like a domain fronting attack, the connection has been terminated.</p>" | ||||
| 					); | ||||
| 					return; | ||||
| 				} | ||||
| 			} | ||||
| 			/* | ||||
|         // Note: This sanitize function is also called on plain sockets, which don't need Domain Fronting checks
 | ||||
|         if (req.socket.encrypted) { | ||||
|             if (req.socket && "string" === typeof req.socket.servername) { | ||||
|                 // Workaround for https://github.com/nodejs/node/issues/22389
 | ||||
|                 if (!SanitizeHost._checkServername(safehost, req.socket)) { | ||||
|                     res.statusCode = 400; | ||||
|                     res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||
|                     res.end( | ||||
|                         "<h1>Domain Fronting Error</h1>" + | ||||
|                             "<p>This connection was secured using TLS/SSL for '" + | ||||
|                             (req.socket.servername || "").toLowerCase() + | ||||
|                             "'</p>" + | ||||
|                             "<p>The HTTP request specified 'Host: " + | ||||
|                             safehost + | ||||
|                             "', which is (obviously) different.</p>" + | ||||
|                             "<p>Because this looks like a domain fronting attack, the connection has been terminated.</p>" | ||||
|                     ); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|             /* | ||||
|       else if (safehost && !gl._skip_fronting_check) { | ||||
| 
 | ||||
| 				// 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;
 | ||||
| 			} | ||||
|       */ | ||||
| 		} | ||||
|         } | ||||
| 
 | ||||
| 		// carry on
 | ||||
| 		realNext(); | ||||
| 	}; | ||||
|         // carry on
 | ||||
|         realNext(); | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| var warnDomainFronting = true; | ||||
| var warnUnexpectedError = true; | ||||
| SanitizeHost._checkServername = function(safeHost, tlsSocket) { | ||||
| 	var servername = (tlsSocket.servername || "").toLowerCase(); | ||||
|     var servername = (tlsSocket.servername || "").toLowerCase(); | ||||
| 
 | ||||
| 	// acceptable: older IoT devices may lack SNI support
 | ||||
| 	if (!servername) { | ||||
| 		return true; | ||||
| 	} | ||||
| 	// acceptable: odd... but acceptable
 | ||||
| 	if (!safeHost) { | ||||
| 		return true; | ||||
| 	} | ||||
| 	if (safeHost === servername) { | ||||
| 		return true; | ||||
| 	} | ||||
|     // acceptable: older IoT devices may lack SNI support
 | ||||
|     if (!servername) { | ||||
|         return true; | ||||
|     } | ||||
|     // acceptable: odd... but acceptable
 | ||||
|     if (!safeHost) { | ||||
|         return true; | ||||
|     } | ||||
|     if (safeHost === servername) { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| 	if ("function" !== typeof tlsSocket.getCertificate) { | ||||
| 		// domain fronting attacks allowed
 | ||||
| 		if (warnDomainFronting) { | ||||
| 			// https://github.com/nodejs/node/issues/24095
 | ||||
| 			console.warn( | ||||
| 				"Warning: node " + | ||||
| 					process.version + | ||||
| 					" is vulnerable to domain fronting attacks. Please use node v11.2.0 or greater." | ||||
| 			); | ||||
| 			warnDomainFronting = false; | ||||
| 		} | ||||
| 		return true; | ||||
| 	} | ||||
|     if ("function" !== typeof tlsSocket.getCertificate) { | ||||
|         // domain fronting attacks allowed
 | ||||
|         if (warnDomainFronting) { | ||||
|             // https://github.com/nodejs/node/issues/24095
 | ||||
|             console.warn( | ||||
|                 "Warning: node " + | ||||
|                     process.version + | ||||
|                     " is vulnerable to domain fronting attacks. Please use node v11.2.0 or greater." | ||||
|             ); | ||||
|             warnDomainFronting = false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| 	// connection established with servername and session is re-used for allowed name
 | ||||
| 	// See https://github.com/nodejs/node/issues/24095
 | ||||
| 	var cert = tlsSocket.getCertificate(); | ||||
| 	try { | ||||
| 		// TODO optimize / cache?
 | ||||
| 		// *should* always have a string, right?
 | ||||
| 		// *should* always be lowercase already, right?
 | ||||
| 		//console.log(safeHost, cert.subject.CN, cert.subjectaltname);
 | ||||
| 		var isSubject = (cert.subject.CN || "").toLowerCase() === safeHost; | ||||
| 		if (isSubject) { | ||||
| 			return true; | ||||
| 		} | ||||
|     // connection established with servername and session is re-used for allowed name
 | ||||
|     // See https://github.com/nodejs/node/issues/24095
 | ||||
|     var cert = tlsSocket.getCertificate(); | ||||
|     try { | ||||
|         // TODO optimize / cache?
 | ||||
|         // *should* always have a string, right?
 | ||||
|         // *should* always be lowercase already, right?
 | ||||
|         //console.log(safeHost, cert.subject.CN, cert.subjectaltname);
 | ||||
|         var isSubject = (cert.subject.CN || "").toLowerCase() === safeHost; | ||||
|         if (isSubject) { | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
| 		var dnsnames = (cert.subjectaltname || "").split(/,\s+/); | ||||
| 		var inSanList = dnsnames.some(function(name) { | ||||
| 			// always prefixed with "DNS:"
 | ||||
| 			return safeHost === name.slice(4).toLowerCase(); | ||||
| 		}); | ||||
|         var dnsnames = (cert.subjectaltname || "").split(/,\s+/); | ||||
|         var inSanList = dnsnames.some(function(name) { | ||||
|             // always prefixed with "DNS:"
 | ||||
|             return safeHost === name.slice(4).toLowerCase(); | ||||
|         }); | ||||
| 
 | ||||
| 		if (inSanList) { | ||||
| 			return true; | ||||
| 		} | ||||
| 	} catch (e) { | ||||
| 		// not sure what else to do in this situation...
 | ||||
| 		if (warnUnexpectedError) { | ||||
| 			console.warn("Warning: encoutered error while performing domain fronting check: " + e.message); | ||||
| 			warnUnexpectedError = false; | ||||
| 		} | ||||
| 		return true; | ||||
| 	} | ||||
|         if (inSanList) { | ||||
|             return true; | ||||
|         } | ||||
|     } catch (e) { | ||||
|         // not sure what else to do in this situation...
 | ||||
|         if (warnUnexpectedError) { | ||||
|             console.warn("Warning: encoutered error while performing domain fronting check: " + e.message); | ||||
|             warnUnexpectedError = false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| 	return false; | ||||
|     return false; | ||||
| }; | ||||
|  | ||||
| @ -1,37 +1,37 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| function requireBluebird() { | ||||
| 	try { | ||||
| 		return require("bluebird"); | ||||
| 	} catch (e) { | ||||
| 		console.error(""); | ||||
| 		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(""); | ||||
| 		throw e; | ||||
| 	} | ||||
|     try { | ||||
|         return require("bluebird"); | ||||
|     } catch (e) { | ||||
|         console.error(""); | ||||
|         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(""); | ||||
|         throw e; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| if ("undefined" === typeof Promise) { | ||||
| 	global.Promise = requireBluebird(); | ||||
|     global.Promise = requireBluebird(); | ||||
| } | ||||
| 
 | ||||
| if ("function" !== typeof require("util").promisify) { | ||||
| 	require("util").promisify = requireBluebird().promisify; | ||||
|     require("util").promisify = requireBluebird().promisify; | ||||
| } | ||||
| 
 | ||||
| if (!console.debug) { | ||||
| 	console.debug = console.log; | ||||
|     console.debug = console.log; | ||||
| } | ||||
| 
 | ||||
| var fs = require("fs"); | ||||
| var fsAsync = {}; | ||||
| Object.keys(fs).forEach(function(key) { | ||||
| 	var fn = fs[key]; | ||||
| 	if ("function" !== typeof fn || !/[a-z]/.test(key[0])) { | ||||
| 		return; | ||||
| 	} | ||||
| 	fsAsync[key] = require("util").promisify(fn); | ||||
|     var fn = fs[key]; | ||||
|     if ("function" !== typeof fn || !/[a-z]/.test(key[0])) { | ||||
|         return; | ||||
|     } | ||||
|     fsAsync[key] = require("util").promisify(fn); | ||||
| }); | ||||
| 
 | ||||
| exports.fsAsync = fsAsync; | ||||
|  | ||||
							
								
								
									
										20
									
								
								main.js
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								main.js
									
									
									
									
									
								
							| @ -13,20 +13,20 @@ _hasSetSecureContext = !!require("https").createServer({}, function() {}).setSec | ||||
| 
 | ||||
| // TODO document in issues
 | ||||
| if (!_hasSetSecureContext) { | ||||
| 	// 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("         The default certificate may not be set."); | ||||
| 	shouldUpgrade = true; | ||||
|     // 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("         The default certificate may not be set."); | ||||
|     shouldUpgrade = true; | ||||
| } | ||||
| 
 | ||||
| if (major < 11 || (11 === major && minor < 2)) { | ||||
| 	// https://github.com/nodejs/node/issues/24095
 | ||||
| 	console.warn("Warning: node " + process.version + " is missing tlsSocket.getCertificate()."); | ||||
| 	console.warn("         This is necessary to guard against domain fronting attacks."); | ||||
| 	shouldUpgrade = true; | ||||
|     // https://github.com/nodejs/node/issues/24095
 | ||||
|     console.warn("Warning: node " + process.version + " is missing tlsSocket.getCertificate()."); | ||||
|     console.warn("         This is necessary to guard against domain fronting attacks."); | ||||
|     shouldUpgrade = true; | ||||
| } | ||||
| 
 | ||||
| if (shouldUpgrade) { | ||||
| 	console.warn("Warning: Please upgrade to node v11.2.0 or greater."); | ||||
| 	console.warn(); | ||||
|     console.warn("Warning: Please upgrade to node v11.2.0 or greater."); | ||||
|     console.warn(); | ||||
| } | ||||
|  | ||||
							
								
								
									
										244
									
								
								master.js
									
									
									
									
									
								
							
							
						
						
									
										244
									
								
								master.js
									
									
									
									
									
								
							| @ -9,152 +9,152 @@ var os = require("os"); | ||||
| var msgPrefix = "greenlock:"; | ||||
| 
 | ||||
| Master.create = function(opts) { | ||||
| 	var resolveCb; | ||||
| 	var _readyCb; | ||||
| 	var _kicked = false; | ||||
|     var resolveCb; | ||||
|     var _readyCb; | ||||
|     var _kicked = false; | ||||
| 
 | ||||
| 	var greenlock = require("./greenlock.js").create(opts); | ||||
|     var greenlock = require("./greenlock.js").create(opts); | ||||
| 
 | ||||
| 	var ready = new Promise(function(resolve) { | ||||
| 		resolveCb = resolve; | ||||
| 	}).then(function(fn) { | ||||
| 		_readyCb = fn; | ||||
| 		return fn; | ||||
| 	}); | ||||
|     var ready = new Promise(function(resolve) { | ||||
|         resolveCb = resolve; | ||||
|     }).then(function(fn) { | ||||
|         _readyCb = fn; | ||||
|         return fn; | ||||
|     }); | ||||
| 
 | ||||
| 	function kickoff() { | ||||
| 		if (_kicked) { | ||||
| 			return; | ||||
| 		} | ||||
| 		_kicked = true; | ||||
|     function kickoff() { | ||||
|         if (_kicked) { | ||||
|             return; | ||||
|         } | ||||
|         _kicked = true; | ||||
| 
 | ||||
| 		Master._spawnWorkers(opts, greenlock); | ||||
|         Master._spawnWorkers(opts, greenlock); | ||||
| 
 | ||||
| 		ready.then(function(fn) { | ||||
| 			// not sure what this API should be yet
 | ||||
| 			fn(); | ||||
| 		}); | ||||
| 	} | ||||
|         ready.then(function(fn) { | ||||
|             // not sure what this API should be yet
 | ||||
|             fn(); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| 	var master = { | ||||
| 		serve: function() { | ||||
| 			kickoff(); | ||||
| 			return master; | ||||
| 		}, | ||||
| 		master: function(fn) { | ||||
| 			if (_readyCb) { | ||||
| 				throw new Error("can't call master twice"); | ||||
| 			} | ||||
| 			kickoff(); | ||||
| 			resolveCb(fn); | ||||
| 			return master; | ||||
| 		} | ||||
| 	}; | ||||
| 	return master; | ||||
|     var master = { | ||||
|         serve: function() { | ||||
|             kickoff(); | ||||
|             return master; | ||||
|         }, | ||||
|         master: function(fn) { | ||||
|             if (_readyCb) { | ||||
|                 throw new Error("can't call master twice"); | ||||
|             } | ||||
|             kickoff(); | ||||
|             resolveCb(fn); | ||||
|             return master; | ||||
|         } | ||||
|     }; | ||||
|     return master; | ||||
| }; | ||||
| 
 | ||||
| function range(n) { | ||||
| 	n = parseInt(n, 10); | ||||
| 	if (!n) { | ||||
| 		return []; | ||||
| 	} | ||||
| 	return new Array(n).join(",").split(","); | ||||
|     n = parseInt(n, 10); | ||||
|     if (!n) { | ||||
|         return []; | ||||
|     } | ||||
|     return new Array(n).join(",").split(","); | ||||
| } | ||||
| 
 | ||||
| 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
 | ||||
| 	// start when dead
 | ||||
| 	var numWorkers = parseInt(opts.workers || opts.numWorkers, 10); | ||||
| 	if (!numWorkers) { | ||||
| 		if (numCpus <= 2) { | ||||
| 			numWorkers = 2; | ||||
| 		} else { | ||||
| 			numWorkers = numCpus - 1; | ||||
| 		} | ||||
| 	} | ||||
|     // process rpc messages
 | ||||
|     // start when dead
 | ||||
|     var numWorkers = parseInt(opts.workers || opts.numWorkers, 10); | ||||
|     if (!numWorkers) { | ||||
|         if (numCpus <= 2) { | ||||
|             numWorkers = 2; | ||||
|         } else { | ||||
|             numWorkers = numCpus - 1; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	cluster.once("exit", function() { | ||||
| 		setTimeout(function() { | ||||
| 			process.exit(3); | ||||
| 		}, 100); | ||||
| 	}); | ||||
|     cluster.once("exit", function() { | ||||
|         setTimeout(function() { | ||||
|             process.exit(3); | ||||
|         }, 100); | ||||
|     }); | ||||
| 
 | ||||
| 	var workers = range(numWorkers); | ||||
| 	function next() { | ||||
| 		if (!workers.length) { | ||||
| 			return; | ||||
| 		} | ||||
| 		workers.pop(); | ||||
|     var workers = range(numWorkers); | ||||
|     function next() { | ||||
|         if (!workers.length) { | ||||
|             return; | ||||
|         } | ||||
|         workers.pop(); | ||||
| 
 | ||||
| 		// for a nice aesthetic
 | ||||
| 		setTimeout(function() { | ||||
| 			Master._spawnWorker(opts, greenlock); | ||||
| 			next(); | ||||
| 		}, 250); | ||||
| 	} | ||||
|         // for a nice aesthetic
 | ||||
|         setTimeout(function() { | ||||
|             Master._spawnWorker(opts, greenlock); | ||||
|             next(); | ||||
|         }, 250); | ||||
|     } | ||||
| 
 | ||||
| 	next(); | ||||
|     next(); | ||||
| }; | ||||
| 
 | ||||
| Master._spawnWorker = function(opts, greenlock) { | ||||
| 	var w = cluster.fork(); | ||||
| 	// automatically added to master's `cluster.workers`
 | ||||
| 	w.once("exit", function(code, signal) { | ||||
| 		// TODO handle failures
 | ||||
| 		// Should test if the first starts successfully
 | ||||
| 		// Should exit if failures happen too quickly
 | ||||
|     var w = cluster.fork(); | ||||
|     // automatically added to master's `cluster.workers`
 | ||||
|     w.once("exit", function(code, signal) { | ||||
|         // TODO handle failures
 | ||||
|         // Should test if the first starts successfully
 | ||||
|         // Should exit if failures happen too quickly
 | ||||
| 
 | ||||
| 		// For now just kill all when any die
 | ||||
| 		if (signal) { | ||||
| 			console.error("worker was killed by signal:", signal); | ||||
| 		} else if (code !== 0) { | ||||
| 			console.error("worker exited with error code:", code); | ||||
| 		} else { | ||||
| 			console.error("worker unexpectedly quit without exit code or signal"); | ||||
| 		} | ||||
| 		process.exit(2); | ||||
|         // For now just kill all when any die
 | ||||
|         if (signal) { | ||||
|             console.error("worker was killed by signal:", signal); | ||||
|         } else if (code !== 0) { | ||||
|             console.error("worker exited with error code:", code); | ||||
|         } else { | ||||
|             console.error("worker unexpectedly quit without exit code or signal"); | ||||
|         } | ||||
|         process.exit(2); | ||||
| 
 | ||||
| 		//addWorker();
 | ||||
| 	}); | ||||
|         //addWorker();
 | ||||
|     }); | ||||
| 
 | ||||
| 	function handleMessage(msg) { | ||||
| 		if (0 !== (msg._id || "").indexOf(msgPrefix)) { | ||||
| 			return; | ||||
| 		} | ||||
| 		if ("string" !== typeof msg._funcname) { | ||||
| 			// TODO developer error
 | ||||
| 			return; | ||||
| 		} | ||||
|     function handleMessage(msg) { | ||||
|         if (0 !== (msg._id || "").indexOf(msgPrefix)) { | ||||
|             return; | ||||
|         } | ||||
|         if ("string" !== typeof msg._funcname) { | ||||
|             // TODO developer error
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| 		function rpc() { | ||||
| 			return greenlock[msg._funcname](msg._input) | ||||
| 				.then(function(result) { | ||||
| 					w.send({ | ||||
| 						_id: msg._id, | ||||
| 						_result: result | ||||
| 					}); | ||||
| 				}) | ||||
| 				.catch(function(e) { | ||||
| 					var error = new Error(e.message); | ||||
| 					Object.getOwnPropertyNames(e).forEach(function(k) { | ||||
| 						error[k] = e[k]; | ||||
| 					}); | ||||
| 					w.send({ | ||||
| 						_id: msg._id, | ||||
| 						_error: error | ||||
| 					}); | ||||
| 				}); | ||||
| 		} | ||||
|         function rpc() { | ||||
|             return greenlock[msg._funcname](msg._input) | ||||
|                 .then(function(result) { | ||||
|                     w.send({ | ||||
|                         _id: msg._id, | ||||
|                         _result: result | ||||
|                     }); | ||||
|                 }) | ||||
|                 .catch(function(e) { | ||||
|                     var error = new Error(e.message); | ||||
|                     Object.getOwnPropertyNames(e).forEach(function(k) { | ||||
|                         error[k] = e[k]; | ||||
|                     }); | ||||
|                     w.send({ | ||||
|                         _id: msg._id, | ||||
|                         _error: error | ||||
|                     }); | ||||
|                 }); | ||||
|         } | ||||
| 
 | ||||
| 		try { | ||||
| 			rpc(); | ||||
| 		} catch (e) { | ||||
| 			console.error("Unexpected and uncaught greenlock." + msg._funcname + " error:"); | ||||
| 			console.error(e); | ||||
| 		} | ||||
| 	} | ||||
|         try { | ||||
|             rpc(); | ||||
|         } catch (e) { | ||||
|             console.error("Unexpected and uncaught greenlock." + msg._funcname + " error:"); | ||||
|             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", | ||||
| 	"version": "3.0.11", | ||||
| 	"lockfileVersion": 1, | ||||
| 	"requires": true, | ||||
| 	"dependencies": { | ||||
| 		"@root/acme": { | ||||
| 			"version": "3.0.8", | ||||
| 			"resolved": "https://registry.npmjs.org/@root/acme/-/acme-3.0.8.tgz", | ||||
| 			"integrity": "sha512-VmBvLvWdCDkolkanI9Dzm1ouSWPaAa2eCCwcDZcVQbWoNiUIOqbbd57fcMA/gZxLyuJPStD2WXFuEuSMPDxcww==", | ||||
| 			"requires": { | ||||
| 				"@root/encoding": "^1.0.1", | ||||
| 				"@root/keypairs": "^0.9.0", | ||||
| 				"@root/pem": "^1.0.4", | ||||
| 				"@root/request": "^1.3.11", | ||||
| 				"@root/x509": "^0.7.2" | ||||
| 			} | ||||
| 		}, | ||||
| 		"@root/asn1": { | ||||
| 			"version": "1.0.0", | ||||
| 			"resolved": "https://registry.npmjs.org/@root/asn1/-/asn1-1.0.0.tgz", | ||||
| 			"integrity": "sha512-0lfZNuOULKJDJmdIkP8V9RnbV3XaK6PAHD3swnFy4tZwtlMDzLKoM/dfNad7ut8Hu3r91wy9uK0WA/9zym5mig==", | ||||
| 			"requires": { | ||||
| 				"@root/encoding": "^1.0.1" | ||||
| 			} | ||||
| 		}, | ||||
| 		"@root/csr": { | ||||
| 			"version": "0.8.1", | ||||
| 			"resolved": "https://registry.npmjs.org/@root/csr/-/csr-0.8.1.tgz", | ||||
| 			"integrity": "sha512-hKl0VuE549TK6SnS2Yn9nRvKbFZXn/oAg+dZJU/tlKl/f/0yRXeuUzf8akg3JjtJq+9E592zDqeXZ7yyrg8fSQ==", | ||||
| 			"requires": { | ||||
| 				"@root/asn1": "^1.0.0", | ||||
| 				"@root/pem": "^1.0.4", | ||||
| 				"@root/x509": "^0.7.2" | ||||
| 			} | ||||
| 		}, | ||||
| 		"@root/encoding": { | ||||
| 			"version": "1.0.1", | ||||
| 			"resolved": "https://registry.npmjs.org/@root/encoding/-/encoding-1.0.1.tgz", | ||||
| 			"integrity": "sha512-OaEub02ufoU038gy6bsNHQOjIn8nUjGiLcaRmJ40IUykneJkIW5fxDqKxQx48cszuNflYldsJLPPXCrGfHs8yQ==" | ||||
| 		}, | ||||
| 		"@root/greenlock": { | ||||
| 			"version": "3.0.25", | ||||
| 			"resolved": "https://registry.npmjs.org/@root/greenlock/-/greenlock-3.0.25.tgz", | ||||
| 			"integrity": "sha512-VC8H9MTkbqxlB2LGntmcq5cstkE0TdZLvxm25SO5i7c6abJBVMQafhTD415OXwoGimnmWTn6SZ93Fj73d9QX/w==", | ||||
| 			"requires": { | ||||
| 				"@root/acme": "^3.0.8", | ||||
| 				"@root/csr": "^0.8.1", | ||||
| 				"@root/keypairs": "^0.9.0", | ||||
| 				"@root/mkdirp": "^1.0.0", | ||||
| 				"@root/request": "^1.3.10", | ||||
| 				"acme-http-01-standalone": "^3.0.5", | ||||
| 				"cert-info": "^1.5.1", | ||||
| 				"greenlock-manager-fs": "^3.0.1", | ||||
| 				"greenlock-store-fs": "^3.2.0", | ||||
| 				"safe-replace": "^1.1.0" | ||||
| 			} | ||||
| 		}, | ||||
| 		"@root/keypairs": { | ||||
| 			"version": "0.9.0", | ||||
| 			"resolved": "https://registry.npmjs.org/@root/keypairs/-/keypairs-0.9.0.tgz", | ||||
| 			"integrity": "sha512-NXE2L9Gv7r3iC4kB/gTPZE1vO9Ox/p14zDzAJ5cGpTpytbWOlWF7QoHSJbtVX4H7mRG/Hp7HR3jWdWdb2xaaXg==", | ||||
| 			"requires": { | ||||
| 				"@root/encoding": "^1.0.1", | ||||
| 				"@root/pem": "^1.0.4", | ||||
| 				"@root/x509": "^0.7.2" | ||||
| 			} | ||||
| 		}, | ||||
| 		"@root/mkdirp": { | ||||
| 			"version": "1.0.0", | ||||
| 			"resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz", | ||||
| 			"integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA==" | ||||
| 		}, | ||||
| 		"@root/pem": { | ||||
| 			"version": "1.0.4", | ||||
| 			"resolved": "https://registry.npmjs.org/@root/pem/-/pem-1.0.4.tgz", | ||||
| 			"integrity": "sha512-rEUDiUsHtild8GfIjFE9wXtcVxeS+ehCJQBwbQQ3IVfORKHK93CFnRtkr69R75lZFjcmKYVc+AXDB+AeRFOULA==" | ||||
| 		}, | ||||
| 		"@root/request": { | ||||
| 			"version": "1.4.2", | ||||
| 			"resolved": "https://registry.npmjs.org/@root/request/-/request-1.4.2.tgz", | ||||
| 			"integrity": "sha512-J8FM4+SJuc7WRC+Jz17m+VT2lgI7HtatHhxN1F2ck5aIKUAxJEaR4u/gLBsgT60mVHevKCjKN0O8115UtJjwLw==" | ||||
| 		}, | ||||
| 		"@root/x509": { | ||||
| 			"version": "0.7.2", | ||||
| 			"resolved": "https://registry.npmjs.org/@root/x509/-/x509-0.7.2.tgz", | ||||
| 			"integrity": "sha512-ENq3LGYORK5NiMFHEVeNMt+fTXaC7DTS6sQXoqV+dFdfT0vmiL5cDLjaXQhaklJQq0NiwicZegzJRl1ZOTp3WQ==", | ||||
| 			"requires": { | ||||
| 				"@root/asn1": "^1.0.0", | ||||
| 				"@root/encoding": "^1.0.1" | ||||
| 			} | ||||
| 		}, | ||||
| 		"acme-http-01-standalone": { | ||||
| 			"version": "3.0.5", | ||||
| 			"resolved": "https://registry.npmjs.org/acme-http-01-standalone/-/acme-http-01-standalone-3.0.5.tgz", | ||||
| 			"integrity": "sha512-W4GfK+39GZ+u0mvxRVUcVFCG6gposfzEnSBF20T/NUwWAKG59wQT1dUbS1NixRIAsRuhpGc4Jx659cErFQH0Pg==" | ||||
| 		}, | ||||
| 		"cert-info": { | ||||
| 			"version": "1.5.1", | ||||
| 			"resolved": "https://registry.npmjs.org/cert-info/-/cert-info-1.5.1.tgz", | ||||
| 			"integrity": "sha512-eoQC/yAgW3gKTKxjzyClvi+UzuY97YCjcl+lSqbsGIy7HeGaWxCPOQFivhUYm27hgsBMhsJJFya3kGvK6PMIcQ==" | ||||
| 		}, | ||||
| 		"escape-html": { | ||||
| 			"version": "1.0.3", | ||||
| 			"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", | ||||
| 			"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" | ||||
| 		}, | ||||
| 		"greenlock-manager-fs": { | ||||
| 			"version": "3.0.1", | ||||
| 			"resolved": "https://registry.npmjs.org/greenlock-manager-fs/-/greenlock-manager-fs-3.0.1.tgz", | ||||
| 			"integrity": "sha512-vZfGFq1TTKxaAqdGDUwNservrNzXx0xCwT/ovG/N378GrhS+U5S8B8LUlNtQU7Fdw6RToMiBcm22OOxSrvZ2zw==", | ||||
| 			"requires": { | ||||
| 				"@root/mkdirp": "^1.0.0", | ||||
| 				"safe-replace": "^1.1.0" | ||||
| 			} | ||||
| 		}, | ||||
| 		"greenlock-store-fs": { | ||||
| 			"version": "3.2.0", | ||||
| 			"resolved": "https://registry.npmjs.org/greenlock-store-fs/-/greenlock-store-fs-3.2.0.tgz", | ||||
| 			"integrity": "sha512-zqcPnF+173oYq5qU7FoGtuqeG8dmmvAiSnz98kEHAHyvgRF9pE1T0MM0AuqDdj45I3kXlCj2gZBwutnRi37J3g==", | ||||
| 			"requires": { | ||||
| 				"@root/mkdirp": "^1.0.0", | ||||
| 				"safe-replace": "^1.1.0" | ||||
| 			} | ||||
| 		}, | ||||
| 		"redirect-https": { | ||||
| 			"version": "1.3.0", | ||||
| 			"resolved": "https://registry.npmjs.org/redirect-https/-/redirect-https-1.3.0.tgz", | ||||
| 			"integrity": "sha512-9GzwI/+Cqw3jlSg0CW6TgBQbhiVhkHSDvW8wjgRQ9IK34wtxS71YJiQeazSCSEqbvowHCJuQZgmQFl1xUHKEgg==", | ||||
| 			"requires": { | ||||
| 				"escape-html": "^1.0.3" | ||||
| 			} | ||||
| 		}, | ||||
| 		"safe-replace": { | ||||
| 			"version": "1.1.0", | ||||
| 			"resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz", | ||||
| 			"integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw==" | ||||
| 		} | ||||
| 	} | ||||
|     "name": "@root/greenlock-express", | ||||
|     "version": "3.0.13", | ||||
|     "lockfileVersion": 1, | ||||
|     "requires": true, | ||||
|     "dependencies": { | ||||
|         "@root/acme": { | ||||
|             "version": "3.0.8", | ||||
|             "resolved": "https://registry.npmjs.org/@root/acme/-/acme-3.0.8.tgz", | ||||
|             "integrity": "sha512-VmBvLvWdCDkolkanI9Dzm1ouSWPaAa2eCCwcDZcVQbWoNiUIOqbbd57fcMA/gZxLyuJPStD2WXFuEuSMPDxcww==", | ||||
|             "requires": { | ||||
|                 "@root/encoding": "^1.0.1", | ||||
|                 "@root/keypairs": "^0.9.0", | ||||
|                 "@root/pem": "^1.0.4", | ||||
|                 "@root/request": "^1.3.11", | ||||
|                 "@root/x509": "^0.7.2" | ||||
|             } | ||||
|         }, | ||||
|         "@root/asn1": { | ||||
|             "version": "1.0.0", | ||||
|             "resolved": "https://registry.npmjs.org/@root/asn1/-/asn1-1.0.0.tgz", | ||||
|             "integrity": "sha512-0lfZNuOULKJDJmdIkP8V9RnbV3XaK6PAHD3swnFy4tZwtlMDzLKoM/dfNad7ut8Hu3r91wy9uK0WA/9zym5mig==", | ||||
|             "requires": { | ||||
|                 "@root/encoding": "^1.0.1" | ||||
|             } | ||||
|         }, | ||||
|         "@root/csr": { | ||||
|             "version": "0.8.1", | ||||
|             "resolved": "https://registry.npmjs.org/@root/csr/-/csr-0.8.1.tgz", | ||||
|             "integrity": "sha512-hKl0VuE549TK6SnS2Yn9nRvKbFZXn/oAg+dZJU/tlKl/f/0yRXeuUzf8akg3JjtJq+9E592zDqeXZ7yyrg8fSQ==", | ||||
|             "requires": { | ||||
|                 "@root/asn1": "^1.0.0", | ||||
|                 "@root/pem": "^1.0.4", | ||||
|                 "@root/x509": "^0.7.2" | ||||
|             } | ||||
|         }, | ||||
|         "@root/encoding": { | ||||
|             "version": "1.0.1", | ||||
|             "resolved": "https://registry.npmjs.org/@root/encoding/-/encoding-1.0.1.tgz", | ||||
|             "integrity": "sha512-OaEub02ufoU038gy6bsNHQOjIn8nUjGiLcaRmJ40IUykneJkIW5fxDqKxQx48cszuNflYldsJLPPXCrGfHs8yQ==" | ||||
|         }, | ||||
|         "@root/greenlock": { | ||||
|             "version": "3.0.25", | ||||
|             "resolved": "https://registry.npmjs.org/@root/greenlock/-/greenlock-3.0.25.tgz", | ||||
|             "integrity": "sha512-VC8H9MTkbqxlB2LGntmcq5cstkE0TdZLvxm25SO5i7c6abJBVMQafhTD415OXwoGimnmWTn6SZ93Fj73d9QX/w==", | ||||
|             "requires": { | ||||
|                 "@root/acme": "^3.0.8", | ||||
|                 "@root/csr": "^0.8.1", | ||||
|                 "@root/keypairs": "^0.9.0", | ||||
|                 "@root/mkdirp": "^1.0.0", | ||||
|                 "@root/request": "^1.3.10", | ||||
|                 "acme-http-01-standalone": "^3.0.5", | ||||
|                 "cert-info": "^1.5.1", | ||||
|                 "greenlock-manager-fs": "^3.0.1", | ||||
|                 "greenlock-store-fs": "^3.2.0", | ||||
|                 "safe-replace": "^1.1.0" | ||||
|             } | ||||
|         }, | ||||
|         "@root/keypairs": { | ||||
|             "version": "0.9.0", | ||||
|             "resolved": "https://registry.npmjs.org/@root/keypairs/-/keypairs-0.9.0.tgz", | ||||
|             "integrity": "sha512-NXE2L9Gv7r3iC4kB/gTPZE1vO9Ox/p14zDzAJ5cGpTpytbWOlWF7QoHSJbtVX4H7mRG/Hp7HR3jWdWdb2xaaXg==", | ||||
|             "requires": { | ||||
|                 "@root/encoding": "^1.0.1", | ||||
|                 "@root/pem": "^1.0.4", | ||||
|                 "@root/x509": "^0.7.2" | ||||
|             } | ||||
|         }, | ||||
|         "@root/mkdirp": { | ||||
|             "version": "1.0.0", | ||||
|             "resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz", | ||||
|             "integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA==" | ||||
|         }, | ||||
|         "@root/pem": { | ||||
|             "version": "1.0.4", | ||||
|             "resolved": "https://registry.npmjs.org/@root/pem/-/pem-1.0.4.tgz", | ||||
|             "integrity": "sha512-rEUDiUsHtild8GfIjFE9wXtcVxeS+ehCJQBwbQQ3IVfORKHK93CFnRtkr69R75lZFjcmKYVc+AXDB+AeRFOULA==" | ||||
|         }, | ||||
|         "@root/request": { | ||||
|             "version": "1.4.2", | ||||
|             "resolved": "https://registry.npmjs.org/@root/request/-/request-1.4.2.tgz", | ||||
|             "integrity": "sha512-J8FM4+SJuc7WRC+Jz17m+VT2lgI7HtatHhxN1F2ck5aIKUAxJEaR4u/gLBsgT60mVHevKCjKN0O8115UtJjwLw==" | ||||
|         }, | ||||
|         "@root/x509": { | ||||
|             "version": "0.7.2", | ||||
|             "resolved": "https://registry.npmjs.org/@root/x509/-/x509-0.7.2.tgz", | ||||
|             "integrity": "sha512-ENq3LGYORK5NiMFHEVeNMt+fTXaC7DTS6sQXoqV+dFdfT0vmiL5cDLjaXQhaklJQq0NiwicZegzJRl1ZOTp3WQ==", | ||||
|             "requires": { | ||||
|                 "@root/asn1": "^1.0.0", | ||||
|                 "@root/encoding": "^1.0.1" | ||||
|             } | ||||
|         }, | ||||
|         "acme-http-01-standalone": { | ||||
|             "version": "3.0.5", | ||||
|             "resolved": "https://registry.npmjs.org/acme-http-01-standalone/-/acme-http-01-standalone-3.0.5.tgz", | ||||
|             "integrity": "sha512-W4GfK+39GZ+u0mvxRVUcVFCG6gposfzEnSBF20T/NUwWAKG59wQT1dUbS1NixRIAsRuhpGc4Jx659cErFQH0Pg==" | ||||
|         }, | ||||
|         "cert-info": { | ||||
|             "version": "1.5.1", | ||||
|             "resolved": "https://registry.npmjs.org/cert-info/-/cert-info-1.5.1.tgz", | ||||
|             "integrity": "sha512-eoQC/yAgW3gKTKxjzyClvi+UzuY97YCjcl+lSqbsGIy7HeGaWxCPOQFivhUYm27hgsBMhsJJFya3kGvK6PMIcQ==" | ||||
|         }, | ||||
|         "escape-html": { | ||||
|             "version": "1.0.3", | ||||
|             "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", | ||||
|             "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" | ||||
|         }, | ||||
|         "greenlock-manager-fs": { | ||||
|             "version": "3.0.1", | ||||
|             "resolved": "https://registry.npmjs.org/greenlock-manager-fs/-/greenlock-manager-fs-3.0.1.tgz", | ||||
|             "integrity": "sha512-vZfGFq1TTKxaAqdGDUwNservrNzXx0xCwT/ovG/N378GrhS+U5S8B8LUlNtQU7Fdw6RToMiBcm22OOxSrvZ2zw==", | ||||
|             "requires": { | ||||
|                 "@root/mkdirp": "^1.0.0", | ||||
|                 "safe-replace": "^1.1.0" | ||||
|             } | ||||
|         }, | ||||
|         "greenlock-store-fs": { | ||||
|             "version": "3.2.0", | ||||
|             "resolved": "https://registry.npmjs.org/greenlock-store-fs/-/greenlock-store-fs-3.2.0.tgz", | ||||
|             "integrity": "sha512-zqcPnF+173oYq5qU7FoGtuqeG8dmmvAiSnz98kEHAHyvgRF9pE1T0MM0AuqDdj45I3kXlCj2gZBwutnRi37J3g==", | ||||
|             "requires": { | ||||
|                 "@root/mkdirp": "^1.0.0", | ||||
|                 "safe-replace": "^1.1.0" | ||||
|             } | ||||
|         }, | ||||
|         "redirect-https": { | ||||
|             "version": "1.3.0", | ||||
|             "resolved": "https://registry.npmjs.org/redirect-https/-/redirect-https-1.3.0.tgz", | ||||
|             "integrity": "sha512-9GzwI/+Cqw3jlSg0CW6TgBQbhiVhkHSDvW8wjgRQ9IK34wtxS71YJiQeazSCSEqbvowHCJuQZgmQFl1xUHKEgg==", | ||||
|             "requires": { | ||||
|                 "escape-html": "^1.0.3" | ||||
|             } | ||||
|         }, | ||||
|         "safe-replace": { | ||||
|             "version": "1.1.0", | ||||
|             "resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz", | ||||
|             "integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw==" | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										98
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										98
									
								
								package.json
									
									
									
									
									
								
							| @ -1,51 +1,51 @@ | ||||
| { | ||||
| 	"name": "@root/greenlock-express", | ||||
| 	"version": "3.0.12", | ||||
| 	"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", | ||||
| 	"homepage": "https://greenlock.domains", | ||||
| 	"files": [ | ||||
| 		"*.js", | ||||
| 		"lib", | ||||
| 		"scripts" | ||||
| 	], | ||||
| 	"scripts": { | ||||
| 		"start": "node_todo server.js ./config.js", | ||||
| 		"test": "node_todo test/greenlock.js" | ||||
| 	}, | ||||
| 	"directories": { | ||||
| 		"example": "examples" | ||||
| 	}, | ||||
| 	"dependencies": { | ||||
| 		"@root/greenlock": "^3.0.25", | ||||
| 		"redirect-https": "^1.1.5" | ||||
| 	}, | ||||
| 	"trulyOptionalDependencies": { | ||||
| 		"http-proxy": "^1.17.0", | ||||
| 		"express": "^4.16.3", | ||||
| 		"express-basic-auth": "^1.2.0", | ||||
| 		"finalhandler": "^1.1.1", | ||||
| 		"serve-index": "^1.9.1", | ||||
| 		"serve-static": "^1.13.2", | ||||
| 		"ws": "^5.2.1" | ||||
| 	}, | ||||
| 	"devDependencies": {}, | ||||
| 	"repository": { | ||||
| 		"type": "git", | ||||
| 		"url": "https://git.rootprojects.org/root/greenlock-express.js.git" | ||||
| 	}, | ||||
| 	"keywords": [ | ||||
| 		"Let's Encrypt", | ||||
| 		"ACME", | ||||
| 		"greenlock", | ||||
| 		"Free SSL", | ||||
| 		"Automated HTTPS", | ||||
| 		"https", | ||||
| 		"tls" | ||||
| 	], | ||||
| 	"author": "AJ ONeal <coolaj86@gmail.com> (https://solderjs.com/)", | ||||
| 	"license": "MPL-2.0", | ||||
| 	"bugs": { | ||||
| 		"url": "https://git.rootprojects.org/root/greenlock-express.js/issues" | ||||
| 	} | ||||
|     "name": "@root/greenlock-express", | ||||
|     "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.", | ||||
|     "main": "greenlock-express.js", | ||||
|     "homepage": "https://greenlock.domains", | ||||
|     "files": [ | ||||
|         "*.js", | ||||
|         "lib", | ||||
|         "scripts" | ||||
|     ], | ||||
|     "scripts": { | ||||
|         "start": "node_todo server.js ./config.js", | ||||
|         "test": "node_todo test/greenlock.js" | ||||
|     }, | ||||
|     "directories": { | ||||
|         "example": "examples" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@root/greenlock": "^3.0.25", | ||||
|         "redirect-https": "^1.1.5" | ||||
|     }, | ||||
|     "trulyOptionalDependencies": { | ||||
|         "http-proxy": "^1.17.0", | ||||
|         "express": "^4.16.3", | ||||
|         "express-basic-auth": "^1.2.0", | ||||
|         "finalhandler": "^1.1.1", | ||||
|         "serve-index": "^1.9.1", | ||||
|         "serve-static": "^1.13.2", | ||||
|         "ws": "^5.2.1" | ||||
|     }, | ||||
|     "devDependencies": {}, | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|         "url": "https://git.rootprojects.org/root/greenlock-express.js.git" | ||||
|     }, | ||||
|     "keywords": [ | ||||
|         "Let's Encrypt", | ||||
|         "ACME", | ||||
|         "greenlock", | ||||
|         "Free SSL", | ||||
|         "Automated HTTPS", | ||||
|         "https", | ||||
|         "tls" | ||||
|     ], | ||||
|     "author": "AJ ONeal <coolaj86@gmail.com> (https://solderjs.com/)", | ||||
|     "license": "MPL-2.0", | ||||
|     "bugs": { | ||||
|         "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"); | ||||
| 
 | ||||
| Servers.create = function(greenlock) { | ||||
| 	var servers = {}; | ||||
| 	var _httpServer; | ||||
| 	var _httpsServer; | ||||
|     var servers = {}; | ||||
|     var _httpServer; | ||||
|     var _httpsServer; | ||||
| 
 | ||||
| 	function startError(e) { | ||||
| 		explainError(e); | ||||
| 		process.exit(1); | ||||
| 	} | ||||
|     function startError(e) { | ||||
|         explainError(e); | ||||
|         process.exit(1); | ||||
|     } | ||||
| 
 | ||||
| 	servers.httpServer = function(defaultApp) { | ||||
| 		if (_httpServer) { | ||||
| 			return _httpServer; | ||||
| 		} | ||||
|     servers.httpServer = function(defaultApp) { | ||||
|         if (_httpServer) { | ||||
|             return _httpServer; | ||||
|         } | ||||
| 
 | ||||
| 		_httpServer = http.createServer(HttpMiddleware.create(greenlock, defaultApp)); | ||||
| 		_httpServer.once("error", startError); | ||||
|         _httpServer = http.createServer(HttpMiddleware.create(greenlock, defaultApp)); | ||||
|         _httpServer.once("error", startError); | ||||
| 
 | ||||
| 		return _httpServer; | ||||
| 	}; | ||||
|         return _httpServer; | ||||
|     }; | ||||
| 
 | ||||
| 	var _middlewareApp; | ||||
|     var _middlewareApp; | ||||
| 
 | ||||
| 	servers.http2Server = function(secureOpts, defaultApp) { | ||||
| 		return servers._httpsServer(secureOpts, defaultApp, function(secureOpts, fn) { | ||||
| 			secureOpts.allowHTTP1 = true; | ||||
| 			return require("http2").createSecureServer(secureOpts, fn); | ||||
| 		}); | ||||
| 	}; | ||||
| 	servers.httpsServer = function(secureOpts, defaultApp) { | ||||
| 		return servers._httpsServer(secureOpts, defaultApp, function(secureOpts, fn) { | ||||
| 			return require("https").createServer(secureOpts, fn); | ||||
| 		}); | ||||
| 	}; | ||||
| 	servers._httpsServer = function(secureOpts, defaultApp, createSecureServer) { | ||||
| 		if (defaultApp) { | ||||
| 			// TODO guard against being set twice?
 | ||||
| 			_middlewareApp = defaultApp; | ||||
| 		} | ||||
|     servers.http2Server = function(secureOpts, defaultApp) { | ||||
|         return servers._httpsServer(secureOpts, defaultApp, function(secureOpts, fn) { | ||||
|             secureOpts.allowHTTP1 = true; | ||||
|             return require("http2").createSecureServer(secureOpts, fn); | ||||
|         }); | ||||
|     }; | ||||
|     servers.httpsServer = function(secureOpts, defaultApp) { | ||||
|         return servers._httpsServer(secureOpts, defaultApp, function(secureOpts, fn) { | ||||
|             return require("https").createServer(secureOpts, fn); | ||||
|         }); | ||||
|     }; | ||||
|     servers._httpsServer = function(secureOpts, defaultApp, createSecureServer) { | ||||
|         if (defaultApp) { | ||||
|             // TODO guard against being set twice?
 | ||||
|             _middlewareApp = defaultApp; | ||||
|         } | ||||
| 
 | ||||
| 		if (_httpsServer) { | ||||
| 			if (secureOpts && Object.keys(secureOpts).length) { | ||||
| 				throw new Error("Call glx.httpsServer(tlsOptions) before calling glx.serveApp(app)"); | ||||
| 			} | ||||
| 			return _httpsServer; | ||||
| 		} | ||||
|         if (_httpsServer) { | ||||
|             if (secureOpts && Object.keys(secureOpts).length) { | ||||
|                 throw new Error("Call glx.httpsServer(tlsOptions) before calling glx.serveApp(app)"); | ||||
|             } | ||||
|             return _httpsServer; | ||||
|         } | ||||
| 
 | ||||
| 		if (!secureOpts) { | ||||
| 			secureOpts = {}; | ||||
| 		} | ||||
|         if (!secureOpts) { | ||||
|             secureOpts = {}; | ||||
|         } | ||||
| 
 | ||||
| 		_httpsServer = createSecureServer( | ||||
| 			wrapDefaultSniCallback(greenlock, secureOpts), | ||||
| 			HttpsMiddleware.create(greenlock, function(req, res) { | ||||
| 				if (!_middlewareApp) { | ||||
| 					throw new Error("Set app with `glx.serveApp(app)` or `glx.httpsServer(tlsOptions, app)`"); | ||||
| 				} | ||||
| 				_middlewareApp(req, res); | ||||
| 			}) | ||||
| 		); | ||||
| 		_httpsServer.once("error", startError); | ||||
|         _httpsServer = createSecureServer( | ||||
|             wrapDefaultSniCallback(greenlock, secureOpts), | ||||
|             HttpsMiddleware.create(greenlock, function(req, res) { | ||||
|                 if (!_middlewareApp) { | ||||
|                     throw new Error("Set app with `glx.serveApp(app)` or `glx.httpsServer(tlsOptions, app)`"); | ||||
|                 } | ||||
|                 _middlewareApp(req, res); | ||||
|             }) | ||||
|         ); | ||||
|         _httpsServer.once("error", startError); | ||||
| 
 | ||||
| 		return _httpsServer; | ||||
| 	}; | ||||
|         return _httpsServer; | ||||
|     }; | ||||
| 
 | ||||
| 	servers.id = function() { | ||||
| 		return (cluster.isWorker && cluster.worker.id) || "0"; | ||||
| 	}; | ||||
| 	servers.serveApp = function(app) { | ||||
| 		return new Promise(function(resolve, reject) { | ||||
| 			if ("function" !== typeof app) { | ||||
| 				reject(new Error("glx.serveApp(app) expects a node/express app in the format `function (req, res) { ... }`")); | ||||
| 				return; | ||||
| 			} | ||||
|     servers.id = function() { | ||||
|         return (cluster.isWorker && cluster.worker.id) || "0"; | ||||
|     }; | ||||
|     servers.serveApp = function(app) { | ||||
|         return new Promise(function(resolve, reject) { | ||||
|             if ("function" !== typeof app) { | ||||
|                 reject( | ||||
|                     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 idstr = (id && "#" + id + " ") || ""; | ||||
| 			var plainServer = servers.httpServer(require("redirect-https")()); | ||||
| 			var plainAddr = "0.0.0.0"; | ||||
| 			var plainPort = 80; | ||||
| 			plainServer.listen(plainPort, plainAddr, function() { | ||||
| 				console.info( | ||||
| 					idstr + "Listening on", | ||||
| 					plainAddr + ":" + plainPort, | ||||
| 					"for ACME challenges, and redirecting to HTTPS" | ||||
| 				); | ||||
|             var id = cluster.isWorker && cluster.worker.id; | ||||
|             var idstr = (id && "#" + id + " ") || ""; | ||||
|             var plainServer = servers.httpServer(require("redirect-https")()); | ||||
|             var plainAddr = "0.0.0.0"; | ||||
|             var plainPort = 80; | ||||
|             plainServer.listen(plainPort, plainAddr, function() { | ||||
|                 console.info( | ||||
|                     idstr + "Listening on", | ||||
|                     plainAddr + ":" + plainPort, | ||||
|                     "for ACME challenges, and redirecting to HTTPS" | ||||
|                 ); | ||||
| 
 | ||||
| 				// TODO fetch greenlock.servername
 | ||||
| 				_middlewareApp = app || _middlewareApp; | ||||
| 				var secureServer = servers.httpsServer(null, app); | ||||
| 				var secureAddr = "0.0.0.0"; | ||||
| 				var securePort = 443; | ||||
| 				secureServer.listen(securePort, secureAddr, function() { | ||||
| 					console.info(idstr + "Listening on", secureAddr + ":" + securePort, "for secure traffic"); | ||||
|                 // TODO fetch greenlock.servername
 | ||||
|                 _middlewareApp = app || _middlewareApp; | ||||
|                 var secureServer = servers.httpsServer(null, app); | ||||
|                 var secureAddr = "0.0.0.0"; | ||||
|                 var securePort = 443; | ||||
|                 secureServer.listen(securePort, secureAddr, function() { | ||||
|                     console.info(idstr + "Listening on", secureAddr + ":" + securePort, "for secure traffic"); | ||||
| 
 | ||||
| 					plainServer.removeListener("error", startError); | ||||
| 					secureServer.removeListener("error", startError); | ||||
| 					resolve(); | ||||
| 				}); | ||||
| 			}); | ||||
| 		}); | ||||
| 	}; | ||||
|                     plainServer.removeListener("error", startError); | ||||
|                     secureServer.removeListener("error", startError); | ||||
|                     resolve(); | ||||
|                 }); | ||||
|             }); | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
| 	return servers; | ||||
|     return servers; | ||||
| }; | ||||
| 
 | ||||
| function explainError(e) { | ||||
| 	console.error(); | ||||
| 	console.error("Error: " + e.message); | ||||
| 	if ("EACCES" === e.errno) { | ||||
| 		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)"'); | ||||
| 	} else if ("EADDRINUSE" === e.errno) { | ||||
| 		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."); | ||||
| 	} else { | ||||
| 		console.error(e.code + ": '" + e.address + ":" + e.port + "'"); | ||||
| 	} | ||||
| 	console.error(); | ||||
|     console.error(); | ||||
|     console.error("Error: " + e.message); | ||||
|     if ("EACCES" === e.errno) { | ||||
|         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)"'); | ||||
|     } else if ("EADDRINUSE" === e.errno) { | ||||
|         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."); | ||||
|     } else { | ||||
|         console.error(e.code + ": '" + e.address + ":" + e.port + "'"); | ||||
|     } | ||||
|     console.error(); | ||||
| } | ||||
| 
 | ||||
| function wrapDefaultSniCallback(greenlock, secureOpts) { | ||||
| 	// I'm not sure yet if the original SNICallback
 | ||||
| 	// should be called before or after, so I'm just
 | ||||
| 	// going to delay making that choice until I have the use case
 | ||||
| 	/* | ||||
|     // I'm not sure yet if the original SNICallback
 | ||||
|     // should be called before or after, so I'm just
 | ||||
|     // going to delay making that choice until I have the use case
 | ||||
|     /* | ||||
| 		if (!secureOpts.SNICallback) { | ||||
| 			secureOpts.SNICallback = function(servername, cb) { | ||||
| 				cb(null, null); | ||||
| 			}; | ||||
| 		} | ||||
|   */ | ||||
| 	if (secureOpts.SNICallback) { | ||||
| 		console.warn(); | ||||
| 		console.warn("[warning] Ignoring the given tlsOptions.SNICallback function."); | ||||
| 		console.warn(); | ||||
| 		console.warn("          We're very open to implementing support for this,"); | ||||
| 		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(); | ||||
| 	} | ||||
|     if (secureOpts.SNICallback) { | ||||
|         console.warn(); | ||||
|         console.warn("[warning] Ignoring the given tlsOptions.SNICallback function."); | ||||
|         console.warn(); | ||||
|         console.warn("          We're very open to implementing support for this,"); | ||||
|         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(); | ||||
|     } | ||||
| 
 | ||||
| 	// TODO greenlock.servername for workers
 | ||||
| 	secureOpts.SNICallback = sni.create(greenlock, secureOpts); | ||||
| 	return secureOpts; | ||||
|     // TODO greenlock.servername for workers
 | ||||
|     secureOpts.SNICallback = sni.create(greenlock, secureOpts); | ||||
|     return secureOpts; | ||||
| } | ||||
|  | ||||
							
								
								
									
										28
									
								
								single.js
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								single.js
									
									
									
									
									
								
							| @ -6,20 +6,20 @@ var Single = module.exports; | ||||
| var Servers = require("./servers.js"); | ||||
| 
 | ||||
| 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 = { | ||||
| 		serve: function(fn) { | ||||
| 			fn(servers); | ||||
| 			return single; | ||||
| 		}, | ||||
| 		master: function(/*fn*/) { | ||||
| 			// ignore
 | ||||
| 			//fn(master);
 | ||||
| 			return single; | ||||
| 		} | ||||
| 	}; | ||||
| 	return single; | ||||
|     var single = { | ||||
|         serve: function(fn) { | ||||
|             fn(servers); | ||||
|             return single; | ||||
|         }, | ||||
|         master: function(/*fn*/) { | ||||
|             // ignore
 | ||||
|             //fn(master);
 | ||||
|             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);
 | ||||
| sni.create = function(greenlock, secureOpts) { | ||||
| 	var _cache = {}; | ||||
| 	var defaultServername = greenlock.servername || ""; | ||||
|     var _cache = {}; | ||||
|     var defaultServername = greenlock.servername || ""; | ||||
| 
 | ||||
| 	if (secureOpts.cert) { | ||||
| 		// Note: it's fine if greenlock.servername is undefined,
 | ||||
| 		// but if the caller wants this to auto-renew, they should define it
 | ||||
| 		_cache[defaultServername] = { | ||||
| 			refreshAt: 0, | ||||
| 			secureContext: tls.createSecureContext(secureOpts) | ||||
| 		}; | ||||
| 	} | ||||
|     if (secureOpts.cert) { | ||||
|         // Note: it's fine if greenlock.servername is undefined,
 | ||||
|         // but if the caller wants this to auto-renew, they should define it
 | ||||
|         _cache[defaultServername] = { | ||||
|             refreshAt: 0, | ||||
|             secureContext: tls.createSecureContext(secureOpts) | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
| 	return getSecureContext; | ||||
|     return getSecureContext; | ||||
| 
 | ||||
| 	function notify(ev, args) { | ||||
| 		try { | ||||
| 			// TODO _notify() or notify()?
 | ||||
| 			(greenlock.notify || greenlock._notify)(ev, args); | ||||
| 		} catch (e) { | ||||
| 			console.error(e); | ||||
| 			console.error(ev, args); | ||||
| 		} | ||||
| 	} | ||||
|     function notify(ev, args) { | ||||
|         try { | ||||
|             // TODO _notify() or notify()?
 | ||||
|             (greenlock.notify || greenlock._notify)(ev, args); | ||||
|         } catch (e) { | ||||
|             console.error(e); | ||||
|             console.error(ev, args); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	function getSecureContext(servername, cb) { | ||||
| 		//console.log("debug sni", servername);
 | ||||
| 		if ("string" !== typeof servername) { | ||||
| 			// this will never happen... right? but stranger things have...
 | ||||
| 			console.error("[sanity fail] non-string servername:", servername); | ||||
| 			cb(new Error("invalid servername"), null); | ||||
| 			return; | ||||
| 		} | ||||
|     function getSecureContext(servername, cb) { | ||||
|         //console.log("debug sni", servername);
 | ||||
|         if ("string" !== typeof servername) { | ||||
|             // this will never happen... right? but stranger things have...
 | ||||
|             console.error("[sanity fail] non-string servername:", servername); | ||||
|             cb(new Error("invalid servername"), null); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| 		var secureContext = getCachedContext(servername); | ||||
| 		if (secureContext) { | ||||
| 			//console.log("debug sni got cached context", servername, getCachedMeta(servername));
 | ||||
| 			cb(null, secureContext); | ||||
| 			return; | ||||
| 		} | ||||
|         var secureContext = getCachedContext(servername); | ||||
|         if (secureContext) { | ||||
|             //console.log("debug sni got cached context", servername, getCachedMeta(servername));
 | ||||
|             cb(null, secureContext); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| 		getFreshContext(servername) | ||||
| 			.then(function(secureContext) { | ||||
| 				if (secureContext) { | ||||
| 					//console.log("debug sni got fresh context", servername, getCachedMeta(servername));
 | ||||
| 					cb(null, secureContext); | ||||
| 					return; | ||||
| 				} | ||||
| 				// Note: this does not replace tlsSocket.setSecureContext()
 | ||||
| 				// as it only works when SNI has been sent
 | ||||
| 				//console.log("debug sni got default context", servername, getCachedMeta(servername));
 | ||||
| 				cb(null, getDefaultContext()); | ||||
| 			}) | ||||
| 			.catch(function(err) { | ||||
| 				if (!err.context) { | ||||
| 					err.context = "sni_callback"; | ||||
| 				} | ||||
| 				notify("error", err); | ||||
| 				//console.log("debug sni error", servername, err);
 | ||||
| 				cb(err); | ||||
| 			}); | ||||
| 	} | ||||
|         getFreshContext(servername) | ||||
|             .then(function(secureContext) { | ||||
|                 if (secureContext) { | ||||
|                     //console.log("debug sni got fresh context", servername, getCachedMeta(servername));
 | ||||
|                     cb(null, secureContext); | ||||
|                     return; | ||||
|                 } | ||||
|                 // Note: this does not replace tlsSocket.setSecureContext()
 | ||||
|                 // as it only works when SNI has been sent
 | ||||
|                 //console.log("debug sni got default context", servername, getCachedMeta(servername));
 | ||||
|                 cb(null, getDefaultContext()); | ||||
|             }) | ||||
|             .catch(function(err) { | ||||
|                 if (!err.context) { | ||||
|                     err.context = "sni_callback"; | ||||
|                 } | ||||
|                 notify("error", err); | ||||
|                 //console.log("debug sni error", servername, err);
 | ||||
|                 cb(err); | ||||
|             }); | ||||
|     } | ||||
| 
 | ||||
| 	function getCachedMeta(servername) { | ||||
| 		var meta = _cache[servername]; | ||||
| 		if (!meta) { | ||||
| 			if (!_cache[wildname(servername)]) { | ||||
| 				return null; | ||||
| 			} | ||||
| 		} | ||||
| 		return meta; | ||||
| 	} | ||||
|     function getCachedMeta(servername) { | ||||
|         var meta = _cache[servername]; | ||||
|         if (!meta) { | ||||
|             if (!_cache[wildname(servername)]) { | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
|         return meta; | ||||
|     } | ||||
| 
 | ||||
| 	function getCachedContext(servername) { | ||||
| 		var meta = getCachedMeta(servername); | ||||
| 		if (!meta) { | ||||
| 			return null; | ||||
| 		} | ||||
|     function getCachedContext(servername) { | ||||
|         var meta = getCachedMeta(servername); | ||||
|         if (!meta) { | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
| 		// always renew in background
 | ||||
| 		if (!meta.refreshAt || Date.now() >= meta.refreshAt) { | ||||
| 			getFreshContext(servername).catch(function(e) { | ||||
| 				if (!e.context) { | ||||
| 					e.context = "sni_background_refresh"; | ||||
| 				} | ||||
| 				notify("error", e); | ||||
| 			}); | ||||
| 		} | ||||
|         // always renew in background
 | ||||
|         if (!meta.refreshAt || Date.now() >= meta.refreshAt) { | ||||
|             getFreshContext(servername).catch(function(e) { | ||||
|                 if (!e.context) { | ||||
|                     e.context = "sni_background_refresh"; | ||||
|                 } | ||||
|                 notify("error", e); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
| 		// under normal circumstances this would never be expired
 | ||||
| 		// and, if it is expired, something is so wrong it's probably
 | ||||
| 		// not worth wating for the renewal - it has probably failed
 | ||||
| 		return meta.secureContext; | ||||
| 	} | ||||
|         // under normal circumstances this would never be expired
 | ||||
|         // and, if it is expired, something is so wrong it's probably
 | ||||
|         // not worth wating for the renewal - it has probably failed
 | ||||
|         return meta.secureContext; | ||||
|     } | ||||
| 
 | ||||
| 	function getFreshContext(servername) { | ||||
| 		var meta = getCachedMeta(servername); | ||||
| 		if (!meta && !validServername(servername)) { | ||||
| 			return Promise.resolve(null); | ||||
| 		} | ||||
|     function getFreshContext(servername) { | ||||
|         var meta = getCachedMeta(servername); | ||||
|         if (!meta && !validServername(servername)) { | ||||
|             return Promise.resolve(null); | ||||
|         } | ||||
| 
 | ||||
| 		if (meta) { | ||||
| 			// prevent stampedes
 | ||||
| 			meta.refreshAt = Date.now() + randomRefreshOffset(); | ||||
| 		} | ||||
|         if (meta) { | ||||
|             // prevent stampedes
 | ||||
|             meta.refreshAt = Date.now() + randomRefreshOffset(); | ||||
|         } | ||||
| 
 | ||||
| 		// 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
 | ||||
| 		return greenlock.get({ servername: servername }).then(function(result) { | ||||
| 			var meta = getCachedMeta(servername); | ||||
| 			if (!meta) { | ||||
| 				meta = _cache[servername] = { secureContext: { _valid: false } }; | ||||
| 			} | ||||
| 			// prevent from being punked by bot trolls
 | ||||
| 			meta.refreshAt = Date.now() + smallStagger; | ||||
|         // 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
 | ||||
|         return greenlock.get({ servername: servername }).then(function(result) { | ||||
|             var meta = getCachedMeta(servername); | ||||
|             if (!meta) { | ||||
|                 meta = _cache[servername] = { secureContext: { _valid: false } }; | ||||
|             } | ||||
|             // prevent from being punked by bot trolls
 | ||||
|             meta.refreshAt = Date.now() + smallStagger; | ||||
| 
 | ||||
| 			// nothing to do
 | ||||
| 			if (!result) { | ||||
| 				return null; | ||||
| 			} | ||||
|             // nothing to do
 | ||||
|             if (!result) { | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
| 			// we only care about the first one
 | ||||
| 			var pems = result.pems; | ||||
| 			var site = result.site; | ||||
| 			if (!pems || !pems.cert) { | ||||
| 				// nothing to do
 | ||||
| 				// (and the error should have been reported already)
 | ||||
| 				return null; | ||||
| 			} | ||||
|             // we only care about the first one
 | ||||
|             var pems = result.pems; | ||||
|             var site = result.site; | ||||
|             if (!pems || !pems.cert) { | ||||
|                 // nothing to do
 | ||||
|                 // (and the error should have been reported already)
 | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
| 			meta = { | ||||
| 				refreshAt: Date.now() + randomRefreshOffset(), | ||||
| 				secureContext: tls.createSecureContext({ | ||||
| 					// TODO support passphrase-protected privkeys
 | ||||
| 					key: pems.privkey, | ||||
| 					cert: pems.cert + "\n" + pems.chain + "\n" | ||||
| 				}) | ||||
| 			}; | ||||
| 			meta.secureContext._valid = true; | ||||
|             meta = { | ||||
|                 refreshAt: Date.now() + randomRefreshOffset(), | ||||
|                 secureContext: tls.createSecureContext({ | ||||
|                     // TODO support passphrase-protected privkeys
 | ||||
|                     key: pems.privkey, | ||||
|                     cert: pems.cert + "\n" + pems.chain + "\n" | ||||
|                 }) | ||||
|             }; | ||||
|             meta.secureContext._valid = true; | ||||
| 
 | ||||
| 			// copy this same object into every place
 | ||||
| 			(result.altnames || site.altnames || [result.subject || site.subject]).forEach(function(altname) { | ||||
| 				_cache[altname] = meta; | ||||
| 			}); | ||||
|             // copy this same object into every place
 | ||||
|             (result.altnames || site.altnames || [result.subject || site.subject]).forEach(function(altname) { | ||||
|                 _cache[altname] = meta; | ||||
|             }); | ||||
| 
 | ||||
| 			return meta.secureContext; | ||||
| 		}); | ||||
| 	} | ||||
|             return meta.secureContext; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| 	function getDefaultContext() { | ||||
| 		return getCachedContext(defaultServername); | ||||
| 	} | ||||
|     function getDefaultContext() { | ||||
|         return getCachedContext(defaultServername); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // whenever we need to know when to refresh next
 | ||||
| function randomRefreshOffset() { | ||||
| 	var stagger = Math.round(refreshStagger / 2) - Math.round(Math.random() * refreshStagger); | ||||
| 	return refreshOffset + stagger; | ||||
|     var stagger = Math.round(refreshStagger / 2) - Math.round(Math.random() * refreshStagger); | ||||
|     return refreshOffset + stagger; | ||||
| } | ||||
| 
 | ||||
| function validServername(servername) { | ||||
| 	// format and (lightly) sanitize sni so that users can be naive
 | ||||
| 	// and not have to worry about SQL injection or fs discovery
 | ||||
|     // format and (lightly) sanitize sni so that users can be naive
 | ||||
|     // and not have to worry about SQL injection or fs discovery
 | ||||
| 
 | ||||
| 	servername = (servername || "").toLowerCase(); | ||||
| 	// 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
 | ||||
| 	// REGEX // https://www.codeproject.com/Questions/1063023/alphanumeric-validation-javascript-without-regex
 | ||||
| 	return servernameRe.test(servername) && -1 === servername.indexOf(".."); | ||||
|     servername = (servername || "").toLowerCase(); | ||||
|     // 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
 | ||||
|     // REGEX // https://www.codeproject.com/Questions/1063023/alphanumeric-validation-javascript-without-regex
 | ||||
|     return servernameRe.test(servername) && -1 === servername.indexOf(".."); | ||||
| } | ||||
| 
 | ||||
| function wildname(servername) { | ||||
| 	return ( | ||||
| 		"*." + | ||||
| 		servername | ||||
| 			.split(".") | ||||
| 			.slice(1) | ||||
| 			.join(".") | ||||
| 	); | ||||
|     return ( | ||||
|         "*." + | ||||
|         servername | ||||
|             .split(".") | ||||
|             .slice(1) | ||||
|             .join(".") | ||||
|     ); | ||||
| } | ||||
|  | ||||
| @ -1,83 +1,83 @@ | ||||
| #!/usr/bin/env node
 | ||||
| var Greenlock = require("../"); | ||||
| var greenlock = Greenlock.create({ | ||||
| 	version: "draft-11", | ||||
| 	server: "https://acme-staging-v02.api.letsencrypt.org/directory", | ||||
| 	agreeTos: true, | ||||
| 	approvedDomains: ["example.com", "www.example.com"], | ||||
| 	configDir: require("path").join(require("os").tmpdir(), "acme"), | ||||
|     version: "draft-11", | ||||
|     server: "https://acme-staging-v02.api.letsencrypt.org/directory", | ||||
|     agreeTos: true, | ||||
|     approvedDomains: ["example.com", "www.example.com"], | ||||
|     configDir: require("path").join(require("os").tmpdir(), "acme"), | ||||
| 
 | ||||
| 	app: require("express")().use("/", function(req, res) { | ||||
| 		res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||
| 		res.end("Hello, World!\n\n💚 🔒.js"); | ||||
| 	}) | ||||
|     app: require("express")().use("/", function(req, res) { | ||||
|         res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||||
|         res.end("Hello, World!\n\n💚 🔒.js"); | ||||
|     }) | ||||
| }); | ||||
| 
 | ||||
| var server1 = greenlock.listen(5080, 5443); | ||||
| server1.on("listening", function() { | ||||
| 	console.log("### THREE 3333 - All is well server1", this.address()); | ||||
| 	setTimeout(function() { | ||||
| 		// so that the address() object doesn't disappear
 | ||||
| 		server1.close(); | ||||
| 		server1.unencrypted.close(); | ||||
| 	}, 10); | ||||
|     console.log("### THREE 3333 - All is well server1", this.address()); | ||||
|     setTimeout(function() { | ||||
|         // so that the address() object doesn't disappear
 | ||||
|         server1.close(); | ||||
|         server1.unencrypted.close(); | ||||
|     }, 10); | ||||
| }); | ||||
| setTimeout(function() { | ||||
| 	var server2 = greenlock.listen(6080, 6443, function() { | ||||
| 		console.log("### FIVE 55555 - Started server 2!"); | ||||
| 		setTimeout(function() { | ||||
| 			server2.close(); | ||||
| 			server2.unencrypted.close(); | ||||
| 			server6.close(); | ||||
| 			server6.unencrypted.close(); | ||||
| 			server7.close(); | ||||
| 			server7.unencrypted.close(); | ||||
| 			setTimeout(function() { | ||||
| 				// TODO greenlock needs a close event (and to listen to its server's close event)
 | ||||
| 				process.exit(0); | ||||
| 			}, 1000); | ||||
| 		}, 1000); | ||||
| 	}); | ||||
| 	server2.on("listening", function() { | ||||
| 		console.log("### FOUR 44444 - All is well server2", server2.address()); | ||||
| 	}); | ||||
|     var server2 = greenlock.listen(6080, 6443, function() { | ||||
|         console.log("### FIVE 55555 - Started server 2!"); | ||||
|         setTimeout(function() { | ||||
|             server2.close(); | ||||
|             server2.unencrypted.close(); | ||||
|             server6.close(); | ||||
|             server6.unencrypted.close(); | ||||
|             server7.close(); | ||||
|             server7.unencrypted.close(); | ||||
|             setTimeout(function() { | ||||
|                 // TODO greenlock needs a close event (and to listen to its server's close event)
 | ||||
|                 process.exit(0); | ||||
|             }, 1000); | ||||
|         }, 1000); | ||||
|     }); | ||||
|     server2.on("listening", function() { | ||||
|         console.log("### FOUR 44444 - All is well server2", server2.address()); | ||||
|     }); | ||||
| }, 1000); | ||||
| 
 | ||||
| var server3 = greenlock.listen( | ||||
| 	22, | ||||
| 	22, | ||||
| 	function() { | ||||
| 		console.error("Error: expected to get an error when launching plain server on port 22"); | ||||
| 	}, | ||||
| 	function() { | ||||
| 		console.error("Error: expected to get an error when launching " + server3.type + " server on port 22"); | ||||
| 	} | ||||
|     22, | ||||
|     22, | ||||
|     function() { | ||||
|         console.error("Error: expected to get an error when launching plain server on port 22"); | ||||
|     }, | ||||
|     function() { | ||||
|         console.error("Error: expected to get an error when launching " + server3.type + " server on port 22"); | ||||
|     } | ||||
| ); | ||||
| server3.unencrypted.on("error", function() { | ||||
| 	console.log("Success: caught expected (plain) error"); | ||||
|     console.log("Success: caught expected (plain) error"); | ||||
| }); | ||||
| server3.on("error", function() { | ||||
| 	console.log("Success: caught expected " + server3.type + " error"); | ||||
| 	//server3.close();
 | ||||
|     console.log("Success: caught expected " + server3.type + " error"); | ||||
|     //server3.close();
 | ||||
| }); | ||||
| 
 | ||||
| var server4 = greenlock.listen( | ||||
| 	7080, | ||||
| 	7443, | ||||
| 	function() { | ||||
| 		console.log("Success: server4: plain"); | ||||
| 		server4.unencrypted.close(); | ||||
| 	}, | ||||
| 	function() { | ||||
| 		console.log("Success: server4: " + server4.type); | ||||
| 		server4.close(); | ||||
| 	} | ||||
|     7080, | ||||
|     7443, | ||||
|     function() { | ||||
|         console.log("Success: server4: plain"); | ||||
|         server4.unencrypted.close(); | ||||
|     }, | ||||
|     function() { | ||||
|         console.log("Success: server4: " + server4.type); | ||||
|         server4.close(); | ||||
|     } | ||||
| ); | ||||
| 
 | ||||
| var server5 = greenlock.listen(10080, 10443, function() { | ||||
| 	console.log("Server 5 with one fn", this.address()); | ||||
| 	server5.close(); | ||||
| 	server5.unencrypted.close(); | ||||
|     console.log("Server 5 with one fn", this.address()); | ||||
|     server5.close(); | ||||
|     server5.unencrypted.close(); | ||||
| }); | ||||
| 
 | ||||
| var server6 = greenlock.listen("[::]:11080", "[::1]:11443"); | ||||
|  | ||||
							
								
								
									
										92
									
								
								worker.js
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								worker.js
									
									
									
									
									
								
							| @ -6,57 +6,57 @@ var messageTimeout = 30 * 1000; | ||||
| var msgPrefix = "greenlock:"; | ||||
| 
 | ||||
| Worker.create = function() { | ||||
| 	var greenlock = {}; | ||||
| 	["getAcmeHttp01ChallengeResponse", "get", "notify"].forEach(function(k) { | ||||
| 		greenlock[k] = function(args) { | ||||
| 			return rpc(k, args); | ||||
| 		}; | ||||
| 	}); | ||||
|     var greenlock = {}; | ||||
|     ["getAcmeHttp01ChallengeResponse", "get", "notify"].forEach(function(k) { | ||||
|         greenlock[k] = function(args) { | ||||
|             return rpc(k, args); | ||||
|         }; | ||||
|     }); | ||||
| 
 | ||||
| 	var worker = { | ||||
| 		serve: function(fn) { | ||||
| 			var servers = require("./servers.js").create(greenlock); | ||||
| 			fn(servers); | ||||
| 			return worker; | ||||
| 		}, | ||||
| 		master: function() { | ||||
| 			// ignore
 | ||||
| 			return worker; | ||||
| 		} | ||||
| 	}; | ||||
| 	return worker; | ||||
|     var worker = { | ||||
|         serve: function(fn) { | ||||
|             var servers = require("./servers.js").create(greenlock); | ||||
|             fn(servers); | ||||
|             return worker; | ||||
|         }, | ||||
|         master: function() { | ||||
|             // ignore
 | ||||
|             return worker; | ||||
|         } | ||||
|     }; | ||||
|     return worker; | ||||
| }; | ||||
| 
 | ||||
| function rpc(funcname, msg) { | ||||
| 	return new Promise(function(resolve, reject) { | ||||
| 		var rnd = Math.random() | ||||
| 			.toString() | ||||
| 			.slice(2) | ||||
| 			.toString(16); | ||||
| 		var id = msgPrefix + rnd; | ||||
| 		var timeout; | ||||
|     return new Promise(function(resolve, reject) { | ||||
|         var rnd = Math.random() | ||||
|             .toString() | ||||
|             .slice(2) | ||||
|             .toString(16); | ||||
|         var id = msgPrefix + rnd; | ||||
|         var timeout; | ||||
| 
 | ||||
| 		function getResponse(msg) { | ||||
| 			if (msg._id !== id) { | ||||
| 				return; | ||||
| 			} | ||||
| 			process.removeListener("message", getResponse); | ||||
| 			clearTimeout(timeout); | ||||
| 			resolve(msg._result); | ||||
| 		} | ||||
|         function getResponse(msg) { | ||||
|             if (msg._id !== id) { | ||||
|                 return; | ||||
|             } | ||||
|             process.removeListener("message", getResponse); | ||||
|             clearTimeout(timeout); | ||||
|             resolve(msg._result); | ||||
|         } | ||||
| 
 | ||||
| 		// TODO keep a single listener than just responds
 | ||||
| 		// via a collection of callbacks? or leave as is?
 | ||||
| 		process.on("message", getResponse); | ||||
| 		process.send({ | ||||
| 			_id: id, | ||||
| 			_funcname: funcname, | ||||
| 			_input: msg | ||||
| 		}); | ||||
|         // TODO keep a single listener than just responds
 | ||||
|         // via a collection of callbacks? or leave as is?
 | ||||
|         process.on("message", getResponse); | ||||
|         process.send({ | ||||
|             _id: id, | ||||
|             _funcname: funcname, | ||||
|             _input: msg | ||||
|         }); | ||||
| 
 | ||||
| 		timeout = setTimeout(function() { | ||||
| 			process.removeListener("message", getResponse); | ||||
| 			reject(new Error("worker rpc request timeout")); | ||||
| 		}, messageTimeout); | ||||
| 	}); | ||||
|         timeout = setTimeout(function() { | ||||
|             process.removeListener("message", getResponse); | ||||
|             reject(new Error("worker rpc request timeout")); | ||||
|         }, messageTimeout); | ||||
|     }); | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user