https
express server läuft jetzt mit https
This commit is contained in:
		
							
								
								
									
										41
									
								
								express-server/node_modules/greenlock/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								express-server/node_modules/greenlock/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
Copyright 2017 AJ ONeal
 | 
			
		||||
 | 
			
		||||
This is open source software; you can redistribute it and/or modify it under the
 | 
			
		||||
terms of either:
 | 
			
		||||
 | 
			
		||||
   a) the "MIT License"
 | 
			
		||||
   b) the "Apache-2.0 License"
 | 
			
		||||
 | 
			
		||||
MIT License
 | 
			
		||||
 | 
			
		||||
   Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
   of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
   in the Software without restriction, including without limitation the rights
 | 
			
		||||
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
   copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
   furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
   The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
   copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
   SOFTWARE.
 | 
			
		||||
 | 
			
		||||
Apache-2.0 License Summary
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
							
								
								
									
										567
									
								
								express-server/node_modules/greenlock/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										567
									
								
								express-server/node_modules/greenlock/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,567 @@
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
Greenlock™ for node.js
 | 
			
		||||
=====
 | 
			
		||||
 | 
			
		||||
Greenlock provides Free SSL, Free Wildcard SSL, and Fully Automated HTTPS <br>
 | 
			
		||||
<small>certificates issued by Let's Encrypt v2 via [ACME](https://git.coolaj86.com/coolaj86/acme-v2.js)</small>
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||

 | 
			
		||||

 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
