Compare commits

..

No commits in common. "eb1d9884051d5d151c0c3eb67c179dcdbdf1db8c" and "51a5bbbe58f58ea86e4cb1702341f4d25f4bb824" have entirely different histories.

7 changed files with 239 additions and 308 deletions

View File

@ -281,8 +281,8 @@ The configuration consists of 3 components:
```javascript ```javascript
'use strict'; 'use strict';
var Greenlock = require('greenlock'); var LE = require('greenlock');
var greenlock; var le;
// Storage Backend // Storage Backend
@ -304,7 +304,7 @@ function leAgree(opts, agreeCb) {
agreeCb(null, opts.tosUrl); agreeCb(null, opts.tosUrl);
} }
greenlock = Greenlock.create({ le = LE.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 @@ greenlock = Greenlock.create({
// If using express you should use the middleware // If using express you should use the middleware
// app.use('/', greenlock.middleware()); // app.use('/', le.middleware());
// //
// Otherwise you should see the test file for usage of this: // Otherwise you should see the test file for usage of this:
// greenlock.challenges['http-01'].get(opts.domain, key, val, done) // le.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
greenlock.check({ domains: [ 'example.com' ] }).then(function (results) { le.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 @@ greenlock.check({ domains: [ 'example.com' ] }).then(function (results) {
// Register Certificate manually // Register Certificate manually
greenlock.register({ le.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 @@ greenlock.check({ domains: [ 'example.com' ] }).then(function (results) {
}, function (err) { }, function (err) {
// Note: you must either use greenlock.middleware() with express, // Note: you must either use le.middleware() with express,
// manually use greenlock.challenges['http-01'].get(opts, domain, key, val, done) // manually use le.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.
``` ```
greenlock.register(opts) le.register(opts)
greenlock.check(opts) le.check(opts)
``` ```
### Helper Functions ### Helper Functions
We do expose a few 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 * LE.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 `greenlock` directly. You probably don't want to use `node-letsencrypt` 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
[greenlock-express](https://git.coolaj86.com/coolaj86/greenlock-express.js). [letsencrypt-express](https://github.com/Daplie/letsencrypt-express).
<https://git.coolaj86.com/coolaj86/greenlock-express.js> <https://github.com/Daplie/letsencrypt-express>
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
[greenlock-cli](https://git.coolaj86.com/coolaj86/greenlock-cli.js). [letsencrypt-cli](https://github.com/Daplie/letsencrypt-cli).
<https://git.coolaj86.com/coolaj86/greenlock-cli.js> <https://github.com/Daplie/letsencrypt-cli>
No, I wanted greenlock No, I wanted node-letsencrypt
====================== =============================
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,10 +5,9 @@ var LE = require('../');
var db = {}; var db = {};
var config = { var config = {
server: 'https://acme-staging-v02.api.letsencrypt.org/directory' server: LE.stagingServerUrl // or LE.productionServerUrl
, version: 'v02'
, configDir: require('os').homedir() + '/acme/etc' // or /etc/acme or wherever , configDir: require('homedir')() + '/letsencrypt/etc' // or /etc/letsencrypt 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
@ -35,7 +34,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 greenlock-cli/bin & greenlock-express/standalone), cb(null, db[key].val); // (see letsencrypt-cli/bin & letsencrypt-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
@ -44,8 +43,6 @@ 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
@ -58,8 +55,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 greenlock-cli and or greenlock-express // See letsencrypt-cli and or letsencrypt-express
console.error('[Error]: greenlock/examples/standalone'); console.error('[Error]: node-letsencrypt/examples/standalone');
console.error(err.stack); console.error(err.stack);
} else { } else {
console.log('success'); console.log('success');

355
index.js
View File

@ -4,9 +4,8 @@ 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 Greenlock = module.exports; var LE = module.exports;
Greenlock.Greenlock = Greenlock; LE.LE = LE;
Greenlock.LE = Greenlock;
// in-process cache, shared between all instances // in-process cache, shared between all instances
var ipc = {}; var ipc = {};
@ -14,14 +13,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("[gl/index.js]"); args.unshift("[le/index.js]");
console.log.apply(console, args); console.log.apply(console, args);
} }
} }
Greenlock.defaults = { LE.defaults = {
productionServerUrl: 'https://acme-v01.api.letsencrypt.org/directory' productionServerUrl: 'https://acme-v02.api.letsencrypt.org/directory'
, stagingServerUrl: 'https://acme-staging.api.letsencrypt.org/directory' , stagingServerUrl: 'https://acme-staging-v02.api.letsencrypt.org/directory'
, rsaKeySize: ACME.rsaKeySize || 2048 , rsaKeySize: ACME.rsaKeySize || 2048
, challengeType: ACME.challengeType || 'http-01' , challengeType: ACME.challengeType || 'http-01'
@ -31,13 +30,13 @@ Greenlock.defaults = {
}; };
// backwards compat // backwards compat
Object.keys(Greenlock.defaults).forEach(function (key) { Object.keys(LE.defaults).forEach(function (key) {
Greenlock[key] = Greenlock.defaults[key]; LE[key] = LE.defaults[key];
}); });
// show all possible options // show all possible options
var u; // undefined var u; // undefined
Greenlock._undefined = { LE._undefined = {
acme: u acme: u
, store: u , store: u
, challenge: u , challenge: u
@ -60,60 +59,78 @@ Greenlock._undefined = {
, duplicate: u , duplicate: u
, _acmeUrls: u , _acmeUrls: u
}; };
Greenlock._undefine = function (gl) { LE._undefine = function (le) {
Object.keys(Greenlock._undefined).forEach(function (key) { Object.keys(LE._undefined).forEach(function (key) {
if (!(key in gl)) { if (!(key in le)) {
gl[key] = u; le[key] = u;
} }
}); });
return gl; return le;
}; };
Greenlock.create = function (gl) { LE.create = function (le) {
var PromiseA = require('bluebird'); var PromiseA = require('bluebird');
gl.store = gl.store || require('le-store-certbot').create({ debug: gl.debug }); le.store = le.store || require('le-store-certbot').create({ debug: le.debug });
gl.core = require('./lib/core'); le.core = require('./lib/core');
var log = gl.log || _log; var log = le.log || _log;
if (!gl.challenges) { if (!le.challenges) {
gl.challenges = {}; le.challenges = {};
} }
if (!gl.challenges['http-01']) { if (!le.challenges['http-01']) {
gl.challenges['http-01'] = require('le-challenge-fs').create({ debug: gl.debug }); le.challenges['http-01'] = require('le-challenge-fs').create({ debug: le.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 {
gl.challenges['dns-01'] = require('le-challenge-ddns').create({ debug: gl.debug }); le.challenges['dns-01'] = require('le-challenge-ddns').create({ debug: le.debug });
} catch(e) { } catch(e) {
try { try {
gl.challenges['dns-01'] = require('le-challenge-dns').create({ debug: gl.debug }); le.challenges['dns-01'] = require('le-challenge-dns').create({ debug: le.debug });
} catch(e) { } catch(e) {
// not yet implemented // not yet implemented
} }
} }
} }
gl = Greenlock._undefine(gl); le = LE._undefine(le);
gl.acmeChallengePrefix = Greenlock.acmeChallengePrefix; le.acmeChallengePrefix = LE.acmeChallengePrefix;
gl.rsaKeySize = gl.rsaKeySize || Greenlock.rsaKeySize; le.rsaKeySize = le.rsaKeySize || LE.rsaKeySize;
gl.challengeType = gl.challengeType || Greenlock.challengeType; le.challengeType = le.challengeType || LE.challengeType;
gl._ipc = ipc; le._ipc = ipc;
gl._communityPackage = gl._communityPackage || 'greenlock.js'; le._communityPackage = le._communityPackage || 'greenlock.js';
gl.agreeToTerms = gl.agreeToTerms || function (args, agreeCb) { le.agreeToTerms = le.agreeToTerms || function (args, agreeCb) {
agreeCb(new Error("'agreeToTerms' was not supplied to Greenlock and 'agreeTos' was not supplied to Greenlock.register")); agreeCb(new Error("'agreeToTerms' was not supplied to LE and 'agreeTos' was not supplied to LE.register"));
}; };
if (!gl.renewWithin) { gl.renewWithin = 14 * DAY; } if (!le.renewWithin) { le.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) {
le.server = LE.stagingServerUrl;
}
else if ('production' === le.server) {
le.server = LE.productionServerUrl;
}
if (-1 !== [ 'https://acme-v01.api.letsencrypt.org/directory'
/////////////////////////// , 'https://acme-staging.api.letsencrypt.org/directory' ].indexOf(le.server)) {
// BEGIN VERSION MADNESS // ACME = require('le-acme-core').ACME;
/////////////////////////// console.warn("Let's Encrypt v1 is deprecated. Please update to Let's Encrypt v2 (ACME draft 11)");
}
if (!gl.version) { else if (-1 !== [ 'https://acme-v02.api.letsencrypt.org/directory'
, 'https://acme-staging-v02.api.letsencrypt.org/directory' ].indexOf(le.server)) {
if ('v02' !== le.version && 'draft-11' !== le.version) {
ACME = require('le-acme-core').ACME;
if ('v01' !== le.version) {
//console.warn("Please specify version: 'v01' (Let's Encrypt v1) or 'draft-11' (Let's Encrypt v2 / ACME draft 11)"); //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("");
@ -124,127 +141,43 @@ Greenlock.create = function (gl) {
console.warn(""); console.warn("");
console.warn("Please specify 'version' option:"); console.warn("Please specify 'version' option:");
console.warn(""); console.warn("");
console.warn(" 'v01' for Let's Encrypt v1");
console.warn(" or");
console.warn(" 'draft-11' for Let's Encrypt v2 and ACME draft 11"); console.warn(" 'draft-11' for Let's Encrypt v2 and ACME draft 11");
console.warn(" ('v02' is an alias of 'draft-11'"); console.warn(" ('v02' is an alias of 'draft-11'");
console.warn(""); console.warn("");
console.warn("or");
console.warn("");
console.warn(" 'v01' for Let's Encrypt v1 (deprecated)");
console.warn("");
console.warn("===================================================================="); console.warn("====================================================================");
console.warn("== this will be required from version v2.3 forward =="); console.warn("== this will be required from version v2.3 forward ==");
console.warn("===================================================================="); console.warn("====================================================================");
console.warn(""); console.warn("");
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 (!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) {
gl.server = 'https://acme-staging.api.letsencrypt.org/directory';
gl.version = 'v01';
console.warn("");
console.warn("");
console.warn("=== WARNING ===");
console.warn("");
console.warn("Due to versioning issues the 'staging' option is deprecated. Please specify the full url and version.");
console.warn("");
console.warn("\t--acme-url '" + gl.server + "' \\");
console.warn("\t--acme-version '" + gl.version + "' \\");
console.warn("");
console.warn("");
}
else if ('production' === gl.server) {
gl.server = 'https://acme-v01.api.letsencrypt.org/directory';
gl.version = 'v01';
console.warn("");
console.warn("");
console.warn("=== WARNING ===");
console.warn("");
console.warn("Due to versioning issues the 'production' option is deprecated. Please specify the full url and version.");
console.warn("");
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. 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);
} }
} }
if (-1 !== [ le.acme = le.acme || ACME.create({ debug: le.debug });
'https://acme-v02.api.letsencrypt.org/directory' if (le.acme.create) {
, 'https://acme-staging-v02.api.letsencrypt.org/directory' ].indexOf(gl.server) le.acme = le.acme.create(le);
) {
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 !== [ le.acme = PromiseA.promisifyAll(le.acme);
'https://acme-v01.api.letsencrypt.org/directory' le._acmeOpts = le.acme.getOptions();
, 'https://acme-staging.api.letsencrypt.org/directory' ].indexOf(gl.server) Object.keys(le._acmeOpts).forEach(function (key) {
|| 'v01' === gl.version if (!(key in le)) {
) { le[key] = le._acmeOpts[key];
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 = 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 (gl.store.create) { if (le.store.create) {
gl.store = gl.store.create(gl); le.store = le.store.create(le);
} }
gl.store = PromiseA.promisifyAll(gl.store); le.store = PromiseA.promisifyAll(le.store);
gl.store.accounts = PromiseA.promisifyAll(gl.store.accounts); le.store.accounts = PromiseA.promisifyAll(le.store.accounts);
gl.store.certificates = PromiseA.promisifyAll(gl.store.certificates); le.store.certificates = PromiseA.promisifyAll(le.store.certificates);
gl._storeOpts = gl.store.getOptions(); le._storeOpts = le.store.getOptions();
Object.keys(gl._storeOpts).forEach(function (key) { Object.keys(le._storeOpts).forEach(function (key) {
if (!(key in gl)) { if (!(key in le)) {
gl[key] = gl._storeOpts[key]; le[key] = le._storeOpts[key];
} }
}); });
@ -252,118 +185,118 @@ Greenlock.create = function (gl) {
// //
// Backwards compat for <= v2.1.7 // Backwards compat for <= v2.1.7
// //
if (gl.challenge) { if (le.challenge) {
console.warn("Deprecated use of gl.challenge. Use gl.challenges['" + Greenlock.challengeType + "'] instead."); console.warn("Deprecated use of le.challenge. Use le.challenges['" + LE.challengeType + "'] instead.");
gl.challenges[gl.challengeType] = gl.challenge; le.challenges[le.challengeType] = le.challenge;
} }
Greenlock.challengeTypes.forEach(function (challengeType) { LE.challengeTypes.forEach(function (challengeType) {
var challenger = gl.challenges[challengeType]; var challenger = le.challenges[challengeType];
if (!challenger) { if (!challenger) {
return; return;
} }
if (challenger.create) { if (challenger.create) {
challenger = gl.challenges[challengeType] = challenger.create(gl); challenger = le.challenges[challengeType] = challenger.create(le);
} }
challenger = gl.challenges[challengeType] = PromiseA.promisifyAll(challenger); challenger = le.challenges[challengeType] = PromiseA.promisifyAll(challenger);
gl['_challengeOpts_' + challengeType] = challenger.getOptions(); le['_challengeOpts_' + challengeType] = challenger.getOptions();
Object.keys(gl['_challengeOpts_' + challengeType]).forEach(function (key) { Object.keys(le['_challengeOpts_' + challengeType]).forEach(function (key) {
if (!(key in gl)) { if (!(key in le)) {
gl[key] = gl['_challengeOpts_' + challengeType][key]; le[key] = le['_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("gl.challenges[" + challengeType + "].set receives the wrong number of arguments." throw new Error("le.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("gl.challenges[" + challengeType + "].get receives the wrong number of arguments." throw new Error("le.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("gl.challenges[" + challengeType + "].remove receives the wrong number of arguments." throw new Error("le.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 (!gl._challengeWarn && (!challenger.loopback || 4 !== challenger.loopback.length)) { if (!le._challengeWarn && (!challenger.loopback || 4 !== challenger.loopback.length)) {
gl._challengeWarn = true; le._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"); 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");
} }
else if (!gl._challengeWarn && (!challenger.test || 5 !== challenger.test.length)) { else if (!le._challengeWarn && (!challenger.test || 5 !== challenger.test.length)) {
gl._challengeWarn = true; le._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"); 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");
} }
*/ */
}); });
gl.sni = gl.sni || null; le.sni = le.sni || null;
gl.tlsOptions = gl.tlsOptions || gl.httpsOptions || {}; le.tlsOptions = le.tlsOptions || le.httpsOptions || {};
if (!gl.tlsOptions.SNICallback) { if (!le.tlsOptions.SNICallback) {
if (!gl.getCertificatesAsync && !gl.getCertificates) { if (!le.getCertificatesAsync && !le.getCertificates) {
if (Array.isArray(gl.approveDomains)) { if (Array.isArray(le.approveDomains)) {
gl.approvedDomains = gl.approveDomains; le.approvedDomains = le.approveDomains;
gl.approveDomains = null; le.approveDomains = null;
} }
if (!gl.approveDomains) { if (!le.approveDomains) {
gl.approvedDomains = gl.approvedDomains || []; le.approvedDomains = le.approvedDomains || [];
gl.approveDomains = function (lexOpts, certs, cb) { le.approveDomains = function (lexOpts, certs, cb) {
if (!gl.email) { if (!le.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 (!gl.agreeTos) { if (!le.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 (!gl.approvedDomains.length) { if (!le.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 !== gl.approvedDomains.indexOf(domain); return -1 !== le.approvedDomains.indexOf(domain);
})) { })) {
lexOpts.domains = gl.approvedDomains.slice(0); lexOpts.domains = le.approvedDomains.slice(0);
lexOpts.email = gl.email; lexOpts.email = le.email;
lexOpts.agreeTos = gl.agreeTos; lexOpts.agreeTos = le.agreeTos;
lexOpts.communityMember = lexOpts.communityMember; lexOpts.communityMember = lexOpts.communityMember;
return cb(null, { options: lexOpts, certs: certs }); return cb(null, { options: lexOpts, certs: certs });
} }
log(gl.debug, 'unapproved domain', lexOpts.domains, gl.approvedDomains); log(le.debug, 'unapproved domain', lexOpts.domains, le.approvedDomains);
cb(new Error("unapproved domain")); cb(new Error("unapproved domain"));
}; };
} }
gl.getCertificates = function (domain, certs, cb) { le.getCertificates = function (domain, certs, cb) {
// certs come from current in-memory cache, not lookup // certs come from current in-memory cache, not lookup
log(gl.debug, 'gl.getCertificates called for', domain, 'with certs for', certs && certs.altnames || 'NONE'); log(le.debug, 'le.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 {
gl.approveDomains(opts, certs, function (_err, results) { le.approveDomains(opts, certs, function (_err, results) {
if (_err) { if (_err) {
log(gl.debug, 'gl.approveDomains called with error', _err); log(le.debug, 'le.approveDomains called with error', _err);
cb(_err); cb(_err);
return; return;
} }
log(gl.debug, 'gl.approveDomains called with certs for', results.certs && results.certs.altnames || 'NONE', 'and options:'); log(le.debug, 'le.approveDomains called with certs for', results.certs && results.certs.altnames || 'NONE', 'and options:');
log(gl.debug, results.options); log(le.debug, results.options);
var promise; var promise;
if (results.certs) { if (results.certs) {
log(gl.debug, 'gl renewing'); log(le.debug, 'le renewing');
promise = gl.core.certificates.renewAsync(results.options, results.certs); promise = le.core.certificates.renewAsync(results.options, results.certs);
} }
else { else {
log(gl.debug, 'gl getting from disk or registering new'); log(le.debug, 'le getting from disk or registering new');
promise = gl.core.certificates.getAsync(results.options); promise = le.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 (gl.debug) { console.debug("Error"); console.debug(e); } if (le.debug) { console.debug("Error"); console.debug(e); }
cb(e); cb(e);
}); });
}); });
@ -374,13 +307,13 @@ Greenlock.create = function (gl) {
} }
}; };
} }
gl.sni = gl.sni || require('le-sni-auto'); le.sni = le.sni || require('le-sni-auto');
if (gl.sni.create) { if (le.sni.create) {
gl.sni = gl.sni.create(gl); le.sni = le.sni.create(le);
} }
gl.tlsOptions.SNICallback = function (domain, cb) { le.tlsOptions.SNICallback = function (domain, cb) {
try { try {
gl.sni.sniCallback(domain, cb); le.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);
@ -391,29 +324,29 @@ Greenlock.create = function (gl) {
// 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.
gl.httpsOptions = gl.tlsOptions; le.httpsOptions = le.tlsOptions;
if (gl.core.create) { if (le.core.create) {
gl.core = gl.core.create(gl); le.core = le.core.create(le);
} }
gl.renew = function (args, certs) { le.renew = function (args, certs) {
return gl.core.certificates.renewAsync(args, certs); return le.core.certificates.renewAsync(args, certs);
}; };
gl.register = function (args) { le.register = function (args) {
return gl.core.certificates.getAsync(args); return le.core.certificates.getAsync(args);
}; };
gl.check = function (args) { le.check = function (args) {
// TODO must return email, domains, tos, pems // TODO must return email, domains, tos, pems
return gl.core.certificates.checkAsync(args); return le.core.certificates.checkAsync(args);
}; };
gl.middleware = gl.middleware || require('./lib/middleware'); le.middleware = le.middleware || require('./lib/middleware');
if (gl.middleware.create) { if (le.middleware.create) {
gl.middleware = gl.middleware.create(gl); le.middleware = le.middleware.create(le);
} }
return gl; return le;
}; };

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("[greenlock/lib/core.js]"); args.unshift("[le/lib/core.js]");
console.log.apply(console, args); console.log.apply(console, args);
} }
} }
module.exports.create = function (gl) { module.exports.create = function (le) {
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 = gl.log || _log; // allow custom log var log = le.log || _log; // allow custom log
var pendingRegistrations = {}; var pendingRegistrations = {};
var core = { var core = {
@ -24,15 +24,15 @@ module.exports.create = function (gl) {
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 - gl._ipc.acmeUrlsUpdatedAt) < 10 * 60 * 1000) { if ((now - le._ipc.acmeUrlsUpdatedAt) < 10 * 60 * 1000) {
return PromiseA.resolve(gl._ipc.acmeUrls); return PromiseA.resolve(le._ipc.acmeUrls);
} }
return gl.acme.getAcmeUrlsAsync(args.server).then(function (data) { return le.acme.getAcmeUrlsAsync(args.server).then(function (data) {
gl._ipc.acmeUrlsUpdatedAt = Date.now(); le._ipc.acmeUrlsUpdatedAt = Date.now();
gl._ipc.acmeUrls = data; le._ipc.acmeUrls = data;
return gl._ipc.acmeUrls; return le._ipc.acmeUrls;
}); });
} }
@ -48,7 +48,7 @@ module.exports.create = function (gl) {
// Accounts // Accounts
registerAsync: function (args) { registerAsync: function (args) {
var err; var err;
var copy = utils.merge(args, gl); var copy = utils.merge(args, le);
var disagreeTos; var disagreeTos;
args = utils.tplCopy(copy); args = utils.tplCopy(copy);
@ -65,20 +65,20 @@ module.exports.create = function (gl) {
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 = gl.store.accounts.checkKeypairAsync(args).then(function (keypair) { var promise = le.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 gl.store.accounts.setKeypairAsync(args, RSA.import(args.accountKeypair)); return le.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 gl.store.accounts.setKeypairAsync(args, keypair); return le.store.accounts.setKeypairAsync(args, keypair);
}); });
}); });
@ -88,11 +88,11 @@ module.exports.create = function (gl) {
return core.getAcmeUrlsAsync(args).then(function (urls) { return core.getAcmeUrlsAsync(args).then(function (urls) {
args._acmeUrls = urls; args._acmeUrls = urls;
return gl.acme.registerNewAccountAsync({ return le.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 === gl.agreeToTerms) { if (true === args.agreeTos || tosUrl === args.agreeTos || tosUrl === le.agreeToTerms) {
agreeCb(null, tosUrl); agreeCb(null, tosUrl);
return; return;
} }
@ -100,11 +100,11 @@ module.exports.create = function (gl) {
// 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;
gl.agreeToTerms(args, agreeCb); le.agreeToTerms(args, agreeCb);
} }
, accountKeypair: keypair , accountKeypair: keypair
, debug: gl.debug || args.debug , debug: le.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 (gl) {
}; };
// TODO move templating of arguments to right here? // TODO move templating of arguments to right here?
return gl.store.accounts.setAsync(args, reg).then(function (account) { return le.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 (gl) {
)); ));
} }
var copy = utils.merge(args, gl); var copy = utils.merge(args, le);
args = utils.tplCopy(copy); args = utils.tplCopy(copy);
return gl.store.accounts.checkAsync(args).then(function (account) { return le.store.accounts.checkAsync(args).then(function (account) {
if (!account) { if (!account) {
return null; return null;
@ -166,9 +166,9 @@ module.exports.create = function (gl) {
// Certificates // Certificates
registerAsync: function (args) { registerAsync: function (args) {
var err; var err;
var challengeDefaults = gl['_challengeOpts_' + (args.challengeType || gl.challengeType)] || {}; var challengeDefaults = le['_challengeOpts_' + (args.challengeType || le.challengeType)] || {};
var copy = utils.merge(args, challengeDefaults || {}); var copy = utils.merge(args, challengeDefaults || {});
copy = utils.merge(copy, gl); copy = utils.merge(copy, le);
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 (gl) {
return core.accounts.getAsync(args).then(function (account) { return core.accounts.getAsync(args).then(function (account) {
args.account = account; args.account = account;
var promise = gl.store.certificates.checkKeypairAsync(args).then(function (keypair) { var promise = le.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 gl.store.certificates.setKeypairAsync(args, RSA.import(args.domainKeypair)); return le.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 (gl) {
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 gl.store.certificates.setKeypairAsync(args, keypair); return le.store.certificates.setKeypairAsync(args, keypair);
}); });
}); });
@ -252,7 +252,7 @@ module.exports.create = function (gl) {
args._acmeUrls = urls; args._acmeUrls = urls;
var certReq = { var certReq = {
debug: args.debug || gl.debug debug: args.debug || le.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 (gl) {
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, gl); copy = utils.merge(copy, le);
utils.tplCopy(copy); utils.tplCopy(copy);
// TODO need to save challengeType // TODO need to save challengeType
gl.challenges[args.challengeType].set(copy, domain, key, value, done); le.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] }, gl); var copy = utils.merge({ domains: [domain] }, le);
utils.tplCopy(copy); utils.tplCopy(copy);
gl.challenges[args.challengeType].remove(copy, domain, key, done); le.challenges[args.challengeType].remove(copy, domain, key, done);
}; };
log(args.debug, 'calling greenlock.acme.getCertificateAsync', certReq.domains); log(args.debug, 'calling le.acme.getCertificateAsync', certReq.domains);
return gl.acme.getCertificateAsync(certReq).then(utils.attachCertInfo); return le.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 (gl) {
args.certs = results; args.certs = results;
// args.pems is deprecated // args.pems is deprecated
args.pems = results; args.pems = results;
return gl.store.certificates.setAsync(args).then(function () { return le.store.certificates.setAsync(args).then(function () {
return results; return results;
}); });
}); });
@ -362,14 +362,14 @@ module.exports.create = function (gl) {
return false; return false;
} }
, _getRenewableAt: function (args, certs) { , _getRenewableAt: function (args, certs) {
return certs.expiresAt - (args.renewWithin || gl.renewWithin); return certs.expiresAt - (args.renewWithin || le.renewWithin);
} }
, checkAsync: function (args) { , checkAsync: function (args) {
var copy = utils.merge(args, gl); var copy = utils.merge(args, le);
utils.tplCopy(copy); utils.tplCopy(copy);
// returns pems // returns pems
return gl.store.certificates.checkAsync(copy).then(function (cert) { return le.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 (gl) {
} }
// Certificates // Certificates
, getAsync: function (args) { , getAsync: function (args) {
var copy = utils.merge(args, gl); var copy = utils.merge(args, le);
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("[greenlock/lib/middleware.js]"); args.unshift("[le/lib/middleware.js]");
console.log.apply(console, args); console.log.apply(console, args);
} }
} }
module.exports.create = function (gl) { module.exports.create = function (le) {
if (!gl.challenges['http-01'] || !gl.challenges['http-01'].get) { if (!le.challenges['http-01'] || !le.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 = gl.log || _log; var log = le.log || _log;
log(gl.debug, "created middleware"); log(le.debug, "created middleware");
return function (_app) { return function (_app) {
if (_app && 'function' !== typeof _app) { if (_app && 'function' !== typeof _app) {
throw new Error("use greenlock.middleware() or greenlock.middleware(function (req, res) {})"); throw new Error("use le.middleware() or le.middleware(function (req, res) {})");
} }
var prefix = gl.acmeChallengePrefix || '/.well-known/acme-challenge/'; var prefix = le.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(gl.debug, "no match, skipping middleware"); log(le.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 (gl) {
} }
else { else {
res.statusCode = 500; res.statusCode = 500;
res.end("[500] Developer Error: app.use('/', greenlock.middleware()) or greenlock.middleware(app)"); res.end("[500] Developer Error: app.use('/', le.middleware()) or le.middleware(app)");
} }
return; return;
} }
log(gl.debug, "this must be tinder, 'cuz it's a match!"); log(le.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(gl.debug, "hostname", hostname, "token", token); log(le.debug, "hostname", hostname, "token", token);
var copy = utils.merge({ domains: [ hostname ] }, gl); var copy = utils.merge({ domains: [ hostname ] }, le);
copy = utils.tplCopy(copy); copy = utils.tplCopy(copy);
// TODO tpl copy? // TODO tpl copy?
// TODO need to restore challengeType // TODO need to restore challengeType
gl.challenges['http-01'].get(copy, hostname, token, function (err, secret) { le.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.12", "version": "2.2.10",
"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,6 +65,7 @@
"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",
@ -74,7 +75,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",