@dupecom/botcha-cloudflare 0.19.0 → 0.20.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.
- package/README.md +1 -1
- package/dist/apps.d.ts +6 -2
- package/dist/apps.d.ts.map +1 -1
- package/dist/apps.js +6 -2
- package/dist/auth.d.ts +3 -3
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +24 -15
- package/dist/dashboard/auth.d.ts +1 -1
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +11 -4
- package/dist/dashboard/device-code.d.ts +1 -1
- package/dist/dashboard/device-code.js +2 -2
- package/dist/dashboard/docs.js +4 -4
- package/dist/dashboard/whitepaper.js +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +136 -83
- package/dist/static.d.ts +10 -1
- package/dist/static.d.ts.map +1 -1
- package/dist/static.js +17 -15
- package/dist/tap-attestation-routes.d.ts.map +1 -1
- package/dist/tap-attestation-routes.js +30 -10
- package/dist/tap-delegation-routes.d.ts.map +1 -1
- package/dist/tap-delegation-routes.js +30 -10
- package/dist/tap-reputation-routes.d.ts.map +1 -1
- package/dist/tap-reputation-routes.js +30 -10
- package/dist/tap-routes.d.ts +10 -1
- package/dist/tap-routes.d.ts.map +1 -1
- package/dist/tap-routes.js +64 -31
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-attestation-routes.d.ts","sourceRoot":"","sources":["../src/tap-attestation-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"tap-attestation-routes.d.ts","sourceRoot":"","sources":["../src/tap-attestation-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAgEpC;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA4GrD;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAiDnD;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;kBA8DrD;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;oEAsEtD;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAmFtD;;;;;;;;AAED,wBAME"}
|
|
@@ -11,25 +11,45 @@
|
|
|
11
11
|
* POST /v1/attestations/:id/revoke — Revoke attestation
|
|
12
12
|
* POST /v1/verify/attestation — Verify attestation + check capability
|
|
13
13
|
*/
|
|
14
|
-
import { extractBearerToken, verifyToken } from './auth.js';
|
|
14
|
+
import { extractBearerToken, verifyToken, getSigningPublicKeyJWK } from './auth.js';
|
|
15
15
|
import { issueAttestation, getAttestation, revokeAttestation, verifyAttestationToken, verifyAndCheckCapability, isValidCapabilityPattern, } from './tap-attestation.js';
|
|
16
16
|
// ============ VALIDATION HELPERS ============
|
|
17
|
+
function getVerificationPublicKey(env) {
|
|
18
|
+
const rawSigningKey = env?.JWT_SIGNING_KEY;
|
|
19
|
+
if (!rawSigningKey)
|
|
20
|
+
return undefined;
|
|
21
|
+
try {
|
|
22
|
+
const signingKey = JSON.parse(rawSigningKey);
|
|
23
|
+
return getSigningPublicKeyJWK(signingKey);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
console.error('Failed to parse JWT_SIGNING_KEY for attestation route verification');
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
17
30
|
async function validateAppAccess(c, requireAuth = true) {
|
|
18
31
|
const queryAppId = c.req.query('app_id');
|
|
19
|
-
let jwtAppId;
|
|
20
32
|
const authHeader = c.req.header('authorization');
|
|
21
33
|
const token = extractBearerToken(authHeader);
|
|
22
|
-
if (token) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
jwtAppId = result.payload.app_id;
|
|
34
|
+
if (!token) {
|
|
35
|
+
if (!requireAuth) {
|
|
36
|
+
return { valid: true, appId: queryAppId };
|
|
26
37
|
}
|
|
38
|
+
return { valid: false, error: 'UNAUTHORIZED', status: 401 };
|
|
39
|
+
}
|
|
40
|
+
const publicKey = getVerificationPublicKey(c.env);
|
|
41
|
+
const result = await verifyToken(token, c.env.JWT_SECRET, c.env, undefined, publicKey);
|
|
42
|
+
if (!result.valid || !result.payload) {
|
|
43
|
+
return { valid: false, error: 'INVALID_TOKEN', status: 401 };
|
|
44
|
+
}
|
|
45
|
+
const jwtAppId = result.payload.app_id;
|
|
46
|
+
if (!jwtAppId) {
|
|
47
|
+
return { valid: false, error: 'MISSING_APP_ID', status: 403 };
|
|
27
48
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return { valid: false, error: 'MISSING_APP_ID', status: 401 };
|
|
49
|
+
if (queryAppId && queryAppId !== jwtAppId) {
|
|
50
|
+
return { valid: false, error: 'APP_ID_MISMATCH', status: 403 };
|
|
31
51
|
}
|
|
32
|
-
return { valid: true, appId };
|
|
52
|
+
return { valid: true, appId: jwtAppId };
|
|
33
53
|
}
|
|
34
54
|
// ============ ROUTE HANDLERS ============
|
|
35
55
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-delegation-routes.d.ts","sourceRoot":"","sources":["../src/tap-delegation-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"tap-delegation-routes.d.ts","sourceRoot":"","sources":["../src/tap-delegation-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAgEpC;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsGrD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAmDlD;AAED;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEAqEpD;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;oEAsErD;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAkDrD;;;;;;;;AAED,wBAME"}
|
|
@@ -11,26 +11,46 @@
|
|
|
11
11
|
* POST /v1/delegations/:id/revoke — Revoke delegation (cascades)
|
|
12
12
|
* POST /v1/verify/delegation — Verify delegation chain
|
|
13
13
|
*/
|
|
14
|
-
import { extractBearerToken, verifyToken } from './auth.js';
|
|
14
|
+
import { extractBearerToken, verifyToken, getSigningPublicKeyJWK } from './auth.js';
|
|
15
15
|
import { TAP_VALID_ACTIONS } from './tap-agents.js';
|
|
16
16
|
import { createDelegation, getDelegation, listDelegations, revokeDelegation, verifyDelegationChain, } from './tap-delegation.js';
|
|
17
17
|
// ============ VALIDATION HELPERS ============
|
|
18
|
+
function getVerificationPublicKey(env) {
|
|
19
|
+
const rawSigningKey = env?.JWT_SIGNING_KEY;
|
|
20
|
+
if (!rawSigningKey)
|
|
21
|
+
return undefined;
|
|
22
|
+
try {
|
|
23
|
+
const signingKey = JSON.parse(rawSigningKey);
|
|
24
|
+
return getSigningPublicKeyJWK(signingKey);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
console.error('Failed to parse JWT_SIGNING_KEY for delegation route verification');
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
18
31
|
async function validateAppAccess(c, requireAuth = true) {
|
|
19
32
|
const queryAppId = c.req.query('app_id');
|
|
20
|
-
let jwtAppId;
|
|
21
33
|
const authHeader = c.req.header('authorization');
|
|
22
34
|
const token = extractBearerToken(authHeader);
|
|
23
|
-
if (token) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
jwtAppId = result.payload.app_id;
|
|
35
|
+
if (!token) {
|
|
36
|
+
if (!requireAuth) {
|
|
37
|
+
return { valid: true, appId: queryAppId };
|
|
27
38
|
}
|
|
39
|
+
return { valid: false, error: 'UNAUTHORIZED', status: 401 };
|
|
40
|
+
}
|
|
41
|
+
const publicKey = getVerificationPublicKey(c.env);
|
|
42
|
+
const result = await verifyToken(token, c.env.JWT_SECRET, c.env, undefined, publicKey);
|
|
43
|
+
if (!result.valid || !result.payload) {
|
|
44
|
+
return { valid: false, error: 'INVALID_TOKEN', status: 401 };
|
|
45
|
+
}
|
|
46
|
+
const jwtAppId = result.payload.app_id;
|
|
47
|
+
if (!jwtAppId) {
|
|
48
|
+
return { valid: false, error: 'MISSING_APP_ID', status: 403 };
|
|
28
49
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return { valid: false, error: 'MISSING_APP_ID', status: 401 };
|
|
50
|
+
if (queryAppId && queryAppId !== jwtAppId) {
|
|
51
|
+
return { valid: false, error: 'APP_ID_MISMATCH', status: 403 };
|
|
32
52
|
}
|
|
33
|
-
return { valid: true, appId };
|
|
53
|
+
return { valid: true, appId: jwtAppId };
|
|
34
54
|
}
|
|
35
55
|
// ============ ROUTE HANDLERS ============
|
|
36
56
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-reputation-routes.d.ts","sourceRoot":"","sources":["../src/tap-reputation-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EASL,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC3B,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"tap-reputation-routes.d.ts","sourceRoot":"","sources":["../src/tap-reputation-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EASL,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC3B,MAAM,qBAAqB,CAAC;AAsD7B;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEA6DlD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,0BAA0B,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA2H1D;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEA4EzD;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;oEAyDpD;;;;;;;AAED,wBAKE"}
|
|
@@ -10,25 +10,45 @@
|
|
|
10
10
|
* GET /v1/reputation/:agent_id/events — List reputation events
|
|
11
11
|
* POST /v1/reputation/:agent_id/reset — Reset agent reputation (admin)
|
|
12
12
|
*/
|
|
13
|
-
import { extractBearerToken, verifyToken } from './auth.js';
|
|
13
|
+
import { extractBearerToken, verifyToken, getSigningPublicKeyJWK } from './auth.js';
|
|
14
14
|
import { getReputationScore, recordReputationEvent, listReputationEvents, resetReputation, isValidCategory, isValidAction, isValidCategoryAction, } from './tap-reputation.js';
|
|
15
15
|
// ============ VALIDATION HELPERS ============
|
|
16
|
+
function getVerificationPublicKey(env) {
|
|
17
|
+
const rawSigningKey = env?.JWT_SIGNING_KEY;
|
|
18
|
+
if (!rawSigningKey)
|
|
19
|
+
return undefined;
|
|
20
|
+
try {
|
|
21
|
+
const signingKey = JSON.parse(rawSigningKey);
|
|
22
|
+
return getSigningPublicKeyJWK(signingKey);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
console.error('Failed to parse JWT_SIGNING_KEY for reputation route verification');
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
16
29
|
async function validateAppAccess(c, requireAuth = true) {
|
|
17
30
|
const queryAppId = c.req.query('app_id');
|
|
18
|
-
let jwtAppId;
|
|
19
31
|
const authHeader = c.req.header('authorization');
|
|
20
32
|
const token = extractBearerToken(authHeader);
|
|
21
|
-
if (token) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
jwtAppId = result.payload.app_id;
|
|
33
|
+
if (!token) {
|
|
34
|
+
if (!requireAuth) {
|
|
35
|
+
return { valid: true, appId: queryAppId };
|
|
25
36
|
}
|
|
37
|
+
return { valid: false, error: 'UNAUTHORIZED', status: 401 };
|
|
38
|
+
}
|
|
39
|
+
const publicKey = getVerificationPublicKey(c.env);
|
|
40
|
+
const result = await verifyToken(token, c.env.JWT_SECRET, c.env, undefined, publicKey);
|
|
41
|
+
if (!result.valid || !result.payload) {
|
|
42
|
+
return { valid: false, error: 'INVALID_TOKEN', status: 401 };
|
|
43
|
+
}
|
|
44
|
+
const jwtAppId = result.payload.app_id;
|
|
45
|
+
if (!jwtAppId) {
|
|
46
|
+
return { valid: false, error: 'MISSING_APP_ID', status: 403 };
|
|
26
47
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return { valid: false, error: 'MISSING_APP_ID', status: 401 };
|
|
48
|
+
if (queryAppId && queryAppId !== jwtAppId) {
|
|
49
|
+
return { valid: false, error: 'APP_ID_MISMATCH', status: 403 };
|
|
30
50
|
}
|
|
31
|
-
return { valid: true, appId };
|
|
51
|
+
return { valid: true, appId: jwtAppId };
|
|
32
52
|
}
|
|
33
53
|
// ============ ROUTE HANDLERS ============
|
|
34
54
|
/**
|
package/dist/tap-routes.d.ts
CHANGED
|
@@ -309,13 +309,22 @@ export declare function verifyIOURoute(c: Context): Promise<(Response & import("
|
|
|
309
309
|
error: string;
|
|
310
310
|
message: string;
|
|
311
311
|
}, 404, "json">) | (Response & import("hono").TypedResponse<{
|
|
312
|
+
success: false;
|
|
313
|
+
error: string;
|
|
314
|
+
message: string;
|
|
315
|
+
}, 403, "json">) | (Response & import("hono").TypedResponse<{
|
|
312
316
|
success: false;
|
|
313
317
|
verified: false;
|
|
314
318
|
error: string | undefined;
|
|
315
319
|
}, 400, "json">) | (Response & import("hono").TypedResponse<{
|
|
320
|
+
success: false;
|
|
321
|
+
verified: true;
|
|
322
|
+
error: string;
|
|
323
|
+
message: string;
|
|
324
|
+
}, 502, "json">) | (Response & import("hono").TypedResponse<{
|
|
316
325
|
success: true;
|
|
317
326
|
verified: true;
|
|
318
|
-
access_token: string
|
|
327
|
+
access_token: string;
|
|
319
328
|
expires_at: string | undefined;
|
|
320
329
|
}, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
|
|
321
330
|
success: false;
|
package/dist/tap-routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-routes.d.ts","sourceRoot":"","sources":["../src/tap-routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"tap-routes.d.ts","sourceRoot":"","sources":["../src/tap-routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAmKpC;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAwErD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAwDhD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEAmDlD;AAID;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsFrD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA2ClD;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA4D9C;AAID;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;kBAwClD;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;kBAuB/C;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA6E9C;AAID;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAqCnD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsClD;;;;;;;;;;;;;;AAaD,wBAYE"}
|
package/dist/tap-routes.js
CHANGED
|
@@ -4,35 +4,64 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Provides backward-compatible endpoints with optional TAP functionality
|
|
6
6
|
*/
|
|
7
|
-
import { extractBearerToken, verifyToken } from './auth.js';
|
|
7
|
+
import { extractBearerToken, verifyToken, getSigningPublicKeyJWK } from './auth.js';
|
|
8
8
|
import { registerTAPAgent, getTAPAgent, listTAPAgents, createTAPSession, getTAPSession, validateCapability, TAP_VALID_ACTIONS } from './tap-agents.js';
|
|
9
9
|
import { parseTAPIntent } from './tap-verify.js';
|
|
10
10
|
import { createInvoice, getInvoice, verifyPaymentContainer, verifyBrowsingIOU, fulfillInvoice, parsePaymentContainer } from './tap-payment.js';
|
|
11
11
|
import { parseAgenticConsumer, verifyAgenticConsumer } from './tap-consumer.js';
|
|
12
12
|
// ============ VALIDATION HELPERS ============
|
|
13
|
+
function getVerificationPublicKey(env) {
|
|
14
|
+
const rawSigningKey = env?.JWT_SIGNING_KEY;
|
|
15
|
+
if (!rawSigningKey)
|
|
16
|
+
return undefined;
|
|
17
|
+
try {
|
|
18
|
+
const signingKey = JSON.parse(rawSigningKey);
|
|
19
|
+
return getSigningPublicKeyJWK(signingKey);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
console.error('Failed to parse JWT_SIGNING_KEY for TAP verification');
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
13
26
|
async function validateAppAccess(c, requireAuth = true) {
|
|
14
|
-
// Extract app_id from query param or JWT
|
|
15
27
|
const queryAppId = c.req.query('app_id');
|
|
16
|
-
// Try to get from JWT Bearer token
|
|
17
|
-
let jwtAppId;
|
|
18
28
|
const authHeader = c.req.header('authorization');
|
|
19
29
|
const token = extractBearerToken(authHeader);
|
|
20
|
-
if (token) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
jwtAppId = result.payload.app_id;
|
|
30
|
+
if (!token) {
|
|
31
|
+
if (!requireAuth) {
|
|
32
|
+
return { valid: true, appId: queryAppId };
|
|
24
33
|
}
|
|
34
|
+
return {
|
|
35
|
+
valid: false,
|
|
36
|
+
error: 'UNAUTHORIZED',
|
|
37
|
+
status: 401
|
|
38
|
+
};
|
|
25
39
|
}
|
|
26
|
-
const
|
|
27
|
-
|
|
40
|
+
const publicKey = getVerificationPublicKey(c.env);
|
|
41
|
+
const result = await verifyToken(token, c.env.JWT_SECRET, c.env, undefined, publicKey);
|
|
42
|
+
if (!result.valid || !result.payload) {
|
|
28
43
|
return {
|
|
29
44
|
valid: false,
|
|
30
|
-
error: '
|
|
45
|
+
error: 'INVALID_TOKEN',
|
|
31
46
|
status: 401
|
|
32
47
|
};
|
|
33
48
|
}
|
|
34
|
-
|
|
35
|
-
|
|
49
|
+
const jwtAppId = result.payload.app_id;
|
|
50
|
+
if (!jwtAppId) {
|
|
51
|
+
return {
|
|
52
|
+
valid: false,
|
|
53
|
+
error: 'MISSING_APP_ID',
|
|
54
|
+
status: 403
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (queryAppId && queryAppId !== jwtAppId) {
|
|
58
|
+
return {
|
|
59
|
+
valid: false,
|
|
60
|
+
error: 'APP_ID_MISMATCH',
|
|
61
|
+
status: 403
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return { valid: true, appId: jwtAppId };
|
|
36
65
|
}
|
|
37
66
|
function validateTAPRegistration(body) {
|
|
38
67
|
if (!body.name || typeof body.name !== 'string') {
|
|
@@ -515,33 +544,37 @@ export async function verifyIOURoute(c) {
|
|
|
515
544
|
if (!agentKeyId) {
|
|
516
545
|
return c.json({ success: false, error: 'MISSING_KEY_ID', message: 'browsingIOU must include kid' }, 400);
|
|
517
546
|
}
|
|
518
|
-
//
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
if (agentIndex) {
|
|
523
|
-
const agentIds = JSON.parse(agentIndex);
|
|
524
|
-
for (const agentId of agentIds) {
|
|
525
|
-
const agentData = await c.env.AGENTS.get(`agent:${agentId}`, 'text');
|
|
526
|
-
if (agentData) {
|
|
527
|
-
const agent = JSON.parse(agentData);
|
|
528
|
-
if (agent.public_key) {
|
|
529
|
-
publicKey = agent.public_key;
|
|
530
|
-
break;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
}
|
|
547
|
+
// Resolve key by kid (agent/key identifier) and enforce same-app ownership.
|
|
548
|
+
const agentData = await c.env.AGENTS.get(`agent:${agentKeyId}`, 'text');
|
|
549
|
+
if (!agentData) {
|
|
550
|
+
return c.json({ success: false, error: 'KEY_NOT_FOUND', message: `No TAP key found for kid: ${agentKeyId}` }, 404);
|
|
534
551
|
}
|
|
535
|
-
|
|
552
|
+
const agent = JSON.parse(agentData);
|
|
553
|
+
if (agent.app_id !== invoiceResult.invoice.app_id) {
|
|
554
|
+
return c.json({
|
|
555
|
+
success: false,
|
|
556
|
+
error: 'KEY_APP_MISMATCH',
|
|
557
|
+
message: 'Key does not belong to the app that issued this invoice',
|
|
558
|
+
}, 403);
|
|
559
|
+
}
|
|
560
|
+
if (!agent.public_key) {
|
|
536
561
|
return c.json({ success: false, error: 'KEY_NOT_FOUND', message: 'Could not resolve public key for verification' }, 404);
|
|
537
562
|
}
|
|
538
563
|
// Verify the IOU
|
|
539
|
-
const iouResult = await verifyBrowsingIOU(body.browsingIOU, invoiceResult.invoice,
|
|
564
|
+
const iouResult = await verifyBrowsingIOU(body.browsingIOU, invoiceResult.invoice, agent.public_key, body.browsingIOU.alg || agent.signature_algorithm || 'ES256');
|
|
540
565
|
if (!iouResult.valid) {
|
|
541
566
|
return c.json({ success: false, verified: false, error: iouResult.error }, 400);
|
|
542
567
|
}
|
|
543
568
|
// Fulfill the invoice
|
|
544
569
|
const fulfillResult = await fulfillInvoice(c.env.INVOICES, invoiceId, body.browsingIOU);
|
|
570
|
+
if (!fulfillResult.success || !fulfillResult.access_token) {
|
|
571
|
+
return c.json({
|
|
572
|
+
success: false,
|
|
573
|
+
verified: true,
|
|
574
|
+
error: 'INVOICE_FULFILLMENT_FAILED',
|
|
575
|
+
message: fulfillResult.error || 'Invoice could not be fulfilled',
|
|
576
|
+
}, 502);
|
|
577
|
+
}
|
|
545
578
|
return c.json({
|
|
546
579
|
success: true,
|
|
547
580
|
verified: true,
|