@nubisco/openbridge 1.4.1 → 1.5.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 (44) hide show
  1. package/dist/__tests__/auth-origin.test.js +2 -4
  2. package/dist/__tests__/auth-origin.test.js.map +1 -1
  3. package/dist/__tests__/mcp.test.d.ts +2 -0
  4. package/dist/__tests__/mcp.test.d.ts.map +1 -0
  5. package/dist/__tests__/mcp.test.js +464 -0
  6. package/dist/__tests__/mcp.test.js.map +1 -0
  7. package/dist/access.d.ts +148 -0
  8. package/dist/access.d.ts.map +1 -0
  9. package/dist/access.js +401 -0
  10. package/dist/access.js.map +1 -0
  11. package/dist/auth.d.ts +13 -5
  12. package/dist/auth.d.ts.map +1 -1
  13. package/dist/auth.js +16 -10
  14. package/dist/auth.js.map +1 -1
  15. package/dist/index.js +8 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/mcp/index.d.ts +48 -0
  18. package/dist/mcp/index.d.ts.map +1 -0
  19. package/dist/mcp/index.js +173 -0
  20. package/dist/mcp/index.js.map +1 -0
  21. package/dist/mcp/oauth.d.ts +35 -0
  22. package/dist/mcp/oauth.d.ts.map +1 -0
  23. package/dist/mcp/oauth.js +319 -0
  24. package/dist/mcp/oauth.js.map +1 -0
  25. package/dist/mcp/tools.d.ts +39 -0
  26. package/dist/mcp/tools.d.ts.map +1 -0
  27. package/dist/mcp/tools.js +432 -0
  28. package/dist/mcp/tools.js.map +1 -0
  29. package/dist/server.d.ts.map +1 -1
  30. package/dist/server.js +67 -114
  31. package/dist/server.js.map +1 -1
  32. package/dist/services/bridge.d.ts +102 -0
  33. package/dist/services/bridge.d.ts.map +1 -0
  34. package/dist/services/bridge.js +191 -0
  35. package/dist/services/bridge.js.map +1 -0
  36. package/dist/token-cli.d.ts +10 -0
  37. package/dist/token-cli.d.ts.map +1 -0
  38. package/dist/token-cli.js +76 -0
  39. package/dist/token-cli.js.map +1 -0
  40. package/package.json +6 -5
  41. package/ui-dist/assets/{index-CL7JhxrS.css → index-9bWNU3bq.css} +2 -2
  42. package/ui-dist/assets/index-DIyesg4J.js +109 -0
  43. package/ui-dist/index.html +2 -2
  44. package/ui-dist/assets/index-Rvs_bO_V.js +0 -109
