diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..76c4a67
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,7 @@
+{
+ "bracketSpacing": true,
+ "printWidth": 120,
+ "tabWidth": 2,
+ "trailingComma": "none",
+ "useTabs": true
+}
diff --git a/README.md b/README.md
index 07f685a..aeec137 100644
--- a/README.md
+++ b/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
-* [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 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
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
[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
[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
[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
[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
[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
[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`
tags: letsencrypt acme free ssl automated https node express.js
diff --git a/config.js b/config.js
index 7017760..478f8cd 100644
--- a/config.js
+++ b/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/"
};
diff --git a/examples/demo.js b/examples/demo.js
index d9bee69..d204bea 100644
--- a/examples/demo.js
+++ b/examples/demo.js
@@ -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('Hello, ā ļø Insecure World!
Visit Secure Site'
- + ''
- );
+var redirectHttps = require("redirect-https")();
+var acmeChallengeHandler = greenlock.middleware(function(req, res) {
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
+ res.end(
+ "Hello, ā ļø Insecure World!
Visit Secure Site" +
+ ''
+ );
});
-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('Hello, š Secure World!
');
-}));
-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("Hello, š Secure World!
");
+ })
+);
+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);
diff --git a/examples/force-renew.js b/examples/force-renew.js
index 8c8f463..6224758 100644
--- a/examples/force-renew.js
+++ b/examples/force-renew.js
@@ -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);
diff --git a/examples/http2.js b/examples/http2.js
index 5b30c65..a890715 100644
--- a/examples/http2.js
+++ b/examples/http2.js
@@ -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);
diff --git a/examples/my-express-app.js b/examples/my-express-app.js
index 04da098..fada117 100644
--- a/examples/my-express-app.js
+++ b/examples/my-express-app.js
@@ -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;
diff --git a/examples/production.js b/examples/production.js
index 08ee7ef..2bcfda9 100644
--- a/examples/production.js
+++ b/examples/production.js
@@ -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);
+ }
}
diff --git a/examples/quickstart.js b/examples/quickstart.js
index e2c6ce0..f13ecc9 100644
--- a/examples/quickstart.js
+++ b/examples/quickstart.js
@@ -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);
diff --git a/examples/remote-access.js b/examples/remote-access.js
index 87676d6..4e66cef 100644
--- a/examples/remote-access.js
+++ b/examples/remote-access.js
@@ -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 Home';
- }
- });
+ var myAuth = basicAuth({
+ users: { root: secret, user: secret },
+ challenge: true,
+ realm: realm,
+ unauthorizedResponse: function(/*req*/) {
+ return 'Unauthorized Home';
+ }
+ });
- app.get('/', function (req, res) {
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
- res.end(
- 'View Files'
- + ' | '
- + 'Logout'
- );
- });
- 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 | Home');
- });
- 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('View Files' + " | " + 'Logout');
+ });
+ 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 | Home');
+ });
+ 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;
}
diff --git a/examples/socket.io.js b/examples/socket.io.js
index 6d4cb0e..b626025 100644
--- a/examples/socket.io.js
+++ b/examples/socket.io.js
@@ -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);
+ });
});
diff --git a/examples/spdy.js b/examples/spdy.js
index 0af2470..6cb87dd 100644
--- a/examples/spdy.js
+++ b/examples/spdy.js
@@ -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);
diff --git a/examples/vhost.js b/examples/vhost.js
index 93460d1..618bf35 100644
--- a/examples/vhost.js
+++ b/examples/vhost.js
@@ -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("");
- 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("");
+ return;
+ }
+ var serve = serveStatic(path.join(srv, hostname), { redirect: true });
+ serve(req, res, fin);
+ })
+ .catch(function() {
+ fin();
+ });
}
diff --git a/examples/websockets.js b/examples/websockets.js
index 54a69da..26cbc25 100644
--- a/examples/websockets.js
+++ b/examples/websockets.js
@@ -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);
+ });
});
diff --git a/examples/wildcard.js b/examples/wildcard.js
index a612fab..5dbadc9 100644
--- a/examples/wildcard.js
+++ b/examples/wildcard.js
@@ -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);
}
diff --git a/index.js b/index.js
index a5124ee..bc97e9e 100644
--- a/index.js
+++ b/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;
};
diff --git a/lib/compat.js b/lib/compat.js
index e80b911..3e5e7bc 100644
--- a/lib/compat.js
+++ b/lib/compat.js
@@ -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;
diff --git a/package-lock.json b/package-lock.json
index 20791e3..174250f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,593 +1,593 @@
{
- "name": "greenlock-express",
- "version": "2.7.9",
- "lockfileVersion": 1,
- "requires": true,
- "dependencies": {
- "@coolaj86/urequest": {
- "version": "1.3.7",
- "resolved": "https://registry.npmjs.org/@coolaj86/urequest/-/urequest-1.3.7.tgz",
- "integrity": "sha512-PPrVYra9aWvZjSCKl/x1pJ9ZpXda1652oJrPBYy5rQumJJMkmTBN3ux+sK2xAUwVvv2wnewDlaQaHLxLwSHnIA=="
- },
- "@root/mkdirp": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz",
- "integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA=="
- },
- "accepts": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
- "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
- "dev": true,
- "requires": {
- "mime-types": "~2.1.18",
- "negotiator": "0.6.1"
- }
- },
- "acme": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/acme/-/acme-1.3.0.tgz",
- "integrity": "sha512-Ny8aXnGdtlEVBZLpzNyVp7gff/3zFYrbfbiY93lx5jdrG4BrraA6P8RkRFP7NbFwh1rBgQkdHEsMxTp3f2r8dA==",
- "requires": {
- "acme-v2": "^1.6.0"
- }
- },
- "acme-dns-01-cli": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/acme-dns-01-cli/-/acme-dns-01-cli-3.0.7.tgz",
- "integrity": "sha512-Aa4bUpq6ftX1VODiShOetOY5U0tsXY5EV7+fQwme3Q8Y9rjYBArBXHgFCAVKtK1AF+Ev8pIuF6Z42hzMFa73/w=="
- },
- "acme-v2": {
- "version": "1.7.7",
- "resolved": "https://registry.npmjs.org/acme-v2/-/acme-v2-1.7.7.tgz",
- "integrity": "sha512-Pg0EQ45h8N2e4K2goYedutCgWxAmtcruwDHr6hgPBgAWEORVb5SQEdXjtEhCrn+APtr7MyFPryyzXpYpDD5ecA==",
- "requires": {
- "@coolaj86/urequest": "^1.3.6",
- "rsa-compat": "^2.0.6"
- }
- },
- "array-flatten": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
- "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
- "dev": true
- },
- "async-limiter": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
- "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
- "dev": true
- },
- "basic-auth": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
- "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
- "dev": true,
- "requires": {
- "safe-buffer": "5.1.2"
- }
- },
- "batch": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
- "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=",
- "dev": true
- },
- "body-parser": {
- "version": "1.18.3",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz",
- "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=",
- "dev": true,
- "requires": {
- "bytes": "3.0.0",
- "content-type": "~1.0.4",
- "debug": "2.6.9",
- "depd": "~1.1.2",
- "http-errors": "~1.6.3",
- "iconv-lite": "0.4.23",
- "on-finished": "~2.3.0",
- "qs": "6.5.2",
- "raw-body": "2.3.3",
- "type-is": "~1.6.16"
- }
- },
- "bytes": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
- "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
- "dev": true
- },
- "cert-info": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/cert-info/-/cert-info-1.5.1.tgz",
- "integrity": "sha512-eoQC/yAgW3gKTKxjzyClvi+UzuY97YCjcl+lSqbsGIy7HeGaWxCPOQFivhUYm27hgsBMhsJJFya3kGvK6PMIcQ=="
- },
- "content-disposition": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
- "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=",
- "dev": true
- },
- "content-type": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
- "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
- "dev": true
- },
- "cookie": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
- "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=",
- "dev": true
- },
- "cookie-signature": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
- "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
- "dev": true
- },
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- },
- "depd": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
- "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
- "dev": true
- },
- "destroy": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
- "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
- "dev": true
- },
- "eckles": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/eckles/-/eckles-1.4.1.tgz",
- "integrity": "sha512-auWyk/k8oSkVHaD4RxkPadKsLUcIwKgr/h8F7UZEueFDBO7BsE4y+H6IMUDbfqKIFPg/9MxV6KcBdJCmVVcxSA=="
- },
- "ee-first": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
- "dev": true
- },
- "encodeurl": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
- "dev": true
- },
- "escape-html": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
- },
- "etag": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
- "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
- "dev": true
- },
- "express": {
- "version": "4.16.4",
- "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz",
- "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==",
- "dev": true,
- "requires": {
- "accepts": "~1.3.5",
- "array-flatten": "1.1.1",
- "body-parser": "1.18.3",
- "content-disposition": "0.5.2",
- "content-type": "~1.0.4",
- "cookie": "0.3.1",
- "cookie-signature": "1.0.6",
- "debug": "2.6.9",
- "depd": "~1.1.2",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "finalhandler": "1.1.1",
- "fresh": "0.5.2",
- "merge-descriptors": "1.0.1",
- "methods": "~1.1.2",
- "on-finished": "~2.3.0",
- "parseurl": "~1.3.2",
- "path-to-regexp": "0.1.7",
- "proxy-addr": "~2.0.4",
- "qs": "6.5.2",
- "range-parser": "~1.2.0",
- "safe-buffer": "5.1.2",
- "send": "0.16.2",
- "serve-static": "1.13.2",
- "setprototypeof": "1.1.0",
- "statuses": "~1.4.0",
- "type-is": "~1.6.16",
- "utils-merge": "1.0.1",
- "vary": "~1.1.2"
- }
- },
- "express-basic-auth": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.1.6.tgz",
- "integrity": "sha512-fRh/UU2q/YhvY0/Pkzi3VcLyjIExveW2NOOnOGgO6yO0jKXt6zcKPVPWSrL8nlhlh+YEH5LOjz+CGFML5dJQNw==",
- "dev": true,
- "requires": {
- "basic-auth": "^2.0.1"
- }
- },
- "finalhandler": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
- "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
- "dev": true,
- "requires": {
- "debug": "2.6.9",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "on-finished": "~2.3.0",
- "parseurl": "~1.3.2",
- "statuses": "~1.4.0",
- "unpipe": "~1.0.0"
- }
- },
- "forwarded": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
- "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
- "dev": true
- },
- "fresh": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
- "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
- "dev": true
- },
- "greenlock": {
- "version": "2.7.24",
- "resolved": "https://registry.npmjs.org/greenlock/-/greenlock-2.7.24.tgz",
- "integrity": "sha512-GQb2LMF6IiEzhp01F6eIN7HlPVlUWpWsBZZn7DOIo9upFAWhFpn2w1PStjGb17VmTkg+lgxzcajqcy6AJhCHUQ==",
- "requires": {
- "acme": "^1.3.0",
- "acme-dns-01-cli": "^3.0.0",
- "acme-v2": "^1.7.7",
- "cert-info": "^1.5.1",
- "greenlock-store-fs": "^3.0.2",
- "keypairs": "^1.2.14",
- "le-challenge-fs": "^2.0.2",
- "le-sni-auto": "^2.1.9",
- "le-store-certbot": "^2.2.3",
- "rsa-compat": "^2.0.8"
- }
- },
- "greenlock-store-fs": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/greenlock-store-fs/-/greenlock-store-fs-3.0.2.tgz",
- "integrity": "sha512-t4So75yKs1+7TqmxD5UKdf+zOQU0/4o0lb2auf5zUcAo7fwwNLOAXyWnnZRL3WuFBUiBGh1qXWleuMua0d3LPg==",
- "requires": {
- "@root/mkdirp": "^1.0.0",
- "safe-replace": "^1.1.0"
- }
- },
- "http-errors": {
- "version": "1.6.3",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
- "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
- "dev": true,
- "requires": {
- "depd": "~1.1.2",
- "inherits": "2.0.3",
- "setprototypeof": "1.1.0",
- "statuses": ">= 1.4.0 < 2"
- }
- },
- "iconv-lite": {
- "version": "0.4.23",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
- "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
- "dev": true,
- "requires": {
- "safer-buffer": ">= 2.1.2 < 3"
- }
- },
- "inherits": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
- "dev": true
- },
- "ipaddr.js": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz",
- "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=",
- "dev": true
- },
- "keypairs": {
- "version": "1.2.14",
- "resolved": "https://registry.npmjs.org/keypairs/-/keypairs-1.2.14.tgz",
- "integrity": "sha512-ZoZfZMygyB0QcjSlz7Rh6wT2CJasYEHBPETtmHZEfxuJd7bnsOG5AdtPZqHZBT+hoHvuWCp/4y8VmvTvH0Y9uA==",
- "requires": {
- "eckles": "^1.4.1",
- "rasha": "^1.2.4"
- }
- },
- "le-challenge-fs": {
- "version": "2.0.9",
- "resolved": "https://registry.npmjs.org/le-challenge-fs/-/le-challenge-fs-2.0.9.tgz",
- "integrity": "sha512-stzI6rxd+aXGxBl87QJKKY/i/wl3uz6EoWzX2xSazJvCPSYBQys1RVNgOcf0SfUQPh6TBCFJFSJkiR4mznb4sg==",
- "requires": {
- "@root/mkdirp": "^1.0.0"
- }
- },
- "le-sni-auto": {
- "version": "2.1.9",
- "resolved": "https://registry.npmjs.org/le-sni-auto/-/le-sni-auto-2.1.9.tgz",
- "integrity": "sha512-QmQHNwQDi/56GY8+qczFZ06FZbxaeJQjbjEhwwQHhkJ9IHhIQFkPfCT/OyDfLj4gqLIrg5ZX8CemxxVZnLEYfg=="
- },
- "le-store-certbot": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/le-store-certbot/-/le-store-certbot-2.2.3.tgz",
- "integrity": "sha512-c4ACR+v+JKMiAOOshLh6gdCKA7wIWR16+mROMLpQjq3rXJ3Vm8FaBHe2H+crT+flP+g7FmciAwUlfOJEJpIuCQ==",
- "requires": {
- "@root/mkdirp": "^1.0.0",
- "pyconf": "^1.1.7",
- "safe-replace": "^1.1.0"
- }
- },
- "media-typer": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
- "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
- "dev": true
- },
- "merge-descriptors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
- "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
- "dev": true
- },
- "methods": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
- "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
- "dev": true
- },
- "mime": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
- "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==",
- "dev": true
- },
- "mime-db": {
- "version": "1.38.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz",
- "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==",
- "dev": true
- },
- "mime-types": {
- "version": "2.1.22",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz",
- "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==",
- "dev": true,
- "requires": {
- "mime-db": "~1.38.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
- "dev": true
- },
- "negotiator": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
- "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=",
- "dev": true
- },
- "on-finished": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
- "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
- "dev": true,
- "requires": {
- "ee-first": "1.1.1"
- }
- },
- "parseurl": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
- "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=",
- "dev": true
- },
- "path-to-regexp": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
- "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
- "dev": true
- },
- "proxy-addr": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz",
- "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==",
- "dev": true,
- "requires": {
- "forwarded": "~0.1.2",
- "ipaddr.js": "1.8.0"
- }
- },
- "pyconf": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/pyconf/-/pyconf-1.1.7.tgz",
- "integrity": "sha512-v4clh33m68sjtMsh8XMpjhGWb/MQODAYZ1y7ORG5Qv58UK25OddoB+oXyexgDkK8ttFui/lZm2sQDgA2Ftjfkw==",
- "requires": {
- "safe-replace": "^1.0.2"
- }
- },
- "qs": {
- "version": "6.5.2",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
- "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
- "dev": true
- },
- "range-parser": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
- "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=",
- "dev": true
- },
- "rasha": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/rasha/-/rasha-1.2.5.tgz",
- "integrity": "sha512-KxtX+/fBk+wM7O3CNgwjSh5elwFilLvqWajhr6wFr2Hd63JnKTTi43Tw+Jb1hxJQWOwoya+NZWR2xztn3hCrTw=="
- },
- "raw-body": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz",
- "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==",
- "dev": true,
- "requires": {
- "bytes": "3.0.0",
- "http-errors": "1.6.3",
- "iconv-lite": "0.4.23",
- "unpipe": "1.0.0"
- }
- },
- "redirect-https": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/redirect-https/-/redirect-https-1.3.0.tgz",
- "integrity": "sha512-9GzwI/+Cqw3jlSg0CW6TgBQbhiVhkHSDvW8wjgRQ9IK34wtxS71YJiQeazSCSEqbvowHCJuQZgmQFl1xUHKEgg==",
- "requires": {
- "escape-html": "^1.0.3"
- }
- },
- "rsa-compat": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/rsa-compat/-/rsa-compat-2.0.8.tgz",
- "integrity": "sha512-BFiiSEbuxzsVdaxpejbxfX07qs+rtous49Y6mL/zw6YHh9cranDvm2BvBmqT3rso84IsxNlP5BXnuNvm1Wn3Tw==",
- "requires": {
- "keypairs": "^1.2.14"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "safe-replace": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz",
- "integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw=="
- },
- "safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "dev": true
- },
- "send": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
- "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
- "dev": true,
- "requires": {
- "debug": "2.6.9",
- "depd": "~1.1.2",
- "destroy": "~1.0.4",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "fresh": "0.5.2",
- "http-errors": "~1.6.2",
- "mime": "1.4.1",
- "ms": "2.0.0",
- "on-finished": "~2.3.0",
- "range-parser": "~1.2.0",
- "statuses": "~1.4.0"
- }
- },
- "serve-index": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
- "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
- "dev": true,
- "requires": {
- "accepts": "~1.3.4",
- "batch": "0.6.1",
- "debug": "2.6.9",
- "escape-html": "~1.0.3",
- "http-errors": "~1.6.2",
- "mime-types": "~2.1.17",
- "parseurl": "~1.3.2"
- }
- },
- "serve-static": {
- "version": "1.13.2",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
- "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
- "dev": true,
- "requires": {
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "parseurl": "~1.3.2",
- "send": "0.16.2"
- }
- },
- "setprototypeof": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
- "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
- "dev": true
- },
- "statuses": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
- "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==",
- "dev": true
- },
- "type-is": {
- "version": "1.6.16",
- "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
- "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
- "dev": true,
- "requires": {
- "media-typer": "0.3.0",
- "mime-types": "~2.1.18"
- }
- },
- "unpipe": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
- "dev": true
- },
- "utils-merge": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
- "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
- "dev": true
- },
- "vary": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
- "dev": true
- },
- "ws": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
- "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
- "dev": true,
- "requires": {
- "async-limiter": "~1.0.0"
- }
- }
- }
+ "name": "greenlock-express",
+ "version": "2.7.9",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@coolaj86/urequest": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/@coolaj86/urequest/-/urequest-1.3.7.tgz",
+ "integrity": "sha512-PPrVYra9aWvZjSCKl/x1pJ9ZpXda1652oJrPBYy5rQumJJMkmTBN3ux+sK2xAUwVvv2wnewDlaQaHLxLwSHnIA=="
+ },
+ "@root/mkdirp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz",
+ "integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA=="
+ },
+ "accepts": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
+ "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
+ "dev": true,
+ "requires": {
+ "mime-types": "~2.1.18",
+ "negotiator": "0.6.1"
+ }
+ },
+ "acme": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/acme/-/acme-1.3.0.tgz",
+ "integrity": "sha512-Ny8aXnGdtlEVBZLpzNyVp7gff/3zFYrbfbiY93lx5jdrG4BrraA6P8RkRFP7NbFwh1rBgQkdHEsMxTp3f2r8dA==",
+ "requires": {
+ "acme-v2": "^1.6.0"
+ }
+ },
+ "acme-dns-01-cli": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/acme-dns-01-cli/-/acme-dns-01-cli-3.0.7.tgz",
+ "integrity": "sha512-Aa4bUpq6ftX1VODiShOetOY5U0tsXY5EV7+fQwme3Q8Y9rjYBArBXHgFCAVKtK1AF+Ev8pIuF6Z42hzMFa73/w=="
+ },
+ "acme-v2": {
+ "version": "1.7.7",
+ "resolved": "https://registry.npmjs.org/acme-v2/-/acme-v2-1.7.7.tgz",
+ "integrity": "sha512-Pg0EQ45h8N2e4K2goYedutCgWxAmtcruwDHr6hgPBgAWEORVb5SQEdXjtEhCrn+APtr7MyFPryyzXpYpDD5ecA==",
+ "requires": {
+ "@coolaj86/urequest": "^1.3.6",
+ "rsa-compat": "^2.0.6"
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
+ "dev": true
+ },
+ "async-limiter": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
+ "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
+ "dev": true
+ },
+ "basic-auth": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+ "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.1.2"
+ }
+ },
+ "batch": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
+ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=",
+ "dev": true
+ },
+ "body-parser": {
+ "version": "1.18.3",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz",
+ "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=",
+ "dev": true,
+ "requires": {
+ "bytes": "3.0.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "~1.6.3",
+ "iconv-lite": "0.4.23",
+ "on-finished": "~2.3.0",
+ "qs": "6.5.2",
+ "raw-body": "2.3.3",
+ "type-is": "~1.6.16"
+ }
+ },
+ "bytes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
+ "dev": true
+ },
+ "cert-info": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/cert-info/-/cert-info-1.5.1.tgz",
+ "integrity": "sha512-eoQC/yAgW3gKTKxjzyClvi+UzuY97YCjcl+lSqbsGIy7HeGaWxCPOQFivhUYm27hgsBMhsJJFya3kGvK6PMIcQ=="
+ },
+ "content-disposition": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
+ "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=",
+ "dev": true
+ },
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+ "dev": true
+ },
+ "cookie": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=",
+ "dev": true
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
+ "dev": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+ "dev": true
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
+ "dev": true
+ },
+ "eckles": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/eckles/-/eckles-1.4.1.tgz",
+ "integrity": "sha512-auWyk/k8oSkVHaD4RxkPadKsLUcIwKgr/h8F7UZEueFDBO7BsE4y+H6IMUDbfqKIFPg/9MxV6KcBdJCmVVcxSA=="
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+ "dev": true
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+ "dev": true
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+ "dev": true
+ },
+ "express": {
+ "version": "4.16.4",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz",
+ "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==",
+ "dev": true,
+ "requires": {
+ "accepts": "~1.3.5",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.18.3",
+ "content-disposition": "0.5.2",
+ "content-type": "~1.0.4",
+ "cookie": "0.3.1",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.1.1",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.2",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.4",
+ "qs": "6.5.2",
+ "range-parser": "~1.2.0",
+ "safe-buffer": "5.1.2",
+ "send": "0.16.2",
+ "serve-static": "1.13.2",
+ "setprototypeof": "1.1.0",
+ "statuses": "~1.4.0",
+ "type-is": "~1.6.16",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ }
+ },
+ "express-basic-auth": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.1.6.tgz",
+ "integrity": "sha512-fRh/UU2q/YhvY0/Pkzi3VcLyjIExveW2NOOnOGgO6yO0jKXt6zcKPVPWSrL8nlhlh+YEH5LOjz+CGFML5dJQNw==",
+ "dev": true,
+ "requires": {
+ "basic-auth": "^2.0.1"
+ }
+ },
+ "finalhandler": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
+ "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
+ "dev": true,
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.2",
+ "statuses": "~1.4.0",
+ "unpipe": "~1.0.0"
+ }
+ },
+ "forwarded": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
+ "dev": true
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+ "dev": true
+ },
+ "greenlock": {
+ "version": "2.7.24",
+ "resolved": "https://registry.npmjs.org/greenlock/-/greenlock-2.7.24.tgz",
+ "integrity": "sha512-GQb2LMF6IiEzhp01F6eIN7HlPVlUWpWsBZZn7DOIo9upFAWhFpn2w1PStjGb17VmTkg+lgxzcajqcy6AJhCHUQ==",
+ "requires": {
+ "acme": "^1.3.0",
+ "acme-dns-01-cli": "^3.0.0",
+ "acme-v2": "^1.7.7",
+ "cert-info": "^1.5.1",
+ "greenlock-store-fs": "^3.0.2",
+ "keypairs": "^1.2.14",
+ "le-challenge-fs": "^2.0.2",
+ "le-sni-auto": "^2.1.9",
+ "le-store-certbot": "^2.2.3",
+ "rsa-compat": "^2.0.8"
+ }
+ },
+ "greenlock-store-fs": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/greenlock-store-fs/-/greenlock-store-fs-3.0.2.tgz",
+ "integrity": "sha512-t4So75yKs1+7TqmxD5UKdf+zOQU0/4o0lb2auf5zUcAo7fwwNLOAXyWnnZRL3WuFBUiBGh1qXWleuMua0d3LPg==",
+ "requires": {
+ "@root/mkdirp": "^1.0.0",
+ "safe-replace": "^1.1.0"
+ }
+ },
+ "http-errors": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+ "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
+ "dev": true,
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.0",
+ "statuses": ">= 1.4.0 < 2"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.23",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
+ "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ },
+ "ipaddr.js": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz",
+ "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=",
+ "dev": true
+ },
+ "keypairs": {
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/keypairs/-/keypairs-1.2.14.tgz",
+ "integrity": "sha512-ZoZfZMygyB0QcjSlz7Rh6wT2CJasYEHBPETtmHZEfxuJd7bnsOG5AdtPZqHZBT+hoHvuWCp/4y8VmvTvH0Y9uA==",
+ "requires": {
+ "eckles": "^1.4.1",
+ "rasha": "^1.2.4"
+ }
+ },
+ "le-challenge-fs": {
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/le-challenge-fs/-/le-challenge-fs-2.0.9.tgz",
+ "integrity": "sha512-stzI6rxd+aXGxBl87QJKKY/i/wl3uz6EoWzX2xSazJvCPSYBQys1RVNgOcf0SfUQPh6TBCFJFSJkiR4mznb4sg==",
+ "requires": {
+ "@root/mkdirp": "^1.0.0"
+ }
+ },
+ "le-sni-auto": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/le-sni-auto/-/le-sni-auto-2.1.9.tgz",
+ "integrity": "sha512-QmQHNwQDi/56GY8+qczFZ06FZbxaeJQjbjEhwwQHhkJ9IHhIQFkPfCT/OyDfLj4gqLIrg5ZX8CemxxVZnLEYfg=="
+ },
+ "le-store-certbot": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/le-store-certbot/-/le-store-certbot-2.2.3.tgz",
+ "integrity": "sha512-c4ACR+v+JKMiAOOshLh6gdCKA7wIWR16+mROMLpQjq3rXJ3Vm8FaBHe2H+crT+flP+g7FmciAwUlfOJEJpIuCQ==",
+ "requires": {
+ "@root/mkdirp": "^1.0.0",
+ "pyconf": "^1.1.7",
+ "safe-replace": "^1.1.0"
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+ "dev": true
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
+ "dev": true
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+ "dev": true
+ },
+ "mime": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
+ "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==",
+ "dev": true
+ },
+ "mime-db": {
+ "version": "1.38.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz",
+ "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==",
+ "dev": true
+ },
+ "mime-types": {
+ "version": "2.1.22",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz",
+ "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==",
+ "dev": true,
+ "requires": {
+ "mime-db": "~1.38.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "negotiator": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
+ "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=",
+ "dev": true
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "dev": true,
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "parseurl": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+ "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=",
+ "dev": true
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
+ "dev": true
+ },
+ "proxy-addr": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz",
+ "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==",
+ "dev": true,
+ "requires": {
+ "forwarded": "~0.1.2",
+ "ipaddr.js": "1.8.0"
+ }
+ },
+ "pyconf": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/pyconf/-/pyconf-1.1.7.tgz",
+ "integrity": "sha512-v4clh33m68sjtMsh8XMpjhGWb/MQODAYZ1y7ORG5Qv58UK25OddoB+oXyexgDkK8ttFui/lZm2sQDgA2Ftjfkw==",
+ "requires": {
+ "safe-replace": "^1.0.2"
+ }
+ },
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+ "dev": true
+ },
+ "range-parser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
+ "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=",
+ "dev": true
+ },
+ "rasha": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/rasha/-/rasha-1.2.5.tgz",
+ "integrity": "sha512-KxtX+/fBk+wM7O3CNgwjSh5elwFilLvqWajhr6wFr2Hd63JnKTTi43Tw+Jb1hxJQWOwoya+NZWR2xztn3hCrTw=="
+ },
+ "raw-body": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz",
+ "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==",
+ "dev": true,
+ "requires": {
+ "bytes": "3.0.0",
+ "http-errors": "1.6.3",
+ "iconv-lite": "0.4.23",
+ "unpipe": "1.0.0"
+ }
+ },
+ "redirect-https": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/redirect-https/-/redirect-https-1.3.0.tgz",
+ "integrity": "sha512-9GzwI/+Cqw3jlSg0CW6TgBQbhiVhkHSDvW8wjgRQ9IK34wtxS71YJiQeazSCSEqbvowHCJuQZgmQFl1xUHKEgg==",
+ "requires": {
+ "escape-html": "^1.0.3"
+ }
+ },
+ "rsa-compat": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/rsa-compat/-/rsa-compat-2.0.8.tgz",
+ "integrity": "sha512-BFiiSEbuxzsVdaxpejbxfX07qs+rtous49Y6mL/zw6YHh9cranDvm2BvBmqT3rso84IsxNlP5BXnuNvm1Wn3Tw==",
+ "requires": {
+ "keypairs": "^1.2.14"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "safe-replace": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz",
+ "integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "send": {
+ "version": "0.16.2",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
+ "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
+ "dev": true,
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.6.2",
+ "mime": "1.4.1",
+ "ms": "2.0.0",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.0",
+ "statuses": "~1.4.0"
+ }
+ },
+ "serve-index": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+ "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
+ "dev": true,
+ "requires": {
+ "accepts": "~1.3.4",
+ "batch": "0.6.1",
+ "debug": "2.6.9",
+ "escape-html": "~1.0.3",
+ "http-errors": "~1.6.2",
+ "mime-types": "~2.1.17",
+ "parseurl": "~1.3.2"
+ }
+ },
+ "serve-static": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
+ "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
+ "dev": true,
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.2",
+ "send": "0.16.2"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
+ "dev": true
+ },
+ "statuses": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
+ "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==",
+ "dev": true
+ },
+ "type-is": {
+ "version": "1.6.16",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
+ "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
+ "dev": true,
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.18"
+ }
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+ "dev": true
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+ "dev": true
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+ "dev": true
+ },
+ "ws": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
+ "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
+ "dev": true,
+ "requires": {
+ "async-limiter": "~1.0.0"
+ }
+ }
+ }
}
diff --git a/package.json b/package.json
index 9c7a2b6..c13bd79 100644
--- a/package.json
+++ b/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 (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 (https://solderjs.com/)",
+ "license": "MPL-2.0",
+ "bugs": {
+ "url": "https://git.rootprojects.org/root/greenlock-express.js/issues"
+ }
}
diff --git a/server.js b/server.js
index 9752d2a..de5ebc9 100644
--- a/server.js
+++ b/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("");
- 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("");
+ 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);
+ });
+ });
}
diff --git a/test/greenlock.js b/test/greenlock.js
index c10e603..b2908ee 100644
--- a/test/greenlock.js
+++ b/test/greenlock.js
@@ -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");