@nubisco/openbridge 1.4.2 → 1.5.2

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 (42) hide show
  1. package/dist/__tests__/mcp.test.d.ts +2 -0
  2. package/dist/__tests__/mcp.test.d.ts.map +1 -0
  3. package/dist/__tests__/mcp.test.js +478 -0
  4. package/dist/__tests__/mcp.test.js.map +1 -0
  5. package/dist/access.d.ts +148 -0
  6. package/dist/access.d.ts.map +1 -0
  7. package/dist/access.js +401 -0
  8. package/dist/access.js.map +1 -0
  9. package/dist/auth.d.ts +9 -1
  10. package/dist/auth.d.ts.map +1 -1
  11. package/dist/auth.js +11 -0
  12. package/dist/auth.js.map +1 -1
  13. package/dist/index.js +8 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/mcp/index.d.ts +54 -0
  16. package/dist/mcp/index.d.ts.map +1 -0
  17. package/dist/mcp/index.js +181 -0
  18. package/dist/mcp/index.js.map +1 -0
  19. package/dist/mcp/oauth.d.ts +35 -0
  20. package/dist/mcp/oauth.d.ts.map +1 -0
  21. package/dist/mcp/oauth.js +323 -0
  22. package/dist/mcp/oauth.js.map +1 -0
  23. package/dist/mcp/tools.d.ts +39 -0
  24. package/dist/mcp/tools.d.ts.map +1 -0
  25. package/dist/mcp/tools.js +432 -0
  26. package/dist/mcp/tools.js.map +1 -0
  27. package/dist/server.d.ts.map +1 -1
  28. package/dist/server.js +67 -114
  29. package/dist/server.js.map +1 -1
  30. package/dist/services/bridge.d.ts +102 -0
  31. package/dist/services/bridge.d.ts.map +1 -0
  32. package/dist/services/bridge.js +191 -0
  33. package/dist/services/bridge.js.map +1 -0
  34. package/dist/token-cli.d.ts +10 -0
  35. package/dist/token-cli.d.ts.map +1 -0
  36. package/dist/token-cli.js +76 -0
  37. package/dist/token-cli.js.map +1 -0
  38. package/package.json +6 -5
  39. package/ui-dist/assets/{index-CL7JhxrS.css → index-9bWNU3bq.css} +2 -2
  40. package/ui-dist/assets/index-DIyesg4J.js +109 -0
  41. package/ui-dist/index.html +2 -2
  42. package/ui-dist/assets/index-Rvs_bO_V.js +0 -109
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Who may use the MCP endpoint: personal tokens and OAuth grants.
3
+ *
4
+ * OpenBridge has no database, so this is one JSON file, `access.json` in the
5
+ * state directory, written atomically with mode 600. Only hashes of secrets are
6
+ * stored. The file is re-read whenever it changes on disk, so a token made with
7
+ * `openbridge token create` on the host works without restarting the daemon.
8
+ *
9
+ * Two scopes, and they are the whole permission model of the endpoint:
10
+ *
11
+ * - `openbridge:read` sees devices, history, events, observations and logs.
12
+ * - `openbridge:control` also runs device controls and writes HomeKit
13
+ * characteristics, which move physical things (a gate, a heat pump).
14
+ *
15
+ * Control implies read. Nothing here reaches plugin installs, config, the
16
+ * shell or updates: those stay behind the dashboard.
17
+ *
18
+ * The OAuth half follows Tally's (tally/apps/api/src/services/oauth.service.ts):
19
+ * public clients only, S256 PKCE only, exact redirect matching, codes single
20
+ * use for five minutes, access tokens for an hour, refresh tokens rotating on
21
+ * every use.
22
+ */
23
+ export declare const READ_SCOPE = "openbridge:read";
24
+ export declare const CONTROL_SCOPE = "openbridge:control";
25
+ export declare const SCOPES: readonly ["openbridge:read", "openbridge:control"];
26
+ export type Scope = (typeof SCOPES)[number];
27
+ export type Access = 'read' | 'control';
28
+ /** Every OpenBridge credential starts with this, so a leaked one is recognisable on sight. */
29
+ export declare const TOKEN_PREFIX = "obt_";
30
+ /** The most never-approved clients held at once. Registration is unauthenticated by design. */
31
+ export declare const MAX_UNUSED_CLIENTS = 100;
32
+ export declare function scopesFor(access: Access): Scope[];
33
+ export declare function accessOf(scopes: readonly string[]): Access;
34
+ export declare function hashToken(raw: string): string;
35
+ /** PKCE: base64url(SHA-256(verifier)), unpadded, per RFC 7636. */
36
+ export declare function s256Challenge(verifier: string): string;
37
+ /** https for the world, plain http only for loopback tooling (Claude Code listens on localhost). */
38
+ export declare function acceptableRedirect(uri: string): boolean;
39
+ /** Who made a token or approved a connector: the signed-in person, or `local` when sign-in is off. */
40
+ export interface Owner {
41
+ id: string;
42
+ email: string | null;
43
+ }
44
+ /** What a credential resolves to. The MCP endpoint needs nothing else. */
45
+ export interface Credential {
46
+ kind: 'personal' | 'oauth';
47
+ name: string;
48
+ scopes: Scope[];
49
+ owner: Owner;
50
+ /** Stable across refreshes, so a retried write op is recognised as the same caller. */
51
+ id: string;
52
+ }
53
+ export interface TokenPair {
54
+ access_token: string;
55
+ token_type: 'Bearer';
56
+ expires_in: number;
57
+ refresh_token: string;
58
+ scope: string;
59
+ }
60
+ export type TokenResult = {
61
+ ok: true;
62
+ pair: TokenPair;
63
+ } | {
64
+ ok: false;
65
+ error: string;
66
+ };
67
+ export declare class AccessStore {
68
+ private readonly path;
69
+ private data;
70
+ private mtimeMs;
71
+ constructor(path: string);
72
+ /** Re-reads the file when it changed on disk, which is how the CLI's writes arrive. */
73
+ private load;
74
+ /** Read, change, write. The file is replaced by rename, so a reader never sees half of it. */
75
+ private mutate;
76
+ private prune;
77
+ /** Creates a token and returns the raw value, the only time it exists outside the caller. */
78
+ createToken(name: string, access: Access, owner: Owner): {
79
+ id: string;
80
+ token: string;
81
+ };
82
+ /**
83
+ * Every token on this bridge. A bridge is one household's: whoever can sign in
84
+ * to the dashboard can already open its shell, so nobody's tokens are hidden
85
+ * from another person who manages it.
86
+ */
87
+ listTokens(): {
88
+ id: string;
89
+ name: string;
90
+ access: Access;
91
+ owner: string | null;
92
+ createdAt: string;
93
+ lastUsedAt: string | null;
94
+ }[];
95
+ /** Deleted outright: a personal token has no refresh to refuse later. */
96
+ revokeToken(id: string): boolean;
97
+ verify(raw: string): Credential | null;
98
+ private touch;
99
+ registerClient(body: {
100
+ redirect_uris?: unknown;
101
+ client_name?: unknown;
102
+ }): {
103
+ ok: true;
104
+ id: string;
105
+ name: string;
106
+ uris: string[];
107
+ } | {
108
+ ok: false;
109
+ error: string;
110
+ description: string;
111
+ };
112
+ /**
113
+ * The client, when this exact redirect is one it registered. Exact match,
114
+ * never a prefix: "starts with" is the classic open redirect.
115
+ */
116
+ client(clientId: string, redirectUri: string): {
117
+ id: string;
118
+ name: string;
119
+ } | null;
120
+ issueCode(p: {
121
+ clientId: string;
122
+ redirectUri: string;
123
+ codeChallenge: string;
124
+ access: Access;
125
+ }, owner: Owner): string;
126
+ private pair;
127
+ /** grant_type=authorization_code. Every check here fails open if omitted. */
128
+ exchangeCode(get: (k: string) => string): TokenResult;
129
+ /** grant_type=refresh_token. Rotates, so the presented token dies here. */
130
+ refresh(get: (k: string) => string): TokenResult;
131
+ /**
132
+ * One row per client rather than per grant: authorising Claude twice makes
133
+ * two grants for what the person thinks of as one connection, and a revoke
134
+ * that left the sibling alive would be a revoke that did not work.
135
+ */
136
+ listConnections(): {
137
+ clientId: string;
138
+ name: string;
139
+ access: Access;
140
+ owners: string[];
141
+ connectedAt: string;
142
+ lastUsedAt: string | null;
143
+ }[];
144
+ /** Revokes every live grant of one client, including its refresh tokens. */
145
+ revokeConnection(clientId: string): boolean;
146
+ }
147
+ export declare function extractBearer(header: string | undefined): string | null;
148
+ //# sourceMappingURL=access.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"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"}
package/dist/access.js ADDED
@@ -0,0 +1,401 @@
1
+ /**
2
+ * Who may use the MCP endpoint: personal tokens and OAuth grants.
3
+ *
4
+ * OpenBridge has no database, so this is one JSON file, `access.json` in the
5
+ * state directory, written atomically with mode 600. Only hashes of secrets are
6
+ * stored. The file is re-read whenever it changes on disk, so a token made with
7
+ * `openbridge token create` on the host works without restarting the daemon.
8
+ *
9
+ * Two scopes, and they are the whole permission model of the endpoint:
10
+ *
11
+ * - `openbridge:read` sees devices, history, events, observations and logs.
12
+ * - `openbridge:control` also runs device controls and writes HomeKit
13
+ * characteristics, which move physical things (a gate, a heat pump).
14
+ *
15
+ * Control implies read. Nothing here reaches plugin installs, config, the
16
+ * shell or updates: those stay behind the dashboard.
17
+ *
18
+ * The OAuth half follows Tally's (tally/apps/api/src/services/oauth.service.ts):
19
+ * public clients only, S256 PKCE only, exact redirect matching, codes single
20
+ * use for five minutes, access tokens for an hour, refresh tokens rotating on
21
+ * every use.
22
+ */
23
+ import { createHash, randomBytes, randomUUID } from 'crypto';
24
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from 'fs';
25
+ import { dirname } from 'path';
26
+ export const READ_SCOPE = 'openbridge:read';
27
+ export const CONTROL_SCOPE = 'openbridge:control';
28
+ export const SCOPES = [READ_SCOPE, CONTROL_SCOPE];
29
+ /** Every OpenBridge credential starts with this, so a leaked one is recognisable on sight. */
30
+ export const TOKEN_PREFIX = 'obt_';
31
+ const PERSONAL_PREFIX = `${TOKEN_PREFIX}pat_`;
32
+ const ACCESS_PREFIX = `${TOKEN_PREFIX}mcp_`;
33
+ const REFRESH_PREFIX = `${TOKEN_PREFIX}ref_`;
34
+ const CODE_PREFIX = `${TOKEN_PREFIX}code_`;
35
+ const CODE_TTL_MS = 5 * 60 * 1000;
36
+ const ACCESS_TTL_MS = 60 * 60 * 1000;
37
+ const REFRESH_TTL_MS = 30 * 24 * 60 * 60 * 1000;
38
+ /** A client that registered and was never approved is dropped after this. */
39
+ const UNUSED_CLIENT_TTL_MS = 3 * 24 * 60 * 60 * 1000;
40
+ /** The most never-approved clients held at once. Registration is unauthenticated by design. */
41
+ export const MAX_UNUSED_CLIENTS = 100;
42
+ /** lastUsedAt is written at most this often, so a busy agent does not rewrite the file per call. */
43
+ const LAST_USED_GRANULARITY_MS = 60 * 1000;
44
+ export function scopesFor(access) {
45
+ return access === 'control' ? [READ_SCOPE, CONTROL_SCOPE] : [READ_SCOPE];
46
+ }
47
+ export function accessOf(scopes) {
48
+ return scopes.includes(CONTROL_SCOPE) ? 'control' : 'read';
49
+ }
50
+ export function hashToken(raw) {
51
+ return createHash('sha256').update(raw).digest('hex');
52
+ }
53
+ function randomSecret(prefix) {
54
+ return `${prefix}${randomBytes(32).toString('base64url')}`;
55
+ }
56
+ /** PKCE: base64url(SHA-256(verifier)), unpadded, per RFC 7636. */
57
+ export function s256Challenge(verifier) {
58
+ return createHash('sha256').update(verifier).digest('base64url');
59
+ }
60
+ /** https for the world, plain http only for loopback tooling (Claude Code listens on localhost). */
61
+ export function acceptableRedirect(uri) {
62
+ try {
63
+ const u = new URL(uri);
64
+ if (u.protocol === 'https:')
65
+ return true;
66
+ return u.protocol === 'http:' && (u.hostname === 'localhost' || u.hostname === '127.0.0.1');
67
+ }
68
+ catch {
69
+ return false;
70
+ }
71
+ }
72
+ const empty = () => ({ tokens: [], clients: [], codes: [], grants: [] });
73
+ const iso = (ms) => new Date(ms).toISOString();
74
+ const past = (at, now) => at !== null && Date.parse(at) <= now;
75
+ export class AccessStore {
76
+ path;
77
+ data = empty();
78
+ mtimeMs = -1;
79
+ constructor(path) {
80
+ this.path = path;
81
+ }
82
+ /** Re-reads the file when it changed on disk, which is how the CLI's writes arrive. */
83
+ load() {
84
+ let mtime = -1;
85
+ try {
86
+ mtime = statSync(this.path).mtimeMs;
87
+ }
88
+ catch {
89
+ this.data = empty();
90
+ this.mtimeMs = -1;
91
+ return this.data;
92
+ }
93
+ if (mtime !== this.mtimeMs) {
94
+ try {
95
+ const parsed = JSON.parse(readFileSync(this.path, 'utf8'));
96
+ this.data = { ...empty(), ...parsed };
97
+ }
98
+ catch {
99
+ // A torn or hand-broken file grants nothing rather than crashing the daemon.
100
+ this.data = empty();
101
+ }
102
+ this.mtimeMs = mtime;
103
+ }
104
+ return this.data;
105
+ }
106
+ /** Read, change, write. The file is replaced by rename, so a reader never sees half of it. */
107
+ mutate(fn) {
108
+ const d = this.load();
109
+ const now = Date.now();
110
+ const out = fn(d, now);
111
+ this.prune(d, now);
112
+ const dir = dirname(this.path);
113
+ if (!existsSync(dir))
114
+ mkdirSync(dir, { recursive: true });
115
+ const tmp = `${this.path}.${process.pid}.tmp`;
116
+ writeFileSync(tmp, JSON.stringify(d, null, 2), { mode: 0o600 });
117
+ try {
118
+ chmodSync(tmp, 0o600);
119
+ }
120
+ catch {
121
+ // best effort: chmod fails on non-POSIX volumes
122
+ }
123
+ renameSync(tmp, this.path);
124
+ this.mtimeMs = statSync(this.path).mtimeMs;
125
+ return out;
126
+ }
127
+ prune(d, now) {
128
+ d.codes = d.codes.filter((c) => !c.usedAt && !past(c.expiresAt, now));
129
+ d.grants = d.grants.filter((g) => !g.revokedAt && !past(g.refreshExpiresAt, now));
130
+ const live = new Set([...d.codes.map((c) => c.clientId), ...d.grants.map((g) => g.clientId)]);
131
+ d.clients = d.clients.filter((c) => c.usedAt !== null || live.has(c.id) || now - Date.parse(c.createdAt) < UNUSED_CLIENT_TTL_MS);
132
+ }
133
+ // ── Personal tokens ────────────────────────────────────────────────────────
134
+ /** Creates a token and returns the raw value, the only time it exists outside the caller. */
135
+ createToken(name, access, owner) {
136
+ const token = randomSecret(PERSONAL_PREFIX);
137
+ const id = randomUUID();
138
+ this.mutate((d, now) => {
139
+ d.tokens.push({
140
+ id,
141
+ name: name.trim().slice(0, 120) || 'Unnamed token',
142
+ hash: hashToken(token),
143
+ scopes: scopesFor(access),
144
+ owner,
145
+ createdAt: iso(now),
146
+ lastUsedAt: null,
147
+ });
148
+ });
149
+ return { id, token };
150
+ }
151
+ /**
152
+ * Every token on this bridge. A bridge is one household's: whoever can sign in
153
+ * to the dashboard can already open its shell, so nobody's tokens are hidden
154
+ * from another person who manages it.
155
+ */
156
+ listTokens() {
157
+ return this.load().tokens.map((t) => ({
158
+ id: t.id,
159
+ name: t.name,
160
+ access: accessOf(t.scopes),
161
+ owner: t.owner.email,
162
+ createdAt: t.createdAt,
163
+ lastUsedAt: t.lastUsedAt,
164
+ }));
165
+ }
166
+ /** Deleted outright: a personal token has no refresh to refuse later. */
167
+ revokeToken(id) {
168
+ if (!this.load().tokens.some((t) => t.id === id))
169
+ return false;
170
+ return this.mutate((d) => {
171
+ const before = d.tokens.length;
172
+ d.tokens = d.tokens.filter((t) => t.id !== id);
173
+ return d.tokens.length < before;
174
+ });
175
+ }
176
+ // ── Resolving a bearer ─────────────────────────────────────────────────────
177
+ verify(raw) {
178
+ if (!raw.startsWith(TOKEN_PREFIX))
179
+ return null;
180
+ const hash = hashToken(raw);
181
+ const d = this.load();
182
+ const now = Date.now();
183
+ const token = d.tokens.find((t) => t.hash === hash);
184
+ if (token) {
185
+ this.touch('tokens', token.id, token.lastUsedAt, now);
186
+ return { kind: 'personal', name: token.name, scopes: token.scopes, owner: token.owner, id: `token:${token.id}` };
187
+ }
188
+ if (!raw.startsWith(ACCESS_PREFIX))
189
+ return null;
190
+ const grant = d.grants.find((g) => g.accessHash === hash);
191
+ if (!grant || grant.revokedAt || past(grant.accessExpiresAt, now))
192
+ return null;
193
+ this.touch('grants', grant.id, grant.lastUsedAt, now);
194
+ const client = d.clients.find((c) => c.id === grant.clientId);
195
+ return {
196
+ kind: 'oauth',
197
+ name: client?.name ?? 'Connector',
198
+ scopes: grant.scopes,
199
+ owner: grant.owner,
200
+ id: `oauth:${grant.id}`,
201
+ };
202
+ }
203
+ touch(kind, id, last, now) {
204
+ if (last && now - Date.parse(last) < LAST_USED_GRANULARITY_MS)
205
+ return;
206
+ this.mutate((d) => {
207
+ const row = d[kind].find((r) => r.id === id);
208
+ if (row)
209
+ row.lastUsedAt = iso(now);
210
+ });
211
+ }
212
+ // ── OAuth: registration ────────────────────────────────────────────────────
213
+ registerClient(body) {
214
+ const uris = Array.isArray(body.redirect_uris)
215
+ ? body.redirect_uris.filter((u) => typeof u === 'string')
216
+ : [];
217
+ if (uris.length === 0 || !uris.every(acceptableRedirect)) {
218
+ return {
219
+ ok: false,
220
+ error: 'invalid_redirect_uri',
221
+ description: 'redirect_uris must be https URLs, or http on localhost',
222
+ };
223
+ }
224
+ const name = ((typeof body.client_name === 'string' && body.client_name.trim()) || 'Unnamed client').slice(0, 120);
225
+ return this.mutate((d, now) => {
226
+ this.prune(d, now);
227
+ if (d.clients.filter((c) => c.usedAt === null).length >= MAX_UNUSED_CLIENTS) {
228
+ return {
229
+ ok: false,
230
+ error: 'temporarily_unavailable',
231
+ description: 'Registration is paused. Try again later.',
232
+ };
233
+ }
234
+ const id = randomUUID();
235
+ d.clients.push({ id, name, redirectUris: uris, createdAt: iso(now), usedAt: null });
236
+ return { ok: true, id, name, uris };
237
+ });
238
+ }
239
+ /**
240
+ * The client, when this exact redirect is one it registered. Exact match,
241
+ * never a prefix: "starts with" is the classic open redirect.
242
+ */
243
+ client(clientId, redirectUri) {
244
+ const c = this.load().clients.find((x) => x.id === clientId);
245
+ if (!c || !c.redirectUris.includes(redirectUri))
246
+ return null;
247
+ return { id: c.id, name: c.name };
248
+ }
249
+ // ── OAuth: code and token ──────────────────────────────────────────────────
250
+ issueCode(p, owner) {
251
+ const code = randomSecret(CODE_PREFIX);
252
+ this.mutate((d, now) => {
253
+ d.codes.push({
254
+ hash: hashToken(code),
255
+ clientId: p.clientId,
256
+ owner,
257
+ redirectUri: p.redirectUri,
258
+ challenge: p.codeChallenge,
259
+ scopes: scopesFor(p.access),
260
+ expiresAt: iso(now + CODE_TTL_MS),
261
+ usedAt: null,
262
+ });
263
+ // A person approved this client, so it is in use and is never pruned.
264
+ const client = d.clients.find((c) => c.id === p.clientId);
265
+ if (client && !client.usedAt)
266
+ client.usedAt = iso(now);
267
+ });
268
+ return code;
269
+ }
270
+ pair(scopes) {
271
+ const access = randomSecret(ACCESS_PREFIX);
272
+ const refresh = randomSecret(REFRESH_PREFIX);
273
+ return {
274
+ access,
275
+ refresh,
276
+ pair: {
277
+ access_token: access,
278
+ token_type: 'Bearer',
279
+ expires_in: Math.floor(ACCESS_TTL_MS / 1000),
280
+ refresh_token: refresh,
281
+ scope: scopes.join(' '),
282
+ },
283
+ };
284
+ }
285
+ /** grant_type=authorization_code. Every check here fails open if omitted. */
286
+ exchangeCode(get) {
287
+ const hash = hashToken(get('code'));
288
+ return this.mutate((d, now) => {
289
+ const row = d.codes.find((c) => c.hash === hash);
290
+ if (!row || row.usedAt || past(row.expiresAt, now))
291
+ return { ok: false, error: 'invalid_grant' };
292
+ if (row.clientId !== get('client_id'))
293
+ return { ok: false, error: 'invalid_grant' };
294
+ // Repeated here so a code minted for one target cannot be redeemed while claiming another.
295
+ if (row.redirectUri !== get('redirect_uri'))
296
+ return { ok: false, error: 'invalid_grant' };
297
+ // The proof. Without it the code alone is enough, which is why PKCE exists for public clients.
298
+ if (s256Challenge(get('code_verifier')) !== row.challenge)
299
+ return { ok: false, error: 'invalid_grant' };
300
+ // Single use. The whole read-change-write runs synchronously, so two
301
+ // requests racing with one code cannot both get past this line.
302
+ row.usedAt = iso(now);
303
+ const { access, refresh, pair } = this.pair(row.scopes);
304
+ d.grants.push({
305
+ id: randomUUID(),
306
+ clientId: row.clientId,
307
+ owner: row.owner,
308
+ accessHash: hashToken(access),
309
+ refreshHash: hashToken(refresh),
310
+ scopes: row.scopes,
311
+ accessExpiresAt: iso(now + ACCESS_TTL_MS),
312
+ refreshExpiresAt: iso(now + REFRESH_TTL_MS),
313
+ createdAt: iso(now),
314
+ lastUsedAt: null,
315
+ revokedAt: null,
316
+ });
317
+ return { ok: true, pair };
318
+ });
319
+ }
320
+ /** grant_type=refresh_token. Rotates, so the presented token dies here. */
321
+ refresh(get) {
322
+ const hash = hashToken(get('refresh_token'));
323
+ return this.mutate((d, now) => {
324
+ const row = d.grants.find((g) => g.refreshHash === hash);
325
+ if (!row || row.revokedAt || past(row.refreshExpiresAt, now))
326
+ return { ok: false, error: 'invalid_grant' };
327
+ if (get('client_id') && get('client_id') !== row.clientId)
328
+ return { ok: false, error: 'invalid_grant' };
329
+ const { access, refresh, pair } = this.pair(row.scopes);
330
+ row.accessHash = hashToken(access);
331
+ row.refreshHash = hashToken(refresh);
332
+ row.accessExpiresAt = iso(now + ACCESS_TTL_MS);
333
+ row.refreshExpiresAt = iso(now + REFRESH_TTL_MS);
334
+ return { ok: true, pair };
335
+ });
336
+ }
337
+ // ── Connected applications ─────────────────────────────────────────────────
338
+ /**
339
+ * One row per client rather than per grant: authorising Claude twice makes
340
+ * two grants for what the person thinks of as one connection, and a revoke
341
+ * that left the sibling alive would be a revoke that did not work.
342
+ */
343
+ listConnections() {
344
+ const d = this.load();
345
+ const now = Date.now();
346
+ const byClient = new Map();
347
+ for (const g of d.grants) {
348
+ if (g.revokedAt || past(g.refreshExpiresAt, now))
349
+ continue;
350
+ const app = byClient.get(g.clientId) ?? {
351
+ clientId: g.clientId,
352
+ name: d.clients.find((c) => c.id === g.clientId)?.name ?? 'Connector',
353
+ scopes: new Set(),
354
+ owners: new Set(),
355
+ connectedAt: g.createdAt,
356
+ lastUsedAt: null,
357
+ };
358
+ for (const s of g.scopes)
359
+ app.scopes.add(s);
360
+ if (g.owner.email)
361
+ app.owners.add(g.owner.email);
362
+ if (g.createdAt < app.connectedAt)
363
+ app.connectedAt = g.createdAt;
364
+ if (g.lastUsedAt && (!app.lastUsedAt || g.lastUsedAt > app.lastUsedAt))
365
+ app.lastUsedAt = g.lastUsedAt;
366
+ byClient.set(g.clientId, app);
367
+ }
368
+ return [...byClient.values()]
369
+ .sort((a, b) => b.connectedAt.localeCompare(a.connectedAt))
370
+ .map((a) => ({
371
+ clientId: a.clientId,
372
+ name: a.name,
373
+ access: accessOf([...a.scopes]),
374
+ owners: [...a.owners],
375
+ connectedAt: a.connectedAt,
376
+ lastUsedAt: a.lastUsedAt,
377
+ }));
378
+ }
379
+ /** Revokes every live grant of one client, including its refresh tokens. */
380
+ revokeConnection(clientId) {
381
+ if (!this.load().grants.some((g) => g.clientId === clientId && !g.revokedAt))
382
+ return false;
383
+ return this.mutate((d, now) => {
384
+ let n = 0;
385
+ for (const g of d.grants) {
386
+ if (g.clientId === clientId && !g.revokedAt) {
387
+ g.revokedAt = iso(now);
388
+ n++;
389
+ }
390
+ }
391
+ return n > 0;
392
+ });
393
+ }
394
+ }
395
+ export function extractBearer(header) {
396
+ if (!header)
397
+ return null;
398
+ const match = /^Bearer\s+(.+)$/i.exec(header);
399
+ return match ? match[1].trim() : null;
400
+ }
401
+ //# sourceMappingURL=access.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.js","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"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"}
package/dist/auth.d.ts CHANGED
@@ -13,7 +13,7 @@
13
13
  * The check uses the route the router matched and a normalized path,
