@camstack/addon-auth 1.1.1 → 1.1.3

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.
Files changed (21) hide show
  1. package/dist/{dist-JmuFs-U5.mjs → dist-mmJDfwXE.js} +335 -8
  2. package/dist/{dist-CXCR7sEk.js → dist-suALViLT.mjs} +276 -37
  3. package/dist/magic-link/auth-magic-link.addon.js +104 -30
  4. package/dist/magic-link/auth-magic-link.addon.mjs +104 -30
  5. package/dist/oidc/auth-oidc.addon.js +36 -8
  6. package/dist/oidc/auth-oidc.addon.mjs +36 -8
  7. package/dist/webauthn/_stub.js +568 -0
  8. package/dist/webauthn/_virtual_mf-localSharedImportMap___mfe_internal__addon_auth_webauthn_widgets-Bg_T1-iY.mjs +156 -0
  9. package/dist/webauthn/_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-EnxrfqY5.mjs +26 -0
  10. package/dist/webauthn/_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-CQ-aEQ9b.mjs +26 -0
  11. package/dist/webauthn/_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare__react__loadShare__.js-BIIa6vDX.mjs +26 -0
  12. package/dist/webauthn/_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-BL2etuqg.mjs +26 -0
  13. package/dist/webauthn/auth-webauthn.addon.js +141 -5
  14. package/dist/webauthn/auth-webauthn.addon.mjs +136 -37
  15. package/dist/webauthn/dist-CYZr2fwk.mjs +2726 -0
  16. package/dist/webauthn/hostInit-Boe91Eeg.mjs +129 -0
  17. package/dist/webauthn/remoteEntry.js +134 -0
  18. package/dist/webauthn/remoteEntry.ssr.js +33 -0
  19. package/dist/webauthn/virtualExposes-Ckj56FAf.mjs +27 -0
  20. package/dist/webauthn/virtual_mf-exposes-ssr___mfe_internal__addon_auth_webauthn_widgets__remoteEntry_js-C5AzEzK5.mjs +10 -0
  21. package/package.json +30 -5
@@ -1,4 +1,4 @@
1
- import { a as BaseAddon, r as userPasskeysCapability } from "../dist-JmuFs-U5.mjs";
1
+ import { a as userPasskeysCapability, c as array, i as loginMethodCapability, l as object, n as addonWidgetsSourceCapability, s as BaseAddon, u as string } from "../dist-suALViLT.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import Stream from "stream";
4
4
  import http from "http";
@@ -12276,40 +12276,85 @@ var PasskeyStore = class {
12276
12276
  }
12277
12277
  };
12278
12278
  //#endregion
