remote.js 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.createRemoteJWKSet = void 0;
  4. const fetch_jwks_js_1 = require("../runtime/fetch_jwks.js");
  5. const errors_js_1 = require("../util/errors.js");
  6. const local_js_1 = require("./local.js");
  7. function isCloudflareWorkers() {
  8. return (typeof WebSocketPair !== 'undefined' ||
  9. (typeof navigator !== 'undefined' && navigator.userAgent === 'Cloudflare-Workers') ||
  10. (typeof EdgeRuntime !== 'undefined' && EdgeRuntime === 'vercel'));
  11. }
  12. class RemoteJWKSet extends local_js_1.LocalJWKSet {
  13. constructor(url, options) {
  14. super({ keys: [] });
  15. this._jwks = undefined;
  16. if (!(url instanceof URL)) {
  17. throw new TypeError('url must be an instance of URL');
  18. }
  19. this._url = new URL(url.href);
  20. this._options = { agent: options === null || options === void 0 ? void 0 : options.agent, headers: options === null || options === void 0 ? void 0 : options.headers };
  21. this._timeoutDuration =
  22. typeof (options === null || options === void 0 ? void 0 : options.timeoutDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.timeoutDuration : 5000;
  23. this._cooldownDuration =
  24. typeof (options === null || options === void 0 ? void 0 : options.cooldownDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.cooldownDuration : 30000;
  25. this._cacheMaxAge = typeof (options === null || options === void 0 ? void 0 : options.cacheMaxAge) === 'number' ? options === null || options === void 0 ? void 0 : options.cacheMaxAge : 600000;
  26. }
  27. coolingDown() {
  28. return typeof this._jwksTimestamp === 'number'
  29. ? Date.now() < this._jwksTimestamp + this._cooldownDuration
  30. : false;
  31. }
  32. fresh() {
  33. return typeof this._jwksTimestamp === 'number'
  34. ? Date.now() < this._jwksTimestamp + this._cacheMaxAge
  35. : false;
  36. }
  37. async getKey(protectedHeader, token) {
  38. if (!this._jwks || !this.fresh()) {
  39. await this.reload();
  40. }
  41. try {
  42. return await super.getKey(protectedHeader, token);
  43. }
  44. catch (err) {
  45. if (err instanceof errors_js_1.JWKSNoMatchingKey) {
  46. if (this.coolingDown() === false) {
  47. await this.reload();
  48. return super.getKey(protectedHeader, token);
  49. }
  50. }
  51. throw err;
  52. }
  53. }
  54. async reload() {
  55. if (this._pendingFetch && isCloudflareWorkers()) {
  56. this._pendingFetch = undefined;
  57. }
  58. this._pendingFetch || (this._pendingFetch = (0, fetch_jwks_js_1.default)(this._url, this._timeoutDuration, this._options)
  59. .then((json) => {
  60. if (!(0, local_js_1.isJWKSLike)(json)) {
  61. throw new errors_js_1.JWKSInvalid('JSON Web Key Set malformed');
  62. }
  63. this._jwks = { keys: json.keys };
  64. this._jwksTimestamp = Date.now();
  65. this._pendingFetch = undefined;
  66. })
  67. .catch((err) => {
  68. this._pendingFetch = undefined;
  69. throw err;
  70. }));
  71. await this._pendingFetch;
  72. }
  73. }
  74. function createRemoteJWKSet(url, options) {
  75. const set = new RemoteJWKSet(url, options);
  76. return async function (protectedHeader, token) {
  77. return set.getKey(protectedHeader, token);
  78. };
  79. }
  80. exports.createRemoteJWKSet = createRemoteJWKSet;