@deslop/auth 0.1.1250 → 0.1.1256

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -6919,7 +6919,7 @@ const keys$1 = (self) => Object.keys(self);
6919
6919
  * @category mutations
6920
6920
  * @since 2.0.0
6921
6921
  */
6922
- const set$6 = /*#__PURE__*/ dual(3, (self, key, value) => {
6922
+ const set$7 = /*#__PURE__*/ dual(3, (self, key, value) => {
6923
6923
  return {
6924
6924
  ...self,
6925
6925
  [key]: value
@@ -16429,7 +16429,7 @@ const make$79 = (...entries) => fromIterable$2(entries);
16429
16429
  */
16430
16430
  const fromIterable$2 = (entries) => {
16431
16431
  const self = empty$10();
16432
- for (const [key, value] of entries) set$5(self, key, value);
16432
+ for (const [key, value] of entries) set$6(self, key, value);
16433
16433
  return self;
16434
16434
  };
16435
16435
  /**
@@ -16521,7 +16521,7 @@ const getFromBucket = (self, bucket, key) => {
16521
16521
  * @category mutations
16522
16522
  * @since 2.0.0
16523
16523
  */
16524
- const set$5 = /*#__PURE__*/ dual(3, (self, key, value) => {
16524
+ const set$6 = /*#__PURE__*/ dual(3, (self, key, value) => {
16525
16525
  if (self.backing.has(key) || isSimpleKey(key)) {
16526
16526
  self.backing.set(key, value);
16527
16527
  return self;
@@ -23909,7 +23909,7 @@ const make$75 = (value) => {
23909
23909
  * @category mutations
23910
23910
  * @since 2.0.0
23911
23911
  */
23912
- const set$4 = /*#__PURE__*/ dual(2, (self, value) => {
23912
+ const set$5 = /*#__PURE__*/ dual(2, (self, value) => {
23913
23913
  self.current = value;
23914
23914
  return self;
23915
23915
  });
@@ -24481,7 +24481,7 @@ const makeAtomicUnbounded = (options) => {
24481
24481
  * @since 2.0.0
24482
24482
  */
24483
24483
  const shutdown$1 = (self) => uninterruptible(withFiber((fiber) => {
24484
- set$4(self.shutdownFlag, true);
24484
+ set$5(self.shutdownFlag, true);
24485
24485
  return close(self.scope, interrupt$2(fiber.id)).pipe(andThen(self.strategy.shutdown), when$2(self.shutdownHook.open), asVoid);
24486
24486
  }));
24487
24487
  /**
@@ -24637,7 +24637,7 @@ const subscribe = (self) => uninterruptible(contextWith((services) => {
24637
24637
  return addFinalizer$1(scope, unsubscribe(subscription)).pipe(andThen(addFinalizerExit(localScope, (exit) => close(scope, exit))), as(subscription));
24638
24638
  }));
24639
24639
  const unsubscribe = (self) => uninterruptible(withFiber((state) => {
24640
- set$4(self.shutdownFlag, true);
24640
+ set$5(self.shutdownFlag, true);
24641
24641
  return forEach$1(takeAll$2(self.pollers), (d) => interruptWith(d, state.id), {
24642
24642
  discard: true,
24643
24643
  concurrency: "unbounded"
@@ -28735,7 +28735,7 @@ const get$10 = /*#__PURE__*/ dual(2, (self, key) => uninterruptibleMask((restore
28735
28735
  refCount: 1
28736
28736
  };
28737
28737
  entry.finalizer = release$1(self, key, entry);
28738
- set$5(state.map, key, entry);
28738
+ set$6(state.map, key, entry);
28739
28739
  const context = new Map(self.context.mapUnsafe);
28740
28740
  parent.context.mapUnsafe.forEach((value, key) => {
28741
28741
  context.set(key, value);
@@ -37729,6 +37729,42 @@ const make$58 = (value) => sync(() => makeUnsafe$2(value));
37729
37729
  */
37730
37730
  const get$7 = (self) => sync(() => self.ref.current);
37731
37731
  /**
37732
+ * Sets the value of the Ref to the specified value.
37733
+ *
37734
+ * **When to use**
37735
+ *
37736
+ * Use to replace the current `Ref` value with a known value.
37737
+ *
37738
+ * **Example** (Setting a value)
37739
+ *
37740
+ * ```ts import.meta.vitest
37741
+ * import { Effect, Ref } from "effect"
37742
+ *
37743
+ * const program = Effect.gen(function*() {
37744
+ * const ref = yield* Ref.make(0)
37745
+ * yield* Ref.set(ref, 42)
37746
+ * return yield* Ref.get(ref)
37747
+ * })
37748
+ *
37749
+ * const program2 = Effect.gen(function*() {
37750
+ * const ref = yield* Ref.make(0)
37751
+ * yield* Ref.set(ref, 100)
37752
+ * return yield* Ref.get(ref)
37753
+ * })
37754
+ *
37755
+ * await Effect.runPromise(program) // => 42
37756
+ * await Effect.runPromise(program2) // => 100
37757
+ * ```
37758
+ *
37759
+ * @see {@link getAndSet} for setting while returning the previous value
37760
+ * @see {@link setAndGet} for setting while returning the new value
37761
+ *
37762
+ * @stability stable
37763
+ * @category mutations
37764
+ * @since 2.0.0
37765
+ */
37766
+ const set$4 = /*#__PURE__*/ dual(2, (self, value) => sync(() => set$5(self.ref, value)));
37767
+ /**
37732
37768
  * Modifies the value of the Ref atomically using the given function.
37733
37769
  *
37734
37770
  * **When to use**
@@ -38143,7 +38179,7 @@ const makeCookieUnsafe = (name, value, options) => getOrThrow(makeCookie(name, v
38143
38179
  * @category combinators
38144
38180
  * @since 4.0.0
38145
38181
  */
38146
- const setUnsafe$1 = /*#__PURE__*/ dual((args) => isCookies(args[0]), (self, name, value, options) => fromReadonlyRecord(set$6(self.cookies, name, makeCookieUnsafe(name, value, options))));
38182
+ const setUnsafe$1 = /*#__PURE__*/ dual((args) => isCookies(args[0]), (self, name, value, options) => fromReadonlyRecord(set$7(self.cookies, name, makeCookieUnsafe(name, value, options))));
38147
38183
  /**
38148
38184
  * Adds an expired cookie to a Cookies object, throwing an error if invalid
38149
38185
  *
@@ -47658,6 +47694,25 @@ function Redacted$1(value, options) {
47658
47694
  });
47659
47695
  return make$51(schema.ast, { value });
47660
47696
  }
47697
+ /**
47698
+ * Decodes a value and wraps it in `Redacted<A>`. Unlike {@link Redacted} which
47699
+ * expects the input to already be a `Redacted` instance, this schema decodes
47700
+ * the raw value and wraps it.
47701
+ *
47702
+ * @see {@link Redacted} for schemas whose input is already a `Redacted` value.
47703
+ * @stability stable
47704
+ * @category schemas
47705
+ * @since 4.0.0
47706
+ */
47707
+ function RedactedFromValue(value, options) {
47708
+ return decodeTo(Redacted$1(toType(value), {
47709
+ label: options?.label,
47710
+ disallowJsonEncode: options?.disallowEncode
47711
+ }), {
47712
+ decode: transform$3((t) => make$61(t, { label: options?.label })),
47713
+ encode: options?.disallowEncode ? forbidden((oe) => "Cannot encode Redacted" + (isSome(oe) && typeof oe.value.label === "string" ? ` with label: "${oe.value.label}"` : "")) : transform$3(value$2)
47714
+ })(value);
47715
+ }
47661
47716
  const immerable = /*#__PURE__*/ globalThis.Symbol.for("immer-draftable");
47662
47717
  const payloadToken = {};
47663
47718
  function makeClass(Inherited, identifier, struct$1, annotations, proto) {
@@ -49007,6 +49062,14 @@ const compressBody = /*#__PURE__*/ dual((args) => isHttpClientRequest(args[0]),
49007
49062
  return map$5(compressBody$1(self.body, algorithm, options), (body) => body === self.body ? self : makeWith$2(self.method, self.url, self.urlParams, self.hash, set$3(updateContentLength(self.headers, body), "content-encoding", algorithm), body));
49008
49063
  });
49009
49064
  /**
49065
+ * Encodes a value as a JSON request body and sets it on the request, failing with `HttpBodyError` if encoding fails.
49066
+ *
49067
+ * @stability unstable
49068
+ * @category combinators
49069
+ * @since 4.0.0
49070
+ */
49071
+ const bodyJson = /*#__PURE__*/ dual(2, (self, body) => map$5(json$1(body), (body) => setBody$1(self, body)));
49072
+ /**
49010
49073
  * Sets a JSON request body using unsafe JSON encoding.
49011
49074
  *
49012
49075
  * **When to use**
@@ -49580,6 +49643,14 @@ const endSpanWithStatusError = (fiber, span, request, response) => {
49580
49643
  span.end(fiber.getRef(TracerTimingEnabled) ? fiber.getRef(Clock).currentTimeNanosUnsafe() : BigInt(0), exit);
49581
49644
  };
49582
49645
  /**
49646
+ * Appends an effectful transformation of the request object before sending it.
49647
+ *
49648
+ * @stability unstable
49649
+ * @category mapping
49650
+ * @since 4.0.0
49651
+ */
49652
+ const mapRequestEffect = /*#__PURE__*/ dual(2, (self, f) => makeWith$1(self.postprocess, (request) => flatMap$2(self.preprocess(request), f)));
49653
+ /**
49583
49654
  * Retries common transient errors, such as rate limiting, timeouts or network issues.
49584
49655
  *
49585
49656
  * **When to use**
@@ -68684,7 +68755,7 @@ const get$2 = /*#__PURE__*/ dual(2, (self, key) => withFiber$1((fiber) => {
68684
68755
  if (isSome(oentry)) {
68685
68756
  remove$5(self.map, key);
68686
68757
  if (!hasExpired(oentry.value, fiber)) {
68687
- set$5(self.map, key, oentry.value);
68758
+ set$6(self.map, key, oentry.value);
68688
68759
  return oentry.value.await(fiber);
68689
68760
  }
68690
68761
  }
@@ -68704,7 +68775,7 @@ const get$2 = /*#__PURE__*/ dual(2, (self, key) => withFiber$1((fiber) => {
68704
68775
  } else if (isFinite$1(ttl)) entry.expiresAt = fiber.getRef(ClockRef).currentTimeMillisUnsafe() + toMillis(ttl);
68705
68776
  });
68706
68777
  const exit = entry.fiber.pollUnsafe();
68707
- if (!skipCache && (exit === void 0 || !exitHasInterrupts(exit))) set$5(self.map, key, entry);
68778
+ if (!skipCache && (exit === void 0 || !exitHasInterrupts(exit))) set$6(self.map, key, entry);
68708
68779
  if (Number.isFinite(self.capacity)) checkCapacity(self);
68709
68780
  return entry.await(fiber);
68710
68781
  }));
@@ -68869,7 +68940,7 @@ const set = /*#__PURE__*/ dual(3, (self, key, value) => withFiber$1((fiber) => {
68869
68940
  return void_$3;
68870
68941
  }
68871
68942
  entry.expiresAt = isFinite$1(ttl) ? fiber.getRef(ClockRef).currentTimeMillisUnsafe() + toMillis(ttl) : void 0;
68872
- set$5(self.map, key, entry);
68943
+ set$6(self.map, key, entry);
68873
68944
  checkCapacity(self);
68874
68945
  return void_$3;
68875
68946
  }));
@@ -89440,6 +89511,71 @@ function failureOptions(error, status) {
89440
89511
  }
89441
89512
  var CurrentUser = class extends Service$1()("@deslop/runtime/auth/lib/utils/CurrentUser") {};
89442
89513
  var RpcAuth = class extends Service()("@deslop/runtime/auth/lib/utils/RpcAuth", { error: AuthError }) {};
89514
+ Literals([
89515
+ "anthropic",
89516
+ "openrouter",
89517
+ "opencode-zen",
89518
+ "opencode-go"
89519
+ ]);
89520
+ // ../../packages/runtime/src/ai/service.ts
89521
+ var AiUnavailable = class extends TaggedError()("AiUnavailable", { message: String$6 }) {};
89522
+ fromJsonString(Struct({ error: Struct({ message: String$6 }) }));
89523
+ var AiGateway = class AiGateway extends Service$1()("@deslop/runtime/ai/service/AiGateway") {
89524
+ static layer = effect(this, gen(function* () {
89525
+ const gateway = yield* option(String$5("GATEWAY_URL"));
89526
+ const local = yield* localAuth;
89527
+ const app = yield* String$5("APP_URL");
89528
+ const client = yield* HttpClient;
89529
+ const store = toSchemaStore(yield* KeyValueStore, Record$1(String$6, RedactedFromValue(String$6)));
89530
+ const grants = yield* make$58(getOrElse(yield* store.get("ai-gateway-grants"), () => ({})));
89531
+ const lock = yield* make$71(1);
89532
+ return AiGateway.of({
89533
+ apiUrl: (provider) => match$8(gateway, {
89534
+ onNone: () => fail$7(AiUnavailable.make({ message: "Start the app with --gateway" })),
89535
+ onSome: (url) => succeed$5(`${url}/ai/${provider}${match$1(provider === "openrouter", {
89536
+ onFalse: () => "",
89537
+ onTrue: () => "/v1"
89538
+ })}`)
89539
+ }),
89540
+ authorize: (userId) => (http) => pipe(mapRequestEffect(http, (request) => gen(function* () {
89541
+ if (local) return request;
89542
+ const token = (yield* get$7(grants))[userId];
89543
+ if (token === void 0) return yield* new HttpClientError({ reason: new TransportError({
89544
+ description: "AI access is unavailable; sign in again to enroll with Gateway",
89545
+ request
89546
+ }) });
89547
+ return setHeader$1(request, "authorization", `Bearer ${value$2(token)}`);
89548
+ })), tap((response) => pipe(gen(function* () {
89549
+ if (local || response.headers["x-gateway-grant-refused"] === void 0 || !exists(gateway, (url) => startsWith(`${url}/ai/`)(response.request.url))) return;
89550
+ const current = yield* get$7(grants);
89551
+ const token = current[userId];
89552
+ if (token === void 0 || response.request.headers["authorization"] !== `Bearer ${value$2(token)}`) return;
89553
+ const next = remove$6(current, userId);
89554
+ yield* pipe(store.set("ai-gateway-grants", next), ignore$1({
89555
+ log: "Warn",
89556
+ message: "The rejected AI grant could not be removed from storage"
89557
+ }));
89558
+ yield* set$4(grants, next);
89559
+ }), withPermit(lock)))),
89560
+ enroll: fnUntraced(function* (userId, headers) {
89561
+ return yield* pipe(gen(function* () {
89562
+ if (local || isNone(gateway) || (yield* get$7(grants))[userId] !== void 0) return;
89563
+ const response = yield* client.execute(yield* bodyJson(post(`${getOrElse(gateway, () => "")}/ai/grants`, { headers: match$1(headers["authorization"] !== void 0, {
89564
+ onFalse: () => ({ cookie: headers["cookie"] ?? "" }),
89565
+ onTrue: () => ({ authorization: headers["authorization"] })
89566
+ }) }), { app }));
89567
+ const result = yield* schemaBodyJson$1(Struct({ token: String$6 }))(response);
89568
+ const next = {
89569
+ ...yield* get$7(grants),
89570
+ [userId]: make$61(result.token)
89571
+ };
89572
+ yield* store.set("ai-gateway-grants", next);
89573
+ yield* set$4(grants, next);
89574
+ }), withPermit(lock), timeout$1("10 seconds"), catch_$2(() => logWarning("AI Gateway enrollment failed")));
89575
+ })
89576
+ });
89577
+ }));
89578
+ };
89443
89579
  // ../../packages/runtime/src/auth/service.ts
89444
89580
  function rejected(message) {
89445
89581
  return mapError$2((cause) => {
@@ -89458,12 +89594,18 @@ function rejected(message) {
89458
89594
  function developer() {
89459
89595
  return succeed$5(DEVELOPER);
89460
89596
  }
89597
+ function enrolled(user, headers) {
89598
+ return gen(function* () {
89599
+ const gateway = getOrUndefined(yield* context(), AiGateway);
89600
+ if (gateway !== void 0) yield* gateway.enroll(user.id, headers);
89601
+ });
89602
+ }
89461
89603
  const unavailable = text("The authorization service is temporarily unavailable; retry later", {
89462
89604
  headers: { "retry-after": "5" },
89463
89605
  status: 503
89464
89606
  });
89465
89607
  var Auth = class Auth extends Service$1()("@deslop/runtime/auth/service/Auth") {
89466
- static makeContext = (auth) => pipe(make$85(Auth, auth), add$1(RpcAuth, RpcAuth.of((effect, request) => pipe(auth.user(request.headers), tap$1(() => {
89608
+ static makeContext = (auth) => pipe(make$85(Auth, auth), add$1(RpcAuth, RpcAuth.of((effect, request) => pipe(auth.user(request.headers), tap$1((user) => enrolled(user, request.headers)), tap$1(() => {
89467
89609
  if (isStreamSchema(request.rpc.successSchema)) return annotateCurrentSpan("rpc.stream", true);
89468
89610
  return void_$1;
89469
89611
  }), flatMap$2((user) => raceFirst(provideService(effect, CurrentUser, user), pipe(delay(auth.user(request.headers), "5 minutes"), retry({ while: (error) => error.error === "temporarily_unavailable" }), forever)))))));
@@ -89498,6 +89640,7 @@ middleware$1()(gen(function* () {
89498
89640
  if (user.failure.error === "temporarily_unavailable") return unavailable;
89499
89641
  return text("Sign in first", { status: 401 });
89500
89642
  }
89643
+ yield* enrolled(user.success, (yield* HttpServerRequest).headers);
89501
89644
  return yield* provideService(app, CurrentUser, user.success);
89502
89645
  });
89503
89646
  }));
@@ -89520,6 +89663,7 @@ function layerMcpAuth(resource) {
89520
89663
  status: 401
89521
89664
  });
89522
89665
  }
89666
+ yield* enrolled(user.success, headers);
89523
89667
  return yield* provideService(app, CurrentUser, user.success);
89524
89668
  });
89525
89669
  })).layer;
@@ -89910,6 +90054,11 @@ const SETTINGS = {
89910
90054
  flag: "auth",
89911
90055
  schema: SecureOrigin
89912
90056
  },
90057
+ GATEWAY_URL: {
90058
+ description: "Deslop Gateway origin for AI calls",
90059
+ flag: "gateway",
90060
+ schema: Origin$1
90061
+ },
89913
90062
  HOST: {
89914
90063
  description: `Listen address; defaults to ${DEFAULT_HOST}`,
89915
90064
  flag: "host",
@@ -89945,7 +90094,7 @@ function server(app) {
89945
90094
  return pipe(serve(pipe(mergeAll$1(app.routes, layerRoutes, layerIcon(app.icon), layerWeb, layerAnnounce), provide$2(match$8(fromUndefinedOr(app.middleware), {
89946
90095
  onNone: () => empty$11,
89947
90096
  onSome: (middleware) => middleware$1()(middleware).layer
89948
- })), provide$2(Auth.layer)), {
90097
+ })), provide$2(Auth.layer), provideMerge(pipe(AiGateway.layer, provide$2(layerDataStore)))), {
89949
90098
  disableLogger: true,
89950
90099
  middleware: guard
89951
90100
  }), provide$2(mergeAll$1(layerProtocol, match$1(app.telemetry === false, {
@@ -90536,7 +90685,7 @@ base64.validate = (encoded, urlMode) => {
90536
90685
  }
90537
90686
  };
90538
90687
  base64.base64 = base64;
90539
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoBase64URL.js
90688
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoBase64URL.js
90540
90689
  /**
90541
90690
  * A runtime-agnostic collection of methods for working with Base64URL encoding
90542
90691
  * @module
@@ -90946,7 +91095,7 @@ function encodeCBOR(data) {
90946
91095
  }
90947
91096
  return output;
90948
91097
  }
90949
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCBOR.js
91098
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCBOR.js
90950
91099
  /**
90951
91100
  * A runtime-agnostic collection of methods for working with CBOR encoding
90952
91101
  * @module
@@ -90978,7 +91127,7 @@ function decodeFirst(input) {
90978
91127
  function encode(input) {
90979
91128
  return encodeCBOR(input);
90980
91129
  }
90981
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/cose.js
91130
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/cose.js
90982
91131
  /**
90983
91132
  * A type guard for determining if a COSE public key is an OKP key pair
90984
91133
  */
@@ -91088,7 +91237,7 @@ function isPQCCOSEAlg(alg) {
91088
91237
  COSEALG.ML_DSA_87
91089
91238
  ].indexOf(alg) >= 0;
91090
91239
  }
91091
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoHashAlgName.js
91240
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoHashAlgName.js
91092
91241
  /**
91093
91242
  * Convert a COSE alg ID into a corresponding hash algorithm string value that WebCrypto APIs expect
91094
91243
  *
@@ -91115,7 +91264,7 @@ function mapCoseAlgToWebCryptoHashAlgName(alg) {
91115
91264
  ].indexOf(alg) >= 0) return "SHA-512";
91116
91265
  throw new Error(`Could not map COSE alg value of ${alg} to a WebCrypto hash alg name`);
91117
91266
  }
91118
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/getWebCrypto.js
91267
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/getWebCrypto.js
91119
91268
  let webCrypto = void 0;
91120
91269
  /**
91121
91270
  * Try to get an instance of the Crypto API from the current runtime. Should support Node,
@@ -91160,7 +91309,7 @@ const _getWebCryptoInternals = {
91160
91309
  webCrypto = newCrypto;
91161
91310
  }
91162
91311
  };
91163
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/digest.js
91312
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/digest.js
91164
91313
  /**
91165
91314
  * Generate a digest of the provided data.
91166
91315
  *
@@ -91173,7 +91322,7 @@ async function digest(data, algorithm) {
91173
91322
  const hashed = await WebCrypto.subtle.digest(subtleAlgorithm, data);
91174
91323
  return new Uint8Array(hashed);
91175
91324
  }
91176
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/getRandomValues.js
91325
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/getRandomValues.js
91177
91326
  /**
91178
91327
  * Fill up the provided bytes array with random bytes equal to its length.
91179
91328
  *
@@ -91183,7 +91332,7 @@ async function getRandomValues(array) {
91183
91332
  (await getWebCrypto()).getRandomValues(array);
91184
91333
  return array;
91185
91334
  }
91186
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/convertAAGUIDToString.js
91335
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/convertAAGUIDToString.js
91187
91336
  /**
91188
91337
  * Convert the aaguid buffer in authData into a UUID string
91189
91338
  */
@@ -91197,7 +91346,7 @@ function convertAAGUIDToString(aaguid) {
91197
91346
  hex.slice(20, 32)
91198
91347
  ].join("-");
91199
91348
  }
91200
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/convertCOSEtoPKCS.js
91349
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/convertCOSEtoPKCS.js
91201
91350
  /**
91202
91351
  * Takes COSE-encoded public key and converts it to PKCS key
91203
91352
  */
@@ -91214,7 +91363,7 @@ function convertCOSEtoPKCS(cosePublicKey) {
91214
91363
  ]);
91215
91364
  return concat([tag, x]);
91216
91365
  }
91217
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/decodeAttestationObject.js
91366
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/decodeAttestationObject.js
91218
91367
  /**
91219
91368
  * Convert an AttestationObject buffer to a proper object
91220
91369
  *
@@ -91228,7 +91377,7 @@ function decodeAttestationObject(attestationObject) {
91228
91377
  * @ignore Don't include this in docs output
91229
91378
  */
91230
91379
  const _decodeAttestationObjectInternals = { stubThis: (value) => value };
91231
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/decodeClientDataJSON.js
91380
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/decodeClientDataJSON.js
91232
91381
  /**
91233
91382
  * Decode an authenticator's base64url-encoded clientDataJSON to JSON
91234
91383
  */
@@ -91242,7 +91391,7 @@ function decodeClientDataJSON(data) {
91242
91391
  * @ignore Don't include this in docs output
91243
91392
  */
91244
91393
  const _decodeClientDataJSONInternals = { stubThis: (value) => value };
91245
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/decodeCredentialPublicKey.js
91394
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/decodeCredentialPublicKey.js
91246
91395
  function decodeCredentialPublicKey(publicKey) {
91247
91396
  return _decodeCredentialPublicKeyInternals.stubThis(decodeFirst(publicKey));
91248
91397
  }
@@ -91251,7 +91400,7 @@ function decodeCredentialPublicKey(publicKey) {
91251
91400
  * @ignore Don't include this in docs output
91252
91401
  */
91253
91402
  const _decodeCredentialPublicKeyInternals = { stubThis: (value) => value };
91254
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/generateChallenge.js
91403
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/generateChallenge.js
91255
91404
  /**
91256
91405
  * Generate a suitably random value to be used as an attestation or assertion challenge
91257
91406
  */
@@ -91273,7 +91422,7 @@ async function generateChallenge() {
91273
91422
  * @ignore Don't include this in docs output
91274
91423
  */
91275
91424
  const _generateChallengeInternals = { stubThis: (value) => value };
91276
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/generateUserID.js
91425
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/generateUserID.js
91277
91426
  /**
91278
91427
  * Generate a suitably random value to be used as user ID
91279
91428
  */
@@ -99678,7 +99827,7 @@ var require_cjs$12 = /* @__PURE__ */ __commonJSMin(((exports) => {
99678
99827
  tslib_1.__exportStar(require_types$3(), exports);
99679
99828
  tslib_1.__exportStar(require_validity(), exports);
99680
99829
  }));
99681
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/getCertificateInfo.js
99830
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/getCertificateInfo.js
99682
99831
  var import_cjs$4 = require_cjs$13();
99683
99832
  var import_cjs$5 = require_cjs$12();
99684
99833
  const issuerSubjectIDKey = {
@@ -107916,15 +108065,15 @@ var import_x509_cjs = require_x509_cjs();
107916
108065
  * A simple method for requesting data via standard `fetch`. Should work
107917
108066
  * across multiple runtimes.
107918
108067
  */
107919
- function fetch(url) {
107920
- return _fetchInternals.stubThis(url);
108068
+ function fetch(...args) {
108069
+ return _fetchInternals.stubThis(...args);
107921
108070
  }
107922
108071
  /**
107923
108072
  * Make it possible to stub the return value during testing
107924
108073
  * @ignore Don't include this in docs output
107925
108074
  */
107926
- const _fetchInternals = { stubThis: (url) => globalThis.fetch(url) };
107927
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/isCertRevoked.js
108075
+ const _fetchInternals = { stubThis: (...args) => globalThis.fetch(...args) };
108076
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/isCertRevoked.js
107928
108077
  const cacheRevokedCerts = {};
107929
108078
  /**
107930
108079
  * A method to pull a CRL from a certificate and compare its serial number to the list of revoked
@@ -107992,7 +108141,7 @@ async function getIssuerKeyIdentifier(issuer) {
107992
108141
  fromExtension: false
107993
108142
  };
107994
108143
  }
107995
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/decodeAuthenticatorExtensions.js
108144
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/decodeAuthenticatorExtensions.js
107996
108145
  /**
107997
108146
  * Convert authenticator extension data buffer to a proper object
107998
108147
  *
@@ -108018,7 +108167,7 @@ function convertMapToObjectDeep(input) {
108018
108167
  else mapped[key] = value;
108019
108168
  return mapped;
108020
108169
  }
108021
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/parseAuthenticatorData.js
108170
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/parseAuthenticatorData.js
108022
108171
  /**
108023
108172
  * Make sense of the authData buffer contained in an Attestation
108024
108173
  */
@@ -108108,16 +108257,16 @@ function parseAuthenticatorData(authData) {
108108
108257
  * @ignore Don't include this in docs output
108109
108258
  */
108110
108259
  const _parseAuthenticatorDataInternals = { stubThis: (value) => value };
108111
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/toHash.js
108260
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/toHash.js
108112
108261
  /**
108113
- * Returns hash digest of the given data, using the given algorithm when provided. Defaults to using
108114
- * SHA-256.
108262
+ * Returns the hash of the given data, using the given algorithm when provided. If `data` is
108263
+ * a string, then it's treated like a UTF-8 string. Defaults to hashing using SHA-256.
108115
108264
  */
108116
108265
  function toHash(data, algorithm = -7) {
108117
108266
  if (typeof data === "string") data = fromUTF8String(data);
108118
108267
  return digest(data, algorithm);
108119
108268
  }
108120
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoKeyAlgName.js
108269
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoKeyAlgName.js
108121
108270
  /**
108122
108271
  * Convert a COSE alg ID into a corresponding key algorithm string value that WebCrypto APIs expect
108123
108272
  *
@@ -108148,7 +108297,7 @@ function mapCoseAlgToWebCryptoKeyAlgName(alg) {
108148
108297
  else if ([COSEALG.ML_DSA_87].indexOf(alg) >= 0) return "ML-DSA-87";
108149
108298
  throw new Error(`Could not map COSE alg value of ${alg} to a WebCrypto key alg name`);
108150
108299
  }
108151
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/errors/index.js
108300
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/errors/index.js
108152
108301
  /**
108153
108302
  * Base error class that helps disambiguate SimpleWebAuthn library errors from other library errors
108154
108303
  */
@@ -108174,7 +108323,7 @@ var PQCNotSupportedError = class extends SimpleWebAuthnError {
108174
108323
  });
108175
108324
  }
108176
108325
  };
108177
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/validateCertificatePath.js
108326
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/validateCertificatePath.js
108178
108327
  /**
108179
108328
  * Traverse an array of PEM certificates and ensure they form a proper chain
108180
108329
  * @param x5cCertsPEM Typically the result of `x5c.map(convertASN1toPEM)`
@@ -108294,7 +108443,7 @@ function assertCertIsWithinValidTimeWindow(certificate) {
108294
108443
  const now = new Date(Date.now());
108295
108444
  if (certNotBefore > now || certNotAfter < now) throw new Error("Certificate is not yet valid or expired");
108296
108445
  }
108297
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/mapX509SignatureAlgToCOSEAlg.js
108446
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/mapX509SignatureAlgToCOSEAlg.js
108298
108447
  var import_cjs$1 = require_cjs$9();
108299
108448
  var import_cjs$2 = require_cjs$8();
108300
108449
  var import_cjs$3 = require_cjs$2();
@@ -108316,7 +108465,7 @@ function mapX509SignatureAlgToCOSEAlg(signatureAlgorithm) {
108316
108465
  else throw new Error(`Unable to map X.509 signature algorithm ${signatureAlgorithm} to a COSE algorithm`);
108317
108466
  return alg;
108318
108467
  }
108319
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/convertX509PublicKeyToCOSE.js
108468
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/convertX509PublicKeyToCOSE.js
108320
108469
  function convertX509PublicKeyToCOSE(x509Certificate) {
108321
108470
  let cosePublicKey = /* @__PURE__ */ new Map();
108322
108471
  const { tbsCertificate } = import_cjs$4.AsnParser.parse(x509Certificate, import_cjs$5.Certificate);
@@ -108384,7 +108533,7 @@ function convertX509PublicKeyToCOSE(x509Certificate) {
108384
108533
  } else throw new Error(`Certificate public key contained unexpected algorithm ID ${publicKeyAlgorithmID}`);
108385
108534
  return cosePublicKey;
108386
108535
  }
108387
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/verifySignature.js
108536
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/verifySignature.js
108388
108537
  /**
108389
108538
  * Verify an authenticator's signature
108390
108539
  */
@@ -108407,7 +108556,7 @@ function verifySignature(opts) {
108407
108556
  * @ignore Don't include this in docs output
108408
108557
  */
108409
108558
  const _verifySignatureInternals = { stubThis: (value) => value };
108410
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/metadata/parseJWT.js
108559
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/metadata/parseJWT.js
108411
108560
  /**
108412
108561
  * Process a JWT into Javascript-friendly data structures
108413
108562
  */
@@ -108419,7 +108568,7 @@ function parseJWT(jwt) {
108419
108568
  parts[2]
108420
108569
  ];
108421
108570
  }
108422
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/mapJWSAlgToCOSEAlg.js
108571
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/mapJWSAlgToCOSEAlg.js
108423
108572
  /**
108424
108573
  * Map JWS algorithms to COSE algorithm IDs
108425
108574
  *
@@ -108436,7 +108585,7 @@ function mapJWSAlgToCOSEAlg(alg) {
108436
108585
  else throw new Error(`Unable to map JWS algorithm "${alg}" to a COSE algorithm`);
108437
108586
  return algCOSE;
108438
108587
  }
108439
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/importJWKKey.js
108588
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/importJWKKey.js
108440
108589
  /**
108441
108590
  * Convert a JWK-formatted public key into a WebCrypto CryptoKey that can be used for
108442
108591
  * signature verification
@@ -108446,7 +108595,7 @@ async function importJWKKey(opts) {
108446
108595
  const { keyData, algorithm } = opts;
108447
108596
  return WebCrypto.subtle.importKey("jwk", keyData, algorithm, false, ["verify"]);
108448
108597
  }
108449
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/verifyEC2.js
108598
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/verifyEC2.js
108450
108599
  /**
108451
108600
  * Verify a signature using an EC2 public key
108452
108601
  */
@@ -108493,7 +108642,7 @@ async function verifyEC2(opts) {
108493
108642
  };
108494
108643
  return WebCrypto.subtle.verify(verifyAlgorithm, key, signature, data);
108495
108644
  }
108496
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/verifyRSA.js
108645
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/verifyRSA.js
108497
108646
  /**
108498
108647
  * Verify a signature using an RSA public key
108499
108648
  */
@@ -108553,7 +108702,7 @@ async function verifyRSA(opts) {
108553
108702
  });
108554
108703
  return WebCrypto.subtle.verify(verifyAlgorithm, key, signature, data);
108555
108704
  }
108556
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/metadata/verifyJWT.js
108705
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/metadata/verifyJWT.js
108557
108706
  /**
108558
108707
  * Lightweight verification for FIDO MDS JWTs. Supports use of EC2 and RSA.
108559
108708
  *
@@ -108584,14 +108733,14 @@ function verifyJWT(jwt, leafCert) {
108584
108733
  const kty = certCOSE.get(COSEKEYS.kty);
108585
108734
  throw new Error(`JWT verification with public key of kty ${kty} is not supported by this method`);
108586
108735
  }
108587
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/convertPEMToBytes.js
108736
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/convertPEMToBytes.js
108588
108737
  /**
108589
108738
  * Take a certificate in PEM format and convert it to bytes
108590
108739
  */
108591
108740
  function convertPEMToBytes(pem) {
108592
108741
  return toBuffer(pem.replace("-----BEGIN CERTIFICATE-----", "").replace("-----END CERTIFICATE-----", "").replace(/[\n ]/g, ""), "base64");
108593
108742
  }
108594
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/metadata/verifyMDSBlob.js
108743
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/metadata/verifyMDSBlob.js
108595
108744
  /**
108596
108745
  * Perform authenticity and integrity verification of a
108597
108746
  * [FIDO Metadata Service (MDS)](https://fidoalliance.org/metadata/)-compatible blob, and then
@@ -108621,7 +108770,7 @@ async function verifyMDSBlob(blob) {
108621
108770
  payload
108622
108771
  };
108623
108772
  }
108624
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/verifyAKP.js
108773
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/verifyAKP.js
108625
108774
  /** AKP, a.k.a ML-DSA */
108626
108775
  async function verifyAKP(opts) {
108627
108776
  const { cosePublicKey, signature, data } = opts;
@@ -108654,7 +108803,7 @@ async function verifyAKP(opts) {
108654
108803
  }
108655
108804
  return WebCrypto.subtle.verify(webCryptoAlg, key, signature, data);
108656
108805
  }
108657
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/verifyOKP.js
108806
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/verifyOKP.js
108658
108807
  async function verifyOKP(opts) {
108659
108808
  const { cosePublicKey, signature, data } = opts;
108660
108809
  const WebCrypto = await getWebCrypto();
@@ -108684,7 +108833,7 @@ async function verifyOKP(opts) {
108684
108833
  const verifyAlgorithm = { name: _crv };
108685
108834
  return WebCrypto.subtle.verify(verifyAlgorithm, key, signature, data);
108686
108835
  }
108687
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/unwrapEC2Signature.js
108836
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/unwrapEC2Signature.js
108688
108837
  /**
108689
108838
  * In WebAuthn, EC2 signatures are wrapped in ASN.1 structure so we need to peel r and s apart.
108690
108839
  *
@@ -108734,7 +108883,7 @@ function toNormalizedBytes(bytes, componentLength) {
108734
108883
  else throw new Error(`Invalid signature component length ${bytes.length}, expected ${componentLength}`);
108735
108884
  return normalizedBytes;
108736
108885
  }
108737
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/verify.js
108886
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/verify.js
108738
108887
  /**
108739
108888
  * Verify signatures with their public key. Supports EC2 and RSA public keys.
108740
108889
  */
@@ -108768,7 +108917,7 @@ function verify(opts) {
108768
108917
  const kty = cosePublicKey.get(COSEKEYS.kty);
108769
108918
  throw new Error(`Signature verification with public key of kty ${kty} is not supported by this method`);
108770
108919
  }
108771
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoUint8Array.js
108920
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoUint8Array.js
108772
108921
  /**
108773
108922
  * A runtime-agnostic collection of methods for working with Uint8Arrays
108774
108923
  * @module
@@ -108836,7 +108985,7 @@ function fromASCIIString(value) {
108836
108985
  function toDataView(array) {
108837
108986
  return new DataView(array.buffer, array.byteOffset, array.length);
108838
108987
  }
108839
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/convertCertBufferToPEM.js
108988
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/convertCertBufferToPEM.js
108840
108989
  /**
108841
108990
  * Convert buffer to an OpenSSL-compatible PEM text format.
108842
108991
  */
@@ -108858,7 +109007,7 @@ function convertCertBufferToPEM(certBuffer) {
108858
109007
  PEMKey = `-----BEGIN CERTIFICATE-----\n${PEMKey}-----END CERTIFICATE-----\n`;
108859
109008
  return PEMKey;
108860
109009
  }
108861
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/runtimeSupportsWebCryptoKeyAlg.js
109010
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCrypto/runtimeSupportsWebCryptoKeyAlg.js
108862
109011
  /**
108863
109012
  * Use SubtleCrypto.supports() to understand if the runtime supports using the given key algorithm
108864
109013
  * for signature verification.
@@ -108872,7 +109021,7 @@ function runtimeSupportsWebCryptoKeyAlg(alg) {
108872
109021
  return false;
108873
109022
  }
108874
109023
  }
108875
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/services/defaultRootCerts/android-safetynet.js
109024
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/services/defaultRootCerts/android-safetynet.js
108876
109025
  /**
108877
109026
  * GlobalSign Root CA
108878
109027
  *
@@ -108905,50 +109054,7 @@ DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
108905
109054
  HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
108906
109055
  -----END CERTIFICATE-----
108907
109056
  `;
108908
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/services/defaultRootCerts/android-key.js
108909
- /**
108910
- * Google Hardware Attestation Root 1
108911
- *
108912
- * Downloaded from https://developer.android.com/training/articles/security-key-attestation#root_certificate
108913
- * (first entry)
108914
- *
108915
- * Valid until 2026-05-24 @ 09:28 PST
108916
- *
108917
- * SHA256 Fingerprint
108918
- * C1:98:4A:3E:F4:5C:1E:2A:91:85:51:DE:10:60:3C:86:F7:05:1B:22:49:C4:89:1C:AE:32:30:EA:BD:0C:97:D5
108919
- */
108920
- const Google_Hardware_Attestation_Root_1 = `-----BEGIN CERTIFICATE-----
108921
- MIIFYDCCA0igAwIBAgIJAOj6GWMU0voYMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV
108922
- BAUTEGY5MjAwOWU4NTNiNmIwNDUwHhcNMTYwNTI2MTYyODUyWhcNMjYwNTI0MTYy
108923
- ODUyWjAbMRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0B
108924
- AQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHsK7Qui8xUFmOr75gvMsd/dTEDDJdS
108925
- Sxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfdnJLmN0pTy/4lj4/7
108926
- tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL/ggj
108927
- nar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGq
108928
- C4FSYa04T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQ
108929
- oVJYnFPlXTcHYvASLu+RhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+O
108930
- JtvsBslHZvPBKCOdT0MS+tgSOIfga+z1Z1g7+DVagf7quvmag8jfPioyKvxnK/Eg
108931
- sTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgpZrt3i5MIlCaY504LzSRi
108932
- igHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6tUXHI/+M
108933
- RPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9E
108934
- aDK8Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5Um
108935
- AGMCAwEAAaOBpjCBozAdBgNVHQ4EFgQUNmHhAHyIBQlRi0RsR/8aTMnqTxIwHwYD
108936
- VR0jBBgwFoAUNmHhAHyIBQlRi0RsR/8aTMnqTxIwDwYDVR0TAQH/BAUwAwEB/zAO
108937
- BgNVHQ8BAf8EBAMCAYYwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cHM6Ly9hbmRyb2lk
108938
- Lmdvb2dsZWFwaXMuY29tL2F0dGVzdGF0aW9uL2NybC8wDQYJKoZIhvcNAQELBQAD
108939
- ggIBACDIw41L3KlXG0aMiS//cqrG+EShHUGo8HNsw30W1kJtjn6UBwRM6jnmiwfB
108940
- Pb8VA91chb2vssAtX2zbTvqBJ9+LBPGCdw/E53Rbf86qhxKaiAHOjpvAy5Y3m00m
108941
- qC0w/Zwvju1twb4vhLaJ5NkUJYsUS7rmJKHHBnETLi8GFqiEsqTWpG/6ibYCv7rY
108942
- DBJDcR9W62BW9jfIoBQcxUCUJouMPH25lLNcDc1ssqvC2v7iUgI9LeoM1sNovqPm
108943
- QUiG9rHli1vXxzCyaMTjwftkJLkf6724DFhuKug2jITV0QkXvaJWF4nUaHOTNA4u
108944
- JU9WDvZLI1j83A+/xnAJUucIv/zGJ1AMH2boHqF8CY16LpsYgBt6tKxxWH00XcyD
108945
- CdW2KlBCeqbQPcsFmWyWugxdcekhYsAWyoSf818NUsZdBWBaR/OukXrNLfkQ79Iy
108946
- ZohZbvabO/X+MVT3rriAoKc8oE2Uws6DF+60PV7/WIPjNvXySdqspImSN78mflxD
108947
- qwLqRBYkA3I75qppLGG9rp7UCdRjxMl8ZDBld+7yvHVgt1cVzJx9xnyGCC23Uaic
108948
- MDSXYrB4I4WHXPGjxhZuCuPBLTdOLU8YRvMYdEvYebWHMpvwGCF6bAx3JBpIeOQ1
108949
- wDB5y0USicV3YgYGmi+NZfhA4URSh77Yd6uuJOJENRaNVTzk
108950
- -----END CERTIFICATE-----
108951
- `;
109057
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/services/defaultRootCerts/android-key.js
108952
109058
  /**
108953
109059
  * Google Hardware Attestation Root 2
108954
109060
  *
@@ -109037,7 +109143,7 @@ mD/vFDkzF+wm7cyWpQpCVQ==
109037
109143
  /**
109038
109144
  * Google Hardware Attestation Root 4
109039
109145
  *
109040
- * Downloaded from https://developer.android.com/training/articles/security-key-attestation#root_certificate
109146
+ * Downloaded from https://developer.android.com/privacy-and-security/security-key-attestation#root_certificate
109041
109147
  * (fourth entry)
109042
109148
  *
109043
109149
  * Valid until 2042-03-15 @ 11:07 PDT
@@ -109077,7 +109183,33 @@ vaI47gC+TNpkgYGkkBT6B/m/U01BuOBBTzhIlMEZq9qkDWuM2cA5kW5V3FJUcfHn
109077
109183
  w1IdYIg2Wxg7yHcQZemFQg==
109078
109184
  -----END CERTIFICATE-----
109079
109185
  `;
109080
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/services/defaultRootCerts/apple.js
109186
+ /**
109187
+ * Google Android Key Attestation CA1
109188
+ *
109189
+ * Downloaded from https://developer.android.com/privacy-and-security/security-key-attestation#root_certificate
109190
+ *
109191
+ * Valid until 2035-07-15 @ 15:32 PDT
109192
+ *
109193
+ * SHA256 Fingerprint
109194
+ * 6D:9D:B4:CE:6C:5C:0B:29:31:66:D0:89:86:E0:57:74:A8:77:6C:EB:52:5D:9E:43:29:52:0D:E1:2B:A4:BC:C0
109195
+ */
109196
+ const Google_Android_Key_Attestation_CA1 = `
109197
+ -----BEGIN CERTIFICATE-----
109198
+ MIICIjCCAaigAwIBAgIRAISp0Cl7DrWK5/8OgN52BgUwCgYIKoZIzj0EAwMwUjEc
109199
+ MBoGA1UEAwwTS2V5IEF0dGVzdGF0aW9uIENBMTEQMA4GA1UECwwHQW5kcm9pZDET
109200
+ MBEGA1UECgwKR29vZ2xlIExMQzELMAkGA1UEBhMCVVMwHhcNMjUwNzE3MjIzMjE4
109201
+ WhcNMzUwNzE1MjIzMjE4WjBSMRwwGgYDVQQDDBNLZXkgQXR0ZXN0YXRpb24gQ0Ex
109202
+ MRAwDgYDVQQLDAdBbmRyb2lkMRMwEQYDVQQKDApHb29nbGUgTExDMQswCQYDVQQG
109203
+ EwJVUzB2MBAGByqGSM49AgEGBSuBBAAiA2IABCPaI3FO3z5bBQo8cuiEas4HjqCt
109204
+ G/mLFfRT0MsIssPBEEU5Cfbt6sH5yOAxqEi5QagpU1yX4HwnGb7OtBYpDTB57uH5
109205
+ Eczm34A5FNijV3s0/f0UPl7zbJcTx6xwqMIRq6NCMEAwDwYDVR0TAQH/BAUwAwEB
109206
+ /zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFFIyuyz7RkOb3NaBqQ5lZuA0QepA
109207
+ MAoGCCqGSM49BAMDA2gAMGUCMETfjPO/HwqReR2CS7p0ZWoD/LHs6hDi422opifH
109208
+ EUaYLxwGlT9SLdjkVpz0UUOR5wIxAIoGyxGKRHVTpqpGRFiJtQEOOTp/+s1GcxeY
109209
+ uR2zh/80lQyu9vAFCj6E4AXc+osmRg==
109210
+ -----END CERTIFICATE-----
109211
+ `;
109212
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/services/defaultRootCerts/apple.js
109081
109213
  /**
109082
109214
  * Apple WebAuthn Root CA
109083
109215
  *
@@ -109103,7 +109235,7 @@ jAGGiQIwHFj+dJZYUJR786osByBelJYsVZd2GbHQu209b5RCmGQ21gpSAk9QZW4B
109103
109235
  1bWeT0vT
109104
109236
  -----END CERTIFICATE-----
109105
109237
  `;
109106
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/services/defaultRootCerts/mds.js
109238
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/services/defaultRootCerts/mds.js
109107
109239
  /**
109108
109240
  * GlobalSign Root CA - R3
109109
109241
  *
@@ -109178,7 +109310,7 @@ N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3
109178
109310
  vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6
109179
109311
  -----END CERTIFICATE-----
109180
109312
  `;
109181
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/services/settingsService.js
109313
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/services/settingsService.js
109182
109314
  var BaseSettingsService = class {
109183
109315
  constructor() {
109184
109316
  Object.defineProperty(this, "pemCertificates", {
@@ -109229,10 +109361,10 @@ const SettingsService = new BaseSettingsService();
109229
109361
  SettingsService.setRootCertificates({
109230
109362
  identifier: "android-key",
109231
109363
  certificates: [
109232
- Google_Hardware_Attestation_Root_1,
109233
109364
  Google_Hardware_Attestation_Root_2,
109234
109365
  Google_Hardware_Attestation_Root_3,
109235
- Google_Hardware_Attestation_Root_4
109366
+ Google_Hardware_Attestation_Root_4,
109367
+ Google_Android_Key_Attestation_CA1
109236
109368
  ]
109237
109369
  });
109238
109370
  SettingsService.setRootCertificates({
@@ -109247,7 +109379,7 @@ SettingsService.setRootCertificates({
109247
109379
  identifier: "mds",
109248
109380
  certificates: [GlobalSign_Root_CA_R3, GlobalSign_Root_R46]
109249
109381
  });
109250
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/registration/generateRegistrationOptions.js
109382
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/registration/generateRegistrationOptions.js
109251
109383
  /**
109252
109384
  * Set up some default authenticator selection options as per the latest spec:
109253
109385
  * https://www.w3.org/TR/webauthn-2/#dictdef-authenticatorselectioncriteria
@@ -109389,7 +109521,7 @@ async function generateRegistrationOptions(options) {
109389
109521
  hints
109390
109522
  };
109391
109523
  }
109392
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/parseBackupFlags.js
109524
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/parseBackupFlags.js
109393
109525
  /**
109394
109526
  * Make sense of Bits 3 and 4 in authenticator indicating:
109395
109527
  *
@@ -109414,7 +109546,21 @@ var InvalidBackupFlags = class extends Error {
109414
109546
  this.name = "InvalidBackupFlags";
109415
109547
  }
109416
109548
  };
109417
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/matchExpectedRPID.js
109549
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/assertValidExpectedRPID.js
109550
+ /**
109551
+ * Check the RP ID to make sure it's valid to compare against what's reported in a WebAuthn
109552
+ * response.
109553
+ *
109554
+ * Invalid RP IDs will raise a `SimpleWebAuthnError` with `code: 'BAD_ARGUMENT'`
109555
+ */
109556
+ function assertValidExpectedRPID(rpID) {
109557
+ const asciiRPID = new URL(`https://${rpID}`).hostname;
109558
+ if (asciiRPID !== rpID) throw new SimpleWebAuthnError({
109559
+ message: `"${rpID}" is not a valid expected RP ID. Replace it with its ASCII punycode representation "${asciiRPID}" and try again`,
109560
+ code: "BAD_ARGUMENT"
109561
+ });
109562
+ }
109563
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/matchExpectedRPID.js
109418
109564
  /**
109419
109565
  * Go through each expected RP ID and try to find one that matches. Returns the unhashed RP ID
109420
109566
  * that matched the hash in the response.
@@ -109422,6 +109568,7 @@ var InvalidBackupFlags = class extends Error {
109422
109568
  * Raises an `UnexpectedRPIDHash` error if no match is found
109423
109569
  */
109424
109570
  async function matchExpectedRPID(rpIDHash, expectedRPIDs) {
109571
+ for (const rpID of expectedRPIDs) assertValidExpectedRPID(rpID);
109425
109572
  try {
109426
109573
  return await Promise.any(expectedRPIDs.map((expected) => {
109427
109574
  return new Promise((resolve, reject) => {
@@ -109432,72 +109579,188 @@ async function matchExpectedRPID(rpIDHash, expectedRPIDs) {
109432
109579
  });
109433
109580
  }));
109434
109581
  } catch (err) {
109435
- if (err.name === "AggregateError") throw new UnexpectedRPIDHash();
109582
+ if (err.name === "AggregateError") throw new SimpleWebAuthnError({
109583
+ message: "Unexpected RP ID hash",
109584
+ code: "UNEXPECTED_RP_ID"
109585
+ });
109436
109586
  throw err;
109437
109587
  }
109438
109588
  }
109439
- var UnexpectedRPIDHash = class extends Error {
109440
- constructor() {
109441
- super("Unexpected RP ID hash");
109442
- this.name = "UnexpectedRPIDHash";
109589
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/services/helpers/serviceStateTracker.js
109590
+ var SERVICE_STATE;
109591
+ (function(SERVICE_STATE) {
109592
+ SERVICE_STATE["DISABLED"] = "DISABLED";
109593
+ SERVICE_STATE["REFRESHING"] = "REFRESHING";
109594
+ SERVICE_STATE["READY"] = "READY";
109595
+ })(SERVICE_STATE || (SERVICE_STATE = {}));
109596
+ var ServiceStateTracker = class {
109597
+ constructor(name, logger) {
109598
+ Object.defineProperty(this, "name", {
109599
+ enumerable: true,
109600
+ configurable: true,
109601
+ writable: true,
109602
+ value: name
109603
+ });
109604
+ Object.defineProperty(this, "logger", {
109605
+ enumerable: true,
109606
+ configurable: true,
109607
+ writable: true,
109608
+ value: logger
109609
+ });
109610
+ Object.defineProperty(this, "state", {
109611
+ enumerable: true,
109612
+ configurable: true,
109613
+ writable: true,
109614
+ value: SERVICE_STATE.DISABLED
109615
+ });
109616
+ }
109617
+ /**
109618
+ * Get the current state
109619
+ */
109620
+ get current() {
109621
+ return this.state;
109622
+ }
109623
+ /**
109624
+ * Set a new state and report it
109625
+ */
109626
+ set(next) {
109627
+ if (this.state === next) return;
109628
+ this.state = next;
109629
+ this.logger.debug(`${this.name} is ${SERVICE_STATE[this.state]}`);
109630
+ }
109631
+ /**
109632
+ * A helper method to pause execution until the service is ready
109633
+ */
109634
+ pauseUntilReady() {
109635
+ if (this.state === SERVICE_STATE.READY) return Promise.resolve();
109636
+ return new Promise((resolve, reject) => {
109637
+ const totalTimeoutMS = 7e4;
109638
+ const intervalMS = 100;
109639
+ let iterations = totalTimeoutMS / intervalMS;
109640
+ const intervalID = globalThis.setInterval(() => {
109641
+ if (iterations < 1) {
109642
+ clearInterval(intervalID);
109643
+ reject(`State did not become ready in ${totalTimeoutMS / 1e3} seconds`);
109644
+ } else if (this.state === SERVICE_STATE.READY) {
109645
+ clearInterval(intervalID);
109646
+ resolve();
109647
+ }
109648
+ iterations -= 1;
109649
+ }, intervalMS);
109650
+ });
109443
109651
  }
109444
109652
  };
109445
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/registration/verifications/verifyAttestationFIDOU2F.js
109446
109653
  /**
109447
- * Verify an attestation response with fmt 'fido-u2f'
109654
+ * An MDS-aware metadata cache that tracks MDS servers and the data downloaded from them. This
109655
+ * includes tracking when an MDS server needs to be refreshed, but does not actually perform the
109656
+ * refresh.
109448
109657
  */
109449
- async function verifyAttestationFIDOU2F(options) {
109450
- const { attStmt, clientDataHash, rpIdHash, credentialID, credentialPublicKey, aaguid, rootCertificates } = options;
109451
- const signatureBase = concat([
109452
- Uint8Array.from([0]),
109453
- rpIdHash,
109454
- clientDataHash,
109455
- credentialID,
109456
- convertCOSEtoPKCS(credentialPublicKey)
109457
- ]);
109458
- const sig = attStmt.get("sig");
109459
- const x5c = attStmt.get("x5c");
109460
- if (!x5c) throw new Error("No attestation certificate provided in attestation statement (FIDOU2F)");
109461
- if (!sig) throw new Error("No attestation signature provided in attestation statement (FIDOU2F)");
109462
- const aaguidToHex = Number.parseInt(toHex(aaguid), 16);
109463
- if (aaguidToHex !== 0) throw new Error(`AAGUID "${aaguidToHex}" was not expected value`);
109464
- try {
109465
- await validateCertificatePath(x5c.map(convertCertBufferToPEM), rootCertificates);
109466
- } catch (err) {
109467
- throw new Error(`${err.message} (FIDOU2F)`);
109658
+ var MDSCache = class {
109659
+ constructor() {
109660
+ Object.defineProperty(this, "serverCache", {
109661
+ enumerable: true,
109662
+ configurable: true,
109663
+ writable: true,
109664
+ value: /* @__PURE__ */ new Map()
109665
+ });
109666
+ Object.defineProperty(this, "metadataCache", {
109667
+ enumerable: true,
109668
+ configurable: true,
109669
+ writable: true,
109670
+ value: /* @__PURE__ */ new Map()
109671
+ });
109468
109672
  }
109469
- return verifySignature({
109470
- signature: sig,
109471
- data: signatureBase,
109472
- x509Certificate: x5c[0],
109473
- hashAlgorithm: COSEALG.ES256
109474
- });
109475
- }
109476
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/validateExtFIDOGenCEAAGUID.js
109477
- /**
109478
- * Attestation Certificate Extension OID: `id-fido-gen-ce-aaguid`
109479
- *
109480
- * Sourced from https://fidoalliance.org/specs/fido-v2.0-ps-20150904/fido-key-attestation-v2.0-ps-20150904.html#verifying-an-attestation-statement
109481
- */
109482
- const id_fido_gen_ce_aaguid = "1.3.6.1.4.1.45724.1.1.4";
109483
- /**
109484
- * Look for the id-fido-gen-ce-aaguid certificate extension. If it's present then check it against
109485
- * the attestation statement AAGUID.
109486
- */
109487
- function validateExtFIDOGenCEAAGUID(certExtensions, aaguid) {
109488
- if (!certExtensions) return true;
109489
- const extFIDOGenCEAAGUID = certExtensions.find((ext) => ext.extnID === id_fido_gen_ce_aaguid);
109490
- if (!extFIDOGenCEAAGUID) return true;
109491
- const parsedExtFIDOGenCEAAGUID = import_cjs$4.AsnParser.parse(extFIDOGenCEAAGUID.extnValue, import_cjs$4.OctetString);
109492
- const extValue = new Uint8Array(parsedExtFIDOGenCEAAGUID.buffer);
109493
- if (!areEqual(aaguid, extValue)) {
109494
- const _debugExtHex = toHex(extValue);
109495
- const _debugAAGUIDHex = toHex(aaguid);
109496
- throw new Error(`Certificate extension id-fido-gen-ce-aaguid (${id_fido_gen_ce_aaguid}) value of "${_debugExtHex}" was present but not equal to attestation statement AAGUID value of "${_debugAAGUIDHex}"`);
109673
+ /**
109674
+ * Set up a Metadata Service API for periodic refreshes
109675
+ */
109676
+ registerMDSServer(url, no, nextUpdate) {
109677
+ this.serverCache.set(url, {
109678
+ url,
109679
+ no,
109680
+ nextUpdate
109681
+ });
109497
109682
  }
109498
- return true;
109499
- }
109500
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/helpers/logging.js
109683
+ /**
109684
+ * Add the provided metadata to the cache, keyed by its corresponding AAGUID
109685
+ */
109686
+ cacheMetadata(aaguid, metadata, url) {
109687
+ this.metadataCache.set(this.normalizeAAGUID(aaguid), {
109688
+ data: metadata,
109689
+ url
109690
+ });
109691
+ }
109692
+ /**
109693
+ * Retrieve cached metadata by AAGUID
109694
+ */
109695
+ getMetadata(aaguid) {
109696
+ if (!aaguid) return;
109697
+ if (aaguid instanceof Uint8Array) aaguid = convertAAGUIDToString(aaguid);
109698
+ return this.metadataCache.get(this.normalizeAAGUID(aaguid))?.data;
109699
+ }
109700
+ /**
109701
+ * Return how many metadata entries have been cached
109702
+ */
109703
+ get count() {
109704
+ return this.metadataCache.size;
109705
+ }
109706
+ /**
109707
+ * Clear out caches
109708
+ */
109709
+ reset() {
109710
+ this.serverCache = /* @__PURE__ */ new Map();
109711
+ this.metadataCache = /* @__PURE__ */ new Map();
109712
+ }
109713
+ /**
109714
+ * Remove cached Metadata Service data for a specific API server. If the URL indicates data that
109715
+ * should not be refreshed, then simply exit.
109716
+ */
109717
+ clearMetadataByURL(url) {
109718
+ if (url === "") return;
109719
+ for (const [aaguid, cached] of this.metadataCache.entries()) if (cached.url === url) this.metadataCache.delete(this.normalizeAAGUID(aaguid));
109720
+ }
109721
+ /**
109722
+ * Whether an MDS server has been registered for periodic refreshes
109723
+ */
109724
+ mdsServerIsRegistered(url) {
109725
+ return this.serverCache.has(url);
109726
+ }
109727
+ /**
109728
+ * Set the MDS server's nextUpdate
109729
+ */
109730
+ setMDSServerNextUpdate(url, newNextUpdate) {
109731
+ const server = this.serverCache.get(url);
109732
+ if (!server) throw new SimpleWebAuthnError({
109733
+ message: `No MDS server has been registered for "${url}". Register it with registerMDSServer() first`,
109734
+ code: "BAD_ARGUMENT"
109735
+ });
109736
+ server.nextUpdate = newNextUpdate;
109737
+ this.serverCache.set(url, server);
109738
+ }
109739
+ /**
109740
+ * Retrieve the version number of the MDS server's latest known data
109741
+ */
109742
+ getMDSServerDataVersion(url) {
109743
+ const server = this.serverCache.get(url);
109744
+ if (!server) throw new SimpleWebAuthnError({
109745
+ message: `No MDS server has been registered for "${url}". Register it with registerMDSServer() first`,
109746
+ code: "BAD_ARGUMENT"
109747
+ });
109748
+ return server.no;
109749
+ }
109750
+ /**
109751
+ * Return a list of MDS server URLs with nextUpdates earlier than the provided date
109752
+ */
109753
+ getStaleMDSServerURLs(date) {
109754
+ return this.serverCache.values().filter((mds) => mds.url !== "" && date > mds.nextUpdate).map((mds) => mds.url).toArray();
109755
+ }
109756
+ /**
109757
+ * Ensure that AAGUIDs are all lowercase before using them as cache keys
109758
+ */
109759
+ normalizeAAGUID(aaguid) {
109760
+ return aaguid.toLowerCase();
109761
+ }
109762
+ };
109763
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/logging.js
109501
109764
  /**
109502
109765
  * A logger instance that doesn't do anything. Useful as a default argument when no custom instance
109503
109766
  * of the `SimpleWebAuthnLogger` interface is specified.
@@ -109520,66 +109783,231 @@ function buildLoggerAllMethods(logger) {
109520
109783
  if (logger.error) toReturn.error = logger.error;
109521
109784
  return toReturn;
109522
109785
  }
109523
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/services/metadataService.js
109524
- /**
109525
- * An instance of `CachedMDS` that will not trigger attempts to refresh the associated entry's blob
109526
- */
109527
- const NonRefreshingMDS = {
109528
- url: "",
109529
- no: 0,
109530
- nextUpdate: /* @__PURE__ */ new Date(0)
109531
- };
109532
- const defaultURLMDS = "https://mds.fidoalliance.org/";
109533
- var SERVICE_STATE;
109534
- (function(SERVICE_STATE) {
109535
- SERVICE_STATE[SERVICE_STATE["DISABLED"] = 0] = "DISABLED";
109536
- SERVICE_STATE[SERVICE_STATE["REFRESHING"] = 1] = "REFRESHING";
109537
- SERVICE_STATE[SERVICE_STATE["READY"] = 2] = "READY";
109538
- })(SERVICE_STATE || (SERVICE_STATE = {}));
109786
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/services/helpers/getInitCacheMessage.js
109539
109787
  /**
109540
- * An implementation of `MetadataService` that can download and parse BLOBs, and support on-demand
109541
- * requesting and caching of individual metadata statements.
109788
+ * Generate a message detailing how many metadata entries were cached, and from which sources
109542
109789
  *
109543
- * https://fidoalliance.org/metadata/
109790
+ * Examples:
109791
+ *
109792
+ * - "ConvenienceMetadataService cached 322 unique metadata entries from 1 local payload(s) and 1 convenience metadata server(s)"
109793
+ * - "ConvenienceMetadataService cached 322 unique metadata entries from 1 local payload(s)"
109794
+ * - "MetadataService cached 285 unique metadata entries from 1 convenience metadata server(s)"
109795
+ * - "MetadataService cached 0 unique metadata entries"
109796
+ */
109797
+ function getInitCacheMessage(serviceName, cacheCount, numLocalFiles, numServers) {
109798
+ let message = `${serviceName} cached ${cacheCount} unique entries`;
109799
+ if (cacheCount) {
109800
+ const formatter = new Intl.ListFormat("en", {
109801
+ style: "long",
109802
+ type: "conjunction"
109803
+ });
109804
+ const sources = [];
109805
+ if (numLocalFiles) sources.push(`${numLocalFiles} local file(s)`);
109806
+ if (numServers) sources.push(`${numServers} metadata server(s)`);
109807
+ message = `${message} from ${formatter.format(sources)}`;
109808
+ }
109809
+ return message;
109810
+ }
109811
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/services/helpers/baseMDSService.js
109812
+ /**
109813
+ * Functionality shared by services that download, cache, and refresh metadata from FIDO
109814
+ * Alliance-style metadata servers (MDS and Convenience MDS.) Subclasses are responsible for
109815
+ * parsing and caching what a server returns.
109544
109816
  */
109545
- var BaseMetadataService = class {
109546
- constructor() {
109547
- Object.defineProperty(this, "mdsCache", {
109817
+ var BaseMDSService = class {
109818
+ /**
109819
+ * @param serviceName Used in logs, e.g. `"MetadataService"`
109820
+ */
109821
+ constructor(serviceName) {
109822
+ Object.defineProperty(this, "serviceName", {
109548
109823
  enumerable: true,
109549
109824
  configurable: true,
109550
109825
  writable: true,
109551
- value: {}
109826
+ value: serviceName
109552
109827
  });
109553
- Object.defineProperty(this, "statementCache", {
109828
+ Object.defineProperty(this, "metadataCache", {
109554
109829
  enumerable: true,
109555
109830
  configurable: true,
109556
109831
  writable: true,
109557
- value: {}
109832
+ value: new MDSCache()
109558
109833
  });
109559
109834
  Object.defineProperty(this, "state", {
109560
109835
  enumerable: true,
109561
109836
  configurable: true,
109562
109837
  writable: true,
109563
- value: SERVICE_STATE.DISABLED
109838
+ value: void 0
109564
109839
  });
109565
- Object.defineProperty(this, "verificationMode", {
109840
+ Object.defineProperty(this, "logger", {
109566
109841
  enumerable: true,
109567
109842
  configurable: true,
109568
109843
  writable: true,
109569
- value: "strict"
109844
+ value: DefaultNoopLogger
109570
109845
  });
109571
- Object.defineProperty(this, "logger", {
109846
+ /** How many hours to wait to check a server again when it has nothing new to download */
109847
+ Object.defineProperty(this, "defaultRefreshDelayHours", {
109572
109848
  enumerable: true,
109573
109849
  configurable: true,
109574
109850
  writable: true,
109575
- value: DefaultNoopLogger
109851
+ value: 24
109852
+ });
109853
+ /** How many hours to wait to retry a _failed_ attempt to refresh a server */
109854
+ Object.defineProperty(this, "defaultRetryDelayHours", {
109855
+ enumerable: true,
109856
+ configurable: true,
109857
+ writable: true,
109858
+ value: 3
109859
+ });
109860
+ /** Abort downloads that take longer than this many milliseconds. No limit if left `undefined` */
109861
+ Object.defineProperty(this, "downloadTimeoutMS", {
109862
+ enumerable: true,
109863
+ configurable: true,
109864
+ writable: true,
109865
+ value: 1e4
109866
+ });
109867
+ /**
109868
+ * Refresh a single server, subscribing to the refresh already in flight if there is one.
109869
+ * Failures are passed to `handleRefreshFailure()`.
109870
+ */
109871
+ Object.defineProperty(this, "serverRefreshes", {
109872
+ enumerable: true,
109873
+ configurable: true,
109874
+ writable: true,
109875
+ value: {}
109576
109876
  });
109877
+ this.state = new ServiceStateTracker(serviceName, this.logger);
109577
109878
  }
109578
- async initialize(opts = {}) {
109579
- this.statementCache = {};
109580
- const { mdsServers = [defaultURLMDS], statements, verificationMode, logger = DefaultNoopLogger } = opts;
109879
+ /**
109880
+ * Reset the service and move it to the `REFRESHING` state. Call this at the start of
109881
+ * `initialize()`.
109882
+ */
109883
+ beginInitialize(logger = DefaultNoopLogger) {
109884
+ this.metadataCache.reset();
109885
+ this.serverRefreshes = {};
109581
109886
  this.logger = buildLoggerAllMethods(logger);
109582
- this.setState(SERVICE_STATE.REFRESHING);
109887
+ this.state = new ServiceStateTracker(this.serviceName, this.logger);
109888
+ this.state.set(SERVICE_STATE.REFRESHING);
109889
+ }
109890
+ /**
109891
+ * Download and cache from each server. A server is only registered for refreshes once data from
109892
+ * it has been cached. One that can't be reached, or that doesn't respond with data, is skipped
109893
+ * so it can't cause lookups of other metadata to fail.
109894
+ *
109895
+ * Returns the number of servers entries were cached from.
109896
+ */
109897
+ async initializeServers(mdsServers) {
109898
+ let numServers = 0;
109899
+ for (const url of mdsServers ?? []) try {
109900
+ const entriesAdded = await this.downloadAndCache(url, 0);
109901
+ if (entriesAdded !== void 0) {
109902
+ numServers += 1;
109903
+ this.logger.debug(`Cached ${entriesAdded} metadata entries from "${url}"`);
109904
+ }
109905
+ } catch (err) {
109906
+ this.logger.error(`Could not download data from "${url}":`, err);
109907
+ }
109908
+ return numServers;
109909
+ }
109910
+ /**
109911
+ * Log how much was cached and report the service as ready. Call this at the end of
109912
+ * `initialize()`.
109913
+ */
109914
+ finishInitialize(numLocalFiles, numServers) {
109915
+ const cacheMessage = getInitCacheMessage(this.serviceName, this.metadataCache.count, numLocalFiles, numServers);
109916
+ this.logger.info(cacheMessage);
109917
+ this.state.set(SERVICE_STATE.READY);
109918
+ }
109919
+ /**
109920
+ * Request data from a server, with a query param that can short-circuit the download if the
109921
+ * latest version is already cached. `no` is the serial number of the last data cached from this
109922
+ * server.
109923
+ *
109924
+ * Returns `undefined` if the server responded with anything other than data, in which case the
109925
+ * next refresh will have been delayed.
109926
+ *
109927
+ * See https://fidoalliance.org/specs/mds/fido-metadata-service-v3.1-ps-20250521.html#sctn-mds-blob-proc-rules
109928
+ */
109929
+ async fetchFromServer(url, no) {
109930
+ const _url = new URL(url);
109931
+ _url.searchParams.set("localCopySerial", String(no));
109932
+ const resp = await fetch(_url.toString(), { signal: AbortSignal.timeout(this.downloadTimeoutMS) });
109933
+ if (resp.status === 304) {
109934
+ await resp.body?.cancel();
109935
+ this.logger.info(`The MDS server at "${_url.toString()}" reported nothing new to download (HTTP 304)`);
109936
+ this.delayNextRefresh(url, this.defaultRefreshDelayHours);
109937
+ return;
109938
+ }
109939
+ if (resp.status === 429) {
109940
+ await resp.body?.cancel();
109941
+ this.logger.warn(`The MDS server at "${_url.toString()}" rate-limited this request (HTTP 429)`);
109942
+ this.delayNextRefresh(url, this.defaultRetryDelayHours);
109943
+ return;
109944
+ }
109945
+ if (!resp.ok) {
109946
+ await resp.body?.cancel();
109947
+ this.logger.warn(`The MDS server at "${_url.toString()}" reported an unsuccessful request (HTTP ${resp.status})`);
109948
+ this.delayNextRefresh(url, this.defaultRetryDelayHours);
109949
+ return;
109950
+ }
109951
+ return resp;
109952
+ }
109953
+ /**
109954
+ * Refresh every server whose `nextUpdate` has passed
109955
+ */
109956
+ async refreshStaleServers() {
109957
+ const now = /* @__PURE__ */ new Date();
109958
+ const staleURLs = this.metadataCache.getStaleMDSServerURLs(now);
109959
+ await Promise.all(staleURLs.map((url) => this.refreshServer(url)));
109960
+ }
109961
+ refreshServer(url) {
109962
+ const inFlight = this.serverRefreshes[url];
109963
+ if (inFlight) return inFlight;
109964
+ this.state.set(SERVICE_STATE.REFRESHING);
109965
+ const refresh = (async () => {
109966
+ try {
109967
+ const mdsNo = this.metadataCache.getMDSServerDataVersion(url);
109968
+ await this.downloadAndCache(url, mdsNo);
109969
+ } catch (err) {
109970
+ this.logger.error(`Could not download data from "${url}":`, err);
109971
+ this.handleRefreshFailure(url, err);
109972
+ } finally {
109973
+ delete this.serverRefreshes[url];
109974
+ if (Object.keys(this.serverRefreshes).length === 0) this.state.set(SERVICE_STATE.READY);
109975
+ }
109976
+ })();
109977
+ this.serverRefreshes[url] = refresh;
109978
+ return refresh;
109979
+ }
109980
+ /**
109981
+ * Delay the next refresh attempt of this server by the specified number of hours
109982
+ */
109983
+ delayNextRefresh(url, numHours) {
109984
+ if (!this.metadataCache.mdsServerIsRegistered(url)) return;
109985
+ this.logger.debug(`Delaying next refresh of "${url}" by ${numHours} hours`);
109986
+ const numHoursMS = 36e5 * numHours;
109987
+ this.metadataCache.setMDSServerNextUpdate(url, new Date(Date.now() + numHoursMS));
109988
+ }
109989
+ };
109990
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/services/metadataService.js
109991
+ const defaultURLMDS = "https://mds.fidoalliance.org/";
109992
+ /**
109993
+ * An implementation of `MetadataService` that can download and parse BLOBs, and support on-demand
109994
+ * requesting and caching of individual metadata statements.
109995
+ *
109996
+ * https://fidoalliance.org/metadata/
109997
+ */
109998
+ var BaseMetadataService = class extends BaseMDSService {
109999
+ constructor() {
110000
+ super("MetadataService");
110001
+ Object.defineProperty(this, "verificationMode", {
110002
+ enumerable: true,
110003
+ configurable: true,
110004
+ writable: true,
110005
+ value: "strict"
110006
+ });
110007
+ }
110008
+ async initialize(opts = {}) {
110009
+ const { mdsServers = [defaultURLMDS], statements, verificationMode, logger } = opts;
110010
+ this.beginInitialize(logger);
109583
110011
  /**
109584
110012
  * If metadata statements are provided, load them into the cache first. These statements will
109585
110013
  * not be refreshed when a stale one is detected.
@@ -109587,139 +110015,240 @@ var BaseMetadataService = class {
109587
110015
  if (statements?.length) {
109588
110016
  let statementsAdded = 0;
109589
110017
  statements.forEach((statement) => {
109590
- if (statement.aaguid) {
109591
- this.statementCache[statement.aaguid] = {
109592
- entry: {
109593
- metadataStatement: statement,
109594
- statusReports: [],
109595
- timeOfLastStatusChange: "1970-01-01"
109596
- },
109597
- url: NonRefreshingMDS.url
109598
- };
109599
- statementsAdded += 1;
109600
- }
110018
+ statementsAdded += this.cacheMetadataBlobEntry("", {
110019
+ aaguid: statement.aaguid,
110020
+ metadataStatement: statement,
110021
+ statusReports: [],
110022
+ timeOfLastStatusChange: "1970-01-01"
110023
+ });
109601
110024
  });
109602
- this.logger.info(`Cached ${statementsAdded} local statements`);
110025
+ this.logger.info(`Cached ${statementsAdded} total local metadata statements`);
109603
110026
  }
109604
110027
  /**
109605
110028
  * If MDS servers are provided, then download blobs from them, verify them, and then add their
109606
110029
  * entries to the cache. Blobs loaded in this way will be refreshed when a stale entry within is
109607
110030
  * detected.
109608
110031
  */
109609
- if (mdsServers?.length) {
109610
- const currentCacheCount = Object.keys(this.statementCache).length;
109611
- let numServers = mdsServers.length;
109612
- for (const url of mdsServers) try {
109613
- const cachedMDS = {
109614
- url,
109615
- no: 0,
109616
- nextUpdate: /* @__PURE__ */ new Date(0)
109617
- };
109618
- const blob = await this.downloadBlob(cachedMDS);
109619
- await this.verifyBlob(blob, cachedMDS);
109620
- } catch (err) {
109621
- this.logger.error(`Could not download BLOB from ${url}:`, err);
109622
- numServers -= 1;
109623
- }
109624
- const cacheDiff = Object.keys(this.statementCache).length - currentCacheCount;
109625
- this.logger.info(`Cached ${cacheDiff} statements from ${numServers} metadata server(s)`);
109626
- }
109627
- if (verificationMode) this.verificationMode = verificationMode;
109628
- this.setState(SERVICE_STATE.READY);
110032
+ const numServers = await this.initializeServers(mdsServers);
110033
+ this.verificationMode = verificationMode ?? "strict";
110034
+ this.finishInitialize(statements?.length, numServers);
109629
110035
  }
109630
110036
  async getStatement(aaguid) {
109631
- if (this.state === SERVICE_STATE.DISABLED) return;
110037
+ if (this.state.current === SERVICE_STATE.DISABLED) return;
109632
110038
  if (!aaguid) return;
109633
110039
  if (aaguid instanceof Uint8Array) aaguid = convertAAGUIDToString(aaguid);
109634
- await this.pauseUntilReady();
109635
- const cachedStatement = this.statementCache[aaguid];
109636
- if (!cachedStatement) {
110040
+ await this.state.pauseUntilReady();
110041
+ await this.refreshStaleServers();
110042
+ const entry = this.metadataCache.getMetadata(aaguid);
110043
+ if (!entry) {
109637
110044
  if (this.verificationMode === "strict") throw new Error(`No metadata statement found for aaguid "${aaguid}"`);
109638
110045
  return;
109639
110046
  }
109640
- if (cachedStatement.url) {
109641
- const mds = this.mdsCache[cachedStatement.url];
109642
- if (/* @__PURE__ */ new Date() > mds.nextUpdate) try {
109643
- this.setState(SERVICE_STATE.REFRESHING);
109644
- const blob = await this.downloadBlob(mds);
109645
- await this.verifyBlob(blob, mds);
109646
- } finally {
109647
- this.setState(SERVICE_STATE.READY);
109648
- }
109649
- }
109650
- const { entry } = cachedStatement;
109651
110047
  for (const report of entry.statusReports) {
109652
110048
  const { status } = report;
109653
110049
  if (status === "USER_VERIFICATION_BYPASS" || status === "ATTESTATION_KEY_COMPROMISE" || status === "USER_KEY_REMOTE_COMPROMISE" || status === "USER_KEY_PHYSICAL_COMPROMISE") throw new Error(`Detected compromised aaguid "${aaguid}"`);
109654
110050
  }
109655
110051
  return entry.metadataStatement;
109656
110052
  }
110053
+ async getProviderMetadata(aaguid) {
110054
+ /**
110055
+ * This is a load-bearing check: without it the `this.verificationMode === 'strict'` check in
110056
+ * `getStatement()` will raise an error on this method when there's no need to do so because
110057
+ * this method's returning `undefined` does not impact the security posture of the RP.
110058
+ */
110059
+ if (!aaguid) return;
110060
+ const metadataStatement = await this.getStatement(aaguid);
110061
+ if (!metadataStatement) return;
110062
+ return {
110063
+ friendlyNames: metadataStatement.friendlyNames,
110064
+ icon: metadataStatement.icon,
110065
+ iconDark: metadataStatement.iconDark,
110066
+ providerLogoDark: metadataStatement.providerLogoDark,
110067
+ providerLogoLight: metadataStatement.providerLogoLight
110068
+ };
110069
+ }
110070
+ /**
110071
+ * Download the latest BLOB from MDS, verify it, and cache its entries
110072
+ */
110073
+ async downloadAndCache(url, no) {
110074
+ const resp = await this.fetchFromServer(url, no);
110075
+ if (!resp) return;
110076
+ const blob = await resp.text();
110077
+ return this.verifyBlob(blob, url, no);
110078
+ }
109657
110079
  /**
109658
- * Download and process the latest BLOB from MDS
110080
+ * Refresh failures are rethrown so that lookups fail closed: until the refresh succeeds the
110081
+ * server stays stale, every lookup tries again, and none of them are answered with statements
110082
+ * from the BLOB that was previously cached.
109659
110083
  */
109660
- async downloadBlob(cachedMDS) {
109661
- const { url } = cachedMDS;
109662
- return await (await fetch(url)).text();
110084
+ handleRefreshFailure(_url, err) {
110085
+ throw err;
109663
110086
  }
109664
110087
  /**
109665
- * Verify and process the MDS metadata blob
110088
+ * Verify and process the MDS metadata blob. Caches metadata and sets up refreshing when blobs
110089
+ * grow stale. `no` is the serial number of the last BLOB cached from this server.
110090
+ *
110091
+ * Returns the number of FIDO2 metadata statements that were cached.
109666
110092
  */
109667
- async verifyBlob(blob, cachedMDS) {
109668
- const { url, no } = cachedMDS;
110093
+ async verifyBlob(blob, url, no) {
109669
110094
  const { payload, parsedNextUpdate } = await verifyMDSBlob(blob);
109670
110095
  if (payload.no <= no) throw new Error(`Latest BLOB no. ${payload.no} is not greater than previous no. ${no}`);
109671
- for (const entry of payload.entries) if (entry.aaguid) this.statementCache[entry.aaguid] = {
109672
- entry,
109673
- url
109674
- };
109675
- if (url) this.mdsCache[url] = {
109676
- ...cachedMDS,
109677
- no: payload.no,
109678
- nextUpdate: parsedNextUpdate
109679
- };
110096
+ this.metadataCache.clearMetadataByURL(url);
110097
+ let totalEntries = 0;
110098
+ for (const entry of payload.entries) totalEntries += this.cacheMetadataBlobEntry(url, entry);
110099
+ if (url !== "") this.metadataCache.registerMDSServer(url, payload.no, parsedNextUpdate);
109680
110100
  else if (parsedNextUpdate < /* @__PURE__ */ new Date()) this.logger.warn(`⚠️ This MDS blob (serial: ${payload.no}) contains stale data as of ${parsedNextUpdate.toISOString()}. Please consider re-initializing MetadataService with a newer MDS blob.`);
110101
+ return totalEntries;
109681
110102
  }
109682
110103
  /**
109683
- * A helper method to pause execution until the service is ready
110104
+ * A central place to contain logic and side effects of caching a BLOB entry. Only caches FIDO2
110105
+ * statements (i.e. ones with `aaguid` as UAF authenticators won't have one.) Returns `1` if the
110106
+ * statement was cached, or `0` if it wasn't (so you can `count += cacheMetadataBlobEntry(...)`)
109684
110107
  */
109685
- pauseUntilReady() {
109686
- if (this.state === SERVICE_STATE.READY) return new Promise((resolve) => {
109687
- resolve();
109688
- });
109689
- return new Promise((resolve, reject) => {
109690
- const totalTimeoutMS = 7e4;
109691
- const intervalMS = 100;
109692
- let iterations = totalTimeoutMS / intervalMS;
109693
- const intervalID = globalThis.setInterval(() => {
109694
- if (iterations < 1) {
109695
- clearInterval(intervalID);
109696
- reject(`State did not become ready in ${totalTimeoutMS / 1e3} seconds`);
109697
- } else if (this.state === SERVICE_STATE.READY) {
109698
- clearInterval(intervalID);
109699
- resolve();
109700
- }
109701
- iterations -= 1;
109702
- }, intervalMS);
110108
+ cacheMetadataBlobEntry(url, entry) {
110109
+ if (!entry.aaguid) return 0;
110110
+ this.metadataCache.cacheMetadata(entry.aaguid, entry, url);
110111
+ return 1;
110112
+ }
110113
+ };
110114
+ /**
110115
+ * A basic service for coordinating interactions with the FIDO Metadata Service. This includes BLOB
110116
+ * download and parsing, and on-demand requesting and caching of individual metadata statements.
110117
+ *
110118
+ * https://fidoalliance.org/metadata/
110119
+ */
110120
+ const MetadataService = new BaseMetadataService();
110121
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/services/convenienceMetadataService.js
110122
+ const defaultURLConvenienceMDS = "https://c-mds.fidoalliance.org/";
110123
+ var BaseConvenienceMetadataService = class extends BaseMDSService {
110124
+ constructor() {
110125
+ super("ConvenienceMetadataService");
110126
+ }
110127
+ async initialize(opts = {}) {
110128
+ const { mdsServers = [defaultURLConvenienceMDS], payloads, logger } = opts;
110129
+ this.beginInitialize(logger);
110130
+ /**
110131
+ * If passkey provider metadata is provided, load them into the cache first.
110132
+ */
110133
+ if (payloads?.length) {
110134
+ let entriesAdded = 0;
110135
+ payloads.forEach((payload) => {
110136
+ entriesAdded += this.cacheConvenienceMDS("", payload);
110137
+ });
110138
+ this.logger.debug(`Cached ${entriesAdded} total local metadata entries`);
110139
+ }
110140
+ /**
110141
+ * If Convenience MDS server URLs are provided, then download and cache the current collection
110142
+ * of metadata from them.
110143
+ */
110144
+ const numServers = await this.initializeServers(mdsServers);
110145
+ this.finishInitialize(payloads?.length, numServers);
110146
+ }
110147
+ /**
110148
+ * Download the convenience metadata, which is surprisingly just a JSON document, and cache it
110149
+ */
110150
+ async downloadAndCache(url, no) {
110151
+ const resp = await this.fetchFromServer(url, no);
110152
+ if (!resp) return;
110153
+ const payload = await resp.json();
110154
+ return this.cacheConvenienceMDS(url, payload);
110155
+ }
110156
+ /**
110157
+ * Refresh failures cause that server's refresh to be re-attempted at a later date
110158
+ */
110159
+ handleRefreshFailure(url) {
110160
+ this.delayNextRefresh(url, this.defaultRetryDelayHours);
110161
+ }
110162
+ /**
110163
+ * Cache the AAGUID-keyed entries in a Convenience MDS payload. Returns the number of entries
110164
+ * cached (so you can `count += cacheConvenienceMDS(...)`)
110165
+ */
110166
+ cacheConvenienceMDS(url, payload) {
110167
+ let entriesAdded = 0;
110168
+ this.metadataCache.clearMetadataByURL(url);
110169
+ Object.keys(payload).forEach((aaguid) => {
110170
+ if (aaguid === "no") return;
110171
+ this.metadataCache.cacheMetadata(aaguid, payload[aaguid], url);
110172
+ entriesAdded += 1;
109703
110173
  });
110174
+ this.metadataCache.registerMDSServer(url, payload.no, new Date(Date.now() + 36e5 * this.defaultRefreshDelayHours));
110175
+ return entriesAdded;
109704
110176
  }
109705
110177
  /**
109706
- * Report service status on change
110178
+ * Get a collection of metadata about a credential manager, including localized name(s) and
110179
+ * light and dark iconography when available. Returns `undefined` if no such metadata has been
110180
+ * registered with a Convenience MDS.
109707
110181
  */
109708
- setState(newState) {
109709
- this.state = newState;
109710
- if (newState === SERVICE_STATE.DISABLED) this.logger.debug("MetadataService is DISABLED");
109711
- else if (newState === SERVICE_STATE.REFRESHING) this.logger.debug("MetadataService is REFRESHING");
109712
- else if (newState === SERVICE_STATE.READY) this.logger.debug("MetadataService is READY");
110182
+ async getProviderMetadata(aaguid) {
110183
+ if (this.state.current === SERVICE_STATE.DISABLED) return;
110184
+ await this.state.pauseUntilReady();
110185
+ await this.refreshStaleServers();
110186
+ return this.metadataCache.getMetadata(aaguid);
109713
110187
  }
109714
110188
  };
109715
110189
  /**
109716
- * A basic service for coordinating interactions with the FIDO Metadata Service. This includes BLOB
109717
- * download and parsing, and on-demand requesting and caching of individual metadata statements.
110190
+ * A basic service for coordinating interactions with the FIDO Convenience Metadata Service. This
110191
+ * includes metadata download and parsing, and on-demand requesting and caching of provider details.
109718
110192
  *
109719
110193
  * https://fidoalliance.org/metadata/
109720
110194
  */
109721
- const MetadataService = new BaseMetadataService();
109722
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/metadata/verifyAttestationWithMetadata.js
110195
+ const ConvenienceMetadataService = new BaseConvenienceMetadataService();
110196
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/registration/verifications/verifyAttestationFIDOU2F.js
110197
+ /**
110198
+ * Verify an attestation response with fmt 'fido-u2f'
110199
+ */
110200
+ async function verifyAttestationFIDOU2F(options) {
110201
+ const { attStmt, clientDataHash, rpIdHash, credentialID, credentialPublicKey, aaguid, rootCertificates } = options;
110202
+ const signatureBase = concat([
110203
+ Uint8Array.from([0]),
110204
+ rpIdHash,
110205
+ clientDataHash,
110206
+ credentialID,
110207
+ convertCOSEtoPKCS(credentialPublicKey)
110208
+ ]);
110209
+ const sig = attStmt.get("sig");
110210
+ const x5c = attStmt.get("x5c");
110211
+ if (!x5c) throw new Error("No attestation certificate provided in attestation statement (FIDOU2F)");
110212
+ if (!sig) throw new Error("No attestation signature provided in attestation statement (FIDOU2F)");
110213
+ const aaguidToHex = Number.parseInt(toHex(aaguid), 16);
110214
+ if (aaguidToHex !== 0) throw new Error(`AAGUID "${aaguidToHex}" was not expected value`);
110215
+ try {
110216
+ await validateCertificatePath(x5c.map(convertCertBufferToPEM), rootCertificates);
110217
+ } catch (err) {
110218
+ throw new Error(`${err.message} (FIDOU2F)`);
110219
+ }
110220
+ return verifySignature({
110221
+ signature: sig,
110222
+ data: signatureBase,
110223
+ x509Certificate: x5c[0],
110224
+ hashAlgorithm: COSEALG.ES256
110225
+ });
110226
+ }
110227
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/validateExtFIDOGenCEAAGUID.js
110228
+ /**
110229
+ * Attestation Certificate Extension OID: `id-fido-gen-ce-aaguid`
110230
+ *
110231
+ * Sourced from https://fidoalliance.org/specs/fido-v2.0-ps-20150904/fido-key-attestation-v2.0-ps-20150904.html#verifying-an-attestation-statement
110232
+ */
110233
+ const id_fido_gen_ce_aaguid = "1.3.6.1.4.1.45724.1.1.4";
110234
+ /**
110235
+ * Look for the id-fido-gen-ce-aaguid certificate extension. If it's present then check it against
110236
+ * the attestation statement AAGUID.
110237
+ */
110238
+ function validateExtFIDOGenCEAAGUID(certExtensions, aaguid) {
110239
+ if (!certExtensions) return true;
110240
+ const extFIDOGenCEAAGUID = certExtensions.find((ext) => ext.extnID === id_fido_gen_ce_aaguid);
110241
+ if (!extFIDOGenCEAAGUID) return true;
110242
+ const parsedExtFIDOGenCEAAGUID = import_cjs$4.AsnParser.parse(extFIDOGenCEAAGUID.extnValue, import_cjs$4.OctetString);
110243
+ const extValue = new Uint8Array(parsedExtFIDOGenCEAAGUID.buffer);
110244
+ if (!areEqual(aaguid, extValue)) {
110245
+ const _debugExtHex = toHex(extValue);
110246
+ const _debugAAGUIDHex = toHex(aaguid);
110247
+ throw new Error(`Certificate extension id-fido-gen-ce-aaguid (${id_fido_gen_ce_aaguid}) value of "${_debugExtHex}" was present but not equal to attestation statement AAGUID value of "${_debugAAGUIDHex}"`);
110248
+ }
110249
+ return true;
110250
+ }
110251
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/metadata/verifyAttestationWithMetadata.js
109723
110252
  /**
109724
110253
  * Match properties of the authenticator's attestation statement against expected values as
109725
110254
  * registered with the FIDO Alliance Metadata Service
@@ -109880,7 +110409,7 @@ function stringifyCOSEInfo(info) {
109880
110409
  else toReturn = `{ kty: ${kty}, alg: ${alg} }`;
109881
110410
  return toReturn;
109882
110411
  }
109883
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/registration/verifications/verifyAttestationPacked.js
110412
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/registration/verifications/verifyAttestationPacked.js
109884
110413
  /**
109885
110414
  * Verify an attestation response with fmt 'packed'
109886
110415
  */
@@ -109945,7 +110474,7 @@ async function verifyAttestationPacked(options) {
109945
110474
  });
109946
110475
  return verified;
109947
110476
  }
109948
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/registration/verifications/verifyAttestationAndroidSafetyNet.js
110477
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/registration/verifications/verifyAttestationAndroidSafetyNet.js
109949
110478
  /**
109950
110479
  * Verify an attestation response with fmt 'android-safetynet'
109951
110480
  */
@@ -110014,7 +110543,7 @@ async function verifyAttestationAndroidSafetyNet(options) {
110014
110543
  hashAlgorithm: alg
110015
110544
  });
110016
110545
  }
110017
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/registration/verifications/tpm/constants.js
110546
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/registration/verifications/tpm/constants.js
110018
110547
  /**
110019
110548
  * A whole lotta domain knowledge is captured here, with hazy connections to source
110020
110549
  * documents. Good places to start searching for more info on these values are the
@@ -110233,13 +110762,13 @@ const TPM_MANUFACTURERS = {
110233
110762
  * Match TPM public area curve ID's to `crv` numbers used in COSE public keys
110234
110763
  */
110235
110764
  const TPM_ECC_CURVE_COSE_CRV_MAP = {
110236
- TPM_ECC_NIST_P256: 1,
110237
- TPM_ECC_NIST_P384: 2,
110238
- TPM_ECC_NIST_P521: 3,
110239
- TPM_ECC_BN_P256: 1,
110240
- TPM_ECC_SM2_P256: 1
110765
+ TPM_ECC_NIST_P256: COSECRV.P256,
110766
+ TPM_ECC_NIST_P384: COSECRV.P384,
110767
+ TPM_ECC_NIST_P521: COSECRV.P521,
110768
+ TPM_ECC_BN_P256: COSECRV.P256,
110769
+ TPM_ECC_SM2_P256: COSECRV.P256
110241
110770
  };
110242
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/registration/verifications/tpm/parseCertInfo.js
110771
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/registration/verifications/tpm/parseCertInfo.js
110243
110772
  /**
110244
110773
  * Cut up a TPM attestation's certInfo into intelligible chunks
110245
110774
  */
@@ -110291,7 +110820,7 @@ function parseCertInfo(certInfo) {
110291
110820
  }
110292
110821
  };
110293
110822
  }
110294
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/registration/verifications/tpm/parsePubArea.js
110823
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/registration/verifications/tpm/parsePubArea.js
110295
110824
  /**
110296
110825
  * Break apart a TPM attestation's pubArea buffer
110297
110826
  *
@@ -110352,6 +110881,27 @@ function parsePubArea(pubArea) {
110352
110881
  pointer += 2;
110353
110882
  const scheme = TPM_ALG[dataView.getUint16(pointer)];
110354
110883
  pointer += 2;
110884
+ /**
110885
+ * In TPM 2.0, a non-TPM_ALG_NULL scheme is followed by alg-specific "details" bytes.
110886
+ * For TPM_ALG_ECC this is defined as TPMT_ECC_SCHEME, which is the
110887
+ * scheme (TPMI_ALG_ECC_SCHEME) followed by details (TPMU_ECC_SCHEME).
110888
+ *
110889
+ * See 11.2.5.7 TPMT_ECC_SCHEME here:
110890
+ * https://medias.cdn.trustedcomputinggroup.org/production/Trusted_Platform_Module_2_0_Library_Part_2_Structures_Version_185_pub_c0a962a931.pdf >
110891
+ */
110892
+ const details = {};
110893
+ if (scheme === "TPM_ALG_NULL") {} else if (scheme === "TPM_ALG_ECDSA") {
110894
+ details.hashAlg = TPM_ALG[dataView.getUint16(pointer)];
110895
+ pointer += 2;
110896
+ } else if (scheme === "TPM_ALG_ECSCHNORR") {
110897
+ details.hashAlg = TPM_ALG[dataView.getUint16(pointer)];
110898
+ pointer += 2;
110899
+ } else if (scheme === "TPM_ALG_ECDAA") {
110900
+ details.hashAlg = TPM_ALG[dataView.getUint16(pointer)];
110901
+ pointer += 2;
110902
+ details.count = dataView.getUint16(pointer);
110903
+ pointer += 2;
110904
+ }
110355
110905
  const curveID = TPM_ECC_CURVE[dataView.getUint16(pointer)];
110356
110906
  pointer += 2;
110357
110907
  const kdf = TPM_ALG[dataView.getUint16(pointer)];
@@ -110359,6 +110909,7 @@ function parsePubArea(pubArea) {
110359
110909
  parameters.ecc = {
110360
110910
  symmetric,
110361
110911
  scheme,
110912
+ details,
110362
110913
  curveID,
110363
110914
  kdf
110364
110915
  };
@@ -110382,12 +110933,12 @@ function parsePubArea(pubArea) {
110382
110933
  unique
110383
110934
  };
110384
110935
  }
110385
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/registration/verifications/tpm/isValidTPMManufacturerID.js
110936
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/registration/verifications/tpm/isValidTPMManufacturerID.js
110386
110937
  function getTPMManufacturerInfo(id) {
110387
110938
  const _normalized = `id:${id.substring(3).toUpperCase()}`;
110388
110939
  return TPM_MANUFACTURERS[_normalized];
110389
110940
  }
110390
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/registration/verifications/tpm/verifyAttestationTPM.js
110941
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/registration/verifications/tpm/verifyAttestationTPM.js
110391
110942
  async function verifyAttestationTPM(options) {
110392
110943
  const { aaguid, attStmt, authData, credentialPublicKey, clientDataHash, rootCertificates } = options;
110393
110944
  const ver = attStmt.get("ver");
@@ -110422,17 +110973,19 @@ async function verifyAttestationTPM(options) {
110422
110973
  if (pubAreaExponent !== eSum) throw new Error(`Unexpected public key exp ${eSum}, expected ${pubAreaExponent} (TPM|RSA)`);
110423
110974
  } else if (pubType === "TPM_ALG_ECC") {
110424
110975
  if (!isCOSEPublicKeyEC2(cosePublicKey)) throw new Error(`Credential public key with kty ${cosePublicKey.get(COSEKEYS.kty)} did not match ${pubType}`);
110425
- const crv = cosePublicKey.get(COSEKEYS.crv);
110426
- const x = cosePublicKey.get(COSEKEYS.x);
110427
- const y = cosePublicKey.get(COSEKEYS.y);
110428
- if (!crv) throw new Error("COSE public key missing crv (TPM|ECC)");
110429
- if (!x) throw new Error("COSE public key missing x (TPM|ECC)");
110430
- if (!y) throw new Error("COSE public key missing y (TPM|ECC)");
110431
- if (!areEqual(unique, concat([x, y]))) throw new Error("PubArea unique is not same as public key x and y (TPM|ECC)");
110976
+ const pubKeyAlg = cosePublicKey.get(COSEKEYS.alg);
110977
+ const pubKeyCrv = cosePublicKey.get(COSEKEYS.crv);
110978
+ const pubKeyX = cosePublicKey.get(COSEKEYS.x);
110979
+ const pubKeyY = cosePublicKey.get(COSEKEYS.y);
110980
+ if (!pubKeyAlg) throw new Error("COSE public key missing crv (TPM|ECC)");
110981
+ if (!pubKeyCrv) throw new Error("COSE public key missing crv (TPM|ECC)");
110982
+ if (!pubKeyX) throw new Error("COSE public key missing x (TPM|ECC)");
110983
+ if (!pubKeyY) throw new Error("COSE public key missing y (TPM|ECC)");
110984
+ if (!areEqual(unique, concat([pubKeyX, pubKeyY]))) throw new Error("PubArea unique is not same as public key x and y (TPM|ECC)");
110432
110985
  if (!parameters.ecc) throw new Error(`Parsed pubArea type is ECC, but missing parameters.ecc (TPM|ECC)`);
110433
110986
  const pubAreaCurveID = parameters.ecc.curveID;
110434
110987
  const pubAreaCurveIDMapToCOSECRV = TPM_ECC_CURVE_COSE_CRV_MAP[pubAreaCurveID];
110435
- if (pubAreaCurveIDMapToCOSECRV !== crv) throw new Error(`Public area key curve ID "${pubAreaCurveID}" mapped to "${pubAreaCurveIDMapToCOSECRV}" which did not match public key crv of "${crv}" (TPM|ECC)`);
110988
+ if (pubAreaCurveIDMapToCOSECRV !== pubKeyCrv) throw new Error(`Public area key curve ID "${pubAreaCurveID}" mapped to "${pubAreaCurveIDMapToCOSECRV}" which did not match public key crv of "${pubKeyCrv}" (TPM|ECC)`);
110436
110989
  } else throw new Error(`Unsupported pubArea.type "${pubType}"`);
110437
110990
  const { magic, type: certType, attested, extraData } = parseCertInfo(certInfo);
110438
110991
  if (magic !== 4283712327) throw new Error(`Unexpected magic value "${magic}", expected "0xff544347" (TPM)`);
@@ -111068,7 +111621,7 @@ var require_attestation = /* @__PURE__ */ __commonJSMin(((exports) => {
111068
111621
  repeated: "set"
111069
111622
  })], AttestationApplicationId.prototype, "signatureDigests", void 0);
111070
111623
  }));
111071
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/registration/verifications/verifyAttestationAndroidKey.js
111624
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/registration/verifications/verifyAttestationAndroidKey.js
111072
111625
  var import_cjs = (/* @__PURE__ */ __commonJSMin(((exports) => {
111073
111626
  Object.defineProperty(exports, "__esModule", { value: true });
111074
111627
  const tslib_1 = (init_tslib_es6$1(), __toCommonJS(tslib_es6_exports$1));
@@ -111110,7 +111663,7 @@ async function verifyAttestationAndroidKey(options) {
111110
111663
  * (i.e. These shouldn't contain the [600] tag)
111111
111664
  */
111112
111665
  if (teeEnforced.allApplications !== void 0) throw new Error("teeEnforced contained \"allApplications [600]\" tag (Android Key)");
111113
- if (softwareEnforced.allApplications !== void 0) throw new Error("teeEnforced contained \"allApplications [600]\" tag (Android Key)");
111666
+ if (softwareEnforced.allApplications !== void 0) throw new Error("softwareEnforced contained \"allApplications [600]\" tag (Android Key)");
111114
111667
  const statement = await MetadataService.getStatement(aaguid);
111115
111668
  if (statement) try {
111116
111669
  await verifyAttestationWithMetadata({
@@ -111125,22 +111678,30 @@ async function verifyAttestationAndroidKey(options) {
111125
111678
  }
111126
111679
  else {
111127
111680
  /**
111128
- * Verify that x5c contains a full certificate path.
111681
+ * Fail closed if for some reason no root certificates were registered with SettingsService
111682
+ * for this attestation format. Android Key attestation statements are a bit unique in that they
111683
+ * contain a full certificate chain, which an attacker could abuse to perform arbitrary network
111684
+ * requests within the RP's boundary if we simply validated x5c like other attestation formats.
111129
111685
  */
111686
+ if (rootCertificates.length === 0) throw new Error("No root certificates were set with SettingsService for \"android-key\" attestation (Android Key)");
111130
111687
  const x5cNoRootPEM = x5c.slice(0, -1).map(convertCertBufferToPEM);
111131
111688
  const x5cRootPEM = x5c.slice(-1).map(convertCertBufferToPEM);
111689
+ /**
111690
+ * Make sure the final cert in x5c is one of the Google Hardware Attestation Root certificates
111691
+ * before we attempt to validate the certificate chain.
111692
+ *
111693
+ * https://developer.android.com/privacy-and-security/security-key-attestation#root_certificate
111694
+ */
111695
+ if (rootCertificates.indexOf(x5cRootPEM[0]) < 0) throw new Error("x5c root certificate was not a known root certificate (Android Key)");
111696
+ /**
111697
+ * Verify that x5c contains a full certificate path.
111698
+ */
111132
111699
  try {
111133
111700
  await validateCertificatePath(x5cNoRootPEM, x5cRootPEM);
111134
111701
  } catch (err) {
111135
111702
  const _err = err;
111136
111703
  throw new Error(`${_err.message} (Android Key)`, { cause: _err });
111137
111704
  }
111138
- /**
111139
- * Make sure the root certificate is one of the Google Hardware Attestation Root certificates
111140
- *
111141
- * https://developer.android.com/privacy-and-security/security-key-attestation#root_certificate
111142
- */
111143
- if (rootCertificates.length > 0 && rootCertificates.indexOf(x5cRootPEM[0]) < 0) throw new Error("x5c root certificate was not a known root certificate (Android Key)");
111144
111705
  }
111145
111706
  return verifySignature({
111146
111707
  signature: sig,
@@ -111149,7 +111710,7 @@ async function verifyAttestationAndroidKey(options) {
111149
111710
  hashAlgorithm: alg
111150
111711
  });
111151
111712
  }
111152
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/registration/verifications/verifyAttestationApple.js
111713
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/registration/verifications/verifyAttestationApple.js
111153
111714
  async function verifyAttestationApple(options) {
111154
111715
  const { attStmt, authData, clientDataHash, credentialPublicKey, rootCertificates } = options;
111155
111716
  const x5c = attStmt.get("x5c");
@@ -111170,7 +111731,42 @@ async function verifyAttestationApple(options) {
111170
111731
  if (!areEqual(convertCOSEtoPKCS(credentialPublicKey), new Uint8Array(subjectPublicKeyInfo.subjectPublicKey))) throw new Error("Credential public key does not equal credCert public key (Apple)");
111171
111732
  return true;
111172
111733
  }
111173
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/registration/verifyRegistrationResponse.js
111734
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/assertValidExpectedOrigin.js
111735
+ /**
111736
+ * Check the origin to make sure it's valid to compare against what's reported in a WebAuthn
111737
+ * response.
111738
+ *
111739
+ * Invalid origins will raise a `SimpleWebAuthnError` with `code: 'BAD_ARGUMENT'`
111740
+ */
111741
+ function assertValidExpectedOrigin(origin) {
111742
+ if (!origin.startsWith("https://")) return;
111743
+ if (origin.endsWith("/")) throw new SimpleWebAuthnError({
111744
+ message: `"${origin}" is not a valid expected origin. Remove the trailing "/" and try again`,
111745
+ code: "BAD_ARGUMENT"
111746
+ });
111747
+ const asciiOrigin = new URL(origin).origin;
111748
+ if (asciiOrigin !== origin) throw new SimpleWebAuthnError({
111749
+ message: `"${origin}" is not a valid expected origin. Replace it with its ASCII punycode representation "${asciiOrigin}" and try again`,
111750
+ code: "BAD_ARGUMENT"
111751
+ });
111752
+ }
111753
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/helpers/matchExpectedOrigin.js
111754
+ /**
111755
+ * Check that the origin reported in a WebAuthn response is an expected one.
111756
+ *
111757
+ * Raises a `SimpleWebAuthnError` if not match is found.
111758
+ */
111759
+ function matchExpectedOrigin(origin, expectedOrigin) {
111760
+ let _expectedOrigins = [];
111761
+ if (typeof expectedOrigin === "string") _expectedOrigins = [expectedOrigin];
111762
+ else _expectedOrigins = expectedOrigin;
111763
+ for (const _origin of _expectedOrigins) assertValidExpectedOrigin(_origin);
111764
+ if (!_expectedOrigins.includes(origin)) throw new SimpleWebAuthnError({
111765
+ message: `Unexpected response origin "${origin}", expected one of: ${_expectedOrigins.join(", ")}`,
111766
+ code: "UNEXPECTED_ORIGIN"
111767
+ });
111768
+ }
111769
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/registration/verifyRegistrationResponse.js
111174
111770
  /**
111175
111771
  * Verify that the user has legitimately completed the registration process
111176
111772
  *
@@ -111205,9 +111801,7 @@ async function verifyRegistrationResponse(options) {
111205
111801
  if (typeof expectedChallenge === "function") {
111206
111802
  if (!await expectedChallenge(challenge)) throw new Error(`Custom challenge verifier returned false for registration response challenge "${challenge}"`);
111207
111803
  } else if (challenge !== expectedChallenge) throw new Error(`Unexpected registration response challenge "${challenge}", expected "${expectedChallenge}"`);
111208
- if (Array.isArray(expectedOrigin)) {
111209
- if (!expectedOrigin.includes(origin)) throw new Error(`Unexpected registration response origin "${origin}", expected one of: ${expectedOrigin.join(", ")}`);
111210
- } else if (origin !== expectedOrigin) throw new Error(`Unexpected registration response origin "${origin}", expected "${expectedOrigin}"`);
111804
+ matchExpectedOrigin(origin, expectedOrigin);
111211
111805
  if (tokenBinding) {
111212
111806
  if (typeof tokenBinding !== "object") throw new Error(`Unexpected value for TokenBinding "${tokenBinding}"`);
111213
111807
  if ([
@@ -111277,11 +111871,13 @@ async function verifyRegistrationResponse(options) {
111277
111871
  } else throw new Error(`Unsupported Attestation Format: ${fmt}`);
111278
111872
  if (!verified) return { verified: false };
111279
111873
  const { credentialDeviceType, credentialBackedUp } = parseBackupFlags(flags);
111874
+ const formattedAAGUID = convertAAGUIDToString(aaguid);
111280
111875
  return {
111281
111876
  verified: true,
111282
111877
  registrationInfo: {
111283
111878
  fmt,
111284
- aaguid: convertAAGUIDToString(aaguid),
111879
+ aaguid: formattedAAGUID,
111880
+ passkeyProviderMetadata: await MetadataService.getProviderMetadata(formattedAAGUID) ?? await ConvenienceMetadataService.getProviderMetadata(formattedAAGUID),
111285
111881
  credentialType,
111286
111882
  credential: {
111287
111883
  id: fromBuffer(credentialID),
@@ -111299,7 +111895,7 @@ async function verifyRegistrationResponse(options) {
111299
111895
  }
111300
111896
  };
111301
111897
  }
111302
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/authentication/generateAuthenticationOptions.js
111898
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/authentication/generateAuthenticationOptions.js
111303
111899
  /**
111304
111900
  * Prepare a value to pass into navigator.credentials.get(...) for authenticator authentication
111305
111901
  *
@@ -111335,7 +111931,7 @@ async function generateAuthenticationOptions(options) {
111335
111931
  extensions
111336
111932
  };
111337
111933
  }
111338
- // ../../node_modules/.pnpm/@simplewebauthn+server@14.0.3/node_modules/@simplewebauthn/server/esm/authentication/verifyAuthenticationResponse.js
111934
+ // ../../node_modules/.pnpm/@simplewebauthn+server@14.1.0/node_modules/@simplewebauthn/server/esm/authentication/verifyAuthenticationResponse.js
111339
111935
  /**
111340
111936
  * Verify that the user has legitimately completed the authentication process
111341
111937
  *
@@ -111399,12 +111995,7 @@ async function verifyAuthenticationResponse(options) {
111399
111995
  * See https://w3c.github.io/webauthn/#dom-collectedclientdata-toporigin.
111400
111996
  */
111401
111997
  throw new Error(`Unexpected top origin of "${topOrigin}" within a non-cross-origin authentication response. This error should be reported to the browser vendor as a WebAuthn specification violation with a link to https://w3c.github.io/webauthn/#dom-collectedclientdata-toporigin`);
111402
- if (Array.isArray(expectedOrigin)) {
111403
- if (!expectedOrigin.includes(origin)) {
111404
- const joinedExpectedOrigin = expectedOrigin.join(", ");
111405
- throw new Error(`Unexpected authentication response origin "${origin}", expected one of: ${joinedExpectedOrigin}`);
111406
- }
111407
- } else if (origin !== expectedOrigin) throw new Error(`Unexpected authentication response origin "${origin}", expected "${expectedOrigin}"`);
111998
+ matchExpectedOrigin(origin, expectedOrigin);
111408
111999
  if (!isBase64URL(assertionResponse.authenticatorData)) throw new Error("Credential response authenticatorData was not a base64url string");
111409
112000
  if (!isBase64URL(assertionResponse.signature)) throw new Error("Credential response signature was not a base64url string");
111410
112001
  if (assertionResponse.userHandle && typeof assertionResponse.userHandle !== "string") throw new Error("Credential response userHandle was not a string");