@suveren/gateway 0.19.5 → 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/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 +308 -97
- package/dist/mcp-server/report-verify-cli.mjs +1 -1
- package/dist/ui/assets/index-1gCMlbLl.js +116 -0
- package/dist/ui/index.html +1 -1
- 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-Du68zJhH.js +0 -116
- package/node_modules/@hap/core/src/attestation.ts +0 -173
- package/node_modules/@hap/core/src/receipt.ts +0 -74
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Attestation Encoding, Decoding, and Verification
|
|
3
|
-
*
|
|
4
|
-
* Supports both v0.3 (frame_hash) and v0.4 (bounds_hash + context_hash).
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { createHash } from 'crypto';
|
|
8
|
-
import * as ed from '@noble/ed25519';
|
|
9
|
-
import type { Attestation, AttestationPayload } from './types';
|
|
10
|
-
import { canonicalize } from './canonicalize';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Decodes a base64url-encoded attestation blob.
|
|
14
|
-
*/
|
|
15
|
-
export function decodeAttestationBlob(blob: string): Attestation {
|
|
16
|
-
try {
|
|
17
|
-
const base64 = blob.replace(/-/g, '+').replace(/_/g, '/');
|
|
18
|
-
const padding = base64.length % 4 === 0 ? '' : '='.repeat(4 - (base64.length % 4));
|
|
19
|
-
const json = Buffer.from(base64 + padding, 'base64').toString('utf8');
|
|
20
|
-
return JSON.parse(json);
|
|
21
|
-
} catch {
|
|
22
|
-
throw new Error('MALFORMED_ATTESTATION: Failed to decode attestation blob');
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Encodes an attestation as a base64url blob (no padding).
|
|
28
|
-
*/
|
|
29
|
-
export function encodeAttestationBlob(attestation: Attestation): string {
|
|
30
|
-
const json = JSON.stringify(attestation);
|
|
31
|
-
const base64 = Buffer.from(json, 'utf8').toString('base64');
|
|
32
|
-
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Computes the attestation ID (hash of the blob).
|
|
37
|
-
*/
|
|
38
|
-
export function attestationId(blob: string): string {
|
|
39
|
-
const hash = createHash('sha256').update(blob, 'utf8').digest('hex');
|
|
40
|
-
return `sha256:${hash}`;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Verifies an attestation signature using the SP public key.
|
|
45
|
-
*
|
|
46
|
-
* @returns true if valid
|
|
47
|
-
* @throws Error with code prefix if invalid
|
|
48
|
-
*/
|
|
49
|
-
export async function verifyAttestationSignature(
|
|
50
|
-
attestation: Attestation,
|
|
51
|
-
publicKeyHex: string
|
|
52
|
-
): Promise<void> {
|
|
53
|
-
try {
|
|
54
|
-
// JCS-canonical bytes (RFC 8785) — must match the canonicalization the
|
|
55
|
-
// signer used. The AS signs the same canonical form (see keys.ts).
|
|
56
|
-
const payloadJson = canonicalize(attestation.payload);
|
|
57
|
-
const payloadBytes = new TextEncoder().encode(payloadJson);
|
|
58
|
-
const signatureBytes = Buffer.from(attestation.signature, 'base64');
|
|
59
|
-
const publicKeyBytes = Buffer.from(publicKeyHex, 'hex');
|
|
60
|
-
|
|
61
|
-
const isValid = await ed.verifyAsync(signatureBytes, payloadBytes, publicKeyBytes);
|
|
62
|
-
|
|
63
|
-
if (!isValid) {
|
|
64
|
-
throw new Error('INVALID_SIGNATURE: Attestation signature verification failed');
|
|
65
|
-
}
|
|
66
|
-
} catch (error) {
|
|
67
|
-
if (error instanceof Error && error.message.startsWith('INVALID_SIGNATURE')) throw error;
|
|
68
|
-
throw new Error(`INVALID_SIGNATURE: Signature verification error: ${error}`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Checks if an attestation has expired.
|
|
74
|
-
*
|
|
75
|
-
* @throws Error if expired
|
|
76
|
-
*/
|
|
77
|
-
export function checkAttestationExpiry(
|
|
78
|
-
payload: AttestationPayload,
|
|
79
|
-
now: number = Math.floor(Date.now() / 1000)
|
|
80
|
-
): void {
|
|
81
|
-
if (payload.expires_at <= now) {
|
|
82
|
-
throw new Error(
|
|
83
|
-
`TTL_EXPIRED: Attestation expired at ${payload.expires_at}, current time is ${now}`
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Verifies that the frame hash in the attestation matches the expected hash (v0.3).
|
|
90
|
-
*
|
|
91
|
-
* @throws Error if frame hash doesn't match
|
|
92
|
-
*/
|
|
93
|
-
export function verifyFrameHash(attestation: Attestation, expectedFrameHash: string): void {
|
|
94
|
-
if (attestation.payload.frame_hash !== expectedFrameHash) {
|
|
95
|
-
throw new Error('FRAME_MISMATCH: Frame hash mismatch');
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Detects whether an attestation is v0.4 (has bounds_hash + context_hash)
|
|
101
|
-
* or v0.3 (has frame_hash).
|
|
102
|
-
*
|
|
103
|
-
* Migration rule: if attestation has frame_hash but not bounds_hash, it is v0.3.
|
|
104
|
-
*/
|
|
105
|
-
export function isV4Attestation(attestation: Attestation): boolean {
|
|
106
|
-
return attestation.payload.bounds_hash !== undefined;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Verifies that the bounds hash in the attestation matches the expected hash (v0.4).
|
|
111
|
-
*
|
|
112
|
-
* @throws Error if bounds hash doesn't match
|
|
113
|
-
*/
|
|
114
|
-
export function verifyBoundsHash(attestation: Attestation, expectedBoundsHash: string): void {
|
|
115
|
-
// Migration: if attestation has frame_hash but not bounds_hash, treat frame_hash as bounds_hash
|
|
116
|
-
const attestedHash = attestation.payload.bounds_hash ?? attestation.payload.frame_hash;
|
|
117
|
-
if (attestedHash !== expectedBoundsHash) {
|
|
118
|
-
throw new Error('BOUNDS_MISMATCH: Bounds hash mismatch');
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Verifies that the context hash in the attestation matches the expected hash (v0.4).
|
|
124
|
-
*
|
|
125
|
-
* @throws Error if context hash doesn't match
|
|
126
|
-
*/
|
|
127
|
-
export function verifyContextHash(attestation: Attestation, expectedContextHash: string): void {
|
|
128
|
-
if (attestation.payload.context_hash !== expectedContextHash) {
|
|
129
|
-
throw new Error('CONTEXT_MISMATCH: Context hash mismatch');
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Full attestation verification (signature + expiry + frame hash) — v0.3.
|
|
135
|
-
*
|
|
136
|
-
* @returns The decoded attestation payload
|
|
137
|
-
* @throws Error on any validation failure
|
|
138
|
-
*/
|
|
139
|
-
export async function verifyAttestation(
|
|
140
|
-
blob: string,
|
|
141
|
-
publicKeyHex: string,
|
|
142
|
-
expectedFrameHash: string
|
|
143
|
-
): Promise<AttestationPayload> {
|
|
144
|
-
const attestation = decodeAttestationBlob(blob);
|
|
145
|
-
|
|
146
|
-
await verifyAttestationSignature(attestation, publicKeyHex);
|
|
147
|
-
checkAttestationExpiry(attestation.payload);
|
|
148
|
-
verifyFrameHash(attestation, expectedFrameHash);
|
|
149
|
-
|
|
150
|
-
return attestation.payload;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Full attestation verification for v0.4 (signature + expiry + bounds_hash + context_hash).
|
|
155
|
-
*
|
|
156
|
-
* @returns The decoded attestation payload
|
|
157
|
-
* @throws Error on any validation failure
|
|
158
|
-
*/
|
|
159
|
-
export async function verifyAttestationV4(
|
|
160
|
-
blob: string,
|
|
161
|
-
publicKeyHex: string,
|
|
162
|
-
expectedBoundsHash: string,
|
|
163
|
-
expectedContextHash: string
|
|
164
|
-
): Promise<AttestationPayload> {
|
|
165
|
-
const attestation = decodeAttestationBlob(blob);
|
|
166
|
-
|
|
167
|
-
await verifyAttestationSignature(attestation, publicKeyHex);
|
|
168
|
-
checkAttestationExpiry(attestation.payload);
|
|
169
|
-
verifyBoundsHash(attestation, expectedBoundsHash);
|
|
170
|
-
verifyContextHash(attestation, expectedContextHash);
|
|
171
|
-
|
|
172
|
-
return attestation.payload;
|
|
173
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Execution receipts (HAP v0.5/v0.6) — the wire type and holder-side
|
|
3
|
-
* verification. Until v0.6 this library had no receipt surface at all; every
|
|
4
|
-
* verifier hand-assembled the strip→canonicalize→verify dance. This module is
|
|
5
|
-
* that dance, once.
|
|
6
|
-
*
|
|
7
|
-
* Receipt payloads are camelCase on the wire (unlike the snake_case
|
|
8
|
-
* attestation payload) — a shipped inconsistency v0.6 chose to document
|
|
9
|
-
* rather than break (changelog.md → "Renames and terminology").
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import * as ed from '@noble/ed25519';
|
|
13
|
-
import type { ContentBinding, Subject } from './types';
|
|
14
|
-
import { canonicalize } from './canonicalize';
|
|
15
|
-
|
|
16
|
-
/** Signed execution receipt — protocol.md → "Receipt Payload Schema". */
|
|
17
|
-
export interface ReceiptPayload {
|
|
18
|
-
id: string;
|
|
19
|
-
groupId?: string | null;
|
|
20
|
-
userId?: string;
|
|
21
|
-
boundsHash: string;
|
|
22
|
-
profileId: string;
|
|
23
|
-
/** Downstream tool name. Audit metadata only — never a dispatch key. */
|
|
24
|
-
action: string;
|
|
25
|
-
/** Semantic category — drives cumulative bucketing and bounds dispatch. */
|
|
26
|
-
actionType: string;
|
|
27
|
-
executionContext: Record<string, unknown>;
|
|
28
|
-
cumulativeState?: Record<string, unknown>;
|
|
29
|
-
limits?: Record<string, unknown>;
|
|
30
|
-
timestamp: number;
|
|
31
|
-
/** v0.6 — hash of the bound content, computed by the Gatekeeper, copied
|
|
32
|
-
* verbatim by the AS. The AS never sees the content. */
|
|
33
|
-
contentHash?: string;
|
|
34
|
-
/** v0.6 — the binding declaration echoed into the signed receipt, so a
|
|
35
|
-
* verifier knows exactly what `contentHash` covers. */
|
|
36
|
-
contentBinding?: Pick<ContentBinding, 'version' | 'kind' | 'fields' | 'required_fields' | 'appliesTo'>;
|
|
37
|
-
/** v0.6 — disclosed subset of the attestation's identity overlay. */
|
|
38
|
-
subjects?: Subject[];
|
|
39
|
-
/** v0.6 — review path: the proposal this receipt executed. */
|
|
40
|
-
proposalId?: string;
|
|
41
|
-
/** v0.6 — review path: the owner's HAP-approval signature (or its sha256)
|
|
42
|
-
* for the executed proposal. */
|
|
43
|
-
approvalSignature?: string;
|
|
44
|
-
/** Ed25519 over the JCS-canonical payload (this field excluded), base64url. */
|
|
45
|
-
signature: string;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Verify a receipt's AS signature: strip `signature`, JCS-canonicalize the
|
|
50
|
-
* rest, Ed25519-verify against the AS public key (hex). This is holder-side
|
|
51
|
-
* verification — it needs the COMPLETE receipt; a redacted public view cannot
|
|
52
|
-
* be re-verified this way (protocol.md → "Receipt Verification").
|
|
53
|
-
*
|
|
54
|
-
* Content is checked separately: where `contentHash` is present, recompute it
|
|
55
|
-
* from the held artifact via the content-binding module and compare.
|
|
56
|
-
*
|
|
57
|
-
* @throws Error prefixed `INVALID_SIGNATURE:` when verification fails.
|
|
58
|
-
*/
|
|
59
|
-
export async function verifyReceiptSignature(receipt: ReceiptPayload, publicKeyHex: string): Promise<void> {
|
|
60
|
-
const { signature, ...unsigned } = receipt;
|
|
61
|
-
if (!signature) {
|
|
62
|
-
throw new Error('INVALID_SIGNATURE: receipt carries no signature');
|
|
63
|
-
}
|
|
64
|
-
const bytes = new TextEncoder().encode(canonicalize(unsigned));
|
|
65
|
-
const base64 = signature.replace(/-/g, '+').replace(/_/g, '/');
|
|
66
|
-
const padding = base64.length % 4 === 0 ? '' : '='.repeat(4 - (base64.length % 4));
|
|
67
|
-
const sigBytes = new Uint8Array(Buffer.from(base64 + padding, 'base64'));
|
|
68
|
-
const publicKeyBytes = new Uint8Array(Buffer.from(publicKeyHex, 'hex'));
|
|
69
|
-
|
|
70
|
-
const ok = await ed.verifyAsync(sigBytes, bytes, publicKeyBytes).catch(() => false);
|
|
71
|
-
if (!ok) {
|
|
72
|
-
throw new Error('INVALID_SIGNATURE: receipt signature verification failed');
|
|
73
|
-
}
|
|
74
|
-
}
|