@kya-os/mcp-i-cloudflare 1.9.7 → 1.10.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/dist/adapter.d.ts +2 -2
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +53 -25
- package/dist/adapter.js.map +1 -1
- package/dist/agent.d.ts +1 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +204 -59
- package/dist/agent.js.map +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +86 -3
- package/dist/app.js.map +1 -1
- package/dist/cache/kv-oauth-config-cache.d.ts +1 -1
- package/dist/cache/kv-oauth-config-cache.d.ts.map +1 -1
- package/dist/cache/kv-tool-protection-cache.d.ts +1 -1
- package/dist/cache/kv-tool-protection-cache.d.ts.map +1 -1
- package/dist/config.d.ts +54 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +58 -0
- package/dist/config.js.map +1 -1
- package/dist/constants/storage-keys.d.ts +6 -0
- package/dist/constants/storage-keys.d.ts.map +1 -1
- package/dist/constants/storage-keys.js +6 -0
- package/dist/constants/storage-keys.js.map +1 -1
- package/dist/delegation-http/anchor-do.d.ts +84 -0
- package/dist/delegation-http/anchor-do.d.ts.map +1 -0
- package/dist/delegation-http/anchor-do.js +253 -0
- package/dist/delegation-http/anchor-do.js.map +1 -0
- package/dist/delegation-http/anchor-routing.d.ts +20 -0
- package/dist/delegation-http/anchor-routing.d.ts.map +1 -0
- package/dist/delegation-http/anchor-routing.js +27 -0
- package/dist/delegation-http/anchor-routing.js.map +1 -0
- package/dist/delegation-http/bearer-retry.d.ts +54 -0
- package/dist/delegation-http/bearer-retry.d.ts.map +1 -0
- package/dist/delegation-http/bearer-retry.js +195 -0
- package/dist/delegation-http/bearer-retry.js.map +1 -0
- package/dist/delegation-http/challenge-middleware.d.ts +28 -0
- package/dist/delegation-http/challenge-middleware.d.ts.map +1 -0
- package/dist/delegation-http/challenge-middleware.js +190 -0
- package/dist/delegation-http/challenge-middleware.js.map +1 -0
- package/dist/delegation-http/challenge.d.ts +86 -0
- package/dist/delegation-http/challenge.d.ts.map +1 -0
- package/dist/delegation-http/challenge.js +173 -0
- package/dist/delegation-http/challenge.js.map +1 -0
- package/dist/delegation-http/consent-anchor-bridge.d.ts +35 -0
- package/dist/delegation-http/consent-anchor-bridge.d.ts.map +1 -0
- package/dist/delegation-http/consent-anchor-bridge.js +355 -0
- package/dist/delegation-http/consent-anchor-bridge.js.map +1 -0
- package/dist/delegation-http/constants.d.ts +51 -0
- package/dist/delegation-http/constants.d.ts.map +1 -0
- package/dist/delegation-http/constants.js +60 -0
- package/dist/delegation-http/constants.js.map +1 -0
- package/dist/delegation-http/hash.d.ts +21 -0
- package/dist/delegation-http/hash.d.ts.map +1 -0
- package/dist/delegation-http/hash.js +92 -0
- package/dist/delegation-http/hash.js.map +1 -0
- package/dist/delegation-http/pickup-routes.d.ts +42 -0
- package/dist/delegation-http/pickup-routes.d.ts.map +1 -0
- package/dist/delegation-http/pickup-routes.js +79 -0
- package/dist/delegation-http/pickup-routes.js.map +1 -0
- package/dist/delegation-http/register.d.ts +19 -0
- package/dist/delegation-http/register.d.ts.map +1 -0
- package/dist/delegation-http/register.js +72 -0
- package/dist/delegation-http/register.js.map +1 -0
- package/dist/delegation-http/sid.d.ts +20 -0
- package/dist/delegation-http/sid.d.ts.map +1 -0
- package/dist/delegation-http/sid.js +32 -0
- package/dist/delegation-http/sid.js.map +1 -0
- package/dist/delegation-http/types.d.ts +64 -0
- package/dist/delegation-http/types.d.ts.map +1 -0
- package/dist/delegation-http/types.js +11 -0
- package/dist/delegation-http/types.js.map +1 -0
- package/dist/helpers/env-mapper.d.ts.map +1 -1
- package/dist/helpers/env-mapper.js +24 -0
- package/dist/helpers/env-mapper.js.map +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -2
- package/dist/index.js.map +1 -1
- package/dist/needs-authorization-meta.d.ts +35 -0
- package/dist/needs-authorization-meta.d.ts.map +1 -0
- package/dist/needs-authorization-meta.js +50 -0
- package/dist/needs-authorization-meta.js.map +1 -0
- package/dist/proof-generator.d.ts +1 -1
- package/dist/proof-generator.d.ts.map +1 -1
- package/dist/providers/crypto.d.ts +1 -1
- package/dist/providers/crypto.d.ts.map +1 -1
- package/dist/providers/crypto.js +1 -1
- package/dist/providers/crypto.js.map +1 -1
- package/dist/providers/kv-identity.d.ts +2 -2
- package/dist/providers/kv-identity.d.ts.map +1 -1
- package/dist/providers/kv-identity.js +1 -1
- package/dist/providers/kv-identity.js.map +1 -1
- package/dist/providers/storage.d.ts +1 -1
- package/dist/providers/storage.d.ts.map +1 -1
- package/dist/providers/storage.js +1 -1
- package/dist/providers/storage.js.map +1 -1
- package/dist/runtime/audit-logger.d.ts +1 -1
- package/dist/runtime/audit-logger.d.ts.map +1 -1
- package/dist/runtime/oauth-handler.d.ts.map +1 -1
- package/dist/runtime/oauth-handler.js +45 -7
- package/dist/runtime/oauth-handler.js.map +1 -1
- package/dist/runtime/oidc/authorize-url.d.ts +19 -0
- package/dist/runtime/oidc/authorize-url.d.ts.map +1 -0
- package/dist/runtime/oidc/authorize-url.js +94 -0
- package/dist/runtime/oidc/authorize-url.js.map +1 -0
- package/dist/runtime/oidc/token-exchange.d.ts +62 -0
- package/dist/runtime/oidc/token-exchange.d.ts.map +1 -0
- package/dist/runtime/oidc/token-exchange.js +75 -0
- package/dist/runtime/oidc/token-exchange.js.map +1 -0
- package/dist/runtime.d.ts +3 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/services/admin.service.js +1 -1
- package/dist/services/admin.service.js.map +1 -1
- package/dist/services/consent-audit.service.d.ts +1 -1
- package/dist/services/consent-audit.service.d.ts.map +1 -1
- package/dist/services/consent-audit.service.js.map +1 -1
- package/dist/services/consent.service.d.ts +5 -5
- package/dist/services/consent.service.d.ts.map +1 -1
- package/dist/services/consent.service.js +41 -52
- package/dist/services/consent.service.js.map +1 -1
- package/dist/services/delegation.service.d.ts +9 -0
- package/dist/services/delegation.service.d.ts.map +1 -1
- package/dist/services/delegation.service.js +21 -7
- package/dist/services/delegation.service.js.map +1 -1
- package/dist/services/idp-token-storage.d.ts +1 -1
- package/dist/services/idp-token-storage.d.ts.map +1 -1
- package/dist/services/oauth-security.service.d.ts.map +1 -1
- package/dist/services/oauth-security.service.js +6 -10
- package/dist/services/oauth-security.service.js.map +1 -1
- package/dist/services/proof.service.js.map +1 -1
- package/dist/services/provider-loader.service.js +1 -1
- package/dist/services/provider-loader.service.js.map +1 -1
- package/dist/types.d.ts +5 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/env-secret-resolver.d.ts +18 -0
- package/dist/utils/env-secret-resolver.d.ts.map +1 -0
- package/dist/utils/env-secret-resolver.js +46 -0
- package/dist/utils/env-secret-resolver.js.map +1 -0
- package/dist/utils/known-clients.d.ts.map +1 -1
- package/dist/utils/known-clients.js +19 -10
- package/dist/utils/known-clients.js.map +1 -1
- package/dist/utils/oauth-service-registry.d.ts +1 -1
- package/dist/utils/oauth-service-registry.d.ts.map +1 -1
- package/dist/utils/oauth-service-registry.js +1 -1
- package/dist/utils/oauth-service-registry.js.map +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* draft-kya-http-02 delegation layer — pickup-anchor durable object.
|
|
3
|
+
*
|
|
4
|
+
* Implements the §13 anchor state machine: create → PENDING (or PINNED for a
|
|
5
|
+
* challenge-time signed caller) → first poll pins the holder → human approves
|
|
6
|
+
* (PINNED→APPROVED, credential parked) → the pinned holder polls 200-ready,
|
|
7
|
+
* repeatably, until the anchor TTL elapses.
|
|
8
|
+
*
|
|
9
|
+
* Design:
|
|
10
|
+
* - ALL transition logic lives in the pure, synchronous reducers
|
|
11
|
+
* `reduceCreate` / `reducePoll` / `reduceApprove` (injectable `now`). They never
|
|
12
|
+
* touch storage and never await — which is what lets the Cloudflare DO input gate
|
|
13
|
+
* serialize the first-poll race (the dispatcher does `get → reduce → put` with no
|
|
14
|
+
* intervening non-storage await, so the read-modify-write is atomic per the gate).
|
|
15
|
+
* - `handlePickupInternal` is the only async surface: it reads the record from
|
|
16
|
+
* `ctx.storage`, runs the reducer, then persists or deletes.
|
|
17
|
+
*
|
|
18
|
+
* Non-negotiables:
|
|
19
|
+
* - never store/log a raw token — only its `sha256Hex` digest (see `./hash`);
|
|
20
|
+
* - no `alarm()` override: the `agents` SDK base class assigns `this.alarm` as an
|
|
21
|
+
* own-property arrow (its SQL scheduler), which shadows any subclass method and
|
|
22
|
+
* exposes no `super.alarm` to delegate to — so anchor lifetime is instead bounded
|
|
23
|
+
* by idempotent creation (one anchor per deterministic sid) plus the ≤600s TTL;
|
|
24
|
+
* - lazy expiry with delete-on-expired-read (a 410 outcome deletes the key);
|
|
25
|
+
* - every response carries `Cache-Control: no-store`;
|
|
26
|
+
* - 429 is status + `Retry-After` only — never a body.
|
|
27
|
+
*
|
|
28
|
+
* @module @kya-os/mcp-i-cloudflare/delegation-http/anchor-do
|
|
29
|
+
*/
|
|
30
|
+
import { sha256Hex } from "./hash";
|
|
31
|
+
import { KYAOS_ERRORS, INTERNAL_PICKUP_CREATE, INTERNAL_PICKUP_POLL, INTERNAL_PICKUP_APPROVE, INTERNAL_PICKUP_INFO, } from "./constants";
|
|
32
|
+
import { STORAGE_KEYS } from "../constants/storage-keys";
|
|
33
|
+
const pendingBody = () => ({ status: "pending" });
|
|
34
|
+
const pinnedErr = () => ({ error: KYAOS_ERRORS.pickupPinned });
|
|
35
|
+
const invalidSessionErr = () => ({ error: KYAOS_ERRORS.invalidSession });
|
|
36
|
+
const pickupExpiredErr = () => ({ error: KYAOS_ERRORS.pickupExpired });
|
|
37
|
+
/**
|
|
38
|
+
* Pure reducer for `create`. Writes a fresh anchor record (PENDING, or PINNED when a
|
|
39
|
+
* challenge-time keyid pin is supplied). Idempotent by construction: a `pickup:<sid>`
|
|
40
|
+
* instance is created once, by the challenge emitter, before the 401 leaves.
|
|
41
|
+
*/
|
|
42
|
+
export function reduceCreate(rec, input, now) {
|
|
43
|
+
const i = input;
|
|
44
|
+
// Creation-bounding (W1): create is idempotent. A still-live anchor for this sid
|
|
45
|
+
// is reused as-is, so repeated challenges for the same (session, scopes) — which
|
|
46
|
+
// derive the same deterministic sid (see challenge-middleware.ts) — never orphan a
|
|
47
|
+
// fresh durable object or reset an in-flight pin/approval.
|
|
48
|
+
if (rec && now <= rec.expiresAt) {
|
|
49
|
+
return { response: { status: 201, body: { success: true } } };
|
|
50
|
+
}
|
|
51
|
+
const record = {
|
|
52
|
+
sid: i.sid,
|
|
53
|
+
status: i.pin ? "pinned" : "pending",
|
|
54
|
+
requiredScopes: i.requiredScopes,
|
|
55
|
+
minAssurance: i.minAssurance,
|
|
56
|
+
pollIntervalS: i.pollIntervalS,
|
|
57
|
+
createdAt: now,
|
|
58
|
+
expiresAt: now + i.anchorTtlS * 1000,
|
|
59
|
+
pin: i.pin
|
|
60
|
+
? {
|
|
61
|
+
type: i.pin.type,
|
|
62
|
+
valueSha256: i.pin.valueSha256,
|
|
63
|
+
pinnedAt: now,
|
|
64
|
+
source: "challenge",
|
|
65
|
+
}
|
|
66
|
+
: undefined,
|
|
67
|
+
};
|
|
68
|
+
return { record, response: { status: 201, body: { success: true } } };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Pure reducer for `poll`. The §13 wire state machine:
|
|
72
|
+
* - no record → 404 invalid-session;
|
|
73
|
+
* - `now > expiresAt` → 410 pickup-expired (the dispatcher deletes the key);
|
|
74
|
+
* - no pin yet → this poll pins `sha256Hex(holder.value)` (PENDING→PINNED);
|
|
75
|
+
* - pin mismatch (any state, incl. after approval) → 403 pickup-pinned;
|
|
76
|
+
* - pinned holder, awaiting consent, polling faster than `pollIntervalS` → 429;
|
|
77
|
+
* - pinned holder, credential parked → 200 ready (repeatable, no consume-on-read);
|
|
78
|
+
* - otherwise → 202 pending.
|
|
79
|
+
*/
|
|
80
|
+
export function reducePoll(rec, holder, now) {
|
|
81
|
+
if (!rec) {
|
|
82
|
+
return { response: { status: 404, body: invalidSessionErr() } };
|
|
83
|
+
}
|
|
84
|
+
if (now > rec.expiresAt) {
|
|
85
|
+
// delete-on-expired-read: a 410 outcome tells the dispatcher to drop the key.
|
|
86
|
+
return { response: { status: 410, body: pickupExpiredErr() } };
|
|
87
|
+
}
|
|
88
|
+
const holderSha = sha256Hex(holder.value);
|
|
89
|
+
let working = rec;
|
|
90
|
+
let pinnedJustNow = false;
|
|
91
|
+
if (rec.pin) {
|
|
92
|
+
// W2: require a matching holder TYPE as well as digest, so a token whose value
|
|
93
|
+
// equals a pinned keyid string (or vice-versa) can never satisfy the pin.
|
|
94
|
+
if (rec.pin.type !== holder.type || rec.pin.valueSha256 !== holderSha) {
|
|
95
|
+
return { response: { status: 403, body: pinnedErr() } };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// First poll on an unpinned anchor pins the holder. The DO input gate makes this
|
|
100
|
+
// read-modify-write the compare-and-set: a racing second holder sees this pin.
|
|
101
|
+
working = {
|
|
102
|
+
...rec,
|
|
103
|
+
status: rec.status === "pending" ? "pinned" : rec.status,
|
|
104
|
+
pin: {
|
|
105
|
+
type: holder.type,
|
|
106
|
+
valueSha256: holderSha,
|
|
107
|
+
pinnedAt: now,
|
|
108
|
+
source: "first-poll",
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
pinnedJustNow = true;
|
|
112
|
+
}
|
|
113
|
+
// The holder is now the pinned holder. Deliver the parked credential if approved.
|
|
114
|
+
if (working.status === "approved" && working.delegation) {
|
|
115
|
+
const body = {
|
|
116
|
+
status: "ready",
|
|
117
|
+
token_type: "Bearer",
|
|
118
|
+
delegation: working.delegation.vcJwt,
|
|
119
|
+
expires_in: working.delegation.expiresInS,
|
|
120
|
+
};
|
|
121
|
+
return pinnedJustNow
|
|
122
|
+
? { record: working, response: { status: 200, body } }
|
|
123
|
+
: { response: { status: 200, body } };
|
|
124
|
+
}
|
|
125
|
+
// Awaiting consent. Throttle repeat polls by the pinned holder (never the pinning
|
|
126
|
+
// poll itself, and never the repeatable ready path above).
|
|
127
|
+
if (!pinnedJustNow &&
|
|
128
|
+
working.lastPollAt !== undefined &&
|
|
129
|
+
now - working.lastPollAt < working.pollIntervalS * 1000) {
|
|
130
|
+
return { response: { status: 429, retryAfterS: working.pollIntervalS } };
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
record: { ...working, lastPollAt: now },
|
|
134
|
+
response: { status: 202, body: pendingBody() },
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Pure reducer for `approve`. Parks the minted credential on a live anchor
|
|
139
|
+
* (PENDING or PINNED → APPROVED). Consent on an EXPIRED anchor MUST fail (410); an
|
|
140
|
+
* unknown anchor is 404 invalid-session.
|
|
141
|
+
*/
|
|
142
|
+
export function reduceApprove(rec, input, now) {
|
|
143
|
+
const i = input;
|
|
144
|
+
if (!rec) {
|
|
145
|
+
return { response: { status: 404, body: invalidSessionErr() } };
|
|
146
|
+
}
|
|
147
|
+
if (now > rec.expiresAt) {
|
|
148
|
+
return { response: { status: 410, body: pickupExpiredErr() } };
|
|
149
|
+
}
|
|
150
|
+
// Idempotent approve: once a credential is parked, a duplicate approval (a
|
|
151
|
+
// double-submit, two consent tabs) must NOT replace it. Each approve mints a fresh
|
|
152
|
+
// VC-JWT, so a blind upsert would swap a live delegation the pinned holder may
|
|
153
|
+
// already be picking up. Return the existing success without re-parking.
|
|
154
|
+
if (rec.status === "approved" && rec.delegation) {
|
|
155
|
+
return { response: { status: 200, body: { success: true } } };
|
|
156
|
+
}
|
|
157
|
+
const record = {
|
|
158
|
+
...rec,
|
|
159
|
+
status: "approved",
|
|
160
|
+
delegation: { vcJwt: i.vcJwt, expiresInS: i.expiresInS, approvedAt: now },
|
|
161
|
+
};
|
|
162
|
+
return { record, response: { status: 200, body: { success: true } } };
|
|
163
|
+
}
|
|
164
|
+
/** Reducer outcome → wire `Response`, applying the frozen header rules. */
|
|
165
|
+
function wireResponse(r) {
|
|
166
|
+
const headers = { "Cache-Control": "no-store" };
|
|
167
|
+
if (r.status === 429) {
|
|
168
|
+
// 429 is status + Retry-After only — never a body (the §9 registry has no
|
|
169
|
+
// over-rate string to put there).
|
|
170
|
+
if (r.retryAfterS !== undefined)
|
|
171
|
+
headers["Retry-After"] = String(r.retryAfterS);
|
|
172
|
+
return new Response(null, { status: 429, headers });
|
|
173
|
+
}
|
|
174
|
+
headers["Content-Type"] = "application/json";
|
|
175
|
+
return new Response(r.body === undefined ? "" : JSON.stringify(r.body), {
|
|
176
|
+
status: r.status,
|
|
177
|
+
headers,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Dispatch `/_internal/pickup/*` requests against the anchor's durable-object
|
|
182
|
+
* storage. One `ctx.storage.get` up front, the matching pure reducer, then a single
|
|
183
|
+
* `put` (or `delete` on an expired 410 read) — no non-storage await between read and
|
|
184
|
+
* write, so the DO input gate makes the first-poll pin a compare-and-set.
|
|
185
|
+
*
|
|
186
|
+
* `now` is injectable for tests; production callers omit it and it resolves to the
|
|
187
|
+
* wall clock.
|
|
188
|
+
*/
|
|
189
|
+
export async function handlePickupInternal(ctx, request, now) {
|
|
190
|
+
const t = now ?? Date.now();
|
|
191
|
+
const path = new URL(request.url).pathname;
|
|
192
|
+
let body;
|
|
193
|
+
try {
|
|
194
|
+
body = (await request.json());
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
body = {};
|
|
198
|
+
}
|
|
199
|
+
const key = STORAGE_KEYS.pickupAnchor(String(body.sid));
|
|
200
|
+
const rec = (await ctx.storage.get(key));
|
|
201
|
+
if (path === INTERNAL_PICKUP_CREATE) {
|
|
202
|
+
const { record, response } = reduceCreate(rec, body, t);
|
|
203
|
+
if (record)
|
|
204
|
+
await ctx.storage.put(key, record);
|
|
205
|
+
return wireResponse(response);
|
|
206
|
+
}
|
|
207
|
+
if (path === INTERNAL_PICKUP_POLL) {
|
|
208
|
+
const h = body.holder;
|
|
209
|
+
if (!h ||
|
|
210
|
+
typeof h.value !== "string" ||
|
|
211
|
+
(h.type !== "token" && h.type !== "keyid")) {
|
|
212
|
+
return wireResponse({
|
|
213
|
+
status: 400,
|
|
214
|
+
body: { error: "kyaos/invalid-request", message: "missing or malformed holder" },
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
const { record, response } = reducePoll(rec, h, t);
|
|
218
|
+
if (response.status === 410)
|
|
219
|
+
await ctx.storage.delete(key);
|
|
220
|
+
else if (record)
|
|
221
|
+
await ctx.storage.put(key, record);
|
|
222
|
+
return wireResponse(response);
|
|
223
|
+
}
|
|
224
|
+
if (path === INTERNAL_PICKUP_APPROVE) {
|
|
225
|
+
const { record, response } = reduceApprove(rec, body, t);
|
|
226
|
+
if (response.status === 410)
|
|
227
|
+
await ctx.storage.delete(key);
|
|
228
|
+
else if (record)
|
|
229
|
+
await ctx.storage.put(key, record);
|
|
230
|
+
return wireResponse(response);
|
|
231
|
+
}
|
|
232
|
+
if (path === INTERNAL_PICKUP_INFO) {
|
|
233
|
+
if (!rec) {
|
|
234
|
+
return wireResponse({ status: 404, body: invalidSessionErr() });
|
|
235
|
+
}
|
|
236
|
+
if (t > rec.expiresAt) {
|
|
237
|
+
await ctx.storage.delete(key);
|
|
238
|
+
return wireResponse({ status: 410, body: pickupExpiredErr() });
|
|
239
|
+
}
|
|
240
|
+
// NEVER expose the pin or the parked delegation here.
|
|
241
|
+
return wireResponse({
|
|
242
|
+
status: 200,
|
|
243
|
+
body: {
|
|
244
|
+
status: rec.status,
|
|
245
|
+
requiredScopes: rec.requiredScopes,
|
|
246
|
+
minAssurance: rec.minAssurance,
|
|
247
|
+
expiresAt: rec.expiresAt,
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
return wireResponse({ status: 404, body: invalidSessionErr() });
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=anchor-do.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor-do.js","sourceRoot":"","sources":["../../src/delegation-http/anchor-do.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* draft-kya-http-02 delegation layer — pickup-anchor durable-object routing.
|
|
3
|
+
*
|
|
4
|
+
* Anchor state lives in the existing `MCP_OBJECT` durable object (no new DO class,
|
|
5
|
+
* no wrangler migration). Each anchor gets its OWN instance, named `pickup:<sid>`,
|
|
6
|
+
* so the §13 first-poll race is serialized by the DO input gate and never collides
|
|
7
|
+
* with the MCP session namespace (which uses `DO_ROUTING_STRATEGY`).
|
|
8
|
+
*
|
|
9
|
+
* @module @kya-os/mcp-i-cloudflare/delegation-http/anchor-routing
|
|
10
|
+
*/
|
|
11
|
+
import type { DurableObjectStub } from "@cloudflare/workers-types";
|
|
12
|
+
import type { CloudflareEnv } from "../types";
|
|
13
|
+
/** Durable-object instance name for an anchor: one instance per sid. */
|
|
14
|
+
export declare function anchorInstanceId(sid: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Resolve the durable-object stub for an anchor's dedicated instance. Throws when
|
|
17
|
+
* `MCP_OBJECT` is not bound (the anchor layer cannot function without it).
|
|
18
|
+
*/
|
|
19
|
+
export declare function getAnchorStub(env: CloudflareEnv, sid: string): DurableObjectStub;
|
|
20
|
+
//# sourceMappingURL=anchor-routing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor-routing.d.ts","sourceRoot":"","sources":["../../src/delegation-http/anchor-routing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,aAAa,EAClB,GAAG,EAAE,MAAM,GACV,iBAAiB,CASnB"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* draft-kya-http-02 delegation layer — pickup-anchor durable-object routing.
|
|
3
|
+
*
|
|
4
|
+
* Anchor state lives in the existing `MCP_OBJECT` durable object (no new DO class,
|
|
5
|
+
* no wrangler migration). Each anchor gets its OWN instance, named `pickup:<sid>`,
|
|
6
|
+
* so the §13 first-poll race is serialized by the DO input gate and never collides
|
|
7
|
+
* with the MCP session namespace (which uses `DO_ROUTING_STRATEGY`).
|
|
8
|
+
*
|
|
9
|
+
* @module @kya-os/mcp-i-cloudflare/delegation-http/anchor-routing
|
|
10
|
+
*/
|
|
11
|
+
/** Durable-object instance name for an anchor: one instance per sid. */
|
|
12
|
+
export function anchorInstanceId(sid) {
|
|
13
|
+
return `pickup:${sid}`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resolve the durable-object stub for an anchor's dedicated instance. Throws when
|
|
17
|
+
* `MCP_OBJECT` is not bound (the anchor layer cannot function without it).
|
|
18
|
+
*/
|
|
19
|
+
export function getAnchorStub(env, sid) {
|
|
20
|
+
const namespace = env.MCP_OBJECT;
|
|
21
|
+
if (!namespace) {
|
|
22
|
+
throw new Error("[kya-http] MCP_OBJECT durable object namespace is not bound; cannot route pickup anchor");
|
|
23
|
+
}
|
|
24
|
+
const id = namespace.idFromName(anchorInstanceId(sid));
|
|
25
|
+
return namespace.get(id);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=anchor-routing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor-routing.js","sourceRoot":"","sources":["../../src/delegation-http/anchor-routing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,wEAAwE;AACxE,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,OAAO,UAAU,GAAG,EAAE,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAkB,EAClB,GAAW;IAEX,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC;IACjC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,yFAAyF,CAC1F,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,GAAG,SAAS,CAAC,UAAU,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC;IACvD,OAAO,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* draft-kya-http-02 delegation layer — Bearer retry verification.
|
|
3
|
+
*
|
|
4
|
+
* After a §8.1 challenge, a kya-capable caller retries the MCP request carrying the
|
|
5
|
+
* minted delegation as a Bearer credential. This module turns that retry into the
|
|
6
|
+
* adapter's existing `params.delegationToken` priority seam (adapter.ts:~458 — tested
|
|
7
|
+
* by `adapter-delegation-priority.test.ts`), WITHOUT editing the adapter:
|
|
8
|
+
*
|
|
9
|
+
* - `extractDelegationVcJwt` accepts `Authorization: Bearer <jwt>` ONLY when the
|
|
10
|
+
* decoded JWT payload carries a `vc` claim. An opaque OAuth bearer (no `vc`) is
|
|
11
|
+
* left untouched (returns null) so existing OAuth clients pass through. When
|
|
12
|
+
* `Authorization` is occupied by such a non-VC bearer, the `KYA-Delegation` header
|
|
13
|
+
* is used as the fallback carrier.
|
|
14
|
+
* - `applyBearerDelegation` verifies the VC-JWT fail-fast via `DelegationService`
|
|
15
|
+
* and, on success, clones the request with `params.delegationToken = vcJwt`. An
|
|
16
|
+
* invalid chain → 403 `kyaos/chain-broken`; an expired credential → 401
|
|
17
|
+
* `kyaos/expired`. Both error responses carry `Cache-Control: no-store`.
|
|
18
|
+
*
|
|
19
|
+
* @module @kya-os/mcp-i-cloudflare/delegation-http/bearer-retry
|
|
20
|
+
*/
|
|
21
|
+
import type { CloudflareEnv } from "../types";
|
|
22
|
+
import type { HttpChallengeConfig } from "../config";
|
|
23
|
+
/**
|
|
24
|
+
* Extract a delegation VC-JWT from the request, or `null` when there is none to act
|
|
25
|
+
* on. Resolution order, mirroring the wire contract:
|
|
26
|
+
*
|
|
27
|
+
* 1. `Authorization: Bearer <jwt>` whose payload carries a `vc` claim.
|
|
28
|
+
* 2. Otherwise (no Authorization, OR an opaque OAuth bearer without `vc`), the
|
|
29
|
+
* `KYA-Delegation` fallback header — used ONLY when it too is a `vc`-bearing JWT.
|
|
30
|
+
*
|
|
31
|
+
* An opaque OAuth bearer with no `vc` and no fallback header yields `null`, so the
|
|
32
|
+
* request passes through to the adapter untouched.
|
|
33
|
+
*/
|
|
34
|
+
export declare function extractDelegationVcJwt(request: Request): string | null;
|
|
35
|
+
/**
|
|
36
|
+
* Apply a presented delegation to the outgoing MCP request before it reaches the
|
|
37
|
+
* adapter.
|
|
38
|
+
*
|
|
39
|
+
* - No delegation VC-JWT present → pass the request through unchanged.
|
|
40
|
+
* - Expired VC-JWT → `{ errorResponse }` 401 `kyaos/expired` (`no-store`).
|
|
41
|
+
* - Invalid / unverifiable VC-JWT → `{ errorResponse }` 403 `kyaos/chain-broken`
|
|
42
|
+
* (`no-store`).
|
|
43
|
+
* - Valid VC-JWT → `{ request }` whose JSON-RPC body now carries
|
|
44
|
+
* `params.delegationToken = vcJwt` (the adapter's existing priority seam).
|
|
45
|
+
* - Valid VC-JWT but a non-JSON-RPC body the token cannot be injected into →
|
|
46
|
+
* `{ errorResponse }` 400 `invalid_request` (`no-store`); we never silently drop
|
|
47
|
+
* an accepted credential.
|
|
48
|
+
*/
|
|
49
|
+
export declare function applyBearerDelegation(request: Request, env: CloudflareEnv, _cfg: Required<HttpChallengeConfig>): Promise<{
|
|
50
|
+
request: Request;
|
|
51
|
+
} | {
|
|
52
|
+
errorResponse: Response;
|
|
53
|
+
}>;
|
|
54
|
+
//# sourceMappingURL=bearer-retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bearer-retry.d.ts","sourceRoot":"","sources":["../../src/delegation-http/bearer-retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AA4DrD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAgBtE;AA+CD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,QAAQ,CAAC,mBAAmB,CAAC,GAClC,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,aAAa,EAAE,QAAQ,CAAA;CAAE,CAAC,CAqC7D"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* draft-kya-http-02 delegation layer — Bearer retry verification.
|
|
3
|
+
*
|
|
4
|
+
* After a §8.1 challenge, a kya-capable caller retries the MCP request carrying the
|
|
5
|
+
* minted delegation as a Bearer credential. This module turns that retry into the
|
|
6
|
+
* adapter's existing `params.delegationToken` priority seam (adapter.ts:~458 — tested
|
|
7
|
+
* by `adapter-delegation-priority.test.ts`), WITHOUT editing the adapter:
|
|
8
|
+
*
|
|
9
|
+
* - `extractDelegationVcJwt` accepts `Authorization: Bearer <jwt>` ONLY when the
|
|
10
|
+
* decoded JWT payload carries a `vc` claim. An opaque OAuth bearer (no `vc`) is
|
|
11
|
+
* left untouched (returns null) so existing OAuth clients pass through. When
|
|
12
|
+
* `Authorization` is occupied by such a non-VC bearer, the `KYA-Delegation` header
|
|
13
|
+
* is used as the fallback carrier.
|
|
14
|
+
* - `applyBearerDelegation` verifies the VC-JWT fail-fast via `DelegationService`
|
|
15
|
+
* and, on success, clones the request with `params.delegationToken = vcJwt`. An
|
|
16
|
+
* invalid chain → 403 `kyaos/chain-broken`; an expired credential → 401
|
|
17
|
+
* `kyaos/expired`. Both error responses carry `Cache-Control: no-store`.
|
|
18
|
+
*
|
|
19
|
+
* @module @kya-os/mcp-i-cloudflare/delegation-http/bearer-retry
|
|
20
|
+
*/
|
|
21
|
+
import { DelegationService } from "../services/delegation.service";
|
|
22
|
+
import { FALLBACK_DELEGATION_HEADER, KYAOS_ERRORS } from "./constants";
|
|
23
|
+
/**
|
|
24
|
+
* Decode a JWT payload (the second `.`-delimited segment) as JSON, or `null` when the
|
|
25
|
+
* value is not a well-formed three-segment JWT with a base64url-decodable JSON body.
|
|
26
|
+
* Never throws.
|
|
27
|
+
*/
|
|
28
|
+
function decodeJwtPayload(jwt) {
|
|
29
|
+
if (!jwt || typeof jwt !== "string")
|
|
30
|
+
return null;
|
|
31
|
+
const parts = jwt.split(".");
|
|
32
|
+
if (parts.length !== 3)
|
|
33
|
+
return null;
|
|
34
|
+
try {
|
|
35
|
+
// Re-add the base64url padding `atob` needs (the `=` is stripped on the wire);
|
|
36
|
+
// a strict atob rejects an unpadded segment whose length isn't a multiple of 4.
|
|
37
|
+
const b64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
38
|
+
const json = atob(b64 + "=".repeat((4 - (b64.length % 4)) % 4));
|
|
39
|
+
const payload = JSON.parse(json);
|
|
40
|
+
return payload && typeof payload === "object"
|
|
41
|
+
? payload
|
|
42
|
+
: null;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Whether the JWT payload carries a `vc` claim — the marker that distinguishes a
|
|
50
|
+
* delegation VC-JWT from an opaque OAuth bearer.
|
|
51
|
+
*/
|
|
52
|
+
function hasVcClaim(jwt) {
|
|
53
|
+
const payload = decodeJwtPayload(jwt);
|
|
54
|
+
return payload !== null && "vc" in payload;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Whether the JWT is expired by its `exp` claim (seconds since epoch). A token with
|
|
58
|
+
* no numeric `exp`, or one that cannot be decoded, is treated as NOT expired here —
|
|
59
|
+
* the cryptographic verification path owns the invalid-vs-expired distinction for
|
|
60
|
+
* those cases (and reports them as 403 chain-broken).
|
|
61
|
+
*/
|
|
62
|
+
function isVcJwtExpired(jwt) {
|
|
63
|
+
const payload = decodeJwtPayload(jwt);
|
|
64
|
+
if (!payload)
|
|
65
|
+
return false;
|
|
66
|
+
const exp = payload.exp;
|
|
67
|
+
if (typeof exp !== "number" || !Number.isFinite(exp))
|
|
68
|
+
return false;
|
|
69
|
+
return exp < Math.floor(Date.now() / 1000);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Read the bearer token from an `Authorization: Bearer <token>` header, or `null`.
|
|
73
|
+
*/
|
|
74
|
+
function readBearerToken(request) {
|
|
75
|
+
const auth = request.headers.get("Authorization");
|
|
76
|
+
if (!auth)
|
|
77
|
+
return null;
|
|
78
|
+
const match = /^Bearer\s+(.+)$/i.exec(auth.trim());
|
|
79
|
+
return match ? match[1].trim() : null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Extract a delegation VC-JWT from the request, or `null` when there is none to act
|
|
83
|
+
* on. Resolution order, mirroring the wire contract:
|
|
84
|
+
*
|
|
85
|
+
* 1. `Authorization: Bearer <jwt>` whose payload carries a `vc` claim.
|
|
86
|
+
* 2. Otherwise (no Authorization, OR an opaque OAuth bearer without `vc`), the
|
|
87
|
+
* `KYA-Delegation` fallback header — used ONLY when it too is a `vc`-bearing JWT.
|
|
88
|
+
*
|
|
89
|
+
* An opaque OAuth bearer with no `vc` and no fallback header yields `null`, so the
|
|
90
|
+
* request passes through to the adapter untouched.
|
|
91
|
+
*/
|
|
92
|
+
export function extractDelegationVcJwt(request) {
|
|
93
|
+
const bearer = readBearerToken(request);
|
|
94
|
+
if (bearer && hasVcClaim(bearer)) {
|
|
95
|
+
return bearer;
|
|
96
|
+
}
|
|
97
|
+
// Authorization is absent or occupied by a non-VC bearer — try the fallback header.
|
|
98
|
+
const fallback = request.headers.get(FALLBACK_DELEGATION_HEADER);
|
|
99
|
+
if (fallback) {
|
|
100
|
+
const token = fallback.trim();
|
|
101
|
+
if (token && hasVcClaim(token)) {
|
|
102
|
+
return token;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Build a `kyaos/*` JSON error response with the mandated `Cache-Control: no-store`.
|
|
109
|
+
*/
|
|
110
|
+
function kyaosError(error, status) {
|
|
111
|
+
return new Response(JSON.stringify({ error }), {
|
|
112
|
+
status,
|
|
113
|
+
headers: {
|
|
114
|
+
"Content-Type": "application/json",
|
|
115
|
+
"Cache-Control": "no-store",
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Clone `request` rewriting the JSON-RPC body so `params.delegationToken = vcJwt`.
|
|
121
|
+
* Returns `null` when the body is not JSON-RPC-shaped JSON (so the caller can pass the
|
|
122
|
+
* request through untouched rather than corrupt a non-JSON-RPC request).
|
|
123
|
+
*/
|
|
124
|
+
async function rewriteDelegationToken(request, vcJwt) {
|
|
125
|
+
let body;
|
|
126
|
+
try {
|
|
127
|
+
body = await request.clone().json();
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
if (!body || typeof body !== "object")
|
|
133
|
+
return null;
|
|
134
|
+
const rpc = body;
|
|
135
|
+
const params = rpc.params && typeof rpc.params === "object"
|
|
136
|
+
? { ...rpc.params }
|
|
137
|
+
: {};
|
|
138
|
+
params.delegationToken = vcJwt;
|
|
139
|
+
const nextBody = { ...rpc, params };
|
|
140
|
+
return new Request(request.url, {
|
|
141
|
+
method: request.method,
|
|
142
|
+
headers: request.headers,
|
|
143
|
+
body: JSON.stringify(nextBody),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Apply a presented delegation to the outgoing MCP request before it reaches the
|
|
148
|
+
* adapter.
|
|
149
|
+
*
|
|
150
|
+
* - No delegation VC-JWT present → pass the request through unchanged.
|
|
151
|
+
* - Expired VC-JWT → `{ errorResponse }` 401 `kyaos/expired` (`no-store`).
|
|
152
|
+
* - Invalid / unverifiable VC-JWT → `{ errorResponse }` 403 `kyaos/chain-broken`
|
|
153
|
+
* (`no-store`).
|
|
154
|
+
* - Valid VC-JWT → `{ request }` whose JSON-RPC body now carries
|
|
155
|
+
* `params.delegationToken = vcJwt` (the adapter's existing priority seam).
|
|
156
|
+
* - Valid VC-JWT but a non-JSON-RPC body the token cannot be injected into →
|
|
157
|
+
* `{ errorResponse }` 400 `invalid_request` (`no-store`); we never silently drop
|
|
158
|
+
* an accepted credential.
|
|
159
|
+
*/
|
|
160
|
+
export async function applyBearerDelegation(request, env, _cfg) {
|
|
161
|
+
const vcJwt = extractDelegationVcJwt(request);
|
|
162
|
+
if (!vcJwt) {
|
|
163
|
+
return { request };
|
|
164
|
+
}
|
|
165
|
+
// Fail-fast expiry check before verification so we can emit the precise 401.
|
|
166
|
+
if (isVcJwtExpired(vcJwt)) {
|
|
167
|
+
return { errorResponse: kyaosError(KYAOS_ERRORS.expired, 401) };
|
|
168
|
+
}
|
|
169
|
+
const isValid = await new DelegationService(env).verifyDelegation(vcJwt);
|
|
170
|
+
if (!isValid) {
|
|
171
|
+
// verifyDelegation also rejects expired tokens; re-check so an expiry that the
|
|
172
|
+
// pre-check missed (e.g. exp encoded unusually) still maps to 401 not 403.
|
|
173
|
+
if (isVcJwtExpired(vcJwt)) {
|
|
174
|
+
return { errorResponse: kyaosError(KYAOS_ERRORS.expired, 401) };
|
|
175
|
+
}
|
|
176
|
+
return { errorResponse: kyaosError(KYAOS_ERRORS.chainBroken, 403) };
|
|
177
|
+
}
|
|
178
|
+
const rewritten = await rewriteDelegationToken(request, vcJwt);
|
|
179
|
+
if (!rewritten) {
|
|
180
|
+
// The delegation verified, but the request body is not a JSON-RPC object we can
|
|
181
|
+
// augment with params.delegationToken. Fail explicitly with 400: silently
|
|
182
|
+
// forwarding the original request would drop the ACCEPTED credential, and the
|
|
183
|
+
// adapter would then treat the call as unauthorized — masking the acceptance.
|
|
184
|
+
// (A real /mcp POST always carries a JSON-RPC object, so this is a
|
|
185
|
+
// malformed-request guard, not a normal path.)
|
|
186
|
+
//
|
|
187
|
+
// `invalid_request`/400 is deliberately OUT-OF-BAND from the §9 `kyaos/*` registry:
|
|
188
|
+
// this is a transport-level malformed-body error, not a delegation-chain verdict.
|
|
189
|
+
// Reusing a `kyaos/*` 401/403 here would mislead the caller into a retry/challenge
|
|
190
|
+
// loop, and the registry (vendored error-codes.json) has no malformed-body code.
|
|
191
|
+
return { errorResponse: kyaosError("invalid_request", 400) };
|
|
192
|
+
}
|
|
193
|
+
return { request: rewritten };
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=bearer-retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bearer-retry.js","sourceRoot":"","sources":["../../src/delegation-http/bearer-retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEvE;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,GAAW;IACnC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACjD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,CAAC;QACH,+EAA+E;QAC/E,gFAAgF;QAChF,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,OAAO,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;YAC3C,CAAC,CAAE,OAAmC;YACtC,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,UAAU,CAAC,GAAW;IAC7B,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACtC,OAAO,OAAO,KAAK,IAAI,IAAI,IAAI,IAAI,OAAO,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,SAAS,cAAc,CAAC,GAAW;IACjC,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACnE,OAAO,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,OAAgB;IACvC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAClD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACnD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,oFAAoF;IACpF,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;IACjE,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,KAAa,EAAE,MAAc;IAC/C,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;QAC7C,MAAM;QACN,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,eAAe,EAAE,UAAU;SAC5B;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,sBAAsB,CACnC,OAAgB,EAChB,KAAa;IAEb,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAEnD,MAAM,GAAG,GAAG,IAA+B,CAAC;IAC5C,MAAM,MAAM,GACV,GAAG,CAAC,MAAM,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ;QAC1C,CAAC,CAAC,EAAE,GAAI,GAAG,CAAC,MAAkC,EAAE;QAChD,CAAC,CAAC,EAAE,CAAC;IACT,MAAM,CAAC,eAAe,GAAG,KAAK,CAAC;IAC/B,MAAM,QAAQ,GAAG,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,CAAC;IAEpC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE;QAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;KAC/B,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAgB,EAChB,GAAkB,EAClB,IAAmC;IAEnC,MAAM,KAAK,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,OAAO,EAAE,CAAC;IACrB,CAAC;IAED,6EAA6E;IAC7E,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,aAAa,EAAE,UAAU,CAAC,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC;IAClE,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,IAAI,iBAAiB,CAAC,GAAG,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACzE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,+EAA+E;QAC/E,2EAA2E;QAC3E,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,aAAa,EAAE,UAAU,CAAC,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC;QAClE,CAAC;QACD,OAAO,EAAE,aAAa,EAAE,UAAU,CAAC,YAAY,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,CAAC;IACtE,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,sBAAsB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC/D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,gFAAgF;QAChF,0EAA0E;QAC1E,8EAA8E;QAC9E,8EAA8E;QAC9E,mEAAmE;QACnE,+CAA+C;QAC/C,EAAE;QACF,oFAAoF;QACpF,kFAAkF;QAClF,mFAAmF;QACnF,iFAAiF;QACjF,OAAO,EAAE,aAAa,EAAE,UAAU,CAAC,iBAAiB,EAAE,GAAG,CAAC,EAAE,CAAC;IAC/D,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* draft-kya-http-02 delegation layer — §8.1 challenge emitter middleware.
|
|
3
|
+
*
|
|
4
|
+
* Triggers on JSON-RPC responses whose `result._meta.errorType ===
|
|
5
|
+
* "authorization_required"` (the existing `DelegationRequiredError` → `result._meta`
|
|
6
|
+
* mapping in `adapter.ts`), mints a sid, creates the pickup anchor (which MUST exist
|
|
7
|
+
* before the 401 leaves), signs the `challenge_proof`, and emits the §8.1 401 in
|
|
8
|
+
* `negotiated`/`always` mode. Returns `null` to pass the original response through.
|
|
9
|
+
*
|
|
10
|
+
* @module @kya-os/mcp-i-cloudflare/delegation-http/challenge-middleware
|
|
11
|
+
*/
|
|
12
|
+
import type { CloudflareEnv } from "../types";
|
|
13
|
+
import type { HttpChallengeConfig } from "../config";
|
|
14
|
+
import type { CloudflareProofGenerator } from "../proof-generator";
|
|
15
|
+
import type { getAnchorStub } from "./anchor-routing";
|
|
16
|
+
/**
|
|
17
|
+
* Emit a §8.1 delegation challenge in place of an `authorization_required` MCP
|
|
18
|
+
* response, or return `null` to pass the original response through untouched.
|
|
19
|
+
*
|
|
20
|
+
* `negotiated` (default): when the caller is NOT kya-capable, the ORIGINAL MCP error
|
|
21
|
+
* response is returned (so existing MCP/OAuth clients still see the unmodified error),
|
|
22
|
+
* never a 401. `always`: every `authorization_required` becomes a 401.
|
|
23
|
+
*/
|
|
24
|
+
export declare function maybeEmitDelegationChallenge(request: Request, response: Response, env: CloudflareEnv, cfg: Required<HttpChallengeConfig>, deps: {
|
|
25
|
+
getAnchorStub: typeof getAnchorStub;
|
|
26
|
+
proofGenerator: () => Promise<CloudflareProofGenerator>;
|
|
27
|
+
}): Promise<Response | null>;
|
|
28
|
+
//# sourceMappingURL=challenge-middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"challenge-middleware.d.ts","sourceRoot":"","sources":["../../src/delegation-http/challenge-middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AA+GtD;;;;;;;GAOG;AACH,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,aAAa,EAClB,GAAG,EAAE,QAAQ,CAAC,mBAAmB,CAAC,EAClC,IAAI,EAAE;IACJ,aAAa,EAAE,OAAO,aAAa,CAAC;IACpC,cAAc,EAAE,MAAM,OAAO,CAAC,wBAAwB,CAAC,CAAC;CACzD,GACA,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAwG1B"}
|