make Prettier
This commit is contained in:
		
							parent
							
								
									a49ccb7398
								
							
						
					
					
						commit
						c73ad565a3
					
				
							
								
								
									
										7
									
								
								.prettierrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.prettierrc
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "bracketSpacing": true,
 | 
			
		||||
  "printWidth": 120,
 | 
			
		||||
  "tabWidth": 2,
 | 
			
		||||
  "trailingComma": "none",
 | 
			
		||||
  "useTabs": true
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										381
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										381
									
								
								README.md
									
									
									
									
									
								
							@ -37,30 +37,30 @@ and **node.js middleware systems**.
 | 
			
		||||
 | 
			
		||||
# Features
 | 
			
		||||
 | 
			
		||||
  - [x] Automatic HTTPS
 | 
			
		||||
    - [x] Free SSL
 | 
			
		||||
    - [x] Free Wildcard SSL
 | 
			
		||||
    - [x] Multiple domain support (up to 100 altnames per SAN)
 | 
			
		||||
    - [x] Dynamic Virtual Hosting (vhost)
 | 
			
		||||
    - [x] Automatical renewal (10 to 14 days before expiration)
 | 
			
		||||
  - [x] Great ACME support
 | 
			
		||||
    - [x] ACME draft 11
 | 
			
		||||
    - [x] Let's Encrypt v2
 | 
			
		||||
    - [x] Let's Encrypt v1
 | 
			
		||||
  - [x] Full node.js support
 | 
			
		||||
    - [x] node v6+
 | 
			
		||||
    - [x] core https module
 | 
			
		||||
    - [x] Express.js
 | 
			
		||||
    - [x] [Koa](https://git.rootprojects.org/root/greenlock-koa.js)
 | 
			
		||||
    - [x] [hapi](https://git.rootprojects.org/root/greenlock-hapi.js)
 | 
			
		||||
  - [x] Extensible Plugin Support
 | 
			
		||||
    - [x] AWS (S3, Route53)
 | 
			
		||||
    - [x] Azure
 | 
			
		||||
    - [x] CloudFlare
 | 
			
		||||
    - [x] Consul
 | 
			
		||||
    - [x] Digital Ocean
 | 
			
		||||
    - [x] etcd
 | 
			
		||||
    - [x] Redis
 | 
			
		||||
- [x] Automatic HTTPS
 | 
			
		||||
  - [x] Free SSL
 | 
			
		||||
  - [x] Free Wildcard SSL
 | 
			
		||||
  - [x] Multiple domain support (up to 100 altnames per SAN)
 | 
			
		||||
  - [x] Dynamic Virtual Hosting (vhost)
 | 
			
		||||
  - [x] Automatical renewal (10 to 14 days before expiration)
 | 
			
		||||
- [x] Great ACME support
 | 
			
		||||
  - [x] ACME draft 11
 | 
			
		||||
  - [x] Let's Encrypt v2
 | 
			
		||||
  - [x] Let's Encrypt v1
 | 
			
		||||
- [x] Full node.js support
 | 
			
		||||
  - [x] node v6+
 | 
			
		||||
  - [x] core https module
 | 
			
		||||
  - [x] Express.js
 | 
			
		||||
  - [x] [Koa](https://git.rootprojects.org/root/greenlock-koa.js)
 | 
			
		||||
  - [x] [hapi](https://git.rootprojects.org/root/greenlock-hapi.js)
 | 
			
		||||
- [x] Extensible Plugin Support
 | 
			
		||||
  - [x] AWS (S3, Route53)
 | 
			
		||||
  - [x] Azure
 | 
			
		||||
  - [x] CloudFlare
 | 
			
		||||
  - [x] Consul
 | 
			
		||||
  - [x] Digital Ocean
 | 
			
		||||
  - [x] etcd
 | 
			
		||||
  - [x] Redis
 | 
			
		||||
 | 
			
		||||
# Install
 | 
			
		||||
 | 
			
		||||
@ -78,18 +78,18 @@ Watch the QuickStart demonstration: [https://youtu.be/e8vaR4CEZ5s](https://youtu
 | 
			
		||||
 | 
			
		||||
<a href="https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk"><img src="https://i.imgur.com/Y8ix6Ts.png" title="QuickStart Video" alt="YouTube Video Preview" /></a>
 | 
			
		||||
 | 
			
		||||
* [0:00](https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk#t=0) - Intro
 | 
			
		||||
* [2:22](https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk#t=142) - Demonstrating QuickStart Example
 | 
			
		||||
* [6:37](https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk?t=397) - Troubleshooting / Gotchas
 | 
			
		||||
- [0:00](https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk#t=0) - Intro
 | 
			
		||||
- [2:22](https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk#t=142) - Demonstrating QuickStart Example
 | 
			
		||||
- [6:37](https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk?t=397) - Troubleshooting / Gotchas
 | 
			
		||||
 | 
			
		||||
#### Beyond the QuickStart (Part 2)
 | 
			
		||||
 | 
			
		||||
* [1:00](https://www.youtube.com/watch?v=bTEn93gxY50&index=2&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk&t=60) - Bringing Greenlock into an Existing Express Project
 | 
			
		||||
* [2:26](https://www.youtube.com/watch?v=bTEn93gxY50&index=2&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk&t=146) - The `approveDomains` callback
 | 
			
		||||
- [1:00](https://www.youtube.com/watch?v=bTEn93gxY50&index=2&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk&t=60) - Bringing Greenlock into an Existing Express Project
 | 
			
		||||
- [2:26](https://www.youtube.com/watch?v=bTEn93gxY50&index=2&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk&t=146) - The `approveDomains` callback
 | 
			
		||||
 | 
			
		||||
#### Security Concerns (Part 3)
 | 
			
		||||
 | 
			
		||||
* [0:00](https://www.youtube.com/watch?v=aZgVqPzoZTY&index=3&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk) - Potential Attacks, and Mitigation
 | 
			
		||||
- [0:00](https://www.youtube.com/watch?v=aZgVqPzoZTY&index=3&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk) - Potential Attacks, and Mitigation
 | 
			
		||||
 | 
			
		||||
### Working Example Code
 | 
			
		||||
 | 
			
		||||
@ -110,35 +110,39 @@ node greenlock-express.js/examples/simple.js
 | 
			
		||||
All you have to do is start the webserver and then visit it at its domain name.
 | 
			
		||||
 | 
			
		||||
`server.js`:
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
require('greenlock-express').create({
 | 
			
		||||
  email: 'john.doe@example.com'     // The email address of the ACME user / hosting provider
 | 
			
		||||
, agreeTos: true                    // You must accept the ToS as the host which handles the certs
 | 
			
		||||
, configDir: '~/.config/acme/'      // Writable directory where certs will be saved
 | 
			
		||||
, communityMember: true             // Join the community to get notified of important updates
 | 
			
		||||
, telemetry: true                   // Contribute telemetry data to the project
 | 
			
		||||
require("greenlock-express")
 | 
			
		||||
	.create({
 | 
			
		||||
		email: "john.doe@example.com", // The email address of the ACME user / hosting provider
 | 
			
		||||
		agreeTos: true, // You must accept the ToS as the host which handles the certs
 | 
			
		||||
		configDir: "~/.config/acme/", // Writable directory where certs will be saved
 | 
			
		||||
		communityMember: true, // Join the community to get notified of important updates
 | 
			
		||||
		telemetry: true, // Contribute telemetry data to the project
 | 
			
		||||
 | 
			
		||||
  // Using your express app:
 | 
			
		||||
  // simply export it as-is, then include it here
 | 
			
		||||
, app: require('./app.js')
 | 
			
		||||
		// Using your express app:
 | 
			
		||||
		// simply export it as-is, then include it here
 | 
			
		||||
		app: require("./app.js")
 | 
			
		||||
 | 
			
		||||
//, debug: true
 | 
			
		||||
}).listen(80, 443);
 | 
			
		||||
		//, debug: true
 | 
			
		||||
	})
 | 
			
		||||
	.listen(80, 443);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
`app.js`:
 | 
			
		||||
```js
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var express = require('express');
 | 
			
		||||
```js
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
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');
 | 
			
		||||
})
 | 
			
		||||
app.use("/", function(req, res) {
 | 
			
		||||
	res.setHeader("Content-Type", "text/html; charset=utf-8");
 | 
			
		||||
	res.end("Hello, World!\n\n💚 🔒.js");
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Don't do this:
 | 
			
		||||
// app.listen(3000)
 | 
			
		||||
@ -166,29 +170,29 @@ You can see our full privacy policy at <https://greenlock.domains/legal/#privacy
 | 
			
		||||
 | 
			
		||||
Double check the following:
 | 
			
		||||
 | 
			
		||||
* **Public Facing IP** for `http-01` challenges
 | 
			
		||||
  * Are you running this *as* a public-facing webserver (good)? or localhost (bad)?
 | 
			
		||||
  * Does `ifconfig` show a public address (good)? or a private one - 10.x, 192.168.x, etc (bad)?
 | 
			
		||||
  * If you're on a non-public server, are you using the `dns-01` challenge?
 | 
			
		||||
* **correct ACME version**
 | 
			
		||||
  * Let's Encrypt **v2** (ACME v2) must use `version: 'draft-11'`
 | 
			
		||||
  * Let's Encrypt v1 must use `version: 'v01'`
 | 
			
		||||
* **valid email**
 | 
			
		||||
  * You MUST set `email` to a **valid address**
 | 
			
		||||
  * MX records must validate (`dig MX example.com` for `'john@example.com'`)
 | 
			
		||||
* **valid DNS records**
 | 
			
		||||
  * Must have public DNS records (test with `dig +trace A example.com; dig +trace www.example.com` for `[ 'example.com', 'www.example.com' ]`)
 | 
			
		||||
* **write access**
 | 
			
		||||
  * You MUST set `configDir` to a writeable location (test with `touch ~/acme/etc/tmp.tmp`)
 | 
			
		||||
* **port binding privileges**
 | 
			
		||||
  * You MUST be able to bind to ports 80 and 443
 | 
			
		||||
  * You can do this via `sudo` or [`setcap`](https://gist.github.com/firstdoit/6389682)
 | 
			
		||||
* **API limits**
 | 
			
		||||
  * You MUST NOT exceed the API [**usage limits**](https://letsencrypt.org/docs/staging-environment/) per domain, certificate, IP address, etc
 | 
			
		||||
* **Red Lock, Untrusted**
 | 
			
		||||
  * You MUST use the **production** server url, not staging
 | 
			
		||||
  * The API URL should not have 'acme-staging-v02', but should have 'acme-v02'
 | 
			
		||||
  * Delete the `configDir` used for getting certificates in staging
 | 
			
		||||
- **Public Facing IP** for `http-01` challenges
 | 
			
		||||
  - Are you running this _as_ a public-facing webserver (good)? or localhost (bad)?
 | 
			
		||||
  - Does `ifconfig` show a public address (good)? or a private one - 10.x, 192.168.x, etc (bad)?
 | 
			
		||||
  - If you're on a non-public server, are you using the `dns-01` challenge?
 | 
			
		||||
- **correct ACME version**
 | 
			
		||||
  - Let's Encrypt **v2** (ACME v2) must use `version: 'draft-11'`
 | 
			
		||||
  - Let's Encrypt v1 must use `version: 'v01'`
 | 
			
		||||
- **valid email**
 | 
			
		||||
  - You MUST set `email` to a **valid address**
 | 
			
		||||
  - MX records must validate (`dig MX example.com` for `'john@example.com'`)
 | 
			
		||||
- **valid DNS records**
 | 
			
		||||
  - Must have public DNS records (test with `dig +trace A example.com; dig +trace www.example.com` for `[ 'example.com', 'www.example.com' ]`)
 | 
			
		||||
- **write access**
 | 
			
		||||
  - You MUST set `configDir` to a writeable location (test with `touch ~/acme/etc/tmp.tmp`)
 | 
			
		||||
- **port binding privileges**
 | 
			
		||||
  - You MUST be able to bind to ports 80 and 443
 | 
			
		||||
  - You can do this via `sudo` or [`setcap`](https://gist.github.com/firstdoit/6389682)
 | 
			
		||||
- **API limits**
 | 
			
		||||
  - You MUST NOT exceed the API [**usage limits**](https://letsencrypt.org/docs/staging-environment/) per domain, certificate, IP address, etc
 | 
			
		||||
- **Red Lock, Untrusted**
 | 
			
		||||
  - You MUST use the **production** server url, not staging
 | 
			
		||||
  - The API URL should not have 'acme-staging-v02', but should have 'acme-v02'
 | 
			
		||||
  - Delete the `configDir` used for getting certificates in staging
 | 
			
		||||
 | 
			
		||||
### Production vs Staging
 | 
			
		||||
 | 
			
		||||
@ -210,19 +214,19 @@ https://acme-staging-v02.api.letsencrypt.org/directory
 | 
			
		||||
 | 
			
		||||
## Working Examples
 | 
			
		||||
 | 
			
		||||
| Example         | Location + Description |
 | 
			
		||||
|:---------------:|:---------:|
 | 
			
		||||
| **QuickStart**  | [examples/quickstart.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/quickstart.js) uses the fewest options and accepts all default settings. It's guaranteed to work for you. |
 | 
			
		||||
| Production      | [examples/production.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/production.js) shows how to require an express app (or other middleware system), expand the `approveDomains` callback, provides an example database shim, and exposes the server instance. |
 | 
			
		||||
| Virtual Hosting | [examples/vhost.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/vhost.js) shows how to dynamically secure and serve domains based on their existance on the file system. |
 | 
			
		||||
| Wildcard Domains | [examples/wildcard.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/wildcard.js) shows how to use the `acme-dns-01-cli` and wildcard cetificates. |
 | 
			
		||||
| HTTPS (raw)    | [examples/spdy.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/spdy.js) demonstrates how to manually configure a node web server using the node's built-in `http` and `https` modules. |
 | 
			
		||||
| HTTP2 (spdy)    | Presently spdy is incompatible with node v11, but [examples/spdy.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/spdy.js) demonstrates how to manually configure a node web server with spdy-compatible versions of node and Greenlock. |
 | 
			
		||||
| HTTP2 (node)    | [examples/http2.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/http2.js) uses node's new HTTP2 module, which is NOT compatible with the existing middleware systems (and is not "stable" as of v10.0). |
 | 
			
		||||
| WebSockets (ws) | [examples/websockets.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/websockets.js) demonstrates how to use Greenlock express with a websocket server. |
 | 
			
		||||
| socket.io | [examples/socket.io.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/socket.io.js) demonstrates how to use Greenlock express with socket.io (even though `ws` is far simpler, faster, and better and every way). |
 | 
			
		||||
| - | Build Your Own <br> Be sure to tell me ([@solderjs](https://twitter.com/@solderjs)) / us ([@GreenlockHTTPS](https://twitter.com/@GreenlockHTTPS)) about it. :) |
 | 
			
		||||
| Full List      | Check out the [examples/](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples) directory |
 | 
			
		||||
|        Example        |                                                                                                                                        Location + Description                                                                                                                                         |
 | 
			
		||||
| :-------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
 | 
			
		||||
|    **QuickStart**     |                                         [examples/quickstart.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/quickstart.js) uses the fewest options and accepts all default settings. It's guaranteed to work for you.                                          |
 | 
			
		||||
|      Production       | [examples/production.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/production.js) shows how to require an express app (or other middleware system), expand the `approveDomains` callback, provides an example database shim, and exposes the server instance. |
 | 
			
		||||
| Virtual Hosting  |                                            [examples/vhost.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/vhost.js) shows how to dynamically secure and serve domains based on their existance on the file system.                                             |
 | 
			
		||||
| Wildcard Domains |                                                        [examples/wildcard.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/wildcard.js) shows how to use the `acme-dns-01-cli` and wildcard cetificates.                                                         |
 | 
			
		||||
|   HTTPS (raw)    |                                     [examples/spdy.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/spdy.js) demonstrates how to manually configure a node web server using the node's built-in `http` and `https` modules.                                      |
 | 
			
		||||
|   HTTP2 (spdy)   |             Presently spdy is incompatible with node v11, but [examples/spdy.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/spdy.js) demonstrates how to manually configure a node web server with spdy-compatible versions of node and Greenlock.             |
 | 
			
		||||
|   HTTP2 (node)   |                             [examples/http2.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/http2.js) uses node's new HTTP2 module, which is NOT compatible with the existing middleware systems (and is not "stable" as of v10.0).                             |
 | 
			
		||||
| WebSockets (ws)  |                                                     [examples/websockets.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/websockets.js) demonstrates how to use Greenlock express with a websocket server.                                                      |
 | 
			
		||||
|       socket.io       |                         [examples/socket.io.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/socket.io.js) demonstrates how to use Greenlock express with socket.io (even though `ws` is far simpler, faster, and better and every way).                         |
 | 
			
		||||
|           -           |                                                                    Build Your Own <br> Be sure to tell me ([@solderjs](https://twitter.com/@solderjs)) / us ([@GreenlockHTTPS](https://twitter.com/@GreenlockHTTPS)) about it. :)                                                                     |
 | 
			
		||||
|    Full List     |                                                                                        Check out the [examples/](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples) directory                                                                                         |
 | 
			
		||||
 | 
			
		||||
# Plugins
 | 
			
		||||
 | 
			
		||||
@ -230,51 +234,49 @@ https://acme-staging-v02.api.letsencrypt.org/directory
 | 
			
		||||
 | 
			
		||||
## HTTP-01 Challenges
 | 
			
		||||
 | 
			
		||||
|                | Plugin    |
 | 
			
		||||
|:--------------:|:---------:|
 | 
			
		||||
| **Default (fs)** | [acme-http-01-fs](https://git.rootprojects.org/root/acme-http-01-webroot.js) |
 | 
			
		||||
| **Manual (cli)** | [acme-http-01-cli](https://git.rootprojects.org/root/acme-http-01-cli.js) |
 | 
			
		||||
| AWS S3         | [acme-http-01-s3](https://git.rootprojects.org/root/acme-http-01-s3.js) |
 | 
			
		||||
| Azure          | [kolarcz/node-le-challenge-azure-storage](https://github.com/kolarcz/node-le-challenge-azure-storage) |
 | 
			
		||||
| - | Build Your Own <br> [acme-http-01-challenge-test](https://git.rootprojects.org/root/acme-challenge-test.js) |
 | 
			
		||||
| Full List      | Search [acme-http-01-](https://www.npmjs.com/search?q=acme-http-01-) on npm (or [le-challenge-](https://www.npmjs.com/search?q=le-challenge-) for older versions) |
 | 
			
		||||
 | 
			
		||||
|                  |                                                                              Plugin                                                                               |
 | 
			
		||||
| :--------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------: |
 | 
			
		||||
| **Default (fs)** |                                           [acme-http-01-fs](https://git.rootprojects.org/root/acme-http-01-webroot.js)                                            |
 | 
			
		||||
| **Manual (cli)** |                                             [acme-http-01-cli](https://git.rootprojects.org/root/acme-http-01-cli.js)                                             |
 | 
			
		||||
|      AWS S3      |                                              [acme-http-01-s3](https://git.rootprojects.org/root/acme-http-01-s3.js)                                              |
 | 
			
		||||
|      Azure       |                               [kolarcz/node-le-challenge-azure-storage](https://github.com/kolarcz/node-le-challenge-azure-storage)                               |
 | 
			
		||||
|        -         |                            Build Your Own <br> [acme-http-01-challenge-test](https://git.rootprojects.org/root/acme-challenge-test.js)                            |
 | 
			
		||||
|    Full List     | Search [acme-http-01-](https://www.npmjs.com/search?q=acme-http-01-) on npm (or [le-challenge-](https://www.npmjs.com/search?q=le-challenge-) for older versions) |
 | 
			
		||||
 | 
			
		||||
## DNS-01 Challenges
 | 
			
		||||
 | 
			
		||||
|                | Plugin    |
 | 
			
		||||
|:--------------:|:---------:|
 | 
			
		||||
| **Manual (cli)** | [acme-dns-01-cli](https://git.rootprojects.org/root/acme-dns-01-cli.js) |
 | 
			
		||||
| AWS Route 53   | [thadeetrompetter/le-challenge-route53](https://github.com/thadeetrompetter/le-challenge-route53) |
 | 
			
		||||
| CloudFlare     | [buschtoens/le-challenge-cloudflare](https://github.com/buschtoens/le-challenge-cloudflare) |
 | 
			
		||||
| CloudFlare     | [llun/le-challenge-cloudflare](https://github.com/llun/le-challenge-cloudflare) |
 | 
			
		||||
| Digital Ocean  | [bmv437/le-challenge-digitalocean](https://github.com/bmv437/le-challenge-digitalocean) |
 | 
			
		||||
| etcd           | [ceecko/le-challenge-etcd](https://github.com/ceecko/le-challenge-etcd) |
 | 
			
		||||
| - | Build Your Own <br> [acme-challenge-test](https://git.rootprojects.org/root/acme-challenge-test.js) |
 | 
			
		||||
| Full List      | Search [acme-dns-01-](https://www.npmjs.com/search?q=acme-dns-01-) or [le-challenge-](https://www.npmjs.com/search?q=le-challenge-) on npm |
 | 
			
		||||
|                  |                                                                   Plugin                                                                   |
 | 
			
		||||
| :--------------: | :----------------------------------------------------------------------------------------------------------------------------------------: |
 | 
			
		||||
| **Manual (cli)** |                                  [acme-dns-01-cli](https://git.rootprojects.org/root/acme-dns-01-cli.js)                                   |
 | 
			
		||||
|   AWS Route 53   |                     [thadeetrompetter/le-challenge-route53](https://github.com/thadeetrompetter/le-challenge-route53)                      |
 | 
			
		||||
|    CloudFlare    |                        [buschtoens/le-challenge-cloudflare](https://github.com/buschtoens/le-challenge-cloudflare)                         |
 | 
			
		||||
|    CloudFlare    |                              [llun/le-challenge-cloudflare](https://github.com/llun/le-challenge-cloudflare)                               |
 | 
			
		||||
|  Digital Ocean   |                          [bmv437/le-challenge-digitalocean](https://github.com/bmv437/le-challenge-digitalocean)                           |
 | 
			
		||||
|       etcd       |                                  [ceecko/le-challenge-etcd](https://github.com/ceecko/le-challenge-etcd)                                   |
 | 
			
		||||
|        -         |                    Build Your Own <br> [acme-challenge-test](https://git.rootprojects.org/root/acme-challenge-test.js)                     |
 | 
			
		||||
|    Full List     | Search [acme-dns-01-](https://www.npmjs.com/search?q=acme-dns-01-) or [le-challenge-](https://www.npmjs.com/search?q=le-challenge-) on npm |
 | 
			
		||||
 | 
			
		||||
## Account & Certificate Storage
 | 
			
		||||
 | 
			
		||||
|                | Plugin    |
 | 
			
		||||
|:--------------:|:---------:|
 | 
			
		||||
| **Simplest** | [greenlock-store-fs](https://git.rootprojects.org/root/greenlock-store-fs.js) |
 | 
			
		||||
| certbot (v2 default) | [le-store-certbot](https://git.coolaj86.com/coolaj86/le-store-certbot.js) |
 | 
			
		||||
| AWS S3         | [gl-store-s3](https://git.rootprojects.org/root/gl-store-s3.js) |
 | 
			
		||||
| Consul         | [sebastian-software/le-store-consul](https://github.com/sebastian-software/le-store-consul) |
 | 
			
		||||
| json (fs)      | [paulgrove/le-store-simple-fs](https://github.com/paulgrove/le-store-simple-fs)
 | 
			
		||||
| Redis          | [digitalbazaar/le-store-redis](https://github.com/digitalbazaar/le-store-redis) |
 | 
			
		||||
| - | Build Your Own <br> [greenlock-store-test](https://git.rootprojects.org/root/greenlock-store-test.js) |
 | 
			
		||||
| Full List      | Search [le-store-](https://www.npmjs.com/search?q=le-store-) on npm |
 | 
			
		||||
|                      |                                                Plugin                                                 |
 | 
			
		||||
| :------------------: | :---------------------------------------------------------------------------------------------------: |
 | 
			
		||||
|     **Simplest**     |             [greenlock-store-fs](https://git.rootprojects.org/root/greenlock-store-fs.js)             |
 | 
			
		||||
| certbot (v2 default) |               [le-store-certbot](https://git.coolaj86.com/coolaj86/le-store-certbot.js)               |
 | 
			
		||||
|        AWS S3        |                    [gl-store-s3](https://git.rootprojects.org/root/gl-store-s3.js)                    |
 | 
			
		||||
|        Consul        |      [sebastian-software/le-store-consul](https://github.com/sebastian-software/le-store-consul)      |
 | 
			
		||||
|      json (fs)       |            [paulgrove/le-store-simple-fs](https://github.com/paulgrove/le-store-simple-fs)            |
 | 
			
		||||
|        Redis         |            [digitalbazaar/le-store-redis](https://github.com/digitalbazaar/le-store-redis)            |
 | 
			
		||||
|          -           | Build Your Own <br> [greenlock-store-test](https://git.rootprojects.org/root/greenlock-store-test.js) |
 | 
			
		||||
|      Full List       |                  Search [le-store-](https://www.npmjs.com/search?q=le-store-) on npm                  |
 | 
			
		||||
 | 
			
		||||
## Auto-SNI
 | 
			
		||||
 | 
			
		||||
|             | Plugin    |
 | 
			
		||||
|:-----------:|:---------:|
 | 
			
		||||
|             |                             Plugin                              |
 | 
			
		||||
| :---------: | :-------------------------------------------------------------: |
 | 
			
		||||
| **Default** | [le-sni-auto](https://git.coolaj86.com/coolaj86/le-sni-auto.js) |
 | 
			
		||||
 | 
			
		||||
(you probably wouldn't need or want to replace this)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**Bugs**: Please report bugs with the community plugins to the appropriate owner first, then here if you don't get a response.
 | 
			
		||||
 | 
			
		||||
# Usage
 | 
			
		||||
@ -300,34 +302,35 @@ node greenlock-express.js/examples/normal.js
 | 
			
		||||
It looks a little more like this:
 | 
			
		||||
 | 
			
		||||
`serve.js`:
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
// returns an instance of greenlock.js with additional helper methods
 | 
			
		||||
var glx = require('greenlock-express').create({
 | 
			
		||||
  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
 | 
			
		||||
, version: 'draft-11' // Let's Encrypt v2 (ACME v2)
 | 
			
		||||
var glx = require("greenlock-express").create({
 | 
			
		||||
	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
 | 
			
		||||
	version: "draft-11", // Let's Encrypt v2 (ACME v2)
 | 
			
		||||
 | 
			
		||||
  // If you wish to replace the default account and domain key storage plugin
 | 
			
		||||
, store: require('le-store-certbot').create({
 | 
			
		||||
    configDir: require('path').join(require('os').homedir(), 'acme', 'etc')
 | 
			
		||||
  , webrootPath: '/tmp/acme-challenges'
 | 
			
		||||
  })
 | 
			
		||||
	// If you wish to replace the default account and domain key storage plugin
 | 
			
		||||
	store: require("le-store-certbot").create({
 | 
			
		||||
		configDir: require("path").join(require("os").homedir(), "acme", "etc"),
 | 
			
		||||
		webrootPath: "/tmp/acme-challenges"
 | 
			
		||||
	}),
 | 
			
		||||
 | 
			
		||||
  // Contribute telemetry data to the project
 | 
			
		||||
, telemetry: true
 | 
			
		||||
	// Contribute telemetry data to the project
 | 
			
		||||
	telemetry: true,
 | 
			
		||||
 | 
			
		||||
  // the default servername to use when the client doesn't specify
 | 
			
		||||
  // (because some IoT devices don't support servername indication)
 | 
			
		||||
, servername: 'example.com'
 | 
			
		||||
	// the default servername to use when the client doesn't specify
 | 
			
		||||
	// (because some IoT devices don't support servername indication)
 | 
			
		||||
	servername: "example.com",
 | 
			
		||||
 | 
			
		||||
, approveDomains: approveDomains
 | 
			
		||||
	approveDomains: approveDomains
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var server = glx.listen(80, 443, function () {
 | 
			
		||||
  console.log("Listening on port 80 for ACME challenges and 443 for express app.");
 | 
			
		||||
var server = glx.listen(80, 443, function() {
 | 
			
		||||
	console.log("Listening on port 80 for ACME challenges and 443 for express app.");
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -341,53 +344,54 @@ plainServer.on('error', function (err) { ... });
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The Automatic Certificate Issuance is initiated via SNI (`httpsOptions.SNICallback`).
 | 
			
		||||
For security, domain validation MUST have an approval callback in *production*.
 | 
			
		||||
For security, domain validation MUST have an approval callback in _production_.
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
var http01 = require('le-challenge-fs').create({ webrootPath: '/tmp/acme-challenges' });
 | 
			
		||||
var http01 = require("le-challenge-fs").create({ webrootPath: "/tmp/acme-challenges" });
 | 
			
		||||
function approveDomains(opts, certs, cb) {
 | 
			
		||||
  // This is where you check your database and associated
 | 
			
		||||
  // email addresses with domains and agreements and such
 | 
			
		||||
  // if (!isAllowed(opts.domains)) { return cb(new Error("not allowed")); }
 | 
			
		||||
	// This is where you check your database and associated
 | 
			
		||||
	// email addresses with domains and agreements and such
 | 
			
		||||
	// if (!isAllowed(opts.domains)) { return cb(new Error("not allowed")); }
 | 
			
		||||
 | 
			
		||||
  // The domains being approved for the first time are listed in opts.domains
 | 
			
		||||
  // Certs being renewed are listed in certs.altnames (if that's useful)
 | 
			
		||||
	// The domains being approved for the first time are listed in opts.domains
 | 
			
		||||
	// Certs being renewed are listed in certs.altnames (if that's useful)
 | 
			
		||||
 | 
			
		||||
  // Opt-in to submit stats and get important updates
 | 
			
		||||
  opts.communityMember = true;
 | 
			
		||||
	// Opt-in to submit stats and get important updates
 | 
			
		||||
	opts.communityMember = true;
 | 
			
		||||
 | 
			
		||||
  // If you wish to replace the default challenge plugin, you may do so here
 | 
			
		||||
  opts.challenges = { 'http-01': http01 };
 | 
			
		||||
	// If you wish to replace the default challenge plugin, you may do so here
 | 
			
		||||
	opts.challenges = { "http-01": http01 };
 | 
			
		||||
 | 
			
		||||
  opts.email = 'john.doe@example.com';
 | 
			
		||||
  opts.agreeTos = true;
 | 
			
		||||
	opts.email = "john.doe@example.com";
 | 
			
		||||
	opts.agreeTos = true;
 | 
			
		||||
 | 
			
		||||
  // NOTE: you can also change other options such as `challengeType` and `challenge`
 | 
			
		||||
  // opts.challengeType = 'http-01';
 | 
			
		||||
  // opts.challenge = require('le-challenge-fs').create({});
 | 
			
		||||
	// NOTE: you can also change other options such as `challengeType` and `challenge`
 | 
			
		||||
	// opts.challengeType = 'http-01';
 | 
			
		||||
	// opts.challenge = require('le-challenge-fs').create({});
 | 
			
		||||
 | 
			
		||||
  cb(null, { options: opts, certs: certs });
 | 
			
		||||
	cb(null, { options: opts, certs: certs });
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
// handles acme-challenge and redirects to https
 | 
			
		||||
require('http').createServer(glx.middleware(require('redirect-https')())).listen(80, function () {
 | 
			
		||||
  console.log("Listening for ACME http-01 challenges on", this.address());
 | 
			
		||||
});
 | 
			
		||||
require("http")
 | 
			
		||||
	.createServer(glx.middleware(require("redirect-https")()))
 | 
			
		||||
	.listen(80, function() {
 | 
			
		||||
		console.log("Listening for ACME http-01 challenges on", this.address());
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var app = require('express')();
 | 
			
		||||
app.use('/', function (req, res) {
 | 
			
		||||
  res.end('Hello, World!');
 | 
			
		||||
var app = require("express")();
 | 
			
		||||
app.use("/", function(req, res) {
 | 
			
		||||
	res.end("Hello, World!");
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// handles your app
 | 
			
		||||
require('https').createServer(glx.httpsOptions, app).listen(443, function () {
 | 
			
		||||
  console.log("Listening for ACME tls-sni-01 challenges and serve app on", this.address());
 | 
			
		||||
});
 | 
			
		||||
require("https")
 | 
			
		||||
	.createServer(glx.httpsOptions, app)
 | 
			
		||||
	.listen(443, function() {
 | 
			
		||||
		console.log("Listening for ACME tls-sni-01 challenges and serve app on", this.address());
 | 
			
		||||
	});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Security**:
 | 
			
		||||
@ -395,7 +399,6 @@ require('https').createServer(glx.httpsOptions, app).listen(443, function () {
 | 
			
		||||
Greenlock will do a self-check on all domain registrations
 | 
			
		||||
to prevent you from hitting rate limits.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# API
 | 
			
		||||
 | 
			
		||||
This module is an elaborate ruse (to provide an oversimplified example and to nab some SEO).
 | 
			
		||||
@ -405,35 +408,35 @@ The API is actually located at [greenlock.js options](https://git.rootprojects.o
 | 
			
		||||
 | 
			
		||||
The only "API" consists of two options, the rest is just a wrapper around `greenlock.js` to take LOC from 15 to 5:
 | 
			
		||||
 | 
			
		||||
* `opts.app` An express app in the format `function (req, res) { ... }` (no `next`).
 | 
			
		||||
* `server = glx.listen(plainAddr, tlsAddr, onListen)` Accepts port numbers (or arrays of port numbers) to listen on, returns secure server.
 | 
			
		||||
  * `listen(80, 443)`
 | 
			
		||||
  * `listen(80, 443, onListenSecure)`
 | 
			
		||||
  * `listen(80, 443, onListenPlain, onListenSecure)`
 | 
			
		||||
  * `listen('localhost:80', '0.0.0.0:443')`
 | 
			
		||||
  * `listen('[::1]:80', '[::]:443')`
 | 
			
		||||
  * `listen('/tmp/glx.plain.sock', '/tmp/glx.secure.sock')`
 | 
			
		||||
- `opts.app` An express app in the format `function (req, res) { ... }` (no `next`).
 | 
			
		||||
- `server = glx.listen(plainAddr, tlsAddr, onListen)` Accepts port numbers (or arrays of port numbers) to listen on, returns secure server.
 | 
			
		||||
  - `listen(80, 443)`
 | 
			
		||||
  - `listen(80, 443, onListenSecure)`
 | 
			
		||||
  - `listen(80, 443, onListenPlain, onListenSecure)`
 | 
			
		||||
  - `listen('localhost:80', '0.0.0.0:443')`
 | 
			
		||||
  - `listen('[::1]:80', '[::]:443')`
 | 
			
		||||
  - `listen('/tmp/glx.plain.sock', '/tmp/glx.secure.sock')`
 | 
			
		||||
 | 
			
		||||
Brief overview of some simple options for `greenlock.js`:
 | 
			
		||||
 | 
			
		||||
* `opts.server` set to https://acme-v02.api.letsencrypt.org/directory in production
 | 
			
		||||
* `opts.version` set to `v01` for Let's Encrypt v1 or `draft-11` for Let's Encrypt v2 (mistakenly called ACME v2)
 | 
			
		||||
* `opts.email` The default email to use to accept agreements.
 | 
			
		||||
* `opts.agreeTos` When set to `true`, this always accepts the LetsEncrypt TOS. When a string it checks the agreement url first.
 | 
			
		||||
* `opts.communityMember` Join the community to get notified of important updates and help make greenlock better
 | 
			
		||||
* `opts.approveDomains` can be either of:
 | 
			
		||||
  * An explicit array of allowed domains such as `[ 'example.com', 'www.example.com' ]`
 | 
			
		||||
  * A callback `function (opts, certs, cb) { cb(null, { options: opts, certs: certs }); }` for setting `email`, `agreeTos`, `domains`, etc (as shown in usage example above)
 | 
			
		||||
* `opts.renewWithin` is the **maximum** number of days (in ms) before expiration to renew a certificate.
 | 
			
		||||
* `opts.renewBy` is the **minimum** number of days (in ms) before expiration to renew a certificate.
 | 
			
		||||
- `opts.server` set to https://acme-v02.api.letsencrypt.org/directory in production
 | 
			
		||||
- `opts.version` set to `v01` for Let's Encrypt v1 or `draft-11` for Let's Encrypt v2 (mistakenly called ACME v2)
 | 
			
		||||
- `opts.email` The default email to use to accept agreements.
 | 
			
		||||
- `opts.agreeTos` When set to `true`, this always accepts the LetsEncrypt TOS. When a string it checks the agreement url first.
 | 
			
		||||
- `opts.communityMember` Join the community to get notified of important updates and help make greenlock better
 | 
			
		||||
- `opts.approveDomains` can be either of:
 | 
			
		||||
  - An explicit array of allowed domains such as `[ 'example.com', 'www.example.com' ]`
 | 
			
		||||
  - A callback `function (opts, certs, cb) { cb(null, { options: opts, certs: certs }); }` for setting `email`, `agreeTos`, `domains`, etc (as shown in usage example above)
 | 
			
		||||
- `opts.renewWithin` is the **maximum** number of days (in ms) before expiration to renew a certificate.
 | 
			
		||||
- `opts.renewBy` is the **minimum** number of days (in ms) before expiration to renew a certificate.
 | 
			
		||||
 | 
			
		||||
## Supported ACME versions
 | 
			
		||||
 | 
			
		||||
* Let's Encrypt v1 (aka v01)
 | 
			
		||||
* Let's Encrypt v2 (aka v02 or ACME draft 11)
 | 
			
		||||
* ACME draft 11 (ACME v2 is a misnomer)
 | 
			
		||||
* Wildcard domains (via dns-01 challenges)
 | 
			
		||||
  * `*.example.com`
 | 
			
		||||
- Let's Encrypt v1 (aka v01)
 | 
			
		||||
- Let's Encrypt v2 (aka v02 or ACME draft 11)
 | 
			
		||||
- ACME draft 11 (ACME v2 is a misnomer)
 | 
			
		||||
- Wildcard domains (via dns-01 challenges)
 | 
			
		||||
  - `*.example.com`
 | 
			
		||||
 | 
			
		||||
<small>tags: letsencrypt acme free ssl automated https node express.js</small>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								config.js
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								config.js
									
									
									
									
									
								
							@ -1,9 +1,9 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
var path = require('path');
 | 
			
		||||
var path = require("path");
 | 
			
		||||
module.exports = {
 | 
			
		||||
  email: 'jon.doe@example.com'
 | 
			
		||||
, configDir: path.join(__dirname, 'acme')
 | 
			
		||||
, srv: '/srv/www/'
 | 
			
		||||
, api: '/srv/api/'
 | 
			
		||||
	email: "jon.doe@example.com",
 | 
			
		||||
	configDir: path.join(__dirname, "acme"),
 | 
			
		||||
	srv: "/srv/www/",
 | 
			
		||||
	api: "/srv/api/"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,59 +1,56 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
// npm install spdy@3.x
 | 
			
		||||
 | 
			
		||||
//var Greenlock = require('greenlock-express')
 | 
			
		||||
var Greenlock = require('../');
 | 
			
		||||
var Greenlock = require("../");
 | 
			
		||||
 | 
			
		||||
var greenlock = Greenlock.create({
 | 
			
		||||
	// Let's Encrypt v2 is ACME draft 11
 | 
			
		||||
	version: "draft-11",
 | 
			
		||||
 | 
			
		||||
  // 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
 | 
			
		||||
 | 
			
		||||
, 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 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 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 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/",
 | 
			
		||||
 | 
			
		||||
  // 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
 | 
			
		||||
	// 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>'
 | 
			
		||||
  );
 | 
			
		||||
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());
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
require("http")
 | 
			
		||||
	.createServer(acmeChallengeHandler)
 | 
			
		||||
	.listen(80, function() {
 | 
			
		||||
		console.log("Listening for ACME http-01 challenges on", this.address());
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
////////////////////////
 | 
			
		||||
// http2 via SPDY h2  //
 | 
			
		||||
@ -61,15 +58,18 @@ require('http').createServer(acmeChallengeHandler).listen(80, function () {
 | 
			
		||||
 | 
			
		||||
// 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);
 | 
			
		||||
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.on("listening", function() {
 | 
			
		||||
	console.log("Listening for SPDY/http2/https requests on", this.address());
 | 
			
		||||
});
 | 
			
		||||
server.listen(443);
 | 
			
		||||
 | 
			
		||||
@ -1,29 +1,30 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
//require('greenlock-express')
 | 
			
		||||
require('../').create({
 | 
			
		||||
require("../")
 | 
			
		||||
	.create({
 | 
			
		||||
		// Let's Encrypt v2 is ACME draft 11
 | 
			
		||||
		version: "draft-11",
 | 
			
		||||
 | 
			
		||||
  // 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
 | 
			
		||||
 | 
			
		||||
, 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",
 | 
			
		||||
 | 
			
		||||
, email: 'john.doe@example.com'
 | 
			
		||||
		agreeTos: true,
 | 
			
		||||
 | 
			
		||||
, agreeTos: true
 | 
			
		||||
		approvedDomains: ["example.com", "www.example.com"],
 | 
			
		||||
 | 
			
		||||
, approvedDomains: [ 'example.com', 'www.example.com' ]
 | 
			
		||||
		app: require("express")().use("/", function(req, res) {
 | 
			
		||||
			res.end("Hello, World!");
 | 
			
		||||
		}),
 | 
			
		||||
 | 
			
		||||
, app: require('express')().use('/', function (req, res) {
 | 
			
		||||
    res.end('Hello, World!');
 | 
			
		||||
  })
 | 
			
		||||
		renewWithin: 91 * 24 * 60 * 60 * 1000,
 | 
			
		||||
		renewBy: 90 * 24 * 60 * 60 * 1000,
 | 
			
		||||
 | 
			
		||||
, 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);
 | 
			
		||||
		// Get notified of important updates and help me make greenlock better
 | 
			
		||||
		communityMember: true,
 | 
			
		||||
		debug: true
 | 
			
		||||
	})
 | 
			
		||||
	.listen(80, 443);
 | 
			
		||||
 | 
			
		||||
@ -1,74 +1,70 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
//var Greenlock = require('greenlock-express')
 | 
			
		||||
var Greenlock = require('../');
 | 
			
		||||
var Greenlock = require("../");
 | 
			
		||||
 | 
			
		||||
var greenlock = Greenlock.create({
 | 
			
		||||
	// Let's Encrypt v2 is ACME draft 11
 | 
			
		||||
	version: "draft-11",
 | 
			
		||||
 | 
			
		||||
  // 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
 | 
			
		||||
 | 
			
		||||
, 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 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 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 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/",
 | 
			
		||||
 | 
			
		||||
  // 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
 | 
			
		||||
	// 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 redirectHttps = require("redirect-https")();
 | 
			
		||||
var acmeChallengeHandler = greenlock.middleware(redirectHttps);
 | 
			
		||||
require('http').createServer(acmeChallengeHandler).listen(80, function () {
 | 
			
		||||
  console.log("Listening for ACME http-01 challenges on", this.address());
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
require("http")
 | 
			
		||||
	.createServer(acmeChallengeHandler)
 | 
			
		||||
	.listen(80, function() {
 | 
			
		||||
		console.log("Listening for ACME http-01 challenges on", this.address());
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
////////////////////////
 | 
			
		||||
// node.js' http2 api //
 | 
			
		||||
////////////////////////
 | 
			
		||||
 | 
			
		||||
// http2 is a new API with which you would use hapi or koa, not express
 | 
			
		||||
var server = require('http2').createSecureServer(greenlock.tlsOptions);
 | 
			
		||||
server.on('error', function (err) {
 | 
			
		||||
  console.error(err);
 | 
			
		||||
var server = require("http2").createSecureServer(greenlock.tlsOptions);
 | 
			
		||||
server.on("error", function(err) {
 | 
			
		||||
	console.error(err);
 | 
			
		||||
});
 | 
			
		||||
// WARNING: Because the middleware don't handle this API style,
 | 
			
		||||
// the Host headers are unmodified and potentially dangerous
 | 
			
		||||
// (ex: Host: Robert'); DROP TABLE Students;)
 | 
			
		||||
server.on('stream', function (stream, headers) {
 | 
			
		||||
  console.log(headers);
 | 
			
		||||
  stream.respond({
 | 
			
		||||
    'content-type': 'text/html'
 | 
			
		||||
  , ':status': 200
 | 
			
		||||
  });
 | 
			
		||||
  stream.end('Hello, HTTP2 World!');
 | 
			
		||||
server.on("stream", function(stream, headers) {
 | 
			
		||||
	console.log(headers);
 | 
			
		||||
	stream.respond({
 | 
			
		||||
		"content-type": "text/html",
 | 
			
		||||
		":status": 200
 | 
			
		||||
	});
 | 
			
		||||
	stream.end("Hello, HTTP2 World!");
 | 
			
		||||
});
 | 
			
		||||
server.on('listening', function () {
 | 
			
		||||
  console.log("Listening for http2 requests on", this.address());
 | 
			
		||||
server.on("listening", function() {
 | 
			
		||||
	console.log("Listening for http2 requests on", this.address());
 | 
			
		||||
});
 | 
			
		||||
server.listen(443);
 | 
			
		||||
 | 
			
		||||
@ -1,15 +1,17 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
var express = require('express');
 | 
			
		||||
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');
 | 
			
		||||
app.use("/", function(req, res) {
 | 
			
		||||
	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); }
 | 
			
		||||
if (require.main === module) {
 | 
			
		||||
	app.listen(3000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Instead do export the app:
 | 
			
		||||
module.exports = app;
 | 
			
		||||
 | 
			
		||||
@ -1,90 +1,88 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// My Secure Server
 | 
			
		||||
//
 | 
			
		||||
//var greenlock = require('greenlock-express')
 | 
			
		||||
var greenlock = require('../').create({
 | 
			
		||||
var greenlock = require("../").create({
 | 
			
		||||
	// Let's Encrypt v2 is ACME draft 11
 | 
			
		||||
	// Note: If at first you don't succeed, stop and switch to staging
 | 
			
		||||
	// https://acme-staging-v02.api.letsencrypt.org/directory
 | 
			
		||||
	server: "https://acme-v02.api.letsencrypt.org/directory",
 | 
			
		||||
	version: "draft-11",
 | 
			
		||||
	// You MUST have write access to save certs
 | 
			
		||||
	configDir: "~/.config/acme/",
 | 
			
		||||
 | 
			
		||||
  // Let's Encrypt v2 is ACME draft 11
 | 
			
		||||
  // Note: If at first you don't succeed, stop and switch to staging
 | 
			
		||||
  // https://acme-staging-v02.api.letsencrypt.org/directory
 | 
			
		||||
  server: 'https://acme-v02.api.letsencrypt.org/directory'
 | 
			
		||||
, version: 'draft-11'
 | 
			
		||||
  // You MUST have write access to save certs
 | 
			
		||||
, configDir: '~/.config/acme/'
 | 
			
		||||
	// The previous 'simple' example set these values statically,
 | 
			
		||||
	// but this example uses approveDomains() to set them dynamically
 | 
			
		||||
	//, email: 'none@see.note.above'
 | 
			
		||||
	//, agreeTos: false
 | 
			
		||||
 | 
			
		||||
// The previous 'simple' example set these values statically,
 | 
			
		||||
// but this example uses approveDomains() to set them dynamically
 | 
			
		||||
//, email: 'none@see.note.above'
 | 
			
		||||
//, agreeTos: false
 | 
			
		||||
	// approveDomains is the right place to check a database for
 | 
			
		||||
	// email addresses with domains and agreements and such
 | 
			
		||||
	approveDomains: approveDomains,
 | 
			
		||||
 | 
			
		||||
  // approveDomains is the right place to check a database for
 | 
			
		||||
  // email addresses with domains and agreements and such
 | 
			
		||||
, approveDomains: approveDomains
 | 
			
		||||
	app: require("./my-express-app.js"),
 | 
			
		||||
 | 
			
		||||
, app: require('./my-express-app.js')
 | 
			
		||||
 | 
			
		||||
  // Get notified of important updates and help me make greenlock better
 | 
			
		||||
, communityMember: true
 | 
			
		||||
 | 
			
		||||
//, debug: true
 | 
			
		||||
	// Get notified of important updates and help me make greenlock better
 | 
			
		||||
	communityMember: true
 | 
			
		||||
 | 
			
		||||
	//, debug: true
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var server = greenlock.listen(80, 443);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// My Secure Database Check
 | 
			
		||||
//
 | 
			
		||||
function approveDomains(opts, certs, cb) {
 | 
			
		||||
	// Only one domain is listed with *automatic* registration via SNI
 | 
			
		||||
	// (it's an array because managed registration allows for multiple domains,
 | 
			
		||||
	//                                which was the case in the simple example)
 | 
			
		||||
	console.log(opts.domains);
 | 
			
		||||
 | 
			
		||||
  // Only one domain is listed with *automatic* registration via SNI
 | 
			
		||||
  // (it's an array because managed registration allows for multiple domains,
 | 
			
		||||
  //                                which was the case in the simple example)
 | 
			
		||||
  console.log(opts.domains);
 | 
			
		||||
	// The domains being approved for the first time are listed in opts.domains
 | 
			
		||||
	// Certs being renewed are listed in certs.altnames
 | 
			
		||||
	if (certs) {
 | 
			
		||||
		opts.domains = [certs.subject].concat(certs.altnames);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  // The domains being approved for the first time are listed in opts.domains
 | 
			
		||||
  // Certs being renewed are listed in certs.altnames
 | 
			
		||||
  if (certs) {
 | 
			
		||||
    opts.domains = [certs.subject].concat(certs.altnames);
 | 
			
		||||
  }
 | 
			
		||||
	fooCheckDb(opts.domains, function(err, agree, email) {
 | 
			
		||||
		if (err) {
 | 
			
		||||
			cb(err);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
  fooCheckDb(opts.domains, function (err, agree, email) {
 | 
			
		||||
    if (err) { cb(err); return; }
 | 
			
		||||
		// Services SHOULD automatically accept the ToS and use YOUR email
 | 
			
		||||
		// Clients MUST NOT accept the ToS without asking the user
 | 
			
		||||
		opts.agreeTos = agree;
 | 
			
		||||
		opts.email = email;
 | 
			
		||||
 | 
			
		||||
    // Services SHOULD automatically accept the ToS and use YOUR email
 | 
			
		||||
    // Clients MUST NOT accept the ToS without asking the user
 | 
			
		||||
    opts.agreeTos = agree;
 | 
			
		||||
    opts.email = email;
 | 
			
		||||
		// NOTE: you can also change other options such as `challengeType` and `challenge`
 | 
			
		||||
		// (this would be helpful if you decided you wanted wildcard support as a domain altname)
 | 
			
		||||
		// opts.challengeType = 'http-01';
 | 
			
		||||
		// opts.challenge = require('le-challenge-fs').create({});
 | 
			
		||||
 | 
			
		||||
    // NOTE: you can also change other options such as `challengeType` and `challenge`
 | 
			
		||||
    // (this would be helpful if you decided you wanted wildcard support as a domain altname)
 | 
			
		||||
    // opts.challengeType = 'http-01';
 | 
			
		||||
    // opts.challenge = require('le-challenge-fs').create({});
 | 
			
		||||
 | 
			
		||||
    cb(null, { options: opts, certs: certs });
 | 
			
		||||
  });
 | 
			
		||||
		cb(null, { options: opts, certs: certs });
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// My User / Domain Database
 | 
			
		||||
//
 | 
			
		||||
function fooCheckDb(domains, cb) {
 | 
			
		||||
  // This is an oversimplified example of how we might implement a check in
 | 
			
		||||
  // our database if we have different rules for different users and domains
 | 
			
		||||
  var domains = [ 'example.com', 'www.example.com' ];
 | 
			
		||||
  var userEmail = 'john.doe@example.com';
 | 
			
		||||
  var userAgrees = true;
 | 
			
		||||
  var passCheck = opts.domains.every(function (domain) {
 | 
			
		||||
    return -1 !== domains.indexOf(domain);
 | 
			
		||||
  });
 | 
			
		||||
	// This is an oversimplified example of how we might implement a check in
 | 
			
		||||
	// our database if we have different rules for different users and domains
 | 
			
		||||
	var domains = ["example.com", "www.example.com"];
 | 
			
		||||
	var userEmail = "john.doe@example.com";
 | 
			
		||||
	var userAgrees = true;
 | 
			
		||||
	var passCheck = opts.domains.every(function(domain) {
 | 
			
		||||
		return -1 !== domains.indexOf(domain);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
  if (!passCheck) {
 | 
			
		||||
    cb(new Error('domain not allowed'));
 | 
			
		||||
  } else {
 | 
			
		||||
    cb(null, userAgrees, userEmail);
 | 
			
		||||
  }
 | 
			
		||||
	if (!passCheck) {
 | 
			
		||||
		cb(new Error("domain not allowed"));
 | 
			
		||||
	} else {
 | 
			
		||||
		cb(null, userAgrees, userEmail);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,37 +1,38 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
//require('greenlock-express')
 | 
			
		||||
require('../').create({
 | 
			
		||||
require("../")
 | 
			
		||||
	.create({
 | 
			
		||||
		// Let's Encrypt v2 is ACME draft 11
 | 
			
		||||
		version: "draft-11",
 | 
			
		||||
 | 
			
		||||
  // 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
 | 
			
		||||
 | 
			
		||||
, 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: "john.doe@example.com",
 | 
			
		||||
 | 
			
		||||
  // You MUST change this to a valid email address
 | 
			
		||||
, email: 'john.doe@example.com'
 | 
			
		||||
		// You MUST NOT build clients that accept the ToS without asking the user
 | 
			
		||||
		agreeTos: true,
 | 
			
		||||
 | 
			
		||||
  // 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 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/",
 | 
			
		||||
		store: require("greenlock-store-fs"),
 | 
			
		||||
 | 
			
		||||
  // You MUST have access to write to directory where certs are saved
 | 
			
		||||
  // ex: /home/foouser/acme/etc
 | 
			
		||||
, configDir: '~/.config/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');
 | 
			
		||||
  })
 | 
			
		||||
		// Get notified of important updates and help me make greenlock better
 | 
			
		||||
		communityMember: true
 | 
			
		||||
 | 
			
		||||
  // Get notified of important updates and help me make greenlock better
 | 
			
		||||
, communityMember: true
 | 
			
		||||
 | 
			
		||||
//, debug: true
 | 
			
		||||
 | 
			
		||||
}).listen(80, 443);
 | 
			
		||||
		//, debug: true
 | 
			
		||||
	})
 | 
			
		||||
	.listen(80, 443);
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// WARNING: Not for noobs
 | 
			
		||||
@ -9,87 +9,96 @@
 | 
			
		||||
// This demo is used with tunnel-server.js and tunnel-client.js
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
var email = 'john.doe@gmail.com';
 | 
			
		||||
var domains = [ 'example.com' ];
 | 
			
		||||
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');
 | 
			
		||||
var secret = require("crypto")
 | 
			
		||||
	.randomBytes(16)
 | 
			
		||||
	.toString("hex");
 | 
			
		||||
 | 
			
		||||
require('../').create({
 | 
			
		||||
  version: 'draft-11'
 | 
			
		||||
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);
 | 
			
		||||
		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 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 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 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 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>';
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
	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');
 | 
			
		||||
  });
 | 
			
		||||
	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('');
 | 
			
		||||
	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;
 | 
			
		||||
	return app;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,19 +2,19 @@
 | 
			
		||||
// I'm not a fan of `socket.io` because it's huge and complex.
 | 
			
		||||
// I much prefer `ws` because it's very simple and easy.
 | 
			
		||||
// That said, it's popular.......
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
//var greenlock = require('greenlock-express');
 | 
			
		||||
var greenlock = require('../');
 | 
			
		||||
var options = require('./greenlock-options.js');
 | 
			
		||||
var socketio = require('socket.io');
 | 
			
		||||
var greenlock = require("../");
 | 
			
		||||
var options = require("./greenlock-options.js");
 | 
			
		||||
var socketio = require("socket.io");
 | 
			
		||||
var server;
 | 
			
		||||
var io;
 | 
			
		||||
 | 
			
		||||
// Any node http app will do - whether express, raw http or whatever
 | 
			
		||||
options.app = require('express')().use('/', function (req, res) {
 | 
			
		||||
  res.setHeader('Content-Type', 'text/html; charset=utf-8');
 | 
			
		||||
  res.end('Hello, World!\n\n💚 🔒.js');
 | 
			
		||||
options.app = require("express")().use("/", function(req, res) {
 | 
			
		||||
	res.setHeader("Content-Type", "text/html; charset=utf-8");
 | 
			
		||||
	res.end("Hello, World!\n\n💚 🔒.js");
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// The server that's handed back from `listen` is a raw https server
 | 
			
		||||
@ -22,11 +22,11 @@ server = greenlock.create(options).listen(80, 443);
 | 
			
		||||
io = socketio(server);
 | 
			
		||||
 | 
			
		||||
// Then you do your socket.io stuff
 | 
			
		||||
io.on('connection', function (socket) {
 | 
			
		||||
  console.log('a user connected');
 | 
			
		||||
  socket.emit('Welcome');
 | 
			
		||||
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);
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -1,54 +1,50 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
// npm install spdy@3.x
 | 
			
		||||
 | 
			
		||||
//var Greenlock = require('greenlock-express')
 | 
			
		||||
var Greenlock = require('../');
 | 
			
		||||
var Greenlock = require("../");
 | 
			
		||||
 | 
			
		||||
var greenlock = Greenlock.create({
 | 
			
		||||
	// Let's Encrypt v2 is ACME draft 11
 | 
			
		||||
	version: "draft-11",
 | 
			
		||||
 | 
			
		||||
  // 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
 | 
			
		||||
 | 
			
		||||
, 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 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 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 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/", // MUST have write access
 | 
			
		||||
 | 
			
		||||
  // You MUST have access to write to directory where certs are saved
 | 
			
		||||
  // ex: /home/foouser/acme/etc
 | 
			
		||||
, configDir: '~/.config/acme/'      // MUST have write access
 | 
			
		||||
 | 
			
		||||
  // Get notified of important updates and help me make greenlock better
 | 
			
		||||
, communityMember: true
 | 
			
		||||
 | 
			
		||||
//, debug: true
 | 
			
		||||
	// 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 redirectHttps = require("redirect-https")();
 | 
			
		||||
var acmeChallengeHandler = greenlock.middleware(redirectHttps);
 | 
			
		||||
require('http').createServer(acmeChallengeHandler).listen(80, function () {
 | 
			
		||||
  console.log("Listening for ACME http-01 challenges on", this.address());
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
require("http")
 | 
			
		||||
	.createServer(acmeChallengeHandler)
 | 
			
		||||
	.listen(80, function() {
 | 
			
		||||
		console.log("Listening for ACME http-01 challenges on", this.address());
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
////////////////////////
 | 
			
		||||
// http2 via SPDY h2  //
 | 
			
		||||
@ -56,13 +52,13 @@ require('http').createServer(acmeChallengeHandler).listen(80, function () {
 | 
			
		||||
 | 
			
		||||
// 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 myApp = require('./my-express-app.js');
 | 
			
		||||
var server = require('spdy').createServer(spdyOptions, myApp);
 | 
			
		||||
server.on('error', function (err) {
 | 
			
		||||
  console.error(err);
 | 
			
		||||
spdyOptions.spdy = { protocols: ["h2", "http/1.1"], plain: false };
 | 
			
		||||
var myApp = require("./my-express-app.js");
 | 
			
		||||
var server = require("spdy").createServer(spdyOptions, myApp);
 | 
			
		||||
server.on("error", function(err) {
 | 
			
		||||
	console.error(err);
 | 
			
		||||
});
 | 
			
		||||
server.on('listening', function () {
 | 
			
		||||
  console.log("Listening for SPDY/http2/https requests on", this.address());
 | 
			
		||||
server.on("listening", function() {
 | 
			
		||||
	console.log("Listening for SPDY/http2/https requests on", this.address());
 | 
			
		||||
});
 | 
			
		||||
server.listen(443);
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#!/usr/bin/env node
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
///////////////////
 | 
			
		||||
// vhost example //
 | 
			
		||||
@ -11,118 +11,124 @@
 | 
			
		||||
 | 
			
		||||
// 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 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 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({
 | 
			
		||||
var glx = require("./").create({
 | 
			
		||||
	version: "draft-11", // Let's Encrypt v2 is ACME draft 11
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
 | 
			
		||||
, 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
 | 
			
		||||
 | 
			
		||||
, 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
 | 
			
		||||
 | 
			
		||||
, 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)
 | 
			
		||||
 | 
			
		||||
, 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
 | 
			
		||||
	/* 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());
 | 
			
		||||
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
 | 
			
		||||
	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);
 | 
			
		||||
	// 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");
 | 
			
		||||
  });
 | 
			
		||||
	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();
 | 
			
		||||
  }
 | 
			
		||||
	// 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();
 | 
			
		||||
  });
 | 
			
		||||
	// 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();
 | 
			
		||||
		});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,40 +1,46 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
////////////////////////
 | 
			
		||||
// Greenlock Setup    //
 | 
			
		||||
////////////////////////
 | 
			
		||||
 | 
			
		||||
//var Greenlock = require('greenlock-express');
 | 
			
		||||
var Greenlock = require('../');
 | 
			
		||||
var Greenlock = require("../");
 | 
			
		||||
var greenlock = Greenlock.create({
 | 
			
		||||
	// Let's Encrypt v2 is ACME draft 11
 | 
			
		||||
	// Note: If at first you don't succeed, stop and switch to staging
 | 
			
		||||
	// https://acme-staging-v02.api.letsencrypt.org/directory
 | 
			
		||||
	server: "https://acme-v02.api.letsencrypt.org/directory",
 | 
			
		||||
	version: "draft-11",
 | 
			
		||||
	configDir: "~/.config/acme/",
 | 
			
		||||
	app: require("./my-express-app.js"),
 | 
			
		||||
 | 
			
		||||
  // Let's Encrypt v2 is ACME draft 11
 | 
			
		||||
  // Note: If at first you don't succeed, stop and switch to staging
 | 
			
		||||
  // https://acme-staging-v02.api.letsencrypt.org/directory
 | 
			
		||||
  server: 'https://acme-v02.api.letsencrypt.org/directory'
 | 
			
		||||
, version: 'draft-11'
 | 
			
		||||
, configDir: '~/.config/acme/'
 | 
			
		||||
, app: require('./my-express-app.js')
 | 
			
		||||
	// You MUST change these to a valid email and domains
 | 
			
		||||
	email: "john.doe@example.com",
 | 
			
		||||
	approvedDomains: ["example.com", "www.example.com"],
 | 
			
		||||
	agreeTos: true,
 | 
			
		||||
 | 
			
		||||
  // You MUST change these to a valid email and domains
 | 
			
		||||
, email: 'john.doe@example.com'
 | 
			
		||||
, approvedDomains: [ 'example.com', 'www.example.com' ]
 | 
			
		||||
, agreeTos: true
 | 
			
		||||
 | 
			
		||||
  // Get notified of important updates and help me make greenlock better
 | 
			
		||||
, communityMember: true
 | 
			
		||||
, telemetry: true
 | 
			
		||||
//, debug: true
 | 
			
		||||
	// Get notified of important updates and help me make greenlock better
 | 
			
		||||
	communityMember: true,
 | 
			
		||||
	telemetry: true
 | 
			
		||||
	//, debug: true
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var server = greenlock.listen(80, 443);
 | 
			
		||||
 | 
			
		||||
var WebSocket = require('ws');
 | 
			
		||||
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); });
 | 
			
		||||
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);
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#!/usr/bin/env node
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
/*global Promise*/
 | 
			
		||||
 | 
			
		||||
///////////////////////
 | 
			
		||||
@ -11,60 +11,67 @@
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
//var glx = require('greenlock-express')
 | 
			
		||||
var glx = require('../').create({
 | 
			
		||||
var glx = require("../").create({
 | 
			
		||||
	version: "draft-11", // Let's Encrypt v2 is ACME draft 11
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
 | 
			
		||||
, 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
 | 
			
		||||
 | 
			
		||||
, 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
 | 
			
		||||
 | 
			
		||||
, 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)
 | 
			
		||||
 | 
			
		||||
, 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
 | 
			
		||||
 | 
			
		||||
  /* 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')
 | 
			
		||||
	//, 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());
 | 
			
		||||
server.on("listening", function() {
 | 
			
		||||
	console.info(server.type + " listening on", server.address());
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function myApproveDomains(opts) {
 | 
			
		||||
  console.log('sni:', opts.domain);
 | 
			
		||||
	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));
 | 
			
		||||
  }
 | 
			
		||||
	// 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' ];
 | 
			
		||||
	// 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({});
 | 
			
		||||
	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 };
 | 
			
		||||
	// explicitly set account id and certificate.id
 | 
			
		||||
	opts.account = { id: opts.email };
 | 
			
		||||
	opts.certificate = { id: opts.subject };
 | 
			
		||||
 | 
			
		||||
  return Promise.resolve(opts);
 | 
			
		||||
	return Promise.resolve(opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										522
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										522
									
								
								index.js
									
									
									
									
									
								
							@ -1,265 +1,321 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
var PromiseA;
 | 
			
		||||
try {
 | 
			
		||||
  PromiseA = require('bluebird');
 | 
			
		||||
} catch(e) {
 | 
			
		||||
  PromiseA = global.Promise;
 | 
			
		||||
	PromiseA = require("bluebird");
 | 
			
		||||
} catch (e) {
 | 
			
		||||
	PromiseA = global.Promise;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// opts.approveDomains(options, certs, cb)
 | 
			
		||||
module.exports.create = function (opts) {
 | 
			
		||||
  // accept all defaults for greenlock.challenges, greenlock.store, greenlock.middleware
 | 
			
		||||
  if (!opts._communityPackage) {
 | 
			
		||||
    opts._communityPackage = 'greenlock-express.js';
 | 
			
		||||
    opts._communityPackageVersion = require('./package.json').version;
 | 
			
		||||
  }
 | 
			
		||||
module.exports.create = function(opts) {
 | 
			
		||||
	// accept all defaults for greenlock.challenges, greenlock.store, greenlock.middleware
 | 
			
		||||
	if (!opts._communityPackage) {
 | 
			
		||||
		opts._communityPackage = "greenlock-express.js";
 | 
			
		||||
		opts._communityPackageVersion = require("./package.json").version;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  function explainError(e) {
 | 
			
		||||
    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)\"");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    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.");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    console.error(e.code + ": '" + e.address + ":" + e.port + "'");
 | 
			
		||||
  }
 | 
			
		||||
	function explainError(e) {
 | 
			
		||||
		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)"');
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		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.");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		console.error(e.code + ": '" + e.address + ":" + e.port + "'");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  function _createPlain(plainPort) {
 | 
			
		||||
    if (!plainPort) { plainPort = 80; }
 | 
			
		||||
	function _createPlain(plainPort) {
 | 
			
		||||
		if (!plainPort) {
 | 
			
		||||
			plainPort = 80;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    var parts = String(plainPort).split(':');
 | 
			
		||||
    var p = parts.pop();
 | 
			
		||||
    var addr = parts.join(':').replace(/^\[/, '').replace(/\]$/, '');
 | 
			
		||||
    var args = [];
 | 
			
		||||
    var httpType;
 | 
			
		||||
    var server;
 | 
			
		||||
    var validHttpPort = (parseInt(p, 10) >= 0);
 | 
			
		||||
		var parts = String(plainPort).split(":");
 | 
			
		||||
		var p = parts.pop();
 | 
			
		||||
		var addr = parts
 | 
			
		||||
			.join(":")
 | 
			
		||||
			.replace(/^\[/, "")
 | 
			
		||||
			.replace(/\]$/, "");
 | 
			
		||||
		var args = [];
 | 
			
		||||
		var httpType;
 | 
			
		||||
		var server;
 | 
			
		||||
		var validHttpPort = parseInt(p, 10) >= 0;
 | 
			
		||||
 | 
			
		||||
    if (addr) { args[1] = addr; }
 | 
			
		||||
    if (!validHttpPort && !/(\/)|(\\\\)/.test(p)) {
 | 
			
		||||
      console.warn("'" + p + "' doesn't seem to be a valid port number, socket path, or pipe");
 | 
			
		||||
    }
 | 
			
		||||
		if (addr) {
 | 
			
		||||
			args[1] = addr;
 | 
			
		||||
		}
 | 
			
		||||
		if (!validHttpPort && !/(\/)|(\\\\)/.test(p)) {
 | 
			
		||||
			console.warn("'" + p + "' doesn't seem to be a valid port number, socket path, or pipe");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    server = require('http').createServer(
 | 
			
		||||
      greenlock.middleware.sanitizeHost(greenlock.middleware(require('redirect-https')()))
 | 
			
		||||
    );
 | 
			
		||||
    httpType = 'http';
 | 
			
		||||
		server = require("http").createServer(
 | 
			
		||||
			greenlock.middleware.sanitizeHost(greenlock.middleware(require("redirect-https")()))
 | 
			
		||||
		);
 | 
			
		||||
		httpType = "http";
 | 
			
		||||
 | 
			
		||||
    return { server: server, listen: function () { return new PromiseA(function (resolve, reject) {
 | 
			
		||||
      args[0] = p;
 | 
			
		||||
      args.push(function () {
 | 
			
		||||
        if (!greenlock.servername) {
 | 
			
		||||
          if (Array.isArray(greenlock.approvedDomains) && greenlock.approvedDomains.length) {
 | 
			
		||||
            greenlock.servername = greenlock.approvedDomains[0];
 | 
			
		||||
          }
 | 
			
		||||
          if (Array.isArray(greenlock.approveDomains) && greenlock.approvedDomains.length) {
 | 
			
		||||
            greenlock.servername = greenlock.approvedDomains[0];
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
		return {
 | 
			
		||||
			server: server,
 | 
			
		||||
			listen: function() {
 | 
			
		||||
				return new PromiseA(function(resolve, reject) {
 | 
			
		||||
					args[0] = p;
 | 
			
		||||
					args.push(function() {
 | 
			
		||||
						if (!greenlock.servername) {
 | 
			
		||||
							if (Array.isArray(greenlock.approvedDomains) && greenlock.approvedDomains.length) {
 | 
			
		||||
								greenlock.servername = greenlock.approvedDomains[0];
 | 
			
		||||
							}
 | 
			
		||||
							if (Array.isArray(greenlock.approveDomains) && greenlock.approvedDomains.length) {
 | 
			
		||||
								greenlock.servername = greenlock.approvedDomains[0];
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
        if (!greenlock.servername) {
 | 
			
		||||
          resolve(null);
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
						if (!greenlock.servername) {
 | 
			
		||||
							resolve(null);
 | 
			
		||||
							return;
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
        return greenlock.check({ domains: [ greenlock.servername ] }).then(function (certs) {
 | 
			
		||||
          if (certs) {
 | 
			
		||||
            return {
 | 
			
		||||
              key: Buffer.from(certs.privkey, 'ascii')
 | 
			
		||||
            , cert: Buffer.from(certs.cert + '\r\n' + certs.chain, 'ascii')
 | 
			
		||||
            };
 | 
			
		||||
          }
 | 
			
		||||
          console.info("Fetching certificate for '%s' to use as default for HTTPS server...", greenlock.servername);
 | 
			
		||||
          return new PromiseA(function (resolve, reject) {
 | 
			
		||||
            // using SNICallback because all options will be set
 | 
			
		||||
            greenlock.tlsOptions.SNICallback(greenlock.servername, function (err/*, secureContext*/) {
 | 
			
		||||
              if (err) { reject(err); return; }
 | 
			
		||||
              return greenlock.check({ domains: [ greenlock.servername ] }).then(function (certs) {
 | 
			
		||||
                resolve({
 | 
			
		||||
                  key: Buffer.from(certs.privkey, 'ascii')
 | 
			
		||||
                , cert: Buffer.from(certs.cert + '\r\n' + certs.chain, 'ascii')
 | 
			
		||||
                });
 | 
			
		||||
              }).catch(reject);
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
        }).then(resolve).catch(reject);
 | 
			
		||||
      });
 | 
			
		||||
      server.listen.apply(server, args).on('error', function (e) {
 | 
			
		||||
        if (server.listenerCount('error') < 2) {
 | 
			
		||||
          console.warn("Did not successfully create http server and bind to port '" + p + "':");
 | 
			
		||||
          explainError(e);
 | 
			
		||||
          process.exit(41);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }); } };
 | 
			
		||||
  }
 | 
			
		||||
						return greenlock
 | 
			
		||||
							.check({ domains: [greenlock.servername] })
 | 
			
		||||
							.then(function(certs) {
 | 
			
		||||
								if (certs) {
 | 
			
		||||
									return {
 | 
			
		||||
										key: Buffer.from(certs.privkey, "ascii"),
 | 
			
		||||
										cert: Buffer.from(certs.cert + "\r\n" + certs.chain, "ascii")
 | 
			
		||||
									};
 | 
			
		||||
								}
 | 
			
		||||
								console.info(
 | 
			
		||||
									"Fetching certificate for '%s' to use as default for HTTPS server...",
 | 
			
		||||
									greenlock.servername
 | 
			
		||||
								);
 | 
			
		||||
								return new PromiseA(function(resolve, reject) {
 | 
			
		||||
									// using SNICallback because all options will be set
 | 
			
		||||
									greenlock.tlsOptions.SNICallback(greenlock.servername, function(err /*, secureContext*/) {
 | 
			
		||||
										if (err) {
 | 
			
		||||
											reject(err);
 | 
			
		||||
											return;
 | 
			
		||||
										}
 | 
			
		||||
										return greenlock
 | 
			
		||||
											.check({ domains: [greenlock.servername] })
 | 
			
		||||
											.then(function(certs) {
 | 
			
		||||
												resolve({
 | 
			
		||||
													key: Buffer.from(certs.privkey, "ascii"),
 | 
			
		||||
													cert: Buffer.from(certs.cert + "\r\n" + certs.chain, "ascii")
 | 
			
		||||
												});
 | 
			
		||||
											})
 | 
			
		||||
											.catch(reject);
 | 
			
		||||
									});
 | 
			
		||||
								});
 | 
			
		||||
							})
 | 
			
		||||
							.then(resolve)
 | 
			
		||||
							.catch(reject);
 | 
			
		||||
					});
 | 
			
		||||
					server.listen.apply(server, args).on("error", function(e) {
 | 
			
		||||
						if (server.listenerCount("error") < 2) {
 | 
			
		||||
							console.warn("Did not successfully create http server and bind to port '" + p + "':");
 | 
			
		||||
							explainError(e);
 | 
			
		||||
							process.exit(41);
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  function _create(port) {
 | 
			
		||||
    if (!port) { port = 443; }
 | 
			
		||||
	function _create(port) {
 | 
			
		||||
		if (!port) {
 | 
			
		||||
			port = 443;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    var parts = String(port).split(':');
 | 
			
		||||
    var p = parts.pop();
 | 
			
		||||
    var addr = parts.join(':').replace(/^\[/, '').replace(/\]$/, '');
 | 
			
		||||
    var args = [];
 | 
			
		||||
    var httpType;
 | 
			
		||||
    var server;
 | 
			
		||||
    var validHttpPort = (parseInt(p, 10) >= 0);
 | 
			
		||||
		var parts = String(port).split(":");
 | 
			
		||||
		var p = parts.pop();
 | 
			
		||||
		var addr = parts
 | 
			
		||||
			.join(":")
 | 
			
		||||
			.replace(/^\[/, "")
 | 
			
		||||
			.replace(/\]$/, "");
 | 
			
		||||
		var args = [];
 | 
			
		||||
		var httpType;
 | 
			
		||||
		var server;
 | 
			
		||||
		var validHttpPort = parseInt(p, 10) >= 0;
 | 
			
		||||
 | 
			
		||||
    if (addr) { args[1] = addr; }
 | 
			
		||||
    if (!validHttpPort && !/(\/)|(\\\\)/.test(p)) {
 | 
			
		||||
      console.warn("'" + p + "' doesn't seem to be a valid port number, socket path, or pipe");
 | 
			
		||||
    }
 | 
			
		||||
		if (addr) {
 | 
			
		||||
			args[1] = addr;
 | 
			
		||||
		}
 | 
			
		||||
		if (!validHttpPort && !/(\/)|(\\\\)/.test(p)) {
 | 
			
		||||
			console.warn("'" + p + "' doesn't seem to be a valid port number, socket path, or pipe");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    var https;
 | 
			
		||||
    try {
 | 
			
		||||
      https = require('spdy');
 | 
			
		||||
      greenlock.tlsOptions.spdy = { protocols: [ 'h2', 'http/1.1' ], plain: false };
 | 
			
		||||
      httpType = 'http2 (spdy/h2)';
 | 
			
		||||
    } catch(e) {
 | 
			
		||||
      https = require('https');
 | 
			
		||||
      httpType = 'https';
 | 
			
		||||
    }
 | 
			
		||||
    var sniCallback = greenlock.tlsOptions.SNICallback;
 | 
			
		||||
    greenlock.tlsOptions.SNICallback = function (domain, cb) {
 | 
			
		||||
      sniCallback(domain, function (err, context) {
 | 
			
		||||
        cb(err, context);
 | 
			
		||||
		var https;
 | 
			
		||||
		try {
 | 
			
		||||
			https = require("spdy");
 | 
			
		||||
			greenlock.tlsOptions.spdy = { protocols: ["h2", "http/1.1"], plain: false };
 | 
			
		||||
			httpType = "http2 (spdy/h2)";
 | 
			
		||||
		} catch (e) {
 | 
			
		||||
			https = require("https");
 | 
			
		||||
			httpType = "https";
 | 
			
		||||
		}
 | 
			
		||||
		var sniCallback = greenlock.tlsOptions.SNICallback;
 | 
			
		||||
		greenlock.tlsOptions.SNICallback = function(domain, cb) {
 | 
			
		||||
			sniCallback(domain, function(err, context) {
 | 
			
		||||
				cb(err, context);
 | 
			
		||||
 | 
			
		||||
        if (!context || server._hasDefaultSecureContext) { return; }
 | 
			
		||||
        if (!domain) { domain = greenlock.servername; }
 | 
			
		||||
        if (!domain) { return; }
 | 
			
		||||
				if (!context || server._hasDefaultSecureContext) {
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				if (!domain) {
 | 
			
		||||
					domain = greenlock.servername;
 | 
			
		||||
				}
 | 
			
		||||
				if (!domain) {
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
        return greenlock.check({ domains: [ domain ] }).then(function (certs) {
 | 
			
		||||
          // ignore the case that check doesn't have all the right args here
 | 
			
		||||
          // to get the same certs that it just got (eventually the right ones will come in)
 | 
			
		||||
          if (!certs) { return; }
 | 
			
		||||
          if (server.setSecureContext) {
 | 
			
		||||
            // only available in node v11.0+
 | 
			
		||||
            server.setSecureContext({
 | 
			
		||||
              key: Buffer.from(certs.privkey, 'ascii')
 | 
			
		||||
            , cert: Buffer.from(certs.cert + '\r\n' + certs.chain, 'ascii')
 | 
			
		||||
            });
 | 
			
		||||
            console.info("Using '%s' as default certificate", domain);
 | 
			
		||||
          } else {
 | 
			
		||||
            console.info("Setting default certificates dynamically requires node v11.0+. Skipping.");
 | 
			
		||||
          }
 | 
			
		||||
          server._hasDefaultSecureContext = true;
 | 
			
		||||
        }).catch(function (/*e*/) {
 | 
			
		||||
          // this may be that the test.example.com was requested, but it's listed
 | 
			
		||||
          // on the cert for demo.example.com which is in its own directory, not the other
 | 
			
		||||
          //console.warn("Unusual error: couldn't get newly authorized certificate:");
 | 
			
		||||
          //console.warn(e.message);
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    };
 | 
			
		||||
    if (greenlock.tlsOptions.cert) {
 | 
			
		||||
      server._hasDefaultSecureContext = true;
 | 
			
		||||
      if (greenlock.tlsOptions.cert.toString('ascii').split("BEGIN").length < 3) {
 | 
			
		||||
        console.warn("Invalid certificate file. 'tlsOptions.cert' should contain cert.pem (certificate file) *and* chain.pem (intermediate certificates) seperated by an extra newline (CRLF)");
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    server = https.createServer(
 | 
			
		||||
      greenlock.tlsOptions
 | 
			
		||||
    , greenlock.middleware.sanitizeHost(function (req, res) {
 | 
			
		||||
        try {
 | 
			
		||||
          greenlock.app(req, res);
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
          console.error("[error] [greenlock.app] Your HTTP handler had an uncaught error:");
 | 
			
		||||
          console.error(e);
 | 
			
		||||
          try {
 | 
			
		||||
            res.statusCode = 500;
 | 
			
		||||
            res.end("Internal Server Error: [Greenlock] HTTP exception logged for user-provided handler.");
 | 
			
		||||
          } catch(e) {
 | 
			
		||||
            // ignore
 | 
			
		||||
            // (headers may have already been sent, etc)
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    );
 | 
			
		||||
    server.type = httpType;
 | 
			
		||||
				return greenlock
 | 
			
		||||
					.check({ domains: [domain] })
 | 
			
		||||
					.then(function(certs) {
 | 
			
		||||
						// ignore the case that check doesn't have all the right args here
 | 
			
		||||
						// to get the same certs that it just got (eventually the right ones will come in)
 | 
			
		||||
						if (!certs) {
 | 
			
		||||
							return;
 | 
			
		||||
						}
 | 
			
		||||
						if (server.setSecureContext) {
 | 
			
		||||
							// only available in node v11.0+
 | 
			
		||||
							server.setSecureContext({
 | 
			
		||||
								key: Buffer.from(certs.privkey, "ascii"),
 | 
			
		||||
								cert: Buffer.from(certs.cert + "\r\n" + certs.chain, "ascii")
 | 
			
		||||
							});
 | 
			
		||||
							console.info("Using '%s' as default certificate", domain);
 | 
			
		||||
						} else {
 | 
			
		||||
							console.info("Setting default certificates dynamically requires node v11.0+. Skipping.");
 | 
			
		||||
						}
 | 
			
		||||
						server._hasDefaultSecureContext = true;
 | 
			
		||||
					})
 | 
			
		||||
					.catch(function(/*e*/) {
 | 
			
		||||
						// this may be that the test.example.com was requested, but it's listed
 | 
			
		||||
						// on the cert for demo.example.com which is in its own directory, not the other
 | 
			
		||||
						//console.warn("Unusual error: couldn't get newly authorized certificate:");
 | 
			
		||||
						//console.warn(e.message);
 | 
			
		||||
					});
 | 
			
		||||
			});
 | 
			
		||||
		};
 | 
			
		||||
		if (greenlock.tlsOptions.cert) {
 | 
			
		||||
			server._hasDefaultSecureContext = true;
 | 
			
		||||
			if (greenlock.tlsOptions.cert.toString("ascii").split("BEGIN").length < 3) {
 | 
			
		||||
				console.warn(
 | 
			
		||||
					"Invalid certificate file. 'tlsOptions.cert' should contain cert.pem (certificate file) *and* chain.pem (intermediate certificates) seperated by an extra newline (CRLF)"
 | 
			
		||||
				);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		server = https.createServer(
 | 
			
		||||
			greenlock.tlsOptions,
 | 
			
		||||
			greenlock.middleware.sanitizeHost(function(req, res) {
 | 
			
		||||
				try {
 | 
			
		||||
					greenlock.app(req, res);
 | 
			
		||||
				} catch (e) {
 | 
			
		||||
					console.error("[error] [greenlock.app] Your HTTP handler had an uncaught error:");
 | 
			
		||||
					console.error(e);
 | 
			
		||||
					try {
 | 
			
		||||
						res.statusCode = 500;
 | 
			
		||||
						res.end("Internal Server Error: [Greenlock] HTTP exception logged for user-provided handler.");
 | 
			
		||||
					} catch (e) {
 | 
			
		||||
						// ignore
 | 
			
		||||
						// (headers may have already been sent, etc)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
		);
 | 
			
		||||
		server.type = httpType;
 | 
			
		||||
 | 
			
		||||
    return { server: server, listen: function () { return new PromiseA(function (resolve) {
 | 
			
		||||
      args[0] = p;
 | 
			
		||||
      args.push(function () { resolve(/*server*/); });
 | 
			
		||||
      server.listen.apply(server, args).on('error', function (e) {
 | 
			
		||||
        if (server.listenerCount('error') < 2) {
 | 
			
		||||
          console.warn("Did not successfully create http server and bind to port '" + p + "':");
 | 
			
		||||
          explainError(e);
 | 
			
		||||
          process.exit(41);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }); } };
 | 
			
		||||
  }
 | 
			
		||||
		return {
 | 
			
		||||
			server: server,
 | 
			
		||||
			listen: function() {
 | 
			
		||||
				return new PromiseA(function(resolve) {
 | 
			
		||||
					args[0] = p;
 | 
			
		||||
					args.push(function() {
 | 
			
		||||
						resolve(/*server*/);
 | 
			
		||||
					});
 | 
			
		||||
					server.listen.apply(server, args).on("error", function(e) {
 | 
			
		||||
						if (server.listenerCount("error") < 2) {
 | 
			
		||||
							console.warn("Did not successfully create http server and bind to port '" + p + "':");
 | 
			
		||||
							explainError(e);
 | 
			
		||||
							process.exit(41);
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  // NOTE: 'greenlock' is just 'opts' renamed
 | 
			
		||||
  var greenlock = require('greenlock').create(opts);
 | 
			
		||||
	// NOTE: 'greenlock' is just 'opts' renamed
 | 
			
		||||
	var greenlock = require("greenlock").create(opts);
 | 
			
		||||
 | 
			
		||||
  if (!opts.app) {
 | 
			
		||||
    opts.app = function (req, res) {
 | 
			
		||||
      res.end("Hello, World!\nWith Love,\nGreenlock for Express.js");
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
	if (!opts.app) {
 | 
			
		||||
		opts.app = function(req, res) {
 | 
			
		||||
			res.end("Hello, World!\nWith Love,\nGreenlock for Express.js");
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  opts.listen = function (plainPort, port, fnPlain, fn) {
 | 
			
		||||
    var server;
 | 
			
		||||
    var plainServer;
 | 
			
		||||
	opts.listen = function(plainPort, port, fnPlain, fn) {
 | 
			
		||||
		var server;
 | 
			
		||||
		var plainServer;
 | 
			
		||||
 | 
			
		||||
    // If there is only one handler for the `listening` (i.e. TCP bound) event
 | 
			
		||||
    // then we want to use it as HTTPS (backwards compat)
 | 
			
		||||
    if (!fn) {
 | 
			
		||||
      fn = fnPlain;
 | 
			
		||||
      fnPlain = null;
 | 
			
		||||
    }
 | 
			
		||||
		// If there is only one handler for the `listening` (i.e. TCP bound) event
 | 
			
		||||
		// then we want to use it as HTTPS (backwards compat)
 | 
			
		||||
		if (!fn) {
 | 
			
		||||
			fn = fnPlain;
 | 
			
		||||
			fnPlain = null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    var obj1 = _createPlain(plainPort, true);
 | 
			
		||||
    var obj2 = _create(port, false);
 | 
			
		||||
		var obj1 = _createPlain(plainPort, true);
 | 
			
		||||
		var obj2 = _create(port, false);
 | 
			
		||||
 | 
			
		||||
    plainServer = obj1.server;
 | 
			
		||||
    server = obj2.server;
 | 
			
		||||
		plainServer = obj1.server;
 | 
			
		||||
		server = obj2.server;
 | 
			
		||||
 | 
			
		||||
    server.then = obj1.listen().then(function (tlsOptions) {
 | 
			
		||||
      if (tlsOptions) {
 | 
			
		||||
        if (server.setSecureContext) {
 | 
			
		||||
          // only available in node v11.0+
 | 
			
		||||
          server.setSecureContext(tlsOptions);
 | 
			
		||||
          console.info("Using '%s' as default certificate", greenlock.servername);
 | 
			
		||||
        } else {
 | 
			
		||||
          console.info("Setting default certificates dynamically requires node v11.0+. Skipping.");
 | 
			
		||||
        }
 | 
			
		||||
        server._hasDefaultSecureContext = true;
 | 
			
		||||
      }
 | 
			
		||||
      return obj2.listen().then(function () {
 | 
			
		||||
        // Report plain http status
 | 
			
		||||
        if ('function' === typeof fnPlain) {
 | 
			
		||||
          fnPlain.apply(plainServer);
 | 
			
		||||
        } else if (!fn && !plainServer.listenerCount('listening') && !server.listenerCount('listening')) {
 | 
			
		||||
          console.info('[:' + (plainServer.address().port || plainServer.address())
 | 
			
		||||
            + "] Handling ACME challenges and redirecting to " + server.type);
 | 
			
		||||
        }
 | 
			
		||||
		server.then = obj1.listen().then(function(tlsOptions) {
 | 
			
		||||
			if (tlsOptions) {
 | 
			
		||||
				if (server.setSecureContext) {
 | 
			
		||||
					// only available in node v11.0+
 | 
			
		||||
					server.setSecureContext(tlsOptions);
 | 
			
		||||
					console.info("Using '%s' as default certificate", greenlock.servername);
 | 
			
		||||
				} else {
 | 
			
		||||
					console.info("Setting default certificates dynamically requires node v11.0+. Skipping.");
 | 
			
		||||
				}
 | 
			
		||||
				server._hasDefaultSecureContext = true;
 | 
			
		||||
			}
 | 
			
		||||
			return obj2.listen().then(function() {
 | 
			
		||||
				// Report plain http status
 | 
			
		||||
				if ("function" === typeof fnPlain) {
 | 
			
		||||
					fnPlain.apply(plainServer);
 | 
			
		||||
				} else if (!fn && !plainServer.listenerCount("listening") && !server.listenerCount("listening")) {
 | 
			
		||||
					console.info(
 | 
			
		||||
						"[:" +
 | 
			
		||||
							(plainServer.address().port || plainServer.address()) +
 | 
			
		||||
							"] Handling ACME challenges and redirecting to " +
 | 
			
		||||
							server.type
 | 
			
		||||
					);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
        // Report h2/https status
 | 
			
		||||
        if ('function' === typeof fn) {
 | 
			
		||||
          fn.apply(server);
 | 
			
		||||
        } else if (!server.listenerCount('listening')) {
 | 
			
		||||
          console.info('[:' + (server.address().port || server.address()) + "] Serving " + server.type);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }).then;
 | 
			
		||||
				// Report h2/https status
 | 
			
		||||
				if ("function" === typeof fn) {
 | 
			
		||||
					fn.apply(server);
 | 
			
		||||
				} else if (!server.listenerCount("listening")) {
 | 
			
		||||
					console.info("[:" + (server.address().port || server.address()) + "] Serving " + server.type);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		}).then;
 | 
			
		||||
 | 
			
		||||
    server.unencrypted = plainServer;
 | 
			
		||||
    return server;
 | 
			
		||||
  };
 | 
			
		||||
  opts.middleware.acme = function (opts) {
 | 
			
		||||
    return greenlock.middleware.sanitizeHost(greenlock.middleware(require('redirect-https')(opts)));
 | 
			
		||||
  };
 | 
			
		||||
  opts.middleware.secure = function (app) {
 | 
			
		||||
    return greenlock.middleware.sanitizeHost(app);
 | 
			
		||||
  };
 | 
			
		||||
		server.unencrypted = plainServer;
 | 
			
		||||
		return server;
 | 
			
		||||
	};
 | 
			
		||||
	opts.middleware.acme = function(opts) {
 | 
			
		||||
		return greenlock.middleware.sanitizeHost(greenlock.middleware(require("redirect-https")(opts)));
 | 
			
		||||
	};
 | 
			
		||||
	opts.middleware.secure = function(app) {
 | 
			
		||||
		return greenlock.middleware.sanitizeHost(app);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
  return greenlock;
 | 
			
		||||
	return greenlock;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,37 +1,37 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"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();
 | 
			
		||||
if ("undefined" === typeof Promise) {
 | 
			
		||||
	global.Promise = requireBluebird();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if ('function' !== typeof require('util').promisify) {
 | 
			
		||||
  require('util').promisify = requireBluebird().promisify;
 | 
			
		||||
if ("function" !== typeof require("util").promisify) {
 | 
			
		||||
	require("util").promisify = requireBluebird().promisify;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if (!console.debug) {
 | 
			
		||||
  console.debug = console.log;
 | 
			
		||||
	console.debug = console.log;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var fs = require('fs');
 | 
			
		||||
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);
 | 
			
		||||
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);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
exports.fsAsync = fsAsync;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1182
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1182
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										96
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								package.json
									
									
									
									
									
								
							@ -1,50 +1,50 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "greenlock-express",
 | 
			
		||||
  "version": "2.7.9",
 | 
			
		||||
  "description": "Free SSL and managed or automatic HTTPS for node.js with Express, Koa, Connect, Hapi, and all other middleware systems.",
 | 
			
		||||
  "main": "index.js",
 | 
			
		||||
  "homepage": "https://greenlock.domains",
 | 
			
		||||
  "directories": {
 | 
			
		||||
    "example": "examples"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "greenlock": "^2.7.24",
 | 
			
		||||
    "redirect-https": "^1.1.5"
 | 
			
		||||
  },
 | 
			
		||||
  "files": [
 | 
			
		||||
    "lib"
 | 
			
		||||
  ],
 | 
			
		||||
  "trulyOptionalDependencies": {
 | 
			
		||||
    "spdy": "^3.4.7"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "express": "^4.16.3",
 | 
			
		||||
    "express-basic-auth": "^1.1.5",
 | 
			
		||||
    "finalhandler": "^1.1.1",
 | 
			
		||||
    "serve-index": "^1.9.1",
 | 
			
		||||
    "serve-static": "^1.13.2",
 | 
			
		||||
    "ws": "^5.2.1"
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "start": "node server.js ./config.js",
 | 
			
		||||
    "test": "node test/greenlock.js"
 | 
			
		||||
  },
 | 
			
		||||
  "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 <solderjs@gmail.com> (https://solderjs.com/)",
 | 
			
		||||
  "license": "MPL-2.0",
 | 
			
		||||
  "bugs": {
 | 
			
		||||
    "url": "https://git.rootprojects.org/root/greenlock-express.js/issues"
 | 
			
		||||
  }
 | 
			
		||||
	"name": "greenlock-express",
 | 
			
		||||
	"version": "2.7.9",
 | 
			
		||||
	"description": "Free SSL and managed or automatic HTTPS for node.js with Express, Koa, Connect, Hapi, and all other middleware systems.",
 | 
			
		||||
	"main": "index.js",
 | 
			
		||||
	"homepage": "https://greenlock.domains",
 | 
			
		||||
	"directories": {
 | 
			
		||||
		"example": "examples"
 | 
			
		||||
	},
 | 
			
		||||
	"dependencies": {
 | 
			
		||||
		"greenlock": "^2.7.24",
 | 
			
		||||
		"redirect-https": "^1.1.5"
 | 
			
		||||
	},
 | 
			
		||||
	"files": [
 | 
			
		||||
		"lib"
 | 
			
		||||
	],
 | 
			
		||||
	"trulyOptionalDependencies": {
 | 
			
		||||
		"spdy": "^3.4.7"
 | 
			
		||||
	},
 | 
			
		||||
	"devDependencies": {
 | 
			
		||||
		"express": "^4.16.3",
 | 
			
		||||
		"express-basic-auth": "^1.1.5",
 | 
			
		||||
		"finalhandler": "^1.1.1",
 | 
			
		||||
		"serve-index": "^1.9.1",
 | 
			
		||||
		"serve-static": "^1.13.2",
 | 
			
		||||
		"ws": "^5.2.1"
 | 
			
		||||
	},
 | 
			
		||||
	"scripts": {
 | 
			
		||||
		"start": "node server.js ./config.js",
 | 
			
		||||
		"test": "node test/greenlock.js"
 | 
			
		||||
	},
 | 
			
		||||
	"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 <solderjs@gmail.com> (https://solderjs.com/)",
 | 
			
		||||
	"license": "MPL-2.0",
 | 
			
		||||
	"bugs": {
 | 
			
		||||
		"url": "https://git.rootprojects.org/root/greenlock-express.js/issues"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										336
									
								
								server.js
									
									
									
									
									
								
							
							
						
						
									
										336
									
								
								server.js
									
									
									
									
									
								
							@ -1,5 +1,5 @@
 | 
			
		||||
#!/usr/bin/env node
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
/*global Promise*/
 | 
			
		||||
 | 
			
		||||
/////////////////////////////////
 | 
			
		||||
@ -15,189 +15,219 @@
 | 
			
		||||
// ex: /srv/api/api.example.com
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
var configpath = process.argv[2] || './config.js';
 | 
			
		||||
var configpath = process.argv[2] || "./config.js";
 | 
			
		||||
var config = require(configpath);
 | 
			
		||||
// 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 path = require('path');
 | 
			
		||||
var fs = require('./lib/compat.js').fsAsync;
 | 
			
		||||
var finalhandler = require('finalhandler');
 | 
			
		||||
var serveStatic = require('serve-static');
 | 
			
		||||
var path = require("path");
 | 
			
		||||
var fs = require("./lib/compat.js").fsAsync;
 | 
			
		||||
var finalhandler = require("finalhandler");
 | 
			
		||||
var serveStatic = require("serve-static");
 | 
			
		||||
 | 
			
		||||
//var glx = require('greenlock-express')
 | 
			
		||||
var glx = require('./').create({
 | 
			
		||||
var glx = require("./").create({
 | 
			
		||||
	version: "draft-11", // Let's Encrypt v2 is ACME draft 11
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
 | 
			
		||||
//, 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: config.configDir, // You MUST have access to write to directory where certs
 | 
			
		||||
	// are saved. ex: /home/foouser/.config/acme
 | 
			
		||||
 | 
			
		||||
, configDir: config.configDir                               // 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
 | 
			
		||||
 | 
			
		||||
, 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)
 | 
			
		||||
 | 
			
		||||
, app: myVhostApp                                           // Any node-style http app (i.e. express, koa, hapi, rill)
 | 
			
		||||
 | 
			
		||||
  /* CHANGE TO A VALID EMAIL */
 | 
			
		||||
, email: config.email                                       // 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
 | 
			
		||||
, store: require('greenlock-store-fs')
 | 
			
		||||
	/* CHANGE TO A VALID EMAIL */
 | 
			
		||||
	email: config.email, // 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
 | 
			
		||||
	store: require("greenlock-store-fs")
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var server = glx.listen(80, 443);
 | 
			
		||||
server.on('listening', function () {
 | 
			
		||||
  console.info(server.type + " listening on", server.address());
 | 
			
		||||
server.on("listening", function() {
 | 
			
		||||
	console.info(server.type + " listening on", server.address());
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function myApproveDomains(opts) {
 | 
			
		||||
  console.info("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
 | 
			
		||||
	console.info("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
 | 
			
		||||
 | 
			
		||||
  var domains = [];
 | 
			
		||||
  var domain = opts.domain.replace(/^(www|api)\./, '');
 | 
			
		||||
  return checkWwws(domain).then(function (hostname) {
 | 
			
		||||
    // this is either example.com or www.example.com
 | 
			
		||||
    domains.push(hostname);
 | 
			
		||||
    if ('api.' + domain !== opts.domain) {
 | 
			
		||||
      if (!domains.includes(opts.domain)) {
 | 
			
		||||
        domains.push(opts.domain)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }).catch(function () {
 | 
			
		||||
    // ignore error
 | 
			
		||||
    return null;
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    // check for api prefix
 | 
			
		||||
    var apiname = domain;
 | 
			
		||||
    if (domains.length) {
 | 
			
		||||
      apiname = 'api.' + domain;
 | 
			
		||||
    }
 | 
			
		||||
    return checkApi(apiname).then(function (app) {
 | 
			
		||||
      if (!app) { return null; }
 | 
			
		||||
      domains.push(apiname);
 | 
			
		||||
    }).catch(function () {
 | 
			
		||||
      return null;
 | 
			
		||||
    });
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    if (0 === domains.length) {
 | 
			
		||||
      return Promise.reject(new Error("no bare, www., or api. domain matching '" + opts.domain + "'"));
 | 
			
		||||
    }
 | 
			
		||||
	var domains = [];
 | 
			
		||||
	var domain = opts.domain.replace(/^(www|api)\./, "");
 | 
			
		||||
	return checkWwws(domain)
 | 
			
		||||
		.then(function(hostname) {
 | 
			
		||||
			// this is either example.com or www.example.com
 | 
			
		||||
			domains.push(hostname);
 | 
			
		||||
			if ("api." + domain !== opts.domain) {
 | 
			
		||||
				if (!domains.includes(opts.domain)) {
 | 
			
		||||
					domains.push(opts.domain);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
		.catch(function() {
 | 
			
		||||
			// ignore error
 | 
			
		||||
			return null;
 | 
			
		||||
		})
 | 
			
		||||
		.then(function() {
 | 
			
		||||
			// check for api prefix
 | 
			
		||||
			var apiname = domain;
 | 
			
		||||
			if (domains.length) {
 | 
			
		||||
				apiname = "api." + domain;
 | 
			
		||||
			}
 | 
			
		||||
			return checkApi(apiname)
 | 
			
		||||
				.then(function(app) {
 | 
			
		||||
					if (!app) {
 | 
			
		||||
						return null;
 | 
			
		||||
					}
 | 
			
		||||
					domains.push(apiname);
 | 
			
		||||
				})
 | 
			
		||||
				.catch(function() {
 | 
			
		||||
					return null;
 | 
			
		||||
				});
 | 
			
		||||
		})
 | 
			
		||||
		.then(function() {
 | 
			
		||||
			if (0 === domains.length) {
 | 
			
		||||
				return Promise.reject(new Error("no bare, www., or api. domain matching '" + opts.domain + "'"));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
    console.info('Approved domains:', domains);
 | 
			
		||||
    opts.domains = domains;
 | 
			
		||||
    //opts.email = email;
 | 
			
		||||
    opts.agreeTos = true;
 | 
			
		||||
    // pick the shortest (bare) or latest (www. instead of api.) to be the subject
 | 
			
		||||
    opts.subject = opts.domains.sort(function (a, b) {
 | 
			
		||||
      var len = a.length - b.length;
 | 
			
		||||
      if (0 !== len) { return len; }
 | 
			
		||||
      if (a < b) { return 1; } else { return -1; }
 | 
			
		||||
    })[0];
 | 
			
		||||
			console.info("Approved domains:", domains);
 | 
			
		||||
			opts.domains = domains;
 | 
			
		||||
			//opts.email = email;
 | 
			
		||||
			opts.agreeTos = true;
 | 
			
		||||
			// pick the shortest (bare) or latest (www. instead of api.) to be the subject
 | 
			
		||||
			opts.subject = opts.domains.sort(function(a, b) {
 | 
			
		||||
				var len = a.length - b.length;
 | 
			
		||||
				if (0 !== len) {
 | 
			
		||||
					return len;
 | 
			
		||||
				}
 | 
			
		||||
				if (a < b) {
 | 
			
		||||
					return 1;
 | 
			
		||||
				} else {
 | 
			
		||||
					return -1;
 | 
			
		||||
				}
 | 
			
		||||
			})[0];
 | 
			
		||||
 | 
			
		||||
    if (!opts.challenges) { opts.challenges = {}; }
 | 
			
		||||
    opts.challenges['http-01'] = require('le-challenge-fs');
 | 
			
		||||
    //opts.challenges['dns-01'] = require('le-challenge-dns');
 | 
			
		||||
			if (!opts.challenges) {
 | 
			
		||||
				opts.challenges = {};
 | 
			
		||||
			}
 | 
			
		||||
			opts.challenges["http-01"] = require("le-challenge-fs");
 | 
			
		||||
			//opts.challenges['dns-01'] = require('le-challenge-dns');
 | 
			
		||||
 | 
			
		||||
    // explicitly set account id and certificate.id
 | 
			
		||||
    opts.account = { id: opts.email };
 | 
			
		||||
    opts.certificate = { id: opts.subject };
 | 
			
		||||
			// explicitly set account id and certificate.id
 | 
			
		||||
			opts.account = { id: opts.email };
 | 
			
		||||
			opts.certificate = { id: opts.subject };
 | 
			
		||||
 | 
			
		||||
    return Promise.resolve(opts);
 | 
			
		||||
  });
 | 
			
		||||
			return Promise.resolve(opts);
 | 
			
		||||
		});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function checkApi(hostname) {
 | 
			
		||||
  var apipath = path.join(config.api, hostname);
 | 
			
		||||
  var link = '';
 | 
			
		||||
  return fs.stat(apipath).then(function (stats) {
 | 
			
		||||
    if (stats.isDirectory()) {
 | 
			
		||||
      return require(apipath);
 | 
			
		||||
    }
 | 
			
		||||
    return fs.readFile(apipath, 'utf8').then(function (txt) {
 | 
			
		||||
      var linkpath = txt.split('\n')[0];
 | 
			
		||||
      link = (' => ' + linkpath + ' ');
 | 
			
		||||
      return require(linkpath);
 | 
			
		||||
    });
 | 
			
		||||
  }).catch(function (e) {
 | 
			
		||||
    if ('ENOENT' === e.code) { return null; }
 | 
			
		||||
    console.error(e);
 | 
			
		||||
    throw new Error("rejecting '" + hostname + "' because '" + apipath + link + "' failed at require()");
 | 
			
		||||
  });
 | 
			
		||||
	var apipath = path.join(config.api, hostname);
 | 
			
		||||
	var link = "";
 | 
			
		||||
	return fs
 | 
			
		||||
		.stat(apipath)
 | 
			
		||||
		.then(function(stats) {
 | 
			
		||||
			if (stats.isDirectory()) {
 | 
			
		||||
				return require(apipath);
 | 
			
		||||
			}
 | 
			
		||||
			return fs.readFile(apipath, "utf8").then(function(txt) {
 | 
			
		||||
				var linkpath = txt.split("\n")[0];
 | 
			
		||||
				link = " => " + linkpath + " ";
 | 
			
		||||
				return require(linkpath);
 | 
			
		||||
			});
 | 
			
		||||
		})
 | 
			
		||||
		.catch(function(e) {
 | 
			
		||||
			if ("ENOENT" === e.code) {
 | 
			
		||||
				return null;
 | 
			
		||||
			}
 | 
			
		||||
			console.error(e);
 | 
			
		||||
			throw new Error("rejecting '" + hostname + "' because '" + apipath + link + "' failed at require()");
 | 
			
		||||
		});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function checkWwws(_hostname) {
 | 
			
		||||
  if (!_hostname) {
 | 
			
		||||
    // SECURITY don't serve the whole config.srv
 | 
			
		||||
    return Promise.reject(new Error("missing hostname"));
 | 
			
		||||
  }
 | 
			
		||||
  var hostname = _hostname;
 | 
			
		||||
  var hostdir = path.join(config.srv, hostname);
 | 
			
		||||
  // 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(config.srv, hostname);
 | 
			
		||||
      return fs.readdir(hostdir).then(function () {
 | 
			
		||||
        return hostname;
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      // Or check and see if perhaps we should redirect non-www to www
 | 
			
		||||
      hostname = 'www.' + hostname;
 | 
			
		||||
      hostdir = path.join(config.srv, hostname);
 | 
			
		||||
      return fs.readdir(hostdir).then(function () {
 | 
			
		||||
        return hostname;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }).catch(function () {
 | 
			
		||||
    throw new Error("rejecting '" + _hostname + "' because '" + hostdir + "' could not be read");
 | 
			
		||||
  });
 | 
			
		||||
	if (!_hostname) {
 | 
			
		||||
		// SECURITY don't serve the whole config.srv
 | 
			
		||||
		return Promise.reject(new Error("missing hostname"));
 | 
			
		||||
	}
 | 
			
		||||
	var hostname = _hostname;
 | 
			
		||||
	var hostdir = path.join(config.srv, hostname);
 | 
			
		||||
	// 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(config.srv, hostname);
 | 
			
		||||
				return fs.readdir(hostdir).then(function() {
 | 
			
		||||
					return hostname;
 | 
			
		||||
				});
 | 
			
		||||
			} else {
 | 
			
		||||
				// Or check and see if perhaps we should redirect non-www to www
 | 
			
		||||
				hostname = "www." + hostname;
 | 
			
		||||
				hostdir = path.join(config.srv, hostname);
 | 
			
		||||
				return fs.readdir(hostdir).then(function() {
 | 
			
		||||
					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.info(req.method, (req.headers.host||'') + req.url);
 | 
			
		||||
  Object.keys(req.headers).forEach(function (key) {
 | 
			
		||||
    console.info(key, req.headers[key])
 | 
			
		||||
  });
 | 
			
		||||
	// 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.info(req.method, (req.headers.host || "") + req.url);
 | 
			
		||||
	Object.keys(req.headers).forEach(function(key) {
 | 
			
		||||
		console.info(key, req.headers[key]);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
  // 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(config.srv, hostname), { redirect: true });
 | 
			
		||||
    serve(req, res, fin);
 | 
			
		||||
  }).catch(function (err) {
 | 
			
		||||
    return checkApi(req.headers.host).then(function (app) {
 | 
			
		||||
      if (app) { app(req, res); return; }
 | 
			
		||||
      console.error("none found", err);
 | 
			
		||||
      fin();
 | 
			
		||||
    }).catch(function (err) {
 | 
			
		||||
      console.error("api crashed error", err);
 | 
			
		||||
      fin(err);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
	// 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(config.srv, hostname), { redirect: true });
 | 
			
		||||
			serve(req, res, fin);
 | 
			
		||||
		})
 | 
			
		||||
		.catch(function(err) {
 | 
			
		||||
			return checkApi(req.headers.host)
 | 
			
		||||
				.then(function(app) {
 | 
			
		||||
					if (app) {
 | 
			
		||||
						app(req, res);
 | 
			
		||||
						return;
 | 
			
		||||
					}
 | 
			
		||||
					console.error("none found", err);
 | 
			
		||||
					fin();
 | 
			
		||||
				})
 | 
			
		||||
				.catch(function(err) {
 | 
			
		||||
					console.error("api crashed error", err);
 | 
			
		||||
					fin(err);
 | 
			
		||||
				});
 | 
			
		||||
		});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,75 +1,85 @@
 | 
			
		||||
#!/usr/bin/env node
 | 
			
		||||
var Greenlock = require('../');
 | 
			
		||||
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);
 | 
			
		||||
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);
 | 
			
		||||
});
 | 
			
		||||
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());
 | 
			
		||||
  });
 | 
			
		||||
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());
 | 
			
		||||
	});
 | 
			
		||||
}, 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");
 | 
			
		||||
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");
 | 
			
		||||
	}
 | 
			
		||||
);
 | 
			
		||||
server3.unencrypted.on("error", function() {
 | 
			
		||||
	console.log("Success: caught expected (plain) error");
 | 
			
		||||
});
 | 
			
		||||
server3.unencrypted.on('error', function () {
 | 
			
		||||
  console.log("Success: caught expected (plain) error");
 | 
			
		||||
});
 | 
			
		||||
server3.on('error', function () {
 | 
			
		||||
  console.log("Success: caught expected " + server3.type + " error");
 | 
			
		||||
  //server3.close();
 | 
			
		||||
server3.on("error", function() {
 | 
			
		||||
	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();
 | 
			
		||||
var server4 = greenlock.listen(
 | 
			
		||||
	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();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var server5 = greenlock.listen(10080, 10443, function () {
 | 
			
		||||
  console.log("Server 5 with one fn", this.address());
 | 
			
		||||
  server5.close();
 | 
			
		||||
  server5.unencrypted.close();
 | 
			
		||||
});
 | 
			
		||||
var server6 = greenlock.listen("[::]:11080", "[::1]:11443");
 | 
			
		||||
 | 
			
		||||
var server6 = greenlock.listen('[::]:11080', '[::1]:11443');
 | 
			
		||||
 | 
			
		||||
var server7 = greenlock.listen('/tmp/gl.plain.sock', '/tmp/gl.sec.sock');
 | 
			
		||||
var server7 = greenlock.listen("/tmp/gl.plain.sock", "/tmp/gl.sec.sock");
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user