12279
- //#region src/webauthn/auth-webauthn.addon.ts
12279
+ //#region src/webauthn/widget-catalog.ts
12280
+ /** MF remote name — must match `vite.widgets.config.ts` `federation.name`. */
12281
+ var AUTH_WEBAUTHN_REMOTE_NAME = "addon_auth_webauthn_widgets";
12282
+ /** MF entry filename served at `/api/addon-widgets/auth-webauthn/<bundle>`. */
12283
+ var AUTH_WEBAUTHN_BUNDLE = "remoteEntry.js";
12284
+ /** Manifest addon id — the public bundle namespace + login-method addonId. */
12285
+ var AUTH_WEBAUTHN_ADDON_ID = "auth-webauthn";
12286
+ var authWebauthnWidgets = [{
12287
+ tab: "dashboard",
12288
+ label: "Passkeys",
12289
+ kind: "remote",
12290
+ remote: {
12291
+ remoteName: AUTH_WEBAUTHN_REMOTE_NAME,
12292
+ exposedModule: "./widgets",
12293
+ componentKey: "passkey-enrollment"
12294
+ },
12295
+ stableId: "passkey-enrollment",
12296
+ description: "Enroll and manage passkeys (WebAuthn) for your account.",
12297
+ icon: "fingerprint",
12298
+ bundle: AUTH_WEBAUTHN_BUNDLE,
12299
+ hosts: ["dashboard"],
12300
+ requires: {
12301
+ deviceContext: false,
12302
+ integrationContext: false
12303
+ },
12304
+ defaultSize: "lg",
12305
+ allowedSizes: [
12306
+ "md",
12307
+ "lg",
12308
+ "xl"
12309
+ ],
12310
+ defaultColumns: 12,
12311
+ defaultRows: 3,
12312
+ preAuth: false
12313
+ }, {
12314
+ tab: "dashboard",
12315
+ label: "Passkey login",
12316
+ kind: "remote",
12317
+ remote: {
12318
+ remoteName: AUTH_WEBAUTHN_REMOTE_NAME,
12319
+ exposedModule: "./widgets",
12320
+ componentKey: "passkey-login"
12321
+ },
12322
+ stableId: "passkey-login",
12323
+ description: "Login-page passkey second-factor ceremony.",
12324
+ icon: "fingerprint",
12325
+ bundle: AUTH_WEBAUTHN_BUNDLE,
12326
+ hosts: ["dashboard"],
12327
+ requires: {
12328
+ deviceContext: false,
12329
+ integrationContext: false
12330
+ },
12331
+ defaultSize: "sm",
12332
+ allowedSizes: ["sm"],
12333
+ defaultColumns: 4,
12334
+ defaultRows: 1,
12335
+ preAuth: true
12336
+ }];
12280
12337
  /**
12281
- * WebAuthn / Passkey authentication addon.
12282
- *
12283
- * Implements the standard two-leg ceremonies for both enrollment
12284
- * (registration) and authentication, backed by `@simplewebauthn/server`.
12285
- *
12286
- * Enrollment (admin or self):
12287
- * 1. `beginRegistration` → server returns
12288
- * PublicKeyCredentialCreationOptions w/ a random challenge.
12289
- * Stored in-memory keyed by `(userId, challenge)` w/ 5min TTL.
12290
- * 2. Browser calls `navigator.credentials.create(options)`.
12291
- * 3. `finishRegistration` → server verifies the attestation against
12292
- * the stored challenge, persists the credential (publicKey +
12293
- * counter + transports + operator-chosen label).
12294
- *
12295
- * Authentication (during 2FA login leg):
12296
- * 1. `beginAuthentication` → server returns
12297
- * PublicKeyCredentialRequestOptions, listing the user's enrolled
12298
- * credentials in `allowCredentials`.
12299
- * 2. Browser calls `navigator.credentials.get(options)`.
12300
- * 3. `finishAuthentication` → server verifies the assertion against
12301
- * the stored publicKey + counter, bumps the counter.
12302
- *
12303
- * Relying-Party id (RP ID) MUST match the hub's domain (or a parent
12304
- * of it). Defaults to `process.env.CAMSTACK_PUBLIC_ORIGIN`'s hostname;
12305
- * operator overrides via settings.
12306
- *
12307
- * Open follow-ups:
12308
- * - Login flow integration (today this addon only provides the
12309
- * cap; the auth router doesn't yet gate sessions on passkey
12310
- * verification — that's a separate piece tied to the TOTP gate).
12311
- * - Multi-device discovery (passkey-discovery flow w/ resident keys).
12338
+ * Login-method contribution the `passkey-login` widget, second-factor
12339
+ * stage. Aggregated by the public `auth.listLoginMethods` procedure,
12340
+ * which stamps a public `bundleUrl` from `addonId` + `bundle`.
12312
12341
  */
