@monotykamary/localterm-server 2.34.0 → 2.35.1

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 (80) hide show
  1. package/dist/cdp/cdp-client.d.ts +30 -0
  2. package/dist/cdp/cdp-client.d.ts.map +1 -1
  3. package/dist/cdp/cdp-client.js +80 -0
  4. package/dist/cdp/cdp-client.js.map +1 -1
  5. package/dist/constants.d.ts +17 -0
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/constants.js +27 -0
  8. package/dist/constants.js.map +1 -1
  9. package/dist/daemon-config-store.d.ts +2 -0
  10. package/dist/daemon-config-store.d.ts.map +1 -1
  11. package/dist/daemon-config-store.js +14 -1
  12. package/dist/daemon-config-store.js.map +1 -1
  13. package/dist/identity/credential-store.d.ts +18 -0
  14. package/dist/identity/credential-store.d.ts.map +1 -0
  15. package/dist/identity/credential-store.js +76 -0
  16. package/dist/identity/credential-store.js.map +1 -0
  17. package/dist/identity/factory.d.ts +3 -0
  18. package/dist/identity/factory.d.ts.map +1 -0
  19. package/dist/identity/factory.js +19 -0
  20. package/dist/identity/factory.js.map +1 -0
  21. package/dist/identity/header-provider.d.ts +3 -0
  22. package/dist/identity/header-provider.d.ts.map +1 -0
  23. package/dist/identity/header-provider.js +33 -0
  24. package/dist/identity/header-provider.js.map +1 -0
  25. package/dist/identity/oidc-provider.d.ts +4 -0
  26. package/dist/identity/oidc-provider.d.ts.map +1 -0
  27. package/dist/identity/oidc-provider.js +172 -0
  28. package/dist/identity/oidc-provider.js.map +1 -0
  29. package/dist/identity/passkey-provider.d.ts +3 -0
  30. package/dist/identity/passkey-provider.d.ts.map +1 -0
  31. package/dist/identity/passkey-provider.js +233 -0
  32. package/dist/identity/passkey-provider.js.map +1 -0
  33. package/dist/identity/proxy-allowlist.d.ts +5 -0
  34. package/dist/identity/proxy-allowlist.d.ts.map +1 -0
  35. package/dist/identity/proxy-allowlist.js +64 -0
  36. package/dist/identity/proxy-allowlist.js.map +1 -0
  37. package/dist/identity/resolve.d.ts +11 -0
  38. package/dist/identity/resolve.d.ts.map +1 -0
  39. package/dist/identity/resolve.js +57 -0
  40. package/dist/identity/resolve.js.map +1 -0
  41. package/dist/identity/session-cookie.d.ts +10 -0
  42. package/dist/identity/session-cookie.d.ts.map +1 -0
  43. package/dist/identity/session-cookie.js +92 -0
  44. package/dist/identity/session-cookie.js.map +1 -0
  45. package/dist/identity/types.d.ts +49 -0
  46. package/dist/identity/types.d.ts.map +1 -0
  47. package/dist/identity/types.js +2 -0
  48. package/dist/identity/types.js.map +1 -0
  49. package/dist/identity/user-store.d.ts +16 -0
  50. package/dist/identity/user-store.d.ts.map +1 -0
  51. package/dist/identity/user-store.js +77 -0
  52. package/dist/identity/user-store.js.map +1 -0
  53. package/dist/index.d.ts +10 -1
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +112 -31
  56. package/dist/index.js.map +1 -1
  57. package/dist/protocol.d.ts +2 -1
  58. package/dist/protocol.d.ts.map +1 -1
  59. package/dist/protocol.js +1 -1
  60. package/dist/protocol.js.map +1 -1
  61. package/dist/schemas.d.ts +79 -0
  62. package/dist/schemas.d.ts.map +1 -1
  63. package/dist/schemas.js +55 -1
  64. package/dist/schemas.js.map +1 -1
  65. package/dist/secret-store.d.ts.map +1 -1
  66. package/dist/secret-store.js +4 -1
  67. package/dist/secret-store.js.map +1 -1
  68. package/dist/session-automation.d.ts +7 -2
  69. package/dist/session-automation.d.ts.map +1 -1
  70. package/dist/session-automation.js +27 -8
  71. package/dist/session-automation.js.map +1 -1
  72. package/dist/session-manager.d.ts +20 -17
  73. package/dist/session-manager.d.ts.map +1 -1
  74. package/dist/session-manager.js +63 -44
  75. package/dist/session-manager.js.map +1 -1
  76. package/dist/utils/timing-safe-equal.d.ts +2 -0
  77. package/dist/utils/timing-safe-equal.d.ts.map +1 -0
  78. package/dist/utils/timing-safe-equal.js +12 -0
  79. package/dist/utils/timing-safe-equal.js.map +1 -0
  80. package/package.json +4 -1