| Sponsored by [ppl](https://ppl.family) |
 | 
			
		||||
Greenlock works
 | 
			
		||||
in the [Commandline](https://git.coolaj86.com/coolaj86/greenlock-cli.js) (cli),
 | 
			
		||||
as a [Web Server](https://git.coolaj86.com/coolaj86/greenlock-server.js),
 | 
			
		||||
in [Web Browsers](https://git.coolaj86.com/coolaj86/greenlock.html) (WebCrypto),
 | 
			
		||||
and with **node.js** ([npm](https://www.npmjs.com/package/greenlock)).
 | 
			
		||||
 | 
			
		||||
Features
 | 
			
		||||
========
 | 
			
		||||
 | 
			
		||||
  - [x] Actively Maintained and Supported
 | 
			
		||||
  - [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 (30 to 21 days before expiration)
 | 
			
		||||
  - [x] Great ACME support via [acme.js](https://git.coolaj86.com/coolaj86/acme-v2.js)
 | 
			
		||||
    - [x] "dry run" with self-diagnostics
 | 
			
		||||
    - [x] ACME draft 12
 | 
			
		||||
    - [x] Let's Encrypt v2
 | 
			
		||||
    - [x] Let's Encrypt v1
 | 
			
		||||
  - [x] [Commandline](https://git.coolaj86.com/coolaj86/greenlock-cli.js) (cli) Utilities
 | 
			
		||||
    - [x] Works with `bash`, `fish`, `zsh`, `cmd.exe`, `PowerShell`, and more
 | 
			
		||||
  - [x] [Browser](https://git.coolaj86.com/coolaj86/greenlock.html) Support
 | 
			
		||||
  - [x] Full node.js support, with modules for
 | 
			
		||||
    - [x] [http/https](https://git.coolaj86.com/coolaj86/greenlock-express.js/src/branch/master/examples/https-server.js), [Express.js](https://git.coolaj86.com/coolaj86/greenlock-express.js), [cluster](https://git.coolaj86.com/coolaj86/greenlock-cluster.js), [hapi](https://git.coolaj86.com/coolaj86/greenlock-hapi.js), [Koa](https://git.coolaj86.com/coolaj86/greenlock-koa.js), [rill](https://git.coolaj86.com/coolaj86/greenlock-rill.js), [restify](https://git.coolaj86.com/coolaj86/greenlock-restify.js), spdy, etc
 | 
			
		||||
  - [x] Great for securing your Raspberry Pi
 | 
			
		||||
  - [x] Extensible Plugin Support
 | 
			
		||||
    - [x] AWS S3, AWS Route53, Azure, CloudFlare, Consul, Digital Ocean, etcd, Redis
 | 
			
		||||
 | 
			
		||||
Greenlock.js for Middleware
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
Documentation for using Greenlock with
 | 
			
		||||
[http/https](https://git.coolaj86.com/coolaj86/greenlock-express.js/src/branch/master/examples/https-server.js),
 | 
			
		||||
[Express.js](https://git.coolaj86.com/coolaj86/greenlock-express.js),
 | 
			
		||||
[cluster](https://git.coolaj86.com/coolaj86/greenlock-cluster.js),
 | 
			
		||||
[hapi](https://git.coolaj86.com/coolaj86/greenlock-hapi.js),
 | 
			
		||||
[Koa](https://git.coolaj86.com/coolaj86/greenlock-koa.js),
 | 
			
		||||
[rill](https://git.coolaj86.com/coolaj86/greenlock-rill.js).
 | 
			
		||||
[restify](https://git.coolaj86.com/coolaj86/greenlock-restify.js).
 | 
			
		||||
 | 
			
		||||
Table of Contents
 | 
			
		||||
=================
 | 
			
		||||
 | 
			
		||||
  * Install
 | 
			
		||||
  * **QuickStart**
 | 
			
		||||
  * Simple Examples
 | 
			
		||||
  * Example with ALL OPTIONS
 | 
			
		||||
  * API
 | 
			
		||||
  * Developer API
 | 
			
		||||
  * Change History
 | 
			
		||||
  * License
 | 
			
		||||
 | 
			
		||||
Install
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm install --save greenlock@2.x
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Optional** dependency for *more efficient* RSA key generation:
 | 
			
		||||
<small>(important for those on ARM devices like Raspberry Pi)</small>
 | 
			
		||||
```bash
 | 
			
		||||
npm install --save ursa
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Optional** dependency for *Let's Encrypt v01* (pre-draft ACME spec) compatibility:
 | 
			
		||||
<small>(important for those on ARM devices like Raspberry Pi)</small>
 | 
			
		||||
```bash
 | 
			
		||||
npm install --save le-acme-core
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Production vs Staging
 | 
			
		||||
 | 
			
		||||
If at first you don't succeed, stop and switch to staging.
 | 
			
		||||
 | 
			
		||||
I've implemented a "dry run" loopback test with self diagnostics
 | 
			
		||||
so it's pretty safe to start off with the production URLs
 | 
			
		||||
and be far less likely to hit the bad request rate limits.
 | 
			
		||||
 | 
			
		||||
However, if your first attempt to get a certificate fails
 | 
			
		||||
I'd recommend switching to the staging acme server to debug -
 | 
			
		||||
unless you're very clear on what the failure was and how to fix it.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
{ server: 'https://acme-staging-v02.api.letsencrypt.org/directory' }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### QuickStart Screencast
 | 
			
		||||
 | 
			
		||||
Watch the QuickStart demonstration: [https://youtu.be/e8vaR4CEZ5s](https://youtu.be/e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk)
 | 
			
		||||
 | 
			
		||||
<a href="https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk"><img src="https://i.imgur.com/Y8ix6Ts.png" title="QuickStart Video" alt="YouTube Video Preview" /></a>
 | 
			
		||||
 | 
			
		||||
* [0:00](https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk#t=0) - Intro
 | 
			
		||||
* [2:22](https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk#t=142) - Demonstrating QuickStart Example
 | 
			
		||||
* [6:37](https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk?t=397) - Troubleshooting / Gotchas
 | 
			
		||||
 | 
			
		||||
#### Production Configuration (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
 | 
			
		||||
 | 
			
		||||
#### Security Concerns (Part 3)
 | 
			
		||||
 | 
			
		||||
* [0:00](https://www.youtube.com/watch?v=aZgVqPzoZTY&index=3&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk) - Potential Attacks, and Mitigation
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Easy as 1, 2, 3... 4
 | 
			
		||||
=====
 | 
			
		||||
 | 
			
		||||
Greenlock is built to incredibly easy to use, without sacrificing customization or extensibility.
 | 
			
		||||
 | 
			
		||||
The following examples range from just a few lines of code for getting started,
 | 
			
		||||
to more robust examples that you might start with for an enterprise-grade use of the ACME api.
 | 
			
		||||
 | 
			
		||||
* Automatic HTTPS (for single sites)
 | 
			
		||||
* Fully Automatic HTTPS (for multi-domain vhosts)
 | 
			
		||||
* Manual HTTPS (for API integration)
 | 
			
		||||
 | 
			
		||||
Automatic HTTPS
 | 
			
		||||
---------------
 | 
			
		||||
 | 
			
		||||
**Note**: For (fully) automatic HTTPS you may prefer
 | 
			
		||||
the [Express.js module](https://git.coolaj86.com/coolaj86/greenlock-express.js)
 | 
			
		||||
 | 
			
		||||
This works for most people, but it's not as fun as some of the other examples.
 | 
			
		||||
 | 
			
		||||
Great when
 | 
			
		||||
 | 
			
		||||
 - [x] You only need a limited number of certificates
 | 
			
		||||
 - [x] You want to use the bare node http and https modules without fluff
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
////////////////////
 | 
			
		||||
// INIT GREENLOCK //
 | 
			
		||||
////////////////////
 | 
			
		||||
 | 
			
		||||
var greenlock = require('greenlock').create({
 | 
			
		||||
 | 
			
		||||
  version: 'draft-12'
 | 
			
		||||
, server: 'https://acme-v02.api.letsencrypt.org/directory'
 | 
			
		||||
, configDir: '~/.config/acme'
 | 
			
		||||
 | 
			
		||||
, email: 'user@example.com'           // IMPORTANT: Change email and domains
 | 
			
		||||
, agreeTos: true                      // Accept Let's Encrypt v2 Agreement
 | 
			
		||||
, communityMember: true               // Get (rare) non-mandatory updates about cool greenlock-related stuff (default false)
 | 
			
		||||
, securityUpdates: true               // Important and mandatory notices related to security or breaking API changes (default true)
 | 
			
		||||
 | 
			
		||||
, approveDomains: approveDomains
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
/////////////////////
 | 
			
		||||
// APPROVE DOMAINS //
 | 
			
		||||
/////////////////////
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function approveDomains(opts, certs, cb) {
 | 
			
		||||
 | 
			
		||||
  // check for domains you want to receive certificates for
 | 
			
		||||
  if ('example.com' === opts.domain) {
 | 
			
		||||
    cb(null, { options: opts, certs: certs });
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // return error otherwise
 | 
			
		||||
  cb(new Error("bad domain"));
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
////////////////////
 | 
			
		||||
// CREATE SERVERS //
 | 
			
		||||
////////////////////
 | 
			
		||||
 | 
			
		||||
var redir = require('redirect-https')();
 | 
			
		||||
require('http').createServer(greenlock.middleware(redir)).listen(80);
 | 
			
		||||
 | 
			
		||||
require('spdy').createServer(greenlock.tlsOptions, function (req, res) {
 | 
			
		||||
  res.end('Hello, Secure World!');
 | 
			
		||||
}).listen(443);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Fully Automatic HTTPS
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
**Note**: For (fully) automatic HTTPS you may prefer
 | 
			
		||||
the [Express.js module](https://git.coolaj86.com/coolaj86/greenlock-express.js)
 | 
			
		||||
 | 
			
		||||
Great when
 | 
			
		||||
 | 
			
		||||
 - [x] You have a growing number of domains
 | 
			
		||||
 - [x] You're integrating into your own hosting solution
 | 
			
		||||
 - [x] Customize ACME http-01 or dns-01 challenge
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
////////////////////
 | 
			
		||||
// INIT GREENLOCK //
 | 
			
		||||
////////////////////
 | 
			
		||||
 | 
			
		||||
var path = require('path');
 | 
			
		||||
var os = require('os')
 | 
			
		||||
var Greenlock = require('greenlock');
 | 
			
		||||
 | 
			
		||||
var greenlock = Greenlock.create({
 | 
			
		||||
  version: 'draft-12'
 | 
			
		||||
, server: 'https://acme-v02.api.letsencrypt.org/directory'
 | 
			
		||||
 | 
			
		||||
  // approve a growing list of domains
 | 
			
		||||
, approveDomains: approveDomains
 | 
			
		||||
 | 
			
		||||
  // If you wish to replace the default account and domain key storage plugin
 | 
			
		||||
, store: require('le-store-certbot').create({
 | 
			
		||||
    configDir: path.join(os.homedir(), 'acme/etc')
 | 
			
		||||
  , webrootPath: '/tmp/acme-challenges'
 | 
			
		||||
  })
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/////////////////////
 | 
			
		||||
// APPROVE DOMAINS //
 | 
			
		||||
/////////////////////
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
  // 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 };
 | 
			
		||||
 | 
			
		||||
  // 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.altnames;
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    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({});
 | 
			
		||||
 | 
			
		||||
  cb(null, { options: opts, certs: certs });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////
 | 
			
		||||
// CREATE SERVERS //
 | 
			
		||||
////////////////////
 | 
			
		||||
 | 
			
		||||
var redir = require('redirect-https')();
 | 
			
		||||
require('http').createServer(greenlock.middleware(redir)).listen(80);
 | 
			
		||||
 | 
			
		||||
require('https').createServer(greenlock.tlsOptions, function (req, res) {
 | 
			
		||||
  res.end('Hello, Secure World!');
 | 
			
		||||
}).listen(443);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Manual HTTPS
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
Here's a taste of the API that you might use if building a commandline tool or API integration
 | 
			
		||||
that doesn't use node's SNICallback.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/////////////////////
 | 
			
		||||
// SET USER PARAMS //
 | 
			
		||||
/////////////////////
 | 
			
		||||
 | 
			
		||||
var opts = {
 | 
			
		||||
  domains: [ 'example.com'        // CHANGE EMAIL AND DOMAINS
 | 
			
		||||
           , 'www.example.com' ]
 | 
			
		||||
, email: 'user@example.com'
 | 
			
		||||
, agreeTos: true                  // Accept Let's Encrypt v2 Agreement
 | 
			
		||||
, communityMember: true           // Help make Greenlock better by submitting
 | 
			
		||||
                                  // stats and getting updates
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////
 | 
			
		||||
// INIT GREENLOCK //
 | 
			
		||||
////////////////////
 | 
			
		||||
 | 
			
		||||
var greenlock = require('greenlock').create({
 | 
			
		||||
  version: 'draft-12'
 | 
			
		||||
, server: 'https://acme-v02.api.letsencrypt.org/directory'
 | 
			
		||||
, configDir: '/tmp/acme/etc'
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
///////////////////
 | 
			
		||||
// GET TLS CERTS //
 | 
			
		||||
///////////////////
 | 
			
		||||
 | 
			
		||||
greenlock.register(opts).then(function (certs) {
 | 
			
		||||
  console.log(certs);
 | 
			
		||||
  // privkey, cert, chain, expiresAt, issuedAt, subject, altnames
 | 
			
		||||
}, function (err) {
 | 
			
		||||
  console.error(err);
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The domain key and ssl certificates you get back can be used in a webserver like this:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var tlsOptions = { key: certs.privkey, cert: certs.cert + '\r\n' + certs.chain };
 | 
			
		||||
require('https').createServer(tlsOptions, function (req, res) {
 | 
			
		||||
  res.end('Hello, Secure World!');
 | 
			
		||||
}).listen(443);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Example with ALL OPTIONS
 | 
			
		||||
=========
 | 
			
		||||
 | 
			
		||||
The configuration consists of 3 components:
 | 
			
		||||
 | 
			
		||||
* Storage Backend (search npm for projects starting with 'le-store-')
 | 
			
		||||
* ACME Challenge Handlers (search npm for projects starting with 'le-challenge-')
 | 
			
		||||
* Letsencryt Config (this is all you)
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var Greenlock = require('greenlock');
 | 
			
		||||
var greenlock;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Storage Backend
 | 
			
		||||
var leStore = require('le-store-certbot').create({
 | 
			
		||||
  configDir: '~/acme/etc'                                 // or /etc/letsencrypt or wherever
 | 
			
		||||
, debug: false
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ACME Challenge Handlers
 | 
			
		||||
var leHttpChallenge = require('le-challenge-fs').create({
 | 
			
		||||
  webrootPath: '~/acme/var/'                              // or template string such as
 | 
			
		||||
, debug: false                                            // '/srv/www/:hostname/.well-known/acme-challenge'
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function leAgree(opts, agreeCb) {
 | 
			
		||||
  // opts = { email, domains, tosUrl }
 | 
			
		||||
  agreeCb(null, opts.tosUrl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
greenlock = Greenlock.create({
 | 
			
		||||
  version: 'draft-12'                                     // 'draft-12' or 'v01'
 | 
			
		||||
                                                          // 'draft-12' is for Let's Encrypt v2 otherwise known as ACME draft 12
 | 
			
		||||
                                                          // 'v02' is an alias for 'draft-12'
 | 
			
		||||
                                                          // 'v01' is for the pre-spec Let's Encrypt v1
 | 
			
		||||
  //
 | 
			
		||||
  // staging API
 | 
			
		||||
  //server: 'https://acme-staging-v02.api.letsencrypt.org/directory'
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // production API
 | 
			
		||||
  server: 'https://acme-v02.api.letsencrypt.org/directory'
 | 
			
		||||
 | 
			
		||||
, store: leStore                                          // handles saving of config, accounts, and certificates
 | 
			
		||||
, challenges: {
 | 
			
		||||
    'http-01': leHttpChallenge                            // handles /.well-known/acme-challege keys and tokens
 | 
			
		||||
  }
 | 
			
		||||
, challengeType: 'http-01'                                // default to this challenge type
 | 
			
		||||
, agreeToTerms: leAgree                                   // hook to allow user to view and accept LE TOS
 | 
			
		||||
//, sni: require('le-sni-auto').create({})                // handles sni callback
 | 
			
		||||
 | 
			
		||||
                                                          // renewals happen at a random time within this window
 | 
			
		||||
, renewWithin: 30 * 24 * 60 * 60 * 1000                   // certificate renewal may begin at this time
 | 
			
		||||
, renewBy:     21 * 24 * 60 * 60 * 1000                   // certificate renewal should happen by this time
 | 
			
		||||
 | 
			
		||||
, debug: false
 | 
			
		||||
//, log: function (debug) {console.log.apply(console, args);} // handles debug outputs
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// If using express you should use the middleware
 | 
			
		||||
// app.use('/', greenlock.middleware());
 | 
			
		||||
//
 | 
			
		||||
// Otherwise you should see the test file for usage of this:
 | 
			
		||||
// greenlock.challenges['http-01'].get(opts.domain, key, val, done)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Check in-memory cache of certificates for the named domain
 | 
			
		||||
greenlock.check({ domains: [ 'example.com' ] }).then(function (results) {
 | 
			
		||||
  if (results) {
 | 
			
		||||
    // we already have certificates
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  // Register Certificate manually
 | 
			
		||||
  greenlock.register({
 | 
			
		||||
 | 
			
		||||
    domains: ['example.com']                                // CHANGE TO YOUR DOMAIN (list for SANS)
 | 
			
		||||
  , email: 'user@email.com'                                 // CHANGE TO YOUR EMAIL
 | 
			
		||||
  , agreeTos: ''                                            // set to tosUrl string (or true) to pre-approve (and skip agreeToTerms)
 | 
			
		||||
  , rsaKeySize: 2048                                        // 2048 or higher
 | 
			
		||||
  , challengeType: 'http-01'                                // http-01, tls-sni-01, or dns-01
 | 
			
		||||
 | 
			
		||||
  }).then(function (results) {
 | 
			
		||||
 | 
			
		||||
    console.log('success');
 | 
			
		||||
 | 
			
		||||
  }, function (err) {
 | 
			
		||||
 | 
			
		||||
    // Note: you must either use greenlock.middleware() with express,
 | 
			
		||||
    // manually use greenlock.challenges['http-01'].get(opts, domain, key, val, done)
 | 
			
		||||
    // or have a webserver running and responding
 | 
			
		||||
    // to /.well-known/acme-challenge at `webrootPath`
 | 
			
		||||
    console.error('[Error]: node-greenlock/examples/standalone');
 | 
			
		||||
    console.error(err.stack);
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Here's what `results` looks like:
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
{ privkey: ''     // PEM encoded private key
 | 
			
		||||
, cert: ''        // PEM encoded cert
 | 
			
		||||
, chain: ''       // PEM encoded intermediate cert
 | 
			
		||||
, issuedAt: 0     // notBefore date (in ms) parsed from cert
 | 
			
		||||
, expiresAt: 0    // notAfter date (in ms) parsed from cert
 | 
			
		||||
, subject: ''     // example.com
 | 
			
		||||
, altnames: []    // example.com,www.example.com
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
API
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
The full end-user API is exposed in the example above and includes all relevant options.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
greenlock.register(opts)
 | 
			
		||||
greenlock.check(opts)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Helper Functions
 | 
			
		||||
 | 
			
		||||
We do expose a few helper functions:
 | 
			
		||||
 | 
			
		||||
* Greenlock.validDomain(hostname) // returns '' or the hostname string if it's a valid ascii or punycode domain name
 | 
			
		||||
 | 
			
		||||
TODO fetch domain tld list
 | 
			
		||||
 | 
			
		||||
### Template Strings
 | 
			
		||||
 | 
			
		||||
The following variables will be tempalted in any strings passed to the options object:
 | 
			
		||||
 | 
			
		||||
* `~/` replaced with `os.homedir()` i.e. `/Users/aj`
 | 
			
		||||
* `:hostname` replaced with the first domain in the list i.e. `example.com`
 | 
			
		||||
 | 
			
		||||
### Dangerous Options
 | 
			
		||||
 | 
			
		||||
By default SNI is made to lowercase and is automatically rejected if it contains invalid characters for a domain.
 | 
			
		||||
This behavior can be modified:
 | 
			
		||||
 | 
			
		||||
  * `__dns_allow_dangerous_names` allow SNI names like "Robert'); DROP TABLE Students;"
 | 
			
		||||
  * `__dns_preserve_case` passes SNI names such as "ExAMpLE.coM" without converting to lower case
 | 
			
		||||
 | 
			
		||||
Developer API
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
If you are developing an `le-store-*` or `le-challenge-*` plugin you need to be aware of
 | 
			
		||||
additional internal API expectations.
 | 
			
		||||
 | 
			
		||||
**IMPORTANT**:
 | 
			
		||||
 | 
			
		||||
Use `v2.0.0` as your initial version - NOT v0.1.0 and NOT v1.0.0 and NOT v3.0.0.
 | 
			
		||||
This is to indicate that your module is compatible with v2.x of node-greenlock.
 | 
			
		||||
 | 
			
		||||
Since the public API for your module is defined by node-greenlock the major version
 | 
			
		||||
should be kept in sync.
 | 
			
		||||
 | 
			
		||||
### store implementation
 | 
			
		||||
 | 
			
		||||
See <https://git.coolaj86.com/coolaj86/le-store-SPEC.js>
 | 
			
		||||
 | 
			
		||||
* getOptions()
 | 
			
		||||
* accounts.
 | 
			
		||||
  * checkKeypair(opts, cb)
 | 
			
		||||
  * check(opts, cb)
 | 
			
		||||
  * setKeypair(opts, keypair, cb)
 | 
			
		||||
  * set(opts, reg, cb)
 | 
			
		||||
* certificates.
 | 
			
		||||
  * checkKeypair(opts, cb)
 | 
			
		||||
  * check(opts, cb)
 | 
			
		||||
  * setKeypair(opts, keypair, cb)
 | 
			
		||||
  * set(opts, reg, cb)
 | 
			
		||||
 | 
			
		||||
### challenge implementation
 | 
			
		||||
 | 
			
		||||
See https://git.coolaj86.com/coolaj86/le-challenge-fs.js
 | 
			
		||||
 | 
			
		||||
* `.set(opts, domain, key, value, cb);`         // opts will be saved with domain/key
 | 
			
		||||
* `.get(opts, domain, key, cb);`                // opts will be retrieved by domain/key
 | 
			
		||||
* `.remove(opts, domain, key, cb);`             // opts will be retrieved by domain/key
 | 
			
		||||
 | 
			
		||||
Change History
 | 
			
		||||
==============
 | 
			
		||||
* v2.4
 | 
			
		||||
  * v2.4.3 - add security updates (default true) independent of community updates (default false)
 | 
			
		||||
* v2.2 - Let's Encrypt v2 Support
 | 
			
		||||
  * v2.2.11 - documentation updates
 | 
			
		||||
  * v2.2.10 - don't let SNICallback swallow approveDomains errors 6286883fc2a6ebfff711a540a2e4d92f3ac2907c
 | 
			
		||||
  * v2.2.8 - communityMember option support
 | 
			
		||||
  * v2.2.7 - bugfix for wildcard support
 | 
			
		||||
  * v2.2.5 - node v6.x compat
 | 
			
		||||
  * v2.2.4 - don't promisify all of `dns`
 | 
			
		||||
  * v2.2.3 - `renewWithin` default to 30 days
 | 
			
		||||
  * v2.2.2 - replace git dependency with npm
 | 
			
		||||
  * v2.2.1 - April 2018 **Let's Encrypt v2** support
 | 
			
		||||
* v2.1.17 - Nov 5th 2017 migrate back to personal repo
 | 
			
		||||
* v2.1.9 - Jan 18th 2017 renamed to greenlock
 | 
			
		||||
* v2.0.2 - Aug 9th 2016 update readme
 | 
			
		||||
* v2.0.1 - Aug 9th 2016
 | 
			
		||||
  * major refactor
 | 
			
		||||
  * simplified API
 | 
			
		||||
  * modular plugins
 | 
			
		||||
  * knock out bugs
 | 
			
		||||
* v1.5.0 now using letiny-core v2.0.0 and rsa-compat
 | 
			
		||||
* v1.4.x I can't remember... but it's better!
 | 
			
		||||
* v1.1.0 Added letiny-core, removed node-letsencrypt-python
 | 
			
		||||
* v1.0.2 Works with node-letsencrypt-python
 | 
			
		||||
* v1.0.0 Thar be dragons
 | 
			
		||||
 | 
			
		||||
LICENSE
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
Dual-licensed MIT and Apache-2.0
 | 
			
		||||
 | 
			
		||||
See LICENSE
 | 
			
		||||
 | 
			
		||||
Greenlock™ is a trademark of AJ ONeal
 | 
			
		||||
							
								
								
									
										597
									
								
								express-server/node_modules/greenlock/index.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										597
									
								
								express-server/node_modules/greenlock/index.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,597 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var DAY = 24 * 60 * 60 * 1000;
 | 
			
		||||
//var MIN = 60 * 1000;
 | 
			
		||||
var ACME = require('acme-v2/compat').ACME;
 | 
			
		||||
var pkg = require('./package.json');
 | 
			
		||||
var PromiseA;
 | 
			
		||||
try {
 | 
			
		||||
  PromiseA = require('bluebird');
 | 
			
		||||
} catch(e) {
 | 
			
		||||
  PromiseA = global.Promise;
 | 
			
		||||
}
 | 
			
		||||
var util = require('util');
 | 
			
		||||
function promisifyAllSelf(obj) {
 | 
			
		||||
  if (obj.__promisified) { return obj; }
 | 
			
		||||
  Object.keys(obj).forEach(function (key) {
 | 
			
		||||
    if ('function' === typeof obj[key]) {
 | 
			
		||||
      obj[key + 'Async'] = util.promisify(obj[key]);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  obj.__promisified = true;
 | 
			
		||||
  return obj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var Greenlock = module.exports;
 | 
			
		||||
Greenlock.Greenlock = Greenlock;
 | 
			
		||||
Greenlock.LE = Greenlock;
 | 
			
		||||
// in-process cache, shared between all instances
 | 
			
		||||
var ipc = {};
 | 
			
		||||
 | 
			
		||||
function _log(debug) {
 | 
			
		||||
  if (debug) {
 | 
			
		||||
    var args = Array.prototype.slice.call(arguments);
 | 
			
		||||
    args.shift();
 | 
			
		||||
    args.unshift("[gl/index.js]");
 | 
			
		||||
    console.log.apply(console, args);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Greenlock.defaults = {
 | 
			
		||||
  productionServerUrl: 'https://acme-v01.api.letsencrypt.org/directory'
 | 
			
		||||
, stagingServerUrl: 'https://acme-staging.api.letsencrypt.org/directory'
 | 
			
		||||
 | 
			
		||||
, rsaKeySize: ACME.rsaKeySize || 2048
 | 
			
		||||
, challengeType: ACME.challengeType || 'http-01'
 | 
			
		||||
, challengeTypes: ACME.challengeTypes || [ 'http-01', 'dns-01' ]
 | 
			
		||||
 | 
			
		||||
, acmeChallengePrefix: ACME.acmeChallengePrefix
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// backwards compat
 | 
			
		||||
Object.keys(Greenlock.defaults).forEach(function (key) {
 | 
			
		||||
  Greenlock[key] = Greenlock.defaults[key];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// show all possible options
 | 
			
		||||
var u; // undefined
 | 
			
		||||
Greenlock._undefined = {
 | 
			
		||||
  acme: u
 | 
			
		||||
, store: u
 | 
			
		||||
, challenge: u
 | 
			
		||||
, challenges: u
 | 
			
		||||
, sni: u
 | 
			
		||||
, tlsOptions: u
 | 
			
		||||
 | 
			
		||||
, register: u
 | 
			
		||||
, check: u
 | 
			
		||||
 | 
			
		||||
, renewWithin: u // le-auto-sni and core
 | 
			
		||||
//, renewBy: u // le-auto-sni
 | 
			
		||||
, acmeChallengePrefix: u
 | 
			
		||||
, rsaKeySize: u
 | 
			
		||||
, challengeType: u
 | 
			
		||||
, server: u
 | 
			
		||||
, version: u
 | 
			
		||||
, agreeToTerms: u
 | 
			
		||||
, _ipc: u
 | 
			
		||||
, duplicate: u
 | 
			
		||||
, _acmeUrls: u
 | 
			
		||||
};
 | 
			
		||||
Greenlock._undefine = function (gl) {
 | 
			
		||||
  Object.keys(Greenlock._undefined).forEach(function (key) {
 | 
			
		||||
    if (!(key in gl)) {
 | 
			
		||||
      gl[key] = u;
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return gl;
 | 
			
		||||
};
 | 
			
		||||
Greenlock.create = function (gl) {
 | 
			
		||||
  gl.store = gl.store || require('le-store-certbot').create({
 | 
			
		||||
    debug: gl.debug
 | 
			
		||||
  , configDir: gl.configDir
 | 
			
		||||
  , logsDir: gl.logsDir
 | 
			
		||||
  , webrootPath: gl.webrootPath
 | 
			
		||||
  });
 | 
			
		||||
  gl.core = require('./lib/core');
 | 
			
		||||
  var log = gl.log || _log;
 | 
			
		||||
 | 
			
		||||
  if (!gl.challenges) {
 | 
			
		||||
    gl.challenges = {};
 | 
			
		||||
  }
 | 
			
		||||
  if (!gl.challenges['http-01']) {
 | 
			
		||||
    gl.challenges['http-01'] = require('le-challenge-fs').create({
 | 
			
		||||
      debug: gl.debug
 | 
			
		||||
    , webrootPath: gl.webrootPath
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  if (!gl.challenges['dns-01']) {
 | 
			
		||||
    try {
 | 
			
		||||
      gl.challenges['dns-01'] = require('le-challenge-ddns').create({ debug: gl.debug });
 | 
			
		||||
    } catch(e) {
 | 
			
		||||
      try {
 | 
			
		||||
        gl.challenges['dns-01'] = require('le-challenge-dns').create({ debug: gl.debug });
 | 
			
		||||
      } catch(e) {
 | 
			
		||||
        // not yet implemented
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  gl = Greenlock._undefine(gl);
 | 
			
		||||
  gl.acmeChallengePrefix = Greenlock.acmeChallengePrefix;
 | 
			
		||||
  gl.rsaKeySize = gl.rsaKeySize || Greenlock.rsaKeySize;
 | 
			
		||||
  gl.challengeType = gl.challengeType || Greenlock.challengeType;
 | 
			
		||||
  gl._ipc = ipc;
 | 
			
		||||
  gl._communityPackage = gl._communityPackage || 'greenlock.js';
 | 
			
		||||
  if ('greenlock.js' === gl._communityPackage) {
 | 
			
		||||
    gl._communityPackageVersion = pkg.version;
 | 
			
		||||
  } else {
 | 
			
		||||
    gl._communityPackageVersion = gl._communityPackageVersion || ('greenlock.js-' + pkg.version);
 | 
			
		||||
  }
 | 
			
		||||
  gl.agreeToTerms = gl.agreeToTerms || function (args, agreeCb) {
 | 
			
		||||
    agreeCb(new Error("'agreeToTerms' was not supplied to Greenlock and 'agreeTos' was not supplied to Greenlock.register"));
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (!gl.renewWithin) { gl.renewWithin = 30 * DAY; }
 | 
			
		||||
  // renewBy has a default in le-sni-auto
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ///////////////////////////
 | 
			
		||||
  // BEGIN VERSION MADNESS //
 | 
			
		||||
  ///////////////////////////
 | 
			
		||||
 | 
			
		||||
  if (!gl.version) {
 | 
			
		||||
    //console.warn("Please specify version: 'v01' (Let's Encrypt v1) or 'draft-12' (Let's Encrypt v2 / ACME draft 12)");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("==========================================================");
 | 
			
		||||
    console.warn("==                greenlock.js (v2.2.0+)                ==");
 | 
			
		||||
    console.warn("==========================================================");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("Please specify 'version' option:");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("        'draft-12' for Let's Encrypt v2 and ACME draft 12");
 | 
			
		||||
    console.warn("        ('v02' is an alias of 'draft-12'");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("or");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("        'v01' for Let's Encrypt v1 (deprecated)");
 | 
			
		||||
    console.warn("         (also 'npm install --save le-acme-core' as this legacy dependency will soon be removed)");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("This will be required in versions v2.3+");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
  } else if ('v02' === gl.version) {
 | 
			
		||||
    gl.version = 'draft-11';
 | 
			
		||||
  } else if ('draft-12' === gl.version) {
 | 
			
		||||
    gl.version = 'draft-11';
 | 
			
		||||
  } else if ('draft-11' === gl.version) {
 | 
			
		||||
    // no-op
 | 
			
		||||
  } else if ('v01' !== gl.version) {
 | 
			
		||||
    throw new Error("Unrecognized version '" + gl.version + "'");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!gl.server) {
 | 
			
		||||
    throw new Error("opts.server must specify an ACME directory URL, such as 'https://acme-staging-v02.api.letsencrypt.org/directory'");
 | 
			
		||||
  }
 | 
			
		||||
  if ('staging' === gl.server || 'production' === gl.server) {
 | 
			
		||||
    if ('staging' === gl.server) {
 | 
			
		||||
      gl.server = 'https://acme-staging.api.letsencrypt.org/directory';
 | 
			
		||||
      gl.version = 'v01';
 | 
			
		||||
      gl._deprecatedServerName = 'staging';
 | 
			
		||||
    }
 | 
			
		||||
    else if ('production' === gl.server) {
 | 
			
		||||
      gl.server = 'https://acme-v01.api.letsencrypt.org/directory';
 | 
			
		||||
      gl.version = 'v01';
 | 
			
		||||
      gl._deprecatedServerName = 'production';
 | 
			
		||||
    }
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("=== WARNING ===");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("Due to versioning issues the '" + gl._deprecatedServerName + "' option is deprecated.");
 | 
			
		||||
    console.warn("Please specify the full url and version.");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("For APIs add:");
 | 
			
		||||
    console.warn("\t, \"version\": \"" + gl.version + "\"");
 | 
			
		||||
    console.warn("\t, \"server\": \"" + gl.server + "\"");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("For the CLI add:");
 | 
			
		||||
    console.warn("\t--acme-url '" + gl.server + "' \\");
 | 
			
		||||
    console.warn("\t--acme-version '" + gl.version + "' \\");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function loadLeV01() {
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("=== WARNING ===");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    console.warn("Let's Encrypt v1 is deprecated.");
 | 
			
		||||
    console.warn("Please update to Let's Encrypt v2 (ACME draft 12)");
 | 
			
		||||
    console.warn("");
 | 
			
		||||
    try {
 | 
			
		||||
      return require('le-acme-core').ACME;
 | 
			
		||||
    } catch(e) {
 | 
			
		||||
      console.error("");
 | 
			
		||||
      console.error("=== Error (easy-to-fix) ===");
 | 
			
		||||
      console.error("");
 | 
			
		||||
      console.error("Hey, this isn't a big deal, but you need to manually add v1 support:");
 | 
			
		||||
      console.error("");
 | 
			
		||||
      console.error("        npm install --save le-acme-core");
 | 
			
		||||
      console.error("");
 | 
			
		||||
      console.error("Just run that real quick, restart, and everything will work great.");
 | 
			
		||||
      console.error("");
 | 
			
		||||
      console.error("");
 | 
			
		||||
      process.exit(e.code || 13);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (-1 !== [
 | 
			
		||||
      'https://acme-v02.api.letsencrypt.org/directory'
 | 
			
		||||
    , 'https://acme-staging-v02.api.letsencrypt.org/directory' ].indexOf(gl.server)
 | 
			
		||||
  ) {
 | 
			
		||||
    if ('draft-11' !== gl.version) {
 | 
			
		||||
      console.warn("Detected Let's Encrypt v02 URL. Changing version to draft-12.");
 | 
			
		||||
      gl.version = 'draft-11';
 | 
			
		||||
    }
 | 
			
		||||
  } else if (-1 !== [
 | 
			
		||||
      'https://acme-v01.api.letsencrypt.org/directory'
 | 
			
		||||
    , 'https://acme-staging.api.letsencrypt.org/directory' ].indexOf(gl.server)
 | 
			
		||||
    || 'v01' === gl.version
 | 
			
		||||
  ) {
 | 
			
		||||
    if ('v01' !== gl.version) {
 | 
			
		||||
      console.warn("Detected Let's Encrypt v01 URL (deprecated). Changing version to v01.");
 | 
			
		||||
      gl.version = 'v01';
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if ('v01' === gl.version) {
 | 
			
		||||
    ACME = loadLeV01();
 | 
			
		||||
  }
 | 
			
		||||
  /////////////////////////
 | 
			
		||||
  // END VERSION MADNESS //
 | 
			
		||||
  /////////////////////////
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  gl.acme = gl.acme || ACME.create({ debug: gl.debug });
 | 
			
		||||
  if (gl.acme.create) {
 | 
			
		||||
    gl.acme = gl.acme.create(gl);
 | 
			
		||||
  }
 | 
			
		||||
  gl.acme = promisifyAllSelf(gl.acme);
 | 
			
		||||
  gl._acmeOpts = gl.acme.getOptions();
 | 
			
		||||
  Object.keys(gl._acmeOpts).forEach(function (key) {
 | 
			
		||||
    if (!(key in gl)) {
 | 
			
		||||
      gl[key] = gl._acmeOpts[key];
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if (gl.store.create) {
 | 
			
		||||
    gl.store = gl.store.create(gl);
 | 
			
		||||
  }
 | 
			
		||||
  gl.store = promisifyAllSelf(gl.store);
 | 
			
		||||
  gl.store.accounts = promisifyAllSelf(gl.store.accounts);
 | 
			
		||||
  gl.store.certificates = promisifyAllSelf(gl.store.certificates);
 | 
			
		||||
  gl._storeOpts = gl.store.getOptions();
 | 
			
		||||
  Object.keys(gl._storeOpts).forEach(function (key) {
 | 
			
		||||
    if (!(key in gl)) {
 | 
			
		||||
      gl[key] = gl._storeOpts[key];
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Backwards compat for <= v2.1.7
 | 
			
		||||
  //
 | 
			
		||||
  if (gl.challenge) {
 | 
			
		||||
    console.warn("Deprecated use of gl.challenge. Use gl.challenges['" + Greenlock.challengeType + "'] instead.");
 | 
			
		||||
    gl.challenges[gl.challengeType] = gl.challenge;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Greenlock.challengeTypes.forEach(function (challengeType) {
 | 
			
		||||
    var challenger = gl.challenges[challengeType];
 | 
			
		||||
 | 
			
		||||
    if (!challenger) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (challenger.create) {
 | 
			
		||||
      challenger = gl.challenges[challengeType] = challenger.create(gl);
 | 
			
		||||
    }
 | 
			
		||||
    if (!challenger.getOptionsAsync) {
 | 
			
		||||
      challenger = gl.challenges[challengeType] = promisifyAllSelf(challenger);
 | 
			
		||||
    }
 | 
			
		||||
    gl['_challengeOpts_' + challengeType] = challenger.getOptions();
 | 
			
		||||
    Object.keys(gl['_challengeOpts_' + challengeType]).forEach(function (key) {
 | 
			
		||||
      if (!(key in gl)) {
 | 
			
		||||
        gl[key] = gl['_challengeOpts_' + challengeType][key];
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // TODO wrap these here and now with tplCopy?
 | 
			
		||||
    if (!challenger.set || 5 !== challenger.set.length) {
 | 
			
		||||
      throw new Error("gl.challenges[" + challengeType + "].set receives the wrong number of arguments."
 | 
			
		||||
        + " You must define setChallenge as function (opts, domain, token, keyAuthorization, cb) { }");
 | 
			
		||||
    }
 | 
			
		||||
    if (challenger.get && 4 !== challenger.get.length) {
 | 
			
		||||
      throw new Error("gl.challenges[" + challengeType + "].get receives the wrong number of arguments."
 | 
			
		||||
        + " You must define getChallenge as function (opts, domain, token, cb) { }");
 | 
			
		||||
    }
 | 
			
		||||
    if (!challenger.remove || 4 !== challenger.remove.length) {
 | 
			
		||||
      throw new Error("gl.challenges[" + challengeType + "].remove receives the wrong number of arguments."
 | 
			
		||||
        + " You must define removeChallenge as function (opts, domain, token, cb) { }");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    if (!gl._challengeWarn && (!challenger.loopback || 4 !== challenger.loopback.length)) {
 | 
			
		||||
      gl._challengeWarn = true;
 | 
			
		||||
      console.warn("gl.challenges[" + challengeType + "].loopback should be defined as function (opts, domain, token, cb) { ... } and should prove (by external means) that the ACME server challenge '" + challengeType + "' will succeed");
 | 
			
		||||
    }
 | 
			
		||||
    else if (!gl._challengeWarn && (!challenger.test || 5 !== challenger.test.length)) {
 | 
			
		||||
      gl._challengeWarn = true;
 | 
			
		||||
      console.warn("gl.challenges[" + challengeType + "].test should be defined as function (opts, domain, token, keyAuthorization, cb) { ... } and should prove (by external means) that the ACME server challenge '" + challengeType + "' will succeed");
 | 
			
		||||
    }
 | 
			
		||||
*/
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  gl.sni = gl.sni || null;
 | 
			
		||||
  gl.tlsOptions = gl.tlsOptions || gl.httpsOptions || {};
 | 
			
		||||
 | 
			
		||||
  // Workaround for https://github.com/nodejs/node/issues/22389
 | 
			
		||||
  gl._updateServernames = function (cert) {
 | 
			
		||||
    if (!gl._certnames) { gl._certnames = {}; }
 | 
			
		||||
 | 
			
		||||
    // Note: Any given domain could exist on multiple certs
 | 
			
		||||
    // (especially during renewal where some may be added)
 | 
			
		||||
    // hence we use a separate object for each domain and list each domain on it
 | 
			
		||||
    // to get the minimal full set associated with each cert and domain
 | 
			
		||||
    var allDomains = [cert.subject].concat(cert.altnames.slice(0));
 | 
			
		||||
    allDomains.forEach(function (name) {
 | 
			
		||||
      name = name.toLowerCase();
 | 
			
		||||
      if (!gl._certnames[name]) {
 | 
			
		||||
        gl._certnames[name] = {};
 | 
			
		||||
      }
 | 
			
		||||
      allDomains.forEach(function (name2) {
 | 
			
		||||
        name2 = name2.toLowerCase();
 | 
			
		||||
        gl._certnames[name][name2] = true;
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
  gl._checkServername = function (safeHost, servername) {
 | 
			
		||||
    // odd, but acceptable
 | 
			
		||||
    if (!safeHost || !servername) { return true; }
 | 
			
		||||
    if (safeHost === servername) { return true; }
 | 
			
		||||
    // connection established with servername and session is re-used for allowed name
 | 
			
		||||
    if (gl._certnames[servername] && gl._certnames[servername][safeHost]) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (!gl.tlsOptions.SNICallback) {
 | 
			
		||||
    if (!gl.getCertificatesAsync && !gl.getCertificates) {
 | 
			
		||||
      if (Array.isArray(gl.approveDomains)) {
 | 
			
		||||
        gl.approvedDomains = gl.approveDomains;
 | 
			
		||||
        gl.approveDomains = null;
 | 
			
		||||
      }
 | 
			
		||||
      if (!gl.approveDomains) {
 | 
			
		||||
        gl.approvedDomains = gl.approvedDomains || [];
 | 
			
		||||
        gl.approveDomains = function (lexOpts, certs, cb) {
 | 
			
		||||
          var err;
 | 
			
		||||
          var emsg;
 | 
			
		||||
 | 
			
		||||
          if (!gl.email) {
 | 
			
		||||
            throw new Error("le-sni-auto is not properly configured. Missing email");
 | 
			
		||||
          }
 | 
			
		||||
          if (!gl.agreeTos) {
 | 
			
		||||
            throw new Error("le-sni-auto is not properly configured. Missing agreeTos");
 | 
			
		||||
          }
 | 
			
		||||
          if (!gl.approvedDomains.length) {
 | 
			
		||||
            throw new Error("le-sni-auto is not properly configured. Missing approveDomains(domain, certs, callback)");
 | 
			
		||||
          }
 | 
			
		||||
          if (lexOpts.domains.every(function (domain) {
 | 
			
		||||
            return -1 !== gl.approvedDomains.indexOf(domain);
 | 
			
		||||
          })) {
 | 
			
		||||
            lexOpts.domains = gl.approvedDomains.slice(0);
 | 
			
		||||
            lexOpts.email = gl.email;
 | 
			
		||||
            lexOpts.agreeTos = gl.agreeTos;
 | 
			
		||||
            lexOpts.communityMember = gl.communityMember;
 | 
			
		||||
            lexOpts.telemetry = gl.telemetry;
 | 
			
		||||
            return cb(null, { options: lexOpts, certs: certs });
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          emsg = "tls SNI for '" + lexOpts.domains.join(',') + "' rejected: not in list '" + gl.approvedDomains + "'";
 | 
			
		||||
          log(gl.debug, emsg, lexOpts.domains, gl.approvedDomains);
 | 
			
		||||
          err = new Error(emsg);
 | 
			
		||||
          err.code = 'E_REJECT_SNI';
 | 
			
		||||
          cb(err);
 | 
			
		||||
        };
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      gl.getCertificates = function (domain, certs, cb) {
 | 
			
		||||
        // certs come from current in-memory cache, not lookup
 | 
			
		||||
        log(gl.debug, 'gl.getCertificates called for', domain, 'with certs for', certs && certs.altnames || 'NONE');
 | 
			
		||||
        var opts = { domain: domain, domains: certs && certs.altnames || [ domain ] };
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
          gl.approveDomains(opts, certs, function (_err, results) {
 | 
			
		||||
            if (_err) {
 | 
			
		||||
              if (false !== gl.logRejectedDomains) {
 | 
			
		||||
                console.error("[Error] approveDomains rejected tls sni '" + domain + "'");
 | 
			
		||||
                console.error("[Error] (see https://git.coolaj86.com/coolaj86/greenlock.js/issues/11)");
 | 
			
		||||
                if ('E_REJECT_SNI' !== _err.code) {
 | 
			
		||||
                  console.error("[Error] This is the rejection message:");
 | 
			
		||||
                  console.error(_err.message);
 | 
			
		||||
                }
 | 
			
		||||
                console.error("");
 | 
			
		||||
              }
 | 
			
		||||
              cb(_err);
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            log(gl.debug, 'gl.approveDomains called with certs for', results.certs && results.certs.altnames || 'NONE', 'and options:');
 | 
			
		||||
            log(gl.debug, results.options);
 | 
			
		||||
 | 
			
		||||
            if (results.certs) {
 | 
			
		||||
              log(gl.debug, 'gl renewing');
 | 
			
		||||
              return gl.core.certificates.renewAsync(results.options, results.certs).then(
 | 
			
		||||
                function (certs) {
 | 
			
		||||
                  // Workaround for https://github.com/nodejs/node/issues/22389
 | 
			
		||||
                  gl._updateServernames(certs);
 | 
			
		||||
                  cb(null, certs);
 | 
			
		||||
                }
 | 
			
		||||
              , function (e) {
 | 
			
		||||
                  console.debug("Error renewing certificate for '" + domain + "':");
 | 
			
		||||
                  console.debug(e);
 | 
			
		||||
                  console.error("");
 | 
			
		||||
                  cb(e);
 | 
			
		||||
                }
 | 
			
		||||
              );
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
              log(gl.debug, 'gl getting from disk or registering new');
 | 
			
		||||
              return gl.core.certificates.getAsync(results.options).then(
 | 
			
		||||
                function (certs) {
 | 
			
		||||
                  // Workaround for https://github.com/nodejs/node/issues/22389
 | 
			
		||||
                  gl._updateServernames(certs);
 | 
			
		||||
                  cb(null, certs);
 | 
			
		||||
                }
 | 
			
		||||
              , function (e) {
 | 
			
		||||
                  console.debug("Error loading/registering certificate for '" + domain + "':");
 | 
			
		||||
                  console.debug(e);
 | 
			
		||||
                  console.error("");
 | 
			
		||||
                  cb(e);
 | 
			
		||||
                }
 | 
			
		||||
              );
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
          console.error("[ERROR] Something went wrong in approveDomains:");
 | 
			
		||||
          console.error(e);
 | 
			
		||||
          console.error("BUT WAIT! Good news: It's probably your fault, so you can probably fix it.");
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
    gl.sni = gl.sni || require('le-sni-auto');
 | 
			
		||||
    if (gl.sni.create) {
 | 
			
		||||
      gl.sni = gl.sni.create(gl);
 | 
			
		||||
    }
 | 
			
		||||
    gl.tlsOptions.SNICallback = function (_domain, cb) {
 | 
			
		||||
      // format and (lightly) sanitize sni so that users can be naive
 | 
			
		||||
      // and not have to worry about SQL injection or fs discovery
 | 
			
		||||
      var domain = (_domain||'').toLowerCase();
 | 
			
		||||
      // hostname labels allow a-z, 0-9, -, and are separated by dots
 | 
			
		||||
      // _ is sometimes allowed
 | 
			
		||||
      // REGEX // https://www.codeproject.com/Questions/1063023/alphanumeric-validation-javascript-without-regex
 | 
			
		||||
      if (!gl.__sni_allow_dangerous_names && (!/^[a-z0-9_\.\-]+$/i.test(domain) || -1 !== domain.indexOf('..'))) {
 | 
			
		||||
        log(gl.debug, "invalid sni '" + domain + "'");
 | 
			
		||||
        cb(new Error("invalid SNI"));
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        gl.sni.sniCallback(gl.__sni_preserve_case && _domain || domain, cb);
 | 
			
		||||
      } catch(e) {
 | 
			
		||||
        console.error("[ERROR] Something went wrong in the SNICallback:");
 | 
			
		||||
        console.error(e);
 | 
			
		||||
        cb(e);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // We want to move to using tlsOptions instead of httpsOptions, but we also need to make
 | 
			
		||||
  // sure anything that uses this object will still work if looking for httpsOptions.
 | 
			
		||||
  gl.httpsOptions = gl.tlsOptions;
 | 
			
		||||
 | 
			
		||||
  if (gl.core.create) {
 | 
			
		||||
    gl.core = gl.core.create(gl);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  gl.renew = function (args, certs) {
 | 
			
		||||
    return gl.core.certificates.renewAsync(args, certs);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  gl.register = function (args) {
 | 
			
		||||
    return gl.core.certificates.getAsync(args);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  gl.check = function (args) {
 | 
			
		||||
    // TODO must return email, domains, tos, pems
 | 
			
		||||
    return gl.core.certificates.checkAsync(args);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  gl.middleware = gl.middleware || require('./lib/middleware');
 | 
			
		||||
  if (gl.middleware.create) {
 | 
			
		||||
    gl.middleware = gl.middleware.create(gl);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //var SERVERNAME_RE = /^[a-z0-9\.\-_]+$/;
 | 
			
		||||
  var SERVERNAME_G = /[^a-z0-9\.\-_]/;
 | 
			
		||||
  gl.middleware.sanitizeHost = function (app) {
 | 
			
		||||
    return function (req, res, next) {
 | 
			
		||||
      function realNext() {
 | 
			
		||||
        if ('function' === typeof app) {
 | 
			
		||||
          app(req, res);
 | 
			
		||||
        } else if ('function' === typeof next) {
 | 
			
		||||
          next();
 | 
			
		||||
        } else {
 | 
			
		||||
          res.statusCode = 500;
 | 
			
		||||
          res.end("Error: no middleware assigned");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      // Get the host:port combo, if it exists
 | 
			
		||||
      var host = (req.headers.host||'').split(':');
 | 
			
		||||
 | 
			
		||||
      // if not, move along
 | 
			
		||||
      if (!host[0]) { realNext(); return; }
 | 
			
		||||
 | 
			
		||||
      // if so, remove non-allowed characters
 | 
			
		||||
      var safehost = host[0].toLowerCase().replace(SERVERNAME_G, '');
 | 
			
		||||
 | 
			
		||||
      // if there were unallowed characters, complain
 | 
			
		||||
      if (!gl.__sni_allow_dangerous_names && safehost.length !== host[0].length) {
 | 
			
		||||
        res.statusCode = 400;
 | 
			
		||||
        res.end("Malformed HTTP Header: 'Host: " + host[0] + "'");
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // make lowercase
 | 
			
		||||
      if (!gl.__sni_preserve_case) {
 | 
			
		||||
        host[0] = safehost;
 | 
			
		||||
        req.headers.host = host.join(':');
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Note: This sanitize function is also called on plain sockets, which don't need Domain Fronting checks
 | 
			
		||||
      if (req.socket.encrypted && !gl.__sni_allow_domain_fronting) {
 | 
			
		||||
        if (req.socket && 'string' === typeof req.socket.servername) {
 | 
			
		||||
          // Workaround for https://github.com/nodejs/node/issues/22389
 | 
			
		||||
          if (!gl._checkServername(safehost, req.socket.servername.toLowerCase())) {
 | 
			
		||||
            res.statusCode = 400;
 | 
			
		||||
            res.setHeader('Content-Type', 'text/html; charset=utf-8');
 | 
			
		||||
            res.end(
 | 
			
		||||
                "<h1>Domain Fronting Error</h1>"
 | 
			
		||||
              + "<p>This connection was secured using TLS/SSL for '" + req.socket.servername.toLowerCase() + "'</p>"
 | 
			
		||||
              + "<p>The HTTP request specified 'Host: " + safehost + "', which is (obviously) different.</p>"
 | 
			
		||||
              + "<p>Because this looks like a domain fronting attack, the connection has been terminated.</p>"
 | 
			
		||||
            );
 | 
			
		||||
            return;
 | 
			
		||||
          }
 | 
			
		||||
        } else if (safehost && !gl.middleware.sanitizeHost._skip_fronting_check) {
 | 
			
		||||
          // TODO how to handle wrapped sockets, as with telebit?
 | 
			
		||||
          console.warn("\n\n\n[greenlock] WARN: no string for req.socket.servername,"
 | 
			
		||||
            + " skipping fronting check for '" + safehost + "'\n\n\n");
 | 
			
		||||
          gl.middleware.sanitizeHost._skip_fronting_check = true;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // carry on
 | 
			
		||||
      realNext();
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
  gl.middleware.sanitizeHost._skip_fronting_check = false;
 | 
			
		||||
 | 
			
		||||
  return gl;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										51
									
								
								express-server/node_modules/greenlock/lib/community.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								express-server/node_modules/greenlock/lib/community.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
function addCommunityMember(opts) {
 | 
			
		||||
  // { name, version, email, domains, action, communityMember, telemetry }
 | 
			
		||||
  setTimeout(function () {
 | 
			
		||||
    var https = require('https');
 | 
			
		||||
    var req = https.request({
 | 
			
		||||
      hostname: 'api.ppl.family'
 | 
			
		||||
    , port: 443
 | 
			
		||||
    , path: '/api/ppl.family/public/list'
 | 
			
		||||
    , method: 'POST'
 | 
			
		||||
    , headers: {
 | 
			
		||||
        'Content-Type': 'application/json'
 | 
			
		||||
      }
 | 
			
		||||
    }, function (err, resp) {
 | 
			
		||||
      if (err) { return; }
 | 
			
		||||
      resp.on('data', function () {});
 | 
			
		||||
    });
 | 
			
		||||
    var os = require('os');
 | 
			
		||||
    var data = {
 | 
			
		||||
      address: opts.email
 | 
			
		||||
      // greenlock-security is transactional and security only
 | 
			
		||||
    , list: opts.communityMember ? (opts.name + '@ppl.family') : 'greenlock-security@ppl.family'
 | 
			
		||||
    , action: opts.action // reg | renew
 | 
			
		||||
    , package: opts.name
 | 
			
		||||
      // hashed for privacy, but so we can still get some telemetry and inform users
 | 
			
		||||
      // if abnormal things are happening (like several registrations for the same domain each day)
 | 
			
		||||
    , domain: (opts.domains||[]).map(function (d) {
 | 
			
		||||
        return require('crypto').createHash('sha1').update(d).digest('base64')
 | 
			
		||||
          .replace(/\//g, '_').replace(/\+/g, '-').replace(/=/g, '');
 | 
			
		||||
      }).join(',')
 | 
			
		||||
    };
 | 
			
		||||
    if (false !== opts.telemetry) {
 | 
			
		||||
      data.arch = process.arch || os.arch();
 | 
			
		||||
      data.platform = process.platform || os.platform();
 | 
			
		||||
      data.release = os.release();
 | 
			
		||||
      data.version = opts.version;
 | 
			
		||||
      data.node = process.version;
 | 
			
		||||
    }
 | 
			
		||||
    req.write(JSON.stringify(data, 2, null));
 | 
			
		||||
    req.end();
 | 
			
		||||
  }, 50);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports.add = addCommunityMember;
 | 
			
		||||
 | 
			
		||||
if (require.main === module) {
 | 
			
		||||
  //addCommunityMember('greenlock-express.js', 'reg', 'coolaj86+test42@gmail.com', ['coolaj86.com'], true);
 | 
			
		||||
  //addCommunityMember('greenlock.js', 'reg', 'coolaj86+test37@gmail.com', ['oneal.im'], false);
 | 
			
		||||
  //addCommunityMember('greenlock.js', 'reg', 'coolaj86+test11@gmail.com', ['ppl.family'], true);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										459
									
								
								express-server/node_modules/greenlock/lib/core.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										459
									
								
								express-server/node_modules/greenlock/lib/core.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,459 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var PromiseA;
 | 
			
		||||
try {
 | 
			
		||||
  PromiseA = require('bluebird');
 | 
			
		||||
} catch(e) {
 | 
			
		||||
  PromiseA = global.Promise;
 | 
			
		||||
}
 | 
			
		||||
var util = require('util');
 | 
			
		||||
function promisifyAll(obj) {
 | 
			
		||||
  var aobj = {};
 | 
			
		||||
  Object.keys(obj).forEach(function (key) {
 | 
			
		||||
    if ('function' === typeof obj[key]) {
 | 
			
		||||
      aobj[key] = obj[key];
 | 
			
		||||
      aobj[key + 'Async'] = util.promisify(obj[key]);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  return aobj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _log(debug) {
 | 
			
		||||
  if (debug) {
 | 
			
		||||
    var args = Array.prototype.slice.call(arguments);
 | 
			
		||||
    args.shift();
 | 
			
		||||
    args.unshift("[greenlock/lib/core.js]");
 | 
			
		||||
    console.log.apply(console, args);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports.create = function (gl) {
 | 
			
		||||
  var utils = require('./utils');
 | 
			
		||||
  var RSA = promisifyAll(require('rsa-compat').RSA);
 | 
			
		||||
  var log = gl.log || _log; // allow custom log
 | 
			
		||||
  var pendingRegistrations = {};
 | 
			
		||||
 | 
			
		||||
  var core = {
 | 
			
		||||
    //
 | 
			
		||||
    // Helpers
 | 
			
		||||
    //
 | 
			
		||||
    getAcmeUrlsAsync: function (args) {
 | 
			
		||||
      var now = Date.now();
 | 
			
		||||
 | 
			
		||||
      // TODO check response header on request for cache time
 | 
			
		||||
      if ((now - gl._ipc.acmeUrlsUpdatedAt) < 10 * 60 * 1000) {
 | 
			
		||||
        return PromiseA.resolve(gl._ipc.acmeUrls);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return gl.acme.getAcmeUrlsAsync(args.server).then(function (data) {
 | 
			
		||||
        gl._ipc.acmeUrlsUpdatedAt = Date.now();
 | 
			
		||||
        gl._ipc.acmeUrls = data;
 | 
			
		||||
 | 
			
		||||
        return gl._ipc.acmeUrls;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // The Main Enchilada
 | 
			
		||||
    //
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // Accounts
 | 
			
		||||
    //
 | 
			
		||||
  , accounts: {
 | 
			
		||||
      // Accounts
 | 
			
		||||
      registerAsync: function (args) {
 | 
			
		||||
        var err;
 | 
			
		||||
        var copy = utils.merge(args, gl);
 | 
			
		||||
        var disagreeTos;
 | 
			
		||||
        args = utils.tplCopy(copy);
 | 
			
		||||
 | 
			
		||||
        disagreeTos = (!args.agreeTos && 'undefined' !== typeof args.agreeTos);
 | 
			
		||||
        if (!args.email || disagreeTos || (parseInt(args.rsaKeySize, 10) < 2048)) {
 | 
			
		||||
          err = new Error(
 | 
			
		||||
            "In order to register an account both 'email' and 'agreeTos' must be present"
 | 
			
		||||
              + " and 'rsaKeySize' must be 2048 or greater."
 | 
			
		||||
          );
 | 
			
		||||
          err.code = 'E_ARGS';
 | 
			
		||||
          return PromiseA.reject(err);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return utils.testEmail(args.email).then(function () {
 | 
			
		||||
          var promise = gl.store.accounts.checkKeypairAsync(args).then(function (keypair) {
 | 
			
		||||
            if (keypair) {
 | 
			
		||||
              return RSA.import(keypair);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (args.accountKeypair) {
 | 
			
		||||
              return gl.store.accounts.setKeypairAsync(args, RSA.import(args.accountKeypair));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var keypairOpts = { bitlen: args.rsaKeySize, exp: 65537, public: true, pem: true };
 | 
			
		||||
            return RSA.generateKeypairAsync(keypairOpts).then(function (keypair) {
 | 
			
		||||
              keypair.privateKeyPem = RSA.exportPrivatePem(keypair);
 | 
			
		||||
              keypair.publicKeyPem = RSA.exportPublicPem(keypair);
 | 
			
		||||
              keypair.privateKeyJwk = RSA.exportPrivateJwk(keypair);
 | 
			
		||||
              return gl.store.accounts.setKeypairAsync(args, keypair);
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          return promise.then(function (keypair) {
 | 
			
		||||
            // Note: the ACME urls are always fetched fresh on purpose
 | 
			
		||||
            // TODO is this the right place for this?
 | 
			
		||||
            return core.getAcmeUrlsAsync(args).then(function (urls) {
 | 
			
		||||
              args._acmeUrls = urls;
 | 
			
		||||
 | 
			
		||||
              return gl.acme.registerNewAccountAsync({
 | 
			
		||||
                email: args.email
 | 
			
		||||
              , newRegUrl: args._acmeUrls.newReg
 | 
			
		||||
              , newAuthzUrl: args._acmeUrls.newAuthz
 | 
			
		||||
              , agreeToTerms: function (tosUrl, agreeCb) {
 | 
			
		||||
                  if (true === args.agreeTos || tosUrl === args.agreeTos || tosUrl === gl.agreeToTerms) {
 | 
			
		||||
                    agreeCb(null, tosUrl);
 | 
			
		||||
                    return;
 | 
			
		||||
                  }
 | 
			
		||||
 | 
			
		||||
                  // args.email = email;      // already there
 | 
			
		||||
                  // args.domains = domains   // already there
 | 
			
		||||
                  args.tosUrl = tosUrl;
 | 
			
		||||
                  gl.agreeToTerms(args, agreeCb);
 | 
			
		||||
                }
 | 
			
		||||
              , accountKeypair: keypair
 | 
			
		||||
 | 
			
		||||
              , debug: gl.debug || args.debug
 | 
			
		||||
              }).then(function (receipt) {
 | 
			
		||||
                var reg = {
 | 
			
		||||
                  keypair: keypair
 | 
			
		||||
                , receipt: receipt
 | 
			
		||||
                , email: args.email
 | 
			
		||||
                , newRegUrl: args._acmeUrls.newReg
 | 
			
		||||
                , newAuthzUrl: args._acmeUrls.newAuthz
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                // TODO move templating of arguments to right here?
 | 
			
		||||
                return gl.store.accounts.setAsync(args, reg).then(function (account) {
 | 
			
		||||
                  // should now have account.id and account.accountId
 | 
			
		||||
                  args.account = account;
 | 
			
		||||
                  args.accountId = account.id;
 | 
			
		||||
                  return account;
 | 
			
		||||
                });
 | 
			
		||||
              });
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Accounts
 | 
			
		||||
    , getAsync: function (args) {
 | 
			
		||||
        return core.accounts.checkAsync(args).then(function (account) {
 | 
			
		||||
          if (account) {
 | 
			
		||||
            return account;
 | 
			
		||||
          } else {
 | 
			
		||||
            return core.accounts.registerAsync(args);
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Accounts
 | 
			
		||||
    , checkAsync: function (args) {
 | 
			
		||||
        var requiredArgs = ['accountId', 'email', 'domains', 'domain'];
 | 
			
		||||
        if (!requiredArgs.some(function (key) { return -1 !== Object.keys(args).indexOf(key); })) {
 | 
			
		||||
          return PromiseA.reject(new Error(
 | 
			
		||||
            "In order to register or retrieve an account one of '" + requiredArgs.join("', '") + "' must be present"
 | 
			
		||||
          ));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var copy = utils.merge(args, gl);
 | 
			
		||||
        args = utils.tplCopy(copy);
 | 
			
		||||
 | 
			
		||||
        return gl.store.accounts.checkAsync(args).then(function (account) {
 | 
			
		||||
 | 
			
		||||
          if (!account) {
 | 
			
		||||
            return null;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          args.account = account;
 | 
			
		||||
          args.accountId = account.id;
 | 
			
		||||
 | 
			
		||||
          return account;
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  , certificates: {
 | 
			
		||||
      // Certificates
 | 
			
		||||
      registerAsync: function (args) {
 | 
			
		||||
        var err;
 | 
			
		||||
        var challengeDefaults = gl['_challengeOpts_' + (args.challengeType || gl.challengeType)] || {};
 | 
			
		||||
        var copy = utils.merge(args, challengeDefaults || {});
 | 
			
		||||
        copy = utils.merge(copy, gl);
 | 
			
		||||
        args = utils.tplCopy(copy);
 | 
			
		||||
 | 
			
		||||
        if (!Array.isArray(args.domains)) {
 | 
			
		||||
          return PromiseA.reject(new Error('args.domains should be an array of domains'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!(args.domains.length && args.domains.every(utils.isValidDomain))) {
 | 
			
		||||
          // NOTE: this library can't assume to handle the http loopback
 | 
			
		||||
          // (or dns-01 validation may be used)
 | 
			
		||||
          // so we do not check dns records or attempt a loopback here
 | 
			
		||||
          err = new Error("invalid domain name(s): '" + args.domains + "'");
 | 
			
		||||
          err.code = "INVALID_DOMAIN";
 | 
			
		||||
          return PromiseA.reject(err);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If a previous request to (re)register a certificate is already underway we need
 | 
			
		||||
        // to return the same promise created before rather than registering things twice.
 | 
			
		||||
        // I'm not 100% sure how to properly handle the case where someone registers domain
 | 
			
		||||
        // lists with some but not all elements common, nor am I sure that's even a case that
 | 
			
		||||
        // is allowed to happen anyway. But for now we act like the list is completely the
 | 
			
		||||
        // same if any elements are the same.
 | 
			
		||||
        var promise;
 | 
			
		||||
        args.domains.some(function (name) {
 | 
			
		||||
          if (pendingRegistrations.hasOwnProperty(name)) {
 | 
			
		||||
            promise = pendingRegistrations[name];
 | 
			
		||||
            return true;
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
        if (promise) {
 | 
			
		||||
          return promise;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        promise = core.certificates._runRegistration(args);
 | 
			
		||||
 | 
			
		||||
        // Now that the registration is actually underway we need to make sure any subsequent
 | 
			
		||||
        // registration attempts return the same promise until it is completed (but not after
 | 
			
		||||
        // it is completed).
 | 
			
		||||
        args.domains.forEach(function (name) {
 | 
			
		||||
          pendingRegistrations[name] = promise;
 | 
			
		||||
        });
 | 
			
		||||
        function clearPending() {
 | 
			
		||||
          args.domains.forEach(function (name) {
 | 
			
		||||
            delete pendingRegistrations[name];
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
        promise.then(clearPending, clearPending);
 | 
			
		||||
 | 
			
		||||
        return promise;
 | 
			
		||||
      }
 | 
			
		||||
    , _runRegistration: function (args) {
 | 
			
		||||
        // TODO renewal cb
 | 
			
		||||
        // accountId and or email
 | 
			
		||||
        return core.accounts.getAsync(args).then(function (account) {
 | 
			
		||||
          args.account = account;
 | 
			
		||||
 | 
			
		||||
          var promise = gl.store.certificates.checkKeypairAsync(args).then(function (keypair) {
 | 
			
		||||
            if (keypair) {
 | 
			
		||||
              return RSA.import(keypair);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (args.domainKeypair) {
 | 
			
		||||
              return gl.store.certificates.setKeypairAsync(args, RSA.import(args.domainKeypair));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var keypairOpts = { bitlen: args.rsaKeySize, exp: 65537, public: true, pem: true };
 | 
			
		||||
            return RSA.generateKeypairAsync(keypairOpts).then(function (keypair) {
 | 
			
		||||
              keypair.privateKeyPem = RSA.exportPrivatePem(keypair);
 | 
			
		||||
              keypair.publicKeyPem = RSA.exportPublicPem(keypair);
 | 
			
		||||
              keypair.privateKeyJwk = RSA.exportPrivateJwk(keypair);
 | 
			
		||||
              return gl.store.certificates.setKeypairAsync(args, keypair);
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          return promise.then(function (domainKeypair) {
 | 
			
		||||
            args.domainKeypair = domainKeypair;
 | 
			
		||||
            //args.registration = domainKey;
 | 
			
		||||
 | 
			
		||||
            // Note: the ACME urls are always fetched fresh on purpose
 | 
			
		||||
            // TODO is this the right place for this?
 | 
			
		||||
            return core.getAcmeUrlsAsync(args).then(function (urls) {
 | 
			
		||||
              args._acmeUrls = urls;
 | 
			
		||||
 | 
			
		||||
              var certReq = {
 | 
			
		||||
                debug: args.debug || gl.debug
 | 
			
		||||
 | 
			
		||||
              , newAuthzUrl: args._acmeUrls.newAuthz
 | 
			
		||||
              , newCertUrl: args._acmeUrls.newCert
 | 
			
		||||
 | 
			
		||||
              , accountKeypair: RSA.import(account.keypair)
 | 
			
		||||
              , domainKeypair: domainKeypair
 | 
			
		||||
              , domains: args.domains
 | 
			
		||||
              , challengeType: args.challengeType
 | 
			
		||||
              };
 | 
			
		||||
 | 
			
		||||
              //
 | 
			
		||||
              // IMPORTANT
 | 
			
		||||
              //
 | 
			
		||||
              // setChallenge and removeChallenge are handed defaults
 | 
			
		||||
              // instead of args because getChallenge does not have
 | 
			
		||||
              // access to args
 | 
			
		||||
              // (args is per-request, defaults is per instance)
 | 
			
		||||
              //
 | 
			
		||||
              // Each of these fires individually for each domain,
 | 
			
		||||
              // even though the certificate on the whole may have many domains
 | 
			
		||||
              //
 | 
			
		||||
              certReq.setChallenge = function (domain, key, value, done) {
 | 
			
		||||
                log(args.debug, "setChallenge called for '" + domain + "'");
 | 
			
		||||
                var copy = utils.merge({ domains: [domain] }, args);
 | 
			
		||||
                copy = utils.merge(copy, gl);
 | 
			
		||||
                utils.tplCopy(copy);
 | 
			
		||||
 | 
			
		||||
                // TODO need to save challengeType
 | 
			
		||||
                gl.challenges[args.challengeType].set(copy, domain, key, value, done);
 | 
			
		||||
              };
 | 
			
		||||
              certReq.removeChallenge = function (domain, key, done) {
 | 
			
		||||
                log(args.debug, "removeChallenge called for '" + domain + "'");
 | 
			
		||||
                var copy = utils.merge({ domains: [domain] }, gl);
 | 
			
		||||
                utils.tplCopy(copy);
 | 
			
		||||
 | 
			
		||||
                gl.challenges[args.challengeType].remove(copy, domain, key, done);
 | 
			
		||||
              };
 | 
			
		||||
 | 
			
		||||
              log(args.debug, 'calling greenlock.acme.getCertificateAsync', certReq.domains);
 | 
			
		||||
 | 
			
		||||
              return gl.acme.getCertificateAsync(certReq).then(utils.attachCertInfo);
 | 
			
		||||
            });
 | 
			
		||||
          }).then(function (results) {
 | 
			
		||||
            // { cert, chain, privkey /*TODO, subject, altnames, issuedAt, expiresAt */ }
 | 
			
		||||
 | 
			
		||||
            // args.certs.privkey = RSA.exportPrivatePem(options.domainKeypair);
 | 
			
		||||
            args.certs = results;
 | 
			
		||||
            // args.pems is deprecated
 | 
			
		||||
            args.pems = results;
 | 
			
		||||
            return gl.store.certificates.setAsync(args).then(function () {
 | 
			
		||||
              return results;
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      // Certificates
 | 
			
		||||
    , renewAsync: function (args, certs) {
 | 
			
		||||
        var renewableAt = core.certificates._getRenewableAt(args, certs);
 | 
			
		||||
        var err;
 | 
			
		||||
        //var halfLife = (certs.expiresAt - certs.issuedAt) / 2;
 | 
			
		||||
        //var renewable = (Date.now() - certs.issuedAt) > halfLife;
 | 
			
		||||
 | 
			
		||||
        log(args.debug, "(Renew) Expires At", new Date(certs.expiresAt).toISOString());
 | 
			
		||||
        log(args.debug, "(Renew) Renewable At", new Date(renewableAt).toISOString());
 | 
			
		||||
 | 
			
		||||
        if (!args.duplicate && Date.now() < renewableAt) {
 | 
			
		||||
          err = new Error(
 | 
			
		||||
              "[ERROR] Certificate issued at '"
 | 
			
		||||
            + new Date(certs.issuedAt).toISOString() + "' and expires at '"
 | 
			
		||||
            + new Date(certs.expiresAt).toISOString() + "'. Ignoring renewal attempt until '"
 | 
			
		||||
            + new Date(renewableAt).toISOString() + "'. Set { duplicate: true } to force."
 | 
			
		||||
          );
 | 
			
		||||
          err.code = 'E_NOT_RENEWABLE';
 | 
			
		||||
          return PromiseA.reject(err);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Either the cert has entered its renewal period
 | 
			
		||||
        // or we're forcing a refresh via 'dupliate: true'
 | 
			
		||||
        log(args.debug, "Renewing!");
 | 
			
		||||
 | 
			
		||||
        if (!args.domains || !args.domains.length) {
 | 
			
		||||
          args.domains = args.servernames || [certs.subject].concat(certs.altnames);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return core.certificates.registerAsync(args);
 | 
			
		||||
      }
 | 
			
		||||
      // Certificates
 | 
			
		||||
    , _isRenewable: function (args, certs) {
 | 
			
		||||
        var renewableAt = core.certificates._getRenewableAt(args, certs);
 | 
			
		||||
 | 
			
		||||
        log(args.debug, "Check Expires At", new Date(certs.expiresAt).toISOString());
 | 
			
		||||
        log(args.debug, "Check Renewable At", new Date(renewableAt).toISOString());
 | 
			
		||||
 | 
			
		||||
        if (args.duplicate || Date.now() >= renewableAt) {
 | 
			
		||||
          log(args.debug, "certificates are renewable");
 | 
			
		||||
          return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
    , _getRenewableAt: function (args, certs) {
 | 
			
		||||
        return certs.expiresAt - (args.renewWithin || gl.renewWithin);
 | 
			
		||||
      }
 | 
			
		||||
    , checkAsync: function (args) {
 | 
			
		||||
        var copy = utils.merge(args, gl);
 | 
			
		||||
        utils.tplCopy(copy);
 | 
			
		||||
 | 
			
		||||
        // returns pems
 | 
			
		||||
        return gl.store.certificates.checkAsync(copy).then(function (cert) {
 | 
			
		||||
          if (cert) {
 | 
			
		||||
            log(args.debug, 'checkAsync found existing certificates');
 | 
			
		||||
            return utils.attachCertInfo(cert);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          log(args.debug, 'checkAsync failed to find certificates');
 | 
			
		||||
          return null;
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      // Certificates
 | 
			
		||||
    , getAsync: function (args) {
 | 
			
		||||
        var copy = utils.merge(args, gl);
 | 
			
		||||
        args = utils.tplCopy(copy);
 | 
			
		||||
 | 
			
		||||
        return core.certificates.checkAsync(args).then(function (certs) {
 | 
			
		||||
          if (!certs) {
 | 
			
		||||
            // There is no cert available
 | 
			
		||||
            if (false !== args.securityUpdates && !args._communityMemberAdded) {
 | 
			
		||||
              try {
 | 
			
		||||
                // We will notify all greenlock users of mandatory and security updates
 | 
			
		||||
                // We'll keep track of versions and os so we can make sure things work well
 | 
			
		||||
                // { name, version, email, domains, action, communityMember, telemetry }
 | 
			
		||||
                require('./community').add({
 | 
			
		||||
                  name: args._communityPackage
 | 
			
		||||
                , version: args._communityPackageVersion
 | 
			
		||||
                , email: args.email
 | 
			
		||||
                , domains: args.domains || args.servernames
 | 
			
		||||
                , action: 'reg'
 | 
			
		||||
                , communityMember: args.communityMember
 | 
			
		||||
                , telemetry: args.telemetry
 | 
			
		||||
                });
 | 
			
		||||
              } catch(e) { /* ignore */ }
 | 
			
		||||
              args._communityMemberAdded = true;
 | 
			
		||||
            }
 | 
			
		||||
            return core.certificates.registerAsync(args);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if (core.certificates._isRenewable(args, certs)) {
 | 
			
		||||
            // it's time to renew the available cert
 | 
			
		||||
            if (false !== args.securityUpdates && !args._communityMemberAdded) {
 | 
			
		||||
              try {
 | 
			
		||||
                // We will notify all greenlock users of mandatory and security updates
 | 
			
		||||
                // We'll keep track of versions and os so we can make sure things work well
 | 
			
		||||
                // { name, version, email, domains, action, communityMember, telemetry }
 | 
			
		||||
                require('./community').add({
 | 
			
		||||
                  name: args._communityPackage
 | 
			
		||||
                , version: args._communityPackageVersion
 | 
			
		||||
                , email: args.email
 | 
			
		||||
                , domains: args.domains || args.servernames
 | 
			
		||||
                , action: 'renew'
 | 
			
		||||
                , communityMember: args.communityMember
 | 
			
		||||
                , telemetry: args.telemetry
 | 
			
		||||
                });
 | 
			
		||||
              } catch(e) { /* ignore */ }
 | 
			
		||||
              args._communityMemberAdded = true;
 | 
			
		||||
            }
 | 
			
		||||
            certs.renewing = core.certificates.renewAsync(args, certs);
 | 
			
		||||
            if (args.waitForRenewal) {
 | 
			
		||||
              return certs.renewing;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          // return existing unexpired (although potentially stale) certificates when available
 | 
			
		||||
          // there will be an additional .renewing property if the certs are being asynchronously renewed
 | 
			
		||||
          return certs;
 | 
			
		||||
        }).then(function (results) {
 | 
			
		||||
          // returns pems
 | 
			
		||||
          return results;
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return core;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										68
									
								
								express-server/node_modules/greenlock/lib/middleware.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								express-server/node_modules/greenlock/lib/middleware.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var utils = require('./utils');
 | 
			
		||||
 | 
			
		||||
function _log(debug) {
 | 
			
		||||
  if (debug) {
 | 
			
		||||
    var args = Array.prototype.slice.call(arguments);
 | 
			
		||||
    args.shift();
 | 
			
		||||
    args.unshift("[greenlock/lib/middleware.js]");
 | 
			
		||||
    console.log.apply(console, args);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports.create = function (gl) {
 | 
			
		||||
  if (!gl.challenges['http-01'] || !gl.challenges['http-01'].get) {
 | 
			
		||||
    throw new Error("middleware requires challenge plugin with get method");
 | 
			
		||||
  }
 | 
			
		||||
  var log = gl.log || _log;
 | 
			
		||||
 | 
			
		||||
  log(gl.debug, "created middleware");
 | 
			
		||||
  return function (_app) {
 | 
			
		||||
    if (_app && 'function' !== typeof _app) {
 | 
			
		||||
      throw new Error("use greenlock.middleware() or greenlock.middleware(function (req, res) {})");
 | 
			
		||||
    }
 | 
			
		||||
    var prefix = gl.acmeChallengePrefix || '/.well-known/acme-challenge/';
 | 
			
		||||
 | 
			
		||||
    return function (req, res, next) {
 | 
			
		||||
      if (0 !== req.url.indexOf(prefix)) {
 | 
			
		||||
        log(gl.debug, "no match, skipping middleware");
 | 
			
		||||
        if ('function' === typeof _app) {
 | 
			
		||||
          _app(req, res, next);
 | 
			
		||||
        }
 | 
			
		||||
        else if ('function' === typeof next) {
 | 
			
		||||
          next();
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
          res.statusCode = 500;
 | 
			
		||||
          res.end("[500] Developer Error: app.use('/', greenlock.middleware()) or greenlock.middleware(app)");
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      log(gl.debug, "this must be tinder, 'cuz it's a match!");
 | 
			
		||||
 | 
			
		||||
      var token = req.url.slice(prefix.length);
 | 
			
		||||
      var hostname = req.hostname || (req.headers.host || '').toLowerCase().replace(/:.*/, '');
 | 
			
		||||
 | 
			
		||||
      log(gl.debug, "hostname", hostname, "token", token);
 | 
			
		||||
 | 
			
		||||
      var copy = utils.merge({ domains: [ hostname ] }, gl);
 | 
			
		||||
      copy = utils.tplCopy(copy);
 | 
			
		||||
 | 
			
		||||
      // TODO tpl copy?
 | 
			
		||||
      // TODO need to restore challengeType
 | 
			
		||||
      gl.challenges['http-01'].get(copy, hostname, token, function (err, secret) {
 | 
			
		||||
        if (err || !token) {
 | 
			
		||||
          res.statusCode = 404;
 | 
			
		||||
          res.setHeader('Content-Type', 'application/json; charset=utf-8');
 | 
			
		||||
          res.end('{ "error": { "message": "Error: These aren\'t the tokens you\'re looking for. Move along." } }');
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        res.setHeader('Content-Type', 'text/plain; charset=utf-8');
 | 
			
		||||
        res.end(secret);
 | 
			
		||||
      });
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										127
									
								
								express-server/node_modules/greenlock/lib/utils.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								express-server/node_modules/greenlock/lib/utils.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,127 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var path = require('path');
 | 
			
		||||
var homeRe = new RegExp("^~(\\/|\\\\|\\" + path.sep + ")");
 | 
			
		||||
// very basic check. Allows *.example.com.
 | 
			
		||||
var re = /^(\*\.)?[a-zA-Z0-9\.\-]+$/;
 | 
			
		||||
var punycode = require('punycode');
 | 
			
		||||
var promisify = (require('util').promisify || require('bluebird').promisify);
 | 
			
		||||
var dnsResolveMxAsync = promisify(require('dns').resolveMx);
 | 
			
		||||
 | 
			
		||||
module.exports.attachCertInfo = function (results) {
 | 
			
		||||
  // XXX Note: Parsing the certificate info comes at a great cost (~500kb)
 | 
			
		||||
  var getCertInfo = require('certpem').info;
 | 
			
		||||
  var certInfo = getCertInfo(results.cert);
 | 
			
		||||
 | 
			
		||||
  // subject, altnames, issuedAt, expiresAt
 | 
			
		||||
  Object.keys(certInfo).forEach(function (key) {
 | 
			
		||||
    results[key] = certInfo[key];
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return results;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports.isValidDomain = function (domain) {
 | 
			
		||||
  if (re.test(domain)) {
 | 
			
		||||
    return domain;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  domain = punycode.toASCII(domain);
 | 
			
		||||
 | 
			
		||||
  if (re.test(domain)) {
 | 
			
		||||
    return domain;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return '';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports.merge = function (/*defaults, args*/) {
 | 
			
		||||
  var allDefaults = Array.prototype.slice.apply(arguments);
 | 
			
		||||
  var args = allDefaults.shift();
 | 
			
		||||
  var copy = {};
 | 
			
		||||
 | 
			
		||||
  allDefaults.forEach(function (defaults) {
 | 
			
		||||
    Object.keys(defaults).forEach(function (key) {
 | 
			
		||||
      copy[key] = defaults[key];
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  Object.keys(args).forEach(function (key) {
 | 
			
		||||
    copy[key] = args[key];
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return copy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports.tplCopy = function (copy) {
 | 
			
		||||
  var homedir = require('os').homedir();
 | 
			
		||||
  var tplKeys;
 | 
			
		||||
 | 
			
		||||
  copy.hostnameGet = function (copy) {
 | 
			
		||||
    return (copy.domains || [])[0] || copy.domain;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  Object.keys(copy).forEach(function (key) {
 | 
			
		||||
    var newName;
 | 
			
		||||
    if (!/Get$/.test(key)) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    newName = key.replace(/Get$/, '');
 | 
			
		||||
    copy[newName] = copy[newName] || copy[key](copy);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  tplKeys = Object.keys(copy);
 | 
			
		||||
  tplKeys.sort(function (a, b) {
 | 
			
		||||
    return b.length - a.length;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  tplKeys.forEach(function (key) {
 | 
			
		||||
    if ('string' !== typeof copy[key]) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    copy[key] = copy[key].replace(homeRe, homedir + path.sep);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  tplKeys.forEach(function (key) {
 | 
			
		||||
    if ('string' !== typeof copy[key]) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tplKeys.forEach(function (tplname) {
 | 
			
		||||
      if (!copy[tplname]) {
 | 
			
		||||
        // what can't be templated now may be templatable later
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      copy[key] = copy[key].replace(':' + tplname, copy[tplname]);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return copy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports.testEmail = function (email) {
 | 
			
		||||
  var parts = (email||'').split('@');
 | 
			
		||||
  var err;
 | 
			
		||||
 | 
			
		||||
  if (2 !== parts.length || !parts[0] || !parts[1]) {
 | 
			
		||||
    err = new Error("malformed email address '" + email + "'");
 | 
			
		||||
    err.code = 'E_EMAIL';
 | 
			
		||||
    return Promise.reject(err);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return dnsResolveMxAsync(parts[1]).then(function (records) {
 | 
			
		||||
    // records only returns when there is data
 | 
			
		||||
    if (!records.length) {
 | 
			
		||||
      throw new Error("sanity check fail: success, but no MX records returned");
 | 
			
		||||
    }
 | 
			
		||||
    return email;
 | 
			
		||||
  }, function (err) {
 | 
			
		||||
    if ('ENODATA' === err.code) {
 | 
			
		||||
      err = new Error("no MX records found for '" + parts[1] + "'");
 | 
			
		||||
      err.code = 'E_EMAIL';
 | 
			
		||||
      return Promise.reject(err);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										124
									
								
								express-server/node_modules/greenlock/package.json
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								express-server/node_modules/greenlock/package.json
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,124 @@
 | 
			
		||||
{
 | 
			
		||||
  "_args": [
 | 
			
		||||
    [
 | 
			
		||||
      "greenlock@^2.4.9",
 | 
			
		||||
      "/nodeapps/https-test/greenlock-express.js"
 | 
			
		||||
    ]
 | 
			
		||||
  ],
 | 
			
		||||
  "_from": "greenlock@>=2.4.9 <3.0.0",
 | 
			
		||||
  "_hasShrinkwrap": false,
 | 
			
		||||
  "_id": "greenlock@2.4.10",
 | 
			
		||||
  "_inCache": true,
 | 
			
		||||
  "_installable": true,
 | 
			
		||||
  "_location": "/greenlock",
 | 
			
		||||
  "_nodeVersion": "10.13.0",
 | 
			
		||||
  "_npmOperationalInternal": {
 | 
			
		||||
    "host": "s3://npm-registry-packages",
 | 
			
		||||
    "tmp": "tmp/greenlock_2.4.10_1541843287866_0.5046853213401128"
 | 
			
		||||
  },
 | 
			
		||||
  "_npmUser": {
 | 
			
		||||
    "email": "coolaj86@gmail.com",
 | 
			
		||||
    "name": "coolaj86"
 | 
			
		||||
  },
 | 
			
		||||
  "_npmVersion": "6.4.1",
 | 
			
		||||
  "_phantomChildren": {},
 | 
			
		||||
  "_requested": {
 | 
			
		||||
    "name": "greenlock",
 | 
			
		||||
    "raw": "greenlock@^2.4.9",
 | 
			
		||||
    "rawSpec": "^2.4.9",
 | 
			
		||||
    "scope": null,
 | 
			
		||||
    "spec": ">=2.4.9 <3.0.0",
 | 
			
		||||
    "type": "range"
 | 
			
		||||
  },
 | 
			
		||||
  "_requiredBy": [
 | 
			
		||||
    "/"
 | 
			
		||||
  ],
 | 
			
		||||
  "_resolved": "https://registry.npmjs.org/greenlock/-/greenlock-2.4.10.tgz",
 | 
			
		||||
  "_shasum": "59a5878d76fba962aeec0b609b2a7a097a102261",
 | 
			
		||||
  "_shrinkwrap": null,
 | 
			
		||||
  "_spec": "greenlock@^2.4.9",
 | 
			
		||||
  "_where": "/nodeapps/https-test/greenlock-express.js",
 | 
			
		||||
  "author": {
 | 
			
		||||
    "email": "coolaj86@gmail.com",
 | 
			
		||||
    "name": "AJ ONeal",
 | 
			
		||||
    "url": "https://coolaj86.com/"
 | 
			
		||||
  },
 | 
			
		||||
  "bugs": {
 | 
			
		||||
    "url": "https://git.coolaj86.com/coolaj86/greenlock.js/issues"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "acme": "^1.0.6",
 | 
			
		||||
    "acme-v2": "^1.2.0",
 | 
			
		||||
    "certpem": "^1.1.0",
 | 
			
		||||
    "le-challenge-fs": "^2.0.2",
 | 
			
		||||
    "le-sni-auto": "^2.1.3",
 | 
			
		||||
    "le-store-certbot": "^2.1.7",
 | 
			
		||||
    "rsa-compat": "^1.5.0"
 | 
			
		||||
  },
 | 
			
		||||
  "description": "Let's Encrypt for node.js on npm",
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "request": "^2.75.0"
 | 
			
		||||
  },
 | 
			
		||||
  "directories": {},
 | 
			
		||||
  "dist": {
 | 
			
		||||
    "fileCount": 8,
 | 
			
		||||
    "integrity": "sha512-vLJ41rhuzmf/DRqceWKXvhoU6yZ8l1b+o3idExea/RANkPT4hs/2qg7hFzjLRngQEYP4LmgeFPbeqPYQV8m+zQ==",
 | 
			
		||||
    "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb5qlYCRA9TVsSAnZWagAAtEEP/1y3ugTwK2Zt3+QDZoRG\newZwL5KyOAKMGHSWRj/xTHHqh0pm3abE85AqS6DwykRu1H/dam5Y7ncIadNm\nL1vDGP0gMH4l6fWOh6UlyX+zOv2JTNOom3km17ISpydxQugae37iotkOUnSy\n2YauoiGOERDEQfbuHYb16llz8x6Ged2SIfDQdRNOgvL13gCOyKmGZDEYpfD4\nayU/7ZHZaYIe/92cGZ/xzph1oD60bgIyqboMrdvdRGe3hwgpKfib9FHDPPfF\nL/YGPKg8EEc5H5/raK8K4cMt3yX3QCb2rsVMoNMxO6WQyz3nGgv21jFoFz8W\n5vExddJhSo2781eEpXNSdRgwuuTP+AFofvBeAj7KTOQrVvd9Sf9dbYdwWOZ5\nui3xsNFJurX0UdS+VrWm+elExhjsKiF6CWwZQk14KAKAUBTNypHKmwnNQvn1\nreBybwgHCZV1zx4yCe+96p4h4RPDE6PohBJwXMnVPLkITeCldKrzvzQfZyz0\nqfCjuHG6YKc5ZVwqBfTjlOWIaBFN3SoOKhlIhCTvecjPxmCh+GwUkVoTBgpR\nyl641AjqrFNVkDMKTolJIe6TczZ9zpJi+tr/Da8W09QZKBdIVNGVKkENO1kN\nLIQkwm1jRv739lgwRt2OISWcw+/lED+fKxJyAMlPUZquCjRZ/iRz2fDIHmNi\n4h72\r\n=YRwx\r\n-----END PGP SIGNATURE-----\r\n",
 | 
			
		||||
    "shasum": "59a5878d76fba962aeec0b609b2a7a097a102261",
 | 
			
		||||
    "tarball": "https://registry.npmjs.org/greenlock/-/greenlock-2.4.10.tgz",
 | 
			
		||||
    "unpackedSize": 67800
 | 
			
		||||
  },
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">=4.5"
 | 
			
		||||
  },
 | 
			
		||||
  "gitDependencies": {
 | 
			
		||||
    "acme": "git+https://git.coolaj86.com/coolaj86/acme-.js.git#v1.0",
 | 
			
		||||
    "le-acme-core": "git+https://git.coolaj86.com/coolaj86/le-acme-core.js.git#v2.1"
 | 
			
		||||
  },
 | 
			
		||||
  "gitHead": "abe081387d13d49a4db55e83e6f0fedc54a1e2e6",
 | 
			
		||||
  "homepage": "https://git.coolaj86.com/coolaj86/greenlock.js",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "ACME",
 | 
			
		||||
    "Automated HTTPS",
 | 
			
		||||
    "Free SSL",
 | 
			
		||||
    "Greenlock",
 | 
			
		||||
    "Let's Encrypt",
 | 
			
		||||
    "auto-sni",
 | 
			
		||||
    "https",
 | 
			
		||||
    "letsencrypt",
 | 
			
		||||
    "tls",
 | 
			
		||||
    "v2"
 | 
			
		||||
  ],
 | 
			
		||||
  "license": "(MIT OR Apache-2.0)",
 | 
			
		||||
  "main": "index.js",
 | 
			
		||||
  "maintainers": [
 | 
			
		||||
    {
 | 
			
		||||
      "name": "coolaj86",
 | 
			
		||||
      "email": "coolaj86@gmail.com"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "name": "ppl",
 | 
			
		||||
      "email": "npm@ppl.family"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "name": "thejshaver",
 | 
			
		||||
      "email": "john@jshaver.net"
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "name": "greenlock",
 | 
			
		||||
  "optionalDependencies": {},
 | 
			
		||||
  "readme": "ERROR: No README data found!",
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "url": "https://git.coolaj86.com/coolaj86/greenlock.js.git"
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "test": "echo \"Error: no test specified\" && exit 1"
 | 
			
		||||
  },
 | 
			
		||||
  "trulyOptionalDependencies": {
 | 
			
		||||
    "bluebird": "^3.5.1",
 | 
			
		||||
    "le-acme-core": "^2.1.3",
 | 
			
		||||
    "ursa": "^0.9.4"
 | 
			
		||||
  },
 | 
			
		||||
  "version": "2.4.10"
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user