v1.1.0: Add tests, more convenience methods, more docs
This commit is contained in:
		
							parent
							
								
									738be9b656
								
							
						
					
					
						commit
						7099943db7
					
				
							
								
								
									
										74
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										74
									
								
								README.md
									
									
									
									
									
								
							@ -1,4 +1,4 @@
 | 
				
			|||||||
# Keypairs for node.js
 | 
					# Keypairs.js
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Lightweight JavaScript RSA and ECDSA utils that work on Windows, Mac, and Linux
 | 
					Lightweight JavaScript RSA and ECDSA utils that work on Windows, Mac, and Linux
 | 
				
			||||||
using modern node.js APIs (no need for C compiler).
 | 
					using modern node.js APIs (no need for C compiler).
 | 
				
			||||||
@ -13,6 +13,7 @@ and [Rasha.js (RSA)](https://git.coolaj86.com/coolaj86/rasha.js/).
 | 
				
			|||||||
    * [x] ECDSA (P-256, P-384)
 | 
					    * [x] ECDSA (P-256, P-384)
 | 
				
			||||||
  * [x] PEM-to-JWK
 | 
					  * [x] PEM-to-JWK
 | 
				
			||||||
  * [x] JWK-to-PEM
 | 
					  * [x] JWK-to-PEM
 | 
				
			||||||
 | 
					  * [x] Create JWTs (and sign JWS)
 | 
				
			||||||
  * [x] SHA256 JWK Thumbprints
 | 
					  * [x] SHA256 JWK Thumbprints
 | 
				
			||||||
  * [ ] JWK fetching. See [Keyfetch.js](https://npmjs.com/packages/keyfetch/)
 | 
					  * [ ] JWK fetching. See [Keyfetch.js](https://npmjs.com/packages/keyfetch/)
 | 
				
			||||||
    * [ ] OIDC
 | 
					    * [ ] OIDC
 | 
				
			||||||
@ -20,7 +21,6 @@ and [Rasha.js (RSA)](https://git.coolaj86.com/coolaj86/rasha.js/).
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<!--
 | 
					<!--
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * [ ] sign JWS
 | 
					 | 
				
			||||||
  * [ ] generate CSR (DER as PEM or base64url)
 | 
					  * [ ] generate CSR (DER as PEM or base64url)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-->
 | 
					-->
 | 
				
			||||||
@ -54,6 +54,16 @@ _much_ longer than RSA has, and they're smaller, and faster to generate.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## API Overview
 | 
					## API Overview
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* generate
 | 
				
			||||||
 | 
					* parse
 | 
				
			||||||
 | 
					* parseOrGenerate
 | 
				
			||||||
 | 
					* import (PEM-to-JWK)
 | 
				
			||||||
 | 
					* export (JWK-to-PEM, private or public)
 | 
				
			||||||
 | 
					* publish (Private JWK to Public JWK)
 | 
				
			||||||
 | 
					* thumbprint (JWK SHA256)
 | 
				
			||||||
 | 
					* signJwt
 | 
				
			||||||
 | 
					* signJws
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Keypairs.generate(options)
 | 
					#### Keypairs.generate(options)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Generates a public/private pair of JWKs as `{ private, public }`
 | 
					Generates a public/private pair of JWKs as `{ private, public }`
 | 
				
			||||||
@ -65,6 +75,50 @@ Option examples:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
When no options are supplied EC P-256 (also known as `prime256v1` and `secp256r1`) is used by default.
 | 
					When no options are supplied EC P-256 (also known as `prime256v1` and `secp256r1`) is used by default.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Keypairs.parse(options)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Parses either a JWK (encoded as JSON) or an x509 (encdode as PEM) and gives
 | 
				
			||||||
 | 
					back the JWK representation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Option Examples:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* JWK { key: '{ "kty":"EC", ... }' }
 | 
				
			||||||
 | 
					* PEM { key: '-----BEGIN PRIVATE KEY-----\n...' }
 | 
				
			||||||
 | 
					* Public Key Only { key: '-----BEGIN PRIVATE KEY-----\n...', public: true }
 | 
				
			||||||
 | 
					* Must Have Private Key { key: '-----BEGIN PUBLIC KEY-----\n...', private: true }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```js
 | 
				
			||||||
 | 
					Keypairs.parse({ key: '...' }).catch(function (e) {
 | 
				
			||||||
 | 
					  // could not be parsed or was a public key
 | 
				
			||||||
 | 
					  console.warn(e);
 | 
				
			||||||
 | 
					  return Keypairs.generate();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Keypairs.parseOrGenerate({ key, throw, [generate opts]... })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Parses the key. Logs a warning on failure, marches on.
 | 
				
			||||||
 | 
					(a shortcut for the above, with `private: true`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Option Examples:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* parse key if exist, otherwise generate `{ key: process.env["PRIVATE_KEY"] }`
 | 
				
			||||||
 | 
					* generated key curve `{ key: null, namedCurve: 'P-256' }`
 | 
				
			||||||
 | 
					* generated key modulus `{ key: null, modulusLength: 2048 }`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```js
 | 
				
			||||||
 | 
					Keypairs.parseOrGenerate({ key: process.env["PRIVATE_KEY"] }).then(function (pair) {
 | 
				
			||||||
 | 
					  console.log(pair.public);
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Great for when you have a set of shared keys for development and randomly
 | 
				
			||||||
 | 
					generated keys in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Keypairs.import({ pem: '...' }
 | 
					#### Keypairs.import({ pem: '...' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Takes a PEM in pretty much any format (PKCS1, SEC1, PKCS8, SPKI) and returns a JWK.
 | 
					Takes a PEM in pretty much any format (PKCS1, SEC1, PKCS8, SPKI) and returns a JWK.
 | 
				
			||||||
@ -85,6 +139,10 @@ Options
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Keypairs.publish({ jwk: jwk })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Synchronously** strips a key of its private parts and returns the public version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Keypairs.thumbprint({ jwk: jwk })
 | 
					#### Keypairs.thumbprint({ jwk: jwk })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Promises a JWK-spec thumbprint: URL Base64-encoded sha256
 | 
					Promises a JWK-spec thumbprint: URL Base64-encoded sha256
 | 
				
			||||||
@ -134,11 +192,15 @@ Options:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Additional Documentation
 | 
					# Additional Documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Keypairs.js provides a 1-to-1 mapping to the Rasha.js and Eckles.js APIs,
 | 
					Keypairs.js provides a 1-to-1 mapping to the Rasha.js and Eckles.js APIs for the following:
 | 
				
			||||||
but it also includes the additional convenience methods `signJwt` and `signJws`.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
That is to say that any option you pass to Keypairs will be passed directly to the corresponding API
 | 
					* generate(options)
 | 
				
			||||||
of either Rasha or Eckles.
 | 
					* import({ pem: '---BEGIN...' })
 | 
				
			||||||
 | 
					* export({ jwk: { kty: 'EC', ... })
 | 
				
			||||||
 | 
					* thumbprint({ jwk: jwk })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you want to know the algorithm-specific options that are available for those
 | 
				
			||||||
 | 
					you'll want to take a look at the corresponding documentation:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* See ECDSA documentation at [Eckles.js](https://git.coolaj86.com/coolaj86/eckles.js/)
 | 
					* See ECDSA documentation at [Eckles.js](https://git.coolaj86.com/coolaj86/eckles.js/)
 | 
				
			||||||
* See RSA documentation at [Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js/)
 | 
					* See RSA documentation at [Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js/)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										80
									
								
								keypairs.js
									
									
									
									
									
								
							
							
						
						
									
										80
									
								
								keypairs.js
									
									
									
									
									
								
							@ -16,9 +16,64 @@ Keypairs.generate = function (opts) {
 | 
				
			|||||||
  return Eckles.generate(opts);
 | 
					  return Eckles.generate(opts);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Keypairs.parse = function (opts) {
 | 
				
			||||||
 | 
					  opts = opts || {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var err;
 | 
				
			||||||
 | 
					  var jwk;
 | 
				
			||||||
 | 
					  var pem;
 | 
				
			||||||
 | 
					  var p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    jwk = JSON.parse(opts.key);
 | 
				
			||||||
 | 
					    p = Keypairs.export({ jwk: jwk }).catch(function (e) {
 | 
				
			||||||
 | 
					      pem = opts.key;
 | 
				
			||||||
 | 
					      err = new Error("Not a valid jwk '" + JSON.stringify(jwk) + "':" + e.message);
 | 
				
			||||||
 | 
					      err.code = "EINVALID";
 | 
				
			||||||
 | 
					      return Promise.reject(err);
 | 
				
			||||||
 | 
					    }).then(function () {
 | 
				
			||||||
 | 
					      return jwk;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  } catch(e) {
 | 
				
			||||||
 | 
					    p = Keypairs.import({ pem: opts.key }).catch(function (e) {
 | 
				
			||||||
 | 
					      err = new Error("Could not parse key (type " + typeof opts.key + ") '" + opts.key + "': " + e.message);
 | 
				
			||||||
 | 
					      err.code = "EPARSE";
 | 
				
			||||||
 | 
					      return Promise.reject(err);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return p.then(function (jwk) {
 | 
				
			||||||
 | 
					    var pubopts = JSON.parse(JSON.stringify(opts));
 | 
				
			||||||
 | 
					    pubopts.jwk = jwk;
 | 
				
			||||||
 | 
					    return Keypairs.publish(pubopts).then(function (pub) {
 | 
				
			||||||
 | 
					      // 'd' happens to be the name of a private part of both RSA and ECDSA keys
 | 
				
			||||||
 | 
					      if (opts.public || opts.publish || !jwk.d) {
 | 
				
			||||||
 | 
					        if (opts.private) {
 | 
				
			||||||
 | 
					          // TODO test that it can actually sign?
 | 
				
			||||||
 | 
					          err = new Error("Not a private key '" + JSON.stringify(jwk) + "'");
 | 
				
			||||||
 | 
					          err.code = "ENOTPRIVATE";
 | 
				
			||||||
 | 
					          return Promise.reject(err);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return { public: pub };
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return { private: jwk, public: pub };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Keypairs.parseOrGenerate = function (opts) {
 | 
				
			||||||
 | 
					  if (!opts.key) { return Keypairs.generate(opts); }
 | 
				
			||||||
 | 
					  opts.private = true;
 | 
				
			||||||
 | 
					  return Keypairs.parse(opts).catch(function (e) {
 | 
				
			||||||
 | 
					    console.warn(e.message);
 | 
				
			||||||
 | 
					    return Keypairs.generate(opts);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Keypairs.import = function (opts) {
 | 
					Keypairs.import = function (opts) {
 | 
				
			||||||
  return Eckles.import(opts.pem).catch(function () {
 | 
					  return Eckles.import(opts).catch(function () {
 | 
				
			||||||
    return Rasha.import(opts.pem);
 | 
					    return Rasha.import(opts);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -32,6 +87,27 @@ Keypairs.export = function (opts) {
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Keypairs.publish = function (opts) {
 | 
				
			||||||
 | 
					  if ('object' !== typeof opts.jwk || !opts.jwk.kty) { throw new Error("invalid jwk: " + JSON.stringify(opts.jwk)); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // trying to find the best balance of an immutable copy with custom attributes
 | 
				
			||||||
 | 
					  var jwk = {};
 | 
				
			||||||
 | 
					  Object.keys(opts.jwk).forEach(function (k) {
 | 
				
			||||||
 | 
					    // ignore RSA and EC private parts
 | 
				
			||||||
 | 
					    if (-1 !== ['d', 'p', 'q', 'dp', 'dq', 'qi'].indexOf(k)) { return; }
 | 
				
			||||||
 | 
					    jwk[k] = JSON.parse(JSON.stringify(opts.jwk[k]));
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!jwk.exp) {
 | 
				
			||||||
 | 
					    if (opts.expiresIn) { jwk.exp = Math.round(Date.now()/1000) + opts.expiresIn; }
 | 
				
			||||||
 | 
					    else { jwk.exp = opts.expiresAt; }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (!jwk.use && false !== jwk.use) { jwk.use = "sig"; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (jwk.kid) { return Promise.resolve(jwk); }
 | 
				
			||||||
 | 
					  return Keypairs.thumbprint({ jwk: jwk }).then(function (thumb) { jwk.kid = thumb; return jwk; });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Keypairs.thumbprint = function (opts) {
 | 
					Keypairs.thumbprint = function (opts) {
 | 
				
			||||||
  return Promise.resolve().then(function () {
 | 
					  return Promise.resolve().then(function () {
 | 
				
			||||||
    if ('RSA' === opts.jwk.kty) {
 | 
					    if ('RSA' === opts.jwk.kty) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										14
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -1,18 +1,18 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "keypairs",
 | 
					  "name": "keypairs",
 | 
				
			||||||
  "version": "1.0.1",
 | 
					  "version": "1.1.0",
 | 
				
			||||||
  "lockfileVersion": 1,
 | 
					  "lockfileVersion": 1,
 | 
				
			||||||
  "requires": true,
 | 
					  "requires": true,
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "eckles": {
 | 
					    "eckles": {
 | 
				
			||||||
      "version": "1.4.0",
 | 
					      "version": "1.4.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/eckles/-/eckles-1.4.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/eckles/-/eckles-1.4.1.tgz",
 | 
				
			||||||
      "integrity": "sha512-Bm5dpwhsBuoCHvKCY3gAvP8XFyXH7im8uAu3szykpVNbFBdC+lOuV8vLC8fvTYRZBfFqB+k/P6ud/ZPVO2V2tA=="
 | 
					      "integrity": "sha512-auWyk/k8oSkVHaD4RxkPadKsLUcIwKgr/h8F7UZEueFDBO7BsE4y+H6IMUDbfqKIFPg/9MxV6KcBdJCmVVcxSA=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "rasha": {
 | 
					    "rasha": {
 | 
				
			||||||
      "version": "1.2.1",
 | 
					      "version": "1.2.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/rasha/-/rasha-1.2.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/rasha/-/rasha-1.2.4.tgz",
 | 
				
			||||||
      "integrity": "sha512-cs4Hu/rVF3/Qucq+V7lxSz449VfHNMVXJaeajAHno9H5FC1PWlmS4NM6IAX5jPKFF0IC2rOdHdf7iNxQuIWZag=="
 | 
					      "integrity": "sha512-GsIwKv+hYSumJyK9wkTDaERLwvWaGYh1WuI7JMTBISfYt13TkKFU/HFzlY4n72p8VfXZRUYm0AqaYhkZVxOC3Q=="
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,11 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "keypairs",
 | 
					  "name": "keypairs",
 | 
				
			||||||
  "version": "1.0.1",
 | 
					  "version": "1.1.0",
 | 
				
			||||||
  "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": [],
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "test": "echo \"Error: no test specified\" && exit 1"
 | 
					    "test": "node test.js"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repository": {
 | 
					  "repository": {
 | 
				
			||||||
    "type": "git",
 | 
					    "type": "git",
 | 
				
			||||||
@ -21,7 +21,7 @@
 | 
				
			|||||||
  "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
 | 
					  "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
 | 
				
			||||||
  "license": "MPL-2.0",
 | 
					  "license": "MPL-2.0",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "eckles": "^1.4.0",
 | 
					    "eckles": "^1.4.1",
 | 
				
			||||||
    "rasha": "^1.2.1"
 | 
					    "rasha": "^1.2.4"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										106
									
								
								test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								test.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					var Keypairs = require('./');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* global Promise*/
 | 
				
			||||||
 | 
					Keypairs.parseOrGenerate({ key: '' }).then(function (pair) {
 | 
				
			||||||
 | 
					  // should NOT have any warning output
 | 
				
			||||||
 | 
					  if (!pair.private || !pair.public) {
 | 
				
			||||||
 | 
					    throw new Error("missing key pairs");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return Promise.all([
 | 
				
			||||||
 | 
					    // Testing Public Part of key
 | 
				
			||||||
 | 
					    Keypairs.export({ jwk: pair.public }).then(function (pem) {
 | 
				
			||||||
 | 
					      if (!/--BEGIN PUBLIC/.test(pem)) {
 | 
				
			||||||
 | 
					        throw new Error("did not export public pem");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return Promise.all([
 | 
				
			||||||
 | 
					        Keypairs.parse({ key: pem }).then(function (pair) {
 | 
				
			||||||
 | 
					          if (pair.private) {
 | 
				
			||||||
 | 
					            throw new Error("shouldn't have private part");
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return true;
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      , Keypairs.parse({ key: pem, private: true }).then(function () {
 | 
				
			||||||
 | 
					          var err = new Error("should have thrown an error when private key was required and public pem was given");
 | 
				
			||||||
 | 
					          err.code = 'NOERR';
 | 
				
			||||||
 | 
					          throw err;
 | 
				
			||||||
 | 
					        }).catch(function (e) {
 | 
				
			||||||
 | 
					          if ('NOERR' === e.code) { throw e; }
 | 
				
			||||||
 | 
					          return true;
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      ]).then(function () {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    // Testing Private Part of Key
 | 
				
			||||||
 | 
					  , Keypairs.export({ jwk: pair.private }).then(function (pem) {
 | 
				
			||||||
 | 
					      if (!/--BEGIN .*PRIVATE KEY--/.test(pem)) {
 | 
				
			||||||
 | 
					        throw new Error("did not export private pem: " + pem);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return Promise.all([
 | 
				
			||||||
 | 
					        Keypairs.parse({ key: pem }).then(function (pair) {
 | 
				
			||||||
 | 
					          if (!pair.private) {
 | 
				
			||||||
 | 
					            throw new Error("should have private part");
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (!pair.public) {
 | 
				
			||||||
 | 
					            throw new Error("should have public part also");
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return true;
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      , Keypairs.parse({ key: pem, public: true }).then(function (pair) {
 | 
				
			||||||
 | 
					          if (pair.private) {
 | 
				
			||||||
 | 
					            throw new Error("should NOT have private part");
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (!pair.public) {
 | 
				
			||||||
 | 
					            throw new Error("should have the public part though");
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return true;
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      ]).then(function () {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  , Keypairs.parseOrGenerate({ key: 'not a key', public: true }).then(function (pair) {
 | 
				
			||||||
 | 
					      // SHOULD have warning output
 | 
				
			||||||
 | 
					      if (!pair.private || !pair.public) {
 | 
				
			||||||
 | 
					        throw new Error("missing key pairs (should ignore 'public')");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  , Keypairs.parse({ key: JSON.stringify(pair.private) }).then(function (pair) {
 | 
				
			||||||
 | 
					      if (!pair.private || !pair.public) {
 | 
				
			||||||
 | 
					        throw new Error("missing key pairs (stringified jwt)");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  , Keypairs.parse({ key: JSON.stringify(pair.private), public: true }).then(function (pair) {
 | 
				
			||||||
 | 
					      if (pair.private) {
 | 
				
			||||||
 | 
					        throw new Error("has private key when it shouldn't");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (!pair.public) {
 | 
				
			||||||
 | 
					        throw new Error("doesn't have public key when it should");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  , Keypairs.parse({ key: JSON.stringify(pair.public), private: true }).then(function () {
 | 
				
			||||||
 | 
					      var err = new Error("should have thrown an error when private key was required and public jwk was given");
 | 
				
			||||||
 | 
					      err.code = 'NOERR';
 | 
				
			||||||
 | 
					      throw err;
 | 
				
			||||||
 | 
					    }).catch(function (e) {
 | 
				
			||||||
 | 
					      if ('NOERR' === e.code) { throw e; }
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  ]).then(function (results) {
 | 
				
			||||||
 | 
					    if (results.length && results.every(function (v) { return true === v; })) {
 | 
				
			||||||
 | 
					      console.info("If a warning prints right above this, it's a pass");
 | 
				
			||||||
 | 
					      console.log("PASS");
 | 
				
			||||||
 | 
					      process.exit(0);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      throw new Error("didn't get all passes (but no errors either)");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}).catch(function (e) {
 | 
				
			||||||
 | 
					  console.error("Caught an unexpected (failing) error:");
 | 
				
			||||||
 | 
					  console.error(e);
 | 
				
			||||||
 | 
					  process.exit(1);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user