@@ -0,0 +1,33 @@
1
+ import { IDENTITY_HEADER_DEFAULT, IDENTITY_PROXY_DEFAULT, IDENTITY_USER_MAX_LENGTH, } from "../constants.js";
2
+ import { createProxyAllowlist } from "./proxy-allowlist.js";
3
+ // The identity provider that trusts a proxy-set header. Covers every external
4
+ // identity-aware proxy and self-hosted forward-auth with no in-app login flow:
5
+ // the proxy authenticates and forwards the user; localterm reads it.
6
+ //
7
+ // The header is only honored when the request's source IP is inside
8
+ // `trustedProxy` (default `"loopback"` — the common single-box deployment where
9
+ // the proxy runs on the same host as the daemon, so only loopback can reach it
10
+ // AND forge the header). A request from the proxy with no header resolves to
11
+ // the operator tier (no identity asserted): that's the CLI from loopback and
12
+ // the daemon's own CDP automation tabs, which keep full access — the admin
13
+ // parity a shared gateway needs. So `denyUnauthenticated` is false: a
14
+ // trusted-proxy request with no header is the operator, not a rejection.
15
+ export const createHeaderIdentityProvider = (config) => {
16
+ const header = config.header?.trim() || IDENTITY_HEADER_DEFAULT;
17
+ const allowlist = createProxyAllowlist(config.trustedProxy?.trim() || IDENTITY_PROXY_DEFAULT);
18
+ return {
19
+ kind: "header",
20
+ denyUnauthenticated: false,
21
+ operatorToken: null,
22
+ identify: (context, sourceIp) => {
23
+ const value = context.req.header(header);
24
+ if (!value)
25
+ return null;
26
+ if (!sourceIp || !allowlist.contains(sourceIp))
27
+ return null;
28
+ const user = value.trim().slice(0, IDENTITY_USER_MAX_LENGTH);
29
+ return user ? { user } : null;
30
+ },
31
+ };
32
+ };
33
+ //# sourceMappingURL=header-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"header-provider.js","sourceRoot":"","sources":["../../src/identity/header-provider.ts"],"names":[],"mappings":"AACA,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,oBAAoB,EAAuB,MAAM,sBAAsB,CAAC;AAEjF,8EAA8E;AAC9E,+EAA+E;AAC/E,qEAAqE;AACrE,EAAE;AACF,oEAAoE;AACpE,gFAAgF;AAChF,+EAA+E;AAC/E,6EAA6E;AAC7E,6EAA6E;AAC7E,2EAA2E;AAC3E,sEAAsE;AACtE,yEAAyE;AACzE,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,MAA4B,EAAoB,EAAE;IAC7F,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,uBAAuB,CAAC;IAChE,MAAM,SAAS,GAAmB,oBAAoB,CACpD,MAAM,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,sBAAsB,CACtD,CAAC;IACF,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,mBAAmB,EAAE,KAAK;QAC1B,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,CAAC,OAAgB,EAAE,QAAuB,EAAmB,EAAE;YACvE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC;YACxB,IAAI,CAAC,QAAQ,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC5D,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,wBAAwB,CAAC,CAAC;YAC7D,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAChC,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { IdentityProvider, IdentityProviderDeps, OidcIdentityConfig } from "./types.js";
2
+ export declare const sanitizeReturnTo: (value: string | null) => string;
3
+ export declare const createOidcIdentityProvider: (config: OidcIdentityConfig, deps: IdentityProviderDeps) => IdentityProvider;
4
+ //# sourceMappingURL=oidc-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oidc-provider.d.ts","sourceRoot":"","sources":["../../src/identity/oidc-provider.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEV,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAqCpB,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,GAAG,IAAI,KAAG,MAGvD,CAAC;AA4IF,eAAO,MAAM,0BAA0B,GACrC,QAAQ,kBAAkB,EAC1B,MAAM,oBAAoB,KACzB,gBA6CF,CAAC"}
@@ -0,0 +1,172 @@
1
+ import { Hono } from "hono";
2
+ import * as oauth from "oauth4webapi";
3
+ import { AUTH_STATE_TTL_MS, IDENTITY_USER_MAX_LENGTH } from "../constants.js";
4
+ import { clearSessionCookie, readSessionIdentity, setSessionCookie } from "./session-cookie.js";
5
+ class OidcStateStore {
6
+ states = new Map();
7
+ set(state, entry) {
8
+ this.states.set(state, entry);
9
+ const now = Date.now();
10
+ for (const [key, value] of this.states) {
11
+ if (value.expiresAt < now)
12
+ this.states.delete(key);
13
+ }
14
+ }
15
+ consume(state) {
16
+ const entry = this.states.get(state);
17
+ this.states.delete(state);
18
+ if (!entry || entry.expiresAt < Date.now())
19
+ return null;
20
+ return entry;
21
+ }
22
+ }
23
+ // Only allow same-origin relative paths as the post-login landing target, to
24
+ // keep the callback from being an open redirect: a value must start with `/`
25
+ // and not `//` (a protocol-relative URL the browser would treat as absolute).
26
+ export const sanitizeReturnTo = (value) => {
27
+ if (!value || !value.startsWith("/") || value.startsWith("//"))
28
+ return "/";
29
+ return value;
30
+ };
31
+ const buildRedirectUri = (origin) => `${origin.replace(/\/$/, "")}/auth/oidc/callback`;
32
+ const buildOidcRoutes = (deps) => {
33
+ const app = new Hono();
34
+ // GET /oidc/login?returnTo=<path> — kick off the auth-code flow: mint PKCE +
35
+ // state + nonce, remember them against `state`, 302 to the IdP's authz
36
+ // endpoint. The `redirect_uri` is the daemon's announced origin + this
37
+ // callback path, which must be registered with the IdP — so OIDC needs a
38
+ // stable announced origin (the tailnet/local-https surface), unlike passkey
39
+ // which binds to whatever origin the browser is on.
40
+ app.get("/oidc/login", async (context) => {
41
+ const origin = deps.getOrigin();
42
+ if (!origin)
43
+ return context.json({ error: "no_origin" }, 500);
44
+ let metadata;
45
+ try {
46
+ metadata = await deps.getMetadata();
47
+ }
48
+ catch {
49
+ return context.json({ error: "issuer_unreachable" }, 502);
50
+ }
51
+ if (!metadata.authorization_endpoint) {
52
+ return context.json({ error: "issuer_unsupported" }, 502);
53
+ }
54
+ const redirectUri = buildRedirectUri(origin);
55
+ const codeVerifier = oauth.generateRandomCodeVerifier();
56
+ const codeChallenge = await oauth.calculatePKCECodeChallenge(codeVerifier);
57
+ const state = oauth.generateRandomState();
58
+ const nonce = oauth.generateRandomNonce();
59
+ const returnTo = sanitizeReturnTo(new URL(context.req.url).searchParams.get("returnTo"));
60
+ deps.stateStore.set(state, {
61
+ codeVerifier,
62
+ nonce,
63
+ returnTo,
64
+ expiresAt: Date.now() + AUTH_STATE_TTL_MS,
65
+ });
66
+ const params = new URLSearchParams();
67
+ params.set("client_id", deps.client.client_id);
68
+ params.set("redirect_uri", redirectUri);
69
+ params.set("response_type", "code");
70
+ params.set("scope", deps.scope);
71
+ params.set("state", state);
72
+ params.set("nonce", nonce);
73
+ params.set("code_challenge", codeChallenge);
74
+ params.set("code_challenge_method", "S256");
75
+ const authUrl = new URL(metadata.authorization_endpoint);
76
+ for (const [key, value] of params.entries()) {
77
+ authUrl.searchParams.set(key, value);
78
+ }
79
+ return context.redirect(authUrl.toString(), 302);
80
+ });
81
+ // GET /oidc/callback?code=&state= — the IdP redirects here. Consume the
82
+ // state, validate the response, exchange the code for tokens (verifying the
83
+ // ID-token nonce), fetch userinfo, and issue a session cookie for the
84
+ // configured claim (default email, falling back to `sub`). Any failure
85
+ // redirects to `/` rather than leaking an error page to the browser.
86
+ app.get("/oidc/callback", async (context) => {
87
+ const origin = deps.getOrigin();
88
+ if (!origin)
89
+ return context.redirect("/", 302);
90
+ const callbackUrl = new URL(context.req.url);
91
+ const state = callbackUrl.searchParams.get("state");
92
+ if (!state)
93
+ return context.redirect("/", 302);
94
+ const stored = deps.stateStore.consume(state);
95
+ if (!stored)
96
+ return context.redirect("/", 302);
97
+ try {
98
+ const metadata = await deps.getMetadata();
99
+ const validated = oauth.validateAuthResponse(metadata, deps.client, callbackUrl.searchParams, state);
100
+ const tokenResponse = await oauth.authorizationCodeGrantRequest(metadata, deps.client, deps.clientAuth, validated, buildRedirectUri(origin), stored.codeVerifier);
101
+ const tokens = await oauth.processAuthorizationCodeResponse(metadata, deps.client, tokenResponse, {
102
+ expectedNonce: stored.nonce,
103
+ });
104
+ const userInfo = await oauth.processUserInfoResponse(metadata, deps.client, oauth.skipSubjectCheck, await oauth.userInfoRequest(metadata, deps.client, tokens.access_token));
105
+ const raw = userInfo[deps.claim];
106
+ const user = (typeof raw === "string" ? raw : userInfo.sub).slice(0, IDENTITY_USER_MAX_LENGTH);
107
+ setSessionCookie(context, deps.secret, user);
108
+ return context.redirect(stored.returnTo, 302);
109
+ }
110
+ catch {
111
+ return context.redirect("/", 302);
112
+ }
113
+ });
114
+ app.post("/oidc/logout", (context) => {
115
+ clearSessionCookie(context);
116
+ return context.json({ ok: true });
117
+ });
118
+ app.get("/oidc/me", (context) => {
119
+ const identity = readSessionIdentity(context, deps.secret);
120
+ return context.json({ user: identity?.user ?? null });
121
+ });
122
+ return app;
123
+ };
124
+ // The bring-your-own-IdP provider: any OIDC IdP (Google, GitHub, or self-hosted
125
+ // Authentik/Zitadel/Keycloak) authenticates via an authorization-code + PKCE
126
+ // flow; localterm keeps no passwords. Like `passkey`, `identify` reads the
127
+ // signed session cookie the callback issued and `denyUnauthenticated` is true
128
+ // (the gate rejects a no-session request). Discovery is cached lazily and
129
+ // retried on failure; the `redirect_uri` is the daemon's announced origin.
130
+ export const createOidcIdentityProvider = (config, deps) => {
131
+ const issuerUrl = new URL(config.issuer);
132
+ const client = { client_id: config.clientId };
133
+ const clientAuth = config.clientSecret
134
+ ? oauth.ClientSecretPost(config.clientSecret)
135
+ : oauth.None();
136
+ const claim = config.claim ?? "email";
137
+ const scope = config.scope ?? "openid email";
138
+ const stateStore = new OidcStateStore();
139
+ const secret = deps.secret;
140
+ // Cached OIDC discovery (the IdP's metadata). Resolved once, shared across
141
+ // flows; reset to null on failure so the next attempt re-discovers rather
142
+ // than caching a bad result. A single shared promise avoids duplicate
143
+ // concurrent discoveries.
144
+ let metadataPromise = null;
145
+ const getMetadata = () => {
146
+ if (!metadataPromise) {
147
+ metadataPromise = (async () => oauth.processDiscoveryResponse(issuerUrl, await oauth.discoveryRequest(issuerUrl)))();
148
+ metadataPromise.catch(() => {
149
+ metadataPromise = null;
150
+ });
151
+ }
152
+ return metadataPromise;
153
+ };
154
+ return {
155
+ kind: "oidc",
156
+ denyUnauthenticated: true,
157
+ operatorToken: config.operatorToken ?? null,
158
+ identify: (context) => readSessionIdentity(context, secret),
159
+ routes: () => buildOidcRoutes({
160
+ issuerUrl,
161
+ client,
162
+ clientAuth,
163
+ claim,
164
+ scope,
165
+ getOrigin: deps.getOrigin,
166
+ stateStore,
167
+ secret,
168
+ getMetadata,
169
+ }),
170
+ };
171
+ };
172
+ //# sourceMappingURL=oidc-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oidc-provider.js","sourceRoot":"","sources":["../../src/identity/oidc-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { IdentityProvider, IdentityProviderDeps, PasskeyIdentityConfig } from "./types.js";
2
+ export declare const createPasskeyIdentityProvider: (config: PasskeyIdentityConfig, deps: IdentityProviderDeps) => IdentityProvider;
3
+ //# sourceMappingURL=passkey-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passkey-provider.d.ts","sourceRoot":"","sources":["../../src/identity/passkey-provider.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAEV,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AA0OpB,eAAO,MAAM,6BAA6B,GACxC,QAAQ,qBAAqB,EAC7B,MAAM,oBAAoB,KACzB,gBAwBF,CAAC"}
@@ -0,0 +1,233 @@
1
+ import path from "node:path";
2
+ import { Hono } from "hono";
3
+ import { generateAuthenticationOptions, generateRegistrationOptions, verifyAuthenticationResponse, verifyRegistrationResponse, } from "@simplewebauthn/server";
4
+ import { AUTH_CHALLENGE_TTL_MS, HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_FORBIDDEN, IDENTITY_RP_NAME_DEFAULT, IDENTITY_USERNAME_MAX_LENGTH, IDENTITY_USERNAME_MIN_LENGTH, } from "../constants.js";
5
+ import { CredentialStore } from "./credential-store.js";
6
+ import { UserStore } from "./user-store.js";
7
+ import { clearSessionCookie, readSessionIdentity, setSessionCookie } from "./session-cookie.js";
8
+ class ChallengeStore {
9
+ challenges = new Map();
10
+ set(challenge, kind) {
11
+ this.challenges.set(challenge, { kind, expiresAt: Date.now() + AUTH_CHALLENGE_TTL_MS });
12
+ const now = Date.now();
13
+ for (const [key, entry] of this.challenges) {
14
+ if (entry.expiresAt < now)
15
+ this.challenges.delete(key);
16
+ }
17
+ }
18
+ // Single-use: delete on read, return true only if it matched the expected
19
+ // kind and hadn't expired. A register challenge can't satisfy a login verify
20
+ // (and vice versa), and a consumed challenge can't be replayed.
21
+ consume(challenge, kind) {
22
+ const entry = this.challenges.get(challenge);
23
+ this.challenges.delete(challenge);
24
+ return entry?.kind === kind && entry.expiresAt >= Date.now();
25
+ }
26
+ }
27
+ const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
28
+ const readBody = async (context) => {
29
+ try {
30
+ const json = await context.req.json();
31
+ return isObject(json) ? json : {};
32
+ }
33
+ catch {
34
+ return {};
35
+ }
36
+ };
37
+ const normalizeUsername = (value) => {
38
+ if (typeof value !== "string")
39
+ return null;
40
+ const trimmed = value.trim();
41
+ if (trimmed.length < IDENTITY_USERNAME_MIN_LENGTH ||
42
+ trimmed.length > IDENTITY_USERNAME_MAX_LENGTH) {
43
+ return null;
44
+ }
45
+ return trimmed;
46
+ };
47
+ // The RP origin/id come from the browser's own Origin header (the surface the
48
+ // user is actually on), falling back to the daemon's announced origin. A
49
+ // passkey is bound to the RP ID (hostname), so this is also why a passkey
50
+ // registered on the loopback origin won't work on the tailnet origin and
51
+ // vice-versa — inherent to WebAuthn, surfaced here as expectedOrigin/RPID.
52
+ const resolveRp = (context, getOrigin) => {
53
+ const raw = context.req.header("origin") || getOrigin();
54
+ if (!raw)
55
+ return null;
56
+ try {
57
+ const url = new URL(raw);
58
+ if (!url.hostname)
59
+ return null;
60
+ return { origin: url.origin, rpID: url.hostname };
61
+ }
62
+ catch {
63
+ return null;
64
+ }
65
+ };
66
+ // Quick structural reject for the credential response the browser sends; the
67
+ // real validation is simplewebauthn's verify (which throws on malformed input,
68
+ // caught by the route). The predicate narrows to the library's exact type so
69
+ // no cast is needed at the verify call.
70
+ const isRegistrationResponse = (value) => isObject(value) && typeof value.id === "string" && isObject(value.response);
71
+ const isAuthenticationResponse = (value) => isObject(value) && typeof value.id === "string" && isObject(value.response);
72
+ const buildPasskeyRoutes = (deps) => {
73
+ const app = new Hono();
74
+ app.get("/passkey/me", (context) => {
75
+ const identity = readSessionIdentity(context, deps.secret);
76
+ return context.json({ user: identity?.user ?? null });
77
+ });
78
+ app.post("/passkey/register/options", async (context) => {
79
+ if (!deps.registrationOpen) {
80
+ return context.json({ error: "registration_closed" }, HTTP_STATUS_FORBIDDEN);
81
+ }
82
+ const body = await readBody(context);
83
+ const username = normalizeUsername(body.username);
84
+ if (!username)
85
+ return context.json({ error: "invalid_username" }, HTTP_STATUS_BAD_REQUEST);
86
+ const rp = resolveRp(context, deps.getOrigin);
87
+ if (!rp)
88
+ return context.json({ error: "invalid_origin" }, HTTP_STATUS_BAD_REQUEST);
89
+ const excludeCredentials = (deps.userStore.get(username)?.credentialIds ?? []).map((id) => ({
90
+ id,
91
+ }));
92
+ const options = await generateRegistrationOptions({
93
+ rpName: deps.rpName,
94
+ rpID: rp.rpID,
95
+ userName: username,
96
+ excludeCredentials,
97
+ authenticatorSelection: { residentKey: "preferred", userVerification: "preferred" },
98
+ });
99
+ deps.challenges.set(options.challenge, "register");
100
+ return context.json(options);
101
+ });
102
+ app.post("/passkey/register/verify", async (context) => {
103
+ if (!deps.registrationOpen) {
104
+ return context.json({ error: "registration_closed" }, HTTP_STATUS_FORBIDDEN);
105
+ }
106
+ const body = await readBody(context);
107
+ const username = normalizeUsername(body.username);
108
+ if (!username || !isRegistrationResponse(body.response)) {
109
+ return context.json({ error: "invalid_body" }, HTTP_STATUS_BAD_REQUEST);
110
+ }
111
+ const rp = resolveRp(context, deps.getOrigin);
112
+ if (!rp)
113
+ return context.json({ error: "invalid_origin" }, HTTP_STATUS_BAD_REQUEST);
114
+ const response = body.response;
115
+ let verified;
116
+ try {
117
+ verified = await verifyRegistrationResponse({
118
+ response,
119
+ expectedChallenge: (challenge) => deps.challenges.consume(challenge, "register"),
120
+ expectedOrigin: rp.origin,
121
+ expectedRPID: rp.rpID,
122
+ requireUserVerification: true,
123
+ });
124
+ }
125
+ catch {
126
+ return context.json({ error: "verification_failed" }, HTTP_STATUS_BAD_REQUEST);
127
+ }
128
+ if (!verified || !verified.verified || !verified.registrationInfo) {
129
+ return context.json({ error: "verification_failed" }, HTTP_STATUS_BAD_REQUEST);
130
+ }
131
+ const credential = verified.registrationInfo.credential;
132
+ deps.userStore.findOrCreate(username);
133
+ deps.userStore.addCredential(username, credential.id);
134
+ deps.credentialStore.put({
135
+ id: credential.id,
136
+ publicKey: Buffer.from(credential.publicKey).toString("base64"),
137
+ counter: credential.counter,
138
+ username,
139
+ });
140
+ setSessionCookie(context, deps.secret, username);
141
+ return context.json({ user: username });
142
+ });
143
+ app.post("/passkey/login/options", async (context) => {
144
+ const body = await readBody(context);
145
+ const username = normalizeUsername(body.username);
146
+ const rp = resolveRp(context, deps.getOrigin);
147
+ if (!rp)
148
+ return context.json({ error: "invalid_origin" }, HTTP_STATUS_BAD_REQUEST);
149
+ const allowCredentials = username
150
+ ? (deps.userStore.get(username)?.credentialIds ?? []).map((id) => ({ id }))
151
+ : undefined;
152
+ const options = await generateAuthenticationOptions({
153
+ rpID: rp.rpID,
154
+ allowCredentials,
155
+ userVerification: "preferred",
156
+ });
157
+ deps.challenges.set(options.challenge, "login");
158
+ return context.json(options);
159
+ });
160
+ app.post("/passkey/login/verify", async (context) => {
161
+ const body = await readBody(context);
162
+ if (!isAuthenticationResponse(body.response)) {
163
+ return context.json({ error: "invalid_body" }, HTTP_STATUS_BAD_REQUEST);
164
+ }
165
+ const response = body.response;
166
+ const rp = resolveRp(context, deps.getOrigin);
167
+ if (!rp)
168
+ return context.json({ error: "invalid_origin" }, HTTP_STATUS_BAD_REQUEST);
169
+ const stored = deps.credentialStore.get(response.id);
170
+ if (!stored)
171
+ return context.json({ error: "unknown_credential" }, HTTP_STATUS_BAD_REQUEST);
172
+ const credential = {
173
+ id: stored.id,
174
+ publicKey: Buffer.from(stored.publicKey, "base64"),
175
+ counter: stored.counter,
176
+ };
177
+ let verified;
178
+ try {
179
+ verified = await verifyAuthenticationResponse({
180
+ response,
181
+ expectedChallenge: (challenge) => deps.challenges.consume(challenge, "login"),
182
+ expectedOrigin: rp.origin,
183
+ expectedRPID: rp.rpID,
184
+ credential,
185
+ requireUserVerification: true,
186
+ });
187
+ }
188
+ catch {
189
+ return context.json({ error: "verification_failed" }, HTTP_STATUS_BAD_REQUEST);
190
+ }
191
+ if (!verified || !verified.verified) {
192
+ return context.json({ error: "verification_failed" }, HTTP_STATUS_BAD_REQUEST);
193
+ }
194
+ deps.credentialStore.updateCounter(stored.id, verified.authenticationInfo.newCounter);
195
+ setSessionCookie(context, deps.secret, stored.username);
196
+ return context.json({ user: stored.username });
197
+ });
198
+ app.post("/passkey/logout", (context) => {
199
+ clearSessionCookie(context);
200
+ return context.json({ ok: true });
201
+ });
202
+ return app;
203
+ };
204
+ // The self-contained identity provider: localterm is the identity authority.
205
+ // `identify` reads the signed session cookie the register/login flow set;
206
+ // `denyUnauthenticated: true` makes the gate reject any request without a
207
+ // valid session (401 / WS policy-violation) — unlike `header`, there's no
208
+ // operator fallback, because there's no external proxy to vouch for one.
209
+ // `routes()` is the `/auth/passkey/*` login flow mounted by the daemon.
210
+ export const createPasskeyIdentityProvider = (config, deps) => {
211
+ const rpName = config.rpName?.trim() || IDENTITY_RP_NAME_DEFAULT;
212
+ const registrationOpen = (config.registration ?? "open") === "open";
213
+ const userStore = new UserStore(path.join(deps.stateDirectory, "users.json"));
214
+ const credentialStore = new CredentialStore(path.join(deps.stateDirectory, "credentials.json"));
215
+ const challenges = new ChallengeStore();
216
+ const secret = deps.secret;
217
+ return {
218
+ kind: "passkey",
219
+ denyUnauthenticated: true,
220
+ operatorToken: config.operatorToken ?? null,
221
+ identify: (context) => readSessionIdentity(context, secret),
222
+ routes: () => buildPasskeyRoutes({
223
+ rpName,
224
+ registrationOpen,
225
+ getOrigin: deps.getOrigin,
226
+ userStore,
227
+ credentialStore,
228
+ challenges,
229
+ secret,
230
+ }),
231
+ };
232
+ };
233
+ //# sourceMappingURL=passkey-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passkey-provider.js","sourceRoot":"","sources":["../../src/identity/passkey-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface ProxyAllowlist {
2
+ contains: (ip: string) => boolean;
3
+ }
4
+ export declare const createProxyAllowlist: (spec: string) => ProxyAllowlist;
5
+ //# sourceMappingURL=proxy-allowlist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-allowlist.d.ts","sourceRoot":"","sources":["../../src/identity/proxy-allowlist.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;CACnC;AAQD,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,KAAG,cA6BnD,CAAC"}
@@ -0,0 +1,64 @@
1
+ import net from "node:net";
2
+ const IPV4_MAPPED_PREFIX = "::ffff:";
3
+ // net.BlockList checks family-strict, so a dual-stack listener hands us an
4
+ // IPv4-mapped IPv6 address (::ffff:1.2.3.4) that an IPv4 subnet rule would
5
+ // miss. Normalize it back to the v4 form so one allowlist rule covers both.
6
+ const normalizeIp = (ip) => {
7
+ if (ip.startsWith(IPV4_MAPPED_PREFIX)) {
8
+ return { address: ip.slice(IPV4_MAPPED_PREFIX.length), family: "ipv4" };
9
+ }
10
+ return { address: ip, family: ip.includes(":") ? "ipv6" : "ipv4" };
11
+ };
12
+ const parseCidr = (cidr) => {
13
+ const slash = cidr.indexOf("/");
14
+ if (slash === -1)
15
+ return null;
16
+ const address = cidr.slice(0, slash);
17
+ const prefix = Number.parseInt(cidr.slice(slash + 1), 10);
18
+ if (!Number.isInteger(prefix) || prefix < 0)
19
+ return null;
20
+ const family = address.includes(":") ? "ipv6" : "ipv4";
21
+ if (prefix > (family === "ipv4" ? 32 : 128))
22
+ return null;
23
+ return { address, prefix, family };
24
+ };
25
+ // Build a source-IP allowlist for the `header` identity provider. `spec` is one
26
+ // of the shorthands `"loopback"` (127/8, ::1) or `"private"` (RFC1918, CGNAT,
27
+ // link-local, ULA — mirrors the network-policy private check), a CIDR string
28
+ // (`"10.0.0.0/8"`, `"::1/128"`), or a bare address. The provider only honors
29
+ // the identity header when the request's source IP is in this range, so a
30
+ // direct caller forging the header from outside the proxy is ignored.
31
+ export const createProxyAllowlist = (spec) => {
32
+ const list = new net.BlockList();
33
+ if (spec === "loopback") {
34
+ list.addSubnet("127.0.0.0", 8, "ipv4");
35
+ list.addAddress("::1", "ipv6");
36
+ }
37
+ else if (spec === "private") {
38
+ list.addSubnet("127.0.0.0", 8, "ipv4");
39
+ list.addSubnet("10.0.0.0", 8, "ipv4");
40
+ list.addSubnet("172.16.0.0", 12, "ipv4");
41
+ list.addSubnet("192.168.0.0", 16, "ipv4");
42
+ list.addSubnet("100.64.0.0", 10, "ipv4");
43
+ list.addSubnet("169.254.0.0", 16, "ipv4");
44
+ list.addAddress("::1", "ipv6");
45
+ list.addSubnet("fc00::", 7, "ipv6");
46
+ list.addSubnet("fe80::", 10, "ipv6");
47
+ }
48
+ else {
49
+ const cidr = parseCidr(spec);
50
+ if (cidr) {
51
+ list.addSubnet(cidr.address, cidr.prefix, cidr.family);
52
+ }
53
+ else {
54
+ list.addAddress(spec, spec.includes(":") ? "ipv6" : "ipv4");
55
+ }
56
+ }
57
+ return {
58
+ contains: (ip) => {
59
+ const { address, family } = normalizeIp(ip);
60
+ return list.check(address, family);
61
+ },
62
+ };
63
+ };
64
+ //# sourceMappingURL=proxy-allowlist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-allowlist.js","sourceRoot":"","sources":["../../src/identity/proxy-allowlist.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAErC,2EAA2E;AAC3E,2EAA2E;AAC3E,4EAA4E;AAC5E,MAAM,WAAW,GAAG,CAAC,EAAU,EAAgD,EAAE;IAC/E,IAAI,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACtC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAC1E,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;AACrE,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,CAChB,IAAY,EACyD,EAAE;IACvE,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACzD,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IACvD,IAAI,MAAM,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACzD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACrC,CAAC,CAAC;AAMF,gFAAgF;AAChF,8EAA8E;AAC9E,6EAA6E;AAC7E,6EAA6E;AAC7E,0EAA0E;AAC1E,sEAAsE;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,IAAY,EAAkB,EAAE;IACnE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;IACjC,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACjC,CAAC;SAAM,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACzD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,CAAC,EAAU,EAAW,EAAE;YAChC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;YAC5C,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACrC,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Context } from "hono";
2
+ import type { MiddlewareHandler } from "hono";
3
+ import type { Identity, IdentityProvider, SessionOwner } from "./types.js";
4
+ export declare const getRequestSourceIp: (context: Context) => string | null;
5
+ export interface IdentityResolver {
6
+ resolve: (context: Context, sourceIp?: string | null) => Identity | null;
7
+ }
8
+ export declare const createIdentityResolver: (provider: IdentityProvider | null) => IdentityResolver;
9
+ export declare const toSessionOwner: (identity: Identity | null) => SessionOwner;
10
+ export declare const createAuthGateMiddleware: (provider: IdentityProvider | null, resolveIdentity: (context: Context, sourceIp?: string | null) => Identity | null) => MiddlewareHandler;
11
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/identity/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAI9C,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAO3E,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,KAAG,MAAM,GAAG,IAO9D,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,QAAQ,GAAG,IAAI,CAAC;CAC1E;AASD,eAAO,MAAM,sBAAsB,GAAI,UAAU,gBAAgB,GAAG,IAAI,KAAG,gBAGzE,CAAC;AAEH,eAAO,MAAM,cAAc,GAAI,UAAU,QAAQ,GAAG,IAAI,KAAG,YAC1B,CAAC;AAYlC,eAAO,MAAM,wBAAwB,GAEjC,UAAU,gBAAgB,GAAG,IAAI,EACjC,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,QAAQ,GAAG,IAAI,KAC/E,iBAkBF,CAAC"}