@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.
- package/dist/{dist-JmuFs-U5.mjs → dist-mmJDfwXE.js} +335 -8
- package/dist/{dist-CXCR7sEk.js → dist-suALViLT.mjs} +276 -37
- package/dist/magic-link/auth-magic-link.addon.js +104 -30
- package/dist/magic-link/auth-magic-link.addon.mjs +104 -30
- package/dist/oidc/auth-oidc.addon.js +36 -8
- package/dist/oidc/auth-oidc.addon.mjs +36 -8
- package/dist/webauthn/_stub.js +568 -0
- package/dist/webauthn/_virtual_mf-localSharedImportMap___mfe_internal__addon_auth_webauthn_widgets-Bg_T1-iY.mjs +156 -0
- 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
- 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
- package/dist/webauthn/_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare__react__loadShare__.js-BIIa6vDX.mjs +26 -0
- 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
- package/dist/webauthn/auth-webauthn.addon.js +141 -5
- package/dist/webauthn/auth-webauthn.addon.mjs +136 -37
- package/dist/webauthn/dist-CYZr2fwk.mjs +2726 -0
- package/dist/webauthn/hostInit-Boe91Eeg.mjs +129 -0
- package/dist/webauthn/remoteEntry.js +134 -0
- package/dist/webauthn/remoteEntry.ssr.js +33 -0
- package/dist/webauthn/virtualExposes-Ckj56FAf.mjs +27 -0
- package/dist/webauthn/virtual_mf-exposes-ssr___mfe_internal__addon_auth_webauthn_widgets__remoteEntry_js-C5AzEzK5.mjs +10 -0
- package/package.json +30 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as BaseAddon,
|
|
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/
|
|
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
|
-
*
|
|
12282
|
-
*
|
|
12283
|
-
*
|
|
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
|
-
|
|
12344
|
-
|
|
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";
|