14
14
  * never the raw URL, see requiresSession().
15
15
  */
16
- import type { FastifyInstance } from 'fastify';
16
+ import type { FastifyInstance, FastifyRequest } from 'fastify';
17
17
  export interface TAuthConfig {
18
18
  enabled: boolean;
19
19
  issuer: string | null;
@@ -58,6 +58,14 @@ export declare function acceptNameClaim(name: unknown): string | undefined;
58
58
  */
59
59
  export declare function resolveAuthOrigin(issuer: string | null, configured: string | undefined): string | null;
60
60
  export declare function loadAuthConfig(): TAuthConfig;
61
+ /**
62
+ * The signed-in person behind a request, from the session cookie, or null.
63
+ * Always null when sign-in is off, because then there is nobody to be.
64
+ */
65
+ export declare function readSession(config: TAuthConfig, req: FastifyRequest): {
66
+ userId: string;
67
+ email: string;
68
+ } | null;
61
69
  export declare function registerAuthRoutes(app: FastifyInstance, config: TAuthConfig): Promise<void>;
62
70
  /**
63
71
  * Reduce a request path to the form the gate compares against, so that no
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAA;AAS9D,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB;;;;OAIG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;CACf;AAYD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAc9F;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAKjE;AA2BD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAItG;AAED,wBAAgB,cAAc,IAAI,WAAW,CAW5C;AAkCD,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAwFjG;AASD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0BlE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAKrF"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAS9D,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB;;;;OAIG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;CACf;AAYD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAc9F;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAKjE;AA2BD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAItG;AAED,wBAAgB,cAAc,IAAI,WAAW,CAW5C;AA8BD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,cAAc,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAK9G;AAMD,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAwFjG;AASD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0BlE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAKrF"}
package/dist/auth.js CHANGED
@@ -147,6 +147,17 @@ function getCookie(req, name) {
147
147
  const match = header.match(new RegExp(`(?:^|;\\s*)${name}=([^;]+)`));
148
148
  return match ? (match[1] ?? null) : null;
149
149
  }
150
+ /**
151
+ * The signed-in person behind a request, from the session cookie, or null.
152
+ * Always null when sign-in is off, because then there is nobody to be.
153
+ */
154
+ export function readSession(config, req) {
155
+ if (!config.enabled || !config.issuer)
156
+ return null;
157
+ const cookie = getCookie(req, COOKIE_NAME);
158
+ const session = cookie ? verifySession(config.secret, cookie) : null;
159
+ return session ? { userId: session.userId, email: session.email } : null;
160
+ }
150
161
  function isProductionLike() {
151
162
  return process.env.NODE_ENV === 'production';
152
163
  }