Compare commits

..

7 Commits

Author SHA1 Message Date
AJ ONeal eb1d988405 Merge branch 'master' of ssh://git.coolaj86.com:22042/coolaj86/greenlock.js 2018-05-15 16:09:09 -06:00
AJ ONeal 299fa6b717 v2.2.12 2018-05-15 16:07:27 -06:00
AJ ONeal 8ddeb26063 replace "le" with "greenlock" 2018-05-15 16:01:09 -06:00
AJ ONeal 1931feed1d update old vars 2018-05-15 15:49:59 -06:00
AJ ONeal 4c6cdfde0a update version detection 2018-05-15 15:42:04 -06:00
AJ ONeal 75ed99904c syntax fix 2018-05-12 17:00:13 -06:00
AJ ONeal 9f8bce2c4f v2.2.11 2018-05-12 16:58:32 -06:00
7 changed files with 308 additions and 239 deletions

View File

@ -281,8 +281,8 @@ The configuration consists of 3 components:
```javascript ```javascript
'use strict'; 'use strict';
var LE = require('greenlock'); var Greenlock = require('greenlock');
var le; var greenlock;
// Storage Backend // Storage Backend
@ -304,7 +304,7 @@ function leAgree(opts, agreeCb) {
agreeCb(null, opts.tosUrl); agreeCb(null, opts.tosUrl);
} }
le = LE.create({ greenlock = Greenlock.create({
version: 'draft-11' // 'draft-11' or 'v01' version: 'draft-11' // 'draft-11' or 'v01'
// 'draft-11' is for Let's Encrypt v2 otherwise known as ACME draft 11 // 'draft-11' is for Let's Encrypt v2 otherwise known as ACME draft 11
// 'v02' is an alias for 'draft-11' // 'v02' is an alias for 'draft-11'
@ -335,15 +335,15 @@ le = LE.create({
// If using express you should use the middleware // If using express you should use the middleware
// app.use('/', le.middleware()); // app.use('/', greenlock.middleware());
// //
// Otherwise you should see the test file for usage of this: // Otherwise you should see the test file for usage of this:
// le.challenges['http-01'].get(opts.domain, key, val, done) // greenlock.challenges['http-01'].get(opts.domain, key, val, done)
// Check in-memory cache of certificates for the named domain // Check in-memory cache of certificates for the named domain
le.check({ domains: [ 'example.com' ] }).then(function (results) { greenlock.check({ domains: [ 'example.com' ] }).then(function (results) {
if (results) { if (results) {
// we already have certificates // we already have certificates
return; return;
@ -351,7 +351,7 @@ le.check({ domains: [ 'example.com' ] }).then(function (results) {
// Register Certificate manually // Register Certificate manually
le.register({ greenlock.register({
domains: ['example.com'] // CHANGE TO YOUR DOMAIN (list for SANS) domains: ['example.com'] // CHANGE TO YOUR DOMAIN (list for SANS)
, email: 'user@email.com' // CHANGE TO YOUR EMAIL , email: 'user@email.com' // CHANGE TO YOUR EMAIL
@ -365,8 +365,8 @@ le.check({ domains: [ 'example.com' ] }).then(function (results) {
}, function (err) { }, function (err) {
// Note: you must either use le.middleware() with express, // Note: you must either use greenlock.middleware() with express,
// manually use le.challenges['http-01'].get(opts, domain, key, val, done) // manually use greenlock.challenges['http-01'].get(opts, domain, key, val, done)
// or have a webserver running and responding // or have a webserver running and responding
// to /.well-known/acme-challenge at `webrootPath` // to /.well-known/acme-challenge at `webrootPath`
console.error('[Error]: node-greenlock/examples/standalone'); console.error('[Error]: node-greenlock/examples/standalone');
@ -396,15 +396,15 @@ API
The full end-user API is exposed in the example above and includes all relevant options. The full end-user API is exposed in the example above and includes all relevant options.
``` ```
le.register(opts) greenlock.register(opts)
le.check(opts) greenlock.check(opts)
``` ```
### Helper Functions ### Helper Functions
We do expose a few helper functions: We do expose a few helper functions:
* LE.validDomain(hostname) // returns '' or the hostname string if it's a valid ascii or punycode domain name * Greenlock.validDomain(hostname) // returns '' or the hostname string if it's a valid ascii or punycode domain name
TODO fetch domain tld list TODO fetch domain tld list

View File

@ -3,7 +3,7 @@ STOP
**These aren't the droids you're looking for.** **These aren't the droids you're looking for.**
You probably don't want to use `node-letsencrypt` directly. You probably don't want to use `greenlock` directly.
Instead, look here: Instead, look here:
@ -12,21 +12,21 @@ Webservers
For any type of webserver (express, hapi, koa, connect, https, spdy, etc), For any type of webserver (express, hapi, koa, connect, https, spdy, etc),
you're going to want to take a look at you're going to want to take a look at
[letsencrypt-express](https://github.com/Daplie/letsencrypt-express). [greenlock-express](https://git.coolaj86.com/coolaj86/greenlock-express.js).
<https://github.com/Daplie/letsencrypt-express> <https://git.coolaj86.com/coolaj86/greenlock-express.js>
CLIs CLIs
---- ----
For any type of CLI (like what you want to use with bash, fish, zsh, cmd.exe, PowerShell, etc), For any type of CLI (like what you want to use with bash, fish, zsh, cmd.exe, PowerShell, etc),
you're going to want to take a look at you're going to want to take a look at
[letsencrypt-cli](https://github.com/Daplie/letsencrypt-cli). [greenlock-cli](https://git.coolaj86.com/coolaj86/greenlock-cli.js).
<https://github.com/Daplie/letsencrypt-cli> <https://git.coolaj86.com/coolaj86/greenlock-cli.js>
No, I wanted node-letsencrypt No, I wanted greenlock
============================= ======================
Well, take a look at the API in the main README Well, take a look at the API in the main README
and you can also check out the code in the repos above. and you can also check out the code in the repos above.

View File

@ -5,9 +5,10 @@ var LE = require('../');
var db = {}; var db = {};
var config = { var config = {
server: LE.stagingServerUrl // or LE.productionServerUrl server: 'https://acme-staging-v02.api.letsencrypt.org/directory'
, version: 'v02'
, configDir: require('homedir')() + '/letsencrypt/etc' // or /etc/letsencrypt or wherever , configDir: require('os').homedir() + '/acme/etc' // or /etc/acme or wherever
, privkeyPath: ':config/live/:hostname/privkey.pem' // , privkeyPath: ':config/live/:hostname/privkey.pem' //
, fullchainPath: ':config/live/:hostname/fullchain.pem' // Note: both that :config and :hostname , fullchainPath: ':config/live/:hostname/fullchain.pem' // Note: both that :config and :hostname
@ -34,7 +35,7 @@ var handlers = {
cb(null); cb(null);
} }
, getChallenge: function (opts, hostname, key, cb) { // this is special because it is called by the webserver , getChallenge: function (opts, hostname, key, cb) { // this is special because it is called by the webserver
cb(null, db[key].val); // (see letsencrypt-cli/bin & letsencrypt-express/standalone), cb(null, db[key].val); // (see greenlock-cli/bin & greenlock-express/standalone),
// not by the library itself // not by the library itself
} }
, agreeToTerms: function (tosUrl, cb) { // gives you an async way to expose the legal agreement , agreeToTerms: function (tosUrl, cb) { // gives you an async way to expose the legal agreement
@ -43,6 +44,8 @@ var handlers = {
}; };
var le = LE.create(config, handlers); var le = LE.create(config, handlers);
console.error("CHANGE THE EMAIL, DOMAINS, AND AGREE TOS IN THE EXAMPLE BEFORE RUNNING IT");
process.exit(1);
// checks :conf/renewal/:hostname.conf // checks :conf/renewal/:hostname.conf
le.register({ // and either renews or registers le.register({ // and either renews or registers
domains: ['example.com'] // CHANGE TO YOUR DOMAIN domains: ['example.com'] // CHANGE TO YOUR DOMAIN
@ -55,8 +58,8 @@ le.register({ // and either renews
// Note: you must have a webserver running // Note: you must have a webserver running
// and expose handlers.getChallenge to it // and expose handlers.getChallenge to it
// in order to pass validation // in order to pass validation
// See letsencrypt-cli and or letsencrypt-express // See greenlock-cli and or greenlock-express
console.error('[Error]: node-letsencrypt/examples/standalone'); console.error('[Error]: greenlock/examples/standalone');
console.error(err.stack); console.error(err.stack);
} else { } else {
console.log('success'); console.log('success');

391
index.js
View File

@ -4,8 +4,9 @@ var DAY = 24 * 60 * 60 * 1000;
//var MIN = 60 * 1000; //var MIN = 60 * 1000;
var ACME = require('acme-v2/compat').ACME; var ACME = require('acme-v2/compat').ACME;
var LE = module.exports; var Greenlock = module.exports;
LE.LE = LE; Greenlock.Greenlock = Greenlock;
Greenlock.LE = Greenlock;
// in-process cache, shared between all instances // in-process cache, shared between all instances
var ipc = {}; var ipc = {};
@ -13,14 +14,14 @@ function _log(debug) {
if (debug) { if (debug) {
var args = Array.prototype.slice.call(arguments); var args = Array.prototype.slice.call(arguments);
args.shift(); args.shift();
args.unshift("[le/index.js]"); args.unshift("[gl/index.js]");
console.log.apply(console, args); console.log.apply(console, args);
} }
} }
LE.defaults = { Greenlock.defaults = {
productionServerUrl: 'https://acme-v02.api.letsencrypt.org/directory' productionServerUrl: 'https://acme-v01.api.letsencrypt.org/directory'
, stagingServerUrl: 'https://acme-staging-v02.api.letsencrypt.org/directory' , stagingServerUrl: 'https://acme-staging.api.letsencrypt.org/directory'
, rsaKeySize: ACME.rsaKeySize || 2048 , rsaKeySize: ACME.rsaKeySize || 2048
, challengeType: ACME.challengeType || 'http-01' , challengeType: ACME.challengeType || 'http-01'
@ -30,13 +31,13 @@ LE.defaults = {
}; };
// backwards compat // backwards compat
Object.keys(LE.defaults).forEach(function (key) { Object.keys(Greenlock.defaults).forEach(function (key) {
LE[key] = LE.defaults[key]; Greenlock[key] = Greenlock.defaults[key];
}); });
// show all possible options // show all possible options
var u; // undefined var u; // undefined
LE._undefined = { Greenlock._undefined = {
acme: u acme: u
, store: u , store: u
, challenge: u , challenge: u
@ -59,125 +60,191 @@ LE._undefined = {
, duplicate: u , duplicate: u
, _acmeUrls: u , _acmeUrls: u
}; };
LE._undefine = function (le) { Greenlock._undefine = function (gl) {
Object.keys(LE._undefined).forEach(function (key) { Object.keys(Greenlock._undefined).forEach(function (key) {
if (!(key in le)) { if (!(key in gl)) {
le[key] = u; gl[key] = u;
} }
}); });
return le; return gl;
}; };
LE.create = function (le) { Greenlock.create = function (gl) {
var PromiseA = require('bluebird'); var PromiseA = require('bluebird');
le.store = le.store || require('le-store-certbot').create({ debug: le.debug }); gl.store = gl.store || require('le-store-certbot').create({ debug: gl.debug });
le.core = require('./lib/core'); gl.core = require('./lib/core');
var log = le.log || _log; var log = gl.log || _log;
if (!le.challenges) { if (!gl.challenges) {
le.challenges = {}; gl.challenges = {};
} }
if (!le.challenges['http-01']) { if (!gl.challenges['http-01']) {
le.challenges['http-01'] = require('le-challenge-fs').create({ debug: le.debug }); gl.challenges['http-01'] = require('le-challenge-fs').create({ debug: gl.debug });
} }
/* if (!gl.challenges['dns-01']) {
if (!le.challenges['tls-sni-01']) {
le.challenges['tls-sni-01'] = require('le-challenge-sni').create({ debug: le.debug });
}
*/
if (!le.challenges['dns-01']) {
try { try {
le.challenges['dns-01'] = require('le-challenge-ddns').create({ debug: le.debug }); gl.challenges['dns-01'] = require('le-challenge-ddns').create({ debug: gl.debug });
} catch(e) { } catch(e) {
try { try {
le.challenges['dns-01'] = require('le-challenge-dns').create({ debug: le.debug }); gl.challenges['dns-01'] = require('le-challenge-dns').create({ debug: gl.debug });
} catch(e) { } catch(e) {
// not yet implemented // not yet implemented
} }
} }
} }
le = LE._undefine(le); gl = Greenlock._undefine(gl);
le.acmeChallengePrefix = LE.acmeChallengePrefix; gl.acmeChallengePrefix = Greenlock.acmeChallengePrefix;
le.rsaKeySize = le.rsaKeySize || LE.rsaKeySize; gl.rsaKeySize = gl.rsaKeySize || Greenlock.rsaKeySize;
le.challengeType = le.challengeType || LE.challengeType; gl.challengeType = gl.challengeType || Greenlock.challengeType;
le._ipc = ipc; gl._ipc = ipc;
le._communityPackage = le._communityPackage || 'greenlock.js'; gl._communityPackage = gl._communityPackage || 'greenlock.js';
le.agreeToTerms = le.agreeToTerms || function (args, agreeCb) { gl.agreeToTerms = gl.agreeToTerms || function (args, agreeCb) {
agreeCb(new Error("'agreeToTerms' was not supplied to LE and 'agreeTos' was not supplied to LE.register")); agreeCb(new Error("'agreeToTerms' was not supplied to Greenlock and 'agreeTos' was not supplied to Greenlock.register"));
}; };
if (!le.renewWithin) { le.renewWithin = 14 * DAY; } if (!gl.renewWithin) { gl.renewWithin = 14 * DAY; }
// renewBy has a default in le-sni-auto // renewBy has a default in le-sni-auto
if (!le.server) {
throw new Error("opts.server must be set to 'staging' or a production url, such as LE.productionServerUrl'");
} ///////////////////////////
if ('staging' === le.server) { // BEGIN VERSION MADNESS //
le.server = LE.stagingServerUrl; ///////////////////////////
}
else if ('production' === le.server) { if (!gl.version) {
le.server = LE.productionServerUrl; //console.warn("Please specify version: 'v01' (Let's Encrypt v1) or 'draft-11' (Let's Encrypt v2 / ACME draft 11)");
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-11' for Let's Encrypt v2 and ACME draft 11");
console.warn(" ('v02' is an alias of 'draft-11'");
console.warn("");
console.warn("or");
console.warn("");
console.warn(" 'v01' for Let's Encrypt v1 (deprecated)");
console.warn("");
console.warn("====================================================================");
console.warn("== this will be required from version v2.3 forward ==");
console.warn("====================================================================");
console.warn("");
console.warn("");
console.warn("");
} else if ('v02' === gl.version) {
gl.version = 'draft-11';
} else if ('v01' !== gl.version && 'draft-11' !== gl.version) {
throw new Error("Unrecognized version '" + gl.version + "'");
} }
if (-1 !== [ 'https://acme-v01.api.letsencrypt.org/directory' if (!gl.server) {
, 'https://acme-staging.api.letsencrypt.org/directory' ].indexOf(le.server)) { throw new Error("opts.server must specify an ACME directory URL, such as 'https://acme-staging-v02.api.letsencrypt.org/directory'");
ACME = require('le-acme-core').ACME;
console.warn("Let's Encrypt v1 is deprecated. Please update to Let's Encrypt v2 (ACME draft 11)");
} }
else if (-1 !== [ 'https://acme-v02.api.letsencrypt.org/directory' if ('staging' === gl.server) {
, 'https://acme-staging-v02.api.letsencrypt.org/directory' ].indexOf(le.server)) { gl.server = 'https://acme-staging.api.letsencrypt.org/directory';
if ('v02' !== le.version && 'draft-11' !== le.version) { gl.version = 'v01';
ACME = require('le-acme-core').ACME; console.warn("");
if ('v01' !== le.version) { console.warn("");
//console.warn("Please specify version: 'v01' (Let's Encrypt v1) or 'draft-11' (Let's Encrypt v2 / ACME draft 11)"); console.warn("=== WARNING ===");
console.warn(""); console.warn("");
console.warn(""); console.warn("Due to versioning issues the 'staging' option is deprecated. Please specify the full url and version.");
console.warn(""); console.warn("");
console.warn("===================================================================="); console.warn("\t--acme-url '" + gl.server + "' \\");
console.warn("== greenlock.js (v2.2.0+) =="); console.warn("\t--acme-version '" + gl.version + "' \\");
console.warn("===================================================================="); console.warn("");
console.warn(""); console.warn("");
console.warn("Please specify 'version' option:"); }
console.warn(""); else if ('production' === gl.server) {
console.warn(" 'v01' for Let's Encrypt v1"); gl.server = 'https://acme-v01.api.letsencrypt.org/directory';
console.warn(" or"); gl.version = 'v01';
console.warn(" 'draft-11' for Let's Encrypt v2 and ACME draft 11"); console.warn("");
console.warn(" ('v02' is an alias of 'draft-11'"); console.warn("");
console.warn(""); console.warn("=== WARNING ===");
console.warn("===================================================================="); console.warn("");
console.warn("== this will be required from version v2.3 forward =="); console.warn("Due to versioning issues the 'production' option is deprecated. Please specify the full url and version.");
console.warn("===================================================================="); console.warn("");
console.warn(""); console.warn("\t--acme-url '" + gl.server + "' \\");
console.warn(""); console.warn("\t--acme-version '" + gl.version + "' \\");
console.warn(""); console.warn("");
} console.warn("");
}
function loadLeV01() {
console.warn("");
console.warn("=== WARNING ===");
console.warn("");
console.warn("Let's Encrypt v1 is deprecated. Please update to Let's Encrypt v2 (ACME draft 11)");
console.warn("");
try {
return require('le-acme-core').ACME;
} catch(e) {
console.error(e);
console.info("");
console.info("");
console.info("If you require v01 API support (which is deprecated), you must install it:");
console.info("");
console.info("\tnpm install le-acme-core");
console.info("");
console.info("");
process.exit(e.code || 13);
} }
} }
le.acme = le.acme || ACME.create({ debug: le.debug }); if (-1 !== [
if (le.acme.create) { 'https://acme-v02.api.letsencrypt.org/directory'
le.acme = le.acme.create(le); , '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-11.");
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';
}
} }
le.acme = PromiseA.promisifyAll(le.acme); if ('v01' === gl.version) {
le._acmeOpts = le.acme.getOptions(); ACME = loadLeV01();
Object.keys(le._acmeOpts).forEach(function (key) { }
if (!(key in le)) { /////////////////////////
le[key] = le._acmeOpts[key]; // END VERSION MADNESS //
/////////////////////////
gl.acme = gl.acme || ACME.create({ debug: gl.debug });
if (gl.acme.create) {
gl.acme = gl.acme.create(gl);
}
gl.acme = PromiseA.promisifyAll(gl.acme);
gl._acmeOpts = gl.acme.getOptions();
Object.keys(gl._acmeOpts).forEach(function (key) {
if (!(key in gl)) {
gl[key] = gl._acmeOpts[key];
} }
}); });
if (le.store.create) { if (gl.store.create) {
le.store = le.store.create(le); gl.store = gl.store.create(gl);
} }
le.store = PromiseA.promisifyAll(le.store); gl.store = PromiseA.promisifyAll(gl.store);
le.store.accounts = PromiseA.promisifyAll(le.store.accounts); gl.store.accounts = PromiseA.promisifyAll(gl.store.accounts);
le.store.certificates = PromiseA.promisifyAll(le.store.certificates); gl.store.certificates = PromiseA.promisifyAll(gl.store.certificates);
le._storeOpts = le.store.getOptions(); gl._storeOpts = gl.store.getOptions();
Object.keys(le._storeOpts).forEach(function (key) { Object.keys(gl._storeOpts).forEach(function (key) {
if (!(key in le)) { if (!(key in gl)) {
le[key] = le._storeOpts[key]; gl[key] = gl._storeOpts[key];
} }
}); });
@ -185,118 +252,118 @@ LE.create = function (le) {
// //
// Backwards compat for <= v2.1.7 // Backwards compat for <= v2.1.7
// //
if (le.challenge) { if (gl.challenge) {
console.warn("Deprecated use of le.challenge. Use le.challenges['" + LE.challengeType + "'] instead."); console.warn("Deprecated use of gl.challenge. Use gl.challenges['" + Greenlock.challengeType + "'] instead.");
le.challenges[le.challengeType] = le.challenge; gl.challenges[gl.challengeType] = gl.challenge;
} }
LE.challengeTypes.forEach(function (challengeType) { Greenlock.challengeTypes.forEach(function (challengeType) {
var challenger = le.challenges[challengeType]; var challenger = gl.challenges[challengeType];
if (!challenger) { if (!challenger) {
return; return;
} }
if (challenger.create) { if (challenger.create) {
challenger = le.challenges[challengeType] = challenger.create(le); challenger = gl.challenges[challengeType] = challenger.create(gl);
} }
challenger = le.challenges[challengeType] = PromiseA.promisifyAll(challenger); challenger = gl.challenges[challengeType] = PromiseA.promisifyAll(challenger);
le['_challengeOpts_' + challengeType] = challenger.getOptions(); gl['_challengeOpts_' + challengeType] = challenger.getOptions();
Object.keys(le['_challengeOpts_' + challengeType]).forEach(function (key) { Object.keys(gl['_challengeOpts_' + challengeType]).forEach(function (key) {
if (!(key in le)) { if (!(key in gl)) {
le[key] = le['_challengeOpts_' + challengeType][key]; gl[key] = gl['_challengeOpts_' + challengeType][key];
} }
}); });
// TODO wrap these here and now with tplCopy? // TODO wrap these here and now with tplCopy?
if (!challenger.set || 5 !== challenger.set.length) { if (!challenger.set || 5 !== challenger.set.length) {
throw new Error("le.challenges[" + challengeType + "].set receives the wrong number of arguments." throw new Error("gl.challenges[" + challengeType + "].set receives the wrong number of arguments."
+ " You must define setChallenge as function (opts, domain, token, keyAuthorization, cb) { }"); + " You must define setChallenge as function (opts, domain, token, keyAuthorization, cb) { }");
} }
if (challenger.get && 4 !== challenger.get.length) { if (challenger.get && 4 !== challenger.get.length) {
throw new Error("le.challenges[" + challengeType + "].get receives the wrong number of arguments." throw new Error("gl.challenges[" + challengeType + "].get receives the wrong number of arguments."
+ " You must define getChallenge as function (opts, domain, token, cb) { }"); + " You must define getChallenge as function (opts, domain, token, cb) { }");
} }
if (!challenger.remove || 4 !== challenger.remove.length) { if (!challenger.remove || 4 !== challenger.remove.length) {
throw new Error("le.challenges[" + challengeType + "].remove receives the wrong number of arguments." throw new Error("gl.challenges[" + challengeType + "].remove receives the wrong number of arguments."
+ " You must define removeChallenge as function (opts, domain, token, cb) { }"); + " You must define removeChallenge as function (opts, domain, token, cb) { }");
} }
/* /*
if (!le._challengeWarn && (!challenger.loopback || 4 !== challenger.loopback.length)) { if (!gl._challengeWarn && (!challenger.loopback || 4 !== challenger.loopback.length)) {
le._challengeWarn = true; gl._challengeWarn = true;
console.warn("le.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"); 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 (!le._challengeWarn && (!challenger.test || 5 !== challenger.test.length)) { else if (!gl._challengeWarn && (!challenger.test || 5 !== challenger.test.length)) {
le._challengeWarn = true; gl._challengeWarn = true;
console.warn("le.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"); 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");
} }
*/ */
}); });
le.sni = le.sni || null; gl.sni = gl.sni || null;
le.tlsOptions = le.tlsOptions || le.httpsOptions || {}; gl.tlsOptions = gl.tlsOptions || gl.httpsOptions || {};
if (!le.tlsOptions.SNICallback) { if (!gl.tlsOptions.SNICallback) {
if (!le.getCertificatesAsync && !le.getCertificates) { if (!gl.getCertificatesAsync && !gl.getCertificates) {
if (Array.isArray(le.approveDomains)) { if (Array.isArray(gl.approveDomains)) {
le.approvedDomains = le.approveDomains; gl.approvedDomains = gl.approveDomains;
le.approveDomains = null; gl.approveDomains = null;
} }
if (!le.approveDomains) { if (!gl.approveDomains) {
le.approvedDomains = le.approvedDomains || []; gl.approvedDomains = gl.approvedDomains || [];
le.approveDomains = function (lexOpts, certs, cb) { gl.approveDomains = function (lexOpts, certs, cb) {
if (!le.email) { if (!gl.email) {
throw new Error("le-sni-auto is not properly configured. Missing email"); throw new Error("le-sni-auto is not properly configured. Missing email");
} }
if (!le.agreeTos) { if (!gl.agreeTos) {
throw new Error("le-sni-auto is not properly configured. Missing agreeTos"); throw new Error("le-sni-auto is not properly configured. Missing agreeTos");
} }
if (!le.approvedDomains.length) { if (!gl.approvedDomains.length) {
throw new Error("le-sni-auto is not properly configured. Missing approveDomains(domain, certs, callback)"); throw new Error("le-sni-auto is not properly configured. Missing approveDomains(domain, certs, callback)");
} }
if (lexOpts.domains.every(function (domain) { if (lexOpts.domains.every(function (domain) {
return -1 !== le.approvedDomains.indexOf(domain); return -1 !== gl.approvedDomains.indexOf(domain);
})) { })) {
lexOpts.domains = le.approvedDomains.slice(0); lexOpts.domains = gl.approvedDomains.slice(0);
lexOpts.email = le.email; lexOpts.email = gl.email;
lexOpts.agreeTos = le.agreeTos; lexOpts.agreeTos = gl.agreeTos;
lexOpts.communityMember = lexOpts.communityMember; lexOpts.communityMember = lexOpts.communityMember;
return cb(null, { options: lexOpts, certs: certs }); return cb(null, { options: lexOpts, certs: certs });
} }
log(le.debug, 'unapproved domain', lexOpts.domains, le.approvedDomains); log(gl.debug, 'unapproved domain', lexOpts.domains, gl.approvedDomains);
cb(new Error("unapproved domain")); cb(new Error("unapproved domain"));
}; };
} }
le.getCertificates = function (domain, certs, cb) { gl.getCertificates = function (domain, certs, cb) {
// certs come from current in-memory cache, not lookup // certs come from current in-memory cache, not lookup
log(le.debug, 'le.getCertificates called for', domain, 'with certs for', certs && certs.altnames || 'NONE'); log(gl.debug, 'gl.getCertificates called for', domain, 'with certs for', certs && certs.altnames || 'NONE');
var opts = { domain: domain, domains: certs && certs.altnames || [ domain ] }; var opts = { domain: domain, domains: certs && certs.altnames || [ domain ] };
try { try {
le.approveDomains(opts, certs, function (_err, results) { gl.approveDomains(opts, certs, function (_err, results) {
if (_err) { if (_err) {
log(le.debug, 'le.approveDomains called with error', _err); log(gl.debug, 'gl.approveDomains called with error', _err);
cb(_err); cb(_err);
return; return;
} }
log(le.debug, 'le.approveDomains called with certs for', results.certs && results.certs.altnames || 'NONE', 'and options:'); log(gl.debug, 'gl.approveDomains called with certs for', results.certs && results.certs.altnames || 'NONE', 'and options:');
log(le.debug, results.options); log(gl.debug, results.options);
var promise; var promise;
if (results.certs) { if (results.certs) {
log(le.debug, 'le renewing'); log(gl.debug, 'gl renewing');
promise = le.core.certificates.renewAsync(results.options, results.certs); promise = gl.core.certificates.renewAsync(results.options, results.certs);
} }
else { else {
log(le.debug, 'le getting from disk or registering new'); log(gl.debug, 'gl getting from disk or registering new');
promise = le.core.certificates.getAsync(results.options); promise = gl.core.certificates.getAsync(results.options);
} }
return promise.then(function (certs) { cb(null, certs); }, function (e) { return promise.then(function (certs) { cb(null, certs); }, function (e) {
if (le.debug) { console.debug("Error"); console.debug(e); } if (gl.debug) { console.debug("Error"); console.debug(e); }
cb(e); cb(e);
}); });
}); });
@ -307,13 +374,13 @@ LE.create = function (le) {
} }
}; };
} }
le.sni = le.sni || require('le-sni-auto'); gl.sni = gl.sni || require('le-sni-auto');
if (le.sni.create) { if (gl.sni.create) {
le.sni = le.sni.create(le); gl.sni = gl.sni.create(gl);
} }
le.tlsOptions.SNICallback = function (domain, cb) { gl.tlsOptions.SNICallback = function (domain, cb) {
try { try {
le.sni.sniCallback(domain, cb); gl.sni.sniCallback(domain, cb);
} catch(e) { } catch(e) {
console.error("[ERROR] Something went wrong in the SNICallback:"); console.error("[ERROR] Something went wrong in the SNICallback:");
console.error(e); console.error(e);
@ -324,29 +391,29 @@ LE.create = function (le) {
// We want to move to using tlsOptions instead of httpsOptions, but we also need to make // 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. // sure anything that uses this object will still work if looking for httpsOptions.
le.httpsOptions = le.tlsOptions; gl.httpsOptions = gl.tlsOptions;
if (le.core.create) { if (gl.core.create) {
le.core = le.core.create(le); gl.core = gl.core.create(gl);
} }
le.renew = function (args, certs) { gl.renew = function (args, certs) {
return le.core.certificates.renewAsync(args, certs); return gl.core.certificates.renewAsync(args, certs);
}; };
le.register = function (args) { gl.register = function (args) {
return le.core.certificates.getAsync(args); return gl.core.certificates.getAsync(args);
}; };
le.check = function (args) { gl.check = function (args) {
// TODO must return email, domains, tos, pems // TODO must return email, domains, tos, pems
return le.core.certificates.checkAsync(args); return gl.core.certificates.checkAsync(args);
}; };
le.middleware = le.middleware || require('./lib/middleware'); gl.middleware = gl.middleware || require('./lib/middleware');
if (le.middleware.create) { if (gl.middleware.create) {
le.middleware = le.middleware.create(le); gl.middleware = gl.middleware.create(gl);
} }
return le; return gl;
}; };

View File

@ -4,16 +4,16 @@ function _log(debug) {
if (debug) { if (debug) {
var args = Array.prototype.slice.call(arguments); var args = Array.prototype.slice.call(arguments);
args.shift(); args.shift();
args.unshift("[le/lib/core.js]"); args.unshift("[greenlock/lib/core.js]");
console.log.apply(console, args); console.log.apply(console, args);
} }
} }
module.exports.create = function (le) { module.exports.create = function (gl) {
var PromiseA = require('bluebird'); var PromiseA = require('bluebird');
var utils = require('./utils'); var utils = require('./utils');
var RSA = PromiseA.promisifyAll(require('rsa-compat').RSA); var RSA = PromiseA.promisifyAll(require('rsa-compat').RSA);
var log = le.log || _log; // allow custom log var log = gl.log || _log; // allow custom log
var pendingRegistrations = {}; var pendingRegistrations = {};
var core = { var core = {
@ -24,15 +24,15 @@ module.exports.create = function (le) {
var now = Date.now(); var now = Date.now();
// TODO check response header on request for cache time // TODO check response header on request for cache time
if ((now - le._ipc.acmeUrlsUpdatedAt) < 10 * 60 * 1000) { if ((now - gl._ipc.acmeUrlsUpdatedAt) < 10 * 60 * 1000) {
return PromiseA.resolve(le._ipc.acmeUrls); return PromiseA.resolve(gl._ipc.acmeUrls);
} }
return le.acme.getAcmeUrlsAsync(args.server).then(function (data) { return gl.acme.getAcmeUrlsAsync(args.server).then(function (data) {
le._ipc.acmeUrlsUpdatedAt = Date.now(); gl._ipc.acmeUrlsUpdatedAt = Date.now();
le._ipc.acmeUrls = data; gl._ipc.acmeUrls = data;
return le._ipc.acmeUrls; return gl._ipc.acmeUrls;
}); });
} }
@ -48,7 +48,7 @@ module.exports.create = function (le) {
// Accounts // Accounts
registerAsync: function (args) { registerAsync: function (args) {
var err; var err;
var copy = utils.merge(args, le); var copy = utils.merge(args, gl);
var disagreeTos; var disagreeTos;
args = utils.tplCopy(copy); args = utils.tplCopy(copy);
@ -65,20 +65,20 @@ module.exports.create = function (le) {
return utils.testEmail(args.email).then(function () { return utils.testEmail(args.email).then(function () {
var keypairOpts = { public: true, pem: true }; var keypairOpts = { public: true, pem: true };
var promise = le.store.accounts.checkKeypairAsync(args).then(function (keypair) { var promise = gl.store.accounts.checkKeypairAsync(args).then(function (keypair) {
if (keypair) { if (keypair) {
return RSA.import(keypair); return RSA.import(keypair);
} }
if (args.accountKeypair) { if (args.accountKeypair) {
return le.store.accounts.setKeypairAsync(args, RSA.import(args.accountKeypair)); return gl.store.accounts.setKeypairAsync(args, RSA.import(args.accountKeypair));
} }
return RSA.generateKeypairAsync(args.rsaKeySize, 65537, keypairOpts).then(function (keypair) { return RSA.generateKeypairAsync(args.rsaKeySize, 65537, keypairOpts).then(function (keypair) {
keypair.privateKeyPem = RSA.exportPrivatePem(keypair); keypair.privateKeyPem = RSA.exportPrivatePem(keypair);
keypair.publicKeyPem = RSA.exportPublicPem(keypair); keypair.publicKeyPem = RSA.exportPublicPem(keypair);
keypair.privateKeyJwk = RSA.exportPrivateJwk(keypair); keypair.privateKeyJwk = RSA.exportPrivateJwk(keypair);
return le.store.accounts.setKeypairAsync(args, keypair); return gl.store.accounts.setKeypairAsync(args, keypair);
}); });
}); });
@ -88,11 +88,11 @@ module.exports.create = function (le) {
return core.getAcmeUrlsAsync(args).then(function (urls) { return core.getAcmeUrlsAsync(args).then(function (urls) {
args._acmeUrls = urls; args._acmeUrls = urls;
return le.acme.registerNewAccountAsync({ return gl.acme.registerNewAccountAsync({
email: args.email email: args.email
, newRegUrl: args._acmeUrls.newReg , newRegUrl: args._acmeUrls.newReg
, agreeToTerms: function (tosUrl, agreeCb) { , agreeToTerms: function (tosUrl, agreeCb) {
if (true === args.agreeTos || tosUrl === args.agreeTos || tosUrl === le.agreeToTerms) { if (true === args.agreeTos || tosUrl === args.agreeTos || tosUrl === gl.agreeToTerms) {
agreeCb(null, tosUrl); agreeCb(null, tosUrl);
return; return;
} }
@ -100,11 +100,11 @@ module.exports.create = function (le) {
// args.email = email; // already there // args.email = email; // already there
// args.domains = domains // already there // args.domains = domains // already there
args.tosUrl = tosUrl; args.tosUrl = tosUrl;
le.agreeToTerms(args, agreeCb); gl.agreeToTerms(args, agreeCb);
} }
, accountKeypair: keypair , accountKeypair: keypair
, debug: le.debug || args.debug , debug: gl.debug || args.debug
}).then(function (receipt) { }).then(function (receipt) {
var reg = { var reg = {
keypair: keypair keypair: keypair
@ -113,7 +113,7 @@ module.exports.create = function (le) {
}; };
// TODO move templating of arguments to right here? // TODO move templating of arguments to right here?
return le.store.accounts.setAsync(args, reg).then(function (account) { return gl.store.accounts.setAsync(args, reg).then(function (account) {
// should now have account.id and account.accountId // should now have account.id and account.accountId
args.account = account; args.account = account;
args.accountId = account.id; args.accountId = account.id;
@ -145,10 +145,10 @@ module.exports.create = function (le) {
)); ));
} }
var copy = utils.merge(args, le); var copy = utils.merge(args, gl);
args = utils.tplCopy(copy); args = utils.tplCopy(copy);
return le.store.accounts.checkAsync(args).then(function (account) { return gl.store.accounts.checkAsync(args).then(function (account) {
if (!account) { if (!account) {
return null; return null;
@ -166,9 +166,9 @@ module.exports.create = function (le) {
// Certificates // Certificates
registerAsync: function (args) { registerAsync: function (args) {
var err; var err;
var challengeDefaults = le['_challengeOpts_' + (args.challengeType || le.challengeType)] || {}; var challengeDefaults = gl['_challengeOpts_' + (args.challengeType || gl.challengeType)] || {};
var copy = utils.merge(args, challengeDefaults || {}); var copy = utils.merge(args, challengeDefaults || {});
copy = utils.merge(copy, le); copy = utils.merge(copy, gl);
args = utils.tplCopy(copy); args = utils.tplCopy(copy);
if (!Array.isArray(args.domains)) { if (!Array.isArray(args.domains)) {
@ -224,13 +224,13 @@ module.exports.create = function (le) {
return core.accounts.getAsync(args).then(function (account) { return core.accounts.getAsync(args).then(function (account) {
args.account = account; args.account = account;
var promise = le.store.certificates.checkKeypairAsync(args).then(function (keypair) { var promise = gl.store.certificates.checkKeypairAsync(args).then(function (keypair) {
if (keypair) { if (keypair) {
return RSA.import(keypair); return RSA.import(keypair);
} }
if (args.domainKeypair) { if (args.domainKeypair) {
return le.store.certificates.setKeypairAsync(args, RSA.import(args.domainKeypair)); return gl.store.certificates.setKeypairAsync(args, RSA.import(args.domainKeypair));
} }
var keypairOpts = { public: true, pem: true }; var keypairOpts = { public: true, pem: true };
@ -238,7 +238,7 @@ module.exports.create = function (le) {
keypair.privateKeyPem = RSA.exportPrivatePem(keypair); keypair.privateKeyPem = RSA.exportPrivatePem(keypair);
keypair.publicKeyPem = RSA.exportPublicPem(keypair); keypair.publicKeyPem = RSA.exportPublicPem(keypair);
keypair.privateKeyJwk = RSA.exportPrivateJwk(keypair); keypair.privateKeyJwk = RSA.exportPrivateJwk(keypair);
return le.store.certificates.setKeypairAsync(args, keypair); return gl.store.certificates.setKeypairAsync(args, keypair);
}); });
}); });
@ -252,7 +252,7 @@ module.exports.create = function (le) {
args._acmeUrls = urls; args._acmeUrls = urls;
var certReq = { var certReq = {
debug: args.debug || le.debug debug: args.debug || gl.debug
, newAuthzUrl: args._acmeUrls.newAuthz , newAuthzUrl: args._acmeUrls.newAuthz
, newCertUrl: args._acmeUrls.newCert , newCertUrl: args._acmeUrls.newCert
@ -277,23 +277,23 @@ module.exports.create = function (le) {
certReq.setChallenge = function (domain, key, value, done) { certReq.setChallenge = function (domain, key, value, done) {
log(args.debug, "setChallenge called for '" + domain + "'"); log(args.debug, "setChallenge called for '" + domain + "'");
var copy = utils.merge({ domains: [domain] }, args); var copy = utils.merge({ domains: [domain] }, args);
copy = utils.merge(copy, le); copy = utils.merge(copy, gl);
utils.tplCopy(copy); utils.tplCopy(copy);
// TODO need to save challengeType // TODO need to save challengeType
le.challenges[args.challengeType].set(copy, domain, key, value, done); gl.challenges[args.challengeType].set(copy, domain, key, value, done);
}; };
certReq.removeChallenge = function (domain, key, done) { certReq.removeChallenge = function (domain, key, done) {
log(args.debug, "removeChallenge called for '" + domain + "'"); log(args.debug, "removeChallenge called for '" + domain + "'");
var copy = utils.merge({ domains: [domain] }, le); var copy = utils.merge({ domains: [domain] }, gl);
utils.tplCopy(copy); utils.tplCopy(copy);
le.challenges[args.challengeType].remove(copy, domain, key, done); gl.challenges[args.challengeType].remove(copy, domain, key, done);
}; };
log(args.debug, 'calling le.acme.getCertificateAsync', certReq.domains); log(args.debug, 'calling greenlock.acme.getCertificateAsync', certReq.domains);
return le.acme.getCertificateAsync(certReq).then(utils.attachCertInfo); return gl.acme.getCertificateAsync(certReq).then(utils.attachCertInfo);
}); });
}).then(function (results) { }).then(function (results) {
// { cert, chain, privkey /*TODO, subject, altnames, issuedAt, expiresAt */ } // { cert, chain, privkey /*TODO, subject, altnames, issuedAt, expiresAt */ }
@ -301,7 +301,7 @@ module.exports.create = function (le) {
args.certs = results; args.certs = results;
// args.pems is deprecated // args.pems is deprecated
args.pems = results; args.pems = results;
return le.store.certificates.setAsync(args).then(function () { return gl.store.certificates.setAsync(args).then(function () {
return results; return results;
}); });
}); });
@ -362,14 +362,14 @@ module.exports.create = function (le) {
return false; return false;
} }
, _getRenewableAt: function (args, certs) { , _getRenewableAt: function (args, certs) {
return certs.expiresAt - (args.renewWithin || le.renewWithin); return certs.expiresAt - (args.renewWithin || gl.renewWithin);
} }
, checkAsync: function (args) { , checkAsync: function (args) {
var copy = utils.merge(args, le); var copy = utils.merge(args, gl);
utils.tplCopy(copy); utils.tplCopy(copy);
// returns pems // returns pems
return le.store.certificates.checkAsync(copy).then(function (cert) { return gl.store.certificates.checkAsync(copy).then(function (cert) {
if (cert) { if (cert) {
log(args.debug, 'checkAsync found existing certificates'); log(args.debug, 'checkAsync found existing certificates');
return utils.attachCertInfo(cert); return utils.attachCertInfo(cert);
@ -381,7 +381,7 @@ module.exports.create = function (le) {
} }
// Certificates // Certificates
, getAsync: function (args) { , getAsync: function (args) {
var copy = utils.merge(args, le); var copy = utils.merge(args, gl);
args = utils.tplCopy(copy); args = utils.tplCopy(copy);
return core.certificates.checkAsync(args).then(function (certs) { return core.certificates.checkAsync(args).then(function (certs) {

View File

@ -6,27 +6,27 @@ function _log(debug) {
if (debug) { if (debug) {
var args = Array.prototype.slice.call(arguments); var args = Array.prototype.slice.call(arguments);
args.shift(); args.shift();
args.unshift("[le/lib/middleware.js]"); args.unshift("[greenlock/lib/middleware.js]");
console.log.apply(console, args); console.log.apply(console, args);
} }
} }
module.exports.create = function (le) { module.exports.create = function (gl) {
if (!le.challenges['http-01'] || !le.challenges['http-01'].get) { if (!gl.challenges['http-01'] || !gl.challenges['http-01'].get) {
throw new Error("middleware requires challenge plugin with get method"); throw new Error("middleware requires challenge plugin with get method");
} }
var log = le.log || _log; var log = gl.log || _log;
log(le.debug, "created middleware"); log(gl.debug, "created middleware");
return function (_app) { return function (_app) {
if (_app && 'function' !== typeof _app) { if (_app && 'function' !== typeof _app) {
throw new Error("use le.middleware() or le.middleware(function (req, res) {})"); throw new Error("use greenlock.middleware() or greenlock.middleware(function (req, res) {})");
} }
var prefix = le.acmeChallengePrefix || '/.well-known/acme-challenge/'; var prefix = gl.acmeChallengePrefix || '/.well-known/acme-challenge/';
return function (req, res, next) { return function (req, res, next) {
if (0 !== req.url.indexOf(prefix)) { if (0 !== req.url.indexOf(prefix)) {
log(le.debug, "no match, skipping middleware"); log(gl.debug, "no match, skipping middleware");
if ('function' === typeof _app) { if ('function' === typeof _app) {
_app(req, res, next); _app(req, res, next);
} }
@ -35,24 +35,24 @@ module.exports.create = function (le) {
} }
else { else {
res.statusCode = 500; res.statusCode = 500;
res.end("[500] Developer Error: app.use('/', le.middleware()) or le.middleware(app)"); res.end("[500] Developer Error: app.use('/', greenlock.middleware()) or greenlock.middleware(app)");
} }
return; return;
} }
log(le.debug, "this must be tinder, 'cuz it's a match!"); log(gl.debug, "this must be tinder, 'cuz it's a match!");
var token = req.url.slice(prefix.length); var token = req.url.slice(prefix.length);
var hostname = req.hostname || (req.headers.host || '').toLowerCase().replace(/:.*/, ''); var hostname = req.hostname || (req.headers.host || '').toLowerCase().replace(/:.*/, '');
log(le.debug, "hostname", hostname, "token", token); log(gl.debug, "hostname", hostname, "token", token);
var copy = utils.merge({ domains: [ hostname ] }, le); var copy = utils.merge({ domains: [ hostname ] }, gl);
copy = utils.tplCopy(copy); copy = utils.tplCopy(copy);
// TODO tpl copy? // TODO tpl copy?
// TODO need to restore challengeType // TODO need to restore challengeType
le.challenges['http-01'].get(copy, hostname, token, function (err, secret) { gl.challenges['http-01'].get(copy, hostname, token, function (err, secret) {
if (err || !token) { if (err || !token) {
res.statusCode = 404; res.statusCode = 404;
res.setHeader('Content-Type', 'application/json; charset=utf-8'); res.setHeader('Content-Type', 'application/json; charset=utf-8');

View File

@ -1,6 +1,6 @@
{ {
"name": "greenlock", "name": "greenlock",
"version": "2.2.10", "version": "2.2.12",
"description": "Let's Encrypt for node.js on npm", "description": "Let's Encrypt for node.js on npm",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
@ -65,7 +65,6 @@
"asn1js": "^1.2.12", "asn1js": "^1.2.12",
"certpem": "^1.0.0", "certpem": "^1.0.0",
"homedir": "^0.6.0", "homedir": "^0.6.0",
"le-acme-core": "^2.1.2",
"le-challenge-fs": "^2.0.2", "le-challenge-fs": "^2.0.2",
"le-challenge-sni": "^2.0.0", "le-challenge-sni": "^2.0.0",
"le-sni-auto": "^2.1.3", "le-sni-auto": "^2.1.3",
@ -75,7 +74,7 @@
"rsa-compat": "^1.2.1" "rsa-compat": "^1.2.1"
}, },
"engines": { "engines": {
{ "node" : ">=4.5" } "node" : ">=4.5"
}, },
"gitDependencies": { "gitDependencies": {
"acme-v2": "git+https://git.coolaj86.com/coolaj86/acme-v2.js.git#v1.0", "acme-v2": "git+https://git.coolaj86.com/coolaj86/acme-v2.js.git#v1.0",