Browse Source

v1.2.5: fix multiple bugs with conversion

tags/v1.2.5
AJ ONeal 6 months ago
parent
commit
ad312edfa6
2 changed files with 69 additions and 43 deletions
  1. 68
    42
      bin/keypairs.js
  2. 1
    1
      package.json

+ 68
- 42
bin/keypairs.js View File

@@ -13,7 +13,7 @@ var Keypairs = require('../');
13 13
 var pkg = require('../package.json');
14 14
 
15 15
 var args = process.argv.slice(2);
16
-var opts = { jwks: [], jwts: [], jwss: [], payloads: [], names: [], filenames: [], files: [], pems: [] };
16
+var opts = { keys: [], jwts: [], jwss: [], payloads: [], names: [], filenames: [], files: [] };
17 17
 var conflicts = {
18 18
   'namedCurve': 'modulusLength'
19 19
 , 'public': 'private'
@@ -187,13 +187,7 @@ args.forEach(function (arg) {
187 187
   }
188 188
 
189 189
   // Possibly the output file
190
-  if (!opts.extra1) {
191
-    opts.extra1 = arg;
192
-    opts.names.push({ taken: false, name: arg });
193
-    return;
194
-  }
195
-  if (!opts.extra2) {
196
-    opts.extra2 = arg;
190
+  if (opts.names.length < 3) {
197 191
     opts.names.push({ taken: false, name: arg });
198 192
     return;
199 193
   }
@@ -220,7 +214,7 @@ function guess(txt, filename) {
220 214
   try {
221 215
     var json = JSON.parse(txt);
222 216
     if (-1 !== [ 'RSA', 'EC' ].indexOf(json.kty)) {
223
-      opts.jwks.push({ jwk: json, filename: filename });
217
+      opts.keys.push({ raw: txt, jwk: json, filename: filename });
224 218
       return true;
225 219
     } else if (json.signature && json.payload && (json.header || json.protected)) {
226 220
       opts.jwss.push(json);
@@ -231,15 +225,15 @@ function guess(txt, filename) {
231 225
     }
232 226
   } catch(e) {
233 227
     try {
234
-      var pem = Eckles.importSync({ pem: txt });
228
+      var jwk = Eckles.importSync({ pem: txt });
235 229
       // pem._string = txt;
236
-      opts.pems.push(pem);
230
+      opts.keys.push({ jwk: jwk, pem: true, raw: txt });
237 231
       return true;
238 232
     } catch(e) {
239 233
       try {
240
-        var pem = Rasha.importSync({ pem: txt });
234
+        var jwk = Rasha.importSync({ pem: txt });
241 235
         // pem._string = txt;
242
-        opts.pems.push(pem);
236
+        opts.keys.push({ jwk: jwk, pem: true, raw: txt });
243 237
         return true;
244 238
       } catch(e) {
245 239
         // ignore
@@ -348,8 +342,8 @@ if ('sign' === opts.action) {
348 342
 
349 343
 function readKeypair() {
350 344
   // note that the jwk may be a string
351
-  var jwkopts = opts.jwks.shift();
352
-  var jwk = jwkopts && jwkopts.jwk;
345
+  var keyopts = opts.keys.shift();
346
+  var jwk = keyopts && keyopts.jwk;
353 347
   if (!jwk) {
354 348
     console.error("no keys could be parsed from the given arguments");
355 349
     console.error(opts.names.map(function (t) { return t.name; }));
@@ -358,13 +352,13 @@ function readKeypair() {
358 352
   }
359 353
 
360 354
   // omit the primary private key from the list of actual (or soon-to-be) files
361
-  if (jwkopts.filename) {
355
+  if (keyopts.filename) {
362 356
     opts.names = opts.names.filter(function (name) {
363
-      return name.name !== jwkopts.filename;
357
+      return name.name !== keyopts.filename;
364 358
     });
365 359
   }
366 360
 
367
-  var pair = { private: null, public: null };
361
+  var pair = { private: null, public: null, pem: keyopts.pem, raw: keyopts.raw };
368 362
   if (jwk.d) {
369 363
     pair.private = jwk;
370 364
   }
@@ -372,69 +366,91 @@ function readKeypair() {
372 366
   return pair;
373 367
 }
374 368
 
369
+// Note: some of the conditions can be factored out
370
+// this was all built in high-speed iterative during the 3ams+
375 371
 function convertKeypair(pair) {
376 372
   //var pair = readKeypair();
377 373
 
378 374
   var ps = [];
379
-  if (pair.private && !opts.public) {
380
-    if ((!opts.privEncoding || 'json' === opts.privEncoding) && (!opts.privFormat || 'jwk' === opts.privFormat)) {
375
+  // if it's private only, or if it's not public-only, produce the private key
376
+  if (pair.private || !opts.public) {
377
+    // if it came from pem (or is explicitly json), it should go to jwk
378
+    // otherwise, if it came from jwk, it should go to pem
379
+    if (((!opts.privEncoding && pair.pem) || 'json' === opts.privEncoding)
380
+      && ((!opts.privFormat && pair.pem) || 'jwk' === opts.privFormat)) {
381 381
       ps.push(Promise.resolve(pair.private));
382 382
     } else {
383 383
       ps.push(Keypairs.export({ jwk: pair.private, format: opts.privFormat, encoding: opts.privEncoding }));
384 384
     }
385 385
   }
386
+
387
+  // if it's not private key only, we want to produce the public key
386 388
   if (!opts.private) {
387 389
     if (opts.public) {
390
+      // if it's public-only the ambigious options will fall to the private key
391
+      // so we need to fix that
388 392
       if (!opts.pubFormat) { opts.pubFormat = opts.privFormat; }
389 393
       if (!opts.pubEncoding) { opts.pubEncoding = opts.privEncoding; }
390 394
     }
391 395
 
392
-    if ((!opts.pubEncoding || 'json' === opts.pubEncoding) && (!opts.pubFormat || 'jwk' === opts.pubFormat)) {
396
+    // same as above - swap formats by default
397
+    if (((!opts.pubEncoding && pair.pem) || 'json' === opts.pubEncoding)
398
+      && ((!opts.pubFormat && pair.pem) || 'jwk' === opts.pubFormat)) {
393 399
       ps.push(Promise.resolve(pair.public));
394 400
     } else {
395 401
       ps.push(Keypairs.export({ jwk: pair.public, format: opts.pubFormat, encoding: opts.pubEncoding, public: true }));
396 402
     }
397 403
   }
398
-  return Promise.all(ps).then(function (arr) {
399
-    // only use the first key
400
-    var key = convert(0, opts.public);
404
+
405
+  return Promise.all(ps).then(function (exported) {
406
+    // start with the first key, annotating if it should be public
407
+    var index = 0;
408
+    var key = stringifyIfJson(index, opts.public);
409
+
410
+    // re: opts.names
411
+    // if we're only doing the public key we can end early
412
+    // (if the source key was from a file and was in opts.names,
413
+    // we're safe here because we already removed it earlier)
414
+
401 415
     if (opts.public) {
402
-      // end early
403 416
       if (opts.names.length) {
404
-        writeFile(opts.names[0].name, key, !opts.public); // todo make pub/priv param consistent, not flip-flop
417
+        writeFile(opts.names[index].name, key, !opts.public);
405 418
       } else {
406
-      console.warn(key + "\n");
419
+        // output public keys to stderr
420
+        printPublic(key);
407 421
       }
422
+      // end <-- we're not outputting other keys
408 423
       return;
409 424
     }
410 425
 
411 426
     // private key stuff
412
-    if (opts.names.length) {
413
-      writeFile(opts.names[0].name, key, true);
427
+    if (opts.names.length >= 1) {
428
+      writeFile(opts.names[index].name, key, true);
414 429
     } else {
415
-      console.info(key + "\n");
430
+      printPrivate(key);
416 431
     }
417 432
 
418 433
     // pub key stuff
419
-    if (!opts.private) {
420
-      if (opts.names.length >= 2) {
421
-        writeFile(opts.names[1].name, key, false);
422
-      } else {
423
-        console.warn(key + "\n");
424
-      }
434
+    // we have to output the private key,
435
+    // but the public key can be derived at any time
436
+    // so we don't need to put the same noise to the screen
437
+    if (!opts.private && opts.names.length >= 2) {
438
+      index = 1;
439
+      key = stringifyIfJson(index, false);
440
+      writeFile(opts.names[index].name, key, false);
425 441
     }
426 442
 
427 443
     return pair;
428 444
 
429
-    function convert(i, pub) {
430
-      if (arr[i].kty) {
445
+    function stringifyIfJson(i, pub) {
446
+      if (exported[i].kty) {
431 447
         if (pub) {
432
-          if (opts.expiresAt) { arr[i].exp = opts.expiresAt; }
433
-          arr[i].use = "sig";
448
+          if (opts.expiresAt) { exported[i].exp = opts.expiresAt; }
449
+          exported[i].use = "sig";
434 450
         }
435
-        arr[i] = JSON.stringify(arr[i]);
451
+        exported[i] = JSON.stringify(exported[i]);
436 452
       }
437
-      return arr[i];
453
+      return exported[i];
438 454
     }
439 455
   });
440 456
 }
@@ -445,6 +461,7 @@ function genKeypair() {
445 461
   , modulusLength: opts.modulusLength
446 462
   , namedCurve: opts.namedCurve
447 463
   }).then(function (pair) {
464
+    // always generate as jwk by default
448 465
     var ps = [];
449 466
     if ((!opts.privEncoding || 'json' === opts.privEncoding) && (!opts.privFormat || 'jwk' === opts.privFormat)) {
450 467
       ps.push(Promise.resolve(pair.private));
@@ -488,8 +505,10 @@ function writeFile(name, key, priv) {
488 505
     overwrite = opts.overwrite;
489 506
     if (!opts.overwrite) {
490 507
       if (priv) {
508
+        // output private keys to stdout
491 509
         console.info(key + "\n");
492 510
       } else {
511
+        // output public keys to stderr
493 512
         console.warn(key + "\n");
494 513
       }
495 514
       console.error("'" + name + "' exists! force overwrite with 'overwrite'");
@@ -583,3 +602,10 @@ function decodeJwt(jwt) {
583 602
   , signature: parts[2] //Buffer.from(parts[2], 'base64')
584 603
   };
585 604
 }
605
+
606
+function printPrivate(key) {
607
+  console.info(key + "\n");
608
+}
609
+function printPublic(key) {
610
+  console.warn(key + "\n");
611
+}

+ 1
- 1
package.json View File

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

Loading…
Cancel
Save