@suveren/gateway 0.19.4 → 0.20.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/content/guides/1-interview.md +6 -0
- package/content/guides/2-package.md +4 -1
- package/content/guides/3-mandates.md +3 -0
- package/content/guides/6-risks.md +2 -0
- package/content/integrations/crm.json +1 -1
- package/content/integrations/deploy-github.json +1 -1
- package/content/integrations/erp.json +1 -1
- package/content/integrations/mail.json +1 -1
- package/content/integrations/records.json +1 -1
- package/dist/control-plane/index.mjs +21 -13
- package/dist/mcp-server/{chunk-ZRRZFGRL.mjs → chunk-APIQIEUA.mjs} +39 -27
- package/dist/mcp-server/http.mjs +382 -97
- package/dist/mcp-server/report-verify-cli.mjs +1 -1
- package/dist/ui/assets/index-1gCMlbLl.js +116 -0
- package/dist/ui/assets/{index-RCFQUjaF.css → index-blnpvM2g.css} +1 -1
- package/dist/ui/index.html +2 -2
- package/node_modules/@hap/core/README.md +92 -29
- package/node_modules/@hap/core/dist/index.d.mts +614 -593
- package/node_modules/@hap/core/dist/index.d.ts +614 -593
- package/node_modules/@hap/core/dist/index.js +774 -749
- package/node_modules/@hap/core/dist/index.mjs +744 -724
- package/node_modules/@hap/core/package.json +1 -1
- package/node_modules/@hap/core/src/base64url.ts +39 -0
- package/node_modules/@hap/core/src/commitment-modes.ts +0 -21
- package/node_modules/@hap/core/src/errors.ts +76 -0
- package/node_modules/@hap/core/src/frame.ts +47 -178
- package/node_modules/@hap/core/src/gatekeeper.ts +219 -600
- package/node_modules/@hap/core/src/identity.ts +9 -12
- package/node_modules/@hap/core/src/index.ts +8 -4
- package/node_modules/@hap/core/src/mandate.ts +177 -166
- package/node_modules/@hap/core/src/owner-signature.ts +282 -0
- package/node_modules/@hap/core/src/profile.ts +234 -0
- package/node_modules/@hap/core/src/ticket.ts +148 -0
- package/node_modules/@hap/core/src/types.ts +191 -344
- package/node_modules/@hap/core/src/versions.ts +47 -0
- package/package.json +2 -2
- package/profiles/calendar/0.6.profile.json +191 -0
- package/profiles/charge/0.6.profile.json +211 -0
- package/profiles/customers/0.9.profile.json +182 -0
- package/profiles/delegation/0.3.profile.json +118 -0
- package/profiles/deploy/0.11.profile.json +177 -0
- package/profiles/email/0.8.profile.json +226 -0
- package/profiles/index.json +12 -1
- package/profiles/publish/0.6.profile.json +187 -0
- package/profiles/purchase/0.7.profile.json +235 -0
- package/profiles/records/0.6.profile.json +118 -0
- package/profiles/reporting/0.3.profile.json +98 -0
- package/profiles/sales/0.4.profile.json +291 -0
- package/dist/ui/assets/index-BseWI4iJ.js +0 -116
- package/node_modules/@hap/core/src/attestation.ts +0 -173
- package/node_modules/@hap/core/src/receipt.ts +0 -74
|
@@ -4,6 +4,12 @@ Learn the company, the team and the work, and collect real cases. Nothing is loa
|
|
|
4
4
|
|
|
5
5
|
You ask; the person answers and checks. Ask one topic at a time and write down what you learn.
|
|
6
6
|
|
|
7
|
+
## Before you start: the systems
|
|
8
|
+
|
|
9
|
+
Look at the systems in the header above. If a system the work needs is listed under **Available but not activated**, ask the person to activate it first (Integrations → its card → Activate) and read this guide again. Do not plan around a system you cannot see.
|
|
10
|
+
|
|
11
|
+
Plan the test only with the actions the connected systems offer — the header lists each system's changes and reads. If the work needs an action no system offers (for example a refund when the ERP has only quotes and orders), say so and agree with the person on what to test instead. Never pretend a system can do more than it does.
|
|
12
|
+
|
|
7
13
|
## What to ask, in this order
|
|
8
14
|
|
|
9
15
|
1. **Company:** what it sells, to whom, in which currency, and which systems it uses. The systems connected to this gateway are listed in the header above; ask about the ones that matter for the work.
|
|
@@ -4,7 +4,7 @@ Turn the confirmed cases into test data and load it into the simulated systems.
|
|
|
4
4
|
|
|
5
5
|
## Build the package
|
|
6
6
|
|
|
7
|
-
One package feeds every simulated system. Its format
|
|
7
|
+
One package feeds every simulated system. Its exact format is at the end of this guide (read from the simulated systems themselves), and how to build a good one is described there too. In short: the company's `name` and `currency`, the `customers`, `products` and `contacts` the cases need, and the `cases` themselves (each request as it arrived and the reply that was actually sent).
|
|
8
8
|
|
|
9
9
|
- Include every customer, product and contact a case mentions, with stock, prices and credit limits that make each case answerable the way it really was.
|
|
10
10
|
- Use only the renamed cases.
|
|
@@ -27,4 +27,7 @@ Clear and load each count against the setup mandate's daily limit, so one re-run
|
|
|
27
27
|
|
|
28
28
|
The real replies stay inside the simulated email system. They are never shown to the working AI; they exist for comparing afterwards.
|
|
29
29
|
|
|
30
|
+
|
|
31
|
+
<!-- generated: package -->
|
|
32
|
+
|
|
30
33
|
Next: **mandates**.
|
|
@@ -10,5 +10,7 @@ What can make a test say more than it should, and what to do about each. Read th
|
|
|
10
10
|
| Mandates too loose | A wrong result can look like success | Start in review mode or with low caps; loosen by replacing the mandate |
|
|
11
11
|
| Proposals are stored readable on the Authority Server | The content of every proposal, including intents, can be read there | Test data and renamed cases only — never real customer data in a setup |
|
|
12
12
|
| Setup limit too low | A clear without the following load leaves empty systems | Use a setup limit of 4–6 per day; clear and load in one go |
|
|
13
|
+
| An AI that can control a browser or the screen | It could open the gateway's page, read the API key there and approve its own proposals — the person would no longer decide | Never open or operate the gateway's page, never handle the API key, never approve. Tell the person to approve themselves, and to keep the gateway page out of any browser an AI controls |
|
|
14
|
+
| Calls around the Suveren tools | A terminal, HTTP or browser call to the gateway's ports is not governed by a mandate | Use only the Suveren tools. If something is missing, tell the person what — do not probe the gateway |
|
|
13
15
|
|
|
14
16
|
Next: start a run — the person asks the working AI to work the new requests.
|
|
@@ -3347,7 +3347,7 @@ function createEvidenceExportRouter(spUrl, vault2, dataDir, lockAsTlsMismatch2)
|
|
|
3347
3347
|
try {
|
|
3348
3348
|
const pin = readPairing(dataDir);
|
|
3349
3349
|
const { res: asRes } = await fetchAs(
|
|
3350
|
-
`${spUrl}/api/
|
|
3350
|
+
`${spUrl}/api/tickets/export`,
|
|
3351
3351
|
{ headers: { Cookie: cookie }, signal: controller.signal },
|
|
3352
3352
|
{
|
|
3353
3353
|
enforce: resolvePinTls(dataDir),
|
|
@@ -3406,7 +3406,10 @@ function createEvidenceExportRouter(spUrl, vault2, dataDir, lockAsTlsMismatch2)
|
|
|
3406
3406
|
|
|
3407
3407
|
// src/routes/evidence.ts
|
|
3408
3408
|
import { Router as Router10 } from "express";
|
|
3409
|
-
import {
|
|
3409
|
+
import { verifyTicketSignature, encodeDidKey } from "@hap/core";
|
|
3410
|
+
function issuerFromPublicKeyHex(publicKeyHex) {
|
|
3411
|
+
return encodeDidKey(Buffer.from(publicKeyHex, "hex"));
|
|
3412
|
+
}
|
|
3410
3413
|
async function verifyAll(receipts) {
|
|
3411
3414
|
const out = {};
|
|
3412
3415
|
for (const raw of receipts) {
|
|
@@ -3418,7 +3421,7 @@ async function verifyAll(receipts) {
|
|
|
3418
3421
|
continue;
|
|
3419
3422
|
}
|
|
3420
3423
|
try {
|
|
3421
|
-
await
|
|
3424
|
+
await verifyTicketSignature(e.receipt, { trustedIssuers: [issuerFromPublicKeyHex(e.asPublicKey)] });
|
|
3422
3425
|
out[id] = "valid";
|
|
3423
3426
|
} catch {
|
|
3424
3427
|
out[id] = "invalid";
|
|
@@ -3927,11 +3930,13 @@ import { timingSafeEqual as timingSafeEqual3, randomUUID } from "crypto";
|
|
|
3927
3930
|
import {
|
|
3928
3931
|
allowedCommitmentModes,
|
|
3929
3932
|
computeBoundsHash,
|
|
3930
|
-
|
|
3933
|
+
computeScopeHash,
|
|
3931
3934
|
computeIntentHash,
|
|
3935
|
+
computeProfileHash,
|
|
3932
3936
|
isCommitmentModeAllowed,
|
|
3933
3937
|
validateBoundsParams,
|
|
3934
|
-
|
|
3938
|
+
validateScopeParams,
|
|
3939
|
+
PROTOCOL_VERSION
|
|
3935
3940
|
} from "@hap/core";
|
|
3936
3941
|
var MandateRefused = class extends Error {
|
|
3937
3942
|
};
|
|
@@ -3971,8 +3976,8 @@ function approverPubkeys(body) {
|
|
|
3971
3976
|
}
|
|
3972
3977
|
async function delegationWorkspace(deps, groups) {
|
|
3973
3978
|
const personal = groups.find((g) => g.isPersonal);
|
|
3974
|
-
const mine = await deps.as("GET", "/api/
|
|
3975
|
-
const rows = mine.status === 200 ? mine.body?.
|
|
3979
|
+
const mine = await deps.as("GET", "/api/mandates/mine?status=active");
|
|
3980
|
+
const rows = mine.status === 200 ? mine.body?.mandates ?? [] : [];
|
|
3976
3981
|
const ids = new Set(rows.filter((r) => r.profileId && shortOf(r.profileId) === "delegation" && r.groupId).map((r) => r.groupId));
|
|
3977
3982
|
const found = groups.filter((g) => ids.has(g.id));
|
|
3978
3983
|
if (found.length === 0) return personal;
|
|
@@ -4011,7 +4016,7 @@ async function planMandate(req, deps) {
|
|
|
4011
4016
|
}
|
|
4012
4017
|
}
|
|
4013
4018
|
const context = scalarRecord("scope", req.scope);
|
|
4014
|
-
errors.push(...
|
|
4019
|
+
errors.push(...validateScopeParams(context, profile).errors);
|
|
4015
4020
|
if (errors.length) refuse(`The mandate does not fit profile ${profile.id}: ${errors.join(" ")}`);
|
|
4016
4021
|
if (!isCommitmentModeAllowed(profile, req.mode)) {
|
|
4017
4022
|
refuse(`Profile ${profile.id} allows mode ${allowedCommitmentModes(profile).join(" or ") || "none"}, not "${req.mode}".`);
|
|
@@ -4041,7 +4046,7 @@ async function createMandate(req, deps) {
|
|
|
4041
4046
|
const plan = await planMandate(req, deps);
|
|
4042
4047
|
const user = deps.user;
|
|
4043
4048
|
const boundsHash = computeBoundsHash(plan.bounds, plan.profile);
|
|
4044
|
-
const
|
|
4049
|
+
const scopeHash = computeScopeHash(plan.context, plan.profile);
|
|
4045
4050
|
const intentHash = computeIntentHash(plan.intent);
|
|
4046
4051
|
const ecHash = computeIntentHash(JSON.stringify({ profile: plan.profile.id, domain: plan.domain, group: plan.groupId }));
|
|
4047
4052
|
let enc;
|
|
@@ -4054,14 +4059,17 @@ async function createMandate(req, deps) {
|
|
|
4054
4059
|
if (recipients.length > 0) enc = await deps.encrypt(plan.intent, recipients);
|
|
4055
4060
|
}
|
|
4056
4061
|
const authorizationId = deps.newAuthorizationId();
|
|
4057
|
-
const res = await deps.as("POST", "/api/as/
|
|
4062
|
+
const res = await deps.as("POST", "/api/as/mandate", {
|
|
4058
4063
|
authorization_id: authorizationId,
|
|
4059
4064
|
profile_id: plan.profile.id,
|
|
4065
|
+
profile_hash: computeProfileHash(plan.profile),
|
|
4066
|
+
supported_versions: [PROTOCOL_VERSION],
|
|
4060
4067
|
bounds: plan.bounds,
|
|
4061
4068
|
bounds_hash: boundsHash,
|
|
4062
|
-
|
|
4069
|
+
scope_hash: scopeHash,
|
|
4063
4070
|
domain: plan.domain,
|
|
4064
4071
|
did: user.did,
|
|
4072
|
+
mandate_owners: [{ did: user.did }],
|
|
4065
4073
|
gate_content_hashes: { intent: intentHash },
|
|
4066
4074
|
execution_context_hash: ecHash,
|
|
4067
4075
|
group_id: plan.groupId,
|
|
@@ -4078,7 +4086,7 @@ async function createMandate(req, deps) {
|
|
|
4078
4086
|
refuse(`The Authority Server refused the mandate: ${why}`);
|
|
4079
4087
|
}
|
|
4080
4088
|
try {
|
|
4081
|
-
await deps.deliverGateContent({ authorizationId, boundsHash, contextHash, context: plan.context, gateContent: { intent: plan.intent } });
|
|
4089
|
+
await deps.deliverGateContent({ authorizationId, boundsHash, contextHash: scopeHash, context: plan.context, gateContent: { intent: plan.intent } });
|
|
4082
4090
|
} catch (err) {
|
|
4083
4091
|
await deps.as("POST", `/api/authorizations/${encodeURIComponent(authorizationId)}/revoke`, {
|
|
4084
4092
|
reason: "Auto-revoked: gate content delivery failed"
|
|
@@ -4960,7 +4968,7 @@ app.use(
|
|
|
4960
4968
|
const url = req.url ?? "";
|
|
4961
4969
|
if (method !== "POST" && method !== "DELETE") return;
|
|
4962
4970
|
const path = url.split("?")[0];
|
|
4963
|
-
if (method === "POST" && path === "/api/as/
|
|
4971
|
+
if (method === "POST" && path === "/api/as/mandate" || method === "POST" && /^\/api\/attestations\/[^/]+\/revoke$/.test(path) || method === "POST" && /^\/api\/authorizations\/[^/]+\/(revoke|delete)$/.test(path)) {
|
|
4964
4972
|
eventBus.emit("attestation-changed");
|
|
4965
4973
|
void resyncGates().catch(() => {
|
|
4966
4974
|
});
|
|
@@ -1053,7 +1053,7 @@ function renderReportHtml(rawHtml, elements, opts = {}) {
|
|
|
1053
1053
|
}
|
|
1054
1054
|
|
|
1055
1055
|
// src/lib/report/export-report.ts
|
|
1056
|
-
import {
|
|
1056
|
+
import { decodeMandateBlob, getProfile as getProfile2 } from "@hap/core";
|
|
1057
1057
|
function processTimeZone() {
|
|
1058
1058
|
try {
|
|
1059
1059
|
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
@@ -1074,7 +1074,7 @@ function disclosedNames(blobs) {
|
|
|
1074
1074
|
const names = /* @__PURE__ */ new Map();
|
|
1075
1075
|
for (const blob of blobs) {
|
|
1076
1076
|
try {
|
|
1077
|
-
for (const sub of
|
|
1077
|
+
for (const sub of decodeMandateBlob(blob).payload.subjects ?? []) {
|
|
1078
1078
|
if (sub.assurance === "high" && sub.disclose?.name) {
|
|
1079
1079
|
if (!names.has(sub.did)) names.set(sub.did, /* @__PURE__ */ new Set());
|
|
1080
1080
|
names.get(sub.did).add(sub.disclose.name);
|
|
@@ -1089,7 +1089,7 @@ function firstOwnerDids(auth) {
|
|
|
1089
1089
|
const blob = auth?.attestations[0]?.blob;
|
|
1090
1090
|
if (!blob) return [];
|
|
1091
1091
|
try {
|
|
1092
|
-
return
|
|
1092
|
+
return (decodeMandateBlob(blob).payload.mandate_owners ?? []).map((o) => o.did);
|
|
1093
1093
|
} catch {
|
|
1094
1094
|
return [];
|
|
1095
1095
|
}
|
|
@@ -1267,10 +1267,16 @@ function isExportBundle(v) {
|
|
|
1267
1267
|
|
|
1268
1268
|
// src/lib/report/verify-export.ts
|
|
1269
1269
|
import { Parser as Parser2 } from "htmlparser2";
|
|
1270
|
-
import {
|
|
1270
|
+
import { verifyTicketSignature as verifyTicketSignature2, verifyMandateSignature as verifyMandateSignature4, decodeMandateBlob as decodeMandateBlob5, computeBoundsHash } from "@hap/core";
|
|
1271
|
+
|
|
1272
|
+
// src/lib/issuer-from-hex.ts
|
|
1273
|
+
import { encodeDidKey } from "@hap/core";
|
|
1274
|
+
function issuerFromPublicKeyHex(publicKeyHex) {
|
|
1275
|
+
return encodeDidKey(Buffer.from(publicKeyHex, "hex"));
|
|
1276
|
+
}
|
|
1271
1277
|
|
|
1272
1278
|
// src/lib/report/verify-drawn.ts
|
|
1273
|
-
import { computeIntentHash,
|
|
1279
|
+
import { computeIntentHash, decodeMandateBlob as decodeMandateBlob4, verifyMandateSignature as verifyMandateSignature3 } from "@hap/core";
|
|
1274
1280
|
|
|
1275
1281
|
// src/lib/report/metric-resolvers.ts
|
|
1276
1282
|
var METRIC_KINDS = [
|
|
@@ -1335,10 +1341,10 @@ function computeMetric(kind, cases, refusalTimes = []) {
|
|
|
1335
1341
|
}
|
|
1336
1342
|
|
|
1337
1343
|
// src/lib/report/ticket-resolvers.ts
|
|
1338
|
-
import {
|
|
1344
|
+
import { verifyTicketSignature, verifyMandateSignature as verifyMandateSignature2, decodeMandateBlob as decodeMandateBlob3 } from "@hap/core";
|
|
1339
1345
|
|
|
1340
1346
|
// src/lib/report/identity.ts
|
|
1341
|
-
import {
|
|
1347
|
+
import { decodeMandateBlob as decodeMandateBlob2, verifyMandateSignature } from "@hap/core";
|
|
1342
1348
|
var cache = /* @__PURE__ */ new WeakMap();
|
|
1343
1349
|
function cacheKey(archive) {
|
|
1344
1350
|
const auths = archive.getAuthorizations();
|
|
@@ -1353,14 +1359,13 @@ async function build(archive) {
|
|
|
1353
1359
|
if (!key2) continue;
|
|
1354
1360
|
for (const att of auth.attestations) {
|
|
1355
1361
|
try {
|
|
1356
|
-
const
|
|
1357
|
-
await
|
|
1358
|
-
for (const s of
|
|
1362
|
+
const mandate = decodeMandateBlob2(att.blob);
|
|
1363
|
+
await verifyMandateSignature(mandate, { trustedIssuers: [issuerFromPublicKeyHex(key2)] });
|
|
1364
|
+
for (const s of mandate.payload.subjects ?? []) {
|
|
1359
1365
|
if (s.assurance === "high" && s.disclose?.name && !names.has(s.did)) names.set(s.did, s.disclose.name);
|
|
1360
1366
|
}
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
}
|
|
1367
|
+
const ownerDid = mandate.payload.mandate_owners?.[0]?.did;
|
|
1368
|
+
if (att.domain && ownerDid && !domainDids.has(att.domain)) domainDids.set(att.domain, ownerDid);
|
|
1364
1369
|
} catch {
|
|
1365
1370
|
}
|
|
1366
1371
|
}
|
|
@@ -1486,7 +1491,9 @@ async function checkTicket(archive, ticketId2) {
|
|
|
1486
1491
|
return { ok: false, reason: `Ticket "${ticketId2}" has no archived Authority Server key to verify it against.`, entry };
|
|
1487
1492
|
}
|
|
1488
1493
|
try {
|
|
1489
|
-
await
|
|
1494
|
+
await verifyTicketSignature(entry.receipt, {
|
|
1495
|
+
trustedIssuers: [issuerFromPublicKeyHex(entry.asPublicKey)]
|
|
1496
|
+
});
|
|
1490
1497
|
} catch (err) {
|
|
1491
1498
|
return {
|
|
1492
1499
|
ok: false,
|
|
@@ -1583,11 +1590,13 @@ async function resolveMandateElement(archive, ticketRef) {
|
|
|
1583
1590
|
const firstBlob = auth.attestations[0]?.blob;
|
|
1584
1591
|
if (firstBlob && check.entry.asPublicKey) {
|
|
1585
1592
|
try {
|
|
1586
|
-
const
|
|
1587
|
-
await
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1593
|
+
const mandate = decodeMandateBlob3(firstBlob);
|
|
1594
|
+
await verifyMandateSignature2(mandate, {
|
|
1595
|
+
trustedIssuers: [issuerFromPublicKeyHex(check.entry.asPublicKey)]
|
|
1596
|
+
});
|
|
1597
|
+
mode = mandate.payload.commitment_mode;
|
|
1598
|
+
const dids = (mandate.payload.mandate_owners ?? []).map((o) => o.did);
|
|
1599
|
+
const subjects = mandate.payload.subjects ?? [];
|
|
1591
1600
|
ownersRaw = dids;
|
|
1592
1601
|
const dir = await getIdentityDirectory(archive);
|
|
1593
1602
|
owners = dids.map((did) => {
|
|
@@ -1787,9 +1796,9 @@ function checkDocumentReproduces(bundle, documentHtml) {
|
|
|
1787
1796
|
}
|
|
1788
1797
|
async function verifiedPayload(blob, publicKeyHex) {
|
|
1789
1798
|
try {
|
|
1790
|
-
const
|
|
1791
|
-
await
|
|
1792
|
-
return
|
|
1799
|
+
const mandate = decodeMandateBlob4(blob);
|
|
1800
|
+
await verifyMandateSignature3(mandate, { trustedIssuers: [issuerFromPublicKeyHex(publicKeyHex)] });
|
|
1801
|
+
return mandate.payload;
|
|
1793
1802
|
} catch {
|
|
1794
1803
|
return null;
|
|
1795
1804
|
}
|
|
@@ -1996,7 +2005,7 @@ function checkMandateFields(ctx, att, m, r, box, prefix) {
|
|
|
1996
2005
|
}
|
|
1997
2006
|
}
|
|
1998
2007
|
function checkOwners(att, payload, labels, box, prefix) {
|
|
1999
|
-
const dids = payload.
|
|
2008
|
+
const dids = (payload.mandate_owners ?? []).map((o) => o.did);
|
|
2000
2009
|
if (labels.length !== dids.length) {
|
|
2001
2010
|
box.mismatches.push(`${prefix}owner: the box shows ${labels.length} owner(s), the signed mandate names ${dids.length}.`);
|
|
2002
2011
|
return;
|
|
@@ -2243,8 +2252,8 @@ async function checkAttestations(auth, publicKeyHex) {
|
|
|
2243
2252
|
}
|
|
2244
2253
|
for (const att of auth.attestations) {
|
|
2245
2254
|
try {
|
|
2246
|
-
const
|
|
2247
|
-
await
|
|
2255
|
+
const mandate = decodeMandateBlob5(att.blob);
|
|
2256
|
+
await verifyMandateSignature4(mandate, { trustedIssuers: [issuerFromPublicKeyHex(publicKeyHex)] });
|
|
2248
2257
|
} catch (err) {
|
|
2249
2258
|
return { valid: false, error: err instanceof Error ? err.message : String(err) };
|
|
2250
2259
|
}
|
|
@@ -2263,7 +2272,9 @@ async function verifyExportBundle(bundle, opts = {}) {
|
|
|
2263
2272
|
continue;
|
|
2264
2273
|
}
|
|
2265
2274
|
try {
|
|
2266
|
-
await
|
|
2275
|
+
await verifyTicketSignature2(receipt, {
|
|
2276
|
+
trustedIssuers: [issuerFromPublicKeyHex(bundle.authorityServer.publicKeyHex)]
|
|
2277
|
+
});
|
|
2267
2278
|
tickets.push({ ticketId: id, referenced: referencedIds.has(id), present: true, signatureValid: true });
|
|
2268
2279
|
} catch (err) {
|
|
2269
2280
|
tickets.push({
|
|
@@ -2283,7 +2294,7 @@ async function verifyExportBundle(bundle, opts = {}) {
|
|
|
2283
2294
|
if (auth.boundsHash) hashes.push({ from: "the mandate record", value: auth.boundsHash, signed: false });
|
|
2284
2295
|
for (const att of auth.attestations) {
|
|
2285
2296
|
try {
|
|
2286
|
-
const bh =
|
|
2297
|
+
const bh = decodeMandateBlob5(att.blob).payload.bounds_hash;
|
|
2287
2298
|
if (bh) hashes.push({ from: "the signed attestation", value: bh, signed: attestationValid });
|
|
2288
2299
|
} catch {
|
|
2289
2300
|
}
|
|
@@ -2379,6 +2390,7 @@ function resolveKeyConfirmation(actualKeyHex, opts) {
|
|
|
2379
2390
|
export {
|
|
2380
2391
|
readPairing,
|
|
2381
2392
|
fingerprintOf,
|
|
2393
|
+
issuerFromPublicKeyHex,
|
|
2382
2394
|
REPORT_ELEMENTS,
|
|
2383
2395
|
REPORT_BRIEF,
|
|
2384
2396
|
sanitizeReport,
|