Merge branch 'rsa-compat'
This commit is contained in:
commit
c80f7aa624
|
@ -297,6 +297,7 @@ the python client, but it's not necessary)
|
||||||
Change History
|
Change History
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
* v1.5.0 now using letiny-core v2.0.0 and rsa-compat
|
||||||
* v1.4.x I can't remember... but it's better!
|
* v1.4.x I can't remember... but it's better!
|
||||||
* v1.1.0 Added letiny-core, removed node-letsencrypt-python
|
* v1.1.0 Added letiny-core, removed node-letsencrypt-python
|
||||||
* v1.0.2 Works with node-letsencrypt-python
|
* v1.0.2 Works with node-letsencrypt-python
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var PromiseA = require('bluebird');
|
var PromiseA = require('bluebird');
|
||||||
|
var crypto = require('crypto');
|
||||||
var LeCore = require('letiny-core');
|
var LeCore = require('letiny-core');
|
||||||
var leCrypto = LeCore.leCrypto;
|
var RSA = PromiseA.promisifyAll(require('rsa-compat').RSA);
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var mkdirpAsync = PromiseA.promisify(require('mkdirp'));
|
var mkdirpAsync = PromiseA.promisify(require('mkdirp'));
|
||||||
var fs = PromiseA.promisifyAll(require('fs'));
|
var fs = PromiseA.promisifyAll(require('fs'));
|
||||||
|
@ -11,10 +12,8 @@ function createAccount(args, handlers) {
|
||||||
var os = require("os");
|
var os = require("os");
|
||||||
var localname = os.hostname();
|
var localname = os.hostname();
|
||||||
|
|
||||||
// TODO support ECDSA
|
|
||||||
// arg.rsaBitLength args.rsaExponent
|
// arg.rsaBitLength args.rsaExponent
|
||||||
return leCrypto.generateRsaKeypairAsync(args.rsaKeySize, 65537).then(function (pems) {
|
return RSA.generateKeypairAsync(args.rsaKeySize || 2048, 65537, { public: true, pem: true }).then(function (keypair) {
|
||||||
/* pems = { privateKeyPem, privateKeyJwk, publicKeyPem, publicKeyMd5, publicKeySha256 } */
|
|
||||||
|
|
||||||
return LeCore.registerNewAccountAsync({
|
return LeCore.registerNewAccountAsync({
|
||||||
email: args.email
|
email: args.email
|
||||||
|
@ -24,12 +23,15 @@ function createAccount(args, handlers) {
|
||||||
args.tosUrl = tosUrl;
|
args.tosUrl = tosUrl;
|
||||||
handlers.agreeToTerms(args, agree);
|
handlers.agreeToTerms(args, agree);
|
||||||
}
|
}
|
||||||
, accountPrivateKeyPem: pems.privateKeyPem
|
, accountKeypair: keypair
|
||||||
|
|
||||||
, debug: args.debug || handlers.debug
|
, debug: args.debug || handlers.debug
|
||||||
}).then(function (body) {
|
}).then(function (body) {
|
||||||
// TODO XXX use sha256
|
// TODO XXX use sha256 (the python client uses md5)
|
||||||
var accountId = pems.publicKeyMd5;
|
// TODO ssh fingerprint (noted on rsa-compat issues page, I believe)
|
||||||
|
keypair.publicKeyMd5 = crypto.createHash('md5').update(RSA.exportPublicPem(keypair)).digest('hex');
|
||||||
|
keypair.publicKeySha256 = crypto.createHash('sha256').update(RSA.exportPublicPem(keypair)).digest('hex');
|
||||||
|
var accountId = keypair.publicKeyMd5;
|
||||||
var accountDir = path.join(args.accountsDir, accountId);
|
var accountDir = path.join(args.accountsDir, accountId);
|
||||||
var regr = { body: body };
|
var regr = { body: body };
|
||||||
|
|
||||||
|
@ -44,11 +46,12 @@ function createAccount(args, handlers) {
|
||||||
, creation_dt: isoDate
|
, creation_dt: isoDate
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO abstract file writing
|
||||||
return PromiseA.all([
|
return PromiseA.all([
|
||||||
// meta.json {"creation_host": "ns1.redirect-www.org", "creation_dt": "2015-12-11T04:14:38Z"}
|
// meta.json {"creation_host": "ns1.redirect-www.org", "creation_dt": "2015-12-11T04:14:38Z"}
|
||||||
fs.writeFileAsync(path.join(accountDir, 'meta.json'), JSON.stringify(accountMeta), 'utf8')
|
fs.writeFileAsync(path.join(accountDir, 'meta.json'), JSON.stringify(accountMeta), 'utf8')
|
||||||
// private_key.json { "e", "d", "n", "q", "p", "kty", "qi", "dp", "dq" }
|
// private_key.json { "e", "d", "n", "q", "p", "kty", "qi", "dp", "dq" }
|
||||||
, fs.writeFileAsync(path.join(accountDir, 'private_key.json'), JSON.stringify(pems.privateKeyJwk), 'utf8')
|
, fs.writeFileAsync(path.join(accountDir, 'private_key.json'), JSON.stringify(RSA.exportPrivateJwk(keypair)), 'utf8')
|
||||||
// regr.json:
|
// regr.json:
|
||||||
/*
|
/*
|
||||||
{ body: { contact: [ 'mailto:coolaj86@gmail.com' ],
|
{ body: { contact: [ 'mailto:coolaj86@gmail.com' ],
|
||||||
|
@ -60,8 +63,11 @@ function createAccount(args, handlers) {
|
||||||
*/
|
*/
|
||||||
, fs.writeFileAsync(path.join(accountDir, 'regr.json'), JSON.stringify(regr), 'utf8')
|
, fs.writeFileAsync(path.join(accountDir, 'regr.json'), JSON.stringify(regr), 'utf8')
|
||||||
]).then(function () {
|
]).then(function () {
|
||||||
|
var pems = {};
|
||||||
|
|
||||||
|
// pems.private_key;
|
||||||
pems.meta = accountMeta;
|
pems.meta = accountMeta;
|
||||||
pems.privateKey = pems.privateKeyJwk;
|
pems.keypair = keypair;
|
||||||
pems.regr = regr;
|
pems.regr = regr;
|
||||||
pems.accountId = accountId;
|
pems.accountId = accountId;
|
||||||
pems.id = accountId;
|
pems.id = accountId;
|
||||||
|
@ -106,19 +112,19 @@ function getAccount(args, handlers) {
|
||||||
return createAccount(args, handlers);
|
return createAccount(args, handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
return leCrypto.privateJwkToPemsAsync(files.private_key).then(function (keypair) {
|
var keypair = { privateKeyJwk: files.private_key };
|
||||||
|
keypair.privateKeyPem = RSA.exportPrivatePem(keypair);
|
||||||
|
keypair.publicKeyPem = RSA.exportPublicPem(keypair);
|
||||||
|
|
||||||
|
//files.private_key;
|
||||||
|
//files.regr;
|
||||||
|
//files.meta;
|
||||||
files.accountId = accountId; // preserve current account id
|
files.accountId = accountId; // preserve current account id
|
||||||
files.id = accountId;
|
files.id = accountId;
|
||||||
files.publicKeySha256 = keypair.publicKeySha256;
|
files.keypair = keypair;
|
||||||
files.publicKeyMd5 = keypair.publicKeyMd5;
|
|
||||||
files.publicKeyPem = keypair.publicKeyPem; // ascii PEM: ----BEGIN...
|
|
||||||
files.privateKeyPem = keypair.privateKeyPem; // ascii PEM: ----BEGIN...
|
|
||||||
files.privateKeyJson = keypair.privateKeyJwk; // json { n: ..., e: ..., iq: ..., etc }
|
|
||||||
files.privateKeyJwk = keypair.privateKeyJwk; // json { n: ..., e: ..., iq: ..., etc }
|
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAccountIdByEmail(args) {
|
function getAccountIdByEmail(args) {
|
||||||
|
|
72
lib/core.js
72
lib/core.js
|
@ -1,13 +1,13 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var PromiseA = require('bluebird');
|
var PromiseA = require('bluebird');
|
||||||
|
var RSA = PromiseA.promisifyAll(require('rsa-compat').RSA);
|
||||||
var mkdirpAsync = PromiseA.promisify(require('mkdirp'));
|
var mkdirpAsync = PromiseA.promisify(require('mkdirp'));
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var fs = PromiseA.promisifyAll(require('fs'));
|
var fs = PromiseA.promisifyAll(require('fs'));
|
||||||
var sfs = require('safe-replace');
|
var sfs = require('safe-replace');
|
||||||
var LE = require('../');
|
var LE = require('../');
|
||||||
var LeCore = PromiseA.promisifyAll(require('letiny-core'));
|
var LeCore = PromiseA.promisifyAll(require('letiny-core'));
|
||||||
var leCrypto = PromiseA.promisifyAll(LeCore.leCrypto);
|
|
||||||
var Accounts = require('./accounts');
|
var Accounts = require('./accounts');
|
||||||
|
|
||||||
var merge = require('./common').merge;
|
var merge = require('./common').merge;
|
||||||
|
@ -166,7 +166,7 @@ function writeCertificateAsync(args, defaults, handlers) {
|
||||||
var obj = args.pyobj;
|
var obj = args.pyobj;
|
||||||
var result = args.pems;
|
var result = args.pems;
|
||||||
|
|
||||||
result.fullchain = result.cert + '\n' + result.ca;
|
result.fullchain = result.cert + '\n' + (result.chain || result.ca);
|
||||||
obj.checkpoints = parseInt(obj.checkpoints, 10) || 0;
|
obj.checkpoints = parseInt(obj.checkpoints, 10) || 0;
|
||||||
|
|
||||||
var liveDir = args.liveDir || path.join(args.configDir, 'live', args.domains[0]);
|
var liveDir = args.liveDir || path.join(args.configDir, 'live', args.domains[0]);
|
||||||
|
@ -193,18 +193,28 @@ function writeCertificateAsync(args, defaults, handlers) {
|
||||||
return mkdirpAsync(archiveDir).then(function () {
|
return mkdirpAsync(archiveDir).then(function () {
|
||||||
return PromiseA.all([
|
return PromiseA.all([
|
||||||
sfs.writeFileAsync(certArchive, result.cert, 'ascii')
|
sfs.writeFileAsync(certArchive, result.cert, 'ascii')
|
||||||
, sfs.writeFileAsync(chainArchive, result.ca || result.chain, 'ascii')
|
, sfs.writeFileAsync(chainArchive, (result.chain || result.ca), 'ascii')
|
||||||
, sfs.writeFileAsync(fullchainArchive, result.fullchain, 'ascii')
|
, sfs.writeFileAsync(fullchainArchive, result.fullchain, 'ascii')
|
||||||
, sfs.writeFileAsync(privkeyArchive, result.key || result.privkey || args.domainPrivateKeyPem, 'ascii')
|
, sfs.writeFileAsync(
|
||||||
|
privkeyArchive
|
||||||
|
// TODO nix args.key, args.domainPrivateKeyPem ??
|
||||||
|
, (result.privkey || result.key) || RSA.exportPrivatePem(args.domainKeypair)
|
||||||
|
, 'ascii'
|
||||||
|
)
|
||||||
]);
|
]);
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
return mkdirpAsync(liveDir);
|
return mkdirpAsync(liveDir);
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
return PromiseA.all([
|
return PromiseA.all([
|
||||||
sfs.writeFileAsync(certPath, result.cert, 'ascii')
|
sfs.writeFileAsync(certPath, result.cert, 'ascii')
|
||||||
, sfs.writeFileAsync(chainPath, result.ca || result.chain, 'ascii')
|
, sfs.writeFileAsync(chainPath, (result.chain || result.ca), 'ascii')
|
||||||
, sfs.writeFileAsync(fullchainPath, result.fullchain, 'ascii')
|
, sfs.writeFileAsync(fullchainPath, result.fullchain, 'ascii')
|
||||||
, sfs.writeFileAsync(privkeyPath, result.key || result.privkey || args.domainPrivateKeyPem, 'ascii')
|
, sfs.writeFileAsync(
|
||||||
|
privkeyPath
|
||||||
|
// TODO nix args.key, args.domainPrivateKeyPem ??
|
||||||
|
, (result.privkey || result.key) || RSA.exportPrivatePem(args.domainKeypair)
|
||||||
|
, 'ascii'
|
||||||
|
)
|
||||||
]);
|
]);
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
obj.checkpoints += 1;
|
obj.checkpoints += 1;
|
||||||
|
@ -219,10 +229,14 @@ function writeCertificateAsync(args, defaults, handlers) {
|
||||||
, fullchainPath: fullchainPath
|
, fullchainPath: fullchainPath
|
||||||
, privkeyPath: privkeyPath
|
, privkeyPath: privkeyPath
|
||||||
|
|
||||||
|
// TODO nix keypair
|
||||||
|
, keypair: args.domainKeypair
|
||||||
|
|
||||||
|
// TODO nix args.key, args.domainPrivateKeyPem ??
|
||||||
// some ambiguity here...
|
// some ambiguity here...
|
||||||
, privkey: result.key || result.privkey || args.domainPrivateKeyPem
|
, privkey: (result.privkey || result.key) || RSA.exportPrivatePem(args.domainKeypair)
|
||||||
, fullchain: result.fullchain || result.cert
|
, fullchain: result.fullchain || (result.cert + '\n' + result.chain)
|
||||||
, chain: result.ca || result.chain
|
, chain: (result.chain || result.ca)
|
||||||
// especially this one... might be cert only, might be fullchain
|
// especially this one... might be cert only, might be fullchain
|
||||||
, cert: result.cert
|
, cert: result.cert
|
||||||
|
|
||||||
|
@ -235,21 +249,39 @@ function writeCertificateAsync(args, defaults, handlers) {
|
||||||
function getCertificateAsync(args, defaults, handlers) {
|
function getCertificateAsync(args, defaults, handlers) {
|
||||||
var account = args.account;
|
var account = args.account;
|
||||||
var promise;
|
var promise;
|
||||||
|
var keypairOpts = { public: true, pem: true };
|
||||||
|
|
||||||
if (args.domainKeyPath) {
|
if (!args.domainKeyPath) {
|
||||||
// TODO use existing pre-generated key if avaibale
|
// TODO use default path ???
|
||||||
console.warn("[LE /lib/core.js] retrieve from domainKeyPath NOT IMPLEMENTED (please file an issue to remind me about this)");
|
if (args.debug) {
|
||||||
promise = leCrypto.generateRsaKeypairAsync(args.rsaKeySize, 65537);
|
console.log('[domainKeyPath]: none');
|
||||||
} else {
|
}
|
||||||
promise = leCrypto.generateRsaKeypairAsync(args.rsaKeySize, 65537);
|
promise = RSA.generateKeypairAsync(args.rsaKeySize, 65537, keypairOpts);
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise.then(function (domainKey) {
|
if (args.domainKeyPath) {
|
||||||
|
if (args.debug) {
|
||||||
|
console.log('[domainKeyPath]:', args.domainKeyPath);
|
||||||
|
}
|
||||||
|
promise = fs.readFileAsync(args.domainKeyPath, 'ascii').then(function (pem) {
|
||||||
|
return RSA.import({ privateKeyPem: pem });
|
||||||
|
}, function (/*err*/) {
|
||||||
|
return RSA.generateKeypairAsync(args.rsaKeySize, 65537, keypairOpts).then(function (keypair) {
|
||||||
|
return mkdirpAsync(path.dirname(args.domainKeyPath)).then(function () {
|
||||||
|
return fs.writeFileAsync(args.domainKeyPath, keypair.privateKeyPem, 'ascii').then(function () {
|
||||||
|
return keypair;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise.then(function (domainKeypair) {
|
||||||
if (args.debug) {
|
if (args.debug) {
|
||||||
console.log("[letsencrypt/lib/core.js] get certificate");
|
console.log("[letsencrypt/lib/core.js] get certificate");
|
||||||
}
|
}
|
||||||
|
|
||||||
args.domainPrivateKeyPem = args.domainPrivateKeyPem || domainKey.privateKeyPem;
|
args.domainKeypair = domainKeypair;
|
||||||
//args.registration = domainKey;
|
//args.registration = domainKey;
|
||||||
|
|
||||||
return LeCore.getCertificateAsync({
|
return LeCore.getCertificateAsync({
|
||||||
|
@ -258,8 +290,8 @@ function getCertificateAsync(args, defaults, handlers) {
|
||||||
, newAuthzUrl: args._acmeUrls.newAuthz
|
, newAuthzUrl: args._acmeUrls.newAuthz
|
||||||
, newCertUrl: args._acmeUrls.newCert
|
, newCertUrl: args._acmeUrls.newCert
|
||||||
|
|
||||||
, accountPrivateKeyPem: account.privateKeyPem
|
, accountKeypair: RSA.import(account.keypair)
|
||||||
, domainPrivateKeyPem: domainKey.privateKeyPem
|
, domainKeypair: domainKeypair
|
||||||
, domains: args.domains
|
, domains: args.domains
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -302,6 +334,7 @@ function getCertificateAsync(args, defaults, handlers) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).then(function (results) {
|
}).then(function (results) {
|
||||||
|
// { cert, chain, fullchain, privkey }
|
||||||
args.pems = results;
|
args.pems = results;
|
||||||
return writeCertificateAsync(args, defaults, handlers);
|
return writeCertificateAsync(args, defaults, handlers);
|
||||||
});
|
});
|
||||||
|
@ -335,6 +368,7 @@ function getOrCreateDomainCertificate(args, defaults, handlers) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns 'account' from lib/accounts { meta, regr, keypair, accountId (id) }
|
||||||
function getOrCreateAcmeAccount(args, defaults, handlers) {
|
function getOrCreateAcmeAccount(args, defaults, handlers) {
|
||||||
var pyconf = PromiseA.promisifyAll(require('pyconf'));
|
var pyconf = PromiseA.promisifyAll(require('pyconf'));
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "letsencrypt",
|
"name": "letsencrypt",
|
||||||
"version": "1.4.4",
|
"version": "1.5.0",
|
||||||
"description": "Let's Encrypt for node.js on npm",
|
"description": "Let's Encrypt for node.js on npm",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -37,10 +37,11 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bluebird": "^3.0.6",
|
"bluebird": "^3.0.6",
|
||||||
"homedir": "^0.6.0",
|
"homedir": "^0.6.0",
|
||||||
"letiny-core": "^1.0.5",
|
"letiny-core": "^2.0.1",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"pyconf": "^1.1.2",
|
"pyconf": "^1.1.2",
|
||||||
"request": "^2.67.0",
|
"request": "^2.67.0",
|
||||||
|
"rsa-compat": "^1.2.1",
|
||||||
"safe-replace": "^1.0.2"
|
"safe-replace": "^1.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue