From 4e7ff0d9e85aedec2f4084e78972a393de358f7b Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Fri, 25 Oct 2019 04:54:54 -0600 Subject: [PATCH] add maintainer notices --- acme.js | 27 +++++++++++++--- maintainers.js | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 maintainers.js diff --git a/acme.js b/acme.js index ad9fa97..37015ad 100644 --- a/acme.js +++ b/acme.js @@ -14,7 +14,8 @@ var sha2 = require('@root/keypairs/lib/node/sha2.js'); var http = require('./lib/node/http.js'); var A = require('./account.js'); var U = require('./utils.js'); -var E = require('./errors'); +var E = require('./errors.js'); +var M = require('./maintainers.js'); var native = require('./lib/native.js'); @@ -27,6 +28,20 @@ ACME.create = function create(me) { me._nonces = []; me._canCheck = {}; + if (!/.+@.+\..+/.test(me.maintainerEmail)) { + throw new Error( + 'you should supply `maintainerEmail` as a contact for security and critical bug notices' + ); + } + + if (!/\w\/v?\d/.test(me.packageAgent) && false !== me.packageAgent) { + console.error( + "\nyou should supply `packageAgent` as an rfc7231-style User-Agent such as Foo/v1.1\n\n\t// your package agent should be this:\n\tvar pkg = require('./package.json');\n\tvar agent = pkg.name + '/' + pkg.version\n" + ); + process.exit(1); + return; + } + if (!me.dns01) { me.dns01 = function(ch) { return native._dns01(me, ch); @@ -43,15 +58,17 @@ ACME.create = function create(me) { }; } - if (!me.request) { - me.request = http.request; + if (!me.__request) { + me.__request = http.request; } // passed to dependencies - me._urequest = function(opts) { + me.request = function(opts) { return U._request(me, opts); }; me.init = function(opts) { + M.init(me); + function fin(dir) { me._directoryUrls = dir; me._tos = dir.meta.termsOfService; @@ -1241,7 +1258,7 @@ ACME._prepRequest = function(me, options) { !presenter._acme_initialized ) { presenter._acme_initialized = true; - return presenter.init({ type: '*', request: me._urequest }); + return presenter.init({ type: '*', request: me.request }); } }); }); diff --git a/maintainers.js b/maintainers.js new file mode 100644 index 0000000..6a3ec99 --- /dev/null +++ b/maintainers.js @@ -0,0 +1,85 @@ +'use strict'; + +var M = module.exports; +var native = require('./lib/native.js'); + +// Keep track of active maintainers so that we know who to inform if +// something breaks or has a serious bug or flaw. + +var oldCollegeTries = {}; +M.init = function(me) { + if (oldCollegeTries[me.maintainerEmail]) { + return; + } + + var tz = ''; + try { + // Use timezone to stagger messages to maintainers + tz = Intl.DateTimeFormat().resolvedOptions().timeZone; + } catch (e) { + // ignore node versions with no or incomplete Intl + } + + // Use locale to know what language to use + var env = process.env; + var locale = env.LC_ALL || env.LC_MESSAGES || env.LANG || env.LANGUAGE; + + try { + M._init(me, tz, locale); + } catch (e) { + //console.log(e); + // ignore + } +}; + +M._init = function(me, tz, locale) { + // prevent a stampede from misconfigured clients in an eternal loop + setTimeout(function() { + me.request({ + method: 'GET', + url: 'https://api.rootprojects.org/api/nonce', + json: true + }) + .then(function(resp) { + // in the browser this will work until solved, but in + // node this will bail unless the challenge is trivial + return native._hashcash(resp.body || {}); + }) + .then(function(hashcash) { + var req = { + headers: { + 'x-root-nonce-v1': hashcash + }, + method: 'POST', + url: + 'https://api.rootprojects.org/api/projects/ACME.js/dependents', + json: { + maintainer: me.maintainerEmail, + tz: tz, + locale: locale + } + }; + return me + .request(req) + .catch(function(err) { + if (true || me.debug) { + console.error(err); + } + }) + .then(function(/*resp*/) { + oldCollegeTries[me.maintainerEmail] = true; + //console.log(resp); + }); + }); + }, me.__timeout || 3000); +}; + +if (require.main === module) { + var ACME = require('./'); + var acme = ACME.create({ + maintainerEmail: 'aj+acme-test@rootprojects.org', + packageAgent: 'test/v0', + __timeout: 100 + }); + M.init(acme); +}