v3.0.2: various bugfixes
This commit is contained in:
parent
6fdafec304
commit
3f2e0cd6e4
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"bracketSpacing": true,
|
||||
"printWidth": 80,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 4,
|
||||
"trailingComma": "none",
|
||||
"useTabs": true
|
||||
}
|
73
README.md
73
README.md
|
@ -55,35 +55,50 @@ var gl = Greenlock.create({
|
|||
|
||||
// This should be the contact who receives critical bug and security notifications
|
||||
// Optionally, you may receive other (very few) updates, such as important new features
|
||||
maintainerEmail: 'jon@example.com',
|
||||
maintainerUpdates: true, // default: false
|
||||
maintainerEmail: 'jon@example.com'
|
||||
});
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| --------------- | ------------------------------------------------------------------------------------ |
|
||||
| maintainerEmail | the developer contact for critical bug and security notifications |
|
||||
| packageAgent | if you publish your package for others to use, `require('./package.json').name` here |
|
||||
|
||||
<!--
|
||||
| maintainerUpdates | (default: false) receive occasional non-critical notifications |
|
||||
maintainerUpdates: true // default: false
|
||||
-->
|
||||
|
||||
### Add Approved Domains
|
||||
|
||||
```js
|
||||
greenlock.manager.defaults({
|
||||
// The "Let's Encrypt Subscriber" (often the same as the maintainer)
|
||||
// NOT the end customer (except where that is also the maintainer)
|
||||
subscriberEmail: 'jon@example.com',
|
||||
agreeToTerms: true // default: false
|
||||
agreeToTerms: true
|
||||
});
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| servername | the default servername to use for non-sni requests (many IoT clients) |
|
||||
| maintainerEmail | the developer contact for critical bug and security notifications |
|
||||
| maintainerUpdates | (default: false) receive occasional non-critical notifications |
|
||||
| maintainerPackage | if you publish your package for others to use, `require('./package.json').name` here |
|
||||
| maintainerPackageVersion | if you publish your package for others to use, `require('./package.json').version` here |
|
||||
| subscriberEmail | the contact who agrees to the Let's Encrypt Subscriber Agreement and the Greenlock Terms of Service<br>this contact receives renewal failure notifications |
|
||||
| agreeToTerms | (default: false) either 'true' or a function that presents the Terms of Service and returns it once accepted |
|
||||
| store | override the default storage module |
|
||||
| store.module | the name of your storage module |
|
||||
| store.xxxx | options specific to your storage module |
|
||||
| challenges['http-01'] | provide an http-01 challenge module |
|
||||
| challenges['dns-01'] | provide a dns-01 challenge module |
|
||||
| challenges['tls-alpn-01'] | provide a tls-alpn-01 challenge module |
|
||||
| challenges[type].module | the name of your challenge module |
|
||||
| challenges[type].xxxx | module-specific options |
|
||||
| servername | the default servername to use for non-sni requests (many IoT clients) |
|
||||
| subscriberEmail | the contact who agrees to the Let's Encrypt Subscriber Agreement and the Greenlock Terms of Service<br>this contact receives renewal failure notifications |
|
||||
| store | override the default storage module |
|
||||
| store.module | the name of your storage module |
|
||||
| store.xxxx | options specific to your storage module |
|
||||
|
||||
### Add Approved Domains
|
||||
<!--
|
||||
|
||||
| serverId | an arbitrary name to distinguish this server within a cluster of servers |
|
||||
|
||||
-->
|
||||
|
||||
```js
|
||||
gl.add({
|
||||
|
@ -104,26 +119,24 @@ gl.add({
|
|||
This will renew only domains that have reached their `renewAt` or are within the befault `renewOffset`.
|
||||
|
||||
```js
|
||||
return greenlock
|
||||
.renew()
|
||||
.then(function(pems) {
|
||||
console.info(pems);
|
||||
})
|
||||
.then(function(results) {
|
||||
results.forEach(function(site) {
|
||||
if (site.error) {
|
||||
console.error(site.subject, site.error);
|
||||
return;
|
||||
}
|
||||
});
|
||||
return greenlock.renew().then(function(results) {
|
||||
results.forEach(function(site) {
|
||||
if (site.error) {
|
||||
console.error(site.subject, site.error);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| ---------- | ---- | ---------------------------------------------------------- |
|
||||
| (optional) | - | ALL parameters are optional, but some should be paired |
|
||||
| force | bool | force silly options, such as tiny durations |
|
||||
| duplicate | bool | force the domain to renew, regardless of age or expiration |
|
||||
| Parameter | Type | Description |
|
||||
| ------------- | ---- | ------------------------------------------------------------------------------- |
|
||||
| (optional) | | ALL parameters are optional, but some should be paired |
|
||||
| force | bool | force silly options, such as tiny durations |
|
||||
| duplicate | bool | force the domain to renew, regardless of age or expiration |
|
||||
| issuedBefore | ms | Check domains issued before the given date in milliseconds |
|
||||
| expiresBefore | ms | Check domains that expire before the given date in milliseconds |
|
||||
| renewBefore | ms | Check domains that are scheduled to renew before the given date in milliseconds |
|
||||
|
||||
<!--
|
||||
| servername | string<br>hostname | renew the certificate that has this domain in its altnames (for ServerName Indication / SNI lookup) |
|
||||
|
|
|
@ -178,7 +178,7 @@ function toCamel(str) {
|
|||
|
||||
function toBagName(bag) {
|
||||
// trim leading and trailing '-'
|
||||
bag = bag.replace(/^-+/g, '').replace(/-+$/g, '')
|
||||
bag = bag.replace(/^-+/g, '').replace(/-+$/g, '');
|
||||
return toCamel(bag) + 'Opts'; // '--bag-option-' => bagOptionOpts
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
var args = process.argv.slice(2);
|
||||
console.log(args);
|
||||
if ('certonly' === args[0]) {
|
||||
require('./certonly.js');
|
||||
return;
|
||||
require('./certonly.js');
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -56,60 +56,48 @@ C._getOrOrder = function(gnlck, mconf, db, acme, chs, acc, args) {
|
|||
// Certificates
|
||||
C._rawGetOrOrder = function(gnlck, mconf, db, acme, chs, acc, email, args) {
|
||||
return C._check(gnlck, mconf, db, args).then(function(pems) {
|
||||
// No pems? get some!
|
||||
if (!pems) {
|
||||
return C._rawOrder(
|
||||
gnlck,
|
||||
mconf,
|
||||
db,
|
||||
acme,
|
||||
chs,
|
||||
acc,
|
||||
email,
|
||||
args
|
||||
).then(function(newPems) {
|
||||
// do not wait on notify
|
||||
gnlck._notify('cert_issue', {
|
||||
options: args,
|
||||
subject: args.subject,
|
||||
altnames: args.altnames,
|
||||
account: acc,
|
||||
email: email,
|
||||
pems: newPems
|
||||
});
|
||||
return newPems;
|
||||
});
|
||||
}
|
||||
|
||||
// Nice and fresh? We're done!
|
||||
if (!C._isStale(gnlck, mconf, args, pems)) {
|
||||
// return existing unexpired (although potentially stale) certificates when available
|
||||
// there will be an additional .renewing property if the certs are being asynchronously renewed
|
||||
//pems._type = 'current';
|
||||
return pems;
|
||||
if (pems) {
|
||||
if (!C._isStale(gnlck, mconf, args, pems)) {
|
||||
// return existing unexpired (although potentially stale) certificates when available
|
||||
// there will be an additional .renewing property if the certs are being asynchronously renewed
|
||||
//pems._type = 'current';
|
||||
return pems;
|
||||
}
|
||||
}
|
||||
|
||||
// Getting stale? Let's renew to freshen up!
|
||||
var p = C._rawOrder(gnlck, mconf, db, acme, chs, acc, email, args).then(
|
||||
function(renewedPems) {
|
||||
// do not wait on notify
|
||||
gnlck._notify('cert_renewal', {
|
||||
options: args,
|
||||
subject: args.subject,
|
||||
altnames: args.altnames,
|
||||
account: acc,
|
||||
email: email,
|
||||
pems: renewedPems
|
||||
});
|
||||
return renewedPems;
|
||||
// We're either starting fresh or freshening up...
|
||||
var p = C._rawOrder(gnlck, mconf, db, acme, chs, acc, email, args);
|
||||
var evname = pems ? 'cert_renewal' : 'cert_issue';
|
||||
p.then(function(newPems) {
|
||||
// notify in the background
|
||||
var renewAt = C._renewableAt(gnlck, mconf, args, newPems);
|
||||
gnlck._notify(evname, {
|
||||
renewAt: renewAt,
|
||||
subject: args.subject,
|
||||
altnames: args.altnames
|
||||
});
|
||||
}).catch(function(err) {
|
||||
if (!err.context) {
|
||||
err.context = evname;
|
||||
}
|
||||
);
|
||||
err.subject = args.subject;
|
||||
err.altnames = args.altnames;
|
||||
gnlck._notify('error', err);
|
||||
});
|
||||
|
||||
// TODO what should this be?
|
||||
// No choice but to hang tight and wait for it
|
||||
if (!pems) {
|
||||
return p;
|
||||
}
|
||||
|
||||
// Wait it out
|
||||
// TODO should we call this waitForRenewal?
|
||||
if (args.waitForRenewal) {
|
||||
return p;
|
||||
}
|
||||
|
||||
// Let the certs renew in the background
|
||||
return pems;
|
||||
});
|
||||
};
|
||||
|
@ -177,6 +165,15 @@ C._rawOrder = function(gnlck, mconf, db, acme, chs, acc, email, args) {
|
|||
.then(U._attachCertInfo);
|
||||
})
|
||||
.then(function(pems) {
|
||||
var renewAt = C._renewableAt(gnlck, mconf, args, pems);
|
||||
|
||||
gnlck._notify('_cert_issue', {
|
||||
renewAt: renewAt,
|
||||
subject: args.subject,
|
||||
altnames: args.altnames,
|
||||
pems: pems
|
||||
});
|
||||
|
||||
if (kresult.exists) {
|
||||
return pems;
|
||||
}
|
||||
|
|
42
express.js
42
express.js
|
@ -1,42 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var Greenlock = module.exports;
|
||||
|
||||
Greenlock.server = function (opts) {
|
||||
var opts = Greenlock.create(opts);
|
||||
|
||||
opts.plainMiddleware = function(req, res) {
|
||||
return Greenlock._plainMiddleware(opts, req, res);
|
||||
};
|
||||
|
||||
opts.secureMiddleware = function(req, res) {
|
||||
return Greenlock._secureMiddleware(opts, req, res);
|
||||
};
|
||||
|
||||
opts.tlsOptions = {
|
||||
SNICallback: function(servername, cb) {
|
||||
return Greenlock._sniCallback(opts, servername)
|
||||
.then(function() {
|
||||
cb(null);
|
||||
})
|
||||
.catch(function(err) {
|
||||
cb(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return opts;
|
||||
};
|
||||
|
||||
// must handle http-01 challenges
|
||||
Greenlock._plainMiddleware = function(opts, req, res) {};
|
||||
|
||||
// should check for domain fronting
|
||||
Greenlock._secureMiddleware = function(opts, req, res) {};
|
||||
|
||||
// should check to see if domain is allowed, and if domain should be renewed
|
||||
// manage should be able to clear the internal cache
|
||||
Greenlock._sniCallback = function(opts, servername) {};
|
||||
|
||||
Greenlock._onSniRejection(function () {
|
||||
});
|
267
greenlock.js
267
greenlock.js
|
@ -65,12 +65,13 @@ G.create = function(gconf) {
|
|||
var defaults = G._defaults(gconf);
|
||||
|
||||
greenlock.manager = Manager.create(defaults);
|
||||
//console.log('debug greenlock.manager', Object.keys(greenlock.manager));
|
||||
greenlock._init = function() {
|
||||
var p;
|
||||
greenlock._init = function() {
|
||||
return p;
|
||||
};
|
||||
p = greenlock.manager.config().then(function(conf) {
|
||||
p = greenlock.manager.defaults().then(function(conf) {
|
||||
var changed = false;
|
||||
if (!conf.challenges) {
|
||||
changed = true;
|
||||
|
@ -81,7 +82,7 @@ G.create = function(gconf) {
|
|||
conf.store = defaults.store;
|
||||
}
|
||||
if (changed) {
|
||||
return greenlock.manager.config(conf);
|
||||
return greenlock.manager.defaults(conf);
|
||||
}
|
||||
});
|
||||
return p;
|
||||
|
@ -154,6 +155,26 @@ G.create = function(gconf) {
|
|||
|
||||
greenlock._notify = function(ev, params) {
|
||||
var mng = greenlock.manager;
|
||||
|
||||
if ('_' === String(ev)[0]) {
|
||||
if ('_cert_issue' === ev) {
|
||||
try {
|
||||
mng.update({
|
||||
subject: params.subject,
|
||||
renewAt: params.renewAt
|
||||
}).catch(function(e) {
|
||||
e.context = '_cert_issue';
|
||||
greenlock._notify('error', e);
|
||||
});
|
||||
} catch (e) {
|
||||
e.context = '_cert_issue';
|
||||
greenlock._notify('error', e);
|
||||
}
|
||||
}
|
||||
// trap internal events internally
|
||||
return;
|
||||
}
|
||||
|
||||
if (mng.notify || greenlock._defaults.notify) {
|
||||
try {
|
||||
var p = (mng.notify || greenlock._defaults.notify)(ev, params);
|
||||
|
@ -193,23 +214,109 @@ G.create = function(gconf) {
|
|||
// { name, version, email, domains, action, communityMember, telemetry }
|
||||
// TODO look at the other one
|
||||
UserEvents.notify({
|
||||
/*
|
||||
// maintainer should be only on pre-publish, or maybe install, I think
|
||||
maintainerEmail: greenlock._defaults._maintainerEmail,
|
||||
name: greenlock._defaults._maintainerPackage,
|
||||
version: greenlock._defaults._maintainerPackageVersion,
|
||||
action: params.pems._type,
|
||||
//action: params.pems._type,
|
||||
domains: params.altnames,
|
||||
subscriberEmail: greenlock._defaults._subscriberEmail,
|
||||
// TODO enable for Greenlock Pro
|
||||
//customerEmail: args.customerEmail
|
||||
telemetry: greenlock._defaults.telemetry
|
||||
*/
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
greenlock._single = function(args) {
|
||||
if (!args.servername) {
|
||||
return Promise.reject(new Error('no servername given'));
|
||||
}
|
||||
if (
|
||||
args.servernames ||
|
||||
args.subject ||
|
||||
args.renewBefore ||
|
||||
args.issueBefore ||
|
||||
args.expiresBefore
|
||||
) {
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
'bad arguments, did you mean to call greenlock.renew()?'
|
||||
)
|
||||
);
|
||||
}
|
||||
// duplicate, force, and others still allowed
|
||||
return Promise.resolve(args);
|
||||
};
|
||||
|
||||
greenlock.get = function(args) {
|
||||
return greenlock
|
||||
._single(args)
|
||||
.then(function() {
|
||||
args._includePems = true;
|
||||
return greenlock.renew(args);
|
||||
})
|
||||
.then(function(results) {
|
||||
if (!results || !results.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// just get the first one
|
||||
var result = results[0];
|
||||
|
||||
// (there should be only one, ideally)
|
||||
if (results.length > 1) {
|
||||
var err = new Error(
|
||||
"a search for '" +
|
||||
args.servername +
|
||||
"' returned multiple certificates"
|
||||
);
|
||||
err.context = 'duplicate_certs';
|
||||
err.servername = args.servername;
|
||||
err.subjects = results.map(function(r) {
|
||||
return (r.site || {}).subject || 'N/A';
|
||||
});
|
||||
|
||||
greenlock._notify('warning', err);
|
||||
}
|
||||
|
||||
if (result.error) {
|
||||
return Promise.reject(result.error);
|
||||
}
|
||||
|
||||
// site for plugin options, such as http-01 challenge
|
||||
// pems for the obvious reasons
|
||||
return result;
|
||||
});
|
||||
};
|
||||
|
||||
greenlock._config = function(args) {
|
||||
return greenlock
|
||||
._single(args)
|
||||
.then(function() {
|
||||
return greenlock.manager.find(args);
|
||||
})
|
||||
.then(function(sites) {
|
||||
if (!sites || !sites.length) {
|
||||
return null;
|
||||
}
|
||||
var site = sites[0];
|
||||
site = JSON.parse(JSON.stringify(site));
|
||||
if (!site.store) {
|
||||
site.store = greenlock._defaults.store;
|
||||
}
|
||||
if (!site.challenges) {
|
||||
site.challenges = greenlock._defaults.challenges;
|
||||
}
|
||||
return site;
|
||||
});
|
||||
};
|
||||
|
||||
// needs to get info about the renewal, such as which store and challenge(s) to use
|
||||
greenlock.renew = function(args) {
|
||||
return greenlock.manager.config().then(function(mconf) {
|
||||
return greenlock.manager.defaults().then(function(mconf) {
|
||||
return greenlock._renew(mconf, args);
|
||||
});
|
||||
};
|
||||
|
@ -226,15 +333,16 @@ G.create = function(gconf) {
|
|||
args.renewStagger = U._parseDuration(args.renewStagger);
|
||||
}
|
||||
|
||||
if (args.domain) {
|
||||
if (args.servername) {
|
||||
// this doesn't have to be the subject, it can be anything
|
||||
// however, not sure how useful this really is...
|
||||
args.domain = args.toLowerCase();
|
||||
args.servername = args.servername.toLowerCase();
|
||||
}
|
||||
|
||||
args.defaults = greenlock.defaults;
|
||||
//console.log('greenlock._renew find', args);
|
||||
return greenlock.manager.find(args).then(function(sites) {
|
||||
// Note: the manager must guaranteed that these are mutable copies
|
||||
//console.log('greenlock._renew found', sites);
|
||||
|
||||
var renewedOrFailed = [];
|
||||
|
||||
|
@ -244,25 +352,28 @@ G.create = function(gconf) {
|
|||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
var order = {
|
||||
site: site
|
||||
};
|
||||
var order = { site: site };
|
||||
renewedOrFailed.push(order);
|
||||
// TODO merge args + result?
|
||||
return greenlock
|
||||
._order(mconf, site)
|
||||
.then(function(pems) {
|
||||
order.pems = pems;
|
||||
if (args._includePems) {
|
||||
order.pems = pems;
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
order.error = err;
|
||||
|
||||
// For greenlock express serialization
|
||||
err.toJSON = errorToJSON;
|
||||
err.context = err.context || 'cert_order';
|
||||
err.subject = site.subject;
|
||||
if (args.servername) {
|
||||
err.servername = args.servername;
|
||||
}
|
||||
// for debugging, but not to be relied on
|
||||
err._order = order;
|
||||
err._site = site;
|
||||
// TODO err.context = err.context || 'renew_certificate'
|
||||
greenlock._notify('error', err);
|
||||
})
|
||||
|
@ -312,20 +423,16 @@ G.create = function(gconf) {
|
|||
|
||||
greenlock.order = function(args) {
|
||||
return greenlock._init().then(function() {
|
||||
return greenlock.manager.config().then(function(mconf) {
|
||||
return greenlock.manager.defaults().then(function(mconf) {
|
||||
return greenlock._order(mconf, args);
|
||||
});
|
||||
});
|
||||
};
|
||||
greenlock._order = function(mconf, args) {
|
||||
// packageAgent, maintainerEmail
|
||||
return greenlock._acme(args).then(function(acme) {
|
||||
var storeConf = args.store || greenlock._defaults.store;
|
||||
return P._load(storeConf.module).then(function(plugin) {
|
||||
var store = Greenlock._normalizeStore(
|
||||
storeConf.module,
|
||||
plugin.create(storeConf)
|
||||
);
|
||||
|
||||
return P._loadStore(storeConf).then(function(store) {
|
||||
return A._getOrCreate(
|
||||
greenlock,
|
||||
mconf,
|
||||
|
@ -339,17 +446,7 @@ G.create = function(gconf) {
|
|||
greenlock._defaults.challenges;
|
||||
return Promise.all(
|
||||
Object.keys(challengeConfs).map(function(typ01) {
|
||||
var chConf = challengeConfs[typ01];
|
||||
return P._load(chConf.module).then(function(
|
||||
plugin
|
||||
) {
|
||||
var ch = Greenlock._normalizeChallenge(
|
||||
chConf.module,
|
||||
plugin.create(chConf)
|
||||
);
|
||||
ch._type = typ01;
|
||||
return ch;
|
||||
});
|
||||
return P._loadChallenge(challengeConfs, typ01);
|
||||
})
|
||||
).then(function(arr) {
|
||||
var challenges = {};
|
||||
|
@ -390,6 +487,8 @@ G.create = function(gconf) {
|
|||
return greenlock;
|
||||
};
|
||||
|
||||
G._loadChallenge = P._loadChallenge;
|
||||
|
||||
G._defaults = function(opts) {
|
||||
var defaults = {};
|
||||
|
||||
|
@ -503,114 +602,6 @@ G._defaults = function(opts) {
|
|||
return defaults;
|
||||
};
|
||||
|
||||
Greenlock._normalizeStore = function(name, store) {
|
||||
var acc = store.accounts;
|
||||
var crt = store.certificates;
|
||||
|
||||
var warned = false;
|
||||
function warn() {
|
||||
if (warned) {
|
||||
return;
|
||||
}
|
||||
warned = true;
|
||||
console.warn(
|
||||
"'" +
|
||||
name +
|
||||
"' may have incorrect function signatures, or contains deprecated use of callbacks"
|
||||
);
|
||||
}
|
||||
|
||||
// accs
|
||||
if (acc.check && 2 === acc.check.length) {
|
||||
warn();
|
||||
acc._thunk_check = acc.check;
|
||||
acc.check = promisify(acc._thunk_check);
|
||||
}
|
||||
if (acc.set && 3 === acc.set.length) {
|
||||
warn();
|
||||
acc._thunk_set = acc.set;
|
||||
acc.set = promisify(acc._thunk_set);
|
||||
}
|
||||
if (2 === acc.checkKeypair.length) {
|
||||
warn();
|
||||
acc._thunk_checkKeypair = acc.checkKeypair;
|
||||
acc.checkKeypair = promisify(acc._thunk_checkKeypair);
|
||||
}
|
||||
if (3 === acc.setKeypair.length) {
|
||||
warn();
|
||||
acc._thunk_setKeypair = acc.setKeypair;
|
||||
acc.setKeypair = promisify(acc._thunk_setKeypair);
|
||||
}
|
||||
|
||||
// certs
|
||||
if (2 === crt.check.length) {
|
||||
warn();
|
||||
crt._thunk_check = crt.check;
|
||||
crt.check = promisify(crt._thunk_check);
|
||||
}
|
||||
if (3 === crt.set.length) {
|
||||
warn();
|
||||
crt._thunk_set = crt.set;
|
||||
crt.set = promisify(crt._thunk_set);
|
||||
}
|
||||
if (2 === crt.checkKeypair.length) {
|
||||
warn();
|
||||
crt._thunk_checkKeypair = crt.checkKeypair;
|
||||
crt.checkKeypair = promisify(crt._thunk_checkKeypair);
|
||||
}
|
||||
if (2 === crt.setKeypair.length) {
|
||||
warn();
|
||||
crt._thunk_setKeypair = crt.setKeypair;
|
||||
crt.setKeypair = promisify(crt._thunk_setKeypair);
|
||||
}
|
||||
|
||||
return store;
|
||||
};
|
||||
|
||||
Greenlock._normalizeChallenge = function(name, ch) {
|
||||
var warned = false;
|
||||
function warn() {
|
||||
if (warned) {
|
||||
return;
|
||||
}
|
||||
warned = true;
|
||||
console.warn(
|
||||
"'" +
|
||||
name +
|
||||
"' may have incorrect function signatures, or contains deprecated use of callbacks"
|
||||
);
|
||||
}
|
||||
|
||||
// init, zones, set, get, remove
|
||||
if (ch.init && 2 === ch.init.length) {
|
||||
warn();
|
||||
ch._thunk_init = ch.init;
|
||||
ch.init = promisify(ch._thunk_init);
|
||||
}
|
||||
if (ch.zones && 2 === ch.zones.length) {
|
||||
warn();
|
||||
ch._thunk_zones = ch.zones;
|
||||
ch.zones = promisify(ch._thunk_zones);
|
||||
}
|
||||
if (2 === ch.set.length) {
|
||||
warn();
|
||||
ch._thunk_set = ch.set;
|
||||
ch.set = promisify(ch._thunk_set);
|
||||
}
|
||||
if (2 === ch.remove.length) {
|
||||
warn();
|
||||
ch._thunk_remove = ch.remove;
|
||||
ch.remove = promisify(ch._thunk_remove);
|
||||
}
|
||||
if (ch.get && 2 === ch.get.length) {
|
||||
warn();
|
||||
ch._thunk_get = ch.get;
|
||||
ch.get = promisify(ch._thunk_get);
|
||||
}
|
||||
|
||||
return ch;
|
||||
};
|
||||
|
||||
function errorToJSON(e) {
|
||||
var error = {};
|
||||
Object.getOwnPropertyNames(e).forEach(function(k) {
|
||||
|
|
176
order.js
176
order.js
|
@ -1,97 +1,95 @@
|
|||
var accountKeypair = await Keypairs.generate({ kty: accKty });
|
||||
var accountKeypair = await Keypairs.generate({ kty: accKty });
|
||||
if (config.debug) {
|
||||
console.info('Account Key Created');
|
||||
console.info(JSON.stringify(accountKeypair, null, 2));
|
||||
console.info();
|
||||
console.info();
|
||||
}
|
||||
|
||||
var account = await acme.accounts.create({
|
||||
agreeToTerms: agree,
|
||||
// TODO detect jwk/pem/der?
|
||||
accountKeypair: { privateKeyJwk: accountKeypair.private },
|
||||
subscriberEmail: config.email
|
||||
});
|
||||
|
||||
// TODO top-level agree
|
||||
function agree(tos) {
|
||||
if (config.debug) {
|
||||
console.info('Account Key Created');
|
||||
console.info(JSON.stringify(accountKeypair, null, 2));
|
||||
console.info('Agreeing to Terms of Service:');
|
||||
console.info(tos);
|
||||
console.info();
|
||||
console.info();
|
||||
}
|
||||
agreed = true;
|
||||
return Promise.resolve(tos);
|
||||
}
|
||||
if (config.debug) {
|
||||
console.info('New Subscriber Account');
|
||||
console.info(JSON.stringify(account, null, 2));
|
||||
console.info();
|
||||
console.info();
|
||||
}
|
||||
if (!agreed) {
|
||||
throw new Error('Failed to ask the user to agree to terms');
|
||||
}
|
||||
|
||||
var account = await acme.accounts.create({
|
||||
agreeToTerms: agree,
|
||||
// TODO detect jwk/pem/der?
|
||||
accountKeypair: { privateKeyJwk: accountKeypair.private },
|
||||
subscriberEmail: config.email
|
||||
});
|
||||
var certKeypair = await Keypairs.generate({ kty: srvKty });
|
||||
var pem = await Keypairs.export({
|
||||
jwk: certKeypair.private,
|
||||
encoding: 'pem'
|
||||
});
|
||||
if (config.debug) {
|
||||
console.info('Server Key Created');
|
||||
console.info('privkey.jwk.json');
|
||||
console.info(JSON.stringify(certKeypair, null, 2));
|
||||
// This should be saved as `privkey.pem`
|
||||
console.info();
|
||||
console.info('privkey.' + srvKty.toLowerCase() + '.pem:');
|
||||
console.info(pem);
|
||||
console.info();
|
||||
}
|
||||
|
||||
// TODO top-level agree
|
||||
function agree(tos) {
|
||||
if (config.debug) {
|
||||
console.info('Agreeing to Terms of Service:');
|
||||
console.info(tos);
|
||||
console.info();
|
||||
console.info();
|
||||
}
|
||||
agreed = true;
|
||||
return Promise.resolve(tos);
|
||||
}
|
||||
if (config.debug) {
|
||||
console.info('New Subscriber Account');
|
||||
console.info(JSON.stringify(account, null, 2));
|
||||
console.info();
|
||||
console.info();
|
||||
}
|
||||
if (!agreed) {
|
||||
throw new Error('Failed to ask the user to agree to terms');
|
||||
}
|
||||
|
||||
var certKeypair = await Keypairs.generate({ kty: srvKty });
|
||||
var pem = await Keypairs.export({
|
||||
jwk: certKeypair.private,
|
||||
encoding: 'pem'
|
||||
});
|
||||
if (config.debug) {
|
||||
console.info('Server Key Created');
|
||||
console.info('privkey.jwk.json');
|
||||
console.info(JSON.stringify(certKeypair, null, 2));
|
||||
// This should be saved as `privkey.pem`
|
||||
console.info();
|
||||
console.info('privkey.' + srvKty.toLowerCase() + '.pem:');
|
||||
console.info(pem);
|
||||
console.info();
|
||||
}
|
||||
|
||||
// 'subject' should be first in list
|
||||
var domains = randomDomains(rnd);
|
||||
if (config.debug) {
|
||||
console.info('Get certificates for random domains:');
|
||||
console.info(
|
||||
domains
|
||||
.map(function(puny) {
|
||||
var uni = punycode.toUnicode(puny);
|
||||
if (puny !== uni) {
|
||||
return puny + ' (' + uni + ')';
|
||||
}
|
||||
return puny;
|
||||
})
|
||||
.join('\n')
|
||||
);
|
||||
console.info();
|
||||
}
|
||||
|
||||
// Create CSR
|
||||
var csrDer = await CSR.csr({
|
||||
jwk: certKeypair.private,
|
||||
domains: domains,
|
||||
encoding: 'der'
|
||||
});
|
||||
var csr = Enc.bufToUrlBase64(csrDer);
|
||||
var csrPem = PEM.packBlock({
|
||||
type: 'CERTIFICATE REQUEST',
|
||||
bytes: csrDer /* { jwk: jwk, domains: opts.domains } */
|
||||
});
|
||||
if (config.debug) {
|
||||
console.info('Certificate Signing Request');
|
||||
console.info(csrPem);
|
||||
console.info();
|
||||
}
|
||||
|
||||
var results = await acme.certificates.create({
|
||||
account: account,
|
||||
accountKeypair: { privateKeyJwk: accountKeypair.private },
|
||||
csr: csr,
|
||||
domains: domains,
|
||||
challenges: challenges, // must be implemented
|
||||
customerEmail: null
|
||||
});
|
||||
// 'subject' should be first in list
|
||||
var domains = randomDomains(rnd);
|
||||
if (config.debug) {
|
||||
console.info('Get certificates for random domains:');
|
||||
console.info(
|
||||
domains
|
||||
.map(function(puny) {
|
||||
var uni = punycode.toUnicode(puny);
|
||||
if (puny !== uni) {
|
||||
return puny + ' (' + uni + ')';
|
||||
}
|
||||
return puny;
|
||||
})
|
||||
.join('\n')
|
||||
);
|
||||
console.info();
|
||||
}
|
||||
|
||||
// Create CSR
|
||||
var csrDer = await CSR.csr({
|
||||
jwk: certKeypair.private,
|
||||
domains: domains,
|
||||
encoding: 'der'
|
||||
});
|
||||
var csr = Enc.bufToUrlBase64(csrDer);
|
||||
var csrPem = PEM.packBlock({
|
||||
type: 'CERTIFICATE REQUEST',
|
||||
bytes: csrDer /* { jwk: jwk, domains: opts.domains } */
|
||||
});
|
||||
if (config.debug) {
|
||||
console.info('Certificate Signing Request');
|
||||
console.info(csrPem);
|
||||
console.info();
|
||||
}
|
||||
|
||||
var results = await acme.certificates.create({
|
||||
account: account,
|
||||
accountKeypair: { privateKeyJwk: accountKeypair.private },
|
||||
csr: csr,
|
||||
domains: domains,
|
||||
challenges: challenges, // must be implemented
|
||||
customerEmail: null
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@root/greenlock",
|
||||
"version": "3.0.1",
|
||||
"version": "3.0.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -74,9 +74,9 @@
|
|||
}
|
||||
},
|
||||
"acme-http-01-standalone": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/acme-http-01-standalone/-/acme-http-01-standalone-3.0.0.tgz",
|
||||
"integrity": "sha512-lZqVab2UZ1Dp36HemfhGEvdYOcVNg5wyVXNjtPUqGSAOVUOKqwi3gDrTGwqz+FBrEEEEpTngDPaZn2g3hfmPLA=="
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/acme-http-01-standalone/-/acme-http-01-standalone-3.0.5.tgz",
|
||||
"integrity": "sha512-W4GfK+39GZ+u0mvxRVUcVFCG6gposfzEnSBF20T/NUwWAKG59wQT1dUbS1NixRIAsRuhpGc4Jx659cErFQH0Pg=="
|
||||
},
|
||||
"cert-info": {
|
||||
"version": "1.5.1",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@root/greenlock",
|
||||
"version": "3.0.1",
|
||||
"version": "3.0.2",
|
||||
"description": "The easiest Let's Encrypt client for Node.js and Browsers",
|
||||
"homepage": "https://rootprojects.org/greenlock/",
|
||||
"main": "greenlock.js",
|
||||
|
@ -40,7 +40,7 @@
|
|||
"@root/keypairs": "^0.9.0",
|
||||
"@root/mkdirp": "^1.0.0",
|
||||
"@root/request": "^1.3.10",
|
||||
"acme-http-01-standalone": "^3.0.0",
|
||||
"acme-http-01-standalone": "^3.0.5",
|
||||
"cert-info": "^1.5.1",
|
||||
"greenlock-manager-fs": "^0.6.0",
|
||||
"greenlock-store-fs": "^3.2.0",
|
||||
|
|
161
plugins.js
161
plugins.js
|
@ -8,7 +8,22 @@ var spawnSync = require('child_process').spawnSync;
|
|||
// Exported for CLIs and such to override
|
||||
P.PKG_DIR = __dirname;
|
||||
|
||||
P._load = function(modname) {
|
||||
P._loadStore = function(storeConf) {
|
||||
return P._loadHelper(storeConf.module).then(function(plugin) {
|
||||
return P._normalizeStore(storeConf.module, plugin.create(storeConf));
|
||||
});
|
||||
};
|
||||
P._loadChallenge = function(chConfs, typ01) {
|
||||
return P._loadHelper(chConfs[typ01].module).then(function(plugin) {
|
||||
var ch = P._normalizeChallenge(
|
||||
chConfs[typ01].module,
|
||||
plugin.create(chConfs[typ01])
|
||||
);
|
||||
ch._type = typ01;
|
||||
return ch;
|
||||
});
|
||||
};
|
||||
P._loadHelper = function(modname) {
|
||||
try {
|
||||
return Promise.resolve(require(modname));
|
||||
} catch (e) {
|
||||
|
@ -18,6 +33,150 @@ P._load = function(modname) {
|
|||
}
|
||||
};
|
||||
|
||||
P._normalizeStore = function(name, store) {
|
||||
var acc = store.accounts;
|
||||
var crt = store.certificates;
|
||||
|
||||
var warned = false;
|
||||
function warn() {
|
||||
if (warned) {
|
||||
return;
|
||||
}
|
||||
warned = true;
|
||||
console.warn(
|
||||
"'" +
|
||||
name +
|
||||
"' may have incorrect function signatures, or contains deprecated use of callbacks"
|
||||
);
|
||||
}
|
||||
|
||||
// accs
|
||||
if (acc.check && 2 === acc.check.length) {
|
||||
warn();
|
||||
acc._thunk_check = acc.check;
|
||||
acc.check = promisify(acc._thunk_check);
|
||||
}
|
||||
if (acc.set && 3 === acc.set.length) {
|
||||
warn();
|
||||
acc._thunk_set = acc.set;
|
||||
acc.set = promisify(acc._thunk_set);
|
||||
}
|
||||
if (2 === acc.checkKeypair.length) {
|
||||
warn();
|
||||
acc._thunk_checkKeypair = acc.checkKeypair;
|
||||
acc.checkKeypair = promisify(acc._thunk_checkKeypair);
|
||||
}
|
||||
if (3 === acc.setKeypair.length) {
|
||||
warn();
|
||||
acc._thunk_setKeypair = acc.setKeypair;
|
||||
acc.setKeypair = promisify(acc._thunk_setKeypair);
|
||||
}
|
||||
|
||||
// certs
|
||||
if (2 === crt.check.length) {
|
||||
warn();
|
||||
crt._thunk_check = crt.check;
|
||||
crt.check = promisify(crt._thunk_check);
|
||||
}
|
||||
if (3 === crt.set.length) {
|
||||
warn();
|
||||
crt._thunk_set = crt.set;
|
||||
crt.set = promisify(crt._thunk_set);
|
||||
}
|
||||
if (2 === crt.checkKeypair.length) {
|
||||
warn();
|
||||
crt._thunk_checkKeypair = crt.checkKeypair;
|
||||
crt.checkKeypair = promisify(crt._thunk_checkKeypair);
|
||||
}
|
||||
if (2 === crt.setKeypair.length) {
|
||||
warn();
|
||||
crt._thunk_setKeypair = crt.setKeypair;
|
||||
crt.setKeypair = promisify(crt._thunk_setKeypair);
|
||||
}
|
||||
|
||||
return store;
|
||||
};
|
||||
P._normalizeChallenge = function(name, ch) {
|
||||
var gch = {};
|
||||
var warned = false;
|
||||
function warn() {
|
||||
if (warned) {
|
||||
return;
|
||||
}
|
||||
warned = true;
|
||||
console.warn(
|
||||
"'" +
|
||||
name +
|
||||
"' may have incorrect function signatures, or contains deprecated use of callbacks"
|
||||
);
|
||||
}
|
||||
|
||||
var warned2 = false;
|
||||
function warn2() {
|
||||
if (warned2) {
|
||||
return;
|
||||
}
|
||||
warned2 = true;
|
||||
console.warn(
|
||||
"'" +
|
||||
name +
|
||||
"' did not return a Promise when called. This should be fixed by the maintainer."
|
||||
);
|
||||
}
|
||||
|
||||
function wrappy(fn) {
|
||||
return function(_params) {
|
||||
return Promise.resolve().then(function() {
|
||||
var result = fn.call(ch, _params);
|
||||
if (!result || !result.then) {
|
||||
warn2();
|
||||
}
|
||||
return result;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// init, zones, set, get, remove
|
||||
if (ch.init) {
|
||||
if (2 === ch.init.length) {
|
||||
warn();
|
||||
ch._thunk_init = ch.init;
|
||||
ch.init = promisify(ch._thunk_init);
|
||||
}
|
||||
gch.init = wrappy(ch.init);
|
||||
}
|
||||
if (ch.zones) {
|
||||
if (2 === ch.zones.length) {
|
||||
warn();
|
||||
ch._thunk_zones = ch.zones;
|
||||
ch.zones = promisify(ch._thunk_zones);
|
||||
}
|
||||
gch.zones = wrappy(ch.zones);
|
||||
}
|
||||
if (2 === ch.set.length) {
|
||||
warn();
|
||||
ch._thunk_set = ch.set;
|
||||
ch.set = promisify(ch._thunk_set);
|
||||
}
|
||||
gch.set = wrappy(ch.set);
|
||||
if (2 === ch.remove.length) {
|
||||
warn();
|
||||
ch._thunk_remove = ch.remove;
|
||||
ch.remove = promisify(ch._thunk_remove);
|
||||
}
|
||||
gch.remove = wrappy(ch.remove);
|
||||
if (ch.get) {
|
||||
if (2 === ch.get.length) {
|
||||
warn();
|
||||
ch._thunk_get = ch.get;
|
||||
ch.get = promisify(ch._thunk_get);
|
||||
}
|
||||
gch.get = wrappy(ch.get);
|
||||
}
|
||||
|
||||
return gch;
|
||||
};
|
||||
|
||||
P._loadSync = function(modname) {
|
||||
var mod;
|
||||
try {
|
||||
|
|
|
@ -33,9 +33,9 @@ greenlock
|
|||
subscriberEmail: email
|
||||
})
|
||||
.then(function() {
|
||||
return greenlock.renew().then(function (pems) {
|
||||
console.info(pems);
|
||||
});
|
||||
return greenlock.renew().then(function(pems) {
|
||||
console.info(pems);
|
||||
});
|
||||
})
|
||||
.catch(function(e) {
|
||||
console.error('yo', e.code);
|
||||
|
|
Loading…
Reference in New Issue