ftown 0.19.51 → 0.19.53

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 (129) hide show
  1. package/claude-mod/hooks/register.js +6 -5
  2. package/dist/attention-store.d.ts +8 -0
  3. package/dist/attention-store.js +30 -0
  4. package/dist/attention-store.js.map +1 -1
  5. package/dist/bridge-auth.d.ts +1 -0
  6. package/dist/bridge-auth.js +2 -2
  7. package/dist/bridge-auth.js.map +1 -1
  8. package/dist/browser-access.js +8 -1
  9. package/dist/browser-access.js.map +1 -1
  10. package/dist/centrifugo-client.d.ts +11 -1
  11. package/dist/centrifugo-client.js +71 -69
  12. package/dist/centrifugo-client.js.map +1 -1
  13. package/dist/cli-client.d.ts +6 -0
  14. package/dist/cli-client.js +43 -18
  15. package/dist/cli-client.js.map +1 -1
  16. package/dist/command-rpc.d.ts +7 -2
  17. package/dist/command-rpc.js +62 -4
  18. package/dist/command-rpc.js.map +1 -1
  19. package/dist/direct-transport/loopback-server.d.ts +5 -1
  20. package/dist/direct-transport/loopback-server.js +19 -6
  21. package/dist/direct-transport/loopback-server.js.map +1 -1
  22. package/dist/direct-transport/peer-manager.d.ts +4 -0
  23. package/dist/direct-transport/peer-manager.js +16 -2
  24. package/dist/direct-transport/peer-manager.js.map +1 -1
  25. package/dist/ftown-cli.js +4 -1
  26. package/dist/ftown-cli.js.map +1 -1
  27. package/dist/index.js +54 -36
  28. package/dist/index.js.map +1 -1
  29. package/dist/local-api-server.d.ts +12 -0
  30. package/dist/local-api-server.js +190 -44
  31. package/dist/local-api-server.js.map +1 -1
  32. package/dist/local-pair-cli.d.ts +2 -3
  33. package/dist/local-pair-cli.js +12 -53
  34. package/dist/local-pair-cli.js.map +1 -1
  35. package/dist/mcp/fleet.d.ts +11 -9
  36. package/dist/mcp/fleet.js +61 -44
  37. package/dist/mcp/fleet.js.map +1 -1
  38. package/dist/mcp/http.d.ts +10 -9
  39. package/dist/mcp/http.js +133 -8
  40. package/dist/mcp/http.js.map +1 -1
  41. package/dist/mcp/legacy-relay.d.ts +2 -2
  42. package/dist/mcp/legacy-relay.js +4 -43
  43. package/dist/mcp/legacy-relay.js.map +1 -1
  44. package/dist/mcp/mcp-key-store.d.ts +52 -0
  45. package/dist/mcp/mcp-key-store.js +206 -0
  46. package/dist/mcp/mcp-key-store.js.map +1 -0
  47. package/dist/mcp/oauth.d.ts +5 -1
  48. package/dist/mcp/oauth.js +113 -39
  49. package/dist/mcp/oauth.js.map +1 -1
  50. package/dist/mcp/relay-handler.d.ts +2 -1
  51. package/dist/mcp/relay-handler.js +5 -40
  52. package/dist/mcp/relay-handler.js.map +1 -1
  53. package/dist/mcp/relay.d.ts +4 -4
  54. package/dist/mcp/relay.js +35 -85
  55. package/dist/mcp/relay.js.map +1 -1
  56. package/dist/mcp/secure-client.d.ts +23 -0
  57. package/dist/mcp/secure-client.js +124 -0
  58. package/dist/mcp/secure-client.js.map +1 -0
  59. package/dist/mcp/security-events.d.ts +65 -0
  60. package/dist/mcp/security-events.js +210 -0
  61. package/dist/mcp/security-events.js.map +1 -0
  62. package/dist/mcp/server.d.ts +1 -0
  63. package/dist/mcp/server.js +2 -2
  64. package/dist/mcp/server.js.map +1 -1
  65. package/dist/mcp/test-support.d.ts +32 -0
  66. package/dist/mcp/test-support.js +120 -0
  67. package/dist/mcp/test-support.js.map +1 -0
  68. package/dist/mcp-cli.js +56 -36
  69. package/dist/mcp-cli.js.map +1 -1
  70. package/dist/pairing-client.d.ts +1 -0
  71. package/dist/pairing-client.js +2 -2
  72. package/dist/pairing-client.js.map +1 -1
  73. package/dist/push-notifier.js +3 -1
  74. package/dist/push-notifier.js.map +1 -1
  75. package/dist/security/bridge/audit.d.ts +37 -0
  76. package/dist/security/bridge/audit.js +185 -0
  77. package/dist/security/bridge/audit.js.map +1 -0
  78. package/dist/security/bridge/direct.d.ts +22 -0
  79. package/dist/security/bridge/direct.js +72 -0
  80. package/dist/security/bridge/direct.js.map +1 -0
  81. package/dist/security/bridge/errors.d.ts +7 -0
  82. package/dist/security/bridge/errors.js +12 -0
  83. package/dist/security/bridge/errors.js.map +1 -0
  84. package/dist/security/bridge/execute.d.ts +3 -0
  85. package/dist/security/bridge/execute.js +37 -0
  86. package/dist/security/bridge/execute.js.map +1 -0
  87. package/dist/security/bridge/identity.d.ts +5 -0
  88. package/dist/security/bridge/identity.js +42 -0
  89. package/dist/security/bridge/identity.js.map +1 -0
  90. package/dist/security/bridge/local-client.d.ts +4 -0
  91. package/dist/security/bridge/local-client.js +43 -0
  92. package/dist/security/bridge/local-client.js.map +1 -0
  93. package/dist/security/bridge/metadata.d.ts +99 -0
  94. package/dist/security/bridge/metadata.js +23 -0
  95. package/dist/security/bridge/metadata.js.map +1 -0
  96. package/dist/security/bridge/native-wake.d.ts +16 -0
  97. package/dist/security/bridge/native-wake.js +15 -0
  98. package/dist/security/bridge/native-wake.js.map +1 -0
  99. package/dist/security/bridge/permissions.d.ts +11 -0
  100. package/dist/security/bridge/permissions.js +97 -0
  101. package/dist/security/bridge/permissions.js.map +1 -0
  102. package/dist/security/bridge/policy.d.ts +35 -0
  103. package/dist/security/bridge/policy.js +263 -0
  104. package/dist/security/bridge/policy.js.map +1 -0
  105. package/dist/security/bridge/security.d.ts +50 -0
  106. package/dist/security/bridge/security.js +298 -0
  107. package/dist/security/bridge/security.js.map +1 -0
  108. package/dist/security/bridge/snapshot.d.ts +14 -0
  109. package/dist/security/bridge/snapshot.js +77 -0
  110. package/dist/security/bridge/snapshot.js.map +1 -0
  111. package/dist/security/crypto.d.ts +17 -0
  112. package/dist/security/crypto.js +280 -0
  113. package/dist/security/crypto.js.map +1 -0
  114. package/dist/security/protocol.d.ts +389 -0
  115. package/dist/security/protocol.js +9 -0
  116. package/dist/security/protocol.js.map +1 -0
  117. package/dist/security-cli.d.ts +3 -0
  118. package/dist/security-cli.js +62 -0
  119. package/dist/security-cli.js.map +1 -0
  120. package/dist/solo/solo-server.js +24 -2
  121. package/dist/solo/solo-server.js.map +1 -1
  122. package/dist/types.d.ts +9 -2
  123. package/dist/wire-types.d.ts +3 -0
  124. package/dist/wire-types.js.map +1 -1
  125. package/hooks/notify.sh +1 -1
  126. package/muse-plugin/lib/ftown-hook.sh +6 -22
  127. package/opencode-plugin/ftown.js +33 -5
  128. package/package.json +4 -2
  129. package/pi-extension/ftown.js +33 -5
