@dupecom/botcha-cloudflare 0.16.0 → 0.18.0

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.
@@ -0,0 +1,396 @@
1
+ /**
2
+ * TAP Capability Attestation API Routes
3
+ *
4
+ * Endpoints for issuing, retrieving, revoking, and verifying
5
+ * capability attestation tokens for TAP agents.
6
+ *
7
+ * Routes:
8
+ * POST /v1/attestations — Issue attestation token
9
+ * GET /v1/attestations/:id — Get attestation details
10
+ * GET /v1/attestations — List attestations for agent
11
+ * POST /v1/attestations/:id/revoke — Revoke attestation
12
+ * POST /v1/verify/attestation — Verify attestation + check capability
13
+ */
14
+ import { extractBearerToken, verifyToken } from './auth.js';
15
+ import { issueAttestation, getAttestation, revokeAttestation, verifyAttestationToken, verifyAndCheckCapability, isValidCapabilityPattern, } from './tap-attestation.js';
16
+ // ============ VALIDATION HELPERS ============
17
+ async function validateAppAccess(c, requireAuth = true) {
18
+ const queryAppId = c.req.query('app_id');
19
+ let jwtAppId;
20
+ const authHeader = c.req.header('authorization');
21
+ const token = extractBearerToken(authHeader);
22
+ if (token) {
23
+ const result = await verifyToken(token, c.env.JWT_SECRET, c.env);
24
+ if (result.valid && result.payload) {
25
+ jwtAppId = result.payload.app_id;
26
+ }
27
+ }
28
+ const appId = queryAppId || jwtAppId;
29
+ if (requireAuth && !appId) {
30
+ return { valid: false, error: 'MISSING_APP_ID', status: 401 };
31
+ }
32
+ return { valid: true, appId };
33
+ }
34
+ // ============ ROUTE HANDLERS ============
35
+ /**
36
+ * POST /v1/attestations
37
+ * Issue a capability attestation token for an agent
38
+ */
39
+ export async function issueAttestationRoute(c) {
40
+ try {
41
+ const appAccess = await validateAppAccess(c, true);
42
+ if (!appAccess.valid) {
43
+ return c.json({
44
+ success: false,
45
+ error: appAccess.error,
46
+ message: 'Authentication required'
47
+ }, (appAccess.status || 401));
48
+ }
49
+ const body = await c.req.json().catch(() => ({}));
50
+ // Validate required fields
51
+ if (!body.agent_id) {
52
+ return c.json({
53
+ success: false,
54
+ error: 'MISSING_AGENT_ID',
55
+ message: 'agent_id is required'
56
+ }, 400);
57
+ }
58
+ if (!body.can || !Array.isArray(body.can) || body.can.length === 0) {
59
+ return c.json({
60
+ success: false,
61
+ error: 'MISSING_CAPABILITIES',
62
+ message: 'At least one "can" rule is required (e.g. ["read:invoices", "browse:*"])'
63
+ }, 400);
64
+ }
65
+ // Validate capability patterns
66
+ for (const rule of body.can) {
67
+ if (!isValidCapabilityPattern(rule)) {
68
+ return c.json({
69
+ success: false,
70
+ error: 'INVALID_CAPABILITY_PATTERN',
71
+ message: `Invalid capability pattern in "can": ${rule}. Use "action:resource" format.`
72
+ }, 400);
73
+ }
74
+ }
75
+ if (body.cannot && Array.isArray(body.cannot)) {
76
+ for (const rule of body.cannot) {
77
+ if (!isValidCapabilityPattern(rule)) {
78
+ return c.json({
79
+ success: false,
80
+ error: 'INVALID_CAPABILITY_PATTERN',
81
+ message: `Invalid capability pattern in "cannot": ${rule}. Use "action:resource" format.`
82
+ }, 400);
83
+ }
84
+ }
85
+ }
86
+ const options = {
87
+ agent_id: body.agent_id,
88
+ can: body.can,
89
+ cannot: body.cannot,
90
+ restrictions: body.restrictions,
91
+ duration_seconds: body.duration_seconds,
92
+ delegation_id: body.delegation_id,
93
+ metadata: body.metadata,
94
+ };
95
+ const result = await issueAttestation(c.env.AGENTS, c.env.SESSIONS, appAccess.appId, c.env.JWT_SECRET, options);
96
+ if (!result.success) {
97
+ const status = result.error?.includes('not found') ? 404
98
+ : result.error?.includes('does not belong') ? 403
99
+ : result.error?.includes('Too many rules') ? 400
100
+ : 400;
101
+ return c.json({
102
+ success: false,
103
+ error: 'ATTESTATION_ISSUANCE_FAILED',
104
+ message: result.error
105
+ }, status);
106
+ }
107
+ const att = result.attestation;
108
+ return c.json({
109
+ success: true,
110
+ attestation_id: att.attestation_id,
111
+ agent_id: att.agent_id,
112
+ app_id: att.app_id,
113
+ token: att.token,
114
+ can: att.can,
115
+ cannot: att.cannot,
116
+ restrictions: att.restrictions || null,
117
+ delegation_id: att.delegation_id || null,
118
+ metadata: att.metadata || null,
119
+ created_at: new Date(att.created_at).toISOString(),
120
+ expires_at: new Date(att.expires_at).toISOString(),
121
+ }, 201);
122
+ }
123
+ catch (error) {
124
+ console.error('Attestation issuance error:', error);
125
+ return c.json({
126
+ success: false,
127
+ error: 'INTERNAL_ERROR',
128
+ message: 'Internal server error'
129
+ }, 500);
130
+ }
131
+ }
132
+ /**
133
+ * GET /v1/attestations/:id
134
+ * Get attestation details
135
+ */
136
+ export async function getAttestationRoute(c) {
137
+ try {
138
+ const attestationId = c.req.param('id');
139
+ if (!attestationId) {
140
+ return c.json({
141
+ success: false,
142
+ error: 'MISSING_ATTESTATION_ID',
143
+ message: 'Attestation ID is required'
144
+ }, 400);
145
+ }
146
+ const result = await getAttestation(c.env.SESSIONS, attestationId);
147
+ if (!result.success || !result.attestation) {
148
+ return c.json({
149
+ success: false,
150
+ error: 'ATTESTATION_NOT_FOUND',
151
+ message: result.error || 'Attestation not found or expired'
152
+ }, 404);
153
+ }
154
+ const att = result.attestation;
155
+ return c.json({
156
+ success: true,
157
+ attestation_id: att.attestation_id,
158
+ agent_id: att.agent_id,
159
+ app_id: att.app_id,
160
+ can: att.can,
161
+ cannot: att.cannot,
162
+ restrictions: att.restrictions || null,
163
+ delegation_id: att.delegation_id || null,
164
+ metadata: att.metadata || null,
165
+ created_at: new Date(att.created_at).toISOString(),
166
+ expires_at: new Date(att.expires_at).toISOString(),
167
+ revoked: att.revoked,
168
+ revoked_at: att.revoked_at ? new Date(att.revoked_at).toISOString() : null,
169
+ revocation_reason: att.revocation_reason || null,
170
+ time_remaining: Math.max(0, att.expires_at - Date.now()),
171
+ });
172
+ }
173
+ catch (error) {
174
+ console.error('Attestation retrieval error:', error);
175
+ return c.json({
176
+ success: false,
177
+ error: 'INTERNAL_ERROR',
178
+ message: 'Internal server error'
179
+ }, 500);
180
+ }
181
+ }
182
+ /**
183
+ * GET /v1/attestations
184
+ * List attestations for an agent
185
+ *
186
+ * Query params:
187
+ * agent_id — required, the agent to list attestations for
188
+ */
189
+ export async function listAttestationsRoute(c) {
190
+ try {
191
+ const appAccess = await validateAppAccess(c, true);
192
+ if (!appAccess.valid) {
193
+ return c.json({
194
+ success: false,
195
+ error: appAccess.error,
196
+ message: 'Authentication required'
197
+ }, (appAccess.status || 401));
198
+ }
199
+ const agentId = c.req.query('agent_id');
200
+ if (!agentId) {
201
+ return c.json({
202
+ success: false,
203
+ error: 'MISSING_AGENT_ID',
204
+ message: 'agent_id query parameter is required'
205
+ }, 400);
206
+ }
207
+ // Get the attestation index for this agent
208
+ const indexKey = `agent_attestations:${agentId}`;
209
+ const indexData = await c.env.SESSIONS.get(indexKey, 'text');
210
+ const attestationIds = indexData ? JSON.parse(indexData) : [];
211
+ // Fetch each attestation (filter out expired/missing)
212
+ const attestations = [];
213
+ for (const id of attestationIds) {
214
+ const result = await getAttestation(c.env.SESSIONS, id);
215
+ if (result.success && result.attestation) {
216
+ const att = result.attestation;
217
+ // Only include attestations for this app
218
+ if (att.app_id === appAccess.appId) {
219
+ attestations.push({
220
+ attestation_id: att.attestation_id,
221
+ agent_id: att.agent_id,
222
+ can: att.can,
223
+ cannot: att.cannot,
224
+ created_at: new Date(att.created_at).toISOString(),
225
+ expires_at: new Date(att.expires_at).toISOString(),
226
+ revoked: att.revoked,
227
+ delegation_id: att.delegation_id || null,
228
+ });
229
+ }
230
+ }
231
+ }
232
+ return c.json({
233
+ success: true,
234
+ attestations,
235
+ count: attestations.length,
236
+ agent_id: agentId,
237
+ });
238
+ }
239
+ catch (error) {
240
+ console.error('Attestation listing error:', error);
241
+ return c.json({
242
+ success: false,
243
+ error: 'INTERNAL_ERROR',
244
+ message: 'Internal server error'
245
+ }, 500);
246
+ }
247
+ }
248
+ /**
249
+ * POST /v1/attestations/:id/revoke
250
+ * Revoke an attestation
251
+ */
252
+ export async function revokeAttestationRoute(c) {
253
+ try {
254
+ const attestationId = c.req.param('id');
255
+ if (!attestationId) {
256
+ return c.json({
257
+ success: false,
258
+ error: 'MISSING_ATTESTATION_ID',
259
+ message: 'Attestation ID is required'
260
+ }, 400);
261
+ }
262
+ const appAccess = await validateAppAccess(c, true);
263
+ if (!appAccess.valid) {
264
+ return c.json({
265
+ success: false,
266
+ error: appAccess.error,
267
+ message: 'Authentication required'
268
+ }, (appAccess.status || 401));
269
+ }
270
+ // Verify attestation exists and belongs to this app
271
+ const existing = await getAttestation(c.env.SESSIONS, attestationId);
272
+ if (!existing.success || !existing.attestation) {
273
+ return c.json({
274
+ success: false,
275
+ error: 'ATTESTATION_NOT_FOUND',
276
+ message: 'Attestation not found or expired'
277
+ }, 404);
278
+ }
279
+ if (existing.attestation.app_id !== appAccess.appId) {
280
+ return c.json({
281
+ success: false,
282
+ error: 'UNAUTHORIZED',
283
+ message: 'Attestation does not belong to this app'
284
+ }, 403);
285
+ }
286
+ const body = await c.req.json().catch(() => ({}));
287
+ const reason = body.reason || undefined;
288
+ const result = await revokeAttestation(c.env.SESSIONS, attestationId, reason);
289
+ if (!result.success) {
290
+ return c.json({
291
+ success: false,
292
+ error: 'REVOCATION_FAILED',
293
+ message: result.error
294
+ }, 500);
295
+ }
296
+ const att = result.attestation;
297
+ return c.json({
298
+ success: true,
299
+ attestation_id: att.attestation_id,
300
+ revoked: true,
301
+ revoked_at: att.revoked_at ? new Date(att.revoked_at).toISOString() : null,
302
+ revocation_reason: att.revocation_reason || null,
303
+ message: 'Attestation revoked. Token will be rejected on verification.',
304
+ });
305
+ }
306
+ catch (error) {
307
+ console.error('Attestation revocation error:', error);
308
+ return c.json({
309
+ success: false,
310
+ error: 'INTERNAL_ERROR',
311
+ message: 'Internal server error'
312
+ }, 500);
313
+ }
314
+ }
315
+ /**
316
+ * POST /v1/verify/attestation
317
+ * Verify an attestation token and optionally check a specific capability
318
+ *
319
+ * Body:
320
+ * token — required, the attestation JWT token
321
+ * action — optional, capability action to check (e.g. "read")
322
+ * resource — optional, capability resource to check (e.g. "invoices")
323
+ */
324
+ export async function verifyAttestationRoute(c) {
325
+ try {
326
+ const body = await c.req.json().catch(() => ({}));
327
+ if (!body.token) {
328
+ return c.json({
329
+ success: false,
330
+ error: 'MISSING_TOKEN',
331
+ message: 'Attestation token is required'
332
+ }, 400);
333
+ }
334
+ // If action specified, do full verify+check
335
+ if (body.action) {
336
+ const result = await verifyAndCheckCapability(c.env.SESSIONS, body.token, c.env.JWT_SECRET, body.action, body.resource);
337
+ if (!result.allowed) {
338
+ return c.json({
339
+ success: false,
340
+ valid: false,
341
+ allowed: false,
342
+ agent_id: result.agent_id || null,
343
+ error: result.error || result.reason,
344
+ matched_rule: result.matched_rule || null,
345
+ checked_capability: body.resource ? `${body.action}:${body.resource}` : body.action,
346
+ }, result.error ? 401 : 403);
347
+ }
348
+ return c.json({
349
+ success: true,
350
+ valid: true,
351
+ allowed: true,
352
+ agent_id: result.agent_id,
353
+ reason: result.reason,
354
+ matched_rule: result.matched_rule,
355
+ checked_capability: body.resource ? `${body.action}:${body.resource}` : body.action,
356
+ });
357
+ }
358
+ // Otherwise just verify the token
359
+ const verification = await verifyAttestationToken(c.env.SESSIONS, body.token, c.env.JWT_SECRET);
360
+ if (!verification.valid || !verification.payload) {
361
+ return c.json({
362
+ success: false,
363
+ valid: false,
364
+ error: verification.error,
365
+ }, 401);
366
+ }
367
+ const payload = verification.payload;
368
+ return c.json({
369
+ success: true,
370
+ valid: true,
371
+ agent_id: payload.sub,
372
+ issuer: payload.iss,
373
+ can: payload.can,
374
+ cannot: payload.cannot,
375
+ restrictions: payload.restrictions || null,
376
+ delegation_id: payload.delegation_id || null,
377
+ issued_at: new Date(payload.iat * 1000).toISOString(),
378
+ expires_at: new Date(payload.exp * 1000).toISOString(),
379
+ });
380
+ }
381
+ catch (error) {
382
+ console.error('Attestation verification error:', error);
383
+ return c.json({
384
+ success: false,
385
+ error: 'INTERNAL_ERROR',
386
+ message: 'Internal server error'
387
+ }, 500);
388
+ }
389
+ }
390
+ export default {
391
+ issueAttestationRoute,
392
+ getAttestationRoute,
393
+ listAttestationsRoute,
394
+ revokeAttestationRoute,
395
+ verifyAttestationRoute,
396
+ };
@@ -0,0 +1,178 @@
1
+ /**
2
+ * TAP Capability Attestation
3
+ *
4
+ * Signed JWT tokens that cryptographically bind:
5
+ * WHO (agent_id) can do WHAT (can/cannot rules) on WHICH resources,
6
+ * attested by WHOM (app authority), until WHEN (expiration).
7
+ *
8
+ * Permission model: "action:resource" patterns with explicit deny.
9
+ * - Allow: { can: ["read:invoices", "write:orders", "browse:*"] }
10
+ * - Deny: { cannot: ["write:transfers", "purchase:*"] }
11
+ * - Deny takes precedence over allow
12
+ * - Wildcards: "*:*" (all), "read:*" (read anything), "*:invoices" (any action on invoices)
13
+ * - Backward compatible: bare actions like "browse" expand to "browse:*"
14
+ *
15
+ * Attestation tokens are signed JWTs (HS256) with type 'botcha-attestation'.
16
+ * They can be verified offline (signature check) or online (revocation check via KV).
17
+ */
18
+ import type { KVNamespace } from './agents.js';
19
+ export interface AttestationPayload {
20
+ sub: string;
21
+ iss: string;
22
+ type: 'botcha-attestation';
23
+ jti: string;
24
+ iat: number;
25
+ exp: number;
26
+ can: string[];
27
+ cannot: string[];
28
+ restrictions?: {
29
+ max_amount?: number;
30
+ rate_limit?: number;
31
+ [key: string]: any;
32
+ };
33
+ delegation_id?: string;
34
+ metadata?: Record<string, string>;
35
+ }
36
+ export interface Attestation {
37
+ attestation_id: string;
38
+ agent_id: string;
39
+ app_id: string;
40
+ can: string[];
41
+ cannot: string[];
42
+ restrictions?: {
43
+ max_amount?: number;
44
+ rate_limit?: number;
45
+ [key: string]: any;
46
+ };
47
+ delegation_id?: string;
48
+ metadata?: Record<string, string>;
49
+ token: string;
50
+ created_at: number;
51
+ expires_at: number;
52
+ revoked: boolean;
53
+ revoked_at?: number;
54
+ revocation_reason?: string;
55
+ }
56
+ export interface IssueAttestationOptions {
57
+ agent_id: string;
58
+ can: string[];
59
+ cannot?: string[];
60
+ restrictions?: {
61
+ max_amount?: number;
62
+ rate_limit?: number;
63
+ [key: string]: any;
64
+ };
65
+ duration_seconds?: number;
66
+ delegation_id?: string;
67
+ metadata?: Record<string, string>;
68
+ }
69
+ export interface AttestationResult {
70
+ success: boolean;
71
+ attestation?: Attestation;
72
+ token?: string;
73
+ error?: string;
74
+ }
75
+ export interface CapabilityCheckResult {
76
+ allowed: boolean;
77
+ reason?: string;
78
+ matched_rule?: string;
79
+ }
80
+ /**
81
+ * Normalize a capability string to "action:resource" format.
82
+ * Bare actions like "browse" expand to "browse:*".
83
+ */
84
+ export declare function normalizeCapability(cap: string): string;
85
+ /**
86
+ * Check if a pattern matches a target.
87
+ * Supports wildcards: "*:*", "read:*", "*:invoices", "read:invoices"
88
+ */
89
+ export declare function matchesPattern(pattern: string, target: string): boolean;
90
+ /**
91
+ * Check if a specific action:resource is allowed by the can/cannot rules.
92
+ *
93
+ * Rules:
94
+ * 1. Check "cannot" list first — any match means DENIED (deny takes precedence)
95
+ * 2. Check "can" list — any match means ALLOWED
96
+ * 3. If no match in either list — DENIED (default deny)
97
+ */
98
+ export declare function checkCapability(can: string[], cannot: string[], action: string, resource?: string): CapabilityCheckResult;
99
+ /**
100
+ * Validate capability pattern syntax.
101
+ * Valid: "action:resource", "action", "*:*", "read:*", "*:invoices"
102
+ */
103
+ export declare function isValidCapabilityPattern(pattern: string): boolean;
104
+ /**
105
+ * Issue a capability attestation token for an agent.
106
+ *
107
+ * Validates:
108
+ * - Agent exists and belongs to the app
109
+ * - All capability patterns are syntactically valid
110
+ * - Total rules don't exceed limit
111
+ *
112
+ * Signs a JWT with the attestation payload.
113
+ */
114
+ export declare function issueAttestation(agents: KVNamespace, sessions: KVNamespace, appId: string, secret: string, options: IssueAttestationOptions): Promise<AttestationResult>;
115
+ /**
116
+ * Get an attestation by ID (from KV, not from JWT)
117
+ */
118
+ export declare function getAttestation(sessions: KVNamespace, attestationId: string): Promise<AttestationResult>;
119
+ /**
120
+ * Revoke an attestation.
121
+ */
122
+ export declare function revokeAttestation(sessions: KVNamespace, attestationId: string, reason?: string): Promise<AttestationResult>;
123
+ /**
124
+ * Verify an attestation JWT token.
125
+ *
126
+ * Checks:
127
+ * 1. JWT signature and expiration (cryptographic)
128
+ * 2. Token type is 'botcha-attestation'
129
+ * 3. Revocation status (via KV, fail-open)
130
+ *
131
+ * Returns the parsed attestation payload if valid.
132
+ */
133
+ export declare function verifyAttestationToken(sessions: KVNamespace, token: string, secret: string): Promise<{
134
+ valid: boolean;
135
+ payload?: AttestationPayload;
136
+ error?: string;
137
+ }>;
138
+ /**
139
+ * Full capability check: verify attestation token + check specific action:resource.
140
+ *
141
+ * Combines token verification with permission checking in one call.
142
+ */
143
+ export declare function verifyAndCheckCapability(sessions: KVNamespace, token: string, secret: string, action: string, resource?: string): Promise<{
144
+ allowed: boolean;
145
+ agent_id?: string;
146
+ reason?: string;
147
+ matched_rule?: string;
148
+ error?: string;
149
+ }>;
150
+ /**
151
+ * Create a Hono middleware that enforces capability attestation.
152
+ *
153
+ * Usage:
154
+ * app.get('/api/invoices', requireCapability('read:invoices'), handler);
155
+ * app.post('/api/transfers', requireCapability('write:transfers'), handler);
156
+ *
157
+ * Extracts attestation token from:
158
+ * 1. X-Botcha-Attestation header
159
+ * 2. Authorization: Bearer header (if token type is attestation)
160
+ *
161
+ * On failure: returns 403 with capability denial details.
162
+ * On missing token: returns 401 requesting attestation.
163
+ */
164
+ export declare function requireCapability(capability: string): (c: any, next: () => Promise<void>) => Promise<any>;
165
+ declare const _default: {
166
+ issueAttestation: typeof issueAttestation;
167
+ getAttestation: typeof getAttestation;
168
+ revokeAttestation: typeof revokeAttestation;
169
+ verifyAttestationToken: typeof verifyAttestationToken;
170
+ verifyAndCheckCapability: typeof verifyAndCheckCapability;
171
+ checkCapability: typeof checkCapability;
172
+ matchesPattern: typeof matchesPattern;
173
+ normalizeCapability: typeof normalizeCapability;
174
+ isValidCapabilityPattern: typeof isValidCapabilityPattern;
175
+ requireCapability: typeof requireCapability;
176
+ };
177
+ export default _default;
178
+ //# sourceMappingURL=tap-attestation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tap-attestation.d.ts","sourceRoot":"","sources":["../src/tap-attestation.ts"],"names":[],"mappings":"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"}