@suveren/gateway 0.7.6 → 0.8.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/mollie.json +103 -28
- package/dist/mcp-server/http.mjs +228 -118
- package/dist/ui/assets/{index-CsrM6RQr.js → index-BFnSVa9N.js} +22 -22
- package/dist/ui/index.html +1 -1
- package/node_modules/@hap/core/dist/index.d.mts +29 -6
- package/node_modules/@hap/core/dist/index.d.ts +29 -6
- package/node_modules/@hap/core/dist/index.js +54 -8
- package/node_modules/@hap/core/dist/index.mjs +53 -8
- package/node_modules/@hap/core/package.json +2 -1
- package/node_modules/@hap/core/src/frame.ts +115 -14
- package/node_modules/@hap/core/src/gatekeeper.ts +26 -0
- package/node_modules/@hap/core/src/types.ts +7 -1
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/buffer.buffer.d.ts +5 -0
- package/node_modules/@types/node/crypto.d.ts +0 -2
- package/node_modules/@types/node/dgram.d.ts +119 -4
- package/node_modules/@types/node/ffi.d.ts +1 -1
- package/node_modules/@types/node/fs/promises.d.ts +61 -65
- package/node_modules/@types/node/fs.d.ts +86 -76
- package/node_modules/@types/node/http.d.ts +1 -1
- package/node_modules/@types/node/http2.d.ts +2 -2
- package/node_modules/@types/node/index.d.ts +1 -0
- package/node_modules/@types/node/inspector.d.ts +2 -1
- package/node_modules/@types/node/net.d.ts +108 -16
- package/node_modules/@types/node/package.json +2 -2
- package/node_modules/@types/node/quic.d.ts +37 -11
- package/node_modules/@types/node/stream/iter.d.ts +4 -4
- package/node_modules/@types/node/tls.d.ts +24 -0
- package/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +5 -0
- package/node_modules/@types/node/ts5.6/index.d.ts +1 -0
- package/node_modules/@types/node/ts5.7/index.d.ts +1 -0
- package/node_modules/@types/node/tty.d.ts +4 -3
- package/node_modules/@types/node/vfs.d.ts +210 -0
- package/node_modules/@types/node/vm.d.ts +1 -1
- package/node_modules/express-rate-limit/dist/index.cjs +6 -3
- package/node_modules/express-rate-limit/dist/index.d.cts +11 -0
- package/node_modules/express-rate-limit/dist/index.d.mts +11 -0
- package/node_modules/express-rate-limit/dist/index.d.ts +11 -0
- package/node_modules/express-rate-limit/dist/index.mjs +6 -3
- package/node_modules/express-rate-limit/{license.md → license} +7 -6
- package/node_modules/express-rate-limit/package.json +5 -5
- package/node_modules/express-rate-limit/readme.md +1 -0
- package/node_modules/fast-uri/index.js +20 -5
- package/node_modules/fast-uri/lib/utils.js +8 -1
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/fast-uri/test/component-safe-serialization.test.js +58 -0
- package/node_modules/fast-uri/test/ipv6-validation.test.js +34 -0
- package/node_modules/ip-address/README.md +92 -82
- package/node_modules/ip-address/dist/common.d.ts +20 -0
- package/node_modules/ip-address/dist/common.js +36 -0
- package/node_modules/ip-address/dist/common.js.map +1 -1
- package/node_modules/ip-address/dist/ipv4.d.ts +50 -0
- package/node_modules/ip-address/dist/ipv4.js +75 -0
- package/node_modules/ip-address/dist/ipv4.js.map +1 -1
- package/node_modules/ip-address/dist/ipv6.d.ts +79 -10
- package/node_modules/ip-address/dist/ipv6.js +120 -30
- package/node_modules/ip-address/dist/ipv6.js.map +1 -1
- package/node_modules/ip-address/dist/v4/constants.d.ts +12 -0
- package/node_modules/ip-address/dist/v4/constants.js +40 -1
- package/node_modules/ip-address/dist/v4/constants.js.map +1 -1
- package/node_modules/ip-address/dist/v6/constants.d.ts +14 -0
- package/node_modules/ip-address/dist/v6/constants.js +47 -1
- package/node_modules/ip-address/dist/v6/constants.js.map +1 -1
- package/node_modules/ip-address/package.json +1 -1
- package/node_modules/jose/dist/types/jwe/compact/decrypt.d.ts +7 -16
- package/node_modules/jose/dist/types/jwe/compact/encrypt.d.ts +6 -17
- package/node_modules/jose/dist/types/jwe/flattened/decrypt.d.ts +7 -16
- package/node_modules/jose/dist/types/jwe/flattened/encrypt.d.ts +11 -34
- package/node_modules/jose/dist/types/jwe/general/decrypt.d.ts +7 -16
- package/node_modules/jose/dist/types/jwe/general/encrypt.d.ts +15 -35
- package/node_modules/jose/dist/types/jwk/embedded.d.ts +3 -8
- package/node_modules/jose/dist/types/jwk/thumbprint.d.ts +5 -5
- package/node_modules/jose/dist/types/jwks/local.d.ts +6 -10
- package/node_modules/jose/dist/types/jwks/remote.d.ts +13 -24
- package/node_modules/jose/dist/types/jws/compact/sign.d.ts +5 -10
- package/node_modules/jose/dist/types/jws/compact/verify.d.ts +9 -18
- package/node_modules/jose/dist/types/jws/flattened/sign.d.ts +7 -16
- package/node_modules/jose/dist/types/jws/flattened/verify.d.ts +9 -18
- package/node_modules/jose/dist/types/jws/general/sign.d.ts +11 -21
- package/node_modules/jose/dist/types/jws/general/verify.d.ts +9 -18
- package/node_modules/jose/dist/types/jwt/decrypt.d.ts +10 -20
- package/node_modules/jose/dist/types/jwt/encrypt.d.ts +6 -13
- package/node_modules/jose/dist/types/jwt/sign.d.ts +5 -6
- package/node_modules/jose/dist/types/jwt/unsecured.d.ts +9 -14
- package/node_modules/jose/dist/types/jwt/verify.d.ts +9 -19
- package/node_modules/jose/dist/types/key/export.d.ts +4 -4
- package/node_modules/jose/dist/types/key/generate_key_pair.d.ts +6 -8
- package/node_modules/jose/dist/types/key/generate_secret.d.ts +4 -11
- package/node_modules/jose/dist/types/key/import.d.ts +10 -17
- package/node_modules/jose/dist/types/types.d.ts +44 -84
- package/node_modules/jose/dist/types/util/base64url.d.ts +2 -2
- package/node_modules/jose/dist/types/util/decode_jwt.d.ts +3 -10
- package/node_modules/jose/dist/types/util/decode_protected_header.d.ts +4 -4
- package/node_modules/jose/dist/types/util/errors.d.ts +26 -53
- package/node_modules/jose/dist/webapi/index.js +70 -32
- package/node_modules/jose/dist/webapi/jwe/compact/decrypt.js +7 -8
- package/node_modules/jose/dist/webapi/jwe/compact/encrypt.js +42 -48
- package/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +14 -14
- package/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +53 -64
- package/node_modules/jose/dist/webapi/jwe/general/decrypt.js +38 -49
- package/node_modules/jose/dist/webapi/jwe/general/encrypt.js +121 -169
- package/node_modules/jose/dist/webapi/jwk/embedded.js +30 -32
- package/node_modules/jose/dist/webapi/jwk/thumbprint.js +54 -70
- package/node_modules/jose/dist/webapi/jwks/local.js +47 -64
- package/node_modules/jose/dist/webapi/jwks/remote.js +88 -136
- package/node_modules/jose/dist/webapi/jws/compact/sign.js +21 -21
- package/node_modules/jose/dist/webapi/jws/compact/verify.js +7 -8
- package/node_modules/jose/dist/webapi/jws/flattened/sign.js +29 -31
- package/node_modules/jose/dist/webapi/jws/flattened/verify.js +21 -24
- package/node_modules/jose/dist/webapi/jws/general/sign.js +61 -72
- package/node_modules/jose/dist/webapi/jws/general/verify.js +45 -69
- package/node_modules/jose/dist/webapi/jwt/decrypt.js +13 -20
- package/node_modules/jose/dist/webapi/jwt/encrypt.js +57 -70
- package/node_modules/jose/dist/webapi/jwt/sign.js +17 -16
- package/node_modules/jose/dist/webapi/jwt/unsecured.js +32 -40
- package/node_modules/jose/dist/webapi/jwt/verify.js +12 -14
- package/node_modules/jose/dist/webapi/key/export.js +32 -37
- package/node_modules/jose/dist/webapi/key/generate_key_pair.js +40 -48
- package/node_modules/jose/dist/webapi/key/generate_secret.js +35 -40
- package/node_modules/jose/dist/webapi/key/import.js +52 -56
- package/node_modules/jose/dist/webapi/lib/asn1.js +130 -169
- package/node_modules/jose/dist/webapi/lib/base64.js +18 -20
- package/node_modules/jose/dist/webapi/lib/buffer_utils.js +34 -38
- package/node_modules/jose/dist/webapi/lib/content_encryption.js +79 -115
- package/node_modules/jose/dist/webapi/lib/crypto_key.js +24 -25
- package/node_modules/jose/dist/webapi/lib/deflate.js +45 -47
- package/node_modules/jose/dist/webapi/lib/helpers.js +40 -37
- package/node_modules/jose/dist/webapi/lib/invalid_key_input.js +10 -24
- package/node_modules/jose/dist/webapi/lib/is_key_like.js +17 -15
- package/node_modules/jose/dist/webapi/lib/jwe_algorithms.js +106 -93
- package/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +207 -230
- package/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +104 -138
- package/node_modules/jose/dist/webapi/lib/jwk_metadata.js +17 -18
- package/node_modules/jose/dist/webapi/lib/jwk_to_key.js +9 -16
- package/node_modules/jose/dist/webapi/lib/jws_algorithms.js +62 -61
- package/node_modules/jose/dist/webapi/lib/jws_sign.js +50 -75
- package/node_modules/jose/dist/webapi/lib/jws_verify.js +80 -125
- package/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +123 -209
- package/node_modules/jose/dist/webapi/lib/key.js +84 -136
- package/node_modules/jose/dist/webapi/lib/key_algorithm.js +13 -8
- package/node_modules/jose/dist/webapi/lib/key_descriptor.js +8 -6
- package/node_modules/jose/dist/webapi/lib/key_management.js +200 -231
- package/node_modules/jose/dist/webapi/lib/key_options.js +7 -5
- package/node_modules/jose/dist/webapi/lib/options.js +55 -68
- package/node_modules/jose/dist/webapi/lib/signing.js +18 -22
- package/node_modules/jose/dist/webapi/lib/type_checks.js +26 -29
- package/node_modules/jose/dist/webapi/util/base64url.js +26 -35
- package/node_modules/jose/dist/webapi/util/decode_jwt.js +32 -31
- package/node_modules/jose/dist/webapi/util/decode_protected_header.js +18 -23
- package/node_modules/jose/dist/webapi/util/errors.js +94 -84
- package/node_modules/jose/package.json +17 -81
- package/package.json +2 -2
- package/profiles/calendar/0.5.profile.json +190 -0
- package/profiles/charge/0.5.profile.json +210 -0
- package/profiles/customers/0.7.profile.json +157 -0
- package/profiles/deploy/0.9.profile.json +176 -0
- package/profiles/email/0.6.profile.json +208 -0
- package/profiles/index.json +9 -1
- package/profiles/publish/0.5.profile.json +186 -0
- package/profiles/purchase/0.5.profile.json +231 -0
- package/profiles/records/0.5.profile.json +117 -0
package/dist/ui/index.html
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
because tab chrome does. -->
|
|
9
9
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
10
10
|
<title>Suveren</title>
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-BFnSVa9N.js"></script>
|
|
12
12
|
<link rel="stylesheet" crossorigin href="/assets/index-BYVb_0oG.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
@@ -656,7 +656,7 @@ interface GatekeeperRequest {
|
|
|
656
656
|
* Structured error from Gatekeeper verification.
|
|
657
657
|
*/
|
|
658
658
|
interface GatekeeperError {
|
|
659
|
-
code: 'BOUND_EXCEEDED' | 'CUMULATIVE_LIMIT_EXCEEDED' | 'INVALID_SIGNATURE' | 'TTL_EXPIRED' | 'FRAME_MISMATCH' | 'BOUNDS_MISMATCH' | 'CONTEXT_MISMATCH' | 'DOMAIN_NOT_COVERED' | 'INVALID_PROFILE' | 'MALFORMED_ATTESTATION' | 'INVALID_ACTION_TYPE' | 'ATTESTATION_REVOKED' | 'APPROVAL_REQUIRED' | 'IDEMPOTENCY_MISMATCH' | 'MANDATE_SIGNATURE_REQUIRED' | 'MANDATE_SIGNATURE_INVALID' | 'APPROVAL_SIGNATURE_REQUIRED' | 'APPROVAL_SIGNATURE_INVALID';
|
|
659
|
+
code: 'BOUND_EXCEEDED' | 'CUMULATIVE_LIMIT_EXCEEDED' | 'INVALID_SIGNATURE' | 'TTL_EXPIRED' | 'FRAME_MISMATCH' | 'BOUNDS_MISMATCH' | 'CONTEXT_MISMATCH' | 'DOMAIN_NOT_COVERED' | 'INVALID_PROFILE' | 'MALFORMED_ATTESTATION' | 'INVALID_ACTION_TYPE' | 'ATTESTATION_REVOKED' | 'APPROVAL_REQUIRED' | 'IDEMPOTENCY_MISMATCH' | 'MANDATE_SIGNATURE_REQUIRED' | 'MANDATE_SIGNATURE_INVALID' | 'APPROVAL_SIGNATURE_REQUIRED' | 'APPROVAL_SIGNATURE_INVALID' | 'BOUNDS_INVALID_VALUE' | 'CONTEXT_INVALID_VALUE';
|
|
660
660
|
field?: string;
|
|
661
661
|
message: string;
|
|
662
662
|
bound?: string | number;
|
|
@@ -921,8 +921,11 @@ declare function deriveIdentityLine(subject: Subject | undefined | null, { opera
|
|
|
921
921
|
* Frame Canonicalization for Agent Profiles
|
|
922
922
|
*
|
|
923
923
|
* Agent profiles support mixed-type fields (strings and numbers).
|
|
924
|
-
* Canonical form:
|
|
925
|
-
*
|
|
924
|
+
* Canonical form: `key=value` records joined with LF, keys in the profile's
|
|
925
|
+
* keyOrder. Values are stringified with String(value) — the shortest
|
|
926
|
+
* round-trippable form for numbers — then percent-encoded per protocol.md
|
|
927
|
+
* (`=`, `%`, and every byte outside printable ASCII); a value carrying a raw
|
|
928
|
+
* LF/CR is refused, never normalized. See `canonicalRecords` below.
|
|
926
929
|
*
|
|
927
930
|
* v0.3: frameSchema
|
|
928
931
|
* v0.4: boundsSchema + contextSchema (separate hashes)
|
|
@@ -966,19 +969,39 @@ declare function validateContextParams(params: AgentContextParams, profile: Agen
|
|
|
966
969
|
valid: boolean;
|
|
967
970
|
errors: string[];
|
|
968
971
|
};
|
|
972
|
+
/**
|
|
973
|
+
* Thrown when a value cannot be canonicalized at all — currently only for raw
|
|
974
|
+
* LF/CR inside a value. Carries the protocol error code so callers can map it
|
|
975
|
+
* straight onto the wire without string-matching a message.
|
|
976
|
+
*
|
|
977
|
+
* protocol.md → *Bounds & Scope Canonicalization* → Value encoding:
|
|
978
|
+
* "Values MUST NOT contain raw newline (\n) or carriage-return (\r)
|
|
979
|
+
* characters. Implementations MUST reject input containing them; silent
|
|
980
|
+
* stripping or normalization is a violation because it produces a hash that
|
|
981
|
+
* does not faithfully represent the input."
|
|
982
|
+
*/
|
|
983
|
+
declare class CanonicalValueError extends Error {
|
|
984
|
+
readonly code: 'BOUNDS_INVALID_VALUE' | 'CONTEXT_INVALID_VALUE';
|
|
985
|
+
readonly field: string;
|
|
986
|
+
constructor(code: 'BOUNDS_INVALID_VALUE' | 'CONTEXT_INVALID_VALUE', field: string, message: string);
|
|
987
|
+
}
|
|
969
988
|
/**
|
|
970
989
|
* Builds the canonical bounds string from parameters.
|
|
971
|
-
*
|
|
990
|
+
* Keys are ordered per profile's boundsSchema.keyOrder; values are encoded per
|
|
991
|
+
* protocol.md → *Value encoding* (see `canonicalRecords`).
|
|
972
992
|
*
|
|
973
993
|
* @throws Error if any field fails validation
|
|
994
|
+
* @throws CanonicalValueError (code BOUNDS_INVALID_VALUE) if a value carries a raw LF/CR
|
|
974
995
|
*/
|
|
975
996
|
declare function canonicalBounds(params: AgentBoundsParams, profile: AgentProfile): string;
|
|
976
997
|
/**
|
|
977
998
|
* Builds the canonical context string from parameters.
|
|
978
|
-
*
|
|
999
|
+
* Keys are ordered per profile's contextSchema.keyOrder; values are encoded per
|
|
1000
|
+
* protocol.md → *Value encoding* (see `canonicalRecords`).
|
|
979
1001
|
* For empty context (no contextSchema or no fields), returns "".
|
|
980
1002
|
*
|
|
981
1003
|
* @throws Error if any field fails validation
|
|
1004
|
+
* @throws CanonicalValueError (code CONTEXT_INVALID_VALUE) if a value carries a raw LF/CR
|
|
982
1005
|
*/
|
|
983
1006
|
declare function canonicalContext(params: AgentContextParams, profile: AgentProfile): string;
|
|
984
1007
|
/**
|
|
@@ -1299,4 +1322,4 @@ interface ReceiptPayload {
|
|
|
1299
1322
|
*/
|
|
1300
1323
|
declare function verifyReceiptSignature(receipt: ReceiptPayload, publicKeyHex: string): Promise<void>;
|
|
1301
1324
|
|
|
1302
|
-
export { type AgentBoundsParams, type AgentContextParams, type AgentFrameParams, type AgentProfile, type ApprovalObject, type Attestation, type AttestationHeader, type AttestationPayload, type BoundType, type ContentBinding, ContentBindingError, type ContentBindingErrorCode, type CumulativeFieldDef, type CumulativeWindow, type DeclaredFieldDef, type ExecutionContextFieldDef, type ExecutionLogEntry, type ExecutionLogQuery, type ExecutionMappingTransform, type ExecutionMappingValue, type ExecutionPath, type FieldConstraint, type FieldUnit, type GateQuestion, type GatekeeperError, type GatekeeperRequest, type GatekeeperResult, type MandateBinding, MandateError, type MandateProjection, type OwnerMandate, type ProfileBoundsField, type ProfileContextField, type ProfileFrameField, type ProfileToolGating, type ProfileToolGatingEntry, type ReceiptPayload, type ResolvedDomain, type SigningSurface, type Subject, type SubjectValidation, approvalSigningBytes, attestationId, bindingAppliesTo, buildMandateProjection, canonicalBounds, canonicalContext, canonicalFrame, canonicalize, canonicalizeText, checkAttestationExpiry, clearProfiles, computeBoundsHash, computeContentHash, computeContextHash, computeFieldsContentHash, computeFrameHash, computeIntentDisclosureHash, computeIntentHash, contentCanonicalBytes, decodeAttestationBlob, decodeDidKey, deriveIdentityLine, encodeAttestationBlob, encodeDidKey, frameHash, getAllProfiles, getProfile, intentDisclosureCanonicalBytes, isFieldBinding, isKeyBearingDid, isV4Attestation, listProfiles, mandateSigningBytes, registerProfile, selectBoundFields, signApproval, signMandateProjection, validateBoundsParams, validateContextParams, validateFrameParams, validateSubject, verify, verifyApproval, verifyAttestation, verifyAttestationSignature, verifyAttestationV4, verifyBoundsHash, verifyContextHash, verifyFrameHash, verifyOwnerMandate, verifyOwnerMandates, verifyReceiptSignature };
|
|
1325
|
+
export { type AgentBoundsParams, type AgentContextParams, type AgentFrameParams, type AgentProfile, type ApprovalObject, type Attestation, type AttestationHeader, type AttestationPayload, type BoundType, CanonicalValueError, type ContentBinding, ContentBindingError, type ContentBindingErrorCode, type CumulativeFieldDef, type CumulativeWindow, type DeclaredFieldDef, type ExecutionContextFieldDef, type ExecutionLogEntry, type ExecutionLogQuery, type ExecutionMappingTransform, type ExecutionMappingValue, type ExecutionPath, type FieldConstraint, type FieldUnit, type GateQuestion, type GatekeeperError, type GatekeeperRequest, type GatekeeperResult, type MandateBinding, MandateError, type MandateProjection, type OwnerMandate, type ProfileBoundsField, type ProfileContextField, type ProfileFrameField, type ProfileToolGating, type ProfileToolGatingEntry, type ReceiptPayload, type ResolvedDomain, type SigningSurface, type Subject, type SubjectValidation, approvalSigningBytes, attestationId, bindingAppliesTo, buildMandateProjection, canonicalBounds, canonicalContext, canonicalFrame, canonicalize, canonicalizeText, checkAttestationExpiry, clearProfiles, computeBoundsHash, computeContentHash, computeContextHash, computeFieldsContentHash, computeFrameHash, computeIntentDisclosureHash, computeIntentHash, contentCanonicalBytes, decodeAttestationBlob, decodeDidKey, deriveIdentityLine, encodeAttestationBlob, encodeDidKey, frameHash, getAllProfiles, getProfile, intentDisclosureCanonicalBytes, isFieldBinding, isKeyBearingDid, isV4Attestation, listProfiles, mandateSigningBytes, registerProfile, selectBoundFields, signApproval, signMandateProjection, validateBoundsParams, validateContextParams, validateFrameParams, validateSubject, verify, verifyApproval, verifyAttestation, verifyAttestationSignature, verifyAttestationV4, verifyBoundsHash, verifyContextHash, verifyFrameHash, verifyOwnerMandate, verifyOwnerMandates, verifyReceiptSignature };
|
|
@@ -656,7 +656,7 @@ interface GatekeeperRequest {
|
|
|
656
656
|
* Structured error from Gatekeeper verification.
|
|
657
657
|
*/
|
|
658
658
|
interface GatekeeperError {
|
|
659
|
-
code: 'BOUND_EXCEEDED' | 'CUMULATIVE_LIMIT_EXCEEDED' | 'INVALID_SIGNATURE' | 'TTL_EXPIRED' | 'FRAME_MISMATCH' | 'BOUNDS_MISMATCH' | 'CONTEXT_MISMATCH' | 'DOMAIN_NOT_COVERED' | 'INVALID_PROFILE' | 'MALFORMED_ATTESTATION' | 'INVALID_ACTION_TYPE' | 'ATTESTATION_REVOKED' | 'APPROVAL_REQUIRED' | 'IDEMPOTENCY_MISMATCH' | 'MANDATE_SIGNATURE_REQUIRED' | 'MANDATE_SIGNATURE_INVALID' | 'APPROVAL_SIGNATURE_REQUIRED' | 'APPROVAL_SIGNATURE_INVALID';
|
|
659
|
+
code: 'BOUND_EXCEEDED' | 'CUMULATIVE_LIMIT_EXCEEDED' | 'INVALID_SIGNATURE' | 'TTL_EXPIRED' | 'FRAME_MISMATCH' | 'BOUNDS_MISMATCH' | 'CONTEXT_MISMATCH' | 'DOMAIN_NOT_COVERED' | 'INVALID_PROFILE' | 'MALFORMED_ATTESTATION' | 'INVALID_ACTION_TYPE' | 'ATTESTATION_REVOKED' | 'APPROVAL_REQUIRED' | 'IDEMPOTENCY_MISMATCH' | 'MANDATE_SIGNATURE_REQUIRED' | 'MANDATE_SIGNATURE_INVALID' | 'APPROVAL_SIGNATURE_REQUIRED' | 'APPROVAL_SIGNATURE_INVALID' | 'BOUNDS_INVALID_VALUE' | 'CONTEXT_INVALID_VALUE';
|
|
660
660
|
field?: string;
|
|
661
661
|
message: string;
|
|
662
662
|
bound?: string | number;
|
|
@@ -921,8 +921,11 @@ declare function deriveIdentityLine(subject: Subject | undefined | null, { opera
|
|
|
921
921
|
* Frame Canonicalization for Agent Profiles
|
|
922
922
|
*
|
|
923
923
|
* Agent profiles support mixed-type fields (strings and numbers).
|
|
924
|
-
* Canonical form:
|
|
925
|
-
*
|
|
924
|
+
* Canonical form: `key=value` records joined with LF, keys in the profile's
|
|
925
|
+
* keyOrder. Values are stringified with String(value) — the shortest
|
|
926
|
+
* round-trippable form for numbers — then percent-encoded per protocol.md
|
|
927
|
+
* (`=`, `%`, and every byte outside printable ASCII); a value carrying a raw
|
|
928
|
+
* LF/CR is refused, never normalized. See `canonicalRecords` below.
|
|
926
929
|
*
|
|
927
930
|
* v0.3: frameSchema
|
|
928
931
|
* v0.4: boundsSchema + contextSchema (separate hashes)
|
|
@@ -966,19 +969,39 @@ declare function validateContextParams(params: AgentContextParams, profile: Agen
|
|
|
966
969
|
valid: boolean;
|
|
967
970
|
errors: string[];
|
|
968
971
|
};
|
|
972
|
+
/**
|
|
973
|
+
* Thrown when a value cannot be canonicalized at all — currently only for raw
|
|
974
|
+
* LF/CR inside a value. Carries the protocol error code so callers can map it
|
|
975
|
+
* straight onto the wire without string-matching a message.
|
|
976
|
+
*
|
|
977
|
+
* protocol.md → *Bounds & Scope Canonicalization* → Value encoding:
|
|
978
|
+
* "Values MUST NOT contain raw newline (\n) or carriage-return (\r)
|
|
979
|
+
* characters. Implementations MUST reject input containing them; silent
|
|
980
|
+
* stripping or normalization is a violation because it produces a hash that
|
|
981
|
+
* does not faithfully represent the input."
|
|
982
|
+
*/
|
|
983
|
+
declare class CanonicalValueError extends Error {
|
|
984
|
+
readonly code: 'BOUNDS_INVALID_VALUE' | 'CONTEXT_INVALID_VALUE';
|
|
985
|
+
readonly field: string;
|
|
986
|
+
constructor(code: 'BOUNDS_INVALID_VALUE' | 'CONTEXT_INVALID_VALUE', field: string, message: string);
|
|
987
|
+
}
|
|
969
988
|
/**
|
|
970
989
|
* Builds the canonical bounds string from parameters.
|
|
971
|
-
*
|
|
990
|
+
* Keys are ordered per profile's boundsSchema.keyOrder; values are encoded per
|
|
991
|
+
* protocol.md → *Value encoding* (see `canonicalRecords`).
|
|
972
992
|
*
|
|
973
993
|
* @throws Error if any field fails validation
|
|
994
|
+
* @throws CanonicalValueError (code BOUNDS_INVALID_VALUE) if a value carries a raw LF/CR
|
|
974
995
|
*/
|
|
975
996
|
declare function canonicalBounds(params: AgentBoundsParams, profile: AgentProfile): string;
|
|
976
997
|
/**
|
|
977
998
|
* Builds the canonical context string from parameters.
|
|
978
|
-
*
|
|
999
|
+
* Keys are ordered per profile's contextSchema.keyOrder; values are encoded per
|
|
1000
|
+
* protocol.md → *Value encoding* (see `canonicalRecords`).
|
|
979
1001
|
* For empty context (no contextSchema or no fields), returns "".
|
|
980
1002
|
*
|
|
981
1003
|
* @throws Error if any field fails validation
|
|
1004
|
+
* @throws CanonicalValueError (code CONTEXT_INVALID_VALUE) if a value carries a raw LF/CR
|
|
982
1005
|
*/
|
|
983
1006
|
declare function canonicalContext(params: AgentContextParams, profile: AgentProfile): string;
|
|
984
1007
|
/**
|
|
@@ -1299,4 +1322,4 @@ interface ReceiptPayload {
|
|
|
1299
1322
|
*/
|
|
1300
1323
|
declare function verifyReceiptSignature(receipt: ReceiptPayload, publicKeyHex: string): Promise<void>;
|
|
1301
1324
|
|
|
1302
|
-
export { type AgentBoundsParams, type AgentContextParams, type AgentFrameParams, type AgentProfile, type ApprovalObject, type Attestation, type AttestationHeader, type AttestationPayload, type BoundType, type ContentBinding, ContentBindingError, type ContentBindingErrorCode, type CumulativeFieldDef, type CumulativeWindow, type DeclaredFieldDef, type ExecutionContextFieldDef, type ExecutionLogEntry, type ExecutionLogQuery, type ExecutionMappingTransform, type ExecutionMappingValue, type ExecutionPath, type FieldConstraint, type FieldUnit, type GateQuestion, type GatekeeperError, type GatekeeperRequest, type GatekeeperResult, type MandateBinding, MandateError, type MandateProjection, type OwnerMandate, type ProfileBoundsField, type ProfileContextField, type ProfileFrameField, type ProfileToolGating, type ProfileToolGatingEntry, type ReceiptPayload, type ResolvedDomain, type SigningSurface, type Subject, type SubjectValidation, approvalSigningBytes, attestationId, bindingAppliesTo, buildMandateProjection, canonicalBounds, canonicalContext, canonicalFrame, canonicalize, canonicalizeText, checkAttestationExpiry, clearProfiles, computeBoundsHash, computeContentHash, computeContextHash, computeFieldsContentHash, computeFrameHash, computeIntentDisclosureHash, computeIntentHash, contentCanonicalBytes, decodeAttestationBlob, decodeDidKey, deriveIdentityLine, encodeAttestationBlob, encodeDidKey, frameHash, getAllProfiles, getProfile, intentDisclosureCanonicalBytes, isFieldBinding, isKeyBearingDid, isV4Attestation, listProfiles, mandateSigningBytes, registerProfile, selectBoundFields, signApproval, signMandateProjection, validateBoundsParams, validateContextParams, validateFrameParams, validateSubject, verify, verifyApproval, verifyAttestation, verifyAttestationSignature, verifyAttestationV4, verifyBoundsHash, verifyContextHash, verifyFrameHash, verifyOwnerMandate, verifyOwnerMandates, verifyReceiptSignature };
|
|
1325
|
+
export { type AgentBoundsParams, type AgentContextParams, type AgentFrameParams, type AgentProfile, type ApprovalObject, type Attestation, type AttestationHeader, type AttestationPayload, type BoundType, CanonicalValueError, type ContentBinding, ContentBindingError, type ContentBindingErrorCode, type CumulativeFieldDef, type CumulativeWindow, type DeclaredFieldDef, type ExecutionContextFieldDef, type ExecutionLogEntry, type ExecutionLogQuery, type ExecutionMappingTransform, type ExecutionMappingValue, type ExecutionPath, type FieldConstraint, type FieldUnit, type GateQuestion, type GatekeeperError, type GatekeeperRequest, type GatekeeperResult, type MandateBinding, MandateError, type MandateProjection, type OwnerMandate, type ProfileBoundsField, type ProfileContextField, type ProfileFrameField, type ProfileToolGating, type ProfileToolGatingEntry, type ReceiptPayload, type ResolvedDomain, type SigningSurface, type Subject, type SubjectValidation, approvalSigningBytes, attestationId, bindingAppliesTo, buildMandateProjection, canonicalBounds, canonicalContext, canonicalFrame, canonicalize, canonicalizeText, checkAttestationExpiry, clearProfiles, computeBoundsHash, computeContentHash, computeContextHash, computeFieldsContentHash, computeFrameHash, computeIntentDisclosureHash, computeIntentHash, contentCanonicalBytes, decodeAttestationBlob, decodeDidKey, deriveIdentityLine, encodeAttestationBlob, encodeDidKey, frameHash, getAllProfiles, getProfile, intentDisclosureCanonicalBytes, isFieldBinding, isKeyBearingDid, isV4Attestation, listProfiles, mandateSigningBytes, registerProfile, selectBoundFields, signApproval, signMandateProjection, validateBoundsParams, validateContextParams, validateFrameParams, validateSubject, verify, verifyApproval, verifyAttestation, verifyAttestationSignature, verifyAttestationV4, verifyBoundsHash, verifyContextHash, verifyFrameHash, verifyOwnerMandate, verifyOwnerMandates, verifyReceiptSignature };
|
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
CanonicalValueError: () => CanonicalValueError,
|
|
33
34
|
ContentBindingError: () => ContentBindingError,
|
|
34
35
|
MandateError: () => MandateError,
|
|
35
36
|
approvalSigningBytes: () => approvalSigningBytes,
|
|
@@ -376,15 +377,51 @@ function validateContextParams(params, profile) {
|
|
|
376
377
|
}
|
|
377
378
|
return { valid: errors.length === 0, errors };
|
|
378
379
|
}
|
|
380
|
+
var CanonicalValueError = class extends Error {
|
|
381
|
+
code;
|
|
382
|
+
field;
|
|
383
|
+
constructor(code, field, message) {
|
|
384
|
+
super(message);
|
|
385
|
+
this.name = "CanonicalValueError";
|
|
386
|
+
this.code = code;
|
|
387
|
+
this.field = field;
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
function percentEncodeCanonicalValue(raw) {
|
|
391
|
+
const bytes = new TextEncoder().encode(raw);
|
|
392
|
+
let out = "";
|
|
393
|
+
for (const b of bytes) {
|
|
394
|
+
if (b === 61 || b === 37 || b < 32 || b > 126) {
|
|
395
|
+
out += "%" + b.toString(16).toUpperCase().padStart(2, "0");
|
|
396
|
+
} else {
|
|
397
|
+
out += String.fromCharCode(b);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return out;
|
|
401
|
+
}
|
|
402
|
+
function canonicalRecords(params, keyOrder, code) {
|
|
403
|
+
const lines = [];
|
|
404
|
+
for (const key of keyOrder) {
|
|
405
|
+
const value = params[key];
|
|
406
|
+
if (value === void 0 || value === null) continue;
|
|
407
|
+
const raw = String(value);
|
|
408
|
+
if (raw.includes("\n") || raw.includes("\r")) {
|
|
409
|
+
throw new CanonicalValueError(
|
|
410
|
+
code,
|
|
411
|
+
key,
|
|
412
|
+
`Value for "${key}" contains a raw newline or carriage return. Refusing: a hash over stripped or normalized input would not represent what was authorized.`
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
lines.push(`${key}=${percentEncodeCanonicalValue(raw)}`);
|
|
416
|
+
}
|
|
417
|
+
return lines.join("\n");
|
|
418
|
+
}
|
|
379
419
|
function canonicalBounds(params, profile) {
|
|
380
420
|
const validation = validateBoundsParams(params, profile);
|
|
381
421
|
if (!validation.valid) {
|
|
382
422
|
throw new Error(`Invalid bounds parameters: ${validation.errors.join("; ")}`);
|
|
383
423
|
}
|
|
384
|
-
|
|
385
|
-
(key) => `${key}=${String(params[key])}`
|
|
386
|
-
);
|
|
387
|
-
return lines.join("\n");
|
|
424
|
+
return canonicalRecords(params, profile.boundsSchema.keyOrder, "BOUNDS_INVALID_VALUE");
|
|
388
425
|
}
|
|
389
426
|
function canonicalContext(params, profile) {
|
|
390
427
|
if (!profile.contextSchema || Object.keys(profile.contextSchema.fields).length === 0) {
|
|
@@ -394,10 +431,7 @@ function canonicalContext(params, profile) {
|
|
|
394
431
|
if (!validation.valid) {
|
|
395
432
|
throw new Error(`Invalid context parameters: ${validation.errors.join("; ")}`);
|
|
396
433
|
}
|
|
397
|
-
|
|
398
|
-
(key) => `${key}=${String(params[key])}`
|
|
399
|
-
);
|
|
400
|
-
return lines.join("\n");
|
|
434
|
+
return canonicalRecords(params, profile.contextSchema.keyOrder, "CONTEXT_INVALID_VALUE");
|
|
401
435
|
}
|
|
402
436
|
function computeBoundsHash(params, profile) {
|
|
403
437
|
const canonical = canonicalBounds(params, profile);
|
|
@@ -527,7 +561,17 @@ async function verify(request, publicKeyHex, now = Math.floor(Date.now() / 1e3),
|
|
|
527
561
|
return verifyV3(request, profile, publicKeyHex, now, executionLog, errors);
|
|
528
562
|
}
|
|
529
563
|
}
|
|
564
|
+
function noAttestationSupplied(request) {
|
|
565
|
+
return !Array.isArray(request.attestations) || request.attestations.length === 0;
|
|
566
|
+
}
|
|
567
|
+
function noAttestationResult() {
|
|
568
|
+
return {
|
|
569
|
+
approved: false,
|
|
570
|
+
errors: [{ code: "MALFORMED_ATTESTATION", message: "No attestation supplied \u2014 nothing to verify" }]
|
|
571
|
+
};
|
|
572
|
+
}
|
|
530
573
|
async function verifyV3(request, profile, publicKeyHex, now, executionLog, errors) {
|
|
574
|
+
if (noAttestationSupplied(request)) return noAttestationResult();
|
|
531
575
|
let expectedFrameHash;
|
|
532
576
|
try {
|
|
533
577
|
expectedFrameHash = computeFrameHash(request.frame, profile);
|
|
@@ -588,6 +632,7 @@ async function verifyV3(request, profile, publicKeyHex, now, executionLog, error
|
|
|
588
632
|
return { approved: true };
|
|
589
633
|
}
|
|
590
634
|
async function verifyV4(request, profile, publicKeyHex, now, executionLog) {
|
|
635
|
+
if (noAttestationSupplied(request)) return noAttestationResult();
|
|
591
636
|
const errors = [];
|
|
592
637
|
const bounds = request.frame;
|
|
593
638
|
const context = request.context;
|
|
@@ -1156,6 +1201,7 @@ async function verifyReceiptSignature(receipt, publicKeyHex) {
|
|
|
1156
1201
|
}
|
|
1157
1202
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1158
1203
|
0 && (module.exports = {
|
|
1204
|
+
CanonicalValueError,
|
|
1159
1205
|
ContentBindingError,
|
|
1160
1206
|
MandateError,
|
|
1161
1207
|
approvalSigningBytes,
|
|
@@ -287,15 +287,51 @@ function validateContextParams(params, profile) {
|
|
|
287
287
|
}
|
|
288
288
|
return { valid: errors.length === 0, errors };
|
|
289
289
|
}
|
|
290
|
+
var CanonicalValueError = class extends Error {
|
|
291
|
+
code;
|
|
292
|
+
field;
|
|
293
|
+
constructor(code, field, message) {
|
|
294
|
+
super(message);
|
|
295
|
+
this.name = "CanonicalValueError";
|
|
296
|
+
this.code = code;
|
|
297
|
+
this.field = field;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
function percentEncodeCanonicalValue(raw) {
|
|
301
|
+
const bytes = new TextEncoder().encode(raw);
|
|
302
|
+
let out = "";
|
|
303
|
+
for (const b of bytes) {
|
|
304
|
+
if (b === 61 || b === 37 || b < 32 || b > 126) {
|
|
305
|
+
out += "%" + b.toString(16).toUpperCase().padStart(2, "0");
|
|
306
|
+
} else {
|
|
307
|
+
out += String.fromCharCode(b);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return out;
|
|
311
|
+
}
|
|
312
|
+
function canonicalRecords(params, keyOrder, code) {
|
|
313
|
+
const lines = [];
|
|
314
|
+
for (const key of keyOrder) {
|
|
315
|
+
const value = params[key];
|
|
316
|
+
if (value === void 0 || value === null) continue;
|
|
317
|
+
const raw = String(value);
|
|
318
|
+
if (raw.includes("\n") || raw.includes("\r")) {
|
|
319
|
+
throw new CanonicalValueError(
|
|
320
|
+
code,
|
|
321
|
+
key,
|
|
322
|
+
`Value for "${key}" contains a raw newline or carriage return. Refusing: a hash over stripped or normalized input would not represent what was authorized.`
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
lines.push(`${key}=${percentEncodeCanonicalValue(raw)}`);
|
|
326
|
+
}
|
|
327
|
+
return lines.join("\n");
|
|
328
|
+
}
|
|
290
329
|
function canonicalBounds(params, profile) {
|
|
291
330
|
const validation = validateBoundsParams(params, profile);
|
|
292
331
|
if (!validation.valid) {
|
|
293
332
|
throw new Error(`Invalid bounds parameters: ${validation.errors.join("; ")}`);
|
|
294
333
|
}
|
|
295
|
-
|
|
296
|
-
(key) => `${key}=${String(params[key])}`
|
|
297
|
-
);
|
|
298
|
-
return lines.join("\n");
|
|
334
|
+
return canonicalRecords(params, profile.boundsSchema.keyOrder, "BOUNDS_INVALID_VALUE");
|
|
299
335
|
}
|
|
300
336
|
function canonicalContext(params, profile) {
|
|
301
337
|
if (!profile.contextSchema || Object.keys(profile.contextSchema.fields).length === 0) {
|
|
@@ -305,10 +341,7 @@ function canonicalContext(params, profile) {
|
|
|
305
341
|
if (!validation.valid) {
|
|
306
342
|
throw new Error(`Invalid context parameters: ${validation.errors.join("; ")}`);
|
|
307
343
|
}
|
|
308
|
-
|
|
309
|
-
(key) => `${key}=${String(params[key])}`
|
|
310
|
-
);
|
|
311
|
-
return lines.join("\n");
|
|
344
|
+
return canonicalRecords(params, profile.contextSchema.keyOrder, "CONTEXT_INVALID_VALUE");
|
|
312
345
|
}
|
|
313
346
|
function computeBoundsHash(params, profile) {
|
|
314
347
|
const canonical = canonicalBounds(params, profile);
|
|
@@ -438,7 +471,17 @@ async function verify(request, publicKeyHex, now = Math.floor(Date.now() / 1e3),
|
|
|
438
471
|
return verifyV3(request, profile, publicKeyHex, now, executionLog, errors);
|
|
439
472
|
}
|
|
440
473
|
}
|
|
474
|
+
function noAttestationSupplied(request) {
|
|
475
|
+
return !Array.isArray(request.attestations) || request.attestations.length === 0;
|
|
476
|
+
}
|
|
477
|
+
function noAttestationResult() {
|
|
478
|
+
return {
|
|
479
|
+
approved: false,
|
|
480
|
+
errors: [{ code: "MALFORMED_ATTESTATION", message: "No attestation supplied \u2014 nothing to verify" }]
|
|
481
|
+
};
|
|
482
|
+
}
|
|
441
483
|
async function verifyV3(request, profile, publicKeyHex, now, executionLog, errors) {
|
|
484
|
+
if (noAttestationSupplied(request)) return noAttestationResult();
|
|
442
485
|
let expectedFrameHash;
|
|
443
486
|
try {
|
|
444
487
|
expectedFrameHash = computeFrameHash(request.frame, profile);
|
|
@@ -499,6 +542,7 @@ async function verifyV3(request, profile, publicKeyHex, now, executionLog, error
|
|
|
499
542
|
return { approved: true };
|
|
500
543
|
}
|
|
501
544
|
async function verifyV4(request, profile, publicKeyHex, now, executionLog) {
|
|
545
|
+
if (noAttestationSupplied(request)) return noAttestationResult();
|
|
502
546
|
const errors = [];
|
|
503
547
|
const bounds = request.frame;
|
|
504
548
|
const context = request.context;
|
|
@@ -1066,6 +1110,7 @@ async function verifyReceiptSignature(receipt, publicKeyHex) {
|
|
|
1066
1110
|
}
|
|
1067
1111
|
}
|
|
1068
1112
|
export {
|
|
1113
|
+
CanonicalValueError,
|
|
1069
1114
|
ContentBindingError,
|
|
1070
1115
|
MandateError,
|
|
1071
1116
|
approvalSigningBytes,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@humanagencyp/hap-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Core types, cryptographic primitives, and verification logic for the Human Agency Protocol",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
26
26
|
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
27
28
|
"test": "vitest run",
|
|
28
29
|
"test:watch": "vitest",
|
|
29
30
|
"prepublishOnly": "pnpm build",
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
* Frame Canonicalization for Agent Profiles
|
|
3
3
|
*
|
|
4
4
|
* Agent profiles support mixed-type fields (strings and numbers).
|
|
5
|
-
* Canonical form:
|
|
6
|
-
*
|
|
5
|
+
* Canonical form: `key=value` records joined with LF, keys in the profile's
|
|
6
|
+
* keyOrder. Values are stringified with String(value) — the shortest
|
|
7
|
+
* round-trippable form for numbers — then percent-encoded per protocol.md
|
|
8
|
+
* (`=`, `%`, and every byte outside printable ASCII); a value carrying a raw
|
|
9
|
+
* LF/CR is refused, never normalized. See `canonicalRecords` below.
|
|
7
10
|
*
|
|
8
11
|
* v0.3: frameSchema
|
|
9
12
|
* v0.4: boundsSchema + contextSchema (separate hashes)
|
|
@@ -176,11 +179,115 @@ export function validateContextParams(
|
|
|
176
179
|
return { valid: errors.length === 0, errors };
|
|
177
180
|
}
|
|
178
181
|
|
|
182
|
+
// ─── Value Encoding (normative, v0.5+) ───────────────────────────────────────
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Thrown when a value cannot be canonicalized at all — currently only for raw
|
|
186
|
+
* LF/CR inside a value. Carries the protocol error code so callers can map it
|
|
187
|
+
* straight onto the wire without string-matching a message.
|
|
188
|
+
*
|
|
189
|
+
* protocol.md → *Bounds & Scope Canonicalization* → Value encoding:
|
|
190
|
+
* "Values MUST NOT contain raw newline (\n) or carriage-return (\r)
|
|
191
|
+
* characters. Implementations MUST reject input containing them; silent
|
|
192
|
+
* stripping or normalization is a violation because it produces a hash that
|
|
193
|
+
* does not faithfully represent the input."
|
|
194
|
+
*/
|
|
195
|
+
export class CanonicalValueError extends Error {
|
|
196
|
+
readonly code: 'BOUNDS_INVALID_VALUE' | 'CONTEXT_INVALID_VALUE';
|
|
197
|
+
readonly field: string;
|
|
198
|
+
|
|
199
|
+
constructor(code: 'BOUNDS_INVALID_VALUE' | 'CONTEXT_INVALID_VALUE', field: string, message: string) {
|
|
200
|
+
super(message);
|
|
201
|
+
this.name = 'CanonicalValueError';
|
|
202
|
+
this.code = code;
|
|
203
|
+
this.field = field;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Percent-encode a value per protocol.md → *Value encoding*.
|
|
209
|
+
*
|
|
210
|
+
* Encoded, over the value's UTF-8 bytes, as `%` + two UPPERCASE hex digits:
|
|
211
|
+
* - `=` (0x3D) — otherwise it would be read as the key/value separator
|
|
212
|
+
* - `%` (0x25) — so the encoding is self-inverse
|
|
213
|
+
* - every byte outside printable ASCII 0x20–0x7E
|
|
214
|
+
*
|
|
215
|
+
* LF and CR are deliberately NOT in this list: they are refused upstream, so
|
|
216
|
+
* encoding them is unreachable (v0.7 removed the spec's contradiction here).
|
|
217
|
+
*
|
|
218
|
+
* This runs at canonicalization time only. Stored values keep the human's
|
|
219
|
+
* original bytes.
|
|
220
|
+
*/
|
|
221
|
+
function percentEncodeCanonicalValue(raw: string): string {
|
|
222
|
+
const bytes = new TextEncoder().encode(raw);
|
|
223
|
+
let out = '';
|
|
224
|
+
for (const b of bytes) {
|
|
225
|
+
if (b === 0x3d || b === 0x25 || b < 0x20 || b > 0x7e) {
|
|
226
|
+
out += '%' + b.toString(16).toUpperCase().padStart(2, '0');
|
|
227
|
+
} else {
|
|
228
|
+
out += String.fromCharCode(b);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return out;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* The one place `key=value` records are built for bounds and context.
|
|
236
|
+
*
|
|
237
|
+
* Rules applied here (all normative, protocol.md → *Bounds & Scope
|
|
238
|
+
* Canonicalization*):
|
|
239
|
+
* - keys in the schema's keyOrder, never alphabetical
|
|
240
|
+
* - a value carrying a raw LF/CR is REFUSED (never stripped or encoded)
|
|
241
|
+
* - `=`, `%`, and any byte outside 0x20–0x7E are percent-encoded (UPPERCASE)
|
|
242
|
+
* - numbers use JS `String()`, which is the shortest round-trippable form
|
|
243
|
+
* (`String(20.0)` === "20")
|
|
244
|
+
* - a key with no value is OMITTED entirely — it emits no record
|
|
245
|
+
*
|
|
246
|
+
* On the omission rule: required keys are guaranteed present by the caller's
|
|
247
|
+
* validation (`validateBoundsParams` / `validateContextParams` reject a missing
|
|
248
|
+
* required field), so "explicit inclusion of all required keys" still holds.
|
|
249
|
+
* What remains are *optional* keys the human never set. Rendering those as the
|
|
250
|
+
* literal string "undefined" — the pre-fix behaviour — hashed a JavaScript
|
|
251
|
+
* artifact that no other language would produce and that collides with a real
|
|
252
|
+
* value of "undefined". Omitting them (rather than emitting `key=`) also keeps
|
|
253
|
+
* "the human set no limit" distinct from "the human set an empty value", and
|
|
254
|
+
* matches this package's JSON canonicalization, which drops undefined-valued
|
|
255
|
+
* properties.
|
|
256
|
+
*/
|
|
257
|
+
function canonicalRecords(
|
|
258
|
+
params: Record<string, string | number | undefined>,
|
|
259
|
+
keyOrder: string[],
|
|
260
|
+
code: 'BOUNDS_INVALID_VALUE' | 'CONTEXT_INVALID_VALUE',
|
|
261
|
+
): string {
|
|
262
|
+
const lines: string[] = [];
|
|
263
|
+
|
|
264
|
+
for (const key of keyOrder) {
|
|
265
|
+
const value = params[key];
|
|
266
|
+
if (value === undefined || value === null) continue;
|
|
267
|
+
|
|
268
|
+
const raw = String(value);
|
|
269
|
+
if (raw.includes('\n') || raw.includes('\r')) {
|
|
270
|
+
throw new CanonicalValueError(
|
|
271
|
+
code,
|
|
272
|
+
key,
|
|
273
|
+
`Value for "${key}" contains a raw newline or carriage return. ` +
|
|
274
|
+
'Refusing: a hash over stripped or normalized input would not represent what was authorized.',
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
lines.push(`${key}=${percentEncodeCanonicalValue(raw)}`);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return lines.join('\n');
|
|
282
|
+
}
|
|
283
|
+
|
|
179
284
|
/**
|
|
180
285
|
* Builds the canonical bounds string from parameters.
|
|
181
|
-
*
|
|
286
|
+
* Keys are ordered per profile's boundsSchema.keyOrder; values are encoded per
|
|
287
|
+
* protocol.md → *Value encoding* (see `canonicalRecords`).
|
|
182
288
|
*
|
|
183
289
|
* @throws Error if any field fails validation
|
|
290
|
+
* @throws CanonicalValueError (code BOUNDS_INVALID_VALUE) if a value carries a raw LF/CR
|
|
184
291
|
*/
|
|
185
292
|
export function canonicalBounds(params: AgentBoundsParams, profile: AgentProfile): string {
|
|
186
293
|
const validation = validateBoundsParams(params, profile);
|
|
@@ -188,19 +295,17 @@ export function canonicalBounds(params: AgentBoundsParams, profile: AgentProfile
|
|
|
188
295
|
throw new Error(`Invalid bounds parameters: ${validation.errors.join('; ')}`);
|
|
189
296
|
}
|
|
190
297
|
|
|
191
|
-
|
|
192
|
-
(key) => `${key}=${String(params[key])}`
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
return lines.join('\n');
|
|
298
|
+
return canonicalRecords(params, profile.boundsSchema!.keyOrder, 'BOUNDS_INVALID_VALUE');
|
|
196
299
|
}
|
|
197
300
|
|
|
198
301
|
/**
|
|
199
302
|
* Builds the canonical context string from parameters.
|
|
200
|
-
*
|
|
303
|
+
* Keys are ordered per profile's contextSchema.keyOrder; values are encoded per
|
|
304
|
+
* protocol.md → *Value encoding* (see `canonicalRecords`).
|
|
201
305
|
* For empty context (no contextSchema or no fields), returns "".
|
|
202
306
|
*
|
|
203
307
|
* @throws Error if any field fails validation
|
|
308
|
+
* @throws CanonicalValueError (code CONTEXT_INVALID_VALUE) if a value carries a raw LF/CR
|
|
204
309
|
*/
|
|
205
310
|
export function canonicalContext(params: AgentContextParams, profile: AgentProfile): string {
|
|
206
311
|
// No contextSchema or no fields → empty context
|
|
@@ -213,11 +318,7 @@ export function canonicalContext(params: AgentContextParams, profile: AgentProfi
|
|
|
213
318
|
throw new Error(`Invalid context parameters: ${validation.errors.join('; ')}`);
|
|
214
319
|
}
|
|
215
320
|
|
|
216
|
-
|
|
217
|
-
(key) => `${key}=${String(params[key])}`
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
return lines.join('\n');
|
|
321
|
+
return canonicalRecords(params, profile.contextSchema.keyOrder, 'CONTEXT_INVALID_VALUE');
|
|
221
322
|
}
|
|
222
323
|
|
|
223
324
|
/**
|
|
@@ -86,6 +86,28 @@ export async function verify(
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Fail closed when there is nothing to verify.
|
|
91
|
+
*
|
|
92
|
+
* The attestation loop below is a `for` over `request.attestations`. With an
|
|
93
|
+
* empty (or missing) array it runs zero times, pushes zero errors, and control
|
|
94
|
+
* falls through to the bounds check — which happily approves a call whose
|
|
95
|
+
* signature, bounds_hash, and TTL were never checked. "No errors" is not the
|
|
96
|
+
* same as "verified"; an absent attestation is the one case where silence must
|
|
97
|
+
* read as refusal.
|
|
98
|
+
*/
|
|
99
|
+
function noAttestationSupplied(request: GatekeeperRequest): boolean {
|
|
100
|
+
return !Array.isArray(request.attestations) || request.attestations.length === 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Built fresh per call so a caller cannot mutate a shared error array. */
|
|
104
|
+
function noAttestationResult(): GatekeeperResult {
|
|
105
|
+
return {
|
|
106
|
+
approved: false,
|
|
107
|
+
errors: [{ code: 'MALFORMED_ATTESTATION', message: 'No attestation supplied — nothing to verify' }],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
89
111
|
// ─── v0.3 Verification ────────────────────────────────────────────────────────
|
|
90
112
|
|
|
91
113
|
async function verifyV3(
|
|
@@ -96,6 +118,8 @@ async function verifyV3(
|
|
|
96
118
|
executionLog: ExecutionLogQuery | undefined,
|
|
97
119
|
errors: GatekeeperError[],
|
|
98
120
|
): Promise<GatekeeperResult> {
|
|
121
|
+
if (noAttestationSupplied(request)) return noAttestationResult();
|
|
122
|
+
|
|
99
123
|
let expectedFrameHash: string;
|
|
100
124
|
try {
|
|
101
125
|
expectedFrameHash = computeFrameHash(request.frame, profile);
|
|
@@ -179,6 +203,8 @@ async function verifyV4(
|
|
|
179
203
|
now: number,
|
|
180
204
|
executionLog: ExecutionLogQuery | undefined,
|
|
181
205
|
): Promise<GatekeeperResult> {
|
|
206
|
+
if (noAttestationSupplied(request)) return noAttestationResult();
|
|
207
|
+
|
|
182
208
|
const errors: GatekeeperError[] = [];
|
|
183
209
|
|
|
184
210
|
// In v0.4 the `frame` param carries bounds; `context` carries context params
|
|
@@ -712,7 +712,13 @@ export interface GatekeeperError {
|
|
|
712
712
|
| 'MANDATE_SIGNATURE_REQUIRED'
|
|
713
713
|
| 'MANDATE_SIGNATURE_INVALID'
|
|
714
714
|
| 'APPROVAL_SIGNATURE_REQUIRED'
|
|
715
|
-
| 'APPROVAL_SIGNATURE_INVALID'
|
|
715
|
+
| 'APPROVAL_SIGNATURE_INVALID'
|
|
716
|
+
// Canonicalization refusals (protocol.md → Bounds & Scope Canonicalization
|
|
717
|
+
// → Value encoding). Raised when a value cannot be canonicalized at all —
|
|
718
|
+
// a raw LF/CR, or a profile `constraint.pattern` violation. Distinct from
|
|
719
|
+
// BOUNDS_MISMATCH / CONTEXT_MISMATCH, which mean the hashes disagree.
|
|
720
|
+
| 'BOUNDS_INVALID_VALUE'
|
|
721
|
+
| 'CONTEXT_INVALID_VALUE';
|
|
716
722
|
field?: string;
|
|
717
723
|
message: string;
|
|
718
724
|
bound?: string | number;
|
|
@@ -8,7 +8,7 @@ This package contains type definitions for node (https://nodejs.org/).
|
|
|
8
8
|
Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node.
|
|
9
9
|
|
|
10
10
|
### Additional Details
|
|
11
|
-
* Last updated:
|
|
11
|
+
* Last updated: Tue, 01 Sep 2026 20:06:05 GMT
|
|
12
12
|
* Dependencies: [undici-types](https://npmjs.com/package/undici-types)
|
|
13
13
|
|
|
14
14
|
# Credits
|
|
@@ -463,4 +463,9 @@ declare module "node:buffer" {
|
|
|
463
463
|
*/
|
|
464
464
|
type AllowSharedBuffer = Buffer<ArrayBufferLike>;
|
|
465
465
|
}
|
|
466
|
+
/**
|
|
467
|
+
* @deprecated This is intended for internal use, and will be removed once `@types/node` no longer supports
|
|
468
|
+
* TypeScript versions earlier than 5.7.
|
|
469
|
+
*/
|
|
470
|
+
type BufferView<T extends NodeJS.ArrayBufferView> = T extends NodeJS.ArrayBufferView<infer B> ? Buffer<B> : never;
|
|
466
471
|
}
|
|
@@ -3475,7 +3475,6 @@ declare module "node:crypto" {
|
|
|
3475
3475
|
* ```
|
|
3476
3476
|
* @since v24.7.0
|
|
3477
3477
|
* @param algorithm Variant of Argon2, one of `"argon2d"`, `"argon2i"` or `"argon2id"`.
|
|
3478
|
-
* @experimental
|
|
3479
3478
|
*/
|
|
3480
3479
|
function argon2(
|
|
3481
3480
|
algorithm: Argon2Algorithm,
|
|
@@ -3515,7 +3514,6 @@ declare module "node:crypto" {
|
|
|
3515
3514
|
* console.log(derivedKey.toString('hex')); // 'af91dad...9520f15'
|
|
3516
3515
|
* ```
|
|
3517
3516
|
* @since v24.7.0
|
|
3518
|
-
* @experimental
|
|
3519
3517
|
*/
|
|
3520
3518
|
function argon2Sync(algorithm: Argon2Algorithm, parameters: Argon2Parameters): NonSharedBuffer;
|
|
3521
3519
|
/**
|