add .prettierrc, and make prettier
This commit is contained in:
parent
466de61232
commit
f2b6772f5c
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"bracketSpacing": true,
|
||||
"printWidth": 80,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "none",
|
||||
"useTabs": true
|
||||
}
|
118
README.md
118
README.md
|
@ -8,21 +8,21 @@
|
|||
|
||||
# [acme-v2.js](https://git.coolaj86.com/coolaj86/acme-v2.js)
|
||||
|
||||
A lightweight, **Low Dependency*** framework for building
|
||||
A lightweight, **Low Dependency**\* framework for building
|
||||
Let's Encrypt v2 (ACME draft 12) clients, successor to `le-acme-core.js`.
|
||||
Built [by request](https://git.coolaj86.com/coolaj86/greenlock.js/issues/5#issuecomment-8).
|
||||
|
||||
* <small>although `node-forge` and `ursa` are included as `optionalDependencies`
|
||||
\* <small>although `node-forge` and `ursa` are included as `optionalDependencies`
|
||||
for backwards compatibility with older versions of node, there are no other
|
||||
dependencies except those that I wrote for this (and related) projects.</small>
|
||||
|
||||
## Looking for Quick 'n' Easy™?
|
||||
|
||||
If you're looking to *build a webserver*, try [greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js).
|
||||
If you're looking for an *ACME-enabled webserver*, try [goldilocks.js](https://git.coolaj86.com/coolaj86/goldilocks.js).
|
||||
If you're looking to _build a webserver_, try [greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js).
|
||||
If you're looking for an _ACME-enabled webserver_, try [goldilocks.js](https://git.coolaj86.com/coolaj86/goldilocks.js).
|
||||
|
||||
* [greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js)
|
||||
* [goldilocks.js](https://git.coolaj86.com/coolaj86/goldilocks.js)
|
||||
- [greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js)
|
||||
- [goldilocks.js](https://git.coolaj86.com/coolaj86/goldilocks.js)
|
||||
|
||||
## How to build ACME clients
|
||||
|
||||
|
@ -77,20 +77,20 @@ https://acme-staging-v02.api.letsencrypt.org/directory
|
|||
|
||||
## Two API versions, Two Implementations
|
||||
|
||||
This library (acme-v2.js) supports ACME [*draft 11*](https://tools.ietf.org/html/draft-ietf-acme-acme-11),
|
||||
This library (acme-v2.js) supports ACME [_draft 11_](https://tools.ietf.org/html/draft-ietf-acme-acme-11),
|
||||
otherwise known as Let's Encrypt v2 (or v02).
|
||||
|
||||
* ACME draft 11
|
||||
* Let's Encrypt v2
|
||||
* Let's Encrypt v02
|
||||
- ACME draft 11
|
||||
- Let's Encrypt v2
|
||||
- Let's Encrypt v02
|
||||
|
||||
The predecessor (le-acme-core) supports Let's Encrypt v1 (or v01), which was a
|
||||
[hodge-podge of various drafts](https://github.com/letsencrypt/boulder/blob/master/docs/acme-divergences.md)
|
||||
of the ACME spec early on.
|
||||
|
||||
* ACME early draft
|
||||
* Let's Encrypt v1
|
||||
* Let's Encrypt v01
|
||||
- ACME early draft
|
||||
- Let's Encrypt v1
|
||||
- Let's Encrypt v01
|
||||
|
||||
This library maintains compatibility with le-acme-core so that it can be used as a **drop-in replacement**
|
||||
and requires **no changes to existing code**,
|
||||
|
@ -102,7 +102,7 @@ Status: Stable, Locked, Bugfix-only
|
|||
|
||||
See Full Documentation at <https://git.coolaj86.com/coolaj86/le-acme-core.js>
|
||||
|
||||
```
|
||||
```js
|
||||
var RSA = require('rsa-compat').RSA;
|
||||
var acme = require('acme-v2/compat.js').ACME.create({ RSA: RSA });
|
||||
|
||||
|
@ -118,7 +118,7 @@ Status: Almost stable, but **not semver locked**
|
|||
This API is a simple evolution of le-acme-core,
|
||||
but tries to provide a better mapping to the new draft 11 APIs.
|
||||
|
||||
```
|
||||
```js
|
||||
// Create Instance (Dependency Injection)
|
||||
var ACME = require('acme-v2').ACME.create({
|
||||
RSA: require('rsa-compat').RSA
|
||||
|
@ -187,54 +187,54 @@ Helpers & Stuff
|
|||
|
||||
```javascript
|
||||
// Constants
|
||||
ACME.challengePrefixes['http-01'] // '/.well-known/acme-challenge'
|
||||
ACME.challengePrefixes['dns-01'] // '_acme-challenge'
|
||||
ACME.challengePrefixes['http-01']; // '/.well-known/acme-challenge'
|
||||
ACME.challengePrefixes['dns-01']; // '_acme-challenge'
|
||||
```
|
||||
|
||||
# Changelog
|
||||
|
||||
* v1.5
|
||||
* perform full test challenge first (even before nonce)
|
||||
* v1.3
|
||||
* Use node RSA keygen by default
|
||||
* No non-optional external deps!
|
||||
* v1.2
|
||||
* fix some API out-of-specness
|
||||
* doc some magic numbers (status)
|
||||
* updated deps
|
||||
* v1.1.0
|
||||
* reduce dependencies (use lightweight @coolaj86/request instead of request)
|
||||
* v1.0.5 - cleanup logging
|
||||
* v1.0.4 - v6- compat use `promisify` from node's util or bluebird
|
||||
* v1.0.3 - documentation cleanup
|
||||
* v1.0.2
|
||||
* use `options.contact` to provide raw contact array
|
||||
* made `options.email` optional
|
||||
* file cleanup
|
||||
* v1.0.1
|
||||
* Compat API is ready for use
|
||||
* Eliminate debug logging
|
||||
* Apr 10, 2018 - tested backwards-compatibility using greenlock.js
|
||||
* Apr 5, 2018 - export http and dns challenge tests
|
||||
* Apr 5, 2018 - test http and dns challenges (success and failure)
|
||||
* Apr 5, 2018 - test subdomains and its wildcard
|
||||
* Apr 5, 2018 - test two subdomains
|
||||
* Apr 5, 2018 - test wildcard
|
||||
* Apr 5, 2018 - completely match api for acme v1 (le-acme-core.js)
|
||||
* Mar 21, 2018 - *mostly* matches le-acme-core.js API
|
||||
* Mar 21, 2018 - can now accept values (not hard coded)
|
||||
* Mar 20, 2018 - SUCCESS - got a test certificate (hard-coded)
|
||||
* Mar 20, 2018 - download certificate
|
||||
* Mar 20, 2018 - poll for status
|
||||
* Mar 20, 2018 - finalize order (submit csr)
|
||||
* Mar 20, 2018 - generate domain keypair
|
||||
* Mar 20, 2018 - respond to challenges
|
||||
* Mar 16, 2018 - get challenges
|
||||
* Mar 16, 2018 - new order
|
||||
* Mar 15, 2018 - create account
|
||||
* Mar 15, 2018 - generate account keypair
|
||||
* Mar 15, 2018 - get nonce
|
||||
* Mar 15, 2018 - get directory
|
||||
- v1.5
|
||||
- perform full test challenge first (even before nonce)
|
||||
- v1.3
|
||||
- Use node RSA keygen by default
|
||||
- No non-optional external deps!
|
||||
- v1.2
|
||||
- fix some API out-of-specness
|
||||
- doc some magic numbers (status)
|
||||
- updated deps
|
||||
- v1.1.0
|
||||
- reduce dependencies (use lightweight @coolaj86/request instead of request)
|
||||
- v1.0.5 - cleanup logging
|
||||
- v1.0.4 - v6- compat use `promisify` from node's util or bluebird
|
||||
- v1.0.3 - documentation cleanup
|
||||
- v1.0.2
|
||||
- use `options.contact` to provide raw contact array
|
||||
- made `options.email` optional
|
||||
- file cleanup
|
||||
- v1.0.1
|
||||
- Compat API is ready for use
|
||||
- Eliminate debug logging
|
||||
- Apr 10, 2018 - tested backwards-compatibility using greenlock.js
|
||||
- Apr 5, 2018 - export http and dns challenge tests
|
||||
- Apr 5, 2018 - test http and dns challenges (success and failure)
|
||||
- Apr 5, 2018 - test subdomains and its wildcard
|
||||
- Apr 5, 2018 - test two subdomains
|
||||
- Apr 5, 2018 - test wildcard
|
||||
- Apr 5, 2018 - completely match api for acme v1 (le-acme-core.js)
|
||||
- Mar 21, 2018 - _mostly_ matches le-acme-core.js API
|
||||
- Mar 21, 2018 - can now accept values (not hard coded)
|
||||
- Mar 20, 2018 - SUCCESS - got a test certificate (hard-coded)
|
||||
- Mar 20, 2018 - download certificate
|
||||
- Mar 20, 2018 - poll for status
|
||||
- Mar 20, 2018 - finalize order (submit csr)
|
||||
- Mar 20, 2018 - generate domain keypair
|
||||
- Mar 20, 2018 - respond to challenges
|
||||
- Mar 16, 2018 - get challenges
|
||||
- Mar 16, 2018 - new order
|
||||
- Mar 15, 2018 - create account
|
||||
- Mar 15, 2018 - generate account keypair
|
||||
- Mar 15, 2018 - get nonce
|
||||
- Mar 15, 2018 - get directory
|
||||
|
||||
# Legal
|
||||
|
||||
|
|
33
compat.js
33
compat.js
|
@ -10,7 +10,9 @@ var ACME2 = require('./').ACME;
|
|||
function resolveFn(cb) {
|
||||
return function(val) {
|
||||
// nextTick to get out of Promise chain
|
||||
process.nextTick(function () { cb(null, val); });
|
||||
process.nextTick(function() {
|
||||
cb(null, val);
|
||||
});
|
||||
};
|
||||
}
|
||||
function rejectFn(cb) {
|
||||
|
@ -19,7 +21,9 @@ function rejectFn(cb) {
|
|||
console.error(err.stack);
|
||||
|
||||
// nextTick to get out of Promise chain
|
||||
process.nextTick(function () { cb(err); });
|
||||
process.nextTick(function() {
|
||||
cb(err);
|
||||
});
|
||||
|
||||
// do not resolve promise further
|
||||
return new Promise(function() {});
|
||||
|
@ -33,7 +37,9 @@ function create(deps) {
|
|||
acme2.accounts.create(options).then(resolveFn(cb), rejectFn(cb));
|
||||
};
|
||||
acme2.getCertificate = function(options, cb) {
|
||||
options.agreeToTerms = options.agreeToTerms || function (tos) {
|
||||
options.agreeToTerms =
|
||||
options.agreeToTerms ||
|
||||
function(tos) {
|
||||
return Promise.resolve(tos);
|
||||
};
|
||||
acme2.certificates.create(options).then(function(certs) {
|
||||
|
@ -62,15 +68,22 @@ function create(deps) {
|
|||
|
||||
module.exports.ACME = {};
|
||||
module.exports.defaults = {
|
||||
productionServerUrl: 'https://acme-v02.api.letsencrypt.org/directory'
|
||||
, stagingServerUrl: 'https://acme-staging-v02.api.letsencrypt.org/directory'
|
||||
, knownEndpoints: [ 'keyChange', 'meta', 'newAccount', 'newNonce', 'newOrder', 'revokeCert' ]
|
||||
, challengeTypes: [ 'http-01', 'dns-01' ]
|
||||
, challengeType: 'http-01'
|
||||
productionServerUrl: 'https://acme-v02.api.letsencrypt.org/directory',
|
||||
stagingServerUrl: 'https://acme-staging-v02.api.letsencrypt.org/directory',
|
||||
knownEndpoints: [
|
||||
'keyChange',
|
||||
'meta',
|
||||
'newAccount',
|
||||
'newNonce',
|
||||
'newOrder',
|
||||
'revokeCert'
|
||||
],
|
||||
challengeTypes: ['http-01', 'dns-01'],
|
||||
challengeType: 'http-01',
|
||||
//, keyType: 'rsa' // ecdsa
|
||||
//, keySize: 2048 // 256
|
||||
, rsaKeySize: 2048 // 256
|
||||
, acmeChallengePrefix: '/.well-known/acme-challenge/'
|
||||
rsaKeySize: 2048, // 256
|
||||
acmeChallengePrefix: '/.well-known/acme-challenge/'
|
||||
};
|
||||
Object.keys(module.exports.defaults).forEach(function(key) {
|
||||
module.exports.ACME[key] = module.exports.defaults[key];
|
||||
|
|
|
@ -14,32 +14,49 @@ var rl = readline.createInterface({
|
|||
require('./genkeypair.js');
|
||||
|
||||
function getWeb() {
|
||||
rl.question('What web address(es) would you like to get certificates for? (ex: example.com,*.example.com) ', function (web) {
|
||||
rl.question(
|
||||
'What web address(es) would you like to get certificates for? (ex: example.com,*.example.com) ',
|
||||
function(web) {
|
||||
web = (web || '').trim().split(/,/g);
|
||||
if (!web[0]) { getWeb(); return; }
|
||||
if (!web[0]) {
|
||||
getWeb();
|
||||
return;
|
||||
}
|
||||
|
||||
if (web.some(function (w) { return '*' === w[0]; })) {
|
||||
if (
|
||||
web.some(function(w) {
|
||||
return '*' === w[0];
|
||||
})
|
||||
) {
|
||||
console.log('Wildcard domains must use dns-01');
|
||||
getEmail(web, 'dns-01');
|
||||
} else {
|
||||
getChallengeType(web);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function getChallengeType(web) {
|
||||
rl.question('What challenge will you be testing today? http-01 or dns-01? [http-01] ', function (chType) {
|
||||
rl.question(
|
||||
'What challenge will you be testing today? http-01 or dns-01? [http-01] ',
|
||||
function(chType) {
|
||||
chType = (chType || '').trim();
|
||||
if (!chType) { chType = 'http-01'; }
|
||||
if (!chType) {
|
||||
chType = 'http-01';
|
||||
}
|
||||
|
||||
getEmail(web, chType);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function getEmail(web, chType) {
|
||||
rl.question('What email should we use? (optional) ', function(email) {
|
||||
email = (email || '').trim();
|
||||
if (!email) { email = null; }
|
||||
if (!email) {
|
||||
email = null;
|
||||
}
|
||||
|
||||
getApiStyle(web, chType, email);
|
||||
});
|
||||
|
@ -47,26 +64,68 @@ function getEmail(web, chType) {
|
|||
|
||||
function getApiStyle(web, chType, email) {
|
||||
var defaultStyle = 'compat';
|
||||
rl.question('What API style would you like to test? v1-compat or promise? [v1-compat] ', function (apiStyle) {
|
||||
rl.question(
|
||||
'What API style would you like to test? v1-compat or promise? [v1-compat] ',
|
||||
function(apiStyle) {
|
||||
apiStyle = (apiStyle || '').trim();
|
||||
if (!apiStyle) { apiStyle = 'v1-compat'; }
|
||||
if (!apiStyle) {
|
||||
apiStyle = 'v1-compat';
|
||||
}
|
||||
|
||||
rl.close();
|
||||
|
||||
var RSA = require('rsa-compat').RSA;
|
||||
var accountKeypair = RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/../tests/account.privkey.pem') });
|
||||
var domainKeypair = RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/../tests/privkey.pem') });
|
||||
var directoryUrl = 'https://acme-staging-v02.api.letsencrypt.org/directory';
|
||||
var accountKeypair = RSA.import({
|
||||
privateKeyPem: require('fs').readFileSync(
|
||||
__dirname + '/../tests/account.privkey.pem'
|
||||
)
|
||||
});
|
||||
var domainKeypair = RSA.import({
|
||||
privateKeyPem: require('fs').readFileSync(
|
||||
__dirname + '/../tests/privkey.pem'
|
||||
)
|
||||
});
|
||||
var directoryUrl =
|
||||
'https://acme-staging-v02.api.letsencrypt.org/directory';
|
||||
|
||||
if ('promise' === apiStyle) {
|
||||
require('../tests/promise.js').run(directoryUrl, RSA, web, chType, email, accountKeypair, domainKeypair);
|
||||
require('../tests/promise.js').run(
|
||||
directoryUrl,
|
||||
RSA,
|
||||
web,
|
||||
chType,
|
||||
email,
|
||||
accountKeypair,
|
||||
domainKeypair
|
||||
);
|
||||
} else if ('cb' === apiStyle) {
|
||||
require('../tests/cb.js').run(directoryUrl, RSA, web, chType, email, accountKeypair, domainKeypair);
|
||||
require('../tests/cb.js').run(
|
||||
directoryUrl,
|
||||
RSA,
|
||||
web,
|
||||
chType,
|
||||
email,
|
||||
accountKeypair,
|
||||
domainKeypair
|
||||
);
|
||||
} else {
|
||||
if ('v1-compat' !== apiStyle) { console.warn("Didn't understand '" + apiStyle + "', using 'v1-compat' instead..."); }
|
||||
require('../tests/compat.js').run(directoryUrl, RSA, web, chType, email, accountKeypair, domainKeypair);
|
||||
if ('v1-compat' !== apiStyle) {
|
||||
console.warn(
|
||||
"Didn't understand '" + apiStyle + "', using 'v1-compat' instead..."
|
||||
);
|
||||
}
|
||||
});
|
||||
require('../tests/compat.js').run(
|
||||
directoryUrl,
|
||||
RSA,
|
||||
web,
|
||||
chType,
|
||||
email,
|
||||
accountKeypair,
|
||||
domainKeypair
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
getWeb();
|
||||
|
|
|
@ -8,7 +8,7 @@ var fs = require('fs');
|
|||
if (!fs.existsSync(__dirname + '/../tests/account.privkey.pem')) {
|
||||
RSA.generateKeypair(2048, 65537, {}, function(err, keypair) {
|
||||
console.log(keypair);
|
||||
var privkeyPem = RSA.exportPrivatePem(keypair)
|
||||
var privkeyPem = RSA.exportPrivatePem(keypair);
|
||||
console.log(privkeyPem);
|
||||
|
||||
fs.writeFileSync(__dirname + '/../tests/account.privkey.pem', privkeyPem);
|
||||
|
@ -18,7 +18,7 @@ if (!fs.existsSync(__dirname + '/../tests/account.privkey.pem')) {
|
|||
if (!fs.existsSync(__dirname + '/../tests/privkey.pem')) {
|
||||
RSA.generateKeypair(2048, 65537, {}, function(err, keypair) {
|
||||
console.log(keypair);
|
||||
var privkeyPem = RSA.exportPrivatePem(keypair)
|
||||
var privkeyPem = RSA.exportPrivatePem(keypair);
|
||||
console.log(privkeyPem);
|
||||
|
||||
fs.writeFileSync(__dirname + '/../tests/privkey.pem', privkeyPem);
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
var http = require('http');
|
||||
var express = require('express');
|
||||
var server = http.createServer(express.static('../tests')).listen(80, function () {
|
||||
var server = http
|
||||
.createServer(express.static('../tests'))
|
||||
.listen(80, function() {
|
||||
console.log('Listening on', this.address());
|
||||
});
|
||||
|
|
|
@ -5,11 +5,16 @@
|
|||
'use strict';
|
||||
|
||||
var https = require('https');
|
||||
var server = https.createServer({
|
||||
key: require('fs').readFileSync('../tests/privkey.pem')
|
||||
, cert: require('fs').readFileSync('../tests/fullchain.pem')
|
||||
}, function (req, res) {
|
||||
res.end("Hello, World!");
|
||||
}).listen(443, function () {
|
||||
var server = https
|
||||
.createServer(
|
||||
{
|
||||
key: require('fs').readFileSync('../tests/privkey.pem'),
|
||||
cert: require('fs').readFileSync('../tests/fullchain.pem')
|
||||
},
|
||||
function(req, res) {
|
||||
res.end('Hello, World!');
|
||||
}
|
||||
)
|
||||
.listen(443, function() {
|
||||
console.log('Listening on', this.address());
|
||||
});
|
||||
|
|
77
tests/cb.js
77
tests/cb.js
|
@ -4,18 +4,26 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
'use strict';
|
||||
|
||||
module.exports.run = function run(directoryUrl, RSA, web, chType, email, accountKeypair, domainKeypair) {
|
||||
module.exports.run = function run(
|
||||
directoryUrl,
|
||||
RSA,
|
||||
web,
|
||||
chType,
|
||||
email,
|
||||
accountKeypair,
|
||||
domainKeypair
|
||||
) {
|
||||
// [ 'test.ppl.family' ] 'coolaj86@gmail.com''http-01'
|
||||
var acme2 = require('../').ACME.create({ RSA: RSA });
|
||||
acme2.init(directoryUrl).then(function() {
|
||||
var options = {
|
||||
agreeToTerms: function(tosUrl, agree) {
|
||||
agree(null, tosUrl);
|
||||
}
|
||||
, setChallenge: function (opts, cb) {
|
||||
},
|
||||
setChallenge: function(opts, cb) {
|
||||
var pathname;
|
||||
|
||||
console.log("");
|
||||
console.log('');
|
||||
console.log('identifier:');
|
||||
console.log(opts.identifier);
|
||||
console.log('hostname:');
|
||||
|
@ -30,18 +38,41 @@ module.exports.run = function run(directoryUrl, RSA, web, chType, email, account
|
|||
console.log(opts.keyAuthorization);
|
||||
console.log('dnsAuthorization:');
|
||||
console.log(opts.dnsAuthorization);
|
||||
console.log("");
|
||||
console.log('');
|
||||
|
||||
if ('http-01' === opts.type) {
|
||||
pathname = opts.hostname + acme2.challengePrefixes['http-01'] + "/" + opts.token;
|
||||
console.log("Put the string '" + opts.keyAuthorization + "' into a file at '" + pathname + "'");
|
||||
console.log("echo '" + opts.keyAuthorization + "' > '" + pathname + "'");
|
||||
pathname =
|
||||
opts.hostname +
|
||||
acme2.challengePrefixes['http-01'] +
|
||||
'/' +
|
||||
opts.token;
|
||||
console.log(
|
||||
"Put the string '" +
|
||||
opts.keyAuthorization +
|
||||
"' into a file at '" +
|
||||
pathname +
|
||||
"'"
|
||||
);
|
||||
console.log(
|
||||
"echo '" + opts.keyAuthorization + "' > '" + pathname + "'"
|
||||
);
|
||||
} else if ('dns-01' === opts.type) {
|
||||
pathname = acme2.challengePrefixes['dns-01'] + "." + opts.hostname.replace(/^\*\./, '');
|
||||
console.log("Put the string '" + opts.dnsAuthorization + "' into the TXT record '" + pathname + "'");
|
||||
console.log("ddig TXT " + pathname + " '" + opts.dnsAuthorization + "'");
|
||||
pathname =
|
||||
acme2.challengePrefixes['dns-01'] +
|
||||
'.' +
|
||||
opts.hostname.replace(/^\*\./, '');
|
||||
console.log(
|
||||
"Put the string '" +
|
||||
opts.dnsAuthorization +
|
||||
"' into the TXT record '" +
|
||||
pathname +
|
||||
"'"
|
||||
);
|
||||
console.log(
|
||||
'ddig TXT ' + pathname + " '" + opts.dnsAuthorization + "'"
|
||||
);
|
||||
} else {
|
||||
cb(new Error("[acme-v2] unrecognized challenge type"));
|
||||
cb(new Error('[acme-v2] unrecognized challenge type'));
|
||||
return;
|
||||
}
|
||||
console.log("\nThen hit the 'any' key to continue...");
|
||||
|
@ -57,17 +88,21 @@ module.exports.run = function run(directoryUrl, RSA, web, chType, email, account
|
|||
process.stdin.setRawMode(true);
|
||||
process.stdin.resume();
|
||||
process.stdin.on('data', onAny);
|
||||
}
|
||||
, removeChallenge: function (opts, cb) {
|
||||
},
|
||||
removeChallenge: function(opts, cb) {
|
||||
// hostname, key
|
||||
console.log('[acme-v2] remove challenge', opts.hostname, opts.keyAuthorization);
|
||||
console.log(
|
||||
'[acme-v2] remove challenge',
|
||||
opts.hostname,
|
||||
opts.keyAuthorization
|
||||
);
|
||||
setTimeout(cb, 1 * 1000);
|
||||
}
|
||||
, challengeType: chType
|
||||
, email: email
|
||||
, accountKeypair: accountKeypair
|
||||
, domainKeypair: domainKeypair
|
||||
, domains: web
|
||||
},
|
||||
challengeType: chType,
|
||||
email: email,
|
||||
accountKeypair: accountKeypair,
|
||||
domainKeypair: domainKeypair,
|
||||
domains: web
|
||||
};
|
||||
|
||||
acme2.accounts.create(options).then(function(account) {
|
||||
|
|
|
@ -4,33 +4,61 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
'use strict';
|
||||
|
||||
module.exports.run = function (directoryUrl, RSA, web, chType, email, accountKeypair, domainKeypair) {
|
||||
module.exports.run = function(
|
||||
directoryUrl,
|
||||
RSA,
|
||||
web,
|
||||
chType,
|
||||
email,
|
||||
accountKeypair,
|
||||
domainKeypair
|
||||
) {
|
||||
console.log('[DEBUG] run', web, chType, email);
|
||||
|
||||
var acme2 = require('../compat.js').ACME.create({ RSA: RSA });
|
||||
acme2.getAcmeUrls(acme2.stagingServerUrl, function(err /*, directoryUrls*/) {
|
||||
if (err) { console.log('err 1'); throw err; }
|
||||
if (err) {
|
||||
console.log('err 1');
|
||||
throw err;
|
||||
}
|
||||
|
||||
var options = {
|
||||
agreeToTerms: function(tosUrl, agree) {
|
||||
agree(null, tosUrl);
|
||||
}
|
||||
, setChallenge: function (hostname, token, val, cb) {
|
||||
},
|
||||
setChallenge: function(hostname, token, val, cb) {
|
||||
var pathname;
|
||||
|
||||
if ('http-01' === cb.type) {
|
||||
pathname = hostname + acme2.acmeChallengePrefix + token;
|
||||
console.log("Put the string '" + val /*keyAuthorization*/ + "' into a file at '" + pathname + "'");
|
||||
console.log("echo '" + val /*keyAuthorization*/ + "' > '" + pathname + "'");
|
||||
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 + "'");
|
||||
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));
|
||||
cb(new Error('[acme-v2] unrecognized challenge type: ' + cb.type));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -45,25 +73,31 @@ module.exports.run = function (directoryUrl, RSA, web, chType, email, accountKey
|
|||
process.stdin.setRawMode(true);
|
||||
process.stdin.resume();
|
||||
process.stdin.on('data', onAny);
|
||||
}
|
||||
, removeChallenge: function (hostname, key, cb) {
|
||||
},
|
||||
removeChallenge: function(hostname, key, cb) {
|
||||
console.log('[DEBUG] remove challenge', hostname, key);
|
||||
setTimeout(cb, 1 * 1000);
|
||||
}
|
||||
, challengeType: chType
|
||||
, email: email
|
||||
, accountKeypair: accountKeypair
|
||||
, domainKeypair: domainKeypair
|
||||
, domains: web
|
||||
},
|
||||
challengeType: chType,
|
||||
email: email,
|
||||
accountKeypair: accountKeypair,
|
||||
domainKeypair: domainKeypair,
|
||||
domains: web
|
||||
};
|
||||
|
||||
acme2.registerNewAccount(options, function(err, account) {
|
||||
if (err) { console.log('err 2'); throw err; }
|
||||
if (err) {
|
||||
console.log('err 2');
|
||||
throw err;
|
||||
}
|
||||
if (options.debug) console.debug('account:');
|
||||
if (options.debug) console.log(account);
|
||||
|
||||
acme2.getCertificate(options, function(err, fullchainPem) {
|
||||
if (err) { console.log('err 3'); throw err; }
|
||||
if (err) {
|
||||
console.log('err 3');
|
||||
throw err;
|
||||
}
|
||||
console.log('[acme-v2] A fullchain.pem:');
|
||||
console.log(fullchainPem);
|
||||
});
|
||||
|
|
|
@ -23,23 +23,31 @@ Rules
|
|||
*/
|
||||
|
||||
// https://github.com/certbot/certbot/issues/5721#issuecomment-402362709
|
||||
var expected = "----\nxxxx\nyyyy\n----\n\n----\nxxxx\nyyyy\n----\n";
|
||||
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"
|
||||
'----\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';
|
||||
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
|
||||
.trim()
|
||||
.split(/[\r\n]{2,}/g)
|
||||
.map(function(str) {
|
||||
return str + '\n';
|
||||
});
|
||||
}
|
||||
|
@ -50,31 +58,31 @@ tests.forEach(function (str) {
|
|||
console.error('input: ', JSON.stringify(str));
|
||||
console.error('expected:', JSON.stringify(expected));
|
||||
console.error('actual: ', JSON.stringify(actual));
|
||||
throw new Error("did not pass");
|
||||
throw new Error('did not pass');
|
||||
}
|
||||
});
|
||||
|
||||
if (
|
||||
"----\nxxxx\nyyyy\n----\n"
|
||||
!==
|
||||
formatPemChain("\n\n----\r\nxxxx\r\nyyyy\r\n----\n\n")
|
||||
'----\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");
|
||||
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")
|
||||
'--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");
|
||||
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"
|
||||
'--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");
|
||||
if ('--B--\nxxxx\nyyyy\n--E--\n' !== str) {
|
||||
throw new Error('bad thingy');
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -5,19 +5,27 @@
|
|||
'use strict';
|
||||
|
||||
/* global Promise */
|
||||
module.exports.run = function run(directoryUrl, RSA, web, chType, email, accountKeypair, domainKeypair) {
|
||||
module.exports.run = function run(
|
||||
directoryUrl,
|
||||
RSA,
|
||||
web,
|
||||
chType,
|
||||
email,
|
||||
accountKeypair,
|
||||
domainKeypair
|
||||
) {
|
||||
var acme2 = require('../').ACME.create({ RSA: RSA });
|
||||
// [ 'test.ppl.family' ] 'coolaj86@gmail.com''http-01'
|
||||
acme2.init(directoryUrl).then(function() {
|
||||
var options = {
|
||||
agreeToTerms: function(tosUrl) {
|
||||
return Promise.resolve(tosUrl);
|
||||
}
|
||||
, setChallenge: function (opts) {
|
||||
},
|
||||
setChallenge: function(opts) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var pathname;
|
||||
|
||||
console.log("");
|
||||
console.log('');
|
||||
console.log('identifier:');
|
||||
console.log(opts.identifier);
|
||||
console.log('hostname:');
|
||||
|
@ -32,18 +40,41 @@ module.exports.run = function run(directoryUrl, RSA, web, chType, email, account
|
|||
console.log(opts.keyAuthorization);
|
||||
console.log('dnsAuthorization:');
|
||||
console.log(opts.dnsAuthorization);
|
||||
console.log("");
|
||||
console.log('');
|
||||
|
||||
if ('http-01' === opts.type) {
|
||||
pathname = opts.hostname + acme2.challengePrefixes['http-01'] + "/" + opts.token;
|
||||
console.log("Put the string '" + opts.keyAuthorization + "' into a file at '" + pathname + "'");
|
||||
console.log("echo '" + opts.keyAuthorization + "' > '" + pathname + "'");
|
||||
pathname =
|
||||
opts.hostname +
|
||||
acme2.challengePrefixes['http-01'] +
|
||||
'/' +
|
||||
opts.token;
|
||||
console.log(
|
||||
"Put the string '" +
|
||||
opts.keyAuthorization +
|
||||
"' into a file at '" +
|
||||
pathname +
|
||||
"'"
|
||||
);
|
||||
console.log(
|
||||
"echo '" + opts.keyAuthorization + "' > '" + pathname + "'"
|
||||
);
|
||||
} else if ('dns-01' === opts.type) {
|
||||
pathname = acme2.challengePrefixes['dns-01'] + "." + opts.hostname.replace(/^\*\./, '');
|
||||
console.log("Put the string '" + opts.dnsAuthorization + "' into the TXT record '" + pathname + "'");
|
||||
console.log("dig TXT " + pathname + " '" + opts.dnsAuthorization + "'");
|
||||
pathname =
|
||||
acme2.challengePrefixes['dns-01'] +
|
||||
'.' +
|
||||
opts.hostname.replace(/^\*\./, '');
|
||||
console.log(
|
||||
"Put the string '" +
|
||||
opts.dnsAuthorization +
|
||||
"' into the TXT record '" +
|
||||
pathname +
|
||||
"'"
|
||||
);
|
||||
console.log(
|
||||
'dig TXT ' + pathname + " '" + opts.dnsAuthorization + "'"
|
||||
);
|
||||
} else {
|
||||
reject(new Error("[acme-v2] unrecognized challenge type"));
|
||||
reject(new Error('[acme-v2] unrecognized challenge type'));
|
||||
return;
|
||||
}
|
||||
console.log("\nThen hit the 'any' key to continue...");
|
||||
|
@ -61,19 +92,23 @@ module.exports.run = function run(directoryUrl, RSA, web, chType, email, account
|
|||
process.stdin.resume();
|
||||
process.stdin.on('data', onAny);
|
||||
});
|
||||
}
|
||||
, removeChallenge: function (opts) {
|
||||
console.log('[acme-v2] remove challenge', opts.hostname, opts.keyAuthorization);
|
||||
},
|
||||
removeChallenge: function(opts) {
|
||||
console.log(
|
||||
'[acme-v2] remove challenge',
|
||||
opts.hostname,
|
||||
opts.keyAuthorization
|
||||
);
|
||||
return new Promise(function(resolve) {
|
||||
// hostname, key
|
||||
setTimeout(resolve, 1 * 1000);
|
||||
});
|
||||
}
|
||||
, challengeType: chType
|
||||
, email: email
|
||||
, accountKeypair: accountKeypair
|
||||
, domainKeypair: domainKeypair
|
||||
, domains: web
|
||||
},
|
||||
challengeType: chType,
|
||||
email: email,
|
||||
accountKeypair: accountKeypair,
|
||||
domainKeypair: domainKeypair,
|
||||
domains: web
|
||||
};
|
||||
|
||||
acme2.accounts.create(options).then(function(account) {
|
||||
|
|
Loading…
Reference in New Issue