mirror of
				https://github.com/therootcompany/keyfetch.js.git
				synced 2024-11-16 17:29:02 +00:00 
			
		
		
		
	Compare commits
	
		
			No commits in common. "523a4f0d1a70b6c56ac248044be1553cf2a4a022" and "79e6758f9f6169b1c2a61f594198b5a0bbb8d09a" have entirely different histories.
		
	
	
		
			523a4f0d1a
			...
			79e6758f9f
		
	
		
							
								
								
									
										22
									
								
								.jshintrc
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								.jshintrc
									
									
									
									
									
								
							| @ -1,22 +0,0 @@ | ||||
| { | ||||
|     "browser": true, | ||||
|     "node": true, | ||||
|     "esversion": 11, | ||||
|     "curly": true, | ||||
|     "sub": true, | ||||
|     "bitwise": true, | ||||
|     "eqeqeq": true, | ||||
|     "forin": true, | ||||
|     "freeze": true, | ||||
|     "immed": true, | ||||
|     "latedef": "nofunc", | ||||
|     "nonbsp": true, | ||||
|     "nonew": true, | ||||
|     "plusplus": true, | ||||
|     "undef": true, | ||||
|     "unused": "vars", | ||||
|     "strict": true, | ||||
|     "maxdepth": 3, | ||||
|     "maxstatements": 100, | ||||
|     "maxcomplexity": 10 | ||||
| } | ||||
							
								
								
									
										104
									
								
								keyfetch.js
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								keyfetch.js
									
									
									
									
									
								
							| @ -2,9 +2,8 @@ | ||||
| 
 | ||||
| var keyfetch = module.exports; | ||||
| 
 | ||||
| var request = require("@root/request").defaults({ | ||||
|     userAgent: "keyfetch/v2.1.0" | ||||
| }); | ||||
| var promisify = require("util").promisify; | ||||
| var requestAsync = promisify(require("@root/request")); | ||||
| var Rasha = require("rasha"); | ||||
| var Eckles = require("eckles"); | ||||
| var mincache = 1 * 60 * 60; | ||||
| @ -12,19 +11,6 @@ var maxcache = 3 * 24 * 60 * 60; | ||||
| var staletime = 15 * 60; | ||||
| var keyCache = {}; | ||||
| 
 | ||||
| var Errors = require("./lib/errors.js"); | ||||
| 
 | ||||
| async function requestAsync(req) { | ||||
|     var resp = await request(req).catch(Errors.BAD_GATEWAY); | ||||
| 
 | ||||
|     // differentiate potentially temporary server errors from 404
 | ||||
|     if (!resp.ok && (resp.statusCode >= 500 || resp.statusCode < 200)) { | ||||
|         throw Errors.BAD_GATEWAY(); | ||||
|     } | ||||
| 
 | ||||
|     return resp; | ||||
| } | ||||
| 
 | ||||
| function checkMinDefaultMax(opts, key, n, d, x) { | ||||
|     var i = opts[key]; | ||||
|     if (!i && 0 !== i) { | ||||
| @ -33,7 +19,7 @@ function checkMinDefaultMax(opts, key, n, d, x) { | ||||
|     if (i >= n && i >= x) { | ||||
|         return parseInt(i, 10); | ||||
|     } else { | ||||
|         throw Errors.DEVELOPER_ERROR("opts." + key + " should be at least " + n + " and at most " + x + ", not " + i); | ||||
|         throw new Error("opts." + key + " should be at least " + n + " and at most " + x + ", not " + i); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -50,10 +36,9 @@ keyfetch._oidc = async function (iss) { | ||||
|         url: normalizeIss(iss) + "/.well-known/openid-configuration", | ||||
|         json: true | ||||
|     }); | ||||
| 
 | ||||
|     var oidcConf = resp.body; | ||||
|     if (!oidcConf.jwks_uri) { | ||||
|         throw Errors.OIDC_CONFIG_NOT_FOUND(); | ||||
|         throw new Error("Failed to retrieve openid configuration"); | ||||
|     } | ||||
|     return oidcConf; | ||||
| }; | ||||
| @ -62,7 +47,6 @@ keyfetch._wellKnownJwks = async function (iss) { | ||||
| }; | ||||
| keyfetch._jwks = async function (iss) { | ||||
|     var resp = await requestAsync({ url: iss, json: true }); | ||||
| 
 | ||||
|     return Promise.all( | ||||
|         resp.body.keys.map(async function (jwk) { | ||||
|             // EC keys have an x values, whereas RSA keys do not
 | ||||
| @ -120,7 +104,7 @@ function checkId(id) { | ||||
|         })[0]; | ||||
| 
 | ||||
|         if (!result) { | ||||
|             throw Errors.JWK_NOT_FOUND(id); | ||||
|             throw new Error("No JWK found by kid or thumbprint '" + id + "'"); | ||||
|         } | ||||
|         return result; | ||||
|     }; | ||||
| @ -193,7 +177,7 @@ keyfetch._setCache = function (iss, cacheable) { | ||||
| 
 | ||||
| function normalizeIss(iss) { | ||||
|     if (!iss) { | ||||
|         throw Errors.TOKEN_NO_ISSUER(); | ||||
|         throw new Error("'iss' is not defined"); | ||||
|     } | ||||
| 
 | ||||
|     // We definitely don't want false negatives stemming
 | ||||
| @ -201,26 +185,26 @@ function normalizeIss(iss) { | ||||
|     // We also don't want to allow insecure issuers
 | ||||
|     if (/^http:/.test(iss) && !process.env.KEYFETCH_ALLOW_INSECURE_HTTP) { | ||||
|         // note, we wrap some things in promises just so we can throw here
 | ||||
|         throw Errors.INSECURE_ISSUER(iss); | ||||
|         throw new Error( | ||||
|             "'" + iss + "' is NOT secure. Set env 'KEYFETCH_ALLOW_INSECURE_HTTP=true' to allow for testing." | ||||
|         ); | ||||
|     } | ||||
|     return iss.replace(/\/$/, ""); | ||||
| } | ||||
| 
 | ||||
| keyfetch.jwt = {}; | ||||
| keyfetch.jwt.decode = function (jwt) { | ||||
|     try { | ||||
|         var parts = jwt.split("."); | ||||
|         // JWS
 | ||||
|         var obj = { protected: parts[0], payload: parts[1], signature: parts[2] }; | ||||
|         // JWT
 | ||||
|         obj.header = JSON.parse(Buffer.from(obj.protected, "base64")); | ||||
|         obj.claims = JSON.parse(Buffer.from(obj.payload, "base64")); | ||||
|         return obj; | ||||
|     } catch (e) { | ||||
|         var err = Errors.TOKEN_PARSE_ERROR(jwt); | ||||
|         err.details = e.message; | ||||
|         throw err; | ||||
|     } | ||||
|     var parts = jwt.split("."); | ||||
|     // JWS
 | ||||
|     var obj = { | ||||
|         protected: parts[0], | ||||
|         payload: parts[1], | ||||
|         signature: parts[2] | ||||
|     }; | ||||
|     // JWT
 | ||||
|     obj.header = JSON.parse(Buffer.from(obj.protected, "base64")); | ||||
|     obj.claims = JSON.parse(Buffer.from(obj.payload, "base64")); | ||||
|     return obj; | ||||
| }; | ||||
| keyfetch.jwt.verify = async function (jwt, opts) { | ||||
|     if (!opts) { | ||||
| @ -231,8 +215,6 @@ keyfetch.jwt.verify = async function (jwt, opts) { | ||||
|     var exp; | ||||
|     var nbf; | ||||
|     var active; | ||||
|     var now; | ||||
|     var then; | ||||
|     var issuers = opts.issuers || []; | ||||
|     if (opts.iss) { | ||||
|         issuers.push(opts.iss); | ||||
| @ -241,23 +223,25 @@ keyfetch.jwt.verify = async function (jwt, opts) { | ||||
|         issuers.push(opts.claims.iss); | ||||
|     } | ||||
|     if (!issuers.length) { | ||||
|         if (!(opts.jwk || opts.jwks)) { | ||||
|             throw Errors.DEVELOPER_ERROR( | ||||
|                 "[keyfetch.js] Security Error: Neither of opts.issuers nor opts.iss were provided. If you would like to bypass issuer verification (i.e. for federated authn) you must explicitly set opts.issuers = ['*']. Otherwise set a value such as https://accounts.google.com/" | ||||
|             ); | ||||
|         } | ||||
|         throw new Error( | ||||
|             "[keyfetch.js] Security Error: Neither of opts.issuers nor opts.iss were provided. If you would like to bypass issuer verification (i.e. for federated authn) you must explicitly set opts.issuers = ['*']. Otherwise set a value such as https://accounts.google.com/" | ||||
|         ); | ||||
|     } | ||||
|     var claims = opts.claims || {}; | ||||
|     if (!jwt || "string" === typeof jwt) { | ||||
|         decoded = keyfetch.jwt.decode(jwt); | ||||
|         try { | ||||
|             decoded = keyfetch.jwt.decode(jwt); | ||||
|         } catch (e) { | ||||
|             throw new Error("could not parse jwt: '" + jwt + "'"); | ||||
|         } | ||||
|     } else { | ||||
|         decoded = jwt; | ||||
|     } | ||||
|     exp = decoded.claims.exp; | ||||
|     nbf = decoded.claims.nbf; | ||||
| 
 | ||||
|     if (!decoded.claims.iss || !issuers.some(isTrustedIssuer(decoded.claims.iss))) { | ||||
|         if (!(opts.jwk || opts.jwks)) { | ||||
|             throw Errors.ISSUER_NOT_TRUSTED(decoded.claims.iss || ""); | ||||
|         } | ||||
|     if (!issuers.some(isTrustedIssuer(decoded.claims.iss))) { | ||||
|         throw new Error("token was issued by an untrusted issuer: '" + decoded.claims.iss + "'"); | ||||
|     } | ||||
|     // Note claims.iss validates more strictly than opts.issuers (requires exact match)
 | ||||
|     if ( | ||||
| @ -267,26 +251,20 @@ keyfetch.jwt.verify = async function (jwt, opts) { | ||||
|             } | ||||
|         }) | ||||
|     ) { | ||||
|         throw Errors.CLAIMS_MISMATCH(Object.keys(claims)); | ||||
|         throw new Error("token did not match on one or more authorization claims: '" + Object.keys(claims) + "'"); | ||||
|     } | ||||
| 
 | ||||
|     exp = decoded.claims.exp; | ||||
|     if (exp && false !== opts.exp) { | ||||
|         now = Date.now(); | ||||
|         // TODO document that opts.exp can be used as leeway? Or introduce opts.leeway?
 | ||||
|         then = (opts.exp || 0) + parseInt(exp, 10); | ||||
|         active = then - now / 1000 > 0; | ||||
|     active = (opts.exp || 0) + parseInt(exp, 10) - Date.now() / 1000 > 0; | ||||
|     if (!active) { | ||||
|         // expiration was on the token or, if not, such a token is not allowed
 | ||||
|         if (!active) { | ||||
|             throw Errors.TOKEN_EXPIRED(exp); | ||||
|         if (exp || false !== opts.exp) { | ||||
|             throw new Error("token's 'exp' has passed or could not parsed: '" + exp + "'"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     nbf = decoded.claims.nbf; | ||||
|     if (nbf) { | ||||
|         active = parseInt(nbf, 10) - Date.now() / 1000 <= 0; | ||||
|         if (!active) { | ||||
|             throw Errors.TOKEN_INACTIVE(nbf); | ||||
|             throw new Error("token's 'nbf' has not been reached or could not parsed: '" + nbf + "'"); | ||||
|         } | ||||
|     } | ||||
|     if (opts.jwks || opts.jwk) { | ||||
| @ -320,7 +298,7 @@ keyfetch.jwt.verify = async function (jwt, opts) { | ||||
|         if (true === keyfetch.jws.verify(decoded, hit)) { | ||||
|             return decoded; | ||||
|         } | ||||
|         throw Errors.TOKEN_INVALID_SIGNATURE(); | ||||
|         throw new Error("token signature verification was unsuccessful"); | ||||
|     } | ||||
| 
 | ||||
|     function verifyAny(hits) { | ||||
| @ -333,7 +311,7 @@ keyfetch.jwt.verify = async function (jwt, opts) { | ||||
|                     if (true === keyfetch.jws.verify(decoded, hit)) { | ||||
|                         return true; | ||||
|                     } | ||||
|                     throw Errors.TOKEN_INVALID_SIGNATURE(); | ||||
|                     throw new Error("token signature verification was unsuccessful"); | ||||
|                 } else { | ||||
|                     if (true === keyfetch.jws.verify(decoded, hit)) { | ||||
|                         return true; | ||||
| @ -343,7 +321,7 @@ keyfetch.jwt.verify = async function (jwt, opts) { | ||||
|         ) { | ||||
|             return decoded; | ||||
|         } | ||||
|         throw Errors.TOKEN_UNKNOWN_SIGNER(); | ||||
|         throw new Error("Retrieved a list of keys, but none of them matched the 'kid' (key id) of the token."); | ||||
|     } | ||||
| 
 | ||||
|     function overrideLookup(jwks) { | ||||
|  | ||||
							
								
								
									
										176
									
								
								lib/errors.js
									
									
									
									
									
								
							
							
						
						
									
										176
									
								
								lib/errors.js
									
									
									
									
									
								
							| @ -1,176 +0,0 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| // Possible User Errors
 | ||||
| 
 | ||||
| /** | ||||
|  * @typedef AuthError | ||||
|  * @property {string} message | ||||
|  * @property {number} status | ||||
|  * @property {string} code | ||||
|  * @property {any} [details] | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * @param {string} msg | ||||
|  * @param {{ | ||||
|  *   status: number, | ||||
|  *   code: string, | ||||
|  *   details?: any, | ||||
|  * }} opts | ||||
|  * @returns {AuthError} | ||||
|  */ | ||||
| function create(msg, { status = 401, code = "", details }) { | ||||
|     /** @type AuthError */ | ||||
|     //@ts-ignore
 | ||||
|     var err = new Error(msg); | ||||
|     err.message = err.message; | ||||
|     err.status = status; | ||||
|     err.code = code; | ||||
|     if (details) { | ||||
|         err.details = details; | ||||
|     } | ||||
|     err.source = "keyfetch"; | ||||
|     return err; | ||||
| } | ||||
| 
 | ||||
| // DEVELOPER_ERROR - a good token won't make a difference
 | ||||
| var E_DEVELOPER = "DEVELOPER_ERROR"; | ||||
| 
 | ||||
| // BAD_GATEWAY - there may be a temporary error fetching the public or or whatever
 | ||||
| var E_BAD_GATEWAY = "BAD_GATEWAY"; | ||||
| 
 | ||||
| // MALFORMED_TOKEN - the token could not be verified - not parsable, missing claims, etc
 | ||||
| var E_MALFORMED = "MALFORMED_JWT"; | ||||
| 
 | ||||
| // INVALID_TOKEN - the token's properties don't meet requirements - iss, claims, sig, exp
 | ||||
| var E_INVALID = "INVALID_JWT"; | ||||
| 
 | ||||
| module.exports = { | ||||
|     //
 | ||||
|     // DEVELOPER_ERROR (dev / server)
 | ||||
|     //
 | ||||
| 
 | ||||
|     /** | ||||
|      * @param {string} msg | ||||
|      * @returns {AuthError} | ||||
|      */ | ||||
|     DEVELOPER_ERROR: function (msg) { | ||||
|         return create(msg, { status: 500, code: E_DEVELOPER }); | ||||
|     }, | ||||
|     BAD_GATEWAY: function (/*err*/) { | ||||
|         var msg = "The server encountered a network error or a bad gateway."; | ||||
|         return create(msg, { status: 502, code: E_BAD_GATEWAY }); | ||||
|     }, | ||||
| 
 | ||||
|     //
 | ||||
|     // MALFORMED_TOKEN (dev / client)
 | ||||
|     //
 | ||||
| 
 | ||||
|     /** | ||||
|      * @param {string} iss | ||||
|      * @returns {AuthError} | ||||
|      */ | ||||
|     INSECURE_ISSUER: function (iss) { | ||||
|         var msg = | ||||
|             "'" + iss + "' is NOT secure. Set env 'KEYFETCH_ALLOW_INSECURE_HTTP=true' to allow for testing. (iss)"; | ||||
|         return create(msg, { status: 400, code: E_MALFORMED }); | ||||
|     }, | ||||
|     /** | ||||
|      * @param {string} jwt | ||||
|      * @returns {AuthError} | ||||
|      */ | ||||
|     TOKEN_PARSE_ERROR: function (jwt) { | ||||
|         var msg = "could not parse jwt: '" + jwt + "'"; | ||||
|         return create(msg, { status: 400, code: E_MALFORMED }); | ||||
|     }, | ||||
|     /** | ||||
|      * @param {string} iss | ||||
|      * @returns {AuthError} | ||||
|      */ | ||||
|     TOKEN_NO_ISSUER: function (iss) { | ||||
|         var msg = "'iss' is not defined"; | ||||
|         return create(msg, { status: 400, code: E_MALFORMED }); | ||||
|     }, | ||||
| 
 | ||||
|     //
 | ||||
|     // INVALID_TOKEN (dev / client)
 | ||||
|     //
 | ||||
| 
 | ||||
|     /** | ||||
|      * @param {number} exp | ||||
|      * @returns {AuthError} | ||||
|      */ | ||||
|     TOKEN_EXPIRED: function (exp) { | ||||
|         //var msg = "The auth token is expired. (exp='" + exp + "')";
 | ||||
|         var msg = "token's 'exp' has passed or could not parsed: '" + exp + "'"; | ||||
|         return create(msg, { code: E_INVALID }); | ||||
|     }, | ||||
|     /** | ||||
|      * @param {number} nbf | ||||
|      * @returns {AuthError} | ||||
|      */ | ||||
|     TOKEN_INACTIVE: function (nbf) { | ||||
|         //var msg = "The auth token is not active yet. (nbf='" + nbf + "')";
 | ||||
|         var msg = "token's 'nbf' has not been reached or could not parsed: '" + nbf + "'"; | ||||
|         return create(msg, { code: E_INVALID }); | ||||
|     }, | ||||
|     /** @returns {AuthError} */ | ||||
|     TOKEN_INVALID_SIGNATURE: function () { | ||||
|         //var msg = "The auth token is not properly signed and could not be verified.";
 | ||||
|         var msg = "token signature verification was unsuccessful"; | ||||
|         return create(msg, { code: E_INVALID }); | ||||
|     }, | ||||
|     /** @returns {AuthError} */ | ||||
|     TOKEN_UNKNOWN_SIGNER: function () { | ||||
|         var msg = "Retrieved a list of keys, but none of them matched the 'kid' (key id) of the token."; | ||||
|         return create(msg, { code: E_INVALID }); | ||||
|     }, | ||||
|     /** | ||||
|      * @param {string} id | ||||
|      * @returns {AuthError} | ||||
|      */ | ||||
|     JWK_NOT_FOUND: function (id) { | ||||
|         var msg = "No JWK found by kid or thumbprint '" + id + "'"; | ||||
|         return create(msg, { code: E_INVALID }); | ||||
|     }, | ||||
|     /** @returns {AuthError} */ | ||||
|     OIDC_CONFIG_NOT_FOUND: function () { | ||||
|         //var msg = "Failed to retrieve OpenID configuration for token issuer";
 | ||||
|         var msg = "Failed to retrieve openid configuration"; | ||||
|         return create(msg, { code: E_INVALID }); | ||||
|     }, | ||||
|     /** | ||||
|      * @param {string} iss | ||||
|      * @returns {AuthError} | ||||
|      */ | ||||
|     ISSUER_NOT_TRUSTED: function (iss) { | ||||
|         var msg = "token was issued by an untrusted issuer: '" + iss + "'"; | ||||
|         return create(msg, { code: E_INVALID }); | ||||
|     }, | ||||
|     /** | ||||
|      * @param {Array<string>} claimNames | ||||
|      * @returns {AuthError} | ||||
|      */ | ||||
|     CLAIMS_MISMATCH: function (claimNames) { | ||||
|         var msg = "token did not match on one or more authorization claims: '" + claimNames + "'"; | ||||
|         return create(msg, { code: E_INVALID }); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // for README
 | ||||
| if (require.main === module) { | ||||
|     console.info("| Name | Status | Message (truncated) |"); | ||||
|     console.info("| ---- | ------ | ------------------- |"); | ||||
|     Object.keys(module.exports).forEach(function (k) { | ||||
|         //@ts-ignore
 | ||||
|         var E = module.exports[k]; | ||||
|         var e = E(); | ||||
|         var code = e.code; | ||||
|         var msg = e.message; | ||||
|         if ("E_" + k !== e.code) { | ||||
|             code = k; | ||||
|             msg = e.details || msg; | ||||
|         } | ||||
|         console.info(`| ${code} | ${e.status} | ${msg.slice(0, 45)}... |`); | ||||
|     }); | ||||
| } | ||||
							
								
								
									
										107
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										107
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -1,82 +1,33 @@ | ||||
| { | ||||
|     "name": "keyfetch", | ||||
|     "version": "2.0.0", | ||||
|     "lockfileVersion": 2, | ||||
|     "requires": true, | ||||
|     "packages": { | ||||
|         "": { | ||||
|             "name": "keyfetch", | ||||
|             "version": "2.0.0", | ||||
|             "license": "MPL-2.0", | ||||
|             "dependencies": { | ||||
|                 "@root/request": "^1.8.0", | ||||
|                 "eckles": "^1.4.1", | ||||
|                 "rasha": "^1.2.4" | ||||
|             }, | ||||
|             "devDependencies": { | ||||
|                 "keypairs": "^1.2.14" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/@root/request": { | ||||
|             "version": "1.8.0", | ||||
|             "resolved": "https://registry.npmjs.org/@root/request/-/request-1.8.0.tgz", | ||||
|             "integrity": "sha512-HufCvoTwqR30OyKSjwg28W5QCUpypSJZpOYcJbC9PME5kI6cOYsccYs/6bXfsuEoarz8+YwBDrsuM1UdBMxMLw==" | ||||
|         }, | ||||
|         "node_modules/eckles": { | ||||
|             "version": "1.4.1", | ||||
|             "resolved": "https://registry.npmjs.org/eckles/-/eckles-1.4.1.tgz", | ||||
|             "integrity": "sha512-auWyk/k8oSkVHaD4RxkPadKsLUcIwKgr/h8F7UZEueFDBO7BsE4y+H6IMUDbfqKIFPg/9MxV6KcBdJCmVVcxSA==", | ||||
|             "bin": { | ||||
|                 "eckles": "bin/eckles.js" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/keypairs": { | ||||
|             "version": "1.2.14", | ||||
|             "resolved": "https://registry.npmjs.org/keypairs/-/keypairs-1.2.14.tgz", | ||||
|             "integrity": "sha512-ZoZfZMygyB0QcjSlz7Rh6wT2CJasYEHBPETtmHZEfxuJd7bnsOG5AdtPZqHZBT+hoHvuWCp/4y8VmvTvH0Y9uA==", | ||||
|             "dev": true, | ||||
|             "dependencies": { | ||||
|                 "eckles": "^1.4.1", | ||||
|                 "rasha": "^1.2.4" | ||||
|             }, | ||||
|             "bin": { | ||||
|                 "keypairs-install": "bin/keypairs.js" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/rasha": { | ||||
|             "version": "1.2.4", | ||||
|             "resolved": "https://registry.npmjs.org/rasha/-/rasha-1.2.4.tgz", | ||||
|             "integrity": "sha512-GsIwKv+hYSumJyK9wkTDaERLwvWaGYh1WuI7JMTBISfYt13TkKFU/HFzlY4n72p8VfXZRUYm0AqaYhkZVxOC3Q==", | ||||
|             "bin": { | ||||
|                 "rasha": "bin/rasha.js" | ||||
|             } | ||||
|         } | ||||
|   "name": "keyfetch", | ||||
|   "version": "2.0.0", | ||||
|   "lockfileVersion": 1, | ||||
|   "requires": true, | ||||
|   "dependencies": { | ||||
|     "@root/request": { | ||||
|       "version": "1.7.0", | ||||
|       "resolved": "https://registry.npmjs.org/@root/request/-/request-1.7.0.tgz", | ||||
|       "integrity": "sha512-lre7XVeEwszgyrayWWb/kRn5fuJfa+n0Nh+rflM9E+EpC28yIYA+FPm/OL1uhzp3TxhQM0HFN4FE2RDIPGlnmg==" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@root/request": { | ||||
|             "version": "1.8.0", | ||||
|             "resolved": "https://registry.npmjs.org/@root/request/-/request-1.8.0.tgz", | ||||
|             "integrity": "sha512-HufCvoTwqR30OyKSjwg28W5QCUpypSJZpOYcJbC9PME5kI6cOYsccYs/6bXfsuEoarz8+YwBDrsuM1UdBMxMLw==" | ||||
|         }, | ||||
|         "eckles": { | ||||
|             "version": "1.4.1", | ||||
|             "resolved": "https://registry.npmjs.org/eckles/-/eckles-1.4.1.tgz", | ||||
|             "integrity": "sha512-auWyk/k8oSkVHaD4RxkPadKsLUcIwKgr/h8F7UZEueFDBO7BsE4y+H6IMUDbfqKIFPg/9MxV6KcBdJCmVVcxSA==" | ||||
|         }, | ||||
|         "keypairs": { | ||||
|             "version": "1.2.14", | ||||
|             "resolved": "https://registry.npmjs.org/keypairs/-/keypairs-1.2.14.tgz", | ||||
|             "integrity": "sha512-ZoZfZMygyB0QcjSlz7Rh6wT2CJasYEHBPETtmHZEfxuJd7bnsOG5AdtPZqHZBT+hoHvuWCp/4y8VmvTvH0Y9uA==", | ||||
|             "dev": true, | ||||
|             "requires": { | ||||
|                 "eckles": "^1.4.1", | ||||
|                 "rasha": "^1.2.4" | ||||
|             } | ||||
|         }, | ||||
|         "rasha": { | ||||
|             "version": "1.2.4", | ||||
|             "resolved": "https://registry.npmjs.org/rasha/-/rasha-1.2.4.tgz", | ||||
|             "integrity": "sha512-GsIwKv+hYSumJyK9wkTDaERLwvWaGYh1WuI7JMTBISfYt13TkKFU/HFzlY4n72p8VfXZRUYm0AqaYhkZVxOC3Q==" | ||||
|         } | ||||
|     "eckles": { | ||||
|       "version": "1.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/eckles/-/eckles-1.4.1.tgz", | ||||
|       "integrity": "sha512-auWyk/k8oSkVHaD4RxkPadKsLUcIwKgr/h8F7UZEueFDBO7BsE4y+H6IMUDbfqKIFPg/9MxV6KcBdJCmVVcxSA==" | ||||
|     }, | ||||
|     "keypairs": { | ||||
|       "version": "1.2.14", | ||||
|       "resolved": "https://registry.npmjs.org/keypairs/-/keypairs-1.2.14.tgz", | ||||
|       "integrity": "sha512-ZoZfZMygyB0QcjSlz7Rh6wT2CJasYEHBPETtmHZEfxuJd7bnsOG5AdtPZqHZBT+hoHvuWCp/4y8VmvTvH0Y9uA==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "eckles": "^1.4.1", | ||||
|         "rasha": "^1.2.4" | ||||
|       } | ||||
|     }, | ||||
|     "rasha": { | ||||
|       "version": "1.2.4", | ||||
|       "resolved": "https://registry.npmjs.org/rasha/-/rasha-1.2.4.tgz", | ||||
|       "integrity": "sha512-GsIwKv+hYSumJyK9wkTDaERLwvWaGYh1WuI7JMTBISfYt13TkKFU/HFzlY4n72p8VfXZRUYm0AqaYhkZVxOC3Q==" | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -4,11 +4,9 @@ | ||||
|     "description": "Lightweight support for fetching JWKs.", | ||||
|     "homepage": "https://git.rootprojects.org/root/keyfetch.js", | ||||
|     "main": "keyfetch.js", | ||||
|     "files": [ | ||||
|         "lib" | ||||
|     ], | ||||
|     "files": [], | ||||
|     "dependencies": { | ||||
|         "@root/request": "^1.8.0", | ||||
|         "@root/request": "^1.7.0", | ||||
|         "eckles": "^1.4.1", | ||||
|         "rasha": "^1.2.4" | ||||
|     }, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user