v1.2.5: fix multiple bugs with conversion
This commit is contained in:
parent
a5236f6c2f
commit
ad312edfa6
110
bin/keypairs.js
110
bin/keypairs.js
|
@ -13,7 +13,7 @@ var Keypairs = require('../');
|
||||||
var pkg = require('../package.json');
|
var pkg = require('../package.json');
|
||||||
|
|
||||||
var args = process.argv.slice(2);
|
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 = {
|
var conflicts = {
|
||||||
'namedCurve': 'modulusLength'
|
'namedCurve': 'modulusLength'
|
||||||
, 'public': 'private'
|
, 'public': 'private'
|
||||||
|
@ -187,13 +187,7 @@ args.forEach(function (arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Possibly the output file
|
// Possibly the output file
|
||||||
if (!opts.extra1) {
|
if (opts.names.length < 3) {
|
||||||
opts.extra1 = arg;
|
|
||||||
opts.names.push({ taken: false, name: arg });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!opts.extra2) {
|
|
||||||
opts.extra2 = arg;
|
|
||||||
opts.names.push({ taken: false, name: arg });
|
opts.names.push({ taken: false, name: arg });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -220,7 +214,7 @@ function guess(txt, filename) {
|
||||||
try {
|
try {
|
||||||
var json = JSON.parse(txt);
|
var json = JSON.parse(txt);
|
||||||
if (-1 !== [ 'RSA', 'EC' ].indexOf(json.kty)) {
|
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;
|
return true;
|
||||||
} else if (json.signature && json.payload && (json.header || json.protected)) {
|
} else if (json.signature && json.payload && (json.header || json.protected)) {
|
||||||
opts.jwss.push(json);
|
opts.jwss.push(json);
|
||||||
|
@ -231,15 +225,15 @@ function guess(txt, filename) {
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
try {
|
try {
|
||||||
var pem = Eckles.importSync({ pem: txt });
|
var jwk = Eckles.importSync({ pem: txt });
|
||||||
// pem._string = txt;
|
// pem._string = txt;
|
||||||
opts.pems.push(pem);
|
opts.keys.push({ jwk: jwk, pem: true, raw: txt });
|
||||||
return true;
|
return true;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
try {
|
try {
|
||||||
var pem = Rasha.importSync({ pem: txt });
|
var jwk = Rasha.importSync({ pem: txt });
|
||||||
// pem._string = txt;
|
// pem._string = txt;
|
||||||
opts.pems.push(pem);
|
opts.keys.push({ jwk: jwk, pem: true, raw: txt });
|
||||||
return true;
|
return true;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
// ignore
|
// ignore
|
||||||
|
@ -348,8 +342,8 @@ if ('sign' === opts.action) {
|
||||||
|
|
||||||
function readKeypair() {
|
function readKeypair() {
|
||||||
// note that the jwk may be a string
|
// note that the jwk may be a string
|
||||||
var jwkopts = opts.jwks.shift();
|
var keyopts = opts.keys.shift();
|
||||||
var jwk = jwkopts && jwkopts.jwk;
|
var jwk = keyopts && keyopts.jwk;
|
||||||
if (!jwk) {
|
if (!jwk) {
|
||||||
console.error("no keys could be parsed from the given arguments");
|
console.error("no keys could be parsed from the given arguments");
|
||||||
console.error(opts.names.map(function (t) { return t.name; }));
|
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
|
// 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) {
|
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) {
|
if (jwk.d) {
|
||||||
pair.private = jwk;
|
pair.private = jwk;
|
||||||
}
|
}
|
||||||
|
@ -372,69 +366,91 @@ function readKeypair() {
|
||||||
return pair;
|
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) {
|
function convertKeypair(pair) {
|
||||||
//var pair = readKeypair();
|
//var pair = readKeypair();
|
||||||
|
|
||||||
var ps = [];
|
var ps = [];
|
||||||
if (pair.private && !opts.public) {
|
// if it's private only, or if it's not public-only, produce the private key
|
||||||
if ((!opts.privEncoding || 'json' === opts.privEncoding) && (!opts.privFormat || 'jwk' === opts.privFormat)) {
|
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));
|
ps.push(Promise.resolve(pair.private));
|
||||||
} else {
|
} else {
|
||||||
ps.push(Keypairs.export({ jwk: pair.private, format: opts.privFormat, encoding: opts.privEncoding }));
|
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.private) {
|
||||||
if (opts.public) {
|
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.pubFormat) { opts.pubFormat = opts.privFormat; }
|
||||||
if (!opts.pubEncoding) { opts.pubEncoding = opts.privEncoding; }
|
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));
|
ps.push(Promise.resolve(pair.public));
|
||||||
} else {
|
} else {
|
||||||
ps.push(Keypairs.export({ jwk: pair.public, format: opts.pubFormat, encoding: opts.pubEncoding, public: true }));
|
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
|
return Promise.all(ps).then(function (exported) {
|
||||||
var key = convert(0, opts.public);
|
// 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) {
|
if (opts.public) {
|
||||||
// end early
|
|
||||||
if (opts.names.length) {
|
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 {
|
} else {
|
||||||
console.warn(key + "\n");
|
// output public keys to stderr
|
||||||
|
printPublic(key);
|
||||||
}
|
}
|
||||||
|
// end <-- we're not outputting other keys
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private key stuff
|
// private key stuff
|
||||||
if (opts.names.length) {
|
if (opts.names.length >= 1) {
|
||||||
writeFile(opts.names[0].name, key, true);
|
writeFile(opts.names[index].name, key, true);
|
||||||
} else {
|
} else {
|
||||||
console.info(key + "\n");
|
printPrivate(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub key stuff
|
// pub key stuff
|
||||||
if (!opts.private) {
|
// we have to output the private key,
|
||||||
if (opts.names.length >= 2) {
|
// but the public key can be derived at any time
|
||||||
writeFile(opts.names[1].name, key, false);
|
// so we don't need to put the same noise to the screen
|
||||||
} else {
|
if (!opts.private && opts.names.length >= 2) {
|
||||||
console.warn(key + "\n");
|
index = 1;
|
||||||
}
|
key = stringifyIfJson(index, false);
|
||||||
|
writeFile(opts.names[index].name, key, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pair;
|
return pair;
|
||||||
|
|
||||||
function convert(i, pub) {
|
function stringifyIfJson(i, pub) {
|
||||||
if (arr[i].kty) {
|
if (exported[i].kty) {
|
||||||
if (pub) {
|
if (pub) {
|
||||||
if (opts.expiresAt) { arr[i].exp = opts.expiresAt; }
|
if (opts.expiresAt) { exported[i].exp = opts.expiresAt; }
|
||||||
arr[i].use = "sig";
|
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
|
, modulusLength: opts.modulusLength
|
||||||
, namedCurve: opts.namedCurve
|
, namedCurve: opts.namedCurve
|
||||||
}).then(function (pair) {
|
}).then(function (pair) {
|
||||||
|
// always generate as jwk by default
|
||||||
var ps = [];
|
var ps = [];
|
||||||
if ((!opts.privEncoding || 'json' === opts.privEncoding) && (!opts.privFormat || 'jwk' === opts.privFormat)) {
|
if ((!opts.privEncoding || 'json' === opts.privEncoding) && (!opts.privFormat || 'jwk' === opts.privFormat)) {
|
||||||
ps.push(Promise.resolve(pair.private));
|
ps.push(Promise.resolve(pair.private));
|
||||||
|
@ -488,8 +505,10 @@ function writeFile(name, key, priv) {
|
||||||
overwrite = opts.overwrite;
|
overwrite = opts.overwrite;
|
||||||
if (!opts.overwrite) {
|
if (!opts.overwrite) {
|
||||||
if (priv) {
|
if (priv) {
|
||||||
|
// output private keys to stdout
|
||||||
console.info(key + "\n");
|
console.info(key + "\n");
|
||||||
} else {
|
} else {
|
||||||
|
// output public keys to stderr
|
||||||
console.warn(key + "\n");
|
console.warn(key + "\n");
|
||||||
}
|
}
|
||||||
console.error("'" + name + "' exists! force overwrite with 'overwrite'");
|
console.error("'" + name + "' exists! force overwrite with 'overwrite'");
|
||||||
|
@ -583,3 +602,10 @@ function decodeJwt(jwt) {
|
||||||
, signature: parts[2] //Buffer.from(parts[2], 'base64')
|
, signature: parts[2] //Buffer.from(parts[2], 'base64')
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function printPrivate(key) {
|
||||||
|
console.info(key + "\n");
|
||||||
|
}
|
||||||
|
function printPublic(key) {
|
||||||
|
console.warn(key + "\n");
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "keypairs",
|
"name": "keypairs",
|
||||||
"version": "1.2.2",
|
"version": "1.2.5",
|
||||||
"description": "Lightweight RSA/ECDSA keypair generation and JWK <-> PEM",
|
"description": "Lightweight RSA/ECDSA keypair generation and JWK <-> PEM",
|
||||||
"main": "keypairs.js",
|
"main": "keypairs.js",
|
||||||
"files": [
|
"files": [
|
||||||
|
|
Loading…
Reference in New Issue