@@ -4,10 +4,8 @@ describe('resolveAuthOrigin', () => {
4
4
  it('uses PLATFORM_AUTH_ORIGIN when it is set, without a trailing slash', () => {
5
5
  expect(resolveAuthOrigin('https://platform.nubisco.io', 'https://auth.example/')).toBe('https://auth.example');
6
6
  });
7
- it("sends Nubisco's issuer to Accord's auth host", () => {
8
- expect(resolveAuthOrigin('https://platform.nubisco.io', undefined)).toBe('https://auth.nubisco.io');
9
- });
10
- it('falls back to any other issuer', () => {
7
+ it("falls back to the issuer, Nubisco's included", () => {
8
+ expect(resolveAuthOrigin('https://platform.nubisco.io', undefined)).toBe('https://platform.nubisco.io');
11
9
  expect(resolveAuthOrigin('https://id.example', undefined)).toBe('https://id.example');
12
10
  expect(resolveAuthOrigin('https://id.example', ' ')).toBe('https://id.example');
13
11
  });
@@ -1 +1 @@
1
- {"version":3,"file":"auth-origin.test.js","sourceRoot":"","sources":["../../src/__tests__/auth-origin.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE9C,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,CAAC,iBAAiB,CAAC,6BAA6B,EAAE,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;IAChH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,iBAAiB,CAAC,6BAA6B,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAA;IACrG,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,iBAAiB,CAAC,oBAAoB,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;QACrF,MAAM,CAAC,iBAAiB,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;IAClF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IACvD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"auth-origin.test.js","sourceRoot":"","sources":["../../src/__tests__/auth-origin.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE9C,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,CAAC,iBAAiB,CAAC,6BAA6B,EAAE,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;IAChH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,iBAAiB,CAAC,6BAA6B,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;QACvG,MAAM,CAAC,iBAAiB,CAAC,oBAAoB,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;QACrF,MAAM,CAAC,iBAAiB,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;IAClF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IACvD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mcp.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/mcp.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,464 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { existsSync, mkdtempSync, readFileSync, rmSync, statSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { tmpdir } from 'os';
5
+ import Fastify from 'fastify';
6
+ import { PluginRegistry } from '@nubisco/openbridge-core';
7
+ import { AccessStore, s256Challenge } from '../access.js';
8
+ import { handleMcpRequest } from '../mcp/index.js';
9
+ import { registerMcpRoutes } from '../mcp/index.js';
10
+ import { registerOauthRoutes, sameOrigin } from '../mcp/oauth.js';
11
+ import { clearReplays } from '../mcp/tools.js';
12
+ import { DeviceSeries } from '../timeseries.js';
13
+ let home;
14
+ function makeBridge() {
15
+ const registry = new PluginRegistry();
16
+ const instance = registry.register({ manifest: { name: 'test-plugin', version: '1.0.0' } });
17
+ registry.updateStatus('test-plugin', 'running');
18
+ instance.devices = {
19
+ meter: {
20
+ id: 'meter',
21
+ name: 'Energy meter',
22
+ widgetType: 'energy_meter',
23
+ pluginId: 'test-plugin',
24
+ metrics: [
25
+ { key: 'power', label: 'Power', unit: 'W', kind: 'instant' },
26
+ { key: 'energy', label: 'Energy', unit: 'kWh', kind: 'cumulative' },
27
+ ],
28
+ },
29
+ gate: { id: 'gate', name: 'Gate', widgetType: 'gate', pluginId: 'test-plugin' },
30
+ };
31
+ instance.telemetry = {
32
+ meter: { power: 420, energy: 1234.5, _updatedAt: new Date().toISOString() },
33
+ };
34
+ const gate = vi.fn();
35
+ const controls = new Map([
36
+ ['gate::open', gate],
37
+ ['gate::factoryReset', () => { }],
38
+ ]);
39
+ return {
40
+ registry,
41
+ home,
42
+ hapAPI: null,
43
+ controls,
44
+ restrictedControls: new Set(['gate::factoryReset']),
45
+ deviceEvents: null,
46
+ observations: null,
47
+ homekitServiceTypes: null,
48
+ nativeAccessoryUuid: null,
49
+ gate,
50
+ };
51
+ }
52
+ const readCred = {
53
+ kind: 'personal',
54
+ name: 't',
55
+ scopes: ['openbridge:read'],
56
+ owner: { id: 'local', email: null },
57
+ id: 'token:r',
58
+ };
59
+ const controlCred = { ...readCred, scopes: ['openbridge:read', 'openbridge:control'], id: 'token:c' };
60
+ function ctxFor(bridge, credential) {
61
+ return { bridge, credential, origin: 'http://bridge.local:8582', bridgeName: () => 'Home' };
62
+ }
63
+ async function call(ctx, name, args = {}) {
64
+ const res = (await handleMcpRequest(ctx, {
65
+ jsonrpc: '2.0',
66
+ id: 1,
67
+ method: 'tools/call',
68
+ params: { name, arguments: args },
69
+ }));
70
+ return {
71
+ isError: res.result?.isError === true,
72
+ error: res.error,
73
+ text: res.result?.content[0]?.text ?? '',
74
+ json: () => JSON.parse(res.result.content[0].text),
75
+ };
76
+ }
77
+ beforeEach(() => {
78
+ home = mkdtempSync(join(tmpdir(), 'openbridge-mcp-'));
79
+ clearReplays();
80
+ });
81
+ afterEach(() => rmSync(home, { recursive: true, force: true }));
82
+ describe('protocol', () => {
83
+ it('initialize names the server and points the agent at overview', async () => {
84
+ const res = (await handleMcpRequest(ctxFor(makeBridge(), readCred), { id: 1, method: 'initialize' }));
85
+ expect(res.result.serverInfo.name).toBe('openbridge');
86
+ expect(res.result.serverInfo.icons[0].src).toBe('http://bridge.local:8582/logo.svg');
87
+ expect(res.result.instructions).toContain('overview');
88
+ });
89
+ it('tools/list marks reads read-only and generates every schema', async () => {
90
+ const res = (await handleMcpRequest(ctxFor(makeBridge(), readCred), { id: 1, method: 'tools/list' }));
91
+ const byName = Object.fromEntries(res.result.tools.map((t) => [t.name, t]));
92
+ expect(byName.overview.annotations).toEqual({ readOnlyHint: true });
93
+ expect(byName.device_control.annotations).toBeUndefined();
94
+ for (const t of res.result.tools)
95
+ expect(t.inputSchema.type).toBe('object');
96
+ });
97
+ it('an unknown tool is a protocol error, a bad argument is a result the model reads', async () => {
98
+ const ctx = ctxFor(makeBridge(), readCred);
99
+ expect((await call(ctx, 'nope')).error).toBeDefined();
100
+ const bad = await call(ctx, 'device_get', {});
101
+ expect(bad.isError).toBe(true);
102
+ expect(bad.text).toContain('device');
103
+ });
104
+ it('notifications get no reply', async () => {
105
+ expect(await handleMcpRequest(ctxFor(makeBridge(), readCred), { method: 'notifications/initialized' })).toBeUndefined();
106
+ });
107
+ });
108
+ describe('reading', () => {
109
+ it('overview lists devices with telemetry, health and unrestricted controls only', async () => {
110
+ const out = (await call(ctxFor(makeBridge(), readCred), 'overview')).json();
111
+ const meter = out.devices.find((d) => d.id === 'meter');
112
+ expect(meter.telemetry).toEqual({ power: 420, energy: 1234.5 });
113
+ expect(meter.health).toBe('ok');
114
+ expect(meter.metrics).toEqual(['power', 'energy']);
115
+ const gate = out.devices.find((d) => d.id === 'gate');
116
+ expect(gate.controls).toEqual(['open']);
117
+ expect(out.url_templates.device).toBe('http://bridge.local:8582/devices/{id}');
118
+ expect(out.plugins).toEqual([{ id: 'test-plugin', status: 'running', devices: 2 }]);
119
+ });
120
+ it('device_history summarises a cumulative metric as the amount used', async () => {
121
+ const bridge = makeBridge();
122
+ const now = Math.floor(Date.now() / 1000);
123
+ const series = new DeviceSeries(join(home, 'metrics'), 'meter', bridge.registry.getAll()[0].devices.meter.metrics);
124
+ series.ensureLayout();
125
+ for (let i = 0; i < 6; i++) {
126
+ series.append({ t: now - 3600 + i * 600, values: { power: 100 + i * 10, energy: 1000 + i * 0.5 } });
127
+ }
128
+ const energy = (await call(ctxFor(bridge, readCred), 'device_history', { device: 'meter', metric: 'energy', last: '2h' })).json();
129
+ expect(energy.summary.count).toBe(6);
130
+ expect(energy.summary.delta).toBeCloseTo(2.5);
131
+ expect(energy.summary.mean).toBeUndefined();
132
+ const power = (await call(ctxFor(bridge, readCred), 'device_history', {
133
+ device: 'meter',
134
+ metric: 'power',
135
+ last: '2h',
136
+ max_points: 0,
137
+ })).json();
138
+ expect(power.summary.max.value).toBe(150);
139
+ expect(power.summary.mean).toBeCloseTo(125);
140
+ expect(power.points).toBeUndefined();
141
+ });
142
+ it('device_history refuses a window it cannot read, in words', async () => {
143
+ const res = await call(ctxFor(makeBridge(), readCred), 'device_history', {
144
+ device: 'meter',
145
+ metric: 'power',
146
+ last: 'yesterday',
147
+ });
148
+ expect(res.isError).toBe(true);
149
+ expect(res.text).toContain('not a duration');
150
+ });
151
+ it('an unknown device is a refusal, not a crash', async () => {
152
+ const res = await call(ctxFor(makeBridge(), readCred), 'device_get', { device: 'nope' });
153
+ expect(res.isError).toBe(true);
154
+ expect(res.text).toContain("Device 'nope' not found");
155
+ });
156
+ });
157
+ describe('control', () => {
158
+ it('a read-only token cannot operate anything', async () => {
159
+ const bridge = makeBridge();
160
+ const res = await call(ctxFor(bridge, readCred), 'device_control', {
161
+ ops: [{ op_id: 'a', device: 'gate', control: 'open', value: true }],
162
+ });
163
+ expect(res.isError).toBe(true);
164
+ expect(res.text).toContain('read-only');
165
+ expect(bridge.gate).not.toHaveBeenCalled();
166
+ });
167
+ it('runs an op once, and a retried op_id replays the first answer', async () => {
168
+ const bridge = makeBridge();
169
+ const ctx = ctxFor(bridge, controlCred);
170
+ const op = { op_id: 'open-1', device: 'gate', control: 'open', value: true };
171
+ expect((await call(ctx, 'device_control', { ops: [op] })).json().results[0]).toEqual({ op_id: 'open-1', ok: true });
172
+ const again = (await call(ctx, 'device_control', { ops: [op] })).json().results[0];
173
+ expect(again.replayed).toBe(true);
174
+ expect(bridge.gate).toHaveBeenCalledTimes(1);
175
+ });
176
+ it('a restricted control is refused per op and the rest of the batch still runs', async () => {
177
+ const bridge = makeBridge();
178
+ const out = (await call(ctxFor(bridge, controlCred), 'device_control', {
179
+ ops: [
180
+ { op_id: 'x', device: 'gate', control: 'factoryReset' },
181
+ { op_id: 'y', device: 'gate', control: 'open', value: true },
182
+ ],
183
+ })).json();
184
+ expect(out.results[0].ok).toBe(false);
185
+ expect(out.results[0].error).toContain('restricted');
186
+ expect(out.results[1].ok).toBe(true);
187
+ });
188
+ });
189
+ describe('AccessStore', () => {
190
+ it('stores only hashes, mode 600, and a revoked token stops working', () => {
191
+ const store = new AccessStore(join(home, 'access.json'));
192
+ const { id, token } = store.createToken('laptop', 'read', { id: 'local', email: null });
193
+ expect(token.startsWith('obt_pat_')).toBe(true);
194
+ const file = readFileSync(join(home, 'access.json'), 'utf8');
195
+ expect(file).not.toContain(token);
196
+ expect(statSync(join(home, 'access.json')).mode & 0o777).toBe(0o600);
197
+ expect(store.verify(token)?.scopes).toEqual(['openbridge:read']);
198
+ expect(store.revokeToken(id)).toBe(true);
199
+ expect(store.verify(token)).toBeNull();
200
+ });
201
+ it('sees a token another process wrote, without a restart', () => {
202
+ const daemon = new AccessStore(join(home, 'access.json'));
203
+ expect(daemon.listTokens()).toEqual([]);
204
+ const { token } = new AccessStore(join(home, 'access.json')).createToken('cli', 'control', {
205
+ id: 'local',
206
+ email: null,
207
+ });
208
+ expect(daemon.verify(token)?.scopes).toContain('openbridge:control');
209
+ });
210
+ it('a code is single use, needs the PKCE verifier, and refresh rotates', () => {
211
+ const store = new AccessStore(join(home, 'access.json'));
212
+ const reg = store.registerClient({ redirect_uris: ['http://localhost:4000/cb'], client_name: 'Claude' });
213
+ if (!reg.ok)
214
+ throw new Error('registration failed');
215
+ const verifier = 'v'.repeat(50);
216
+ const code = store.issueCode({
217
+ clientId: reg.id,
218
+ redirectUri: 'http://localhost:4000/cb',
219
+ codeChallenge: s256Challenge(verifier),
220
+ access: 'read',
221
+ }, { id: 'local', email: null });
222
+ const form = (o) => (k) => o[k] ?? '';
223
+ const base = { code, client_id: reg.id, redirect_uri: 'http://localhost:4000/cb' };
224
+ expect(store.exchangeCode(form({ ...base, code_verifier: 'wrong' })).ok).toBe(false);
225
+ const first = store.exchangeCode(form({ ...base, code_verifier: verifier }));
226
+ if (!first.ok)
227
+ throw new Error('exchange failed');
228
+ expect(store.exchangeCode(form({ ...base, code_verifier: verifier })).ok).toBe(false);
229
+ expect(store.verify(first.pair.access_token)?.kind).toBe('oauth');
230
+ const next = store.refresh(form({ refresh_token: first.pair.refresh_token }));
231
+ expect(next.ok).toBe(true);
232
+ expect(store.refresh(form({ refresh_token: first.pair.refresh_token })).ok).toBe(false);
233
+ expect(store.listConnections()).toHaveLength(1);
234
+ expect(store.revokeConnection(reg.id)).toBe(true);
235
+ if (next.ok)
236
+ expect(store.verify(next.pair.access_token)).toBeNull();
237
+ });
238
+ it('refuses redirect targets that are not https or loopback', () => {
239
+ const store = new AccessStore(join(home, 'access.json'));
240
+ expect(store.registerClient({ redirect_uris: ['http://evil.example/cb'] }).ok).toBe(false);
241
+ });
242
+ });
243
+ describe('over HTTP', () => {
244
+ let app;
245
+ let store;
246
+ let bridge;
247
+ async function build(signIn = false) {
248
+ app = Fastify();
249
+ store = new AccessStore(join(home, 'access.json'));
250
+ bridge = makeBridge();
251
+ const authConfig = {
252
+ enabled: signIn,
253
+ issuer: signIn ? 'https://auth.example' : null,
254
+ authOrigin: null,
255
+ appId: null,
256
+ secret: Buffer.from('x'.repeat(32)),
257
+ };
258
+ await registerMcpRoutes(app, { bridge, store, bridgeName: () => 'Home' });
259
+ await registerOauthRoutes(app, { store, authConfig });
260
+ await app.ready();
261
+ }
262
+ afterEach(async () => app?.close());
263
+ const rpc = (body, token) => app.inject({
264
+ method: 'POST',
265
+ url: '/mcp',
266
+ headers: { host: 'bridge.local:8582', ...(token ? { authorization: `Bearer ${token}` } : {}) },
267
+ payload: body,
268
+ });
269
+ it('refuses /mcp without a token even when sign-in is off, and says where to sign in', async () => {
270
+ await build(false);
271
+ const res = await rpc({ jsonrpc: '2.0', id: 1, method: 'tools/list' });
272
+ expect(res.statusCode).toBe(401);
273
+ expect(res.headers['www-authenticate']).toBe('Bearer resource_metadata="http://bridge.local:8582/.well-known/oauth-protected-resource/mcp"');
274
+ });
275
+ it('serves tools to a personal token', async () => {
276
+ await build(false);
277
+ const { token } = store.createToken('t', 'read', { id: 'local', email: null });
278
+ const res = await rpc({ jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name: 'overview', arguments: {} } }, token);
279
+ expect(res.statusCode).toBe(200);
280
+ expect(JSON.parse(res.json().result.content[0].text).devices).toHaveLength(2);
281
+ });
282
+ it('refuses token creation from another site', async () => {
283
+ await build(false);
284
+ const res = await app.inject({
285
+ method: 'POST',
286
+ url: '/api/access/tokens',
287
+ headers: { host: 'bridge.local:8582', origin: 'https://evil.example', 'sec-fetch-site': 'cross-site' },
288
+ payload: { name: 'x', access: 'control' },
289
+ });
290
+ expect(res.statusCode).toBe(403);
291
+ expect(store.listTokens()).toEqual([]);
292
+ const ok = await app.inject({
293
+ method: 'POST',
294
+ url: '/api/access/tokens',
295
+ headers: { host: 'bridge.local:8582', origin: 'http://bridge.local:8582', 'sec-fetch-site': 'same-origin' },
296
+ payload: { name: 'x', access: 'control' },
297
+ });
298
+ expect(ok.statusCode).toBe(200);
299
+ expect(ok.json().token).toMatch(/^obt_pat_/);
300
+ });
301
+ it('completes the connector handshake: discover, register, consent, token, call', async () => {
302
+ await build(false);
303
+ const meta = await app.inject({
304
+ url: '/.well-known/oauth-authorization-server/mcp',
305
+ headers: { host: 'bridge.local:8582' },
306
+ });
307
+ expect(meta.json().token_endpoint).toBe('http://bridge.local:8582/oauth/token');
308
+ const reg = await app.inject({
309
+ method: 'POST',
310
+ url: '/oauth/register',
311
+ payload: { redirect_uris: ['http://localhost:4000/cb'], client_name: 'Claude Code' },
312
+ });
313
+ expect(reg.statusCode).toBe(201);
314
+ const clientId = reg.json().client_id;
315
+ const verifier = 'a'.repeat(64);
316
+ const params = new URLSearchParams({
317
+ client_id: clientId,
318
+ redirect_uri: 'http://localhost:4000/cb',
319
+ response_type: 'code',
320
+ state: 's1',
321
+ code_challenge: s256Challenge(verifier),
322
+ code_challenge_method: 'S256',
323
+ });
324
+ const authz = await app.inject({ url: `/oauth/authorize?${params}` });
325
+ expect(authz.headers.location).toBe(`/oauth/consent?${params}`);
326
+ const context = await app.inject({ url: `/oauth/context?${params}` });
327
+ expect(context.json()).toMatchObject({ ok: true, clientName: 'Claude Code', signedIn: true });
328
+ // A page elsewhere cannot approve on the person's behalf.
329
+ const forged = await app.inject({
330
+ method: 'POST',
331
+ url: '/oauth/authorize',
332
+ headers: {
333
+ 'content-type': 'application/x-www-form-urlencoded',
334
+ 'sec-fetch-site': 'cross-site',
335
+ host: 'bridge.local:8582',
336
+ },
337
+ payload: `${params}&decision=approve&access=control`,
338
+ });
339
+ expect(forged.statusCode).toBe(403);
340
+ const approved = await app.inject({
341
+ method: 'POST',
342
+ url: '/oauth/authorize',
343
+ headers: {
344
+ 'content-type': 'application/x-www-form-urlencoded',
345
+ 'sec-fetch-site': 'same-origin',
346
+ host: 'bridge.local:8582',
347
+ },
348
+ payload: `${params}&decision=approve&access=read`,
349
+ });
350
+ expect(approved.statusCode).toBe(302);
351
+ const back = new URL(approved.headers.location);
352
+ expect(back.searchParams.get('state')).toBe('s1');
353
+ const tok = await app.inject({
354
+ method: 'POST',
355
+ url: '/oauth/token',
356
+ headers: { 'content-type': 'application/x-www-form-urlencoded' },
357
+ payload: new URLSearchParams({
358
+ grant_type: 'authorization_code',
359
+ code: back.searchParams.get('code'),
360
+ client_id: clientId,
361
+ redirect_uri: 'http://localhost:4000/cb',
362
+ code_verifier: verifier,
363
+ }).toString(),
364
+ });
365
+ expect(tok.statusCode).toBe(200);
366
+ expect(tok.json().scope).toBe('openbridge:read');
367
+ const control = await rpc({
368
+ jsonrpc: '2.0',
369
+ id: 1,
370
+ method: 'tools/call',
371
+ params: { name: 'device_control', arguments: { ops: [{ op_id: 'z', device: 'gate', control: 'open' }] } },
372
+ }, tok.json().access_token);
373
+ expect(control.json().result.isError).toBe(true);
374
+ expect(bridge.gate).not.toHaveBeenCalled();
375
+ });
376
+ it('asks for sign-in before consent when dashboard sign-in is on', async () => {
377
+ await build(true);
378
+ const reg = store.registerClient({ redirect_uris: ['http://localhost:4000/cb'] });
379
+ if (!reg.ok)
380
+ throw new Error('registration failed');
381
+ const params = new URLSearchParams({
382
+ client_id: reg.id,
383
+ redirect_uri: 'http://localhost:4000/cb',
384
+ response_type: 'code',
385
+ code_challenge: 'c',
386
+ code_challenge_method: 'S256',
387
+ });
388
+ expect((await app.inject({ url: `/oauth/context?${params}` })).json()).toMatchObject({
389
+ signInRequired: true,
390
+ signedIn: false,
391
+ });
392
+ const res = await app.inject({
393
+ method: 'POST',
394
+ url: '/oauth/authorize',
395
+ headers: { 'content-type': 'application/x-www-form-urlencoded', 'sec-fetch-site': 'same-origin' },
396
+ payload: `${params}&decision=approve`,
397
+ });
398
+ expect(res.headers.location).toMatch(/^\/oauth\/consent\?/);
399
+ });
400
+ });
401
+ describe('sameOrigin', () => {
402
+ const req = (headers) => ({ headers, host: 'bridge.local:8582', protocol: 'http' });
403
+ it('accepts the dashboard and non-browser callers, refuses other sites', () => {
404
+ expect(sameOrigin(req({ 'sec-fetch-site': 'same-origin', origin: 'http://bridge.local:8582' }))).toBe(true);
405
+ expect(sameOrigin(req({}))).toBe(true);
406
+ expect(sameOrigin(req({ origin: 'https://evil.example' }))).toBe(false);
407
+ expect(sameOrigin(req({ 'sec-fetch-site': 'same-site' }))).toBe(false);
408
+ });
409
+ });
410
+ describe('the off switch', () => {
411
+ it('reads only an explicit yes', async () => {
412
+ const { isMcpEnabled } = await import('../mcp/index.js');
413
+ expect(isMcpEnabled(undefined)).toBe(false);
414
+ expect(isMcpEnabled('')).toBe(false);
415
+ expect(isMcpEnabled('off')).toBe(false);
416
+ expect(isMcpEnabled('ON')).toBe(true);
417
+ expect(isMcpEnabled('1')).toBe(true);
418
+ });
419
+ it('serves no MCP, OAuth or token routes until OPENBRIDGE_MCP=on', async () => {
420
+ const previousHome = process.env.HOME;
421
+ const previousFlag = process.env.OPENBRIDGE_MCP;
422
+ process.env.HOME = home;
423
+ try {
424
+ const { createServer } = await import('../server.js');
425
+ const off = await createServer(new PluginRegistry(), null, null, [], new Set(), new Map());
426
+ try {
427
+ const mcp = await off.inject({ method: 'POST', url: '/mcp', payload: {} });
428
+ expect(mcp.statusCode).toBe(404);
429
+ expect(mcp.json().error).toContain('OPENBRIDGE_MCP=on');
430
+ // Unknown paths fall through to the dashboard, so what matters is that
431
+ // nothing answers as the feature would.
432
+ const reg = await off.inject({
433
+ method: 'POST',
434
+ url: '/oauth/register',
435
+ payload: { redirect_uris: ['https://a.example/cb'] },
436
+ });
437
+ expect(reg.statusCode).not.toBe(201);
438
+ await off.inject({ method: 'POST', url: '/api/access/tokens', payload: { name: 'x', access: 'control' } });
439
+ expect(existsSync(join(home, '.openbridge', 'access.json'))).toBe(false);
440
+ expect((await off.inject({ url: '/api/access' })).json()).toEqual({ enabled: false });
441
+ }
442
+ finally {
443
+ await off.close();
444
+ }
445
+ process.env.OPENBRIDGE_MCP = 'on';
446
+ const on = await createServer(new PluginRegistry(), null, null, [], new Set(), new Map());
447
+ try {
448
+ expect((await on.inject({ method: 'POST', url: '/mcp', payload: {} })).statusCode).toBe(401);
449
+ expect((await on.inject({ url: '/api/access' })).json().enabled).toBe(true);
450
+ }
451
+ finally {
452
+ await on.close();
453
+ }
454
+ }
455
+ finally {
456
+ process.env.HOME = previousHome;
457
+ if (previousFlag === undefined)
458
+ delete process.env.OPENBRIDGE_MCP;
459
+ else
460
+ process.env.OPENBRIDGE_MCP = previousFlag;
461
+ }
462
+ });
463
+ });
464
+ //# sourceMappingURL=mcp.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.test.js","sourceRoot":"","sources":["../../src/__tests__/mcp.test.ts"],"names":[],"mappings":"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"}