local.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.createLocalJWKSet = exports.LocalJWKSet = exports.isJWKSLike = void 0;
  4. const import_js_1 = require("../key/import.js");
  5. const errors_js_1 = require("../util/errors.js");
  6. const is_object_js_1 = require("../lib/is_object.js");
  7. function getKtyFromAlg(alg) {
  8. switch (typeof alg === 'string' && alg.slice(0, 2)) {
  9. case 'RS':
  10. case 'PS':
  11. return 'RSA';
  12. case 'ES':
  13. return 'EC';
  14. case 'Ed':
  15. return 'OKP';
  16. default:
  17. throw new errors_js_1.JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
  18. }
  19. }
  20. function isJWKSLike(jwks) {
  21. return (jwks &&
  22. typeof jwks === 'object' &&
  23. Array.isArray(jwks.keys) &&
  24. jwks.keys.every(isJWKLike));
  25. }
  26. exports.isJWKSLike = isJWKSLike;
  27. function isJWKLike(key) {
  28. return (0, is_object_js_1.default)(key);
  29. }
  30. function clone(obj) {
  31. if (typeof structuredClone === 'function') {
  32. return structuredClone(obj);
  33. }
  34. return JSON.parse(JSON.stringify(obj));
  35. }
  36. class LocalJWKSet {
  37. constructor(jwks) {
  38. this._cached = new WeakMap();
  39. if (!isJWKSLike(jwks)) {
  40. throw new errors_js_1.JWKSInvalid('JSON Web Key Set malformed');
  41. }
  42. this._jwks = clone(jwks);
  43. }
  44. async getKey(protectedHeader, token) {
  45. const { alg, kid } = { ...protectedHeader, ...token === null || token === void 0 ? void 0 : token.header };
  46. const kty = getKtyFromAlg(alg);
  47. const candidates = this._jwks.keys.filter((jwk) => {
  48. let candidate = kty === jwk.kty;
  49. if (candidate && typeof kid === 'string') {
  50. candidate = kid === jwk.kid;
  51. }
  52. if (candidate && typeof jwk.alg === 'string') {
  53. candidate = alg === jwk.alg;
  54. }
  55. if (candidate && typeof jwk.use === 'string') {
  56. candidate = jwk.use === 'sig';
  57. }
  58. if (candidate && Array.isArray(jwk.key_ops)) {
  59. candidate = jwk.key_ops.includes('verify');
  60. }
  61. if (candidate && alg === 'EdDSA') {
  62. candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
  63. }
  64. if (candidate) {
  65. switch (alg) {
  66. case 'ES256':
  67. candidate = jwk.crv === 'P-256';
  68. break;
  69. case 'ES256K':
  70. candidate = jwk.crv === 'secp256k1';
  71. break;
  72. case 'ES384':
  73. candidate = jwk.crv === 'P-384';
  74. break;
  75. case 'ES512':
  76. candidate = jwk.crv === 'P-521';
  77. break;
  78. }
  79. }
  80. return candidate;
  81. });
  82. const { 0: jwk, length } = candidates;
  83. if (length === 0) {
  84. throw new errors_js_1.JWKSNoMatchingKey();
  85. }
  86. else if (length !== 1) {
  87. const error = new errors_js_1.JWKSMultipleMatchingKeys();
  88. const { _cached } = this;
  89. error[Symbol.asyncIterator] = async function* () {
  90. for (const jwk of candidates) {
  91. try {
  92. yield await importWithAlgCache(_cached, jwk, alg);
  93. }
  94. catch {
  95. continue;
  96. }
  97. }
  98. };
  99. throw error;
  100. }
  101. return importWithAlgCache(this._cached, jwk, alg);
  102. }
  103. }
  104. exports.LocalJWKSet = LocalJWKSet;
  105. async function importWithAlgCache(cache, jwk, alg) {
  106. const cached = cache.get(jwk) || cache.set(jwk, {}).get(jwk);
  107. if (cached[alg] === undefined) {
  108. const key = await (0, import_js_1.importJWK)({ ...jwk, ext: true }, alg);
  109. if (key instanceof Uint8Array || key.type !== 'public') {
  110. throw new errors_js_1.JWKSInvalid('JSON Web Key Set members must be public keys');
  111. }
  112. cached[alg] = key;
  113. }
  114. return cached[alg];
  115. }
  116. function createLocalJWKSet(jwks) {
  117. const set = new LocalJWKSet(jwks);
  118. return async function (protectedHeader, token) {
  119. return set.getKey(protectedHeader, token);
  120. };
  121. }
  122. exports.createLocalJWKSet = createLocalJWKSet;