12342
+ var authWebauthnLoginMethods = [{
12343
+ kind: "widget",
12344
+ id: `${AUTH_WEBAUTHN_ADDON_ID}/passkey-login`,
12345
+ addonId: AUTH_WEBAUTHN_ADDON_ID,
12346
+ bundle: AUTH_WEBAUTHN_BUNDLE,
12347
+ remote: {
12348
+ remoteName: AUTH_WEBAUTHN_REMOTE_NAME,
12349
+ exposedModule: "./widgets",
12350
+ componentKey: "passkey-login"
12351
+ },
12352
+ stage: "second-factor"
12353
+ }];
12354
+ var EndpointsSchema = array(object({
12355
+ hostname: string(),
12356
+ url: string()
12357
+ }));
12313
12358
  var DEFAULT_CONFIG = {
12314
12359
  rpID: "",
12315
12360
  rpName: "CamStack",
@@ -12335,14 +12380,26 @@ var AuthWebauthnAddon = class extends BaseAddon {
12335
12380
  listPasskeys: async ({ userId }) => this.listPasskeys(userId),
12336
12381
  removePasskey: async ({ userId, credentialId }) => this.removePasskey(userId, credentialId)
12337
12382
  };
12383
+ const widgetsProvider = { listWidgets: async () => authWebauthnWidgets };
12384
+ const loginMethodProvider = { getLoginMethods: async () => authWebauthnLoginMethods };
12338
12385
  this.ctx.logger.info("WebAuthn passkey provider initialized", { meta: {
12339
12386
  rpID: this.resolveRpID(),
12340
12387
  rpName: this.config.rpName
12341
12388
  } });
12342
- return [{
12343
- capability: userPasskeysCapability,
12344
- provider
12345
- }];
12389
+ return [
12390
+ {
12391
+ capability: userPasskeysCapability,
12392
+ provider
12393
+ },
12394
+ {
12395
+ capability: addonWidgetsSourceCapability,
12396
+ provider: widgetsProvider
12397
+ },
12398
+ {
12399
+ capability: loginMethodCapability,
12400
+ provider: loginMethodProvider
12401
+ }
12402
+ ];
12346
12403
  }
12347
12404
  globalSettingsSchema() {
12348
12405
  return this.schema({ sections: [{
@@ -12382,6 +12439,48 @@ var AuthWebauthnAddon = class extends BaseAddon {
12382
12439
  ]
12383
12440
  }] });
12384
12441
  }
12442
+ /**
12443
+ * Surface the cluster's registered public endpoints as an RP ID /
12444
+ * origin suggestion. Fed by the `network-access` CAPABILITY (via
12445
+ * `ctx.api`) — cap-driven, never a hardcoded hostname or a specific
12446
+ * ingress addon. Injected as a read-only info banner atop the settings
12447
+ * form so the operator can pick the canonical login hostname. Degrades
12448
+ * to the bare schema when no ingress provider is installed.
12449
+ */
12450
+ async getGlobalSettings(overlay, cap, nodeId) {
12451
+ const base = await super.getGlobalSettings(overlay, cap, nodeId);
12452
+ if (!base) return base;
12453
+ const hint = await this.buildEndpointHintField();
12454
+ if (!hint) return base;
12455
+ return {
12456
+ ...base,
12457
+ sections: base.sections.map((s) => s.id === "webauthn" ? {
12458
+ ...s,
12459
+ fields: [hint, ...s.fields]
12460
+ } : s)
12461
+ };
12462
+ }
12463
+ async buildEndpointHintField() {
12464
+ try {
12465
+ const api = this.ctx.api;
12466
+ if (!api) return null;
12467
+ const raw = await api.networkAccess.listEndpoints.query();
12468
+ const parsed = EndpointsSchema.safeParse(raw);
12469
+ if (!parsed.success || parsed.data.length === 0) return null;
12470
+ const hosts = [...new Set(parsed.data.map((e) => e.hostname))].filter((h) => h.length > 0);
12471
+ const origins = [...new Set(parsed.data.map((e) => e.url.replace(/\/+$/, "")))].filter((u) => u.length > 0);
12472
+ if (hosts.length === 0) return null;
12473
+ return {
12474
+ type: "info",
12475
+ key: "detectedEndpoints",
12476
+ label: "Suggested RP ID / origin",
12477
+ content: `Detected public endpoints (from the network-access capability). Set RP ID to one canonical hostname — ${hosts.join(", ")} — and Origin to its full origin${origins.length > 0 ? ` (e.g. ${origins[0]})` : ""}. Changing RP ID invalidates every already-enrolled passkey.`,
12478
+ variant: "info"
12479
+ };
12480
+ } catch {
12481
+ return null;
12482
+ }
12483
+ }
12385
12484
  resolveRpID() {
12386
12485
  if (this.config.rpID && this.config.rpID.trim()) return this.config.rpID.trim();
12387
12486
  const origin = process.env["CAMSTACK_PUBLIC_ORIGIN"] || "http://localhost:4443";