Переглянути джерело

v1.2.8: allow non-stringified jwk in parse, ignore undefineds when neutering

tags/v1.2.8
AJ ONeal 6 місяці тому
джерело
коміт
083cc6d73e
3 змінених файлів з 55 додано та 22 видалено
  1. 16
    2
      README.md
  2. 38
    19
      keypairs.js
  3. 1
    1
      package.json

+ 16
- 2
README.md Переглянути файл

@@ -51,6 +51,7 @@ return Keypairs.export({ jwk: pair.private, format: 'pkcs8' }).then(function (pe
51 51
 ```
52 52
 // PEM to JWK
53 53
 return Keypairs.import({ pem: pem }).then(function (jwk) {
54
+  console.log(jwk);
54 55
 });
55 56
 ```
56 57
 
@@ -164,9 +165,22 @@ Options
164 165
 }
165 166
 ```
166 167
 
167
-#### Keypairs.publish({ jwk: jwk })
168
+#### Keypairs.publish({ jwk: jwk, exp: '3d', use: 'sig' })
168 169
 
169
-**Synchronously** strips a key of its private parts and returns the public version.
170
+Promises a public key that adheres to the OIDC and Auth0 spec (plus expiry), suitable to be published to a JWKs URL:
171
+
172
+```
173
+{ "kty": "EC"
174
+, "crv": "P-256"
175
+, "x": "..."
176
+, "y": "..."
177
+, "kid": "..."
178
+, "use": "sig"
179
+, "exp": 1552074208
180
+}
181
+```
182
+
183
+In particular this adds "use" and "exp".
170 184
 
171 185
 #### Keypairs.thumbprint({ jwk: jwk })
172 186
 

+ 38
- 19
keypairs.js Переглянути файл

@@ -10,10 +10,19 @@ var Keypairs = module.exports;
10 10
 Keypairs.generate = function (opts) {
11 11
   opts = opts || {};
12 12
   var kty = opts.kty || opts.type;
13
+  var p;
13 14
   if ('RSA' === kty) {
14
-    return Rasha.generate(opts);
15
+    p = Rasha.generate(opts);
16
+  } else {
17
+    p = Eckles.generate(opts);
15 18
   }
16
-  return Eckles.generate(opts);
19
+  return p.then(function (pair) {
20
+    return Keypairs.thumbprint({ jwk: pair.public }).then(function (thumb) {
21
+      pair.private.kid = thumb; // maybe not the same id on the private key?
22
+      pair.public.kid = thumb;
23
+      return pair;
24
+    });
25
+  });
17 26
 };
18 27
 
19 28
 Keypairs.parse = function (opts) {
@@ -24,22 +33,26 @@ Keypairs.parse = function (opts) {
24 33
   var pem;
25 34
   var p;
26 35
 
27
-  try {
28
-    jwk = JSON.parse(opts.key);
29
-    p = Keypairs.export({ jwk: jwk }).catch(function (e) {
30
-      pem = opts.key;
31
-      err = new Error("Not a valid jwk '" + JSON.stringify(jwk) + "':" + e.message);
32
-      err.code = "EINVALID";
33
-      return Promise.reject(err);
34
-    }).then(function () {
35
-      return jwk;
36
-    });
37
-  } catch(e) {
38
-    p = Keypairs.import({ pem: opts.key }).catch(function (e) {
39
-      err = new Error("Could not parse key (type " + typeof opts.key + ") '" + opts.key + "': " + e.message);
40
-      err.code = "EPARSE";
41
-      return Promise.reject(err);
42
-    });
36
+  if (!opts.key || !opts.key.kty) {
37
+    try {
38
+      jwk = JSON.parse(opts.key);
39
+      p = Keypairs.export({ jwk: jwk }).catch(function (e) {
40
+        pem = opts.key;
41
+        err = new Error("Not a valid jwk '" + JSON.stringify(jwk) + "':" + e.message);
42
+        err.code = "EINVALID";
43
+        return Promise.reject(err);
44
+      }).then(function () {
45
+        return jwk;
46
+      });
47
+    } catch(e) {
48
+      p = Keypairs.import({ pem: opts.key }).catch(function (e) {
49
+        err = new Error("Could not parse key (type " + typeof opts.key + ") '" + opts.key + "': " + e.message);
50
+        err.code = "EPARSE";
51
+        return Promise.reject(err);
52
+      });
53
+    }
54
+  } else {
55
+    p = Promise.resolve(opts.key);
43 56
   }
44 57
 
45 58
   return p.then(function (jwk) {
@@ -74,6 +87,11 @@ Keypairs.parseOrGenerate = function (opts) {
74 87
 Keypairs.import = function (opts) {
75 88
   return Eckles.import(opts).catch(function () {
76 89
     return Rasha.import(opts);
90
+  }).then(function (jwk) {
91
+    return Keypairs.thumbprint({ jwk: jwk }).then(function (thumb) {
92
+      jwk.kid = thumb;
93
+      return jwk;
94
+    });
77 95
   });
78 96
 };
79 97
 
@@ -93,6 +111,7 @@ Keypairs.neuter = Keypairs._neuter = function (opts) {
93 111
   // trying to find the best balance of an immutable copy with custom attributes
94 112
   var jwk = {};
95 113
   Object.keys(opts.jwk).forEach(function (k) {
114
+    if ('undefined' === typeof opts.jwk[k]) { return; }
96 115
     // ignore RSA and EC private parts
97 116
     if (-1 !== ['d', 'p', 'q', 'dp', 'dq', 'qi'].indexOf(k)) { return; }
98 117
     jwk[k] = JSON.parse(JSON.stringify(opts.jwk[k]));
@@ -111,7 +130,7 @@ Keypairs.publish = function (opts) {
111 130
   } else {
112 131
     if (opts.exp) { jwk.exp = setTime(opts.exp); }
113 132
     else if (opts.expiresIn) { jwk.exp = Math.round(Date.now()/1000) + opts.expiresIn; }
114
-    else { jwk.exp = opts.expiresAt; }
133
+    else if (opts.expiresAt) { jwk.exp = opts.expiresAt; }
115 134
   }
116 135
   if (!jwk.use && false !== jwk.use) { jwk.use = "sig"; }
117 136
 

+ 1
- 1
package.json Переглянути файл

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

Завантаження…
Відмінити
Зберегти