@@ -0,0 +1,50 @@
1
+ import type { ApplicationJson, ApprovedEndpoint, BridgeInvitation, BridgeSecurity, EndpointIdentity, EnrollmentPacket, InboundTransportContext, InvitationOptions, LocalRecoveryAuthority, McpApproval, McpBridgeApproval, SecureApplication, SecureEnvelope, SecurePublication, VerifiedApplication, VerifiedPrincipal } from '../protocol.js';
2
+ import { BridgePolicyStore, type PolicyOptions } from './policy.js';
3
+ import { BridgeAuditStore } from './audit.js';
4
+ export declare const applicationJson: (value: unknown) => ApplicationJson;
5
+ export interface BridgeSecurityOptions extends PolicyOptions {
6
+ relayUserId: string;
7
+ browserOrigin?: string;
8
+ }
9
+ export declare class BridgeSecurityService implements BridgeSecurity {
10
+ readonly identity: EndpointIdentity;
11
+ readonly bridgeId: string;
12
+ readonly options: BridgeSecurityOptions;
13
+ readonly endpoint: import("../protocol.js").EndpointPublic;
14
+ readonly receiverEpoch: `${string}-${string}-${string}-${string}-${string}`;
15
+ readonly policy: BridgePolicyStore;
16
+ readonly audit: BridgeAuditStore;
17
+ private readonly now;
18
+ private readonly replay;
19
+ private readonly revoked;
20
+ private readonly admissions;
21
+ private readonly verified;
22
+ private closed;
23
+ constructor(identity: EndpointIdentity, bridgeId: string, dataDir: string, options: BridgeSecurityOptions);
24
+ private context;
25
+ private freshness;
26
+ private claim;
27
+ private decode;
28
+ private reply;
29
+ handleHandshake(packet: SecureEnvelope | EnrollmentPacket, route: InboundTransportContext): Promise<SecureEnvelope>;
30
+ private parseApplication;
31
+ private requirement;
32
+ private admission;
33
+ acceptApplication(packet: SecureEnvelope, route: InboundTransportContext): Promise<VerifiedApplication>;
34
+ revalidate(principal: VerifiedPrincipal): Promise<void>;
35
+ /** One non-content receipt, prepared while authorized and released only after durable self-removal. */
36
+ revokeSelfWithReceipt(message: VerifiedApplication, route: InboundTransportContext): Promise<SecureEnvelope | null>;
37
+ complete(message: VerifiedApplication, status: 'succeeded' | 'rejected' | 'failed' | 'unknown', errorCode?: string | null): Promise<void>;
38
+ sealTo(recipientId: string, application: SecureApplication, route: InboundTransportContext): Promise<SecureEnvelope>;
39
+ sealPublication(channel: string, application: SecureApplication): Promise<(SecureEnvelope | SecurePublication)[]>;
40
+ createInvitation(actor: VerifiedPrincipal | LocalRecoveryAuthority, options: InvitationOptions): Promise<BridgeInvitation>;
41
+ listDevices(actor: VerifiedPrincipal): Promise<ApprovedEndpoint[]>;
42
+ approveMcp(actor: VerifiedPrincipal, approval: McpApproval): Promise<McpBridgeApproval>;
43
+ activateMcp(actor: VerifiedPrincipal, grantId: string): Promise<{
44
+ grantId: string;
45
+ expiresAt: string;
46
+ }>;
47
+ revokeEndpoint(actor: VerifiedPrincipal, endpointId: string): Promise<void>;
48
+ onRevoked(listener: (endpointId: string) => void): () => void;
49
+ close(): Promise<void>;
50
+ }
@@ -0,0 +1,298 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { z } from 'zod';
3
+ import { open, seal, parseSecureEnvelope } from '../crypto.js';
4
+ import { BridgePolicyStore } from './policy.js';
5
+ import { BridgeAuditStore } from './audit.js';
6
+ import { BridgeSecurityError } from './errors.js';
7
+ import { classifyCommand, classifyHttp, classifyTerminal } from './permissions.js';
8
+ import { endpointSchema } from './metadata.js';
9
+ const token = z.string().regex(/^[A-Za-z0-9_-]{1,200}$/);
10
+ const actionSchema = z.object({ actionId: token, parentActionId: token.nullable(), clientId: token, grantId: token,
11
+ tool: z.string().max(200), operation: z.string().max(200).nullable() }).strict();
12
+ const routeSchema = z.discriminatedUnion('kind', [
13
+ z.object({ kind: z.literal('command'), requestId: token, command: z.string().min(1).max(100), sessionId: token.nullable() }).strict(),
14
+ z.object({ kind: z.literal('http'), requestId: token, method: z.enum(['GET', 'POST', 'PATCH', 'PUT', 'DELETE']), path: z.string().max(16384) }).strict(),
15
+ z.object({ kind: z.literal('terminal'), sessionId: z.string().max(200), frameType: z.string().max(50), pairId: token.nullable() }).strict(),
16
+ z.object({ kind: z.literal('response'), requestId: token }).strict(), z.object({ kind: z.literal('publication') }).strict(),
17
+ ]);
18
+ const object = (value) => {
19
+ if (!value || typeof value !== 'object' || Array.isArray(value))
20
+ throw new BridgeSecurityError('invalid_envelope');
21
+ return value;
22
+ };
23
+ export const applicationJson = (value) => JSON.parse(JSON.stringify(value));
24
+ export class BridgeSecurityService {
25
+ identity;
26
+ bridgeId;
27
+ options;
28
+ endpoint;
29
+ receiverEpoch = randomUUID();
30
+ policy;
31
+ audit;
32
+ now;
33
+ replay = new Map();
34
+ revoked = new Set();
35
+ admissions = new Map();
36
+ verified = new WeakSet();
37
+ closed = false;
38
+ constructor(identity, bridgeId, dataDir, options) {
39
+ this.identity = identity;
40
+ this.bridgeId = bridgeId;
41
+ this.options = options;
42
+ this.endpoint = identity.endpoint;
43
+ this.now = options.now ?? Date.now;
44
+ this.policy = new BridgePolicyStore(dataDir, bridgeId, this.endpoint, options);
45
+ this.audit = new BridgeAuditStore(dataDir, this.endpoint.ownerId, bridgeId, options);
46
+ }
47
+ context(route) {
48
+ if (this.closed || route.bridgeId !== this.bridgeId)
49
+ throw new BridgeSecurityError('wrong_context');
50
+ const expected = route.transport === 'local-http' ? `local-http:${this.bridgeId}`
51
+ : route.transport === 'local-events' ? `local-events:${this.bridgeId}`
52
+ : route.transport === 'cloud' ? route.channel
53
+ : `direct:${route.transport}:${this.bridgeId}:${route.pairId}`;
54
+ if (expected !== route.channel || ((route.transport === 'webrtc' || route.transport === 'loopback-ws') && !route.pairId)) {
55
+ throw new BridgeSecurityError('wrong_context');
56
+ }
57
+ }
58
+ freshness(envelope, executable) {
59
+ const now = this.now();
60
+ if (envelope.createdAt > now + 30000 || envelope.expiresAt <= now || envelope.expiresAt - envelope.createdAt > 120000) {
61
+ throw new BridgeSecurityError('expired');
62
+ }
63
+ if (executable && envelope.receiverEpoch !== this.receiverEpoch)
64
+ throw new BridgeSecurityError('epoch_changed');
65
+ }
66
+ claim(envelope) {
67
+ const now = this.now();
68
+ for (const [id, expires] of this.replay)
69
+ if (expires <= now)
70
+ this.replay.delete(id);
71
+ const id = `${envelope.senderId}:${envelope.messageId}`;
72
+ if (this.replay.has(id))
73
+ throw new BridgeSecurityError('replayed');
74
+ if (this.replay.size >= 10000)
75
+ throw new BridgeSecurityError('capacity_exceeded');
76
+ this.replay.set(id, envelope.expiresAt);
77
+ }
78
+ async decode(sender, envelope, route) {
79
+ this.context(route);
80
+ const bytes = await open(this.identity, sender, envelope, { ownerId: this.endpoint.ownerId, bridgeId: this.bridgeId,
81
+ channel: route.channel, recipientId: this.endpoint.id, purpose: envelope.purpose });
82
+ try {
83
+ return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
84
+ }
85
+ catch {
86
+ throw new BridgeSecurityError('invalid_envelope');
87
+ }
88
+ }
89
+ async reply(recipient, purpose, data, route, messageId = randomUUID()) {
90
+ this.context(route);
91
+ return seal(this.identity, recipient, { type: 'ftown_encrypted', version: 1, senderId: this.endpoint.id, recipientId: recipient.id,
92
+ ownerId: this.endpoint.ownerId, bridgeId: this.bridgeId, channel: route.channel, purpose, messageId,
93
+ createdAt: this.now(), expiresAt: this.now() + 120000, receiverEpoch: null }, new TextEncoder().encode(JSON.stringify(data)));
94
+ }
95
+ async handleHandshake(packet, route) {
96
+ this.context(route);
97
+ if (packet.type === 'ftown_enrollment') {
98
+ const wrapper = z.object({ type: z.literal('ftown_enrollment'), version: z.literal(1), candidate: endpointSchema, envelope: z.unknown() }).strict().parse(packet);
99
+ const envelope = parseSecureEnvelope(wrapper.envelope);
100
+ if (envelope.purpose !== 'enroll')
101
+ throw new BridgeSecurityError('wrong_context');
102
+ this.freshness(envelope, false);
103
+ const message = z.object({ type: z.literal('enroll'), candidate: endpointSchema, invitationId: z.string().uuid(),
104
+ invitationSecret: z.string().regex(/^[A-Za-z0-9_-]{43}$/), label: z.string().max(200) }).strict().parse(await this.decode(wrapper.candidate, envelope, route));
105
+ if (JSON.stringify(message.candidate) !== JSON.stringify(wrapper.candidate))
106
+ throw new BridgeSecurityError('wrong_context');
107
+ const approved = await this.policy.consumeInvitation(message);
108
+ return this.reply(approved.endpoint, 'enrolled', { type: 'enrolled', invitationId: message.invitationId, approved, receiverEpoch: this.receiverEpoch }, route, envelope.messageId);
109
+ }
110
+ const envelope = parseSecureEnvelope(packet);
111
+ if (envelope.purpose !== 'hello')
112
+ throw new BridgeSecurityError('wrong_context');
113
+ this.freshness(envelope, false);
114
+ const principal = await this.policy.principal(envelope.senderId, true);
115
+ const hello = z.object({ type: z.literal('hello'), challenge: token }).strict().parse(await this.decode(principal.endpoint, envelope, route));
116
+ return this.reply(principal.endpoint, 'welcome', { type: 'welcome', challenge: hello.challenge, receiverEpoch: this.receiverEpoch }, route, envelope.messageId);
117
+ }
118
+ parseApplication(value) {
119
+ const parsed = z.object({ type: z.literal('application'), route: routeSchema, data: z.unknown(), mcp: actionSchema.nullable() }).strict().parse(value);
120
+ return { ...parsed, data: applicationJson(parsed.data) };
121
+ }
122
+ requirement(application, transport) {
123
+ const route = application.route;
124
+ if ((transport.transport === 'webrtc' || transport.transport === 'loopback-ws') && route.kind !== 'terminal') {
125
+ throw new BridgeSecurityError('wrong_context');
126
+ }
127
+ if (route.kind === 'command') {
128
+ const data = object(application.data);
129
+ if (['terminal_watch', 'terminal_unwatch', 'webrtc_offer', 'webrtc_answer', 'webrtc_ice', 'webrtc_close'].includes(route.command)) {
130
+ if (data.type !== route.command || (data.bridgeId !== undefined && data.bridgeId !== this.bridgeId)
131
+ || (typeof data.sessionId === 'string' ? data.sessionId : null) !== route.sessionId)
132
+ throw new BridgeSecurityError('wrong_context');
133
+ return classifyCommand(route.command, data);
134
+ }
135
+ const payload = object(data.payload ?? null);
136
+ if (data.type !== route.command || data.requestId !== route.requestId || payload.bridgeId !== this.bridgeId
137
+ || (typeof payload.sessionId === 'string' ? payload.sessionId : null) !== route.sessionId)
138
+ throw new BridgeSecurityError('wrong_context');
139
+ return classifyCommand(route.command, payload);
140
+ }
141
+ if (route.kind === 'http') {
142
+ const data = object(application.data);
143
+ if (Object.keys(data).some(key => key !== 'body' && key !== 'timeoutMs' && key !== 'callerSessionId')
144
+ || (data.timeoutMs !== undefined && (typeof data.timeoutMs !== 'number' || !Number.isInteger(data.timeoutMs) || data.timeoutMs < 1 || data.timeoutMs > 60000)))
145
+ throw new BridgeSecurityError('invalid_envelope');
146
+ return classifyHttp(route.method, route.path);
147
+ }
148
+ if (route.kind === 'terminal') {
149
+ const data = object(application.data);
150
+ if (route.pairId !== transport.pairId || data.kind !== route.frameType
151
+ || (typeof data.sessionId === 'string' ? data.sessionId : '') !== route.sessionId)
152
+ throw new BridgeSecurityError('wrong_context');
153
+ if (route.sessionId && !/^[A-Za-z0-9_-]+$/.test(route.sessionId))
154
+ throw new BridgeSecurityError('invalid_envelope');
155
+ return classifyTerminal(route.frameType);
156
+ }
157
+ throw new BridgeSecurityError('permission_denied');
158
+ }
159
+ async admission(envelope, principal, app, operation) {
160
+ if (principal.endpoint.kind !== 'mcp') {
161
+ if (app.mcp !== null)
162
+ throw new BridgeSecurityError('permission_denied');
163
+ return;
164
+ }
165
+ const context = app.mcp;
166
+ if (!context || context.grantId !== principal.grantId)
167
+ throw new BridgeSecurityError('wrong_context');
168
+ const admitted = await this.audit.admit({ admissionId: envelope.messageId, ...context, endpointId: principal.endpoint.id,
169
+ operation: operation.operation, sessionId: operation.sessionId, mutating: operation.mutating });
170
+ if (!admitted.isNew)
171
+ throw new BridgeSecurityError('replayed');
172
+ this.admissions.set(`${envelope.senderId}:${envelope.messageId}`, admitted.event.id);
173
+ }
174
+ async acceptApplication(packet, route) {
175
+ const envelope = parseSecureEnvelope(packet);
176
+ if (envelope.purpose !== 'application')
177
+ throw new BridgeSecurityError('wrong_context');
178
+ const principal = await this.policy.principal(envelope.senderId, true);
179
+ const app = this.parseApplication(await this.decode(principal.endpoint, envelope, route));
180
+ if (app.route.kind === 'http') {
181
+ const data = object(app.data);
182
+ if (data.callerSessionId !== undefined && (principal.endpoint.kind !== 'local-cli'
183
+ || typeof data.callerSessionId !== 'string' || !/^[A-Za-z0-9_-]{1,200}$/.test(data.callerSessionId)))
184
+ throw new BridgeSecurityError('permission_denied');
185
+ }
186
+ this.freshness(envelope, true);
187
+ this.claim(envelope);
188
+ // Pending identities can do precisely this one bound operation; never generic application work.
189
+ if (app.route.kind === 'command' && app.route.command === 'security_activate_mcp') {
190
+ const data = object(app.data);
191
+ const payload = object(data.payload ?? null);
192
+ if (data.type !== app.route.command || data.requestId !== app.route.requestId || payload.bridgeId !== this.bridgeId
193
+ || payload.grantId !== principal.grantId || principal.endpoint.kind !== 'mcp')
194
+ throw new BridgeSecurityError('permission_denied');
195
+ const message = { principal, envelope, application: app };
196
+ this.verified.add(message);
197
+ return message;
198
+ }
199
+ let operation;
200
+ try {
201
+ operation = this.requirement(app, route);
202
+ }
203
+ catch (error) {
204
+ if (principal.endpoint.kind === 'mcp' && app.mcp) {
205
+ await this.admission(envelope, principal, app, { permission: 'control', mutating: true, operation: 'invalid_operation', sessionId: null });
206
+ await this.complete({ principal, envelope, application: app }, 'rejected', 'permission_denied');
207
+ }
208
+ throw error;
209
+ }
210
+ await this.admission(envelope, principal, app, operation);
211
+ try {
212
+ await this.policy.revalidate(principal, operation.permission);
213
+ }
214
+ catch (error) {
215
+ await this.complete({ principal, envelope, application: app }, 'rejected', 'permission_denied');
216
+ throw error;
217
+ }
218
+ const message = { principal, envelope, application: app };
219
+ this.verified.add(message);
220
+ return message;
221
+ }
222
+ async revalidate(principal) { await this.policy.revalidate(principal); }
223
+ /** One non-content receipt, prepared while authorized and released only after durable self-removal. */
224
+ async revokeSelfWithReceipt(message, route) {
225
+ const application = message.application;
226
+ if (application.route.kind !== 'command' || application.route.command !== 'security_revoke')
227
+ return null;
228
+ const data = object(application.data);
229
+ const payload = object(data.payload ?? null);
230
+ if (payload.endpointId !== message.principal.endpoint.id)
231
+ return null;
232
+ if (!this.verified.has(message) || message.envelope.senderId !== message.principal.endpoint.id
233
+ || message.envelope.channel !== route.channel || message.envelope.bridgeId !== route.bridgeId
234
+ || message.envelope.messageId !== application.route.requestId || payload.bridgeId !== this.bridgeId) {
235
+ throw new BridgeSecurityError('wrong_context');
236
+ }
237
+ await this.policy.revalidate(message.principal, 'admin');
238
+ const receipt = await this.reply(message.principal.endpoint, 'application', { type: 'application',
239
+ route: { kind: 'response', requestId: application.route.requestId }, mcp: null,
240
+ data: { type: 'command_response', response: { requestId: application.route.requestId, success: true,
241
+ data: { endpointId: message.principal.endpoint.id, revoked: true } } } }, route, application.route.requestId);
242
+ // No sealed value leaves this method before both persistence steps have succeeded.
243
+ await this.revokeEndpoint(message.principal, message.principal.endpoint.id);
244
+ await this.complete(message, 'succeeded');
245
+ this.verified.delete(message);
246
+ return receipt;
247
+ }
248
+ async complete(message, status, errorCode = null) {
249
+ const key = `${message.envelope.senderId}:${message.envelope.messageId}`;
250
+ const admission = this.admissions.get(key);
251
+ if (!admission)
252
+ return;
253
+ try {
254
+ await this.audit.finish(admission, status, errorCode);
255
+ this.admissions.delete(key);
256
+ }
257
+ catch {
258
+ throw new BridgeSecurityError('outcome_unknown');
259
+ }
260
+ }
261
+ async sealTo(recipientId, application, route) {
262
+ const principal = await this.policy.principal(recipientId);
263
+ const envelope = await this.reply(principal.endpoint, 'application', application, route, application.route.kind === 'response' ? application.route.requestId : randomUUID());
264
+ await this.policy.revalidate(principal);
265
+ return envelope;
266
+ }
267
+ async sealPublication(channel, application) {
268
+ const recipients = await this.policy.recipients();
269
+ const packets = [];
270
+ for (const recipient of recipients) {
271
+ try {
272
+ packets.push(await this.sealTo(recipient.endpoint.id, application, { transport: 'cloud', channel, bridgeId: this.bridgeId, pairId: null }));
273
+ }
274
+ catch (error) {
275
+ if (!(error instanceof BridgeSecurityError) || !['endpoint_revoked', 'approval_required', 'expired'].includes(error.code))
276
+ throw error;
277
+ }
278
+ }
279
+ return packets;
280
+ }
281
+ createInvitation(actor, options) { return this.policy.createInvitation(actor, options); }
282
+ listDevices(actor) { return this.policy.list(actor); }
283
+ async approveMcp(actor, approval) {
284
+ const receipt = await this.policy.approveMcp(actor, approval);
285
+ const envelope = await this.reply(approval.endpoint, 'mcp-approval', receipt, { transport: 'cloud', channel: `mcp-approval:${this.bridgeId}:${approval.requestId}`,
286
+ bridgeId: this.bridgeId, pairId: null });
287
+ return { bridgeId: this.bridgeId, bridge: this.endpoint, receipt: envelope };
288
+ }
289
+ activateMcp(actor, grantId) { return this.policy.activateMcp(actor, grantId); }
290
+ async revokeEndpoint(actor, endpointId) {
291
+ await this.policy.revoke(actor, endpointId);
292
+ for (const listener of this.revoked)
293
+ listener(endpointId);
294
+ }
295
+ onRevoked(listener) { this.revoked.add(listener); return () => this.revoked.delete(listener); }
296
+ async close() { this.closed = true; this.revoked.clear(); this.replay.clear(); await this.audit.close(); await this.policy.close(); }
297
+ }
298
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../../src/security/bridge/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { z } from 'zod';
2
+ /** One process owns each instance directory. Never publish in-memory state before durable replacement. */
3
+ export declare class AtomicSnapshot<T> {
4
+ private readonly file;
5
+ private readonly schema;
6
+ private readonly initial;
7
+ private tail;
8
+ constructor(file: string, schema: z.ZodType<T>, initial: () => T);
9
+ private load;
10
+ private save;
11
+ transact<R>(update: (state: T) => R | Promise<R>): Promise<R>;
12
+ read<R>(select: (state: T) => R): Promise<R>;
13
+ close(): Promise<void>;
14
+ }
@@ -0,0 +1,77 @@
1
+ import { mkdir, open, rename, rm } from 'node:fs/promises';
2
+ import { dirname } from 'node:path';
3
+ import { randomUUID } from 'node:crypto';
4
+ import { BridgeSecurityError } from './errors.js';
5
+ /** One process owns each instance directory. Never publish in-memory state before durable replacement. */
6
+ export class AtomicSnapshot {
7
+ file;
8
+ schema;
9
+ initial;
10
+ tail = Promise.resolve();
11
+ constructor(file, schema, initial) {
12
+ this.file = file;
13
+ this.schema = schema;
14
+ this.initial = initial;
15
+ }
16
+ async load() {
17
+ let handle;
18
+ try {
19
+ handle = await open(this.file, 'r');
20
+ if ((await handle.stat()).size > 64 * 1024 * 1024)
21
+ throw new Error('Oversize snapshot');
22
+ return this.schema.parse(JSON.parse(await handle.readFile('utf8')));
23
+ }
24
+ catch (error) {
25
+ if (error.code === 'ENOENT')
26
+ return this.initial();
27
+ throw new BridgeSecurityError('storage_unavailable');
28
+ }
29
+ finally {
30
+ await handle?.close();
31
+ }
32
+ }
33
+ async save(value) {
34
+ const directory = dirname(this.file);
35
+ const temporary = `${this.file}.${randomUUID()}.tmp`;
36
+ try {
37
+ await mkdir(directory, { recursive: true, mode: 0o700 });
38
+ const handle = await open(temporary, 'wx', 0o600);
39
+ try {
40
+ await handle.writeFile(JSON.stringify(this.schema.parse(value)));
41
+ await handle.sync();
42
+ }
43
+ finally {
44
+ await handle.close();
45
+ }
46
+ await rename(temporary, this.file);
47
+ const parent = await open(directory, 'r');
48
+ try {
49
+ await parent.sync();
50
+ }
51
+ finally {
52
+ await parent.close();
53
+ }
54
+ }
55
+ catch {
56
+ await rm(temporary, { force: true }).catch(() => undefined);
57
+ throw new BridgeSecurityError('storage_unavailable');
58
+ }
59
+ }
60
+ transact(update) {
61
+ const run = this.tail.then(async () => {
62
+ const state = await this.load();
63
+ const result = await update(state);
64
+ await this.save(state);
65
+ return structuredClone(result);
66
+ });
67
+ this.tail = run.catch(() => undefined);
68
+ return run;
69
+ }
70
+ read(select) {
71
+ const run = this.tail.then(async () => structuredClone(select(await this.load())));
72
+ this.tail = run.catch(() => undefined);
73
+ return run;
74
+ }
75
+ async close() { await this.tail; }
76
+ }
77
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../../src/security/bridge/snapshot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { EndpointIdentity, EndpointKind, EndpointPublic, EnvelopeHeader, OpenContext, SecureEnvelope, SecurePublication, SecurityErrorCode, SecurityFailure } from './protocol.js';
2
+ /** Wire limits apply to serialized UTF-8, including headers and base64 expansion. */
3
+ export declare const MAX_ENVELOPE_BYTES = 450000;
4
+ /** A safe, stable error: underlying crypto/input details never cross this boundary. */
5
+ export declare class SecurityError extends Error implements SecurityFailure {
6
+ readonly code: SecurityErrorCode;
7
+ readonly retryable: boolean;
8
+ constructor(code: SecurityErrorCode, message: string, retryable?: boolean);
9
+ }
10
+ export declare function parseSecureEnvelope(value: unknown): SecureEnvelope;
11
+ export declare function parseSecurePublication(value: unknown): SecurePublication;
12
+ export declare function exportPublicKey(key: CryptoKey): Promise<string>;
13
+ export declare function importPublicKey(raw: string): Promise<CryptoKey>;
14
+ export declare function generateEndpoint(ownerId: string, kind: EndpointKind, extractable?: boolean): Promise<EndpointIdentity>;
15
+ export declare function importEndpoint(endpoint: EndpointPublic, privateKey: JsonWebKey, extractable?: boolean): Promise<EndpointIdentity>;
16
+ export declare function seal(identity: EndpointIdentity, recipient: EndpointPublic, input: EnvelopeHeader, plaintext: Uint8Array): Promise<SecureEnvelope>;
17
+ export declare function open(identity: EndpointIdentity, sender: EndpointPublic, value: SecureEnvelope, expected: OpenContext): Promise<Uint8Array>;