forked from root/acme.js
Compare commits
No commits in common. "master" and "v3" have entirely different histories.
12
README.md
12
README.md
|
@ -2,16 +2,10 @@
|
||||||
|
|
||||||
| Built by [Root](https://therootcompany.com) for [Hub](https://rootprojects.org/hub)
|
| Built by [Root](https://therootcompany.com) for [Hub](https://rootprojects.org/hub)
|
||||||
|
|
||||||
## Automated Certificate Management Environment
|
ACME.js is a _low-level_ client for Let's Encrypt.
|
||||||
|
|
||||||
ACME ([RFC 8555](https://tools.ietf.org/html/rfc8555)) is the protocol that powers **Let's Encrypt**.
|
|
||||||
|
|
||||||
ACME.js is a _low-level_ client that speaks RFC 8555 to get Free SSL certificates through Let's Encrypt.
|
|
||||||
|
|
||||||
Looking for an **easy**, _high-level_ client? Check out [Greenlock.js](https://git.rootprojects.org/root/greenlock.js).
|
Looking for an **easy**, _high-level_ client? Check out [Greenlock.js](https://git.rootprojects.org/root/greenlock.js).
|
||||||
|
|
||||||
# Quick Start
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var acme = ACME.create({ maintainerEmail, packageAgent, notify });
|
var acme = ACME.create({ maintainerEmail, packageAgent, notify });
|
||||||
await acme.init(directoryUrl);
|
await acme.init(directoryUrl);
|
||||||
|
@ -103,7 +97,7 @@ The public API encapsulates the three high-level steps of the ACME protocol:
|
||||||
- Challenge Presentation
|
- Challenge Presentation
|
||||||
- Certificate Redemption
|
- Certificate Redemption
|
||||||
|
|
||||||
## API Overview
|
## Overview
|
||||||
|
|
||||||
The core API can be show in just four functions:
|
The core API can be show in just four functions:
|
||||||
|
|
||||||
|
@ -183,7 +177,7 @@ These `notify` events are intended for _logging_ and debugging, NOT as a data AP
|
||||||
Note: DO NOT rely on **undocumented properties**. They are experimental and **will break**.
|
Note: DO NOT rely on **undocumented properties**. They are experimental and **will break**.
|
||||||
If you have a use case for a particular property **open an issue** - we can lock it down and document it.
|
If you have a use case for a particular property **open an issue** - we can lock it down and document it.
|
||||||
|
|
||||||
# Example (Full Walkthrough)
|
# Example
|
||||||
|
|
||||||
### See [examples/README.md](https://git.rootprojects.org/root/acme.js/src/branch/master/examples/README.md)
|
### See [examples/README.md](https://git.rootprojects.org/root/acme.js/src/branch/master/examples/README.md)
|
||||||
|
|
||||||
|
|
21
account.js
21
account.js
|
@ -5,13 +5,12 @@ var U = require('./utils.js');
|
||||||
|
|
||||||
var Keypairs = require('@root/keypairs');
|
var Keypairs = require('@root/keypairs');
|
||||||
var Enc = require('@root/encoding/bytes');
|
var Enc = require('@root/encoding/bytes');
|
||||||
var agreers = {};
|
|
||||||
|
|
||||||
A._getAccountKid = function(me, options) {
|
A._getAccountKid = function(me, options) {
|
||||||
// It's just fine if there's no account, we'll go get the key id we need via the existing key
|
// It's just fine if there's no account, we'll go get the key id we need via the existing key
|
||||||
var kid =
|
var kid =
|
||||||
options.kid ||
|
options.kid ||
|
||||||
(options.account && options.account.key && options.account.key.kid);
|
(options.account && (options.account.key && options.account.key.kid));
|
||||||
|
|
||||||
if (kid) {
|
if (kid) {
|
||||||
return Promise.resolve(kid);
|
return Promise.resolve(kid);
|
||||||
|
@ -139,15 +138,8 @@ A._registerAccount = function (me, options) {
|
||||||
var agreeToTerms = options.agreeToTerms;
|
var agreeToTerms = options.agreeToTerms;
|
||||||
if (!agreeToTerms) {
|
if (!agreeToTerms) {
|
||||||
agreeToTerms = function(terms) {
|
agreeToTerms = function(terms) {
|
||||||
if (agreers[options.subscriberEmail]) {
|
console.log(
|
||||||
return true;
|
'By using this software you accept this Subscriber Agreement and Terms of Service:'
|
||||||
}
|
|
||||||
agreers[options.subscriberEmail] = true;
|
|
||||||
console.info();
|
|
||||||
console.info(
|
|
||||||
'By using this software you (' +
|
|
||||||
options.subscriberEmail +
|
|
||||||
') are agreeing to the following:'
|
|
||||||
);
|
);
|
||||||
console.info(
|
console.info(
|
||||||
'ACME Subscriber Agreement:',
|
'ACME Subscriber Agreement:',
|
||||||
|
@ -155,9 +147,8 @@ A._registerAccount = function (me, options) {
|
||||||
);
|
);
|
||||||
console.info(
|
console.info(
|
||||||
'Greenlock/ACME.js Terms of Use:',
|
'Greenlock/ACME.js Terms of Use:',
|
||||||
terms.acmeJsTermsUrl
|
terms.terms.acmeJsTermsUrl
|
||||||
);
|
);
|
||||||
console.info();
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
} else if (true === agreeToTerms) {
|
} else if (true === agreeToTerms) {
|
||||||
|
@ -166,8 +157,8 @@ A._registerAccount = function (me, options) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return agreeToTerms({
|
return agreeToTerms({
|
||||||
acmeSubscriberTermsUrl: me._tos,
|
acmeSubscriberTosUrl: me._tos,
|
||||||
acmeJsTermsUrl: 'https://rootprojects.org/legal/#terms'
|
acmeJsTosUrl: 'https://rootprojects.org/legal/#terms'
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(agree)
|
.then(agree)
|
||||||
|
|
88
acme.js
88
acme.js
|
@ -474,7 +474,7 @@ ACME._dryRun = function (me, realOptions, zonenames) {
|
||||||
var selected = [];
|
var selected = [];
|
||||||
noopts.order._claims = claims.slice(0);
|
noopts.order._claims = claims.slice(0);
|
||||||
noopts.notify = function(ev, params) {
|
noopts.notify = function(ev, params) {
|
||||||
if ('_challenge_select' === ev) {
|
if ('challenge_select' === ev) {
|
||||||
selected.push(params.challenge);
|
selected.push(params.challenge);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -486,7 +486,6 @@ ACME._dryRun = function (me, realOptions, zonenames) {
|
||||||
type: ch.type
|
type: ch.type
|
||||||
//challenge: ch
|
//challenge: ch
|
||||||
});
|
});
|
||||||
// ignore promise return
|
|
||||||
noopts.challenges[ch.type]
|
noopts.challenges[ch.type]
|
||||||
.remove({ challenge: ch })
|
.remove({ challenge: ch })
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
|
@ -756,8 +755,12 @@ ACME._postChallenge = function (me, options, kid, auth) {
|
||||||
altname: altname
|
altname: altname
|
||||||
});
|
});
|
||||||
|
|
||||||
// State can be pending while waiting ACME server to transition to
|
if ('processing' === resp.body.status) {
|
||||||
// processing
|
//#console.debug('poll: again', auth.url);
|
||||||
|
return ACME._wait(RETRY_INTERVAL).then(pollStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This state should never occur
|
||||||
if ('pending' === resp.body.status) {
|
if ('pending' === resp.body.status) {
|
||||||
if (count >= MAX_PEND) {
|
if (count >= MAX_PEND) {
|
||||||
return ACME._wait(RETRY_INTERVAL)
|
return ACME._wait(RETRY_INTERVAL)
|
||||||
|
@ -765,25 +768,13 @@ ACME._postChallenge = function (me, options, kid, auth) {
|
||||||
.then(respondToChallenge);
|
.then(respondToChallenge);
|
||||||
}
|
}
|
||||||
//#console.debug('poll: again', auth.url);
|
//#console.debug('poll: again', auth.url);
|
||||||
return ACME._wait(RETRY_INTERVAL).then(pollStatus);
|
return ACME._wait(RETRY_INTERVAL).then(respondToChallenge);
|
||||||
}
|
|
||||||
|
|
||||||
if ('processing' === resp.body.status) {
|
|
||||||
//#console.debug('poll: again', auth.url);
|
|
||||||
return ACME._wait(RETRY_INTERVAL).then(pollStatus);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// REMOVE DNS records as soon as the state is non-processing
|
// REMOVE DNS records as soon as the state is non-processing
|
||||||
// (valid or invalid or other)
|
// (valid or invalid or other)
|
||||||
try {
|
try {
|
||||||
options.challenges[auth.type]
|
options.challenges[auth.type].remove({ challenge: auth });
|
||||||
.remove({ challenge: auth })
|
|
||||||
.catch(function (err) {
|
|
||||||
err.action = 'challenge_remove';
|
|
||||||
err.altname = auth.altname;
|
|
||||||
err.type = auth.type;
|
|
||||||
ACME._notify(me, options, 'error', err);
|
|
||||||
});
|
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
if ('valid' === resp.body.status) {
|
if ('valid' === resp.body.status) {
|
||||||
|
@ -902,15 +893,6 @@ ACME._setChallenges = function (me, options, order) {
|
||||||
placed.push(selected);
|
placed.push(selected);
|
||||||
ACME._notify(me, options, 'challenge_select', {
|
ACME._notify(me, options, 'challenge_select', {
|
||||||
// API-locked
|
// API-locked
|
||||||
altname: ACME._untame(
|
|
||||||
claim.identifier.value,
|
|
||||||
claim.wildcard
|
|
||||||
),
|
|
||||||
type: selected.type,
|
|
||||||
dnsHost: selected.dnsHost,
|
|
||||||
keyAuthorization: selected.keyAuthorization
|
|
||||||
});
|
|
||||||
ACME._notify(me, options, '_challenge_select', {
|
|
||||||
altname: ACME._untame(
|
altname: ACME._untame(
|
||||||
claim.identifier.value,
|
claim.identifier.value,
|
||||||
claim.wildcard
|
claim.wildcard
|
||||||
|
@ -1013,7 +995,14 @@ ACME._pollOrderStatus = function (me, options, kid, order, verifieds) {
|
||||||
var body = { csr: csr64 };
|
var body = { csr: csr64 };
|
||||||
var payload = JSON.stringify(body);
|
var payload = JSON.stringify(body);
|
||||||
|
|
||||||
function processResponse(resp) {
|
function pollCert() {
|
||||||
|
//#console.debug('[ACME.js] pollCert:', order._finalizeUrl);
|
||||||
|
return U._jwsRequest(me, {
|
||||||
|
accountKey: options.accountKey,
|
||||||
|
url: order._finalizeUrl,
|
||||||
|
protected: { kid: kid },
|
||||||
|
payload: Enc.strToBuf(payload)
|
||||||
|
}).then(function(resp) {
|
||||||
ACME._notify(me, options, 'certificate_status', {
|
ACME._notify(me, options, 'certificate_status', {
|
||||||
subject: options.domains[0],
|
subject: options.domains[0],
|
||||||
status: resp.body.status
|
status: resp.body.status
|
||||||
|
@ -1029,7 +1018,7 @@ ACME._pollOrderStatus = function (me, options, kid, order, verifieds) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('processing' === resp.body.status) {
|
if ('processing' === resp.body.status) {
|
||||||
return ACME._wait().then(pollStatus);
|
return ACME._wait().then(pollCert);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (me.debug) {
|
if (me.debug) {
|
||||||
|
@ -1069,28 +1058,10 @@ ACME._pollOrderStatus = function (me, options, kid, order, verifieds) {
|
||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
E.UNHANDLED_ORDER_STATUS(options, verifieds, resp)
|
E.UNHANDLED_ORDER_STATUS(options, verifieds, resp)
|
||||||
);
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function pollStatus() {
|
return pollCert();
|
||||||
return U._jwsRequest(me, {
|
|
||||||
accountKey: options.accountKey,
|
|
||||||
url: order._orderUrl,
|
|
||||||
protected: { kid: kid },
|
|
||||||
payload: Enc.binToBuf('')
|
|
||||||
}).then(processResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
function finalizeOrder() {
|
|
||||||
//#console.debug('[ACME.js] pollCert:', order._finalizeUrl);
|
|
||||||
return U._jwsRequest(me, {
|
|
||||||
accountKey: options.accountKey,
|
|
||||||
url: order._finalizeUrl,
|
|
||||||
protected: { kid: kid },
|
|
||||||
payload: Enc.strToBuf(payload)
|
|
||||||
}).then(processResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalizeOrder();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ACME._redeemCert = function(me, options, kid, voucher) {
|
ACME._redeemCert = function(me, options, kid, voucher) {
|
||||||
|
@ -1248,8 +1219,14 @@ ACME._prepRequest = function (me, options) {
|
||||||
options.domains = options.domains || _csr.altnames;
|
options.domains = options.domains || _csr.altnames;
|
||||||
_csr.altnames = _csr.altnames || [];
|
_csr.altnames = _csr.altnames || [];
|
||||||
if (
|
if (
|
||||||
options.domains.slice(0).sort().join(' ') !==
|
options.domains
|
||||||
_csr.altnames.slice(0).sort().join(' ')
|
.slice(0)
|
||||||
|
.sort()
|
||||||
|
.join(' ') !==
|
||||||
|
_csr.altnames
|
||||||
|
.slice(0)
|
||||||
|
.sort()
|
||||||
|
.join(' ')
|
||||||
) {
|
) {
|
||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
new Error('certificate altnames do not match requested domains')
|
new Error('certificate altnames do not match requested domains')
|
||||||
|
@ -1353,7 +1330,10 @@ ACME._csrToUrlBase64 = function (csr) {
|
||||||
// TODO use PEM.parseBlock()
|
// TODO use PEM.parseBlock()
|
||||||
// nix PEM headers, if any
|
// nix PEM headers, if any
|
||||||
if ('-' === csr[0]) {
|
if ('-' === csr[0]) {
|
||||||
csr = csr.split(/\n+/).slice(1, -1).join('');
|
csr = csr
|
||||||
|
.split(/\n+/)
|
||||||
|
.slice(1, -1)
|
||||||
|
.join('');
|
||||||
}
|
}
|
||||||
return Enc.base64ToUrlBase64(csr.trim().replace(/\s+/g, ''));
|
return Enc.base64ToUrlBase64(csr.trim().replace(/\s+/g, ''));
|
||||||
};
|
};
|
||||||
|
@ -1362,7 +1342,9 @@ ACME._csrToUrlBase64 = function (csr) {
|
||||||
ACME._prnd = function(n) {
|
ACME._prnd = function(n) {
|
||||||
var rnd = '';
|
var rnd = '';
|
||||||
while (rnd.length / 2 < n) {
|
while (rnd.length / 2 < n) {
|
||||||
var i = Math.random().toString().substr(2);
|
var i = Math.random()
|
||||||
|
.toString()
|
||||||
|
.substr(2);
|
||||||
var h = parseInt(i, 10).toString(16);
|
var h = parseInt(i, 10).toString(16);
|
||||||
if (h.length % 2) {
|
if (h.length % 2) {
|
||||||
h = '0' + h;
|
h = '0' + h;
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var https = require('http2');
|
|
||||||
var tls = require('tls');
|
|
||||||
var fs = require('fs');
|
|
||||||
|
|
||||||
var key = fs.readFileSync('./privkey.pem');
|
|
||||||
var cert = fs.readFileSync('./fullchain.pem');
|
|
||||||
|
|
||||||
function SNICallback(servername, cb) {
|
|
||||||
console.log('sni:', servername);
|
|
||||||
cb(null, tls.createSecureContext({ key, cert }));
|
|
||||||
}
|
|
||||||
|
|
||||||
var server = https
|
|
||||||
.createSecureServer({ SNICallback: SNICallback }, function (req, res) {
|
|
||||||
res.end('Hello, Encrypted World!');
|
|
||||||
})
|
|
||||||
.listen(443, function () {
|
|
||||||
console.info('Listening on', server.address());
|
|
||||||
});
|
|
|
@ -9,6 +9,9 @@ sha2.sum = function (alg, str) {
|
||||||
var sha = 'sha' + String(alg).replace(/^sha-?/i, '');
|
var sha = 'sha' + String(alg).replace(/^sha-?/i, '');
|
||||||
// utf8 is the default for strings
|
// utf8 is the default for strings
|
||||||
var buf = Buffer.from(str);
|
var buf = Buffer.from(str);
|
||||||
return crypto.createHash(sha).update(buf).digest();
|
return crypto
|
||||||
|
.createHash(sha)
|
||||||
|
.update(buf)
|
||||||
|
.digest();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,10 +33,9 @@ M.init = function (me) {
|
||||||
};
|
};
|
||||||
|
|
||||||
M._init = function(me, tz, locale) {
|
M._init = function(me, tz, locale) {
|
||||||
setTimeout(function () {
|
|
||||||
// prevent a stampede from misconfigured clients in an eternal loop
|
// prevent a stampede from misconfigured clients in an eternal loop
|
||||||
|
setTimeout(function() {
|
||||||
me.request({
|
me.request({
|
||||||
timeout: 3000,
|
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: 'https://api.rootprojects.org/api/nonce',
|
url: 'https://api.rootprojects.org/api/nonce',
|
||||||
json: true
|
json: true
|
||||||
|
@ -48,7 +47,6 @@ M._init = function (me, tz, locale) {
|
||||||
})
|
})
|
||||||
.then(function(hashcash) {
|
.then(function(hashcash) {
|
||||||
var req = {
|
var req = {
|
||||||
timeout: 3000,
|
|
||||||
headers: {
|
headers: {
|
||||||
'x-root-nonce-v1': hashcash
|
'x-root-nonce-v1': hashcash
|
||||||
},
|
},
|
||||||
|
@ -62,13 +60,10 @@ M._init = function (me, tz, locale) {
|
||||||
locale: locale
|
locale: locale
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return me.request(req);
|
return me
|
||||||
})
|
.request(req)
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
if (me.debug) {
|
if (true || me.debug) {
|
||||||
console.error(
|
|
||||||
'error adding maintainer to support notices:'
|
|
||||||
);
|
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -76,6 +71,7 @@ M._init = function (me, tz, locale) {
|
||||||
oldCollegeTries[me.maintainerEmail] = true;
|
oldCollegeTries[me.maintainerEmail] = true;
|
||||||
//console.log(resp);
|
//console.log(resp);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}, me.__timeout || 3000);
|
}, me.__timeout || 3000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@root/acme",
|
"name": "@root/acme",
|
||||||
"version": "3.1.0",
|
"version": "3.0.1",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -16,6 +16,7 @@
|
||||||
"version": "0.8.1",
|
"version": "0.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@root/csr/-/csr-0.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/@root/csr/-/csr-0.8.1.tgz",
|
||||||
"integrity": "sha512-hKl0VuE549TK6SnS2Yn9nRvKbFZXn/oAg+dZJU/tlKl/f/0yRXeuUzf8akg3JjtJq+9E592zDqeXZ7yyrg8fSQ==",
|
"integrity": "sha512-hKl0VuE549TK6SnS2Yn9nRvKbFZXn/oAg+dZJU/tlKl/f/0yRXeuUzf8akg3JjtJq+9E592zDqeXZ7yyrg8fSQ==",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@root/asn1": "^1.0.0",
|
"@root/asn1": "^1.0.0",
|
||||||
"@root/pem": "^1.0.4",
|
"@root/pem": "^1.0.4",
|
||||||
|
@ -28,9 +29,9 @@
|
||||||
"integrity": "sha512-OaEub02ufoU038gy6bsNHQOjIn8nUjGiLcaRmJ40IUykneJkIW5fxDqKxQx48cszuNflYldsJLPPXCrGfHs8yQ=="
|
"integrity": "sha512-OaEub02ufoU038gy6bsNHQOjIn8nUjGiLcaRmJ40IUykneJkIW5fxDqKxQx48cszuNflYldsJLPPXCrGfHs8yQ=="
|
||||||
},
|
},
|
||||||
"@root/keypairs": {
|
"@root/keypairs": {
|
||||||
"version": "0.10.0",
|
"version": "0.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/@root/keypairs/-/keypairs-0.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@root/keypairs/-/keypairs-0.9.0.tgz",
|
||||||
"integrity": "sha512-t8VocY46Mtb0NTsxzyLLf5tsgfw0BXLYVADAyiRdEdqHcvPFGJdjkXNtHVQuSV/FMaC65iTOHVP4E6X8iT3Ikg==",
|
"integrity": "sha512-NXE2L9Gv7r3iC4kB/gTPZE1vO9Ox/p14zDzAJ5cGpTpytbWOlWF7QoHSJbtVX4H7mRG/Hp7HR3jWdWdb2xaaXg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@root/encoding": "^1.0.1",
|
"@root/encoding": "^1.0.1",
|
||||||
"@root/pem": "^1.0.4",
|
"@root/pem": "^1.0.4",
|
||||||
|
@ -43,9 +44,9 @@
|
||||||
"integrity": "sha512-rEUDiUsHtild8GfIjFE9wXtcVxeS+ehCJQBwbQQ3IVfORKHK93CFnRtkr69R75lZFjcmKYVc+AXDB+AeRFOULA=="
|
"integrity": "sha512-rEUDiUsHtild8GfIjFE9wXtcVxeS+ehCJQBwbQQ3IVfORKHK93CFnRtkr69R75lZFjcmKYVc+AXDB+AeRFOULA=="
|
||||||
},
|
},
|
||||||
"@root/request": {
|
"@root/request": {
|
||||||
"version": "1.6.1",
|
"version": "1.3.11",
|
||||||
"resolved": "https://registry.npmjs.org/@root/request/-/request-1.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/@root/request/-/request-1.3.11.tgz",
|
||||||
"integrity": "sha512-8wrWyeBLRp7T8J36GkT3RODJ6zYmL0/maWlAUD5LOXT28D3TDquUepyYDKYANNA3Gc8R5ZCgf+AXvSTYpJEWwQ=="
|
"integrity": "sha512-3a4Eeghcjsfe6zh7EJ+ni1l8OK9Fz2wL1OjP4UCa0YdvtH39kdXB9RGWuzyNv7dZi0+Ffkc83KfH0WbPMiuJFw=="
|
||||||
},
|
},
|
||||||
"@root/x509": {
|
"@root/x509": {
|
||||||
"version": "0.7.2",
|
"version": "0.7.2",
|
||||||
|
@ -152,9 +153,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"glob": {
|
"glob": {
|
||||||
"version": "7.1.6",
|
"version": "7.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz",
|
||||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
"integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@root/acme",
|
"name": "@root/acme",
|
||||||
"version": "3.1.0",
|
"version": "3.0.5",
|
||||||
"description": "Free SSL certificates for Node.js and Browsers. Issued via Let's Encrypt",
|
"description": "Free SSL certificates for Node.js and Browsers. Issued via Let's Encrypt",
|
||||||
"homepage": "https://rootprojects.org/acme/",
|
"homepage": "https://rootprojects.org/acme/",
|
||||||
"main": "acme.js",
|
"main": "acme.js",
|
||||||
|
@ -42,14 +42,14 @@
|
||||||
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@root/csr": "^0.8.1",
|
|
||||||
"@root/encoding": "^1.0.1",
|
"@root/encoding": "^1.0.1",
|
||||||
"@root/keypairs": "^0.10.0",
|
"@root/keypairs": "^0.9.0",
|
||||||
"@root/pem": "^1.0.4",
|
"@root/pem": "^1.0.4",
|
||||||
"@root/request": "^1.6.1",
|
"@root/request": "^1.3.11",
|
||||||
"@root/x509": "^0.7.2"
|
"@root/x509": "^0.7.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@root/csr": "^0.8.1",
|
||||||
"dig.js": "^1.3.9",
|
"dig.js": "^1.3.9",
|
||||||
"dns-suite": "^1.2.13",
|
"dns-suite": "^1.2.13",
|
||||||
"dotenv": "^8.1.0",
|
"dotenv": "^8.1.0",
|
||||||
|
|
|
@ -247,7 +247,12 @@ module.exports = function () {
|
||||||
|
|
||||||
function random() {
|
function random() {
|
||||||
return (
|
return (
|
||||||
parseInt(Math.random().toString().slice(2, 99), 10)
|
parseInt(
|
||||||
|
Math.random()
|
||||||
|
.toString()
|
||||||
|
.slice(2, 99),
|
||||||
|
10
|
||||||
|
)
|
||||||
.toString(16)
|
.toString(16)
|
||||||
.slice(0, 4) + '例'
|
.slice(0, 4) + '例'
|
||||||
);
|
);
|
||||||
|
|
|
@ -33,7 +33,10 @@ native
|
||||||
|
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
var nonce = '20';
|
var nonce = '20';
|
||||||
var needle = crypto.randomBytes(3).toString('hex').slice(0, 5);
|
var needle = crypto
|
||||||
|
.randomBytes(3)
|
||||||
|
.toString('hex')
|
||||||
|
.slice(0, 5);
|
||||||
native
|
native
|
||||||
._hashcash({
|
._hashcash({
|
||||||
alg: 'SHA-256',
|
alg: 'SHA-256',
|
||||||
|
|
9
utils.js
9
utils.js
|
@ -11,13 +11,12 @@ U._jwsRequest = function (me, bigopts) {
|
||||||
bigopts.protected.nonce = nonce;
|
bigopts.protected.nonce = nonce;
|
||||||
bigopts.protected.url = bigopts.url;
|
bigopts.protected.url = bigopts.url;
|
||||||
// protected.alg: added by Keypairs.signJws
|
// protected.alg: added by Keypairs.signJws
|
||||||
if (bigopts.protected.jwk) {
|
if (!bigopts.protected.jwk) {
|
||||||
bigopts.protected.kid = false;
|
// protected.kid must be overwritten due to ACME's interpretation of the spec
|
||||||
} else if (!('kid' in bigopts.protected)) {
|
if (!('kid' in bigopts.protected)) {
|
||||||
// protected.kid must be provided according to ACME's interpretation of the spec
|
|
||||||
// (using the provided URL rather than the Key's Thumbprint as Key ID)
|
|
||||||
bigopts.protected.kid = bigopts.kid;
|
bigopts.protected.kid = bigopts.kid;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// this will shasum the thumbprint the 2nd time
|
// this will shasum the thumbprint the 2nd time
|
||||||
return Keypairs.signJws({
|
return Keypairs.signJws({
|
||||||
|
|
Loading…
Reference in New Issue