dev testing
This commit is contained in:
91
functions/node_modules/jwks-rsa/src/JwksClient.js
generated
vendored
Normal file
91
functions/node_modules/jwks-rsa/src/JwksClient.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
const logger = require('debug')('jwks');
|
||||
const { retrieveSigningKeys } = require('./utils') ;
|
||||
const { request, cacheSigningKey, rateLimitSigningKey, getKeysInterceptor, callbackSupport } = require('./wrappers');
|
||||
const JwksError = require('./errors/JwksError');
|
||||
const SigningKeyNotFoundError = require('./errors/SigningKeyNotFoundError');
|
||||
|
||||
class JwksClient {
|
||||
constructor(options) {
|
||||
this.options = {
|
||||
rateLimit: false,
|
||||
cache: true,
|
||||
timeout: 30000,
|
||||
...options
|
||||
};
|
||||
|
||||
// Initialize wrappers.
|
||||
if (this.options.getKeysInterceptor) {
|
||||
this.getSigningKey = getKeysInterceptor(this, options);
|
||||
}
|
||||
|
||||
if (this.options.rateLimit) {
|
||||
this.getSigningKey = rateLimitSigningKey(this, options);
|
||||
}
|
||||
if (this.options.cache) {
|
||||
this.getSigningKey = cacheSigningKey(this, options);
|
||||
}
|
||||
|
||||
this.getSigningKey = callbackSupport(this, options);
|
||||
}
|
||||
|
||||
async getKeys() {
|
||||
logger(`Fetching keys from '${this.options.jwksUri}'`);
|
||||
|
||||
try {
|
||||
const res = await request({
|
||||
uri: this.options.jwksUri,
|
||||
headers: this.options.requestHeaders,
|
||||
agent: this.options.requestAgent,
|
||||
timeout: this.options.timeout,
|
||||
fetcher: this.options.fetcher
|
||||
});
|
||||
|
||||
logger('Keys:', res.keys);
|
||||
return res.keys;
|
||||
} catch (err) {
|
||||
const { errorMsg } = err;
|
||||
logger('Failure:', errorMsg || err);
|
||||
throw (errorMsg ? new JwksError(errorMsg) : err);
|
||||
}
|
||||
}
|
||||
|
||||
async getSigningKeys() {
|
||||
const keys = await this.getKeys();
|
||||
|
||||
if (!keys || !keys.length) {
|
||||
throw new JwksError('The JWKS endpoint did not contain any keys');
|
||||
}
|
||||
|
||||
const signingKeys = await retrieveSigningKeys(keys);
|
||||
|
||||
if (!signingKeys.length) {
|
||||
throw new JwksError('The JWKS endpoint did not contain any signing keys');
|
||||
}
|
||||
|
||||
logger('Signing Keys:', signingKeys);
|
||||
return signingKeys;
|
||||
}
|
||||
|
||||
async getSigningKey (kid) {
|
||||
logger(`Fetching signing key for '${kid}'`);
|
||||
const keys = await this.getSigningKeys();
|
||||
|
||||
const kidDefined = kid !== undefined && kid !== null;
|
||||
if (!kidDefined && keys.length > 1) {
|
||||
logger('No KID specified and JWKS endpoint returned more than 1 key');
|
||||
throw new SigningKeyNotFoundError('No KID specified and JWKS endpoint returned more than 1 key');
|
||||
}
|
||||
|
||||
const key = keys.find(k => !kidDefined || k.kid === kid);
|
||||
if (key) {
|
||||
return key;
|
||||
} else {
|
||||
logger(`Unable to find a signing key that matches '${kid}'`);
|
||||
throw new SigningKeyNotFoundError(`Unable to find a signing key that matches '${kid}'`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
JwksClient
|
||||
};
|
||||
10
functions/node_modules/jwks-rsa/src/errors/ArgumentError.js
generated
vendored
Normal file
10
functions/node_modules/jwks-rsa/src/errors/ArgumentError.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
function ArgumentError(message) {
|
||||
Error.call(this, message);
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
this.name = 'ArgumentError';
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
ArgumentError.prototype = Object.create(Error.prototype);
|
||||
ArgumentError.prototype.constructor = ArgumentError;
|
||||
module.exports = ArgumentError;
|
||||
10
functions/node_modules/jwks-rsa/src/errors/JwksError.js
generated
vendored
Normal file
10
functions/node_modules/jwks-rsa/src/errors/JwksError.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
function JwksError(message) {
|
||||
Error.call(this, message);
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
this.name = 'JwksError';
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
JwksError.prototype = Object.create(Error.prototype);
|
||||
JwksError.prototype.constructor = JwksError;
|
||||
module.exports = JwksError;
|
||||
10
functions/node_modules/jwks-rsa/src/errors/JwksRateLimitError.js
generated
vendored
Normal file
10
functions/node_modules/jwks-rsa/src/errors/JwksRateLimitError.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
function JwksRateLimitError(message) {
|
||||
Error.call(this, message);
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
this.name = 'JwksRateLimitError';
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
JwksRateLimitError.prototype = Object.create(Error.prototype);
|
||||
JwksRateLimitError.prototype.constructor = JwksRateLimitError;
|
||||
module.exports = JwksRateLimitError;
|
||||
10
functions/node_modules/jwks-rsa/src/errors/SigningKeyNotFoundError.js
generated
vendored
Normal file
10
functions/node_modules/jwks-rsa/src/errors/SigningKeyNotFoundError.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
function SigningKeyNotFoundError(message) {
|
||||
Error.call(this, message);
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
this.name = 'SigningKeyNotFoundError';
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
SigningKeyNotFoundError.prototype = Object.create(Error.prototype);
|
||||
SigningKeyNotFoundError.prototype.constructor = SigningKeyNotFoundError;
|
||||
module.exports = SigningKeyNotFoundError;
|
||||
6
functions/node_modules/jwks-rsa/src/errors/index.js
generated
vendored
Normal file
6
functions/node_modules/jwks-rsa/src/errors/index.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
ArgumentError: require('./ArgumentError'),
|
||||
JwksError: require('./JwksError'),
|
||||
JwksRateLimitError: require('./JwksRateLimitError'),
|
||||
SigningKeyNotFoundError: require('./SigningKeyNotFoundError')
|
||||
};
|
||||
22
functions/node_modules/jwks-rsa/src/index.js
generated
vendored
Normal file
22
functions/node_modules/jwks-rsa/src/index.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
const { JwksClient } = require('./JwksClient');
|
||||
const errors = require('./errors');
|
||||
const { hapiJwt2Key, hapiJwt2KeyAsync } = require('./integrations/hapi');
|
||||
const { expressJwtSecret } = require('./integrations/express');
|
||||
const { koaJwtSecret } = require('./integrations/koa');
|
||||
const { passportJwtSecret } = require('./integrations/passport');
|
||||
|
||||
module.exports = (options) => {
|
||||
return new JwksClient(options);
|
||||
};
|
||||
module.exports.JwksClient = JwksClient;
|
||||
|
||||
module.exports.ArgumentError = errors.ArgumentError;
|
||||
module.exports.JwksError = errors.JwksError;
|
||||
module.exports.JwksRateLimitError = errors.JwksRateLimitError;
|
||||
module.exports.SigningKeyNotFoundError = errors.SigningKeyNotFoundError;
|
||||
|
||||
module.exports.expressJwtSecret = expressJwtSecret;
|
||||
module.exports.hapiJwt2Key = hapiJwt2Key;
|
||||
module.exports.hapiJwt2KeyAsync = hapiJwt2KeyAsync;
|
||||
module.exports.koaJwtSecret = koaJwtSecret;
|
||||
module.exports.passportJwtSecret = passportJwtSecret;
|
||||
15
functions/node_modules/jwks-rsa/src/integrations/config.js
generated
vendored
Normal file
15
functions/node_modules/jwks-rsa/src/integrations/config.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
const allowedSignatureAlg = [
|
||||
'RS256',
|
||||
'RS384',
|
||||
'RS512',
|
||||
'PS256',
|
||||
'PS384',
|
||||
'PS512',
|
||||
'ES256',
|
||||
'ES256K',
|
||||
'ES384',
|
||||
'ES512',
|
||||
'EdDSA'
|
||||
];
|
||||
|
||||
module.exports = allowedSignatureAlg;
|
||||
60
functions/node_modules/jwks-rsa/src/integrations/express.js
generated
vendored
Normal file
60
functions/node_modules/jwks-rsa/src/integrations/express.js
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
const { ArgumentError } = require('../errors');
|
||||
const { JwksClient } = require('../JwksClient');
|
||||
const supportedAlg = require('./config');
|
||||
|
||||
const handleSigningKeyError = (err, cb) => {
|
||||
// If we didn't find a match, can't provide a key.
|
||||
if (err && err.name === 'SigningKeyNotFoundError') {
|
||||
return cb(null);
|
||||
}
|
||||
|
||||
// If an error occured like rate limiting or HTTP issue, we'll bubble up the error.
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.expressJwtSecret = function (options) {
|
||||
if (options === null || options === undefined) {
|
||||
throw new ArgumentError('An options object must be provided when initializing expressJwtSecret');
|
||||
}
|
||||
|
||||
const client = new JwksClient(options);
|
||||
const onError = options.handleSigningKeyError || handleSigningKeyError;
|
||||
|
||||
const expressJwt7Provider = async (req, token) => {
|
||||
if (!token) { return; }
|
||||
const header = token.header;
|
||||
if (!header || !supportedAlg.includes(header.alg)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const key = await client.getSigningKey(header.kid);
|
||||
return key.publicKey || key.rsaPublicKey;
|
||||
} catch (err) {
|
||||
return new Promise((resolve, reject) => {
|
||||
onError(err, (newError) => {
|
||||
if (!newError) { return resolve(); }
|
||||
reject(newError);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return function secretProvider(req, header, payload, cb) {
|
||||
//This function has 4 parameters to make it work with express-jwt@6
|
||||
//but it also supports express-jwt@7 which only has 2.
|
||||
if (arguments.length === 4) {
|
||||
expressJwt7Provider(req, { header })
|
||||
.then(key => {
|
||||
setImmediate(cb, null, key);
|
||||
}).catch(err => {
|
||||
setImmediate(cb, err);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return expressJwt7Provider(req, arguments[1]);
|
||||
};
|
||||
};
|
||||
59
functions/node_modules/jwks-rsa/src/integrations/hapi.js
generated
vendored
Normal file
59
functions/node_modules/jwks-rsa/src/integrations/hapi.js
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
const { ArgumentError } = require('../errors');
|
||||
const { JwksClient } = require('../JwksClient');
|
||||
const supportedAlg = require('./config');
|
||||
|
||||
const handleSigningKeyError = (err, cb) => {
|
||||
// If we didn't find a match, can't provide a key.
|
||||
if (err && err.name === 'SigningKeyNotFoundError') {
|
||||
return cb(err, null, null);
|
||||
}
|
||||
|
||||
// If an error occured like rate limiting or HTTP issue, we'll bubble up the error.
|
||||
if (err) {
|
||||
return cb(err, null, null);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Call hapiJwt2Key as a Promise
|
||||
* @param {object} options
|
||||
* @returns {Promise}
|
||||
*/
|
||||
module.exports.hapiJwt2KeyAsync = (options) => {
|
||||
const secretProvider = module.exports.hapiJwt2Key(options);
|
||||
return function(decoded) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const cb = (err, key) => {
|
||||
(!key || err) ? reject(err) : resolve({ key });
|
||||
};
|
||||
secretProvider(decoded, cb);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.hapiJwt2Key = function (options) {
|
||||
if (options === null || options === undefined) {
|
||||
throw new ArgumentError('An options object must be provided when initializing hapiJwt2Key');
|
||||
}
|
||||
|
||||
const client = new JwksClient(options);
|
||||
const onError = options.handleSigningKeyError || handleSigningKeyError;
|
||||
|
||||
return function secretProvider(decoded, cb) {
|
||||
// We cannot find a signing certificate if there is no header (no kid).
|
||||
if (!decoded || !decoded.header) {
|
||||
return cb(new Error('Cannot find a signing certificate if there is no header'), null, null);
|
||||
}
|
||||
|
||||
if (!supportedAlg.includes(decoded.header.alg)) {
|
||||
return cb(new Error('Unsupported algorithm ' + decoded.header.alg + ' supplied.'), null, null);
|
||||
}
|
||||
|
||||
client.getSigningKey(decoded.header.kid)
|
||||
.then(key => {
|
||||
return cb(null, key.publicKey || key.rsaPublicKey, key);
|
||||
}).catch(err => {
|
||||
return onError(err, (newError) => cb(newError, null, null));
|
||||
});
|
||||
};
|
||||
};
|
||||
30
functions/node_modules/jwks-rsa/src/integrations/koa.js
generated
vendored
Normal file
30
functions/node_modules/jwks-rsa/src/integrations/koa.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
const { ArgumentError } = require('../errors');
|
||||
const { JwksClient } = require('../JwksClient');
|
||||
const supportedAlg = require('./config');
|
||||
|
||||
module.exports.koaJwtSecret = function (options = {}) {
|
||||
if (!options.jwksUri) {
|
||||
throw new ArgumentError('No JWKS provided. Please provide a jwksUri');
|
||||
}
|
||||
|
||||
const client = new JwksClient(options);
|
||||
|
||||
return function secretProvider({ alg, kid } = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!supportedAlg.includes(alg)) {
|
||||
return reject(new Error('Missing / invalid token algorithm'));
|
||||
}
|
||||
|
||||
client.getSigningKey(kid)
|
||||
.then(key => {
|
||||
resolve(key.publicKey || key.rsaPublicKey);
|
||||
}).catch(err => {
|
||||
if (options.handleSigningKeyError) {
|
||||
return options.handleSigningKeyError(err).then(reject);
|
||||
}
|
||||
|
||||
return reject(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
52
functions/node_modules/jwks-rsa/src/integrations/passport.js
generated
vendored
Normal file
52
functions/node_modules/jwks-rsa/src/integrations/passport.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
const jose = require('jose');
|
||||
const { ArgumentError } = require('../errors');
|
||||
const { JwksClient } = require('../JwksClient');
|
||||
const supportedAlg = require('./config');
|
||||
|
||||
const handleSigningKeyError = (err, cb) => {
|
||||
// If we didn't find a match, can't provide a key.
|
||||
if (err && err.name === 'SigningKeyNotFoundError') {
|
||||
return cb(null);
|
||||
}
|
||||
|
||||
// If an error occured like rate limiting or HTTP issue, we'll bubble up the error.
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.passportJwtSecret = function (options) {
|
||||
if (options === null || options === undefined) {
|
||||
throw new ArgumentError('An options object must be provided when initializing passportJwtSecret');
|
||||
}
|
||||
|
||||
if (!options.jwksUri) {
|
||||
throw new ArgumentError('No JWKS provided. Please provide a jwksUri');
|
||||
}
|
||||
|
||||
const client = new JwksClient(options);
|
||||
const onError = options.handleSigningKeyError || handleSigningKeyError;
|
||||
|
||||
return function secretProvider(req, rawJwtToken, cb) {
|
||||
let decoded;
|
||||
try {
|
||||
decoded = {
|
||||
payload: jose.decodeJwt(rawJwtToken),
|
||||
header: jose.decodeProtectedHeader(rawJwtToken)
|
||||
};
|
||||
} catch (err) {
|
||||
decoded = null;
|
||||
}
|
||||
|
||||
if (!decoded || !supportedAlg.includes(decoded.header.alg)) {
|
||||
return cb(null, null);
|
||||
}
|
||||
|
||||
client.getSigningKey(decoded.header.kid)
|
||||
.then(key => {
|
||||
cb(null, key.publicKey || key.rsaPublicKey);
|
||||
}).catch(err => {
|
||||
onError(err, (newError) => cb(newError, null));
|
||||
});
|
||||
};
|
||||
};
|
||||
80
functions/node_modules/jwks-rsa/src/utils.js
generated
vendored
Normal file
80
functions/node_modules/jwks-rsa/src/utils.js
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
const jose = require('jose');
|
||||
const JwksError = require('./errors/JwksError');
|
||||
|
||||
function resolveAlg(jwk) {
|
||||
if (jwk.alg) {
|
||||
return jwk.alg;
|
||||
}
|
||||
|
||||
if (jwk.kty === 'RSA') {
|
||||
return 'RS256';
|
||||
}
|
||||
|
||||
if (jwk.kty === 'EC') {
|
||||
switch (jwk.crv) {
|
||||
case 'P-256':
|
||||
return 'ES256';
|
||||
case 'secp256k1':
|
||||
return 'ES256K';
|
||||
case 'P-384':
|
||||
return 'ES384';
|
||||
case 'P-521':
|
||||
return 'ES512';
|
||||
}
|
||||
}
|
||||
|
||||
if (jwk.kty === 'OKP') {
|
||||
switch (jwk.crv) {
|
||||
case 'Ed25519':
|
||||
case 'Ed448':
|
||||
return 'EdDSA';
|
||||
}
|
||||
}
|
||||
|
||||
throw new JwksError('Unsupported JWK');
|
||||
}
|
||||
|
||||
async function retrieveSigningKeys(jwks) {
|
||||
const results = [];
|
||||
|
||||
jwks = jwks
|
||||
.filter(({ use }) => use === 'sig' || use === undefined)
|
||||
.filter(({ kty }) => kty === 'RSA' || kty === 'EC' || kty === 'OKP');
|
||||
|
||||
for (const jwk of jwks) {
|
||||
try {
|
||||
const key = await jose.importJWK({ ...jwk, ext: true }, resolveAlg(jwk));
|
||||
if (key.type !== 'public') {
|
||||
continue;
|
||||
}
|
||||
let getSpki;
|
||||
switch (key[Symbol.toStringTag]) {
|
||||
case 'CryptoKey': {
|
||||
const spki = await jose.exportSPKI(key);
|
||||
getSpki = () => spki;
|
||||
break;
|
||||
}
|
||||
case 'KeyObject':
|
||||
// Assume legacy Node.js version without the Symbol.toStringTag backported
|
||||
// Fall through
|
||||
default:
|
||||
getSpki = () => key.export({ format: 'pem', type: 'spki' });
|
||||
}
|
||||
results.push({
|
||||
get publicKey() { return getSpki(); },
|
||||
get rsaPublicKey() { return getSpki(); },
|
||||
getPublicKey() { return getSpki(); },
|
||||
...(typeof jwk.kid === 'string' && jwk.kid ? { kid: jwk.kid } : undefined),
|
||||
...(typeof jwk.alg === 'string' && jwk.alg ? { alg: jwk.alg } : undefined)
|
||||
});
|
||||
} catch (err) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
retrieveSigningKeys
|
||||
};
|
||||
15
functions/node_modules/jwks-rsa/src/wrappers/cache.js
generated
vendored
Normal file
15
functions/node_modules/jwks-rsa/src/wrappers/cache.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
const logger = require('debug')('jwks');
|
||||
const memoizer = require('lru-memoizer');
|
||||
const { promisify, callbackify } = require('util');
|
||||
|
||||
function cacheWrapper(client, { cacheMaxEntries = 5, cacheMaxAge = 600000 }) {
|
||||
logger(`Configured caching of signing keys. Max: ${cacheMaxEntries} / Age: ${cacheMaxAge}`);
|
||||
return promisify(memoizer({
|
||||
hash: (kid) => kid,
|
||||
load: callbackify(client.getSigningKey.bind(client)),
|
||||
maxAge: cacheMaxAge,
|
||||
max: cacheMaxEntries
|
||||
}));
|
||||
}
|
||||
|
||||
module.exports.default = cacheWrapper;
|
||||
16
functions/node_modules/jwks-rsa/src/wrappers/callbackSupport.js
generated
vendored
Normal file
16
functions/node_modules/jwks-rsa/src/wrappers/callbackSupport.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
const { callbackify } = require('util');
|
||||
|
||||
const callbackSupport = (client) => {
|
||||
const getSigningKey = client.getSigningKey.bind(client);
|
||||
|
||||
return (kid, cb) => {
|
||||
if (cb) {
|
||||
const callbackFunc = callbackify(getSigningKey);
|
||||
return callbackFunc(kid, cb);
|
||||
}
|
||||
|
||||
return getSigningKey(kid);
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.default = callbackSupport;
|
||||
7
functions/node_modules/jwks-rsa/src/wrappers/index.js
generated
vendored
Normal file
7
functions/node_modules/jwks-rsa/src/wrappers/index.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
request: require('./request').default,
|
||||
cacheSigningKey: require('./cache').default,
|
||||
rateLimitSigningKey: require('./rateLimit').default,
|
||||
getKeysInterceptor: require('./interceptor').default,
|
||||
callbackSupport: require('./callbackSupport').default
|
||||
};
|
||||
30
functions/node_modules/jwks-rsa/src/wrappers/interceptor.js
generated
vendored
Normal file
30
functions/node_modules/jwks-rsa/src/wrappers/interceptor.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
const retrieveSigningKeys = require('../utils').retrieveSigningKeys;
|
||||
|
||||
/**
|
||||
* Uses getKeysInterceptor to allow users to retrieve keys from a file,
|
||||
* external cache, or provided object before falling back to the jwksUri endpoint
|
||||
*/
|
||||
function getKeysInterceptor(client, { getKeysInterceptor }) {
|
||||
const getSigningKey = client.getSigningKey.bind(client);
|
||||
|
||||
return async (kid) => {
|
||||
const keys = await getKeysInterceptor();
|
||||
|
||||
let signingKeys;
|
||||
if (keys && keys.length) {
|
||||
signingKeys = await retrieveSigningKeys(keys);
|
||||
}
|
||||
|
||||
if (signingKeys && signingKeys.length) {
|
||||
const key = signingKeys.find(k => !kid || k.kid === kid);
|
||||
|
||||
if (key) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return getSigningKey(kid);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports.default = getKeysInterceptor;
|
||||
34
functions/node_modules/jwks-rsa/src/wrappers/rateLimit.js
generated
vendored
Normal file
34
functions/node_modules/jwks-rsa/src/wrappers/rateLimit.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
const logger = require('debug')('jwks');
|
||||
const { RateLimiter } = require('limiter');
|
||||
|
||||
const JwksRateLimitError = require('../errors/JwksRateLimitError');
|
||||
|
||||
function rateLimitWrapper(client, { jwksRequestsPerMinute = 10 }) {
|
||||
const getSigningKey = client.getSigningKey.bind(client);
|
||||
|
||||
const limiter = new RateLimiter(jwksRequestsPerMinute, 'minute', true);
|
||||
logger(`Configured rate limiting to JWKS endpoint at ${jwksRequestsPerMinute}/minute`);
|
||||
|
||||
return async (kid) => await new Promise((resolve, reject) => {
|
||||
limiter.removeTokens(1, async (err, remaining) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
logger('Requests to the JWKS endpoint available for the next minute:', remaining);
|
||||
if (remaining < 0) {
|
||||
logger('Too many requests to the JWKS endpoint');
|
||||
reject(new JwksRateLimitError('Too many requests to the JWKS endpoint'));
|
||||
} else {
|
||||
try {
|
||||
const key = await getSigningKey(kid);
|
||||
resolve(key);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.default = rateLimitWrapper;
|
||||
54
functions/node_modules/jwks-rsa/src/wrappers/request.js
generated
vendored
Normal file
54
functions/node_modules/jwks-rsa/src/wrappers/request.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
const http = require('http');
|
||||
const https = require('https');
|
||||
const ArgumentError = require('../errors/ArgumentError');
|
||||
|
||||
module.exports.default = (options) => {
|
||||
if (options.fetcher) {
|
||||
return options.fetcher(options.uri);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let url;
|
||||
try {
|
||||
url = new URL(options.uri);
|
||||
} catch (err) {
|
||||
throw new ArgumentError('Invalid JWKS URI: The provided URI is not a valid URL.');
|
||||
}
|
||||
const { hostname, port, protocol, pathname, search } = url;
|
||||
const path = pathname + search;
|
||||
|
||||
const requestOptions = {
|
||||
hostname,
|
||||
path,
|
||||
port,
|
||||
method: 'GET',
|
||||
...(options.headers && { headers: { ...options.headers } }),
|
||||
...(options.timeout && { timeout: options.timeout }),
|
||||
...(options.agent && { agent: options.agent })
|
||||
};
|
||||
|
||||
const httpRequestLib = protocol === 'https:' ? https : http;
|
||||
const httpRequest = httpRequestLib.request(requestOptions, (res) => {
|
||||
let rawData = '';
|
||||
res.setEncoding('utf8');
|
||||
res.on('data', (chunk) => { rawData += chunk; });
|
||||
res.on('end', () => {
|
||||
if (res.statusCode < 200 || res.statusCode >= 300) {
|
||||
const errorMsg = res.body && (res.body.message || res.body) || res.statusMessage || `Http Error ${res.statusCode}`;
|
||||
reject({ errorMsg });
|
||||
} else {
|
||||
try {
|
||||
resolve(rawData && JSON.parse(rawData));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
httpRequest
|
||||
.on('timeout', () => httpRequest.destroy())
|
||||
.on('error', (e) => reject(e))
|
||||
.end();
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user