Compare commits
No commits in common. "098e05f3ef16ceaa86831a2a05183d31b85d01d2" and "89487c203003913613598ddbc502b2acd8ccdbaf" have entirely different histories.
098e05f3ef
...
89487c2030
32
.gitignore
vendored
32
.gitignore
vendored
@ -1,32 +0,0 @@
|
|||||||
*.pem
|
|
||||||
letsencrypt.work
|
|
||||||
letsencrypt.logs
|
|
||||||
letsencrypt.config
|
|
||||||
|
|
||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
|
|
||||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directory
|
|
||||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
|
||||||
node_modules
|
|
18
.jshintrc
18
.jshintrc
@ -1,18 +0,0 @@
|
|||||||
{ "node": true
|
|
||||||
, "browser": true
|
|
||||||
, "jquery": true
|
|
||||||
, "globals": { "angular": true, "Promise": true }
|
|
||||||
|
|
||||||
, "indent": 2
|
|
||||||
, "onevar": true
|
|
||||||
, "laxcomma": true
|
|
||||||
, "laxbreak": true
|
|
||||||
, "curly": true
|
|
||||||
, "nonbsp": true
|
|
||||||
|
|
||||||
, "eqeqeq": true
|
|
||||||
, "immed": true
|
|
||||||
, "undef": true
|
|
||||||
, "unused": true
|
|
||||||
, "latedef": true
|
|
||||||
}
|
|
41
LICENSE
41
LICENSE
@ -1,41 +0,0 @@
|
|||||||
Copyright 2018 AJ ONeal
|
|
||||||
|
|
||||||
This is open source software; you can redistribute it and/or modify it under the
|
|
||||||
terms of either:
|
|
||||||
|
|
||||||
a) the "MIT License"
|
|
||||||
b) the "Apache-2.0 License"
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
Apache-2.0 License Summary
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
10
compat.js
10
compat.js
@ -1,5 +1,4 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
/* global Promise */
|
|
||||||
|
|
||||||
var ACME2 = require('./').ACME;
|
var ACME2 = require('./').ACME;
|
||||||
|
|
||||||
@ -32,10 +31,13 @@ function create(deps) {
|
|||||||
options.agreeToTerms = options.agreeToTerms || function (tos) {
|
options.agreeToTerms = options.agreeToTerms || function (tos) {
|
||||||
return Promise.resolve(tos);
|
return Promise.resolve(tos);
|
||||||
};
|
};
|
||||||
acme2.certificates.create(options).then(function (certs) {
|
acme2.certificates.create(options).then(function (chainPem) {
|
||||||
var privkeyPem = acme2.RSA.exportPrivatePem(options.domainKeypair);
|
var privkeyPem = acme2.RSA.exportPrivatePem(options.domainKeypair);
|
||||||
certs.privkey = privkeyPem;
|
resolveFn(cb)({
|
||||||
resolveFn(cb)(certs);
|
cert: chainPem.split(/[\r\n]{2,}/g)[0] + '\r\n'
|
||||||
|
, privkey: privkeyPem
|
||||||
|
, chain: chainPem.split(/[\r\n]{2,}/g)[1] + '\r\n'
|
||||||
|
});
|
||||||
}, rejectFn(cb));
|
}, rejectFn(cb));
|
||||||
};
|
};
|
||||||
acme2.getAcmeUrls = function (options, cb) {
|
acme2.getAcmeUrls = function (options, cb) {
|
||||||
|
165
node.js
165
node.js
@ -8,15 +8,6 @@
|
|||||||
|
|
||||||
var ACME = module.exports.ACME = {};
|
var ACME = module.exports.ACME = {};
|
||||||
|
|
||||||
ACME.formatPemChain = function formatPemChain(str) {
|
|
||||||
return str.trim().replace(/[\r\n]+/g, '\n').replace(/\-\n\-/g, '-\n\n-') + '\n';
|
|
||||||
};
|
|
||||||
ACME.splitPemChain = function splitPemChain(str) {
|
|
||||||
return str.trim().split(/[\r\n]{2,}/g).map(function (str) {
|
|
||||||
return str + '\n';
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
ACME.challengePrefixes = {
|
ACME.challengePrefixes = {
|
||||||
'http-01': '/.well-known/acme-challenge'
|
'http-01': '/.well-known/acme-challenge'
|
||||||
, 'dns-01': '_acme-challenge'
|
, 'dns-01': '_acme-challenge'
|
||||||
@ -115,7 +106,7 @@ ACME._getNonce = function (me) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
ACME._registerAccount = function (me, options) {
|
ACME._registerAccount = function (me, options) {
|
||||||
if (me.debug) { console.debug('[acme-v2] accounts.create'); }
|
if (me.debug) console.debug('[acme-v2] accounts.create');
|
||||||
|
|
||||||
return ACME._getNonce(me).then(function () {
|
return ACME._getNonce(me).then(function () {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
@ -134,7 +125,7 @@ ACME._registerAccount = function (me, options) {
|
|||||||
if (options.contact) {
|
if (options.contact) {
|
||||||
contact = options.contact.slice(0);
|
contact = options.contact.slice(0);
|
||||||
} else if (options.email) {
|
} else if (options.email) {
|
||||||
contact = [ 'mailto:' + options.email ];
|
contact = [ 'mailto:' + options.email ]
|
||||||
}
|
}
|
||||||
var body = {
|
var body = {
|
||||||
termsOfServiceAgreed: tosUrl === me._tos
|
termsOfServiceAgreed: tosUrl === me._tos
|
||||||
@ -149,7 +140,7 @@ ACME._registerAccount = function (me, options) {
|
|||||||
, kid: options.externalAccount.id
|
, kid: options.externalAccount.id
|
||||||
, url: me._directoryUrls.newAccount
|
, url: me._directoryUrls.newAccount
|
||||||
}
|
}
|
||||||
, Buffer.from(JSON.stringify(jwk))
|
, new Buffer(JSON.stringify(jwk))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
var payload = JSON.stringify(body);
|
var payload = JSON.stringify(body);
|
||||||
@ -161,12 +152,12 @@ ACME._registerAccount = function (me, options) {
|
|||||||
, url: me._directoryUrls.newAccount
|
, url: me._directoryUrls.newAccount
|
||||||
, jwk: jwk
|
, jwk: jwk
|
||||||
}
|
}
|
||||||
, Buffer.from(payload)
|
, new Buffer(payload)
|
||||||
);
|
);
|
||||||
|
|
||||||
delete jws.header;
|
delete jws.header;
|
||||||
if (me.debug) { console.debug('[acme-v2] accounts.create JSON body:'); }
|
if (me.debug) console.debug('[acme-v2] accounts.create JSON body:');
|
||||||
if (me.debug) { console.debug(jws); }
|
if (me.debug) console.debug(jws);
|
||||||
me._nonce = null;
|
me._nonce = null;
|
||||||
return me._request({
|
return me._request({
|
||||||
method: 'POST'
|
method: 'POST'
|
||||||
@ -176,34 +167,34 @@ ACME._registerAccount = function (me, options) {
|
|||||||
}).then(function (resp) {
|
}).then(function (resp) {
|
||||||
var account = resp.body;
|
var account = resp.body;
|
||||||
|
|
||||||
if (2 !== Math.floor(resp.statusCode / 100)) {
|
|
||||||
throw new Error('account error: ' + JSON.stringify(body));
|
|
||||||
}
|
|
||||||
|
|
||||||
me._nonce = resp.toJSON().headers['replay-nonce'];
|
me._nonce = resp.toJSON().headers['replay-nonce'];
|
||||||
var location = resp.toJSON().headers.location;
|
var location = resp.toJSON().headers.location;
|
||||||
// the account id url
|
// the account id url
|
||||||
me._kid = location;
|
me._kid = location;
|
||||||
if (me.debug) { console.debug('[DEBUG] new account location:'); }
|
if (me.debug) console.debug('[DEBUG] new account location:');
|
||||||
if (me.debug) { console.debug(location); }
|
if (me.debug) console.debug(location);
|
||||||
if (me.debug) { console.debug(resp.toJSON()); }
|
if (me.debug) console.debug(resp.toJSON());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
contact: ["mailto:jon@example.com"],
|
id: 5925245,
|
||||||
orders: "https://some-url",
|
key:
|
||||||
|
{ kty: 'RSA',
|
||||||
|
n: 'tBr7m1hVaUNQjUeakznGidnrYyegVUQrsQjNrcipljI9Vxvxd0baHc3vvRZWFyFO5BlS7UDl-KHQdbdqb-MQzfP6T2sNXsOHARQ41pCGY5BYzIPRJF0nD48-CY717is-7BKISv8rf9yx5iSjvK1wZ3Ke3YIpxzK2fWRqccVxXQ92VYioxOfGObACgEUSvdoEttWV2B0Uv4Sdi6zZbk5eo2zALvyGb1P4fKVfQycGLXC41AyhHOAuTqzNCyIkiWEkbfh2lZNcYClP2epS0pHRFXYyjJN6-c8InfM3PISo4k6Qew65HZ-oqUow0tTIgNwuen9q5O6Hc73GvU-2npGJVQ',
|
||||||
|
e: 'AQAB' },
|
||||||
|
contact: [],
|
||||||
|
initialIp: '198.199.82.211',
|
||||||
|
createdAt: '2018-04-16T00:41:00.720584972Z',
|
||||||
status: 'valid'
|
status: 'valid'
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (!account) { account = { _emptyResponse: true, key: {} }; }
|
if (!account) { account = { _emptyResponse: true, key: {} }; }
|
||||||
// https://git.coolaj86.com/coolaj86/acme-v2.js/issues/8
|
|
||||||
if (!account.key) { account.key = {}; }
|
|
||||||
account.key.kid = me._kid;
|
account.key.kid = me._kid;
|
||||||
return account;
|
return account;
|
||||||
}).then(resolve, reject);
|
}).then(resolve, reject);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (me.debug) { console.debug('[acme-v2] agreeToTerms'); }
|
if (me.debug) console.debug('[acme-v2] agreeToTerms');
|
||||||
if (1 === options.agreeToTerms.length) {
|
if (1 === options.agreeToTerms.length) {
|
||||||
// newer promise API
|
// newer promise API
|
||||||
return options.agreeToTerms(me._tos).then(agree, reject);
|
return options.agreeToTerms(me._tos).then(agree, reject);
|
||||||
@ -243,7 +234,7 @@ ACME._registerAccount = function (me, options) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
ACME._getChallenges = function (me, options, auth) {
|
ACME._getChallenges = function (me, options, auth) {
|
||||||
if (me.debug) { console.debug('\n[DEBUG] getChallenges\n'); }
|
if (me.debug) console.debug('\n[DEBUG] getChallenges\n');
|
||||||
return me._request({ method: 'GET', url: auth, json: true }).then(function (resp) {
|
return me._request({ method: 'GET', url: auth, json: true }).then(function (resp) {
|
||||||
return resp.body;
|
return resp.body;
|
||||||
});
|
});
|
||||||
@ -297,7 +288,7 @@ ACME._postChallenge = function (me, options, identifier, ch) {
|
|||||||
options.accountKeypair
|
options.accountKeypair
|
||||||
, undefined
|
, undefined
|
||||||
, { nonce: me._nonce, alg: 'RS256', url: ch.url, kid: me._kid }
|
, { nonce: me._nonce, alg: 'RS256', url: ch.url, kid: me._kid }
|
||||||
, Buffer.from(JSON.stringify({ "status": "deactivated" }))
|
, new Buffer(JSON.stringify({ "status": "deactivated" }))
|
||||||
);
|
);
|
||||||
me._nonce = null;
|
me._nonce = null;
|
||||||
return me._request({
|
return me._request({
|
||||||
@ -306,14 +297,14 @@ ACME._postChallenge = function (me, options, identifier, ch) {
|
|||||||
, headers: { 'Content-Type': 'application/jose+json' }
|
, headers: { 'Content-Type': 'application/jose+json' }
|
||||||
, json: jws
|
, json: jws
|
||||||
}).then(function (resp) {
|
}).then(function (resp) {
|
||||||
if (me.debug) { console.debug('[acme-v2.js] deactivate:'); }
|
if (me.debug) console.debug('[acme-v2.js] deactivate:');
|
||||||
if (me.debug) { console.debug(resp.headers); }
|
if (me.debug) console.debug(resp.headers);
|
||||||
if (me.debug) { console.debug(resp.body); }
|
if (me.debug) console.debug(resp.body);
|
||||||
if (me.debug) { console.debug(); }
|
if (me.debug) console.debug();
|
||||||
|
|
||||||
me._nonce = resp.toJSON().headers['replay-nonce'];
|
me._nonce = resp.toJSON().headers['replay-nonce'];
|
||||||
if (me.debug) { console.debug('deactivate challenge: resp.body:'); }
|
if (me.debug) console.debug('deactivate challenge: resp.body:');
|
||||||
if (me.debug) { console.debug(resp.body); }
|
if (me.debug) console.debug(resp.body);
|
||||||
return ACME._wait(10 * 1000);
|
return ACME._wait(10 * 1000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -325,11 +316,11 @@ ACME._postChallenge = function (me, options, identifier, ch) {
|
|||||||
|
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
||||||
if (me.debug) { console.debug('\n[DEBUG] statusChallenge\n'); }
|
if (me.debug) console.debug('\n[DEBUG] statusChallenge\n');
|
||||||
return me._request({ method: 'GET', url: ch.url, json: true }).then(function (resp) {
|
return me._request({ method: 'GET', url: ch.url, json: true }).then(function (resp) {
|
||||||
|
|
||||||
if ('processing' === resp.body.status) {
|
if ('processing' === resp.body.status) {
|
||||||
if (me.debug) { console.debug('poll: again'); }
|
if (me.debug) console.debug('poll: again');
|
||||||
return ACME._wait(1 * 1000).then(pollStatus);
|
return ACME._wait(1 * 1000).then(pollStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,12 +329,12 @@ ACME._postChallenge = function (me, options, identifier, ch) {
|
|||||||
if (count >= 4) {
|
if (count >= 4) {
|
||||||
return ACME._wait(1 * 1000).then(deactivate).then(testChallenge);
|
return ACME._wait(1 * 1000).then(deactivate).then(testChallenge);
|
||||||
}
|
}
|
||||||
if (me.debug) { console.debug('poll: again'); }
|
if (me.debug) console.debug('poll: again');
|
||||||
return ACME._wait(1 * 1000).then(testChallenge);
|
return ACME._wait(1 * 1000).then(testChallenge);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('valid' === resp.body.status) {
|
if ('valid' === resp.body.status) {
|
||||||
if (me.debug) { console.debug('poll: valid'); }
|
if (me.debug) console.debug('poll: valid');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (1 === options.removeChallenge.length) {
|
if (1 === options.removeChallenge.length) {
|
||||||
@ -376,7 +367,7 @@ ACME._postChallenge = function (me, options, identifier, ch) {
|
|||||||
options.accountKeypair
|
options.accountKeypair
|
||||||
, undefined
|
, undefined
|
||||||
, { nonce: me._nonce, alg: 'RS256', url: ch.url, kid: me._kid }
|
, { nonce: me._nonce, alg: 'RS256', url: ch.url, kid: me._kid }
|
||||||
, Buffer.from(JSON.stringify({ }))
|
, new Buffer(JSON.stringify({ }))
|
||||||
);
|
);
|
||||||
me._nonce = null;
|
me._nonce = null;
|
||||||
return me._request({
|
return me._request({
|
||||||
@ -385,18 +376,23 @@ ACME._postChallenge = function (me, options, identifier, ch) {
|
|||||||
, headers: { 'Content-Type': 'application/jose+json' }
|
, headers: { 'Content-Type': 'application/jose+json' }
|
||||||
, json: jws
|
, json: jws
|
||||||
}).then(function (resp) {
|
}).then(function (resp) {
|
||||||
if (me.debug) { console.debug('[acme-v2.js] challenge accepted!'); }
|
if (me.debug) console.debug('[acme-v2.js] challenge accepted!');
|
||||||
if (me.debug) { console.debug(resp.headers); }
|
if (me.debug) console.debug(resp.headers);
|
||||||
if (me.debug) { console.debug(resp.body); }
|
if (me.debug) console.debug(resp.body);
|
||||||
if (me.debug) { console.debug(); }
|
if (me.debug) console.debug();
|
||||||
|
|
||||||
me._nonce = resp.toJSON().headers['replay-nonce'];
|
me._nonce = resp.toJSON().headers['replay-nonce'];
|
||||||
if (me.debug) { console.debug('respond to challenge: resp.body:'); }
|
if (me.debug) console.debug('respond to challenge: resp.body:');
|
||||||
if (me.debug) { console.debug(resp.body); }
|
if (me.debug) console.debug(resp.body);
|
||||||
return ACME._wait(1 * 1000).then(pollStatus);
|
return ACME._wait(1 * 1000).then(pollStatus).then(resolve, reject);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function failChallenge(err) {
|
||||||
|
if (err) { reject(err); return; }
|
||||||
|
return testChallenge();
|
||||||
|
}
|
||||||
|
|
||||||
function testChallenge() {
|
function testChallenge() {
|
||||||
// TODO put check dns / http checks here?
|
// TODO put check dns / http checks here?
|
||||||
// http-01: GET https://example.org/.well-known/acme-challenge/{{token}} => {{keyAuth}}
|
// http-01: GET https://example.org/.well-known/acme-challenge/{{token}} => {{keyAuth}}
|
||||||
@ -414,27 +410,11 @@ ACME._postChallenge = function (me, options, identifier, ch) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (1 === options.setChallenge.length) {
|
if (1 === options.setChallenge.length) {
|
||||||
options.setChallenge(auth).then(testChallenge).then(resolve, reject);
|
options.setChallenge(auth).then(testChallenge, reject);
|
||||||
} else if (2 === options.setChallenge.length) {
|
} else if (2 === options.setChallenge.length) {
|
||||||
options.setChallenge(auth, function (err) {
|
options.setChallenge(auth, failChallenge);
|
||||||
if(err) {
|
|
||||||
reject(err);
|
|
||||||
} else {
|
|
||||||
testChallenge().then(resolve, reject);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
var challengeCb = function(err) {
|
options.setChallenge(identifier.value, ch.token, keyAuthorization, failChallenge);
|
||||||
if(err) {
|
|
||||||
reject(err);
|
|
||||||
} else {
|
|
||||||
testChallenge().then(resolve, reject);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Object.keys(auth).forEach(function (key) {
|
|
||||||
challengeCb[key] = auth[key];
|
|
||||||
});
|
|
||||||
options.setChallenge(identifier.value, ch.token, keyAuthorization, challengeCb);
|
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
reject(e);
|
reject(e);
|
||||||
@ -442,7 +422,7 @@ ACME._postChallenge = function (me, options, identifier, ch) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
ACME._finalizeOrder = function (me, options, validatedDomains) {
|
ACME._finalizeOrder = function (me, options, validatedDomains) {
|
||||||
if (me.debug) { console.debug('finalizeOrder:'); }
|
if (me.debug) console.debug('finalizeOrder:');
|
||||||
var csr = me.RSA.generateCsrWeb64(options.domainKeypair, validatedDomains);
|
var csr = me.RSA.generateCsrWeb64(options.domainKeypair, validatedDomains);
|
||||||
var body = { csr: csr };
|
var body = { csr: csr };
|
||||||
var payload = JSON.stringify(body);
|
var payload = JSON.stringify(body);
|
||||||
@ -452,10 +432,10 @@ ACME._finalizeOrder = function (me, options, validatedDomains) {
|
|||||||
options.accountKeypair
|
options.accountKeypair
|
||||||
, undefined
|
, undefined
|
||||||
, { nonce: me._nonce, alg: 'RS256', url: me._finalize, kid: me._kid }
|
, { nonce: me._nonce, alg: 'RS256', url: me._finalize, kid: me._kid }
|
||||||
, Buffer.from(payload)
|
, new Buffer(payload)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (me.debug) { console.debug('finalize:', me._finalize); }
|
if (me.debug) console.debug('finalize:', me._finalize);
|
||||||
me._nonce = null;
|
me._nonce = null;
|
||||||
return me._request({
|
return me._request({
|
||||||
method: 'POST'
|
method: 'POST'
|
||||||
@ -467,21 +447,21 @@ ACME._finalizeOrder = function (me, options, validatedDomains) {
|
|||||||
// Possible values are: "pending" => ("invalid" || "ready") => "processing" => "valid"
|
// Possible values are: "pending" => ("invalid" || "ready") => "processing" => "valid"
|
||||||
me._nonce = resp.toJSON().headers['replay-nonce'];
|
me._nonce = resp.toJSON().headers['replay-nonce'];
|
||||||
|
|
||||||
if (me.debug) { console.debug('order finalized: resp.body:'); }
|
if (me.debug) console.debug('order finalized: resp.body:');
|
||||||
if (me.debug) { console.debug(resp.body); }
|
if (me.debug) console.debug(resp.body);
|
||||||
|
|
||||||
if ('valid' === resp.body.status) {
|
if ('valid' === resp.body.status) {
|
||||||
me._expires = resp.body.expires;
|
me._expires = resp.body.expires;
|
||||||
me._certificate = resp.body.certificate;
|
me._certificate = resp.body.certificate;
|
||||||
|
|
||||||
return resp.body; // return order
|
return resp.body;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('processing' === resp.body.status) {
|
if ('processing' === resp.body.status) {
|
||||||
return ACME._wait().then(pollCert);
|
return ACME._wait().then(pollCert);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (me.debug) { console.debug("Error: bad status:\n" + JSON.stringify(resp.body, null, 2)); }
|
if (me.debug) console.debug("Error: bad status:\n" + JSON.stringify(resp.body, null, 2));
|
||||||
|
|
||||||
if ('pending' === resp.body.status) {
|
if ('pending' === resp.body.status) {
|
||||||
return Promise.reject(new Error(
|
return Promise.reject(new Error(
|
||||||
@ -522,7 +502,7 @@ ACME._finalizeOrder = function (me, options, validatedDomains) {
|
|||||||
return pollCert();
|
return pollCert();
|
||||||
};
|
};
|
||||||
ACME._getCertificate = function (me, options) {
|
ACME._getCertificate = function (me, options) {
|
||||||
if (me.debug) { console.debug('[acme-v2] DEBUG get cert 1'); }
|
if (me.debug) console.debug('[acme-v2] DEBUG get cert 1');
|
||||||
|
|
||||||
if (!options.challengeTypes) {
|
if (!options.challengeTypes) {
|
||||||
if (!options.challengeType) {
|
if (!options.challengeType) {
|
||||||
@ -542,7 +522,7 @@ ACME._getCertificate = function (me, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (me.debug) { console.debug('[acme-v2] certificates.create'); }
|
if (me.debug) console.debug('[acme-v2] certificates.create');
|
||||||
return ACME._getNonce(me).then(function () {
|
return ACME._getNonce(me).then(function () {
|
||||||
var body = {
|
var body = {
|
||||||
identifiers: options.domains.map(function (hostname) {
|
identifiers: options.domains.map(function (hostname) {
|
||||||
@ -557,10 +537,10 @@ ACME._getCertificate = function (me, options) {
|
|||||||
options.accountKeypair
|
options.accountKeypair
|
||||||
, undefined
|
, undefined
|
||||||
, { nonce: me._nonce, alg: 'RS256', url: me._directoryUrls.newOrder, kid: me._kid }
|
, { nonce: me._nonce, alg: 'RS256', url: me._directoryUrls.newOrder, kid: me._kid }
|
||||||
, Buffer.from(payload)
|
, new Buffer(payload)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (me.debug) { console.debug('\n[DEBUG] newOrder\n'); }
|
if (me.debug) console.debug('\n[DEBUG] newOrder\n');
|
||||||
me._nonce = null;
|
me._nonce = null;
|
||||||
return me._request({
|
return me._request({
|
||||||
method: 'POST'
|
method: 'POST'
|
||||||
@ -571,8 +551,8 @@ ACME._getCertificate = function (me, options) {
|
|||||||
me._nonce = resp.toJSON().headers['replay-nonce'];
|
me._nonce = resp.toJSON().headers['replay-nonce'];
|
||||||
var location = resp.toJSON().headers.location;
|
var location = resp.toJSON().headers.location;
|
||||||
var auths;
|
var auths;
|
||||||
if (me.debug) { console.debug(location); } // the account id url
|
if (me.debug) console.debug(location); // the account id url
|
||||||
if (me.debug) { console.debug(resp.toJSON()); }
|
if (me.debug) console.debug(resp.toJSON());
|
||||||
me._authorizations = resp.body.authorizations;
|
me._authorizations = resp.body.authorizations;
|
||||||
me._order = location;
|
me._order = location;
|
||||||
me._finalize = resp.body.finalize;
|
me._finalize = resp.body.finalize;
|
||||||
@ -583,7 +563,7 @@ ACME._getCertificate = function (me, options) {
|
|||||||
console.error(resp.body);
|
console.error(resp.body);
|
||||||
return Promise.reject(new Error("authorizations were not fetched"));
|
return Promise.reject(new Error("authorizations were not fetched"));
|
||||||
}
|
}
|
||||||
if (me.debug) { console.debug("[acme-v2] POST newOrder has authorizations"); }
|
if (me.debug) console.debug("47 &#&#&#&#&#&#&&##&#&#&#&#&#&#&#&");
|
||||||
|
|
||||||
//return resp.body;
|
//return resp.body;
|
||||||
auths = me._authorizations.slice(0);
|
auths = me._authorizations.slice(0);
|
||||||
@ -617,29 +597,18 @@ ACME._getCertificate = function (me, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return next().then(function () {
|
return next().then(function () {
|
||||||
if (me.debug) { console.debug("[getCertificate] next.then"); }
|
if (me.debug) console.debug("37 &#&#&#&#&#&#&&##&#&#&#&#&#&#&#&");
|
||||||
var validatedDomains = body.identifiers.map(function (ident) {
|
var validatedDomains = body.identifiers.map(function (ident) {
|
||||||
return ident.value;
|
return ident.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
return ACME._finalizeOrder(me, options, validatedDomains);
|
return ACME._finalizeOrder(me, options, validatedDomains);
|
||||||
}).then(function (order) {
|
}).then(function () {
|
||||||
if (me.debug) { console.debug('acme-v2: order was finalized'); }
|
if (me.debug) console.debug('acme-v2: order was finalized');
|
||||||
return me._request({ method: 'GET', url: me._certificate, json: true }).then(function (resp) {
|
return me._request({ method: 'GET', url: me._certificate, json: true }).then(function (resp) {
|
||||||
if (me.debug) { console.debug('acme-v2: csr submitted and cert received:'); }
|
if (me.debug) console.debug('acme-v2: csr submitted and cert received:');
|
||||||
// https://github.com/certbot/certbot/issues/5721
|
if (me.debug) console.debug(resp.body);
|
||||||
var certsarr = ACME.splitPemChain(ACME.formatPemChain((resp.body||'')));
|
return resp.body;
|
||||||
// cert, chain, fullchain, privkey, /*TODO, subject, altnames, issuedAt, expiresAt */
|
|
||||||
var certs = {
|
|
||||||
expires: order.expires
|
|
||||||
, identifiers: order.identifiers
|
|
||||||
//, authorizations: order.authorizations
|
|
||||||
, cert: certsarr.shift()
|
|
||||||
//, privkey: privkeyPem
|
|
||||||
, chain: certsarr.join('\n')
|
|
||||||
};
|
|
||||||
if (me.debug) { console.debug(certs); }
|
|
||||||
return certs;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -651,7 +620,7 @@ ACME.create = function create(me) {
|
|||||||
// me.debug = true;
|
// me.debug = true;
|
||||||
me.challengePrefixes = ACME.challengePrefixes;
|
me.challengePrefixes = ACME.challengePrefixes;
|
||||||
me.RSA = me.RSA || require('rsa-compat').RSA;
|
me.RSA = me.RSA || require('rsa-compat').RSA;
|
||||||
me.request = me.request || require('@coolaj86/urequest');
|
me.request = me.request || require('request');
|
||||||
me._dig = function (query) {
|
me._dig = function (query) {
|
||||||
// TODO use digd.js
|
// TODO use digd.js
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
|
38
package.json
38
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "acme-v2",
|
"name": "acme-v2",
|
||||||
"version": "1.2.0",
|
"version": "1.0.7",
|
||||||
"description": "Free SSL. A framework for building Let's Encrypt v2 clients, and other ACME v2 (draft 11) clients. Successor to le-acme-core.js",
|
"description": "Free SSL. A framework for building Let's Encrypt v2 clients, and other ACME v2 (draft 11) clients. Successor to le-acme-core.js",
|
||||||
"homepage": "https://git.coolaj86.com/coolaj86/acme-v2.js",
|
"homepage": "https://git.coolaj86.com/coolaj86/acme-v2.js",
|
||||||
"main": "node.js",
|
"main": "node.js",
|
||||||
@ -12,21 +12,37 @@
|
|||||||
"url": "ssh://gitea@git.coolaj86.com:22042/coolaj86/acme-v2.js.git"
|
"url": "ssh://gitea@git.coolaj86.com:22042/coolaj86/acme-v2.js.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Let's Encrypt",
|
"acmev2",
|
||||||
"ACME",
|
"acmev02",
|
||||||
"v02",
|
"acme-v2",
|
||||||
"v2",
|
"acme-v02",
|
||||||
"draft-11",
|
"acme",
|
||||||
"draft-12",
|
"acme2",
|
||||||
"free ssl",
|
"acme11",
|
||||||
|
"acme-draft11",
|
||||||
|
"acme-draft-11",
|
||||||
|
"draft",
|
||||||
|
"11",
|
||||||
|
"ssl",
|
||||||
"tls",
|
"tls",
|
||||||
"automated https",
|
"https",
|
||||||
"letsencrypt"
|
"Let's Encrypt",
|
||||||
|
"letsencrypt",
|
||||||
|
"letsencrypt-v2",
|
||||||
|
"letsencrypt-v02",
|
||||||
|
"letsencryptv2",
|
||||||
|
"letsencryptv02",
|
||||||
|
"letsencrypt2",
|
||||||
|
"greenlock",
|
||||||
|
"greenlock2"
|
||||||
],
|
],
|
||||||
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
||||||
"license": "(MIT OR Apache-2.0)",
|
"license": "(MIT OR Apache-2.0)",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@coolaj86/urequest": "^1.1.1",
|
"request": "^2.85.0",
|
||||||
"rsa-compat": "^1.3.0"
|
"rsa-compat": "^1.3.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"bluebird": "^3.5.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,23 +12,10 @@ module.exports.run = function (directoryUrl, RSA, web, chType, email, accountKey
|
|||||||
agree(null, tosUrl);
|
agree(null, tosUrl);
|
||||||
}
|
}
|
||||||
, setChallenge: function (hostname, token, val, cb) {
|
, setChallenge: function (hostname, token, val, cb) {
|
||||||
var pathname;
|
var pathname = hostname + acme2.acmeChallengePrefix + token;
|
||||||
|
console.log("Put the string '" + val + "' into a file at '" + pathname + "'");
|
||||||
if ('http-01' === cb.type) {
|
console.log("echo '" + val + "' > '" + pathname + "'");
|
||||||
pathname = hostname + acme2.acmeChallengePrefix + token;
|
console.log("\nThen hit the 'any' key to continue...");
|
||||||
console.log("Put the string '" + val /*keyAuthorization*/ + "' into a file at '" + pathname + "'");
|
|
||||||
console.log("echo '" + val /*keyAuthorization*/ + "' > '" + pathname + "'");
|
|
||||||
console.log("\nThen hit the 'any' key to continue...");
|
|
||||||
} else if ('dns-01' === cb.type) {
|
|
||||||
// forwards-backwards compat
|
|
||||||
pathname = acme2.challengePrefixes['dns-01'] + "." + hostname.replace(/^\*\./, '');
|
|
||||||
console.log("Put the string '" + cb.dnsAuthorization + "' into the TXT record '" + pathname + "'");
|
|
||||||
console.log("dig TXT " + pathname + " '" + cb.dnsAuthorization + "'");
|
|
||||||
console.log("\nThen hit the 'any' key to continue...");
|
|
||||||
} else {
|
|
||||||
cb(new Error("[acme-v2] unrecognized challenge type: " + cb.type));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onAny() {
|
function onAny() {
|
||||||
console.log("'any' key was hit");
|
console.log("'any' key was hit");
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/*
|
|
||||||
-----BEGIN CERTIFICATE-----LF
|
|
||||||
xxxLF
|
|
||||||
yyyLF
|
|
||||||
-----END CERTIFICATE-----LF
|
|
||||||
LF
|
|
||||||
-----BEGIN CERTIFICATE-----LF
|
|
||||||
xxxLF
|
|
||||||
yyyLF
|
|
||||||
-----END CERTIFICATE-----LF
|
|
||||||
|
|
||||||
Rules
|
|
||||||
* Only Unix LF (\n) Line endings
|
|
||||||
* Each PEM's lines are separated with \n
|
|
||||||
* Each PEM ends with \n
|
|
||||||
* Each PEM is separated with a \n (just like commas separating an array)
|
|
||||||
*/
|
|
||||||
|
|
||||||
// https://github.com/certbot/certbot/issues/5721#issuecomment-402362709
|
|
||||||
var expected = "----\nxxxx\nyyyy\n----\n\n----\nxxxx\nyyyy\n----\n";
|
|
||||||
var tests = [
|
|
||||||
"----\r\nxxxx\r\nyyyy\r\n----\r\n\r\n----\r\nxxxx\r\nyyyy\r\n----\r\n"
|
|
||||||
, "----\r\nxxxx\r\nyyyy\r\n----\r\n----\r\nxxxx\r\nyyyy\r\n----\r\n"
|
|
||||||
, "----\nxxxx\nyyyy\n----\n\n----\r\nxxxx\r\nyyyy\r\n----"
|
|
||||||
, "----\nxxxx\nyyyy\n----\n----\r\nxxxx\r\nyyyy\r\n----"
|
|
||||||
, "----\nxxxx\nyyyy\n----\n----\nxxxx\nyyyy\n----"
|
|
||||||
, "----\nxxxx\nyyyy\n----\n----\nxxxx\nyyyy\n----\n"
|
|
||||||
, "----\nxxxx\nyyyy\n----\n\n----\nxxxx\nyyyy\n----\n"
|
|
||||||
, "----\nxxxx\nyyyy\n----\r\n----\nxxxx\ryyyy\n----\n"
|
|
||||||
];
|
|
||||||
|
|
||||||
function formatPemChain(str) {
|
|
||||||
return str.trim().replace(/[\r\n]+/g, '\n').replace(/\-\n\-/g, '-\n\n-') + '\n';
|
|
||||||
}
|
|
||||||
function splitPemChain(str) {
|
|
||||||
return str.trim().split(/[\r\n]{2,}/g).map(function (str) {
|
|
||||||
return str + '\n';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
tests.forEach(function (str) {
|
|
||||||
var actual = formatPemChain(str);
|
|
||||||
if (expected !== actual) {
|
|
||||||
console.error('input: ', JSON.stringify(str));
|
|
||||||
console.error('expected:', JSON.stringify(expected));
|
|
||||||
console.error('actual: ', JSON.stringify(actual));
|
|
||||||
throw new Error("did not pass");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (
|
|
||||||
"----\nxxxx\nyyyy\n----\n"
|
|
||||||
!==
|
|
||||||
formatPemChain("\n\n----\r\nxxxx\r\nyyyy\r\n----\n\n")
|
|
||||||
) {
|
|
||||||
throw new Error("Not proper for single cert in chain");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
"--B--\nxxxx\nyyyy\n--E--\n\n--B--\nxxxx\nyyyy\n--E--\n\n--B--\nxxxx\nyyyy\n--E--\n"
|
|
||||||
!==
|
|
||||||
formatPemChain("\n\n\n--B--\nxxxx\nyyyy\n--E--\n\n\n\n--B--\nxxxx\nyyyy\n--E--\n\n\n--B--\nxxxx\nyyyy\n--E--\n\n\n")
|
|
||||||
) {
|
|
||||||
throw new Error("Not proper for three certs in chain");
|
|
||||||
}
|
|
||||||
|
|
||||||
splitPemChain(
|
|
||||||
"--B--\nxxxx\nyyyy\n--E--\n\n--B--\nxxxx\nyyyy\n--E--\n\n--B--\nxxxx\nyyyy\n--E--\n"
|
|
||||||
).forEach(function (str) {
|
|
||||||
if ("--B--\nxxxx\nyyyy\n--E--\n" !== str) {
|
|
||||||
throw new Error("bad thingy");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
console.info('PASS');
|
|
@ -35,9 +35,9 @@ module.exports.run = function run(directoryUrl, RSA, web, chType, email, account
|
|||||||
console.log("Put the string '" + opts.keyAuthorization + "' into a file at '" + pathname + "'");
|
console.log("Put the string '" + opts.keyAuthorization + "' into a file at '" + pathname + "'");
|
||||||
console.log("echo '" + opts.keyAuthorization + "' > '" + pathname + "'");
|
console.log("echo '" + opts.keyAuthorization + "' > '" + pathname + "'");
|
||||||
} else if ('dns-01' === opts.type) {
|
} else if ('dns-01' === opts.type) {
|
||||||
pathname = acme2.challengePrefixes['dns-01'] + "." + opts.hostname.replace(/^\*\./, '');
|
pathname = acme2.challengePrefixes['dns-01'] + "." + opts.hostname.replace(/^\*\./, '');;
|
||||||
console.log("Put the string '" + opts.dnsAuthorization + "' into the TXT record '" + pathname + "'");
|
console.log("Put the string '" + opts.dnsAuthorization + "' into the TXT record '" + pathname + "'");
|
||||||
console.log("dig TXT " + pathname + " '" + opts.dnsAuthorization + "'");
|
console.log("ddig TXT " + pathname + " '" + opts.dnsAuthorization + "'");
|
||||||
} else {
|
} else {
|
||||||
reject(new Error("[acme-v2] unrecognized challenge type"));
|
reject(new Error("[acme-v2] unrecognized challenge type"));
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user