v1.2.5: fix multiple bugs with conversion

This commit is contained in:
AJ ONeal 2019-03-05 12:23:50 -07:00
parent a5236f6c2f
commit ad312edfa6
2 changed files with 69 additions and 43 deletions

View File

@ -13,7 +13,7 @@ var Keypairs = require('../');
var pkg = require('../package.json');
var args = process.argv.slice(2);
var opts = { jwks: [], jwts: [], jwss: [], payloads: [], names: [], filenames: [], files: [], pems: [] };
var opts = { keys: [], jwts: [], jwss: [], payloads: [], names: [], filenames: [], files: [] };
var conflicts = {
'namedCurve': 'modulusLength'
, 'public': 'private'
@ -187,13 +187,7 @@ args.forEach(function (arg) {
}
// Possibly the output file
if (!opts.extra1) {
opts.extra1 = arg;
opts.names.push({ taken: false, name: arg });
return;
}
if (!opts.extra2) {
opts.extra2 = arg;
if (opts.names.length < 3) {
opts.names.push({ taken: false, name: arg });
return;
}
@ -220,7 +214,7 @@ function guess(txt, filename) {
try {
var json = JSON.parse(txt);
if (-1 !== [ 'RSA', 'EC' ].indexOf(json.kty)) {
opts.jwks.push({ jwk: json, filename: filename });
opts.keys.push({ raw: txt, jwk: json, filename: filename });
return true;
} else if (json.signature && json.payload && (json.header || json.protected)) {
opts.jwss.push(json);
@ -231,15 +225,15 @@ function guess(txt, filename) {
}
} catch(e) {
try {
var pem = Eckles.importSync({ pem: txt });
var jwk = Eckles.importSync({ pem: txt });
// pem._string = txt;
opts.pems.push(pem);
opts.keys.push({ jwk: jwk, pem: true, raw: txt });
return true;
} catch(e) {
try {
var pem = Rasha.importSync({ pem: txt });
var jwk = Rasha.importSync({ pem: txt });
// pem._string = txt;
opts.pems.push(pem);
opts.keys.push({ jwk: jwk, pem: true, raw: txt });
return true;
} catch(e) {
// ignore
@ -348,8 +342,8 @@ if ('sign' === opts.action) {
function readKeypair() {
// note that the jwk may be a string
var jwkopts = opts.jwks.shift();
var jwk = jwkopts && jwkopts.jwk;
var keyopts = opts.keys.shift();
var jwk = keyopts && keyopts.jwk;
if (!jwk) {
console.error("no keys could be parsed from the given arguments");
console.error(opts.names.map(function (t) { return t.name; }));
@ -358,13 +352,13 @@ function readKeypair() {
}
// omit the primary private key from the list of actual (or soon-to-be) files
if (jwkopts.filename) {
if (keyopts.filename) {
opts.names = opts.names.filter(function (name) {
return name.name !== jwkopts.filename;
return name.name !== keyopts.filename;
});
}
var pair = { private: null, public: null };
var pair = { private: null, public: null, pem: keyopts.pem, raw: keyopts.raw };
if (jwk.d) {
pair.private = jwk;
}
@ -372,69 +366,91 @@ function readKeypair() {
return pair;
}
// Note: some of the conditions can be factored out
// this was all built in high-speed iterative during the 3ams+
function convertKeypair(pair) {
//var pair = readKeypair();
var ps = [];
if (pair.private && !opts.public) {
if ((!opts.privEncoding || 'json' === opts.privEncoding) && (!opts.privFormat || 'jwk' === opts.privFormat)) {
// if it's private only, or if it's not public-only, produce the private key
if (pair.private || !opts.public) {
// if it came from pem (or is explicitly json), it should go to jwk
// otherwise, if it came from jwk, it should go to pem
if (((!opts.privEncoding && pair.pem) || 'json' === opts.privEncoding)
&& ((!opts.privFormat && pair.pem) || 'jwk' === opts.privFormat)) {
ps.push(Promise.resolve(pair.private));
} else {
ps.push(Keypairs.export({ jwk: pair.private, format: opts.privFormat, encoding: opts.privEncoding }));
}
}
// if it's not private key only, we want to produce the public key
if (!opts.private) {
if (opts.public) {
// if it's public-only the ambigious options will fall to the private key
// so we need to fix that
if (!opts.pubFormat) { opts.pubFormat = opts.privFormat; }
if (!opts.pubEncoding) { opts.pubEncoding = opts.privEncoding; }
}
if ((!opts.pubEncoding || 'json' === opts.pubEncoding) && (!opts.pubFormat || 'jwk' === opts.pubFormat)) {
// same as above - swap formats by default
if (((!opts.pubEncoding && pair.pem) || 'json' === opts.pubEncoding)
&& ((!opts.pubFormat && pair.pem) || 'jwk' === opts.pubFormat)) {
ps.push(Promise.resolve(pair.public));
} else {
ps.push(Keypairs.export({ jwk: pair.public, format: opts.pubFormat, encoding: opts.pubEncoding, public: true }));
}
}
return Promise.all(ps).then(function (arr) {
// only use the first key
var key = convert(0, opts.public);
return Promise.all(ps).then(function (exported) {
// start with the first key, annotating if it should be public
var index = 0;
var key = stringifyIfJson(index, opts.public);
// re: opts.names
// if we're only doing the public key we can end early
// (if the source key was from a file and was in opts.names,
// we're safe here because we already removed it earlier)
if (opts.public) {
// end early
if (opts.names.length) {
writeFile(opts.names[0].name, key, !opts.public); // todo make pub/priv param consistent, not flip-flop
writeFile(opts.names[index].name, key, !opts.public);
} else {
console.warn(key + "\n");
// output public keys to stderr
printPublic(key);
}
// end <-- we're not outputting other keys
return;
}
// private key stuff
if (opts.names.length) {
writeFile(opts.names[0].name, key, true);
if (opts.names.length >= 1) {
writeFile(opts.names[index].name, key, true);
} else {
console.info(key + "\n");
printPrivate(key);
}
// pub key stuff
if (!opts.private) {
if (opts.names.length >= 2) {
writeFile(opts.names[1].name, key, false);
} else {
console.warn(key + "\n");
}
// we have to output the private key,
// but the public key can be derived at any time
// so we don't need to put the same noise to the screen
if (!opts.private && opts.names.length >= 2) {
index = 1;
key = stringifyIfJson(index, false);
writeFile(opts.names[index].name, key, false);
}
return pair;
function convert(i, pub) {
if (arr[i].kty) {
function stringifyIfJson(i, pub) {
if (exported[i].kty) {
if (pub) {
if (opts.expiresAt) { arr[i].exp = opts.expiresAt; }
arr[i].use = "sig";
if (opts.expiresAt) { exported[i].exp = opts.expiresAt; }
exported[i].use = "sig";
}
arr[i] = JSON.stringify(arr[i]);
exported[i] = JSON.stringify(exported[i]);
}
return arr[i];
return exported[i];
}
});
}
@ -445,6 +461,7 @@ function genKeypair() {
, modulusLength: opts.modulusLength
, namedCurve: opts.namedCurve
}).then(function (pair) {
// always generate as jwk by default
var ps = [];
if ((!opts.privEncoding || 'json' === opts.privEncoding) && (!opts.privFormat || 'jwk' === opts.privFormat)) {
ps.push(Promise.resolve(pair.private));
@ -488,8 +505,10 @@ function writeFile(name, key, priv) {
overwrite = opts.overwrite;
if (!opts.overwrite) {
if (priv) {
// output private keys to stdout
console.info(key + "\n");
} else {
// output public keys to stderr
console.warn(key + "\n");
}
console.error("'" + name + "' exists! force overwrite with 'overwrite'");
@ -583,3 +602,10 @@ function decodeJwt(jwt) {
, signature: parts[2] //Buffer.from(parts[2], 'base64')
};
}
function printPrivate(key) {
console.info(key + "\n");
}
function printPublic(key) {
console.warn(key + "\n");
}

View File

@ -1,6 +1,6 @@
{
"name": "keypairs",
"version": "1.2.2",
"version": "1.2.5",
"description": "Lightweight RSA/ECDSA keypair generation and JWK <-> PEM",
"main": "keypairs.js",
"files": [