@calimero-network/mero-js 25.0.6 → 25.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/README.md +25 -0
- package/dist/agent-gate/chacha20poly1305.d.ts +20 -0
- package/dist/agent-gate/chacha20poly1305.js +148 -0
- package/dist/agent-gate/gate.d.ts +115 -0
- package/dist/agent-gate/gate.js +232 -0
- package/dist/agent-gate/hpke.d.ts +23 -0
- package/dist/agent-gate/hpke.js +84 -0
- package/dist/agent-gate/index.d.ts +4 -0
- package/dist/agent-gate/index.js +2 -0
- package/dist/agent-gate/policy.d.ts +65 -0
- package/dist/agent-gate/policy.js +103 -0
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +580 -111
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.mjs +580 -111
- package/dist/index.mjs.map +4 -4
- package/dist/mero-js.d.ts +5 -0
- package/dist/mero-js.js +31 -9
- package/dist/token-store/index.js +1 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -48,14 +48,14 @@ function extractErrorMessage(bodyText) {
|
|
|
48
48
|
return void 0;
|
|
49
49
|
}
|
|
50
50
|
var HTTPError = class extends Error {
|
|
51
|
-
constructor(status, statusText,
|
|
51
|
+
constructor(status, statusText, url2, headers, bodyText) {
|
|
52
52
|
const explanation = extractErrorMessage(bodyText) ?? (status === 0 && bodyText?.trim() ? bodyText.trim() : void 0);
|
|
53
53
|
super(
|
|
54
54
|
explanation ? `HTTP ${status} ${statusText}: ${explanation}` : `HTTP ${status} ${statusText}`
|
|
55
55
|
);
|
|
56
56
|
this.status = status;
|
|
57
57
|
this.statusText = statusText;
|
|
58
|
-
this.url =
|
|
58
|
+
this.url = url2;
|
|
59
59
|
this.headers = headers;
|
|
60
60
|
this.bodyText = bodyText;
|
|
61
61
|
this.name = "HTTPError";
|
|
@@ -72,8 +72,8 @@ var HTTPError = class extends Error {
|
|
|
72
72
|
}
|
|
73
73
|
};
|
|
74
74
|
var AuthRevokedError = class extends HTTPError {
|
|
75
|
-
constructor(reason, status, statusText,
|
|
76
|
-
super(status, statusText,
|
|
75
|
+
constructor(reason, status, statusText, url2, headers, bodyText) {
|
|
76
|
+
super(status, statusText, url2, headers, bodyText);
|
|
77
77
|
this.reason = reason;
|
|
78
78
|
this.name = "AuthRevokedError";
|
|
79
79
|
this.message = `Authentication revoked (${reason}): HTTP ${status} ${statusText}`;
|
|
@@ -86,12 +86,12 @@ function headersToRecord(headers) {
|
|
|
86
86
|
});
|
|
87
87
|
return record;
|
|
88
88
|
}
|
|
89
|
-
function pathForProof(
|
|
89
|
+
function pathForProof(url2) {
|
|
90
90
|
try {
|
|
91
|
-
return new URL(
|
|
91
|
+
return new URL(url2).pathname;
|
|
92
92
|
} catch {
|
|
93
|
-
const query =
|
|
94
|
-
return query === -1 ?
|
|
93
|
+
const query = url2.indexOf("?");
|
|
94
|
+
return query === -1 ? url2 : url2.slice(0, query);
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
var WebHttpClient = class {
|
|
@@ -157,7 +157,7 @@ var WebHttpClient = class {
|
|
|
157
157
|
}
|
|
158
158
|
async makeRequest(path, init, retryCount = 0, requestStartTime) {
|
|
159
159
|
const MAX_RETRY_ATTEMPTS = 1;
|
|
160
|
-
const
|
|
160
|
+
const url2 = this.buildUrl(path);
|
|
161
161
|
const startTime = requestStartTime ?? Date.now();
|
|
162
162
|
const signal = this.createAbortSignal(init);
|
|
163
163
|
const headers = await this.buildHeaders(init?.headers);
|
|
@@ -182,7 +182,7 @@ var WebHttpClient = class {
|
|
|
182
182
|
headersObj,
|
|
183
183
|
await this.transport.authorizeRequest({
|
|
184
184
|
method,
|
|
185
|
-
path: new URL(
|
|
185
|
+
path: new URL(url2).pathname,
|
|
186
186
|
// Narrowed by the guard above; `BodyInit` is wider than what can be
|
|
187
187
|
// signed.
|
|
188
188
|
body
|
|
@@ -242,7 +242,7 @@ var WebHttpClient = class {
|
|
|
242
242
|
if (this.transport.getProof) {
|
|
243
243
|
const proof = await this.transport.getProof({
|
|
244
244
|
method: requestInit.method ?? "GET",
|
|
245
|
-
path: pathForProof(
|
|
245
|
+
path: pathForProof(url2),
|
|
246
246
|
body: requestInit.body
|
|
247
247
|
});
|
|
248
248
|
if (proof) {
|
|
@@ -250,13 +250,13 @@ var WebHttpClient = class {
|
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
252
|
try {
|
|
253
|
-
const response = await this.transport.fetch(
|
|
253
|
+
const response = await this.transport.fetch(url2, requestInit);
|
|
254
254
|
if (!response.ok) {
|
|
255
255
|
const bodyText = await this.getBodyText(response);
|
|
256
256
|
const httpError = new HTTPError(
|
|
257
257
|
response.status,
|
|
258
258
|
response.statusText,
|
|
259
|
-
|
|
259
|
+
url2,
|
|
260
260
|
response.headers,
|
|
261
261
|
bodyText
|
|
262
262
|
);
|
|
@@ -274,7 +274,7 @@ var WebHttpClient = class {
|
|
|
274
274
|
authError,
|
|
275
275
|
response.status,
|
|
276
276
|
response.statusText,
|
|
277
|
-
|
|
277
|
+
url2,
|
|
278
278
|
response.headers,
|
|
279
279
|
bodyText
|
|
280
280
|
);
|
|
@@ -339,7 +339,7 @@ var WebHttpClient = class {
|
|
|
339
339
|
throw new HTTPError(
|
|
340
340
|
0,
|
|
341
341
|
"Network Error",
|
|
342
|
-
|
|
342
|
+
url2,
|
|
343
343
|
new Headers(),
|
|
344
344
|
error instanceof Error ? error.message : "Unknown error"
|
|
345
345
|
);
|
|
@@ -442,7 +442,7 @@ function createBrowserHttpClient(options) {
|
|
|
442
442
|
const transport2 = {
|
|
443
443
|
// globalThis.fetch must be called as a method on globalThis, not through a
|
|
444
444
|
// variable, or browsers throw "Illegal invocation".
|
|
445
|
-
fetch: (
|
|
445
|
+
fetch: (url2, init) => options.fetch ? options.fetch(url2, init) : globalThis.fetch(url2, init),
|
|
446
446
|
baseUrl: options.baseUrl,
|
|
447
447
|
getAuthToken: options.getAuthToken,
|
|
448
448
|
getProof: options.getProof,
|
|
@@ -469,7 +469,7 @@ function createNodeHttpClient(options) {
|
|
|
469
469
|
// Wrap fetch in arrow function to prevent "Illegal invocation" error
|
|
470
470
|
// For globalThis.fetch, call it directly to preserve 'this' context
|
|
471
471
|
// For custom implementations, calling through the variable is safe
|
|
472
|
-
fetch: isDefaultFetch ? (
|
|
472
|
+
fetch: isDefaultFetch ? (url2, init) => globalThis.fetch(url2, init) : (url2, init) => fetchImpl(url2, init),
|
|
473
473
|
baseUrl: options.baseUrl,
|
|
474
474
|
getAuthToken: options.getAuthToken,
|
|
475
475
|
getProof: options.getProof,
|
|
@@ -1045,10 +1045,10 @@ function compareSemverId(a, b) {
|
|
|
1045
1045
|
if (nb) return 1;
|
|
1046
1046
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
1047
1047
|
}
|
|
1048
|
-
async function fetchRegistry(
|
|
1048
|
+
async function fetchRegistry(url2, kind, context) {
|
|
1049
1049
|
return withRetry(
|
|
1050
1050
|
async () => {
|
|
1051
|
-
const resp = await fetch(
|
|
1051
|
+
const resp = await fetch(url2, { signal: AbortSignal.timeout(1e4) });
|
|
1052
1052
|
if (!resp.ok) {
|
|
1053
1053
|
const err = new Error(
|
|
1054
1054
|
`registry ${kind} fetch failed (${resp.status}) for ${context}`
|
|
@@ -1100,9 +1100,9 @@ var AdminApiClient = class {
|
|
|
1100
1100
|
* the running `Context.applicationVersion` to detect "a new version exists".
|
|
1101
1101
|
*/
|
|
1102
1102
|
async getRegistryVersions(registryUrl, packageName) {
|
|
1103
|
-
const
|
|
1104
|
-
|
|
1105
|
-
const resp = await fetchRegistry(
|
|
1103
|
+
const url2 = new URL("/api/v2/bundles", new URL(registryUrl).origin);
|
|
1104
|
+
url2.searchParams.set("package", packageName);
|
|
1105
|
+
const resp = await fetchRegistry(url2.toString(), "versions", packageName);
|
|
1106
1106
|
const bundles = await resp.json();
|
|
1107
1107
|
return (Array.isArray(bundles) ? bundles : []).map((b) => b.appVersion).filter((v) => typeof v === "string").sort((a, b) => compareSemver(b, a));
|
|
1108
1108
|
}
|
|
@@ -2420,11 +2420,11 @@ function createAdminApiClientFromHttpClient(httpClient, _config) {
|
|
|
2420
2420
|
}
|
|
2421
2421
|
|
|
2422
2422
|
// src/auth/index.ts
|
|
2423
|
-
function parseAuthCallback(
|
|
2423
|
+
function parseAuthCallback(url2) {
|
|
2424
2424
|
try {
|
|
2425
|
-
const hashIndex =
|
|
2425
|
+
const hashIndex = url2.indexOf("#");
|
|
2426
2426
|
if (hashIndex === -1) return null;
|
|
2427
|
-
const hash =
|
|
2427
|
+
const hash = url2.substring(hashIndex + 1);
|
|
2428
2428
|
const params = new URLSearchParams(hash);
|
|
2429
2429
|
const accessToken = params.get("access_token");
|
|
2430
2430
|
if (!accessToken) return null;
|
|
@@ -2781,7 +2781,7 @@ var SseClient = class {
|
|
|
2781
2781
|
throw new Error("SseClient needs either `getAuthToken` or `authorize`");
|
|
2782
2782
|
}
|
|
2783
2783
|
this.reconnectDelayMs = opts.reconnectDelayMs ?? 3e3;
|
|
2784
|
-
this.fetchImpl = (
|
|
2784
|
+
this.fetchImpl = (url2, init) => opts.fetch ? opts.fetch(url2, init) : globalThis.fetch(url2, init);
|
|
2785
2785
|
}
|
|
2786
2786
|
on(event, handler) {
|
|
2787
2787
|
const key = event;
|
|
@@ -2846,10 +2846,10 @@ var SseClient = class {
|
|
|
2846
2846
|
this.closed = false;
|
|
2847
2847
|
this.abortController = new AbortController();
|
|
2848
2848
|
try {
|
|
2849
|
-
const
|
|
2850
|
-
const response = await this.fetchImpl(
|
|
2849
|
+
const url2 = `${this.baseUrl}/sse`;
|
|
2850
|
+
const response = await this.fetchImpl(url2, {
|
|
2851
2851
|
headers: {
|
|
2852
|
-
...await this.authorize({ method: "GET", path: new URL(
|
|
2852
|
+
...await this.authorize({ method: "GET", path: new URL(url2).pathname }),
|
|
2853
2853
|
"Accept": "text/event-stream"
|
|
2854
2854
|
},
|
|
2855
2855
|
signal: this.abortController.signal
|
|
@@ -2862,7 +2862,7 @@ var SseClient = class {
|
|
|
2862
2862
|
terminal,
|
|
2863
2863
|
response.status,
|
|
2864
2864
|
response.statusText,
|
|
2865
|
-
|
|
2865
|
+
url2,
|
|
2866
2866
|
response.headers,
|
|
2867
2867
|
bodyText
|
|
2868
2868
|
);
|
|
@@ -2870,7 +2870,7 @@ var SseClient = class {
|
|
|
2870
2870
|
throw new HTTPError(
|
|
2871
2871
|
response.status,
|
|
2872
2872
|
response.statusText,
|
|
2873
|
-
|
|
2873
|
+
url2,
|
|
2874
2874
|
response.headers,
|
|
2875
2875
|
bodyText
|
|
2876
2876
|
);
|
|
@@ -3049,12 +3049,12 @@ var SseClient = class {
|
|
|
3049
3049
|
const params = {};
|
|
3050
3050
|
if (ids.contextIds && ids.contextIds.length > 0) params.contextIds = ids.contextIds;
|
|
3051
3051
|
if (ids.groupIds && ids.groupIds.length > 0) params.groupIds = ids.groupIds;
|
|
3052
|
-
const
|
|
3052
|
+
const url2 = `${this.baseUrl}/sse/subscription`;
|
|
3053
3053
|
const body = JSON.stringify({ id: this.sessionId, method, params });
|
|
3054
|
-
const response = await this.fetchImpl(
|
|
3054
|
+
const response = await this.fetchImpl(url2, {
|
|
3055
3055
|
method: "POST",
|
|
3056
3056
|
headers: {
|
|
3057
|
-
...await this.authorize({ method: "POST", path: new URL(
|
|
3057
|
+
...await this.authorize({ method: "POST", path: new URL(url2).pathname, body }),
|
|
3058
3058
|
"Content-Type": "application/json"
|
|
3059
3059
|
},
|
|
3060
3060
|
body,
|
|
@@ -5965,14 +5965,14 @@ function reportDataOf(quote) {
|
|
|
5965
5965
|
}
|
|
5966
5966
|
async function attestRelayNodeKey(opts) {
|
|
5967
5967
|
const nonce2 = crypto.getRandomValues(new Uint8Array(32));
|
|
5968
|
-
const
|
|
5968
|
+
const url2 = `${opts.relayUrl.replace(/\/+$/, "")}/admin-api/tee/attest`;
|
|
5969
5969
|
const body = JSON.stringify({
|
|
5970
5970
|
nonce: hex(nonce2),
|
|
5971
5971
|
bindNodeKey: true,
|
|
5972
5972
|
...opts.verify?.includeCollateral ? { includeCollateral: true } : {}
|
|
5973
5973
|
});
|
|
5974
5974
|
const init = { method: "POST", headers: { "Content-Type": "application/json" }, body };
|
|
5975
|
-
const response = opts.fetch ? await opts.fetch(
|
|
5975
|
+
const response = opts.fetch ? await opts.fetch(url2, init) : await globalThis.fetch(url2, init);
|
|
5976
5976
|
if (!response.ok) {
|
|
5977
5977
|
const text = await response.text().catch(() => "");
|
|
5978
5978
|
throw new Error(`the relay would not attest (HTTP ${response.status})${text ? `: ${text}` : ""}`);
|
|
@@ -6294,13 +6294,13 @@ function createSealedFetch(options) {
|
|
|
6294
6294
|
};
|
|
6295
6295
|
return async (input, init) => {
|
|
6296
6296
|
const request = new Request(input, init);
|
|
6297
|
-
const
|
|
6298
|
-
if (
|
|
6299
|
-
throw new Error(`Refusing to send ${
|
|
6297
|
+
const url2 = new URL(request.url);
|
|
6298
|
+
if (url2.origin !== base.origin || !url2.pathname.startsWith(`${basePath}/`)) {
|
|
6299
|
+
throw new Error(`Refusing to send ${url2.href} outside the sealed node at ${options.baseUrl}`);
|
|
6300
6300
|
}
|
|
6301
6301
|
const headers = [];
|
|
6302
6302
|
request.headers.forEach((value, name) => headers.push([name, value]));
|
|
6303
|
-
const head = { method: request.method, path:
|
|
6303
|
+
const head = { method: request.method, path: url2.pathname.slice(basePath.length) + url2.search, headers };
|
|
6304
6304
|
const body = new Uint8Array(await request.arrayBuffer());
|
|
6305
6305
|
const send = async (open2) => {
|
|
6306
6306
|
const { requestId, header, envelope } = await sealRequest(open2, head, body);
|
|
@@ -6522,7 +6522,7 @@ function createQuoteVerifier(options) {
|
|
|
6522
6522
|
const allowedMrtd = measurements(options.allowedMrtd ?? [], "allowedMrtd");
|
|
6523
6523
|
const allowedImages = (options.allowedMeasurements ?? []).map((image, index) => {
|
|
6524
6524
|
const label2 = `allowedMeasurements[${index}]`;
|
|
6525
|
-
return REGISTERS.map((
|
|
6525
|
+
return REGISTERS.map((register2) => measurements([image?.[register2] ?? ""], `${label2}.${register2}`)[0]).join();
|
|
6526
6526
|
});
|
|
6527
6527
|
const allowedRtmr = [
|
|
6528
6528
|
measurements(options.allowedRtmr0 ?? [], "allowedRtmr0"),
|
|
@@ -6571,7 +6571,7 @@ function createQuoteVerifier(options) {
|
|
|
6571
6571
|
if (td.tdAttributes?.length !== 8 || (td.tdAttributes[0] & 1) !== 0) {
|
|
6572
6572
|
throw new Error("The quote is from a debug TD, or its TD attributes cannot be read");
|
|
6573
6573
|
}
|
|
6574
|
-
const measured = [td.mrTd, td.rtMr0, td.rtMr1, td.rtMr2, td.rtMr3].map((
|
|
6574
|
+
const measured = [td.mrTd, td.rtMr0, td.rtMr1, td.rtMr2, td.rtMr3].map((register2) => hex(register2));
|
|
6575
6575
|
if (allowedImages.length > 0 && !allowedImages.includes(measured.join())) {
|
|
6576
6576
|
throw new Error(
|
|
6577
6577
|
`The measurements (MRTD ${measured[0]}, RTMR0-3 ${measured.slice(1).join(", ")}) are not an image this verifier trusts`
|
|
@@ -6581,10 +6581,10 @@ function createQuoteVerifier(options) {
|
|
|
6581
6581
|
throw new Error(`MRTD ${measured[0]} is not an image this verifier trusts`);
|
|
6582
6582
|
}
|
|
6583
6583
|
const registers = [td.rtMr0, td.rtMr1, td.rtMr2, td.rtMr3];
|
|
6584
|
-
registers.forEach((
|
|
6584
|
+
registers.forEach((register2, index) => {
|
|
6585
6585
|
const allowed = allowedRtmr[index];
|
|
6586
|
-
if (allowed.length > 0 && !allowed.includes(hex(
|
|
6587
|
-
throw new Error(`RTMR${index} ${hex(
|
|
6586
|
+
if (allowed.length > 0 && !allowed.includes(hex(register2))) {
|
|
6587
|
+
throw new Error(`RTMR${index} ${hex(register2)} is not one this verifier trusts`);
|
|
6588
6588
|
}
|
|
6589
6589
|
});
|
|
6590
6590
|
if (hex(td.reportData) !== `${nonce2}${reportDataSuffix}`.toLowerCase()) {
|
|
@@ -7061,7 +7061,7 @@ async function verifySignedNodeRelease(publishedMrtds, bundle, options = {}) {
|
|
|
7061
7061
|
throw new Error(`The signed release is a ${JSON.stringify(release?.role)} release, not a node one`);
|
|
7062
7062
|
}
|
|
7063
7063
|
const profiles = Object.values(release.profiles ?? {});
|
|
7064
|
-
const measured = (image) => MEASUREMENTS.every((
|
|
7064
|
+
const measured = (image) => MEASUREMENTS.every((register2) => /^[0-9a-f]{96}$/i.test(String(image?.[register2])));
|
|
7065
7065
|
if (typeof release.tag !== "string" || profiles.length === 0 || !profiles.every(measured)) {
|
|
7066
7066
|
throw new Error("The signed file is not a release's published-mrtds.json: it lists no measured profiles");
|
|
7067
7067
|
}
|
|
@@ -7070,17 +7070,17 @@ async function verifySignedNodeRelease(publishedMrtds, bundle, options = {}) {
|
|
|
7070
7070
|
}
|
|
7071
7071
|
return release;
|
|
7072
7072
|
}
|
|
7073
|
-
async function fetchNodeRelease(
|
|
7074
|
-
const response = await (options.fetch ?? fetch)(
|
|
7075
|
-
if (!response.ok) throw new Error(`Fetching the node release from ${
|
|
7073
|
+
async function fetchNodeRelease(url2, options = {}) {
|
|
7074
|
+
const response = await (options.fetch ?? fetch)(url2, { headers: { accept: "application/json" } });
|
|
7075
|
+
if (!response.ok) throw new Error(`Fetching the node release from ${url2} failed: HTTP ${response.status}`);
|
|
7076
7076
|
let release;
|
|
7077
7077
|
try {
|
|
7078
7078
|
release = (await response.json())?.data;
|
|
7079
7079
|
} catch {
|
|
7080
|
-
throw new Error(`${
|
|
7080
|
+
throw new Error(`${url2} did not answer with JSON`);
|
|
7081
7081
|
}
|
|
7082
7082
|
if (typeof release?.version !== "string" || typeof release.publishedMrtds !== "string" || typeof release.bundle !== "string") {
|
|
7083
|
-
throw new Error(`${
|
|
7083
|
+
throw new Error(`${url2} did not answer with a signed node release`);
|
|
7084
7084
|
}
|
|
7085
7085
|
return { version: release.version, publishedMrtds: release.publishedMrtds, bundle: release.bundle };
|
|
7086
7086
|
}
|
|
@@ -7102,20 +7102,20 @@ function infoUrl(baseUrl) {
|
|
|
7102
7102
|
return `${baseUrl.replace(/\/+$/, "")}/admin-api/tee/info`;
|
|
7103
7103
|
}
|
|
7104
7104
|
async function readNodeReleaseVersion(baseUrl, givenFetch) {
|
|
7105
|
-
const
|
|
7106
|
-
const response = await givenFetch(
|
|
7105
|
+
const url2 = infoUrl(baseUrl);
|
|
7106
|
+
const response = await givenFetch(url2, { headers: { accept: "application/json" } });
|
|
7107
7107
|
if (response.status === 403) {
|
|
7108
7108
|
const code = await response.json().then((body) => body?.error?.code).catch(() => void 0);
|
|
7109
7109
|
if (code === "sealed_required") return void 0;
|
|
7110
7110
|
}
|
|
7111
|
-
if (!response.ok) throw new Error(`Fetching ${
|
|
7111
|
+
if (!response.ok) throw new Error(`Fetching ${url2} failed: HTTP ${response.status}`);
|
|
7112
7112
|
let osImage;
|
|
7113
7113
|
try {
|
|
7114
7114
|
osImage = (await response.json())?.data?.osImage;
|
|
7115
7115
|
} catch {
|
|
7116
|
-
throw new Error(`${
|
|
7116
|
+
throw new Error(`${url2} did not answer with JSON`);
|
|
7117
7117
|
}
|
|
7118
|
-
if (typeof osImage !== "string") throw new Error(`${
|
|
7118
|
+
if (typeof osImage !== "string") throw new Error(`${url2} did not name the node's image`);
|
|
7119
7119
|
return nodeReleaseVersionFromImage(osImage);
|
|
7120
7120
|
}
|
|
7121
7121
|
function cloudNodeReleaseUrl(cloudUrl, version) {
|
|
@@ -8725,8 +8725,8 @@ function createProofAuthorizer(credential) {
|
|
|
8725
8725
|
return { [REQUEST_PROOF_HEADER]: proof };
|
|
8726
8726
|
};
|
|
8727
8727
|
}
|
|
8728
|
-
function signedPath(
|
|
8729
|
-
return new URL(
|
|
8728
|
+
function signedPath(url2) {
|
|
8729
|
+
return new URL(url2).pathname;
|
|
8730
8730
|
}
|
|
8731
8731
|
|
|
8732
8732
|
// src/presence/statement.ts
|
|
@@ -8913,7 +8913,7 @@ var MeroClient = class {
|
|
|
8913
8913
|
const authorizeRequest = this.proofAuthorizer;
|
|
8914
8914
|
this.relayAdmin = createAdminApiClientFromHttpClient(
|
|
8915
8915
|
createHttpClient({
|
|
8916
|
-
fetch: (
|
|
8916
|
+
fetch: (url2, init) => fetchImpl ? fetchImpl(url2, init) : globalThis.fetch(url2, init),
|
|
8917
8917
|
baseUrl: relay.relayUrl,
|
|
8918
8918
|
authorizeRequest
|
|
8919
8919
|
}),
|
|
@@ -9556,9 +9556,9 @@ function writeRelayMap(account, map) {
|
|
|
9556
9556
|
}
|
|
9557
9557
|
function rememberRelay(account, relayUrl, at) {
|
|
9558
9558
|
const map = readRelayMap(account);
|
|
9559
|
-
const
|
|
9560
|
-
if (at.namespaceId) map.namespaces[at.namespaceId] =
|
|
9561
|
-
if (at.contextId) map.contexts[at.contextId] =
|
|
9559
|
+
const url2 = relayOrigin(relayUrl);
|
|
9560
|
+
if (at.namespaceId) map.namespaces[at.namespaceId] = url2;
|
|
9561
|
+
if (at.contextId) map.contexts[at.contextId] = url2;
|
|
9562
9562
|
writeRelayMap(account, map);
|
|
9563
9563
|
}
|
|
9564
9564
|
function relayForContext(account, contextId) {
|
|
@@ -9941,7 +9941,7 @@ function beginLinkState(account, returnTo) {
|
|
|
9941
9941
|
if (!ACCOUNT_HEX.test(account)) {
|
|
9942
9942
|
throw new Error("accountId must be 64 lowercase hex characters");
|
|
9943
9943
|
}
|
|
9944
|
-
const
|
|
9944
|
+
const url2 = new URL(returnTo);
|
|
9945
9945
|
const now = Date.now();
|
|
9946
9946
|
const pending = readPending(now);
|
|
9947
9947
|
const bytes = crypto.getRandomValues(new Uint8Array(16));
|
|
@@ -9950,8 +9950,8 @@ function beginLinkState(account, returnTo) {
|
|
|
9950
9950
|
);
|
|
9951
9951
|
pending[state] = { account, expiresAt: now + LIFETIME_MS };
|
|
9952
9952
|
writePending(Object.fromEntries(Object.entries(pending).slice(-MAX_PENDING)));
|
|
9953
|
-
|
|
9954
|
-
return
|
|
9953
|
+
url2.searchParams.set(STATE_PARAM, state);
|
|
9954
|
+
return url2.toString();
|
|
9955
9955
|
}
|
|
9956
9956
|
function takeLinkState(search) {
|
|
9957
9957
|
const state = new URLSearchParams(search).get(STATE_PARAM);
|
|
@@ -9973,10 +9973,10 @@ function withoutLinkState(search) {
|
|
|
9973
9973
|
// src/cloud/link-redirect.ts
|
|
9974
9974
|
var DEFAULT_CLOUD_WEB_URL = "https://cloud.calimero.network";
|
|
9975
9975
|
function cloudLinkUrl(options) {
|
|
9976
|
-
const
|
|
9977
|
-
|
|
9978
|
-
|
|
9979
|
-
return
|
|
9976
|
+
const url2 = new URL(options.cloudWebUrl ?? DEFAULT_CLOUD_WEB_URL);
|
|
9977
|
+
url2.searchParams.set("link-account", options.accountId);
|
|
9978
|
+
url2.searchParams.set("callback-url", beginLinkState(options.accountId, options.returnTo));
|
|
9979
|
+
return url2.toString();
|
|
9980
9980
|
}
|
|
9981
9981
|
function beginCloudLink(options) {
|
|
9982
9982
|
window.location.assign(cloudLinkUrl(options));
|
|
@@ -10032,12 +10032,12 @@ function deviceEnrolmentUrl(options) {
|
|
|
10032
10032
|
assertHex(options.kemPublicKey, "kemPublicKey");
|
|
10033
10033
|
assertSafeReturnTo(options.returnTo);
|
|
10034
10034
|
warnOnForeignCallback(options.returnTo);
|
|
10035
|
-
const
|
|
10036
|
-
|
|
10037
|
-
|
|
10038
|
-
|
|
10039
|
-
if (options.state)
|
|
10040
|
-
return
|
|
10035
|
+
const url2 = new URL(options.walletUrl);
|
|
10036
|
+
url2.searchParams.set(DEVICE_PARAM, options.devicePublicKey);
|
|
10037
|
+
url2.searchParams.set(KEM_PARAM, options.kemPublicKey);
|
|
10038
|
+
url2.searchParams.set(CALLBACK_PARAM, options.returnTo);
|
|
10039
|
+
if (options.state) url2.searchParams.set(STATE_PARAM2, options.state);
|
|
10040
|
+
return url2.toString();
|
|
10041
10041
|
}
|
|
10042
10042
|
function beginDeviceEnrolment(options) {
|
|
10043
10043
|
window.location.assign(deviceEnrolmentUrl(options));
|
|
@@ -10122,17 +10122,17 @@ function warnOnForeignCallback(returnTo) {
|
|
|
10122
10122
|
);
|
|
10123
10123
|
}
|
|
10124
10124
|
function assertSafeReturnTo(returnTo) {
|
|
10125
|
-
let
|
|
10125
|
+
let url2;
|
|
10126
10126
|
try {
|
|
10127
|
-
|
|
10127
|
+
url2 = new URL(returnTo);
|
|
10128
10128
|
} catch {
|
|
10129
10129
|
throw new Error(`returnTo must be an absolute URL, got ${returnTo}`);
|
|
10130
10130
|
}
|
|
10131
|
-
const loopback =
|
|
10132
|
-
if (
|
|
10133
|
-
if (
|
|
10131
|
+
const loopback = url2.hostname === "localhost" || url2.hostname === "127.0.0.1" || url2.hostname === "[::1]" || url2.hostname === "::1";
|
|
10132
|
+
if (url2.protocol === "https:") return;
|
|
10133
|
+
if (url2.protocol === "http:" && loopback) return;
|
|
10134
10134
|
throw new Error(
|
|
10135
|
-
`returnTo must be https:, or http: on localhost \u2014 got ${
|
|
10135
|
+
`returnTo must be https:, or http: on localhost \u2014 got ${url2.protocol}//${url2.hostname}`
|
|
10136
10136
|
);
|
|
10137
10137
|
}
|
|
10138
10138
|
|
|
@@ -10419,8 +10419,8 @@ function joinNonce(account) {
|
|
|
10419
10419
|
const source = createLocalStorageNonceSource(`calimero.delegated.joinnonce.${account}`);
|
|
10420
10420
|
return () => source.next();
|
|
10421
10421
|
}
|
|
10422
|
-
function origin(
|
|
10423
|
-
return
|
|
10422
|
+
function origin(url2) {
|
|
10423
|
+
return url2.replace(/\/+$/, "");
|
|
10424
10424
|
}
|
|
10425
10425
|
async function joinWithNode(input) {
|
|
10426
10426
|
const { account, credential, deviceSecret } = input.credential;
|
|
@@ -10442,11 +10442,11 @@ async function joinWithNode(input) {
|
|
|
10442
10442
|
};
|
|
10443
10443
|
}
|
|
10444
10444
|
const body = { invitation: input.invitation, signedOp };
|
|
10445
|
-
const
|
|
10445
|
+
const url2 = input.admitUrl ?? `${origin(input.nodeUrl)}/admin-api/namespaces/${pathSegment(input.namespaceId)}/admit`;
|
|
10446
10446
|
const doFetch = input.deps?.fetch ?? fetch;
|
|
10447
10447
|
let response;
|
|
10448
10448
|
try {
|
|
10449
|
-
response = await doFetch(
|
|
10449
|
+
response = await doFetch(url2, {
|
|
10450
10450
|
method: "POST",
|
|
10451
10451
|
// No Authorization header and no request proof, deliberately: the route is
|
|
10452
10452
|
// unauthenticated because the joiner's signature is the authorization.
|
|
@@ -10569,8 +10569,8 @@ function selectLatestBundle(bundles) {
|
|
|
10569
10569
|
);
|
|
10570
10570
|
}
|
|
10571
10571
|
async function fetchRegistryBundles(registryUrl, pkg, fetchFn = globalThis.fetch) {
|
|
10572
|
-
const
|
|
10573
|
-
const response = await fetchFn(
|
|
10572
|
+
const url2 = `${registryUrl.replace(/\/+$/, "")}/api/v2/bundles?package=${encodeURIComponent(pkg)}`;
|
|
10573
|
+
const response = await fetchFn(url2, { headers: { Accept: "application/json" } });
|
|
10574
10574
|
if (!response.ok) throw new Error(`the registry has no ${pkg} (HTTP ${response.status})`);
|
|
10575
10575
|
const body = await response.json();
|
|
10576
10576
|
return Array.isArray(body) ? body : [];
|
|
@@ -10610,9 +10610,9 @@ function nextGovernanceNonce(relay, group) {
|
|
|
10610
10610
|
return next;
|
|
10611
10611
|
}
|
|
10612
10612
|
function relayFor(s, namespaceId) {
|
|
10613
|
-
const
|
|
10614
|
-
if (!
|
|
10615
|
-
return
|
|
10613
|
+
const url2 = readRelayMap(s.account).namespaces[namespaceId] ?? s.relayUrl;
|
|
10614
|
+
if (!url2) throw new Error("no relay is known for this namespace, so there is nowhere to send this");
|
|
10615
|
+
return url2.replace(/\/+$/, "");
|
|
10616
10616
|
}
|
|
10617
10617
|
function initArgsOf(params) {
|
|
10618
10618
|
if (!params || params.length === 0) return {};
|
|
@@ -10695,7 +10695,7 @@ async function foundingExecutor(s, relay, fetch2) {
|
|
|
10695
10695
|
const named = s.executorAccount && s.relayUrl?.replace(/\/+$/, "") === relay ? s.executorAccount : null;
|
|
10696
10696
|
if (named) return { executorAccount: named, executorKey: await attestedNodeKey(relay) };
|
|
10697
10697
|
const known = Object.entries(readRelayMap(s.account).namespaces).find(
|
|
10698
|
-
([,
|
|
10698
|
+
([, url2]) => url2.replace(/\/+$/, "") === relay
|
|
10699
10699
|
)?.[0];
|
|
10700
10700
|
if (!known) {
|
|
10701
10701
|
throw new Error(
|
|
@@ -11142,8 +11142,8 @@ function accountHexOrNull(value) {
|
|
|
11142
11142
|
return typeof value === "string" && ACCOUNT_HEX.test(value) ? value : null;
|
|
11143
11143
|
}
|
|
11144
11144
|
var AccountHaRefusedError = class extends HTTPError {
|
|
11145
|
-
constructor(code, status, statusText,
|
|
11146
|
-
super(status, statusText,
|
|
11145
|
+
constructor(code, status, statusText, url2, headers, bodyText) {
|
|
11146
|
+
super(status, statusText, url2, headers, bodyText);
|
|
11147
11147
|
this.code = code;
|
|
11148
11148
|
this.name = "AccountHaRefusedError";
|
|
11149
11149
|
}
|
|
@@ -12077,6 +12077,14 @@ function getLockManager() {
|
|
|
12077
12077
|
const locks = nav?.locks;
|
|
12078
12078
|
return locks && typeof locks.request === "function" ? locks : null;
|
|
12079
12079
|
}
|
|
12080
|
+
function nodeKeyOf(baseUrl) {
|
|
12081
|
+
try {
|
|
12082
|
+
const { origin: origin2, pathname } = new URL(baseUrl);
|
|
12083
|
+
return origin2 === "null" ? baseUrl : origin2 + pathname.replace(/\/+$/, "");
|
|
12084
|
+
} catch {
|
|
12085
|
+
return baseUrl;
|
|
12086
|
+
}
|
|
12087
|
+
}
|
|
12080
12088
|
function expiresAtFromJwt(token, fallbackMs) {
|
|
12081
12089
|
try {
|
|
12082
12090
|
const parts = token.split(".");
|
|
@@ -12112,8 +12120,9 @@ var MeroJs = class {
|
|
|
12112
12120
|
...config
|
|
12113
12121
|
};
|
|
12114
12122
|
this.tokenStore = config.tokenStore ?? null;
|
|
12123
|
+
this.nodeKey = nodeKeyOf(config.baseUrl);
|
|
12124
|
+
this.tokenData = this.readStoredTokens();
|
|
12115
12125
|
if (this.tokenStore) {
|
|
12116
|
-
this.tokenData = this.tokenStore.getTokens();
|
|
12117
12126
|
this.storeHoldsTokens = this.tokenData !== null;
|
|
12118
12127
|
if (typeof window !== "undefined") window.addEventListener("storage", this.onStorage);
|
|
12119
12128
|
}
|
|
@@ -12134,7 +12143,7 @@ var MeroJs = class {
|
|
|
12134
12143
|
onTokenRefresh: async (newToken) => {
|
|
12135
12144
|
if (this.tokenData) {
|
|
12136
12145
|
this.tokenData.access_token = newToken;
|
|
12137
|
-
this.persistTokens(
|
|
12146
|
+
this.persistTokens();
|
|
12138
12147
|
}
|
|
12139
12148
|
},
|
|
12140
12149
|
onAuthRevoked: async () => {
|
|
@@ -12280,7 +12289,7 @@ var MeroJs = class {
|
|
|
12280
12289
|
refresh_token: response.data.refresh_token,
|
|
12281
12290
|
expires_at: expiresAtFromJwt(accessToken, Date.now() + 36e5)
|
|
12282
12291
|
};
|
|
12283
|
-
this.persistTokens(
|
|
12292
|
+
this.persistTokens();
|
|
12284
12293
|
return this.tokenData;
|
|
12285
12294
|
} catch (error) {
|
|
12286
12295
|
throw new Error(
|
|
@@ -12288,11 +12297,21 @@ var MeroJs = class {
|
|
|
12288
12297
|
);
|
|
12289
12298
|
}
|
|
12290
12299
|
}
|
|
12291
|
-
persistTokens(
|
|
12292
|
-
if (!this.tokenStore) return;
|
|
12293
|
-
this.tokenStore.setTokens(
|
|
12300
|
+
persistTokens() {
|
|
12301
|
+
if (!this.tokenStore || !this.tokenData) return;
|
|
12302
|
+
this.tokenStore.setTokens({ ...this.tokenData, node_origin: this.nodeKey });
|
|
12294
12303
|
this.storeHoldsTokens = this.tokenStore.getTokens() !== null;
|
|
12295
12304
|
}
|
|
12305
|
+
/** The stored bundle, only if this node issued it; a legacy or foreign entry reads as empty. */
|
|
12306
|
+
readStoredTokens() {
|
|
12307
|
+
const stored = this.tokenStore?.getTokens();
|
|
12308
|
+
if (!stored || stored.node_origin !== this.nodeKey) return null;
|
|
12309
|
+
return {
|
|
12310
|
+
access_token: stored.access_token,
|
|
12311
|
+
refresh_token: stored.refresh_token,
|
|
12312
|
+
expires_at: stored.expires_at
|
|
12313
|
+
};
|
|
12314
|
+
}
|
|
12296
12315
|
// Raw store read: an empty store is a logout, another node's bundle is not.
|
|
12297
12316
|
signedOutElsewhere() {
|
|
12298
12317
|
return this.storeHoldsTokens && !this.tokenStore?.getTokens();
|
|
@@ -12360,7 +12379,7 @@ var MeroJs = class {
|
|
|
12360
12379
|
this.dropLocalTokens();
|
|
12361
12380
|
throw new Error("Signed out in another tab");
|
|
12362
12381
|
}
|
|
12363
|
-
const stored = this.
|
|
12382
|
+
const stored = this.readStoredTokens();
|
|
12364
12383
|
if (stored?.refresh_token) {
|
|
12365
12384
|
this.storeHoldsTokens = true;
|
|
12366
12385
|
this.tokenData = stored;
|
|
@@ -12393,7 +12412,7 @@ var MeroJs = class {
|
|
|
12393
12412
|
refresh_token: response.data.refresh_token,
|
|
12394
12413
|
expires_at: expiresAtFromJwt(accessToken, Date.now() + 36e5)
|
|
12395
12414
|
};
|
|
12396
|
-
this.persistTokens(
|
|
12415
|
+
this.persistTokens();
|
|
12397
12416
|
return this.tokenData;
|
|
12398
12417
|
} catch (error) {
|
|
12399
12418
|
throw new Error(
|
|
@@ -12422,7 +12441,7 @@ var MeroJs = class {
|
|
|
12422
12441
|
setTokenData(data) {
|
|
12423
12442
|
const expiresAt = data.expires_at || expiresAtFromJwt(data.access_token, Date.now() + 36e5);
|
|
12424
12443
|
this.tokenData = { ...data, expires_at: expiresAt };
|
|
12425
|
-
this.persistTokens(
|
|
12444
|
+
this.persistTokens();
|
|
12426
12445
|
}
|
|
12427
12446
|
/**
|
|
12428
12447
|
* Get the current token data (for debugging)
|
|
@@ -12441,8 +12460,8 @@ var MeroJs = class {
|
|
|
12441
12460
|
/**
|
|
12442
12461
|
* Parse an auth callback URL hash fragment (static utility)
|
|
12443
12462
|
*/
|
|
12444
|
-
static parseAuthCallback(
|
|
12445
|
-
return parseAuthCallback(
|
|
12463
|
+
static parseAuthCallback(url2) {
|
|
12464
|
+
return parseAuthCallback(url2);
|
|
12446
12465
|
}
|
|
12447
12466
|
/**
|
|
12448
12467
|
* Build an auth login URL (static utility)
|
|
@@ -12485,7 +12504,8 @@ var LocalStorageTokenStore = class {
|
|
|
12485
12504
|
return {
|
|
12486
12505
|
access_token: parsed.access_token,
|
|
12487
12506
|
refresh_token: parsed.refresh_token,
|
|
12488
|
-
expires_at: typeof parsed.expires_at === "number" ? parsed.expires_at : Date.now() + 36e5
|
|
12507
|
+
expires_at: typeof parsed.expires_at === "number" ? parsed.expires_at : Date.now() + 36e5,
|
|
12508
|
+
...typeof parsed.node_origin === "string" && { node_origin: parsed.node_origin }
|
|
12489
12509
|
};
|
|
12490
12510
|
}
|
|
12491
12511
|
return null;
|
|
@@ -12706,8 +12726,8 @@ async function probeNodeHealth(baseUrl, options = {}) {
|
|
|
12706
12726
|
if (abortSignal) abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
12707
12727
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
12708
12728
|
try {
|
|
12709
|
-
const
|
|
12710
|
-
const res = await fetch(
|
|
12729
|
+
const url2 = nodeEndpoint(baseUrl, "admin-api/health");
|
|
12730
|
+
const res = await fetch(url2, {
|
|
12711
12731
|
method: "GET",
|
|
12712
12732
|
signal: controller.signal
|
|
12713
12733
|
});
|
|
@@ -12731,20 +12751,457 @@ async function discoverLocalNodes(options = {}) {
|
|
|
12731
12751
|
const { ports = DEFAULT_LOCAL_NODE_PORTS, timeoutMs, signal } = options;
|
|
12732
12752
|
const results = await Promise.all(
|
|
12733
12753
|
ports.map(async (port) => {
|
|
12734
|
-
const
|
|
12735
|
-
const ok = await probeNodeHealth(
|
|
12736
|
-
return ok ?
|
|
12754
|
+
const url2 = localNodeUrl(port);
|
|
12755
|
+
const ok = await probeNodeHealth(url2, { timeoutMs, signal });
|
|
12756
|
+
return ok ? url2 : null;
|
|
12737
12757
|
})
|
|
12738
12758
|
);
|
|
12739
|
-
return results.filter((
|
|
12759
|
+
return results.filter((url2) => url2 !== null);
|
|
12760
|
+
}
|
|
12761
|
+
|
|
12762
|
+
// src/agent-gate/chacha20poly1305.ts
|
|
12763
|
+
var KEY_LEN = 32;
|
|
12764
|
+
var NONCE_LEN = 12;
|
|
12765
|
+
var TAG_LEN2 = 16;
|
|
12766
|
+
function rotl(value, shift) {
|
|
12767
|
+
return (value << shift | value >>> 32 - shift) >>> 0;
|
|
12768
|
+
}
|
|
12769
|
+
function quarterRound(s, a, b, c, d) {
|
|
12770
|
+
s[a] = s[a] + s[b] >>> 0;
|
|
12771
|
+
s[d] = rotl(s[d] ^ s[a], 16);
|
|
12772
|
+
s[c] = s[c] + s[d] >>> 0;
|
|
12773
|
+
s[b] = rotl(s[b] ^ s[c], 12);
|
|
12774
|
+
s[a] = s[a] + s[b] >>> 0;
|
|
12775
|
+
s[d] = rotl(s[d] ^ s[a], 8);
|
|
12776
|
+
s[c] = s[c] + s[d] >>> 0;
|
|
12777
|
+
s[b] = rotl(s[b] ^ s[c], 7);
|
|
12778
|
+
}
|
|
12779
|
+
function u32le2(bytes, offset) {
|
|
12780
|
+
return (bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24) >>> 0;
|
|
12781
|
+
}
|
|
12782
|
+
function chacha20Block(key, counter, nonce2) {
|
|
12783
|
+
const state = new Uint32Array(16);
|
|
12784
|
+
state[0] = 1634760805;
|
|
12785
|
+
state[1] = 857760878;
|
|
12786
|
+
state[2] = 2036477234;
|
|
12787
|
+
state[3] = 1797285236;
|
|
12788
|
+
for (let i = 0; i < 8; i += 1) state[4 + i] = u32le2(key, i * 4);
|
|
12789
|
+
state[12] = counter >>> 0;
|
|
12790
|
+
for (let i = 0; i < 3; i += 1) state[13 + i] = u32le2(nonce2, i * 4);
|
|
12791
|
+
const working = state.slice();
|
|
12792
|
+
for (let round = 0; round < 10; round += 1) {
|
|
12793
|
+
quarterRound(working, 0, 4, 8, 12);
|
|
12794
|
+
quarterRound(working, 1, 5, 9, 13);
|
|
12795
|
+
quarterRound(working, 2, 6, 10, 14);
|
|
12796
|
+
quarterRound(working, 3, 7, 11, 15);
|
|
12797
|
+
quarterRound(working, 0, 5, 10, 15);
|
|
12798
|
+
quarterRound(working, 1, 6, 11, 12);
|
|
12799
|
+
quarterRound(working, 2, 7, 8, 13);
|
|
12800
|
+
quarterRound(working, 3, 4, 9, 14);
|
|
12801
|
+
}
|
|
12802
|
+
const out = new Uint8Array(64);
|
|
12803
|
+
for (let i = 0; i < 16; i += 1) {
|
|
12804
|
+
const word = working[i] + state[i] >>> 0;
|
|
12805
|
+
out[i * 4] = word & 255;
|
|
12806
|
+
out[i * 4 + 1] = word >>> 8 & 255;
|
|
12807
|
+
out[i * 4 + 2] = word >>> 16 & 255;
|
|
12808
|
+
out[i * 4 + 3] = word >>> 24 & 255;
|
|
12809
|
+
}
|
|
12810
|
+
return out;
|
|
12811
|
+
}
|
|
12812
|
+
function chacha20(key, counter, nonce2, data) {
|
|
12813
|
+
const out = new Uint8Array(data.length);
|
|
12814
|
+
for (let offset = 0, block = counter; offset < data.length; offset += 64, block += 1) {
|
|
12815
|
+
const stream = chacha20Block(key, block, nonce2);
|
|
12816
|
+
const end = Math.min(offset + 64, data.length);
|
|
12817
|
+
for (let i = offset; i < end; i += 1) out[i] = data[i] ^ stream[i - offset];
|
|
12818
|
+
}
|
|
12819
|
+
return out;
|
|
12820
|
+
}
|
|
12821
|
+
function leToBigInt(bytes) {
|
|
12822
|
+
let value = 0n;
|
|
12823
|
+
for (let i = bytes.length - 1; i >= 0; i -= 1) value = value << 8n | BigInt(bytes[i]);
|
|
12824
|
+
return value;
|
|
12825
|
+
}
|
|
12826
|
+
var P1305 = (1n << 130n) - 5n;
|
|
12827
|
+
function poly1305(key, message) {
|
|
12828
|
+
const r = leToBigInt(key.subarray(0, 16)) & 0x0ffffffc0ffffffc0ffffffc0fffffffn;
|
|
12829
|
+
const s = leToBigInt(key.subarray(16, 32));
|
|
12830
|
+
let acc = 0n;
|
|
12831
|
+
for (let offset = 0; offset < message.length; offset += 16) {
|
|
12832
|
+
const block = message.subarray(offset, Math.min(offset + 16, message.length));
|
|
12833
|
+
const n = leToBigInt(block) + (1n << BigInt(8 * block.length));
|
|
12834
|
+
acc = (acc + n) * r % P1305;
|
|
12835
|
+
}
|
|
12836
|
+
let tag3 = acc + s & (1n << 128n) - 1n;
|
|
12837
|
+
const out = new Uint8Array(TAG_LEN2);
|
|
12838
|
+
for (let i = 0; i < TAG_LEN2; i += 1) {
|
|
12839
|
+
out[i] = Number(tag3 & 0xffn);
|
|
12840
|
+
tag3 >>= 8n;
|
|
12841
|
+
}
|
|
12842
|
+
return out;
|
|
12843
|
+
}
|
|
12844
|
+
function pad16(length) {
|
|
12845
|
+
return new Uint8Array((16 - length % 16) % 16);
|
|
12846
|
+
}
|
|
12847
|
+
function u64le2(value) {
|
|
12848
|
+
const out = new Uint8Array(8);
|
|
12849
|
+
new DataView(out.buffer).setBigUint64(0, BigInt(value), true);
|
|
12850
|
+
return out;
|
|
12851
|
+
}
|
|
12852
|
+
function macData(aad, ciphertext) {
|
|
12853
|
+
const parts = [aad, pad16(aad.length), ciphertext, pad16(ciphertext.length), u64le2(aad.length), u64le2(ciphertext.length)];
|
|
12854
|
+
const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
|
|
12855
|
+
let offset = 0;
|
|
12856
|
+
for (const part of parts) {
|
|
12857
|
+
out.set(part, offset);
|
|
12858
|
+
offset += part.length;
|
|
12859
|
+
}
|
|
12860
|
+
return out;
|
|
12861
|
+
}
|
|
12862
|
+
function check(key, nonce2) {
|
|
12863
|
+
if (key.length !== KEY_LEN) throw new Error("ChaCha20-Poly1305 needs a 32-byte key");
|
|
12864
|
+
if (nonce2.length !== NONCE_LEN) throw new Error("ChaCha20-Poly1305 needs a 12-byte nonce");
|
|
12865
|
+
}
|
|
12866
|
+
function chacha20Poly1305Seal(key, nonce2, plaintext, aad = new Uint8Array(0)) {
|
|
12867
|
+
check(key, nonce2);
|
|
12868
|
+
const otk = chacha20Block(key, 0, nonce2).subarray(0, 32);
|
|
12869
|
+
const ciphertext = chacha20(key, 1, nonce2, plaintext);
|
|
12870
|
+
const tag3 = poly1305(otk, macData(aad, ciphertext));
|
|
12871
|
+
const out = new Uint8Array(ciphertext.length + TAG_LEN2);
|
|
12872
|
+
out.set(ciphertext);
|
|
12873
|
+
out.set(tag3, ciphertext.length);
|
|
12874
|
+
return out;
|
|
12875
|
+
}
|
|
12876
|
+
|
|
12877
|
+
// src/agent-gate/hpke.ts
|
|
12878
|
+
var KEM_ID = 32;
|
|
12879
|
+
var KDF_ID = 1;
|
|
12880
|
+
var AEAD_ID = 3;
|
|
12881
|
+
var MODE_AUTH = 2;
|
|
12882
|
+
var N_SECRET = 32;
|
|
12883
|
+
var N_KEY = 32;
|
|
12884
|
+
var N_NONCE = 12;
|
|
12885
|
+
var utf84 = (s) => new TextEncoder().encode(s);
|
|
12886
|
+
var i2osp2 = (n) => new Uint8Array([n >> 8 & 255, n & 255]);
|
|
12887
|
+
var KEM_SUITE = concat(utf84("KEM"), i2osp2(KEM_ID));
|
|
12888
|
+
var HPKE_SUITE = concat(utf84("HPKE"), i2osp2(KEM_ID), i2osp2(KDF_ID), i2osp2(AEAD_ID));
|
|
12889
|
+
async function hmac(key, data) {
|
|
12890
|
+
const raw = key.length === 0 ? new Uint8Array(32) : key;
|
|
12891
|
+
const k = await crypto.subtle.importKey("raw", raw, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
12892
|
+
return new Uint8Array(await crypto.subtle.sign("HMAC", k, data));
|
|
12893
|
+
}
|
|
12894
|
+
async function expand(prk, info, length) {
|
|
12895
|
+
const out = new Uint8Array(length);
|
|
12896
|
+
let previous = new Uint8Array(0);
|
|
12897
|
+
for (let i = 1, offset = 0; offset < length; i += 1) {
|
|
12898
|
+
previous = await hmac(prk, concat(previous, info, new Uint8Array([i])));
|
|
12899
|
+
out.set(previous.subarray(0, Math.min(previous.length, length - offset)), offset);
|
|
12900
|
+
offset += previous.length;
|
|
12901
|
+
}
|
|
12902
|
+
return out;
|
|
12903
|
+
}
|
|
12904
|
+
function labeledExtract(suite, salt, label2, ikm) {
|
|
12905
|
+
return hmac(salt, concat(utf84("HPKE-v1"), suite, utf84(label2), ikm));
|
|
12906
|
+
}
|
|
12907
|
+
function labeledExpand(suite, prk, label2, info, length) {
|
|
12908
|
+
return expand(prk, concat(i2osp2(length), utf84("HPKE-v1"), suite, utf84(label2), info), length);
|
|
12909
|
+
}
|
|
12910
|
+
async function extractAndExpand(dhValue, kemContext) {
|
|
12911
|
+
const prk = await labeledExtract(KEM_SUITE, new Uint8Array(0), "eae_prk", dhValue);
|
|
12912
|
+
return labeledExpand(KEM_SUITE, prk, "shared_secret", kemContext, N_SECRET);
|
|
12913
|
+
}
|
|
12914
|
+
async function keySchedule(sharedSecret, info) {
|
|
12915
|
+
const empty = new Uint8Array(0);
|
|
12916
|
+
const pskIdHash = await labeledExtract(HPKE_SUITE, empty, "psk_id_hash", empty);
|
|
12917
|
+
const infoHash = await labeledExtract(HPKE_SUITE, empty, "info_hash", info);
|
|
12918
|
+
const context = concat(new Uint8Array([MODE_AUTH]), pskIdHash, infoHash);
|
|
12919
|
+
const secret = await labeledExtract(HPKE_SUITE, sharedSecret, "secret", empty);
|
|
12920
|
+
return {
|
|
12921
|
+
key: await labeledExpand(HPKE_SUITE, secret, "key", context, N_KEY),
|
|
12922
|
+
nonce: await labeledExpand(HPKE_SUITE, secret, "base_nonce", context, N_NONCE)
|
|
12923
|
+
};
|
|
12924
|
+
}
|
|
12925
|
+
async function hpkeSealAuth(recipientPublic, senderSecret, info, plaintext, aad = new Uint8Array(0), ephemeralSecret) {
|
|
12926
|
+
if (recipientPublic.length !== 32) throw new Error("The recipient key is not 32 bytes of X25519");
|
|
12927
|
+
const ephemeral = await x25519KeyPair(ephemeralSecret);
|
|
12928
|
+
const sender = await x25519KeyPair(senderSecret);
|
|
12929
|
+
const dhValue = concat(await dh(ephemeral.privateKey, recipientPublic), await dh(sender.privateKey, recipientPublic));
|
|
12930
|
+
const shared = await extractAndExpand(dhValue, concat(ephemeral.publicKey, recipientPublic, sender.publicKey));
|
|
12931
|
+
const { key, nonce: nonce2 } = await keySchedule(shared, info);
|
|
12932
|
+
return { enc: ephemeral.publicKey, ciphertext: chacha20Poly1305Seal(key, nonce2, plaintext, aad) };
|
|
12933
|
+
}
|
|
12934
|
+
|
|
12935
|
+
// src/agent-gate/gate.ts
|
|
12936
|
+
var AGENT_ATTEST_DOMAIN = "mero-agent-gate/attest/v3";
|
|
12937
|
+
var AGENT_PROVISION_INFO_DOMAIN = "mero-agent-gate/provision/v2";
|
|
12938
|
+
var AGENT_ID = /^[a-z0-9][a-z0-9-]{0,62}$/;
|
|
12939
|
+
var SECRET_NAME = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$/;
|
|
12940
|
+
var MAX_SECRETS = 64;
|
|
12941
|
+
var MAX_SECRET_LEN = 64 * 1024;
|
|
12942
|
+
var AgentGateError = class extends Error {
|
|
12943
|
+
constructor(message, status, code) {
|
|
12944
|
+
super(message);
|
|
12945
|
+
this.status = status;
|
|
12946
|
+
this.code = code;
|
|
12947
|
+
this.name = "AgentGateError";
|
|
12948
|
+
}
|
|
12949
|
+
};
|
|
12950
|
+
function validateAgentId(agentId) {
|
|
12951
|
+
if (!AGENT_ID.test(agentId)) {
|
|
12952
|
+
throw new Error(`Agent id ${JSON.stringify(agentId)} must match [a-z0-9][a-z0-9-]{0,62}`);
|
|
12953
|
+
}
|
|
12954
|
+
}
|
|
12955
|
+
function utf85(value) {
|
|
12956
|
+
return new TextEncoder().encode(value);
|
|
12957
|
+
}
|
|
12958
|
+
function lengthPrefixed(agentId) {
|
|
12959
|
+
const id = utf85(agentId);
|
|
12960
|
+
return concat(new Uint8Array([id.length]), id);
|
|
12961
|
+
}
|
|
12962
|
+
function toBase64(bytes) {
|
|
12963
|
+
let binary = "";
|
|
12964
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
12965
|
+
return btoa(binary);
|
|
12966
|
+
}
|
|
12967
|
+
function fromBase644(value, label2, length) {
|
|
12968
|
+
let bytes;
|
|
12969
|
+
try {
|
|
12970
|
+
bytes = Uint8Array.from(atob(value.trim()), (c) => c.charCodeAt(0));
|
|
12971
|
+
} catch {
|
|
12972
|
+
throw new Error(`${label2} is not base64`);
|
|
12973
|
+
}
|
|
12974
|
+
if (length !== void 0 && bytes.length !== length) throw new Error(`${label2} is not ${length} bytes`);
|
|
12975
|
+
return bytes;
|
|
12976
|
+
}
|
|
12977
|
+
async function agentKeyBinding(provisioningPublic, agentId, signingPublic, ownerPublic) {
|
|
12978
|
+
const zero = new Uint8Array(32);
|
|
12979
|
+
const data = concat(
|
|
12980
|
+
utf85(AGENT_ATTEST_DOMAIN),
|
|
12981
|
+
provisioningPublic,
|
|
12982
|
+
lengthPrefixed(agentId),
|
|
12983
|
+
signingPublic ?? zero,
|
|
12984
|
+
ownerPublic ?? zero
|
|
12985
|
+
);
|
|
12986
|
+
return new Uint8Array(await crypto.subtle.digest("SHA-256", data));
|
|
12987
|
+
}
|
|
12988
|
+
function provisionInfo(recipientPublic, agentId) {
|
|
12989
|
+
return concat(utf85(AGENT_PROVISION_INFO_DOMAIN), recipientPublic, lengthPrefixed(agentId));
|
|
12990
|
+
}
|
|
12991
|
+
async function generateOwnerKey() {
|
|
12992
|
+
const secret = crypto.getRandomValues(new Uint8Array(32));
|
|
12993
|
+
return { secret, publicKey: await ownerPublicKey(secret) };
|
|
12994
|
+
}
|
|
12995
|
+
async function ownerPublicKey(secret) {
|
|
12996
|
+
if (secret.length !== 32) throw new Error("An owner key is 32 bytes");
|
|
12997
|
+
return toBase64((await x25519KeyPair(secret)).publicKey);
|
|
12998
|
+
}
|
|
12999
|
+
function url(gateUrl, path) {
|
|
13000
|
+
return `${gateUrl.replace(/\/+$/, "")}${path}`;
|
|
13001
|
+
}
|
|
13002
|
+
async function postJson(fetchImpl, target, body) {
|
|
13003
|
+
const response = await fetchImpl(target, {
|
|
13004
|
+
method: "POST",
|
|
13005
|
+
headers: { "content-type": "application/json" },
|
|
13006
|
+
body: JSON.stringify(body)
|
|
13007
|
+
});
|
|
13008
|
+
const text = await response.text();
|
|
13009
|
+
let parsed = void 0;
|
|
13010
|
+
try {
|
|
13011
|
+
parsed = text ? JSON.parse(text) : void 0;
|
|
13012
|
+
} catch {
|
|
13013
|
+
}
|
|
13014
|
+
if (!response.ok) {
|
|
13015
|
+
const error = parsed;
|
|
13016
|
+
throw new AgentGateError(
|
|
13017
|
+
`The gate answered ${response.status}${error?.error ? ` ${error.error}` : ""}: ${error?.details ?? text.slice(0, 200)}`,
|
|
13018
|
+
response.status,
|
|
13019
|
+
error?.error
|
|
13020
|
+
);
|
|
13021
|
+
}
|
|
13022
|
+
return parsed;
|
|
13023
|
+
}
|
|
13024
|
+
async function attestAgent(options) {
|
|
13025
|
+
const agentId = options.agentId ?? "";
|
|
13026
|
+
if (agentId) validateAgentId(agentId);
|
|
13027
|
+
const nonce2 = crypto.getRandomValues(new Uint8Array(32));
|
|
13028
|
+
const body = await postJson(options.fetch ?? fetch, url(options.gateUrl, "/attest"), {
|
|
13029
|
+
nonceB64: toBase64(nonce2),
|
|
13030
|
+
...agentId ? { agentId } : {}
|
|
13031
|
+
});
|
|
13032
|
+
if ((body?.agentId ?? "") !== agentId) {
|
|
13033
|
+
throw new Error(`Asked about agent ${JSON.stringify(agentId)}, the gate answered for ${JSON.stringify(body?.agentId)}`);
|
|
13034
|
+
}
|
|
13035
|
+
const provisioning = fromBase644(body.provisioningPublicKeyB64 ?? "", "provisioningPublicKeyB64", 32);
|
|
13036
|
+
const signing = body.signingPublicKeyB64 ? fromBase644(body.signingPublicKeyB64, "signingPublicKeyB64", 32) : void 0;
|
|
13037
|
+
const owner = body.ownerPublicKeyB64 ? fromBase644(body.ownerPublicKeyB64, "ownerPublicKeyB64", 32) : void 0;
|
|
13038
|
+
if (!signing !== !owner) {
|
|
13039
|
+
throw new Error("A claimed agent has both a signing key and an owner; the gate named one");
|
|
13040
|
+
}
|
|
13041
|
+
const binding = await agentKeyBinding(provisioning, agentId, signing, owner);
|
|
13042
|
+
await options.verifier({ quoteB64: body.quoteB64, nonce: hex(nonce2), reportDataSuffix: hex(binding) });
|
|
13043
|
+
return {
|
|
13044
|
+
agentId,
|
|
13045
|
+
provisioningPublicKey: toBase64(provisioning),
|
|
13046
|
+
...signing ? { signingPublicKey: toBase64(signing) } : {},
|
|
13047
|
+
...owner ? { ownerPublicKey: toBase64(owner) } : {}
|
|
13048
|
+
};
|
|
13049
|
+
}
|
|
13050
|
+
async function checkOwner(agent, ownerSecret) {
|
|
13051
|
+
const mine = await ownerPublicKey(ownerSecret);
|
|
13052
|
+
if (agent.ownerPublicKey && agent.ownerPublicKey !== mine) {
|
|
13053
|
+
throw new AgentGateError(
|
|
13054
|
+
`This agent is claimed by another key (${agent.ownerPublicKey}); it is not yours. Send it nothing and do not authorize its signing key`,
|
|
13055
|
+
void 0,
|
|
13056
|
+
"not_yours"
|
|
13057
|
+
);
|
|
13058
|
+
}
|
|
13059
|
+
return mine;
|
|
13060
|
+
}
|
|
13061
|
+
function validateSecrets(secrets) {
|
|
13062
|
+
const names = Object.keys(secrets);
|
|
13063
|
+
if (names.length === 0) throw new Error("There are no secrets to provision");
|
|
13064
|
+
if (names.length > MAX_SECRETS) throw new Error(`At most ${MAX_SECRETS} secrets at once`);
|
|
13065
|
+
for (const name of names) {
|
|
13066
|
+
if (!SECRET_NAME.test(name)) throw new Error(`Secret name ${JSON.stringify(name)} must match [A-Za-z0-9][A-Za-z0-9_.-]{0,63}`);
|
|
13067
|
+
if (typeof secrets[name] !== "string") throw new Error(`Secret ${name} is not a string`);
|
|
13068
|
+
if (utf85(secrets[name]).length > MAX_SECRET_LEN) throw new Error(`Secret ${name} is over ${MAX_SECRET_LEN} bytes`);
|
|
13069
|
+
}
|
|
13070
|
+
}
|
|
13071
|
+
async function sendSealed(fetchImpl, gateUrl, path, agent, ownerSecret, message) {
|
|
13072
|
+
if (!agent.agentId) throw new Error("This quote names no agent; attest with the agent id");
|
|
13073
|
+
const mine = await checkOwner(agent, ownerSecret);
|
|
13074
|
+
const recipient = fromBase644(agent.provisioningPublicKey, "provisioningPublicKey", 32);
|
|
13075
|
+
const sealed = await hpkeSealAuth(
|
|
13076
|
+
recipient,
|
|
13077
|
+
ownerSecret,
|
|
13078
|
+
provisionInfo(recipient, agent.agentId),
|
|
13079
|
+
utf85(JSON.stringify(message))
|
|
13080
|
+
);
|
|
13081
|
+
return postJson(fetchImpl, url(gateUrl, path), {
|
|
13082
|
+
agentId: agent.agentId,
|
|
13083
|
+
provisioningPublicKeyB64: agent.provisioningPublicKey,
|
|
13084
|
+
senderPublicKeyB64: mine,
|
|
13085
|
+
encappedKeyB64: toBase64(sealed.enc),
|
|
13086
|
+
ciphertextB64: toBase64(sealed.ciphertext)
|
|
13087
|
+
});
|
|
13088
|
+
}
|
|
13089
|
+
async function provisionAgent(options) {
|
|
13090
|
+
validateSecrets(options.secrets);
|
|
13091
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
13092
|
+
const answer = await sendSealed(fetchImpl, options.gateUrl, "/provision", options.agent, options.ownerSecret, {
|
|
13093
|
+
secrets: options.secrets
|
|
13094
|
+
});
|
|
13095
|
+
const after = await attestAgent({ gateUrl: options.gateUrl, agentId: options.agent.agentId, verifier: options.verifier, fetch: fetchImpl });
|
|
13096
|
+
const mine = await ownerPublicKey(options.ownerSecret);
|
|
13097
|
+
if (after.ownerPublicKey !== mine || !after.signingPublicKey) {
|
|
13098
|
+
throw new AgentGateError("The gate accepted the secrets, but its quote does not name your key as owner");
|
|
13099
|
+
}
|
|
13100
|
+
if (options.agent.signingPublicKey && options.agent.signingPublicKey !== after.signingPublicKey) {
|
|
13101
|
+
throw new AgentGateError("The agent's signing key changed while provisioning");
|
|
13102
|
+
}
|
|
13103
|
+
return {
|
|
13104
|
+
agentId: after.agentId,
|
|
13105
|
+
provisioningPublicKey: after.provisioningPublicKey,
|
|
13106
|
+
signingPublicKey: after.signingPublicKey,
|
|
13107
|
+
ownerPublicKey: mine,
|
|
13108
|
+
written: answer?.written ?? [],
|
|
13109
|
+
claimed: answer?.claimed === true
|
|
13110
|
+
};
|
|
13111
|
+
}
|
|
13112
|
+
async function releaseAgent(options) {
|
|
13113
|
+
if (!options.agent.ownerPublicKey) throw new Error("This agent is not claimed; there is nothing to release");
|
|
13114
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
13115
|
+
await sendSealed(fetchImpl, options.gateUrl, "/release", options.agent, options.ownerSecret, { release: true });
|
|
13116
|
+
const after = await attestAgent({ gateUrl: options.gateUrl, agentId: options.agent.agentId, verifier: options.verifier, fetch: fetchImpl });
|
|
13117
|
+
if (after.ownerPublicKey) {
|
|
13118
|
+
throw new AgentGateError("The gate says it released the agent, but its quote still names an owner");
|
|
13119
|
+
}
|
|
13120
|
+
}
|
|
13121
|
+
|
|
13122
|
+
// src/agent-gate/policy.ts
|
|
13123
|
+
var KMS_RELEASE_SIGNER = Object.freeze({
|
|
13124
|
+
identity: "https://github.com/calimero-network/mero-tee/.github/workflows/release-kms.yaml@refs/heads/master",
|
|
13125
|
+
issuer: "https://token.actions.githubusercontent.com"
|
|
13126
|
+
});
|
|
13127
|
+
var LISTS = [
|
|
13128
|
+
"allowed_tcb_statuses",
|
|
13129
|
+
"allowed_mrtd",
|
|
13130
|
+
"allowed_rtmr0",
|
|
13131
|
+
"allowed_rtmr1",
|
|
13132
|
+
"allowed_rtmr2",
|
|
13133
|
+
"allowed_rtmr3"
|
|
13134
|
+
];
|
|
13135
|
+
async function verifySignedAgentPolicy(policy, bundle, options = {}) {
|
|
13136
|
+
const body = typeof policy === "string" ? new TextEncoder().encode(policy) : policy;
|
|
13137
|
+
await verifyCosignBundle(body, bundle, {
|
|
13138
|
+
identity: options.identity ?? KMS_RELEASE_SIGNER.identity,
|
|
13139
|
+
issuer: options.issuer ?? KMS_RELEASE_SIGNER.issuer
|
|
13140
|
+
});
|
|
13141
|
+
let parsed;
|
|
13142
|
+
try {
|
|
13143
|
+
parsed = JSON.parse(new TextDecoder().decode(body));
|
|
13144
|
+
} catch {
|
|
13145
|
+
throw new Error("The signed agent policy is not JSON");
|
|
13146
|
+
}
|
|
13147
|
+
if (parsed?.role !== "agent") {
|
|
13148
|
+
throw new Error(`The signed file is a ${JSON.stringify(parsed?.role)} policy, not an agent one`);
|
|
13149
|
+
}
|
|
13150
|
+
const profile = options.profile ?? PRODUCTION_PROFILE;
|
|
13151
|
+
if (parsed.profile !== profile) {
|
|
13152
|
+
throw new Error(`The signed agent policy is for the ${JSON.stringify(parsed.profile)} profile, not ${profile}`);
|
|
13153
|
+
}
|
|
13154
|
+
if (options.expectedVersion !== void 0 && parsed.version !== options.expectedVersion) {
|
|
13155
|
+
throw new Error(`The signed agent policy is release ${JSON.stringify(parsed.version)}, not ${options.expectedVersion}`);
|
|
13156
|
+
}
|
|
13157
|
+
checkLists(parsed);
|
|
13158
|
+
return parsed;
|
|
13159
|
+
}
|
|
13160
|
+
function checkLists(policy) {
|
|
13161
|
+
for (const list of LISTS) {
|
|
13162
|
+
if (!Array.isArray(policy?.[list]) || policy[list].length === 0) {
|
|
13163
|
+
throw new Error(`The agent policy's ${list} is empty, so no agent would be accepted`);
|
|
13164
|
+
}
|
|
13165
|
+
}
|
|
13166
|
+
}
|
|
13167
|
+
var TCB_STATUSES2 = [
|
|
13168
|
+
"UpToDate",
|
|
13169
|
+
"SWHardeningNeeded",
|
|
13170
|
+
"ConfigurationNeeded",
|
|
13171
|
+
"ConfigurationAndSWHardeningNeeded",
|
|
13172
|
+
"OutOfDate",
|
|
13173
|
+
"OutOfDateConfigurationNeeded"
|
|
13174
|
+
];
|
|
13175
|
+
function tcbStatus2(value) {
|
|
13176
|
+
const found = TCB_STATUSES2.find((status) => status.toLowerCase() === value.trim().toLowerCase());
|
|
13177
|
+
if (!found) throw new Error(`The agent policy allows an unknown TCB status ${JSON.stringify(value)}`);
|
|
13178
|
+
return found;
|
|
13179
|
+
}
|
|
13180
|
+
var register = (value) => value.trim().replace(/^0x/i, "");
|
|
13181
|
+
function agentQuoteVerifier(policy, options) {
|
|
13182
|
+
checkLists(policy);
|
|
13183
|
+
return createQuoteVerifier({
|
|
13184
|
+
dcapVerify: options.dcapVerify,
|
|
13185
|
+
fetchCollateral: options.fetchCollateral,
|
|
13186
|
+
now: options.now,
|
|
13187
|
+
allowedTcbStatuses: policy.allowed_tcb_statuses.map(tcbStatus2),
|
|
13188
|
+
allowedMrtd: policy.allowed_mrtd.map(register),
|
|
13189
|
+
allowedRtmr0: policy.allowed_rtmr0.map(register),
|
|
13190
|
+
allowedRtmr1: policy.allowed_rtmr1.map(register),
|
|
13191
|
+
allowedRtmr2: policy.allowed_rtmr2.map(register),
|
|
13192
|
+
allowedRtmr3: policy.allowed_rtmr3.map(register)
|
|
13193
|
+
});
|
|
12740
13194
|
}
|
|
12741
13195
|
export {
|
|
12742
13196
|
ACCOUNT_HA_AUDIENCE,
|
|
12743
13197
|
ACCOUNT_OWNERSHIP_AUDIENCE,
|
|
13198
|
+
AGENT_ATTEST_DOMAIN,
|
|
13199
|
+
AGENT_PROVISION_INFO_DOMAIN,
|
|
12744
13200
|
AccountHaRefusedError,
|
|
12745
13201
|
AccountLinkedToSeveralUsersError,
|
|
12746
13202
|
AccountNotLinkedError,
|
|
12747
13203
|
AdminApiClient,
|
|
13204
|
+
AgentGateError,
|
|
12748
13205
|
AuthApiClient,
|
|
12749
13206
|
AuthRevokedError,
|
|
12750
13207
|
CAPABILITIES,
|
|
@@ -12761,6 +13218,7 @@ export {
|
|
|
12761
13218
|
INVITED_ROLE,
|
|
12762
13219
|
IntentRefusedError,
|
|
12763
13220
|
InvitationNotClaimableError,
|
|
13221
|
+
KMS_RELEASE_SIGNER,
|
|
12764
13222
|
LocalStorageTokenStore,
|
|
12765
13223
|
MAX_INVITATION_VALIDITY_SECS,
|
|
12766
13224
|
MemoryTokenStore,
|
|
@@ -12799,8 +13257,11 @@ export {
|
|
|
12799
13257
|
accountRootSignerFromPhrase,
|
|
12800
13258
|
adminChangedOp,
|
|
12801
13259
|
admitterAddrsFromNetworkStatus,
|
|
13260
|
+
agentKeyBinding,
|
|
13261
|
+
agentQuoteVerifier,
|
|
12802
13262
|
applicationIdForBundle,
|
|
12803
13263
|
attemptRelayNodeKey,
|
|
13264
|
+
attestAgent,
|
|
12804
13265
|
attestKeyBinding,
|
|
12805
13266
|
attestRelayNodeKey,
|
|
12806
13267
|
authorNonceLookup,
|
|
@@ -12814,6 +13275,7 @@ export {
|
|
|
12814
13275
|
capMask,
|
|
12815
13276
|
capNames,
|
|
12816
13277
|
carryExecutorAccount,
|
|
13278
|
+
checkOwner,
|
|
12817
13279
|
classifyError,
|
|
12818
13280
|
clearDelegatedCredential,
|
|
12819
13281
|
clearDelegatedSession,
|
|
@@ -12881,6 +13343,7 @@ export {
|
|
|
12881
13343
|
foundDelegatedNamespace,
|
|
12882
13344
|
foundedNamespaceId,
|
|
12883
13345
|
generateAccountRoot,
|
|
13346
|
+
generateOwnerKey,
|
|
12884
13347
|
generateSessionKey,
|
|
12885
13348
|
governGroup,
|
|
12886
13349
|
governRoot,
|
|
@@ -12921,6 +13384,7 @@ export {
|
|
|
12921
13384
|
normaliseAccount,
|
|
12922
13385
|
ownerOpDigest,
|
|
12923
13386
|
ownerOpSigningPayload,
|
|
13387
|
+
ownerPublicKey,
|
|
12924
13388
|
parseAuthCallback,
|
|
12925
13389
|
parseCreationWarrant,
|
|
12926
13390
|
parseDeviceCredential,
|
|
@@ -12930,6 +13394,8 @@ export {
|
|
|
12930
13394
|
pinRelayNodeKey,
|
|
12931
13395
|
presenceStatementBytes,
|
|
12932
13396
|
probeNodeHealth,
|
|
13397
|
+
provisionAgent,
|
|
13398
|
+
provisionInfo,
|
|
12933
13399
|
readCloudLinkCallback,
|
|
12934
13400
|
readDelegatedCredential,
|
|
12935
13401
|
readDelegatedSession,
|
|
@@ -12939,6 +13405,7 @@ export {
|
|
|
12939
13405
|
redeemInvitation,
|
|
12940
13406
|
relayForContext,
|
|
12941
13407
|
relayTransportFetch,
|
|
13408
|
+
releaseAgent,
|
|
12942
13409
|
rememberGroupNamespace,
|
|
12943
13410
|
rememberRelay,
|
|
12944
13411
|
reportDataOf,
|
|
@@ -12985,7 +13452,9 @@ export {
|
|
|
12985
13452
|
transportKeyBinding,
|
|
12986
13453
|
trustSignedRelease,
|
|
12987
13454
|
trustedMeasurementsFromReleases,
|
|
13455
|
+
validateAgentId,
|
|
12988
13456
|
verifyDeviceCredential,
|
|
13457
|
+
verifySignedAgentPolicy,
|
|
12989
13458
|
verifySignedNodeRelease,
|
|
12990
13459
|
withCap,
|
|
12991
13460
|
withRetry,
|