agent-authority 0.1.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.
- package/CHANGELOG.md +118 -0
- package/LICENSE +21 -0
- package/QUICKSTART.md +91 -0
- package/README.md +553 -0
- package/dist/a2a.d.ts +73 -0
- package/dist/a2a.d.ts.map +1 -0
- package/dist/a2a.js +117 -0
- package/dist/a2a.js.map +1 -0
- package/dist/audit.d.ts +12 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +52 -0
- package/dist/audit.js.map +1 -0
- package/dist/behalf.d.ts +173 -0
- package/dist/behalf.d.ts.map +1 -0
- package/dist/behalf.js +475 -0
- package/dist/behalf.js.map +1 -0
- package/dist/capability.d.ts +56 -0
- package/dist/capability.d.ts.map +1 -0
- package/dist/capability.js +176 -0
- package/dist/capability.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +273 -0
- package/dist/cli.js.map +1 -0
- package/dist/control-plane.d.ts +57 -0
- package/dist/control-plane.d.ts.map +1 -0
- package/dist/control-plane.js +332 -0
- package/dist/control-plane.js.map +1 -0
- package/dist/crypto.d.ts +68 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +105 -0
- package/dist/crypto.js.map +1 -0
- package/dist/errors.d.ts +25 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +40 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/lint.d.ts +17 -0
- package/dist/lint.d.ts.map +1 -0
- package/dist/lint.js +75 -0
- package/dist/lint.js.map +1 -0
- package/dist/mandate.d.ts +99 -0
- package/dist/mandate.d.ts.map +1 -0
- package/dist/mandate.js +141 -0
- package/dist/mandate.js.map +1 -0
- package/dist/mcp-server.d.ts +26 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +111 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/mcp.d.ts +63 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +123 -0
- package/dist/mcp.js.map +1 -0
- package/dist/persist.d.ts +51 -0
- package/dist/persist.d.ts.map +1 -0
- package/dist/persist.js +150 -0
- package/dist/persist.js.map +1 -0
- package/dist/quickstart.d.ts +63 -0
- package/dist/quickstart.d.ts.map +1 -0
- package/dist/quickstart.js +171 -0
- package/dist/quickstart.js.map +1 -0
- package/dist/remote.d.ts +93 -0
- package/dist/remote.d.ts.map +1 -0
- package/dist/remote.js +120 -0
- package/dist/remote.js.map +1 -0
- package/dist/seal.d.ts +12 -0
- package/dist/seal.d.ts.map +1 -0
- package/dist/seal.js +96 -0
- package/dist/seal.js.map +1 -0
- package/dist/store.d.ts +119 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +139 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +173 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/llms.txt +106 -0
- package/package.json +107 -0
- package/schemas/capability.schema.json +14 -0
- package/schemas/mandate.schema.json +68 -0
- package/vectors/mandate-vector.json +63 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { realpathSync } from "node:fs";
|
|
5
|
+
import { MemoryRevocationStore, MemoryAuditStore, MemoryRateStore, MemoryConsentStore, MemoryPolicyStore, } from "./store.js";
|
|
6
|
+
export function createControlPlane(options = {}) {
|
|
7
|
+
const revocations = options.revocations ?? new MemoryRevocationStore();
|
|
8
|
+
const audit = options.audit ?? new MemoryAuditStore();
|
|
9
|
+
const rate = options.rate ?? new MemoryRateStore();
|
|
10
|
+
const consents = options.consents ?? new MemoryConsentStore();
|
|
11
|
+
const policies = options.policies ?? new MemoryPolicyStore();
|
|
12
|
+
let server;
|
|
13
|
+
const handler = (req, res) => {
|
|
14
|
+
void route(req, res).catch((e) => send(res, 500, { error: String(e) }));
|
|
15
|
+
};
|
|
16
|
+
async function route(req, res) {
|
|
17
|
+
// Resolve the caller. `token` is an admin credential (full, unscoped);
|
|
18
|
+
// `tenants` maps a bearer token to the issuer it is allowed to act for.
|
|
19
|
+
let isAdmin = false;
|
|
20
|
+
let callerIssuer;
|
|
21
|
+
if (options.token || options.tenants) {
|
|
22
|
+
const auth = req.headers["authorization"];
|
|
23
|
+
const bearer = typeof auth === "string" && auth.startsWith("Bearer ") ? auth.slice(7) : "";
|
|
24
|
+
if (options.token && bearer === options.token) {
|
|
25
|
+
isAdmin = true;
|
|
26
|
+
}
|
|
27
|
+
else if (options.tenants && Object.prototype.hasOwnProperty.call(options.tenants, bearer) && bearer) {
|
|
28
|
+
callerIssuer = options.tenants[bearer];
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
return send(res, 401, { error: "unauthorized" });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const url = new URL(req.url ?? "/", "http://localhost");
|
|
35
|
+
const path = url.pathname;
|
|
36
|
+
const method = req.method ?? "GET";
|
|
37
|
+
// ---- Dashboard ----
|
|
38
|
+
if (method === "GET" && path === "/") {
|
|
39
|
+
// A tenant only ever sees its own audit; the shared revocation/consent
|
|
40
|
+
// views are withheld so the dashboard can't leak across tenants.
|
|
41
|
+
if (callerIssuer) {
|
|
42
|
+
const recent = (await audit.forIssuer(callerIssuer)).slice(-20).reverse();
|
|
43
|
+
return sendHtml(res, dashboard([], recent, []));
|
|
44
|
+
}
|
|
45
|
+
// Admin / single-trust-domain: full view (withheld under tenantScoped).
|
|
46
|
+
const recent = options.tenantScoped ? [] : (await audit.all()).slice(-20).reverse();
|
|
47
|
+
return sendHtml(res, dashboard(listRevoked(revocations), recent, await consents.list()));
|
|
48
|
+
}
|
|
49
|
+
// ---- Revocation ----
|
|
50
|
+
// Tenant revocations are namespaced under the tenant's issuer, so one
|
|
51
|
+
// tenant can never revoke (or unrevoke-by-collision) another tenant's
|
|
52
|
+
// mandate ids. Admin revocations are global and visible to all tenants.
|
|
53
|
+
const revKey = (id) => (callerIssuer ? `${callerIssuer} ${id}` : id);
|
|
54
|
+
if (method === "POST" && path === "/v1/revoke") {
|
|
55
|
+
const body = await readJson(req);
|
|
56
|
+
if (!body?.id)
|
|
57
|
+
return send(res, 400, { error: "id required" });
|
|
58
|
+
await revocations.revoke(revKey(String(body.id)));
|
|
59
|
+
return send(res, 200, { ok: true });
|
|
60
|
+
}
|
|
61
|
+
if (method === "GET" && path === "/v1/revoked") {
|
|
62
|
+
const all = listRevoked(revocations);
|
|
63
|
+
const ids = callerIssuer
|
|
64
|
+
? all.filter((i) => i.startsWith(`${callerIssuer} `)).map((i) => i.slice(callerIssuer.length + 1))
|
|
65
|
+
: all;
|
|
66
|
+
return send(res, 200, { ids });
|
|
67
|
+
}
|
|
68
|
+
const revMatch = method === "GET" && /^\/v1\/revoked\/(.+)$/.exec(path);
|
|
69
|
+
if (revMatch) {
|
|
70
|
+
const id = decodeURIComponent(revMatch[1]);
|
|
71
|
+
// Tenants see their own namespaced revocations PLUS global (admin) ones.
|
|
72
|
+
const revoked = (await revocations.isRevoked(revKey(id))) ||
|
|
73
|
+
(callerIssuer ? await revocations.isRevoked(id) : false);
|
|
74
|
+
return send(res, 200, { revoked: Boolean(revoked) });
|
|
75
|
+
}
|
|
76
|
+
// ---- Audit retention ----
|
|
77
|
+
if (method === "POST" && path === "/v1/audit") {
|
|
78
|
+
const body = await readJson(req);
|
|
79
|
+
// Preferred path: the client sends raw fields and the control plane (the
|
|
80
|
+
// single writer) seals them onto the chain — race-free, O(1) per record.
|
|
81
|
+
if (body?.fields) {
|
|
82
|
+
const fields = body.fields;
|
|
83
|
+
if (callerIssuer && fields.issuer !== callerIssuer) {
|
|
84
|
+
return send(res, 403, { error: "issuer does not match tenant token" });
|
|
85
|
+
}
|
|
86
|
+
const entry = await audit.record(fields);
|
|
87
|
+
return send(res, 200, { entry });
|
|
88
|
+
}
|
|
89
|
+
// Replication path: store an already-sealed entry verbatim.
|
|
90
|
+
if (body?.entry) {
|
|
91
|
+
if (callerIssuer && body.entry.issuer !== callerIssuer) {
|
|
92
|
+
return send(res, 403, { error: "issuer does not match tenant token" });
|
|
93
|
+
}
|
|
94
|
+
await audit.append(body.entry);
|
|
95
|
+
return send(res, 200, { entry: body.entry });
|
|
96
|
+
}
|
|
97
|
+
return send(res, 400, { error: "fields or entry required" });
|
|
98
|
+
}
|
|
99
|
+
if (method === "GET" && path === "/v1/audit") {
|
|
100
|
+
// A tenant token is locked to its own issuer, ignoring any ?issuer.
|
|
101
|
+
let entries;
|
|
102
|
+
if (callerIssuer) {
|
|
103
|
+
entries = await audit.forIssuer(callerIssuer);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
const issuer = url.searchParams.get("issuer");
|
|
107
|
+
if (issuer)
|
|
108
|
+
entries = await audit.forIssuer(issuer);
|
|
109
|
+
else if (options.tenantScoped) {
|
|
110
|
+
return send(res, 403, { error: "issuer query required (tenant-scoped)" });
|
|
111
|
+
}
|
|
112
|
+
else
|
|
113
|
+
entries = await audit.all();
|
|
114
|
+
}
|
|
115
|
+
// Pagination so the response stays bounded as the log grows.
|
|
116
|
+
const total = entries.length;
|
|
117
|
+
const offset = Math.max(0, Number(url.searchParams.get("offset") ?? 0) || 0);
|
|
118
|
+
const limitRaw = Number(url.searchParams.get("limit") ?? 0);
|
|
119
|
+
const limit = Number.isFinite(limitRaw) && limitRaw > 0 ? limitRaw : undefined;
|
|
120
|
+
if (offset > 0 || limit !== undefined) {
|
|
121
|
+
entries = entries.slice(offset, limit !== undefined ? offset + limit : undefined);
|
|
122
|
+
}
|
|
123
|
+
return send(res, 200, { entries, total });
|
|
124
|
+
}
|
|
125
|
+
const auditMatch = method === "GET" && /^\/v1\/audit\/(.+)$/.exec(path);
|
|
126
|
+
if (auditMatch) {
|
|
127
|
+
const id = decodeURIComponent(auditMatch[1]);
|
|
128
|
+
let entries = await audit.forMandate(id);
|
|
129
|
+
if (callerIssuer)
|
|
130
|
+
entries = entries.filter((e) => e.issuer === callerIssuer);
|
|
131
|
+
return send(res, 200, { entries });
|
|
132
|
+
}
|
|
133
|
+
// ---- Shared rate limiting ----
|
|
134
|
+
if (method === "POST" && path === "/v1/rate") {
|
|
135
|
+
const body = await readJson(req);
|
|
136
|
+
if (!body?.key)
|
|
137
|
+
return send(res, 400, { error: "key required" });
|
|
138
|
+
const windowMs = Number(body.windowMs);
|
|
139
|
+
const limit = Number(body.limit);
|
|
140
|
+
if (!Number.isFinite(windowMs) || windowMs <= 0 || !Number.isFinite(limit) || limit < 0) {
|
|
141
|
+
return send(res, 400, { error: "windowMs must be > 0 and limit must be >= 0" });
|
|
142
|
+
}
|
|
143
|
+
// The control plane is the time authority — the client's clock is ignored
|
|
144
|
+
// so it can't slide the window to evade the shared cap. Tenant rate keys
|
|
145
|
+
// are namespaced so tenants can't consume (or observe) each other's caps.
|
|
146
|
+
const rateKey = callerIssuer ? `${callerIssuer} ${String(body.key)}` : String(body.key);
|
|
147
|
+
const allowed = await rate.hit(rateKey, windowMs, limit, Date.now());
|
|
148
|
+
return send(res, 200, { allowed });
|
|
149
|
+
}
|
|
150
|
+
// ---- Consent ----
|
|
151
|
+
// Pending requests past their TTL become "expired" — a terminal deny.
|
|
152
|
+
const sweep = async (r) => {
|
|
153
|
+
if (r.status === "pending" &&
|
|
154
|
+
options.consentTtlMs !== undefined &&
|
|
155
|
+
Date.now() - r.createdAt > options.consentTtlMs) {
|
|
156
|
+
r.status = "expired";
|
|
157
|
+
r.decidedAt = Date.now();
|
|
158
|
+
await consents.put(r);
|
|
159
|
+
}
|
|
160
|
+
return r;
|
|
161
|
+
};
|
|
162
|
+
// A tenant token only sees/decides its own consent records.
|
|
163
|
+
const visible = (r) => !callerIssuer || r.issuer === callerIssuer;
|
|
164
|
+
if (method === "POST" && path === "/v1/consent") {
|
|
165
|
+
const body = await readJson(req);
|
|
166
|
+
if (!body?.agent || !body?.capability) {
|
|
167
|
+
return send(res, 400, { error: "agent and capability required" });
|
|
168
|
+
}
|
|
169
|
+
const id = randomId();
|
|
170
|
+
const record = {
|
|
171
|
+
id,
|
|
172
|
+
agent: String(body.agent),
|
|
173
|
+
capability: String(body.capability),
|
|
174
|
+
context: body.context,
|
|
175
|
+
...(callerIssuer ? { issuer: callerIssuer } : {}),
|
|
176
|
+
status: "pending",
|
|
177
|
+
createdAt: Date.now(),
|
|
178
|
+
};
|
|
179
|
+
await consents.put(record);
|
|
180
|
+
return send(res, 201, record);
|
|
181
|
+
}
|
|
182
|
+
if (method === "GET" && path === "/v1/consent") {
|
|
183
|
+
const all = await Promise.all((await consents.list()).map(sweep));
|
|
184
|
+
return send(res, 200, { consents: all.filter(visible) });
|
|
185
|
+
}
|
|
186
|
+
const consentDecide = method === "POST" && /^\/v1\/consent\/([^/]+)\/decision$/.exec(path);
|
|
187
|
+
if (consentDecide) {
|
|
188
|
+
const record = await consents.get(consentDecide[1]);
|
|
189
|
+
if (!record || !visible(record))
|
|
190
|
+
return send(res, 404, { error: "not found" });
|
|
191
|
+
await sweep(record);
|
|
192
|
+
if (record.status === "expired")
|
|
193
|
+
return send(res, 200, record);
|
|
194
|
+
const body = await readJson(req);
|
|
195
|
+
record.status = body?.approve ? "approved" : "denied";
|
|
196
|
+
record.decidedAt = Date.now();
|
|
197
|
+
await consents.put(record);
|
|
198
|
+
return send(res, 200, record);
|
|
199
|
+
}
|
|
200
|
+
const consentGet = method === "GET" && /^\/v1\/consent\/([^/]+)$/.exec(path);
|
|
201
|
+
if (consentGet) {
|
|
202
|
+
const record = await consents.get(consentGet[1]);
|
|
203
|
+
if (!record || !visible(record))
|
|
204
|
+
return send(res, 404, { error: "not found" });
|
|
205
|
+
return send(res, 200, await sweep(record));
|
|
206
|
+
}
|
|
207
|
+
// ---- Policy ----
|
|
208
|
+
const policyMatch = /^\/v1\/policy\/([^/]+)$/.exec(path);
|
|
209
|
+
if (policyMatch) {
|
|
210
|
+
const name = policyMatch[1];
|
|
211
|
+
// Tenants get a private namespace so policy names can't clash or leak.
|
|
212
|
+
const key = callerIssuer ? `${callerIssuer}${name}` : name;
|
|
213
|
+
if (method === "GET") {
|
|
214
|
+
return (await policies.has(key))
|
|
215
|
+
? send(res, 200, { name, policy: await policies.get(key) })
|
|
216
|
+
: send(res, 404, { error: "not found" });
|
|
217
|
+
}
|
|
218
|
+
if (method === "PUT") {
|
|
219
|
+
const body = await readJson(req);
|
|
220
|
+
await policies.set(key, body?.policy ?? body);
|
|
221
|
+
return send(res, 200, { name, policy: await policies.get(key) });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return send(res, 404, { error: `no route for ${method} ${path}` });
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
handler,
|
|
228
|
+
listen(port = 0) {
|
|
229
|
+
server = createServer(handler);
|
|
230
|
+
return new Promise((resolve) => {
|
|
231
|
+
server.listen(port, () => {
|
|
232
|
+
const addr = server.address();
|
|
233
|
+
resolve(typeof addr === "object" && addr ? addr.port : port);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
},
|
|
237
|
+
close() {
|
|
238
|
+
return new Promise((resolve) => (server ? server.close(() => resolve()) : resolve()));
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
// ---- helpers ----
|
|
243
|
+
function readJson(req) {
|
|
244
|
+
return new Promise((resolve) => {
|
|
245
|
+
let data = "";
|
|
246
|
+
req.on("data", (c) => (data += c));
|
|
247
|
+
req.on("end", () => {
|
|
248
|
+
if (!data)
|
|
249
|
+
return resolve(null);
|
|
250
|
+
try {
|
|
251
|
+
resolve(JSON.parse(data));
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
resolve(null);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
req.on("error", () => resolve(null));
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
function send(res, status, body) {
|
|
261
|
+
res.statusCode = status;
|
|
262
|
+
res.setHeader("content-type", "application/json");
|
|
263
|
+
res.end(JSON.stringify(body));
|
|
264
|
+
}
|
|
265
|
+
function sendHtml(res, html) {
|
|
266
|
+
res.statusCode = 200;
|
|
267
|
+
res.setHeader("content-type", "text/html; charset=utf-8");
|
|
268
|
+
res.end(html);
|
|
269
|
+
}
|
|
270
|
+
function randomId() {
|
|
271
|
+
return Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
272
|
+
}
|
|
273
|
+
function listRevoked(store) {
|
|
274
|
+
// MemoryRevocationStore keeps a private Set; expose what we can generically.
|
|
275
|
+
return store.revoked
|
|
276
|
+
? [...store.revoked]
|
|
277
|
+
: [];
|
|
278
|
+
}
|
|
279
|
+
function esc(s) {
|
|
280
|
+
return String(s).replace(/[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c]);
|
|
281
|
+
}
|
|
282
|
+
function dashboard(revoked, recent, consents) {
|
|
283
|
+
const pending = consents.filter((c) => c.status === "pending");
|
|
284
|
+
return `<!doctype html><html><head><meta charset="utf-8"><title>Behalf Control Plane</title>
|
|
285
|
+
<style>body{font:14px system-ui,sans-serif;margin:2rem;max-width:60rem}h1{font-size:1.4rem}
|
|
286
|
+
table{border-collapse:collapse;width:100%;margin:.5rem 0 2rem}td,th{border:1px solid #ddd;padding:.3rem .5rem;text-align:left}
|
|
287
|
+
.deny{color:#b00}.allow{color:#070}code{background:#f4f4f4;padding:.1rem .3rem;border-radius:3px}</style></head><body>
|
|
288
|
+
<h1>Behalf Control Plane</h1>
|
|
289
|
+
<h2>Revoked mandates (${revoked.length})</h2>
|
|
290
|
+
<table><tr><th>id</th></tr>${revoked.map((id) => `<tr><td><code>${esc(id)}</code></td></tr>`).join("") || "<tr><td>none</td></tr>"}</table>
|
|
291
|
+
<h2>Pending consent (${pending.length})</h2>
|
|
292
|
+
<table><tr><th>id</th><th>agent</th><th>capability</th></tr>${pending.map((c) => `<tr><td><code>${esc(c.id)}</code></td><td>${esc(c.agent)}</td><td><code>${esc(c.capability)}</code></td></tr>`).join("") ||
|
|
293
|
+
"<tr><td colspan=3>none</td></tr>"}</table>
|
|
294
|
+
<h2>Recent audit (${recent.length})</h2>
|
|
295
|
+
<table><tr><th>time</th><th>decision</th><th>action</th><th>reason</th></tr>${recent
|
|
296
|
+
.map((e) => `<tr><td>${new Date(e.ts).toISOString()}</td><td class="${e.decision}">${esc(e.decision)}</td><td><code>${esc(e.action)}</code></td><td>${esc(e.reason ?? "")}</td></tr>`)
|
|
297
|
+
.join("") || "<tr><td colspan=4>none</td></tr>"}</table>
|
|
298
|
+
</body></html>`;
|
|
299
|
+
}
|
|
300
|
+
// Allow `node dist/control-plane.js` (and the `behalf-control-plane` bin) to run
|
|
301
|
+
// a durable, file-backed control plane. PORT and BEHALF_HOME are read from env.
|
|
302
|
+
function runningAsMain() {
|
|
303
|
+
const entry = process.argv[1];
|
|
304
|
+
if (!entry)
|
|
305
|
+
return false;
|
|
306
|
+
try {
|
|
307
|
+
return realpathSync(entry) === realpathSync(fileURLToPath(import.meta.url));
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (runningAsMain()) {
|
|
314
|
+
void (async () => {
|
|
315
|
+
const { join } = await import("node:path");
|
|
316
|
+
const { homedir } = await import("node:os");
|
|
317
|
+
const { FileRevocationStore, FileAuditStore, FileConsentStore, FilePolicyStore, FileRateStore } = await import("./persist.js");
|
|
318
|
+
const home = process.env.BEHALF_HOME ?? join(homedir(), ".behalf");
|
|
319
|
+
const port = Number(process.env.PORT ?? 8787);
|
|
320
|
+
const cp = createControlPlane({
|
|
321
|
+
revocations: new FileRevocationStore(join(home, "revocations.json")),
|
|
322
|
+
audit: new FileAuditStore(join(home, "audit.jsonl")),
|
|
323
|
+
consents: new FileConsentStore(join(home, "consents.json")),
|
|
324
|
+
policies: new FilePolicyStore(join(home, "policies.json")),
|
|
325
|
+
rate: new FileRateStore(join(home, "rate.json")),
|
|
326
|
+
token: process.env.BEHALF_TOKEN,
|
|
327
|
+
});
|
|
328
|
+
const bound = await cp.listen(port);
|
|
329
|
+
console.error(`behalf control plane listening on http://127.0.0.1:${bound} (dashboard at /)`);
|
|
330
|
+
})();
|
|
331
|
+
}
|
|
332
|
+
//# sourceMappingURL=control-plane.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-plane.js","sourceRoot":"","sources":["../src/control-plane.ts"],"names":[],"mappings":"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"}
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type KeyObject } from "node:crypto";
|
|
2
|
+
import type { Block } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Asymmetric attenuable tokens (biscuit-style Ed25519 signature chain).
|
|
5
|
+
*
|
|
6
|
+
* The token is an ordered list of blocks. Block 0 (the root grant) is signed by
|
|
7
|
+
* the issuer's private key. Every block also publishes a fresh public key
|
|
8
|
+
* (`nextPub`); the *next* block is signed by the matching private key. So:
|
|
9
|
+
*
|
|
10
|
+
* sig[0] = sign(rootPriv, canonical(block[0])) verify with rootPub
|
|
11
|
+
* sig[i] = sign(block[i-1].next, canonical(block[i])) verify with block[i-1].nextPub
|
|
12
|
+
*
|
|
13
|
+
* Consequences:
|
|
14
|
+
* - Verification needs only PUBLIC keys — any relying party can check a mandate
|
|
15
|
+
* and its whole chain offline, without the issuer's secret.
|
|
16
|
+
* - A holder attenuates by appending a block signed with the private key it was
|
|
17
|
+
* handed; it never needs the issuer key.
|
|
18
|
+
* - A block cannot be edited (its signature) or removed from the middle (the
|
|
19
|
+
* next block's signer key was published inside it). Trailing-block TRUNCATION
|
|
20
|
+
* is prevented separately, at authorize time, by a proof of possession: the
|
|
21
|
+
* presenter must sign a fresh challenge with the private key matching the
|
|
22
|
+
* LAST block's `nextPub`. Each delegation hands a fresh such key downstream,
|
|
23
|
+
* so a holder cannot produce the proof for any shorter prefix of its chain.
|
|
24
|
+
* - Widening is impossible because every block's caveats are intersected at
|
|
25
|
+
* authorize time.
|
|
26
|
+
*/
|
|
27
|
+
export interface KeyPair {
|
|
28
|
+
publicKey: KeyObject;
|
|
29
|
+
privateKey: KeyObject;
|
|
30
|
+
}
|
|
31
|
+
export declare function newKeyPair(): KeyPair;
|
|
32
|
+
/**
|
|
33
|
+
* Deterministic canonical JSON: object keys sorted recursively, no insignificant
|
|
34
|
+
* whitespace. Produces byte-identical output to Python's
|
|
35
|
+
* `json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=False)`,
|
|
36
|
+
* so the two reference ports — and any third-party verifier following this rule —
|
|
37
|
+
* compute the same signed bytes regardless of object construction order.
|
|
38
|
+
*/
|
|
39
|
+
export declare function canonicalJson(value: unknown): string;
|
|
40
|
+
/** Canonical bytes for a block (what gets signed/verified) — see canonicalJson. */
|
|
41
|
+
export declare function canonicalBlock(block: Block): string;
|
|
42
|
+
export declare function signBlock(privateKey: KeyObject, block: Block): string;
|
|
43
|
+
export declare function verifyBlock(publicKey: KeyObject, block: Block, sig: string): boolean;
|
|
44
|
+
export declare function exportPublicKey(key: KeyObject): string;
|
|
45
|
+
export declare function importPublicKey(b64: string): KeyObject;
|
|
46
|
+
export declare function exportPrivateKey(key: KeyObject): string;
|
|
47
|
+
export declare function importPrivateKey(d: string, x: string): KeyObject;
|
|
48
|
+
/**
|
|
49
|
+
* Proof of possession (PoP) of the chain's terminal key — closes trailing-block
|
|
50
|
+
* truncation and makes a serialized token NOT a usable bearer credential.
|
|
51
|
+
*
|
|
52
|
+
* The message binds the proof to the EXACT presented chain (id + every block
|
|
53
|
+
* signature), the timestamp, AND the action, so it cannot be replayed for a
|
|
54
|
+
* different/truncated token or reused for a different action, and only within a
|
|
55
|
+
* short freshness window for the same (token, action). Producing it requires the
|
|
56
|
+
* private key matching `blocks[last].nextPub`, which only the legitimate tail
|
|
57
|
+
* holder has. (Over the wire, run under TLS; for single-use guarantees within
|
|
58
|
+
* the window, layer a verifier-issued nonce.)
|
|
59
|
+
*/
|
|
60
|
+
export declare function proofMessage(id: string, sigs: string[], ts: number, action: string, nonce?: string): string;
|
|
61
|
+
export declare function signProof(delegationKey: KeyObject, id: string, sigs: string[], ts: number, action: string, nonce?: string): string;
|
|
62
|
+
export declare function verifyProof(terminalPub: KeyObject, id: string, sigs: string[], ts: number, action: string, sig: string, nonce?: string): boolean;
|
|
63
|
+
/** Sign / verify an arbitrary canonical message (used for audit checkpoints). */
|
|
64
|
+
export declare function signMessage(privateKey: KeyObject, message: string): string;
|
|
65
|
+
export declare function verifyMessage(publicKey: KeyObject, message: string, sig: string): boolean;
|
|
66
|
+
export declare function sha256Hex(data: string): string;
|
|
67
|
+
export declare function newId(): string;
|
|
68
|
+
//# sourceMappingURL=crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,SAAS,CAAC;CACvB;AAED,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAYpD;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAEnD;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,CAIrE;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAWpF;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAMtD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAEtD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAKvD;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAEhE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EAAE,EACd,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,KAAK,SAAK,GACT,MAAM,CAER;AAED,wBAAgB,SAAS,CACvB,aAAa,EAAE,SAAS,EACxB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EAAE,EACd,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,KAAK,SAAK,GACT,MAAM,CAMR;AAED,wBAAgB,WAAW,CACzB,WAAW,EAAE,SAAS,EACtB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EAAE,EACd,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,KAAK,SAAK,GACT,OAAO,CAWT;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAMzF;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,KAAK,IAAI,MAAM,CAE9B"}
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { generateKeyPairSync, sign as edSign, verify as edVerify, createHash, createPublicKey, createPrivateKey, randomUUID, } from "node:crypto";
|
|
2
|
+
export function newKeyPair() {
|
|
3
|
+
return generateKeyPairSync("ed25519");
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Deterministic canonical JSON: object keys sorted recursively, no insignificant
|
|
7
|
+
* whitespace. Produces byte-identical output to Python's
|
|
8
|
+
* `json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=False)`,
|
|
9
|
+
* so the two reference ports — and any third-party verifier following this rule —
|
|
10
|
+
* compute the same signed bytes regardless of object construction order.
|
|
11
|
+
*/
|
|
12
|
+
export function canonicalJson(value) {
|
|
13
|
+
if (value === null || typeof value !== "object")
|
|
14
|
+
return JSON.stringify(value);
|
|
15
|
+
if (Array.isArray(value))
|
|
16
|
+
return "[" + value.map(canonicalJson).join(",") + "]";
|
|
17
|
+
const obj = value;
|
|
18
|
+
return ("{" +
|
|
19
|
+
Object.keys(obj)
|
|
20
|
+
.sort()
|
|
21
|
+
.map((k) => JSON.stringify(k) + ":" + canonicalJson(obj[k]))
|
|
22
|
+
.join(",") +
|
|
23
|
+
"}");
|
|
24
|
+
}
|
|
25
|
+
/** Canonical bytes for a block (what gets signed/verified) — see canonicalJson. */
|
|
26
|
+
export function canonicalBlock(block) {
|
|
27
|
+
return canonicalJson({ caveats: block.caveats, nextPub: block.nextPub });
|
|
28
|
+
}
|
|
29
|
+
export function signBlock(privateKey, block) {
|
|
30
|
+
return edSign(null, Buffer.from(canonicalBlock(block), "utf8"), privateKey).toString("base64url");
|
|
31
|
+
}
|
|
32
|
+
export function verifyBlock(publicKey, block, sig) {
|
|
33
|
+
try {
|
|
34
|
+
return edVerify(null, Buffer.from(canonicalBlock(block), "utf8"), publicKey, Buffer.from(sig, "base64url"));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function exportPublicKey(key) {
|
|
41
|
+
// Raw 32-byte Ed25519 public key (JWK `x`), base64url — matches the Python
|
|
42
|
+
// port's encoding so tokens verify across both reference implementations.
|
|
43
|
+
const jwk = key.export({ format: "jwk" });
|
|
44
|
+
if (!jwk.x)
|
|
45
|
+
throw new Error("not an Ed25519 public key");
|
|
46
|
+
return jwk.x;
|
|
47
|
+
}
|
|
48
|
+
export function importPublicKey(b64) {
|
|
49
|
+
return createPublicKey({ key: { kty: "OKP", crv: "Ed25519", x: b64 }, format: "jwk" });
|
|
50
|
+
}
|
|
51
|
+
export function exportPrivateKey(key) {
|
|
52
|
+
// Raw 32-byte seed (JWK `d`), base64url.
|
|
53
|
+
const jwk = key.export({ format: "jwk" });
|
|
54
|
+
if (!jwk.d)
|
|
55
|
+
throw new Error("not an Ed25519 private key");
|
|
56
|
+
return jwk.d;
|
|
57
|
+
}
|
|
58
|
+
export function importPrivateKey(d, x) {
|
|
59
|
+
return createPrivateKey({ key: { kty: "OKP", crv: "Ed25519", x, d }, format: "jwk" });
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Proof of possession (PoP) of the chain's terminal key — closes trailing-block
|
|
63
|
+
* truncation and makes a serialized token NOT a usable bearer credential.
|
|
64
|
+
*
|
|
65
|
+
* The message binds the proof to the EXACT presented chain (id + every block
|
|
66
|
+
* signature), the timestamp, AND the action, so it cannot be replayed for a
|
|
67
|
+
* different/truncated token or reused for a different action, and only within a
|
|
68
|
+
* short freshness window for the same (token, action). Producing it requires the
|
|
69
|
+
* private key matching `blocks[last].nextPub`, which only the legitimate tail
|
|
70
|
+
* holder has. (Over the wire, run under TLS; for single-use guarantees within
|
|
71
|
+
* the window, layer a verifier-issued nonce.)
|
|
72
|
+
*/
|
|
73
|
+
export function proofMessage(id, sigs, ts, action, nonce = "") {
|
|
74
|
+
return `behalf-pop\n${id}\n${sigs.join(",")}\n${ts}\n${action}\n${nonce}`;
|
|
75
|
+
}
|
|
76
|
+
export function signProof(delegationKey, id, sigs, ts, action, nonce = "") {
|
|
77
|
+
return edSign(null, Buffer.from(proofMessage(id, sigs, ts, action, nonce), "utf8"), delegationKey).toString("base64url");
|
|
78
|
+
}
|
|
79
|
+
export function verifyProof(terminalPub, id, sigs, ts, action, sig, nonce = "") {
|
|
80
|
+
try {
|
|
81
|
+
return edVerify(null, Buffer.from(proofMessage(id, sigs, ts, action, nonce), "utf8"), terminalPub, Buffer.from(sig, "base64url"));
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/** Sign / verify an arbitrary canonical message (used for audit checkpoints). */
|
|
88
|
+
export function signMessage(privateKey, message) {
|
|
89
|
+
return edSign(null, Buffer.from(message, "utf8"), privateKey).toString("base64url");
|
|
90
|
+
}
|
|
91
|
+
export function verifyMessage(publicKey, message, sig) {
|
|
92
|
+
try {
|
|
93
|
+
return edVerify(null, Buffer.from(message, "utf8"), publicKey, Buffer.from(sig, "base64url"));
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export function sha256Hex(data) {
|
|
100
|
+
return createHash("sha256").update(data, "utf8").digest("hex");
|
|
101
|
+
}
|
|
102
|
+
export function newId() {
|
|
103
|
+
return randomUUID();
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Base class for all Behalf errors, so callers can `catch (e instanceof BehalfError)`. */
|
|
2
|
+
export declare class BehalfError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
/** Thrown by `authorize()` when the requested action is not permitted. */
|
|
6
|
+
export declare class AuthorizationError extends BehalfError {
|
|
7
|
+
readonly action: string;
|
|
8
|
+
readonly reason: string;
|
|
9
|
+
constructor(action: string, reason: string);
|
|
10
|
+
}
|
|
11
|
+
/** Thrown by `attenuate()` when a requested capability would widen authority. */
|
|
12
|
+
export declare class WideningError extends BehalfError {
|
|
13
|
+
readonly capability: string;
|
|
14
|
+
constructor(capability: string);
|
|
15
|
+
}
|
|
16
|
+
/** Thrown when a token's signature chain does not verify. */
|
|
17
|
+
export declare class IntegrityError extends BehalfError {
|
|
18
|
+
constructor(message?: string);
|
|
19
|
+
}
|
|
20
|
+
/** Thrown when a capability string cannot be parsed. */
|
|
21
|
+
export declare class CapabilityParseError extends BehalfError {
|
|
22
|
+
readonly capability: string;
|
|
23
|
+
constructor(capability: string, detail: string);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B;AAED,0EAA0E;AAC1E,qBAAa,kBAAmB,SAAQ,WAAW;aAE/B,MAAM,EAAE,MAAM;aACd,MAAM,EAAE,MAAM;gBADd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM;CAIjC;AAED,iFAAiF;AACjF,qBAAa,aAAc,SAAQ,WAAW;aAChB,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAK/C;AAED,6DAA6D;AAC7D,qBAAa,cAAe,SAAQ,WAAW;gBACjC,OAAO,SAAiC;CAGrD;AAED,wDAAwD;AACxD,qBAAa,oBAAqB,SAAQ,WAAW;aACvB,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAG/D"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Base class for all Behalf errors, so callers can `catch (e instanceof BehalfError)`. */
|
|
2
|
+
export class BehalfError extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = new.target.name;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/** Thrown by `authorize()` when the requested action is not permitted. */
|
|
9
|
+
export class AuthorizationError extends BehalfError {
|
|
10
|
+
action;
|
|
11
|
+
reason;
|
|
12
|
+
constructor(action, reason) {
|
|
13
|
+
super(`authorization denied for "${action}": ${reason}`);
|
|
14
|
+
this.action = action;
|
|
15
|
+
this.reason = reason;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Thrown by `attenuate()` when a requested capability would widen authority. */
|
|
19
|
+
export class WideningError extends BehalfError {
|
|
20
|
+
capability;
|
|
21
|
+
constructor(capability) {
|
|
22
|
+
super(`attenuation would widen authority: "${capability}" is not covered by the parent mandate`);
|
|
23
|
+
this.capability = capability;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Thrown when a token's signature chain does not verify. */
|
|
27
|
+
export class IntegrityError extends BehalfError {
|
|
28
|
+
constructor(message = "mandate signature is invalid") {
|
|
29
|
+
super(message);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Thrown when a capability string cannot be parsed. */
|
|
33
|
+
export class CapabilityParseError extends BehalfError {
|
|
34
|
+
capability;
|
|
35
|
+
constructor(capability, detail) {
|
|
36
|
+
super(`invalid capability "${capability}": ${detail}`);
|
|
37
|
+
this.capability = capability;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;IAC9B,CAAC;CACF;AAED,0EAA0E;AAC1E,MAAM,OAAO,kBAAmB,SAAQ,WAAW;IAE/B;IACA;IAFlB,YACkB,MAAc,EACd,MAAc;QAE9B,KAAK,CAAC,6BAA6B,MAAM,MAAM,MAAM,EAAE,CAAC,CAAC;QAHzC,WAAM,GAAN,MAAM,CAAQ;QACd,WAAM,GAAN,MAAM,CAAQ;IAGhC,CAAC;CACF;AAED,iFAAiF;AACjF,MAAM,OAAO,aAAc,SAAQ,WAAW;IAChB;IAA5B,YAA4B,UAAkB;QAC5C,KAAK,CACH,uCAAuC,UAAU,wCAAwC,CAC1F,CAAC;QAHwB,eAAU,GAAV,UAAU,CAAQ;IAI9C,CAAC;CACF;AAED,6DAA6D;AAC7D,MAAM,OAAO,cAAe,SAAQ,WAAW;IAC7C,YAAY,OAAO,GAAG,8BAA8B;QAClD,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;CACF;AAED,wDAAwD;AACxD,MAAM,OAAO,oBAAqB,SAAQ,WAAW;IACvB;IAA5B,YAA4B,UAAkB,EAAE,MAAc;QAC5D,KAAK,CAAC,uBAAuB,UAAU,MAAM,MAAM,EAAE,CAAC,CAAC;QAD7B,eAAU,GAAV,UAAU,CAAQ;IAE9C,CAAC;CACF"}
|