@adastracomputing/ink 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -3
- package/dist/crypto/sign.d.ts +1 -1
- package/dist/crypto/sign.js +38 -6
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/ink/discovery-gating.d.ts +3 -2
- package/dist/models/agent-card.d.ts +9 -2
- package/dist/models/agent-card.js +21 -0
- package/dist/models/intent.d.ts +64 -42
- package/dist/models/intent.js +80 -42
- package/dist/models/profile.d.ts +9 -9
- package/dist/models/profile.js +9 -5
- package/package.json +2 -1
- package/test-vectors/README.md +4 -3
- package/test-vectors/body-signature.json +201 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,9 +4,23 @@ All notable changes to INK are recorded
|
|
|
4
4
|
here. Pre-1.0 releases follow `0.Y.Z` semantics, see
|
|
5
5
|
[`docs/maturity.md`](docs/maturity.md) for the versioning policy.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## 0.2.0, version-keyed body-signature domain
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Version-keyed body-signature domain. The body message signature is now domain-separated by protocol version. ink/0.1 messages, and any object with no explicit ink/0.2 protocol, keep the legacy `tulpa/sign` domain so every signature produced to date still verifies. ink/0.2 messages are signed and verified under the neutral `ink/sign` domain. The verifier selects exactly one domain from the signed `protocol` field and never tries an alternate, so a signature made under one version's domain cannot be replayed under another.
|
|
10
|
+
|
|
11
|
+
This change is receiver-first and backward compatible. Verifiers accept both versions and `MessageEnvelopeSchema` now accepts ink/0.1 and ink/0.2 as a strict enum, rejecting any unknown version. Senders still emit ink/0.1 by default. The HTTP transport-auth signature is unchanged.
|
|
12
|
+
|
|
13
|
+
New vectors in `test-vectors/body-signature.json` pin the version-keyed domain including the cross-version and tamper cases. The standalone Python interop client verifies them identically.
|
|
14
|
+
|
|
15
|
+
Per the pre-1.0 policy this release publishes under the `next` dist-tag.
|
|
16
|
+
|
|
17
|
+
## 0.1.7, expose per-intent payload schemas and getPayloadSchema from the package root
|
|
18
|
+
|
|
19
|
+
Pure additive release. Re-exports every per-intent Zod payload schema (`ScheduleMeetingPayloadSchema`, `IntroRequestPayloadSchema`, `OpportunityPayloadSchema`, `ConnectionRequestPayloadSchema`, `FollowUpPayloadSchema`, `AskPayloadSchema`, `PingPayloadSchema`, `RetractPayloadSchema`, `ContextSharePayloadSchema`, `MultiPartySyncPayloadSchema`, plus the matching `*ResponsePayloadSchema` variants) and the `getPayloadSchema(intent)` resolver from the package root. Adopters writing intent-aware receivers / handlers can now type their dispatch surface directly against the canonical payload shapes.
|
|
20
|
+
|
|
21
|
+
No wire-level changes. No behavior changes inside the existing functions. Receivers on 0.1.6 work unchanged on 0.1.7.
|
|
22
|
+
|
|
23
|
+
Per the pre-1.0 policy this release publishes under the `next` dist-tag.
|
|
10
24
|
|
|
11
25
|
## 0.1.6, expose intent + key-entry types and add optional inclusionProof to InkAuditInclusionSchema
|
|
12
26
|
|
|
@@ -71,7 +85,7 @@ Fixes the v0.1.1 erratum: the Python `examples/interop-cli/` shipped in v0.1.1 e
|
|
|
71
85
|
|
|
72
86
|
**CLI now builds `connection_request` envelopes.** `ink-interop send/build --intent-type connection_request` (or the alias `connection`) constructs a `ConnectionRequestPayloadSchema`-conformant payload (`method`, `context`, `profileSnapshot`). This is the bootstrap intent for first contact between strangers: receivers that opt in to foreign senders verify the body signature against the inline key extracted from the sender's `did:key` (trust-on-first-use). Other intent types (`intro_request`, `ask`, `follow_up`) presume the sender is already a known contact and remain reserved for established relationships.
|
|
73
87
|
|
|
74
|
-
Verified end-to-end against `https://api.tulpa.network/ink/v1/<agentId>/intent`: a `did:key:` `connection_request` from `ink-interop send` lands as a pending action in the recipient's inbox (`status: 200`, `accepted: true`, `pendingActionId: 01KT…`). Coverage spans schema validation, body + transport signature verification, replay/freshness, identity resolution, routing, the foreign-DID policy gate
|
|
88
|
+
Verified end-to-end against `https://api.tulpa.network/ink/v1/<agentId>/intent`: a `did:key:` `connection_request` from `ink-interop send` lands as a pending action in the recipient's inbox (`status: 200`, `accepted: true`, `pendingActionId: 01KT…`). Coverage spans schema validation, body + transport signature verification, replay/freshness, identity resolution, routing, and the foreign-DID policy gate. Tests pinned to the canonical shape (`tests/test_envelope.py`) prevent regression. The npm library itself is unchanged from v0.1.1.
|
|
75
89
|
|
|
76
90
|
**Example-helper API break.** `examples/interop-cli/`'s Python helper `build_intent_envelope()` now requires `keypair`, replaces `intent_type`/`purpose`/`timestamp` with canonical args (`target`, `reason`, `created_at`, etc.), and removes the `extra=` kwarg. Adopters who imported the old helper directly will need to update their calls — the previous signature emitted invalid wire data so no callable interop existed there to preserve. This is an example-only change; the npm library (`@adastracomputing/ink`) exports are unchanged.
|
|
77
91
|
|
package/dist/crypto/sign.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 1. Remove `signature` field if present
|
|
5
5
|
* 2. JCS canonicalize (RFC 8785) via `canonicalize` library
|
|
6
|
-
* 3. Sign canonical bytes directly with Ed25519
|
|
6
|
+
* 3. Sign domain-prefixed canonical bytes directly with Ed25519
|
|
7
7
|
* 4. Return base64url-encoded signature (no padding)
|
|
8
8
|
*/
|
|
9
9
|
export declare function signMessage(message: Record<string, unknown>, privateKey: Uint8Array): Promise<string>;
|
package/dist/crypto/sign.js
CHANGED
|
@@ -54,12 +54,39 @@ function isWithinBounds(value) {
|
|
|
54
54
|
}
|
|
55
55
|
return walk(value, 0);
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Body-signature domain-separation prefix, keyed off the message's
|
|
59
|
+
* declared `protocol` version.
|
|
60
|
+
*
|
|
61
|
+
* - `ink/0.2` -> `ink/sign\n` (neutral, current).
|
|
62
|
+
* - everything else (`ink/0.1`, or any object with no explicit
|
|
63
|
+
* `ink/0.2` protocol) -> `tulpa/sign\n`, the legacy domain, kept
|
|
64
|
+
* forever so every signature ever produced still verifies.
|
|
65
|
+
*
|
|
66
|
+
* The prefix is derived from the `protocol` field that is part of the
|
|
67
|
+
* signed body, so a verifier selects exactly one domain and tampering
|
|
68
|
+
* with `protocol` after signing breaks the signature (an `ink/0.2` body
|
|
69
|
+
* re-labelled `ink/0.1` is verified under `tulpa/sign\n` against a
|
|
70
|
+
* signature made over `ink/sign\n`, and fails). Only the exact string
|
|
71
|
+
* `"ink/0.2"` switches domains, so no other value can smuggle one in.
|
|
72
|
+
*
|
|
73
|
+
* This raw signer stays permissive on purpose: it is a general-purpose
|
|
74
|
+
* Ed25519 message signer (receipts, arbitrary objects), not envelope-
|
|
75
|
+
* specific. Strict "reject unknown protocol version" lives at the
|
|
76
|
+
* envelope schema layer, which validates `protocol` against the allowed
|
|
77
|
+
* set before this function is reached.
|
|
78
|
+
*/
|
|
79
|
+
const LEGACY_SIGN_DOMAIN = "tulpa/sign\n";
|
|
80
|
+
const V02_SIGN_DOMAIN = "ink/sign\n";
|
|
81
|
+
function bodySignatureDomain(unsigned) {
|
|
82
|
+
return unsigned.protocol === "ink/0.2" ? V02_SIGN_DOMAIN : LEGACY_SIGN_DOMAIN;
|
|
83
|
+
}
|
|
57
84
|
/**
|
|
58
85
|
* Sign a message object using Ed25519.
|
|
59
86
|
*
|
|
60
87
|
* 1. Remove `signature` field if present
|
|
61
88
|
* 2. JCS canonicalize (RFC 8785) via `canonicalize` library
|
|
62
|
-
* 3. Sign canonical bytes directly with Ed25519
|
|
89
|
+
* 3. Sign domain-prefixed canonical bytes directly with Ed25519
|
|
63
90
|
* 4. Return base64url-encoded signature (no padding)
|
|
64
91
|
*/
|
|
65
92
|
export async function signMessage(message, privateKey) {
|
|
@@ -83,8 +110,10 @@ export async function signMessage(message, privateKey) {
|
|
|
83
110
|
if (canonical.length > MAX_MESSAGE_CANONICAL_BYTES) {
|
|
84
111
|
throw new Error("Canonicalized message exceeds maximum allowed size");
|
|
85
112
|
}
|
|
86
|
-
// Domain-separated signing to prevent cross-protocol signature replay
|
|
87
|
-
|
|
113
|
+
// Domain-separated signing to prevent cross-protocol signature replay.
|
|
114
|
+
// Domain is keyed off the (signed) protocol version; see
|
|
115
|
+
// bodySignatureDomain. Legacy ink/0.1 keeps the tulpa/sign domain.
|
|
116
|
+
const prefixed = `${bodySignatureDomain(unsigned)}${canonical}`;
|
|
88
117
|
const bytes = new TextEncoder().encode(prefixed);
|
|
89
118
|
const sig = await ed.signAsync(bytes, privateKey);
|
|
90
119
|
return base64urlEncode(sig);
|
|
@@ -124,9 +153,12 @@ export async function verifyMessage(message, publicKey) {
|
|
|
124
153
|
if (canonical.length > MAX_MESSAGE_CANONICAL_BYTES) {
|
|
125
154
|
return false;
|
|
126
155
|
}
|
|
127
|
-
// Domain-prefixed verification only
|
|
128
|
-
//
|
|
129
|
-
|
|
156
|
+
// Domain-prefixed verification only. The domain is selected from the
|
|
157
|
+
// signed `protocol` field (see bodySignatureDomain); a verifier never
|
|
158
|
+
// tries an alternate prefix, so a signature made under one version's
|
|
159
|
+
// domain cannot be replayed under another. Legacy unprefixed
|
|
160
|
+
// signatures are not accepted.
|
|
161
|
+
const prefixed = `${bodySignatureDomain(unsigned)}${canonical}`;
|
|
130
162
|
const prefixedBytes = new TextEncoder().encode(prefixed);
|
|
131
163
|
try {
|
|
132
164
|
const sig = base64urlDecode(signature);
|
package/dist/index.d.ts
CHANGED
|
@@ -16,12 +16,12 @@ export type { InkAuditEventType, InkAuditEvent, InkAuditInclusion, InkReceipt, I
|
|
|
16
16
|
export { InkChallengeSchema, InkRejectionSchema, InkResolutionSchema, InkTransportSchema, } from "./models/ink-handshake.js";
|
|
17
17
|
export type { AgentCardVisibility, InkChallenge, InkRejection, InkResolution, InkTransport, } from "./models/ink-handshake.js";
|
|
18
18
|
export { AgentCardSchema } from "./models/agent-card.js";
|
|
19
|
-
export { validateMessage, MessageEnvelopeSchema, IntentTypeSchema, } from "./models/intent.js";
|
|
20
|
-
export type { MessageEnvelope, IntentType, } from "./models/intent.js";
|
|
19
|
+
export { validateMessage, getPayloadSchema, MessageEnvelopeSchema, ProtocolVersionSchema, INK_PROTOCOL_VERSIONS, IntentTypeSchema, ScheduleMeetingPayloadSchema, ScheduleMeetingResponsePayloadSchema, IntroRequestPayloadSchema, IntroResponsePayloadSchema, OpportunityPayloadSchema, OpportunityResponsePayloadSchema, ConnectionRequestPayloadSchema, ConnectionResponsePayloadSchema, FollowUpPayloadSchema, AskPayloadSchema, AskResponsePayloadSchema, PingPayloadSchema, RetractPayloadSchema, ContextSharePayloadSchema, MultiPartySyncPayloadSchema, } from "./models/intent.js";
|
|
20
|
+
export type { MessageEnvelope, ProtocolVersion, IntentType, } from "./models/intent.js";
|
|
21
21
|
export { KeyStatusSchema, KeyRoleSchema, KeyEntrySchema, } from "./models/key-entry.js";
|
|
22
22
|
export type { KeyStatus, KeyRole, KeyEntry, StoredKey, } from "./models/key-entry.js";
|
|
23
23
|
export type { InkSignInput } from "./crypto/ink.js";
|
|
24
24
|
export type { CandidateKey } from "./models/key-entry.js";
|
|
25
|
-
export { resolveAgentInbox } from "./models/agent-card.js";
|
|
25
|
+
export { resolveAgentInbox, agentSupportedProtocolVersions } from "./models/agent-card.js";
|
|
26
26
|
export type { AgentCard } from "./models/agent-card.js";
|
|
27
27
|
export type { BudgetCheckResult, HandshakeBudgetConfig, } from "./ink/handshake-budget.js";
|
package/dist/index.js
CHANGED
|
@@ -32,9 +32,9 @@ export { AgentCardSchema } from "./models/agent-card.js";
|
|
|
32
32
|
// reject malformed envelopes before signature verification; without
|
|
33
33
|
// it they have to re-implement the schema check or import from a
|
|
34
34
|
// non-public path.
|
|
35
|
-
export { validateMessage, MessageEnvelopeSchema, IntentTypeSchema, } from "./models/intent.js";
|
|
35
|
+
export { validateMessage, getPayloadSchema, MessageEnvelopeSchema, ProtocolVersionSchema, INK_PROTOCOL_VERSIONS, IntentTypeSchema, ScheduleMeetingPayloadSchema, ScheduleMeetingResponsePayloadSchema, IntroRequestPayloadSchema, IntroResponsePayloadSchema, OpportunityPayloadSchema, OpportunityResponsePayloadSchema, ConnectionRequestPayloadSchema, ConnectionResponsePayloadSchema, FollowUpPayloadSchema, AskPayloadSchema, AskResponsePayloadSchema, PingPayloadSchema, RetractPayloadSchema, ContextSharePayloadSchema, MultiPartySyncPayloadSchema, } from "./models/intent.js";
|
|
36
36
|
// Key-entry types and schemas for adopters wiring their own key-set
|
|
37
37
|
// storage and rotation. `CandidateKey` was already root-exported via
|
|
38
38
|
// the verifier surface; this batch adds the persistence shapes.
|
|
39
39
|
export { KeyStatusSchema, KeyRoleSchema, KeyEntrySchema, } from "./models/key-entry.js";
|
|
40
|
-
export { resolveAgentInbox } from "./models/agent-card.js";
|
|
40
|
+
export { resolveAgentInbox, agentSupportedProtocolVersions } from "./models/agent-card.js";
|
|
@@ -96,9 +96,9 @@ export declare const AgentCardResponseSchema: z.ZodObject<{
|
|
|
96
96
|
timezone: z.ZodString;
|
|
97
97
|
meetingHours: z.ZodOptional<z.ZodString>;
|
|
98
98
|
responseSla: z.ZodOptional<z.ZodString>;
|
|
99
|
-
}, z.core.$
|
|
99
|
+
}, z.core.$strict>>;
|
|
100
100
|
openTo: z.ZodArray<z.ZodString>;
|
|
101
|
-
}, z.core.$
|
|
101
|
+
}, z.core.$strict>>;
|
|
102
102
|
capabilities: z.ZodObject<{
|
|
103
103
|
intentsAccepted: z.ZodArray<z.ZodEnum<{
|
|
104
104
|
schedule_meeting: "schedule_meeting";
|
|
@@ -202,6 +202,7 @@ export declare const AgentCardResponseSchema: z.ZodObject<{
|
|
|
202
202
|
currentSigningKeyId: z.ZodOptional<z.ZodString>;
|
|
203
203
|
currentEncryptionKeyId: z.ZodOptional<z.ZodString>;
|
|
204
204
|
keySetVersion: z.ZodOptional<z.ZodNumber>;
|
|
205
|
+
supportedProtocolVersions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
205
206
|
visibility: z.ZodOptional<z.ZodEnum<{
|
|
206
207
|
public: "public";
|
|
207
208
|
network_only: "network_only";
|
|
@@ -23,9 +23,9 @@ export declare const AgentCardSchema: z.ZodObject<{
|
|
|
23
23
|
timezone: z.ZodString;
|
|
24
24
|
meetingHours: z.ZodOptional<z.ZodString>;
|
|
25
25
|
responseSla: z.ZodOptional<z.ZodString>;
|
|
26
|
-
}, z.core.$
|
|
26
|
+
}, z.core.$strict>>;
|
|
27
27
|
openTo: z.ZodArray<z.ZodString>;
|
|
28
|
-
}, z.core.$
|
|
28
|
+
}, z.core.$strict>>;
|
|
29
29
|
capabilities: z.ZodObject<{
|
|
30
30
|
intentsAccepted: z.ZodArray<z.ZodEnum<{
|
|
31
31
|
schedule_meeting: "schedule_meeting";
|
|
@@ -129,6 +129,7 @@ export declare const AgentCardSchema: z.ZodObject<{
|
|
|
129
129
|
currentSigningKeyId: z.ZodOptional<z.ZodString>;
|
|
130
130
|
currentEncryptionKeyId: z.ZodOptional<z.ZodString>;
|
|
131
131
|
keySetVersion: z.ZodOptional<z.ZodNumber>;
|
|
132
|
+
supportedProtocolVersions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
132
133
|
visibility: z.ZodOptional<z.ZodEnum<{
|
|
133
134
|
public: "public";
|
|
134
135
|
network_only: "network_only";
|
|
@@ -153,6 +154,12 @@ export declare const AgentCardSchema: z.ZodObject<{
|
|
|
153
154
|
}, z.core.$strip>>;
|
|
154
155
|
}, z.core.$strip>;
|
|
155
156
|
export type AgentCard = z.infer<typeof AgentCardSchema>;
|
|
157
|
+
/**
|
|
158
|
+
* The message protocol versions a card's receiver can verify. Falls back
|
|
159
|
+
* to ink/0.1 when the card does not advertise the field, so a sender
|
|
160
|
+
* defaults to the original version for any card that predates it.
|
|
161
|
+
*/
|
|
162
|
+
export declare function agentSupportedProtocolVersions(card: Pick<AgentCard, "supportedProtocolVersions">): string[];
|
|
156
163
|
/**
|
|
157
164
|
* Return the inbound message URL for an Agent Card.
|
|
158
165
|
*
|
|
@@ -58,6 +58,18 @@ export const AgentCardSchema = z.object({
|
|
|
58
58
|
currentSigningKeyId: z.string().optional(),
|
|
59
59
|
currentEncryptionKeyId: z.string().optional(),
|
|
60
60
|
keySetVersion: z.number().int().positive().optional(),
|
|
61
|
+
// Message protocol versions this agent's receiver can verify on the
|
|
62
|
+
// body signature. When absent, assume ink/0.1 only. A sender MUST NOT
|
|
63
|
+
// emit a newer version to a card that does not advertise it; advertising
|
|
64
|
+
// a version here is necessary but not sufficient for a sender to use it.
|
|
65
|
+
//
|
|
66
|
+
// The entries are advisory hints, so they are accepted as bounded
|
|
67
|
+
// strings rather than the strict version enum: a newer peer may
|
|
68
|
+
// advertise a version this build does not know yet, and that must not
|
|
69
|
+
// make its whole card unparseable. A sender intersects this list with
|
|
70
|
+
// the versions it can actually emit. The strict enum lives on the
|
|
71
|
+
// envelope (MessageEnvelopeSchema), where an unknown version is rejected.
|
|
72
|
+
supportedProtocolVersions: z.array(z.string().max(16)).max(8).optional(),
|
|
61
73
|
// Containment extension (Phase 1)
|
|
62
74
|
visibility: AgentCardVisibilitySchema.optional(),
|
|
63
75
|
governance: z.object({
|
|
@@ -83,6 +95,15 @@ export const AgentCardSchema = z.object({
|
|
|
83
95
|
});
|
|
84
96
|
}
|
|
85
97
|
});
|
|
98
|
+
/**
|
|
99
|
+
* The message protocol versions a card's receiver can verify. Falls back
|
|
100
|
+
* to ink/0.1 when the card does not advertise the field, so a sender
|
|
101
|
+
* defaults to the original version for any card that predates it.
|
|
102
|
+
*/
|
|
103
|
+
export function agentSupportedProtocolVersions(card) {
|
|
104
|
+
const advertised = card.supportedProtocolVersions;
|
|
105
|
+
return advertised && advertised.length > 0 ? advertised : ["ink/0.1"];
|
|
106
|
+
}
|
|
86
107
|
/**
|
|
87
108
|
* Return the inbound message URL for an Agent Card.
|
|
88
109
|
*
|
package/dist/models/intent.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ export declare const ScheduleMeetingPayloadSchema: z.ZodObject<{
|
|
|
33
33
|
}>;
|
|
34
34
|
context: z.ZodOptional<z.ZodString>;
|
|
35
35
|
location: z.ZodOptional<z.ZodString>;
|
|
36
|
-
}, z.core.$
|
|
36
|
+
}, z.core.$strict>;
|
|
37
37
|
export declare const ScheduleMeetingResponsePayloadSchema: z.ZodObject<{
|
|
38
38
|
status: z.ZodEnum<{
|
|
39
39
|
accepted: "accepted";
|
|
@@ -50,7 +50,7 @@ export declare const ScheduleMeetingResponsePayloadSchema: z.ZodObject<{
|
|
|
50
50
|
too_busy: "too_busy";
|
|
51
51
|
deferred: "deferred";
|
|
52
52
|
}>>;
|
|
53
|
-
}, z.core.$
|
|
53
|
+
}, z.core.$strict>;
|
|
54
54
|
export declare const IntroRequestPayloadSchema: z.ZodObject<{
|
|
55
55
|
target: z.ZodString;
|
|
56
56
|
reason: z.ZodString;
|
|
@@ -59,7 +59,7 @@ export declare const IntroRequestPayloadSchema: z.ZodObject<{
|
|
|
59
59
|
low: "low";
|
|
60
60
|
normal: "normal";
|
|
61
61
|
}>;
|
|
62
|
-
}, z.core.$
|
|
62
|
+
}, z.core.$strict>;
|
|
63
63
|
export declare const IntroResponsePayloadSchema: z.ZodObject<{
|
|
64
64
|
status: z.ZodEnum<{
|
|
65
65
|
declined: "declined";
|
|
@@ -72,7 +72,7 @@ export declare const IntroResponsePayloadSchema: z.ZodObject<{
|
|
|
72
72
|
declined: "declined";
|
|
73
73
|
pending: "pending";
|
|
74
74
|
}>>;
|
|
75
|
-
}, z.core.$
|
|
75
|
+
}, z.core.$strict>;
|
|
76
76
|
export declare const OpportunityPayloadSchema: z.ZodObject<{
|
|
77
77
|
type: z.ZodEnum<{
|
|
78
78
|
role: "role";
|
|
@@ -88,7 +88,7 @@ export declare const OpportunityPayloadSchema: z.ZodObject<{
|
|
|
88
88
|
matchReason: z.ZodString;
|
|
89
89
|
expiresAt: z.ZodOptional<z.ZodString>;
|
|
90
90
|
url: z.ZodOptional<z.ZodString>;
|
|
91
|
-
}, z.core.$
|
|
91
|
+
}, z.core.$strict>;
|
|
92
92
|
export declare const OpportunityResponsePayloadSchema: z.ZodObject<{
|
|
93
93
|
status: z.ZodEnum<{
|
|
94
94
|
not_interested: "not_interested";
|
|
@@ -113,7 +113,7 @@ export declare const OpportunityResponsePayloadSchema: z.ZodObject<{
|
|
|
113
113
|
retract: "retract";
|
|
114
114
|
multi_party_sync: "multi_party_sync";
|
|
115
115
|
}>>;
|
|
116
|
-
}, z.core.$
|
|
116
|
+
}, z.core.$strict>;
|
|
117
117
|
export declare const ConnectionRequestPayloadSchema: z.ZodObject<{
|
|
118
118
|
method: z.ZodEnum<{
|
|
119
119
|
qr: "qr";
|
|
@@ -131,10 +131,10 @@ export declare const ConnectionRequestPayloadSchema: z.ZodObject<{
|
|
|
131
131
|
timezone: z.ZodString;
|
|
132
132
|
meetingHours: z.ZodOptional<z.ZodString>;
|
|
133
133
|
responseSla: z.ZodOptional<z.ZodString>;
|
|
134
|
-
}, z.core.$
|
|
134
|
+
}, z.core.$strict>>;
|
|
135
135
|
openTo: z.ZodArray<z.ZodString>;
|
|
136
|
-
}, z.core.$
|
|
137
|
-
}, z.core.$
|
|
136
|
+
}, z.core.$strict>;
|
|
137
|
+
}, z.core.$strict>;
|
|
138
138
|
export declare const ConnectionResponsePayloadSchema: z.ZodObject<{
|
|
139
139
|
status: z.ZodEnum<{
|
|
140
140
|
accepted: "accepted";
|
|
@@ -149,11 +149,11 @@ export declare const ConnectionResponsePayloadSchema: z.ZodObject<{
|
|
|
149
149
|
timezone: z.ZodString;
|
|
150
150
|
meetingHours: z.ZodOptional<z.ZodString>;
|
|
151
151
|
responseSla: z.ZodOptional<z.ZodString>;
|
|
152
|
-
}, z.core.$
|
|
152
|
+
}, z.core.$strict>>;
|
|
153
153
|
openTo: z.ZodArray<z.ZodString>;
|
|
154
|
-
}, z.core.$
|
|
154
|
+
}, z.core.$strict>>;
|
|
155
155
|
note: z.ZodOptional<z.ZodString>;
|
|
156
|
-
}, z.core.$
|
|
156
|
+
}, z.core.$strict>;
|
|
157
157
|
export declare const FollowUpPayloadSchema: z.ZodObject<{
|
|
158
158
|
referenceId: z.ZodString;
|
|
159
159
|
message: z.ZodString;
|
|
@@ -163,7 +163,7 @@ export declare const FollowUpPayloadSchema: z.ZodObject<{
|
|
|
163
163
|
review: "review";
|
|
164
164
|
none: "none";
|
|
165
165
|
}>>;
|
|
166
|
-
}, z.core.$
|
|
166
|
+
}, z.core.$strict>;
|
|
167
167
|
export declare const AskPayloadSchema: z.ZodObject<{
|
|
168
168
|
question: z.ZodString;
|
|
169
169
|
context: z.ZodOptional<z.ZodString>;
|
|
@@ -173,18 +173,18 @@ export declare const AskPayloadSchema: z.ZodObject<{
|
|
|
173
173
|
}>>;
|
|
174
174
|
choices: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
175
175
|
deadline: z.ZodOptional<z.ZodString>;
|
|
176
|
-
}, z.core.$
|
|
176
|
+
}, z.core.$strict>;
|
|
177
177
|
export declare const AskResponsePayloadSchema: z.ZodObject<{
|
|
178
178
|
answer: z.ZodString;
|
|
179
179
|
choiceIndex: z.ZodOptional<z.ZodNumber>;
|
|
180
|
-
}, z.core.$
|
|
180
|
+
}, z.core.$strict>;
|
|
181
181
|
export declare const PingPayloadSchema: z.ZodObject<{
|
|
182
182
|
note: z.ZodOptional<z.ZodString>;
|
|
183
|
-
}, z.core.$
|
|
183
|
+
}, z.core.$strict>;
|
|
184
184
|
export declare const RetractPayloadSchema: z.ZodObject<{
|
|
185
185
|
targetMessageId: z.ZodString;
|
|
186
186
|
reason: z.ZodOptional<z.ZodString>;
|
|
187
|
-
}, z.core.$
|
|
187
|
+
}, z.core.$strict>;
|
|
188
188
|
export declare const ContextSharePayloadSchema: z.ZodObject<{
|
|
189
189
|
context: z.ZodString;
|
|
190
190
|
category: z.ZodEnum<{
|
|
@@ -196,7 +196,7 @@ export declare const ContextSharePayloadSchema: z.ZodObject<{
|
|
|
196
196
|
}>;
|
|
197
197
|
referenceId: z.ZodOptional<z.ZodString>;
|
|
198
198
|
expiresAt: z.ZodOptional<z.ZodString>;
|
|
199
|
-
}, z.core.$
|
|
199
|
+
}, z.core.$strict>;
|
|
200
200
|
export declare const MultiPartySyncPayloadSchema: z.ZodObject<{
|
|
201
201
|
enclaveType: z.ZodEnum<{
|
|
202
202
|
meeting_sync: "meeting_sync";
|
|
@@ -204,7 +204,7 @@ export declare const MultiPartySyncPayloadSchema: z.ZodObject<{
|
|
|
204
204
|
purpose: z.ZodString;
|
|
205
205
|
participants: z.ZodArray<z.ZodString>;
|
|
206
206
|
expiresAt: z.ZodString;
|
|
207
|
-
}, z.core.$
|
|
207
|
+
}, z.core.$strict>;
|
|
208
208
|
export declare const MessageProvenanceSchema: z.ZodOptional<z.ZodObject<{
|
|
209
209
|
origin: z.ZodEnum<{
|
|
210
210
|
human: "human";
|
|
@@ -213,9 +213,25 @@ export declare const MessageProvenanceSchema: z.ZodOptional<z.ZodObject<{
|
|
|
213
213
|
}>;
|
|
214
214
|
extensionId: z.ZodString;
|
|
215
215
|
installationId: z.ZodString;
|
|
216
|
-
}, z.core.$
|
|
216
|
+
}, z.core.$strict>>;
|
|
217
|
+
/**
|
|
218
|
+
* INK protocol versions a receiver accepts. ink/0.1 is the original wire
|
|
219
|
+
* version; ink/0.2 differs only in the body-signature domain (see
|
|
220
|
+
* src/crypto/sign.ts). The enum is strict: an unknown version is rejected
|
|
221
|
+
* at schema validation, never inferred. Senders still emit ink/0.1 by
|
|
222
|
+
* default; emitting ink/0.2 is a later, negotiated step.
|
|
223
|
+
*/
|
|
224
|
+
export declare const INK_PROTOCOL_VERSIONS: readonly ["ink/0.1", "ink/0.2"];
|
|
225
|
+
export declare const ProtocolVersionSchema: z.ZodEnum<{
|
|
226
|
+
"ink/0.1": "ink/0.1";
|
|
227
|
+
"ink/0.2": "ink/0.2";
|
|
228
|
+
}>;
|
|
229
|
+
export type ProtocolVersion = z.infer<typeof ProtocolVersionSchema>;
|
|
217
230
|
export declare const MessageEnvelopeSchema: z.ZodObject<{
|
|
218
|
-
protocol: z.
|
|
231
|
+
protocol: z.ZodEnum<{
|
|
232
|
+
"ink/0.1": "ink/0.1";
|
|
233
|
+
"ink/0.2": "ink/0.2";
|
|
234
|
+
}>;
|
|
219
235
|
id: z.ZodString;
|
|
220
236
|
correlationId: z.ZodString;
|
|
221
237
|
createdAt: z.ZodString;
|
|
@@ -242,6 +258,8 @@ export declare const MessageEnvelopeSchema: z.ZodObject<{
|
|
|
242
258
|
payload: z.ZodUnknown;
|
|
243
259
|
signature: z.ZodString;
|
|
244
260
|
signingKeyId: z.ZodOptional<z.ZodString>;
|
|
261
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
262
|
+
nonce: z.ZodOptional<z.ZodString>;
|
|
245
263
|
provenance: z.ZodOptional<z.ZodObject<{
|
|
246
264
|
origin: z.ZodEnum<{
|
|
247
265
|
human: "human";
|
|
@@ -250,8 +268,8 @@ export declare const MessageEnvelopeSchema: z.ZodObject<{
|
|
|
250
268
|
}>;
|
|
251
269
|
extensionId: z.ZodString;
|
|
252
270
|
installationId: z.ZodString;
|
|
253
|
-
}, z.core.$
|
|
254
|
-
}, z.core.$
|
|
271
|
+
}, z.core.$strict>>;
|
|
272
|
+
}, z.core.$strict>;
|
|
255
273
|
export type MessageEnvelope = z.infer<typeof MessageEnvelopeSchema>;
|
|
256
274
|
/**
|
|
257
275
|
* Validate a message envelope AND its payload based on the intent type.
|
|
@@ -260,6 +278,10 @@ export type MessageEnvelope = z.infer<typeof MessageEnvelopeSchema>;
|
|
|
260
278
|
export declare function validateMessage(raw: unknown): MessageEnvelope;
|
|
261
279
|
/**
|
|
262
280
|
* Get the payload schema for a given intent type.
|
|
281
|
+
*
|
|
282
|
+
* Runtime-validates the `intent` argument against IntentTypeSchema so a
|
|
283
|
+
* JS caller cannot pass an arbitrary string and silently get `undefined`
|
|
284
|
+
* back; the function instead throws ZodError on an invalid intent.
|
|
263
285
|
*/
|
|
264
286
|
export declare function getPayloadSchema(intent: IntentType): z.ZodObject<{
|
|
265
287
|
proposedTimes: z.ZodArray<z.ZodString>;
|
|
@@ -277,7 +299,7 @@ export declare function getPayloadSchema(intent: IntentType): z.ZodObject<{
|
|
|
277
299
|
}>;
|
|
278
300
|
context: z.ZodOptional<z.ZodString>;
|
|
279
301
|
location: z.ZodOptional<z.ZodString>;
|
|
280
|
-
}, z.core.$
|
|
302
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
281
303
|
status: z.ZodEnum<{
|
|
282
304
|
accepted: "accepted";
|
|
283
305
|
declined: "declined";
|
|
@@ -293,7 +315,7 @@ export declare function getPayloadSchema(intent: IntentType): z.ZodObject<{
|
|
|
293
315
|
too_busy: "too_busy";
|
|
294
316
|
deferred: "deferred";
|
|
295
317
|
}>>;
|
|
296
|
-
}, z.core.$
|
|
318
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
297
319
|
target: z.ZodString;
|
|
298
320
|
reason: z.ZodString;
|
|
299
321
|
context: z.ZodOptional<z.ZodString>;
|
|
@@ -301,7 +323,7 @@ export declare function getPayloadSchema(intent: IntentType): z.ZodObject<{
|
|
|
301
323
|
low: "low";
|
|
302
324
|
normal: "normal";
|
|
303
325
|
}>;
|
|
304
|
-
}, z.core.$
|
|
326
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
305
327
|
status: z.ZodEnum<{
|
|
306
328
|
declined: "declined";
|
|
307
329
|
forwarded: "forwarded";
|
|
@@ -313,7 +335,7 @@ export declare function getPayloadSchema(intent: IntentType): z.ZodObject<{
|
|
|
313
335
|
declined: "declined";
|
|
314
336
|
pending: "pending";
|
|
315
337
|
}>>;
|
|
316
|
-
}, z.core.$
|
|
338
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
317
339
|
type: z.ZodEnum<{
|
|
318
340
|
role: "role";
|
|
319
341
|
investment: "investment";
|
|
@@ -328,7 +350,7 @@ export declare function getPayloadSchema(intent: IntentType): z.ZodObject<{
|
|
|
328
350
|
matchReason: z.ZodString;
|
|
329
351
|
expiresAt: z.ZodOptional<z.ZodString>;
|
|
330
352
|
url: z.ZodOptional<z.ZodString>;
|
|
331
|
-
}, z.core.$
|
|
353
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
332
354
|
status: z.ZodEnum<{
|
|
333
355
|
not_interested: "not_interested";
|
|
334
356
|
interested: "interested";
|
|
@@ -352,7 +374,7 @@ export declare function getPayloadSchema(intent: IntentType): z.ZodObject<{
|
|
|
352
374
|
retract: "retract";
|
|
353
375
|
multi_party_sync: "multi_party_sync";
|
|
354
376
|
}>>;
|
|
355
|
-
}, z.core.$
|
|
377
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
356
378
|
method: z.ZodEnum<{
|
|
357
379
|
qr: "qr";
|
|
358
380
|
intro: "intro";
|
|
@@ -369,10 +391,10 @@ export declare function getPayloadSchema(intent: IntentType): z.ZodObject<{
|
|
|
369
391
|
timezone: z.ZodString;
|
|
370
392
|
meetingHours: z.ZodOptional<z.ZodString>;
|
|
371
393
|
responseSla: z.ZodOptional<z.ZodString>;
|
|
372
|
-
}, z.core.$
|
|
394
|
+
}, z.core.$strict>>;
|
|
373
395
|
openTo: z.ZodArray<z.ZodString>;
|
|
374
|
-
}, z.core.$
|
|
375
|
-
}, z.core.$
|
|
396
|
+
}, z.core.$strict>;
|
|
397
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
376
398
|
status: z.ZodEnum<{
|
|
377
399
|
accepted: "accepted";
|
|
378
400
|
declined: "declined";
|
|
@@ -386,11 +408,11 @@ export declare function getPayloadSchema(intent: IntentType): z.ZodObject<{
|
|
|
386
408
|
timezone: z.ZodString;
|
|
387
409
|
meetingHours: z.ZodOptional<z.ZodString>;
|
|
388
410
|
responseSla: z.ZodOptional<z.ZodString>;
|
|
389
|
-
}, z.core.$
|
|
411
|
+
}, z.core.$strict>>;
|
|
390
412
|
openTo: z.ZodArray<z.ZodString>;
|
|
391
|
-
}, z.core.$
|
|
413
|
+
}, z.core.$strict>>;
|
|
392
414
|
note: z.ZodOptional<z.ZodString>;
|
|
393
|
-
}, z.core.$
|
|
415
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
394
416
|
referenceId: z.ZodString;
|
|
395
417
|
message: z.ZodString;
|
|
396
418
|
actionRequested: z.ZodOptional<z.ZodEnum<{
|
|
@@ -399,7 +421,7 @@ export declare function getPayloadSchema(intent: IntentType): z.ZodObject<{
|
|
|
399
421
|
review: "review";
|
|
400
422
|
none: "none";
|
|
401
423
|
}>>;
|
|
402
|
-
}, z.core.$
|
|
424
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
403
425
|
question: z.ZodString;
|
|
404
426
|
context: z.ZodOptional<z.ZodString>;
|
|
405
427
|
responseFormat: z.ZodOptional<z.ZodEnum<{
|
|
@@ -408,15 +430,15 @@ export declare function getPayloadSchema(intent: IntentType): z.ZodObject<{
|
|
|
408
430
|
}>>;
|
|
409
431
|
choices: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
410
432
|
deadline: z.ZodOptional<z.ZodString>;
|
|
411
|
-
}, z.core.$
|
|
433
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
412
434
|
answer: z.ZodString;
|
|
413
435
|
choiceIndex: z.ZodOptional<z.ZodNumber>;
|
|
414
|
-
}, z.core.$
|
|
436
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
415
437
|
note: z.ZodOptional<z.ZodString>;
|
|
416
|
-
}, z.core.$
|
|
438
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
417
439
|
targetMessageId: z.ZodString;
|
|
418
440
|
reason: z.ZodOptional<z.ZodString>;
|
|
419
|
-
}, z.core.$
|
|
441
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
420
442
|
context: z.ZodString;
|
|
421
443
|
category: z.ZodEnum<{
|
|
422
444
|
availability: "availability";
|
|
@@ -427,11 +449,11 @@ export declare function getPayloadSchema(intent: IntentType): z.ZodObject<{
|
|
|
427
449
|
}>;
|
|
428
450
|
referenceId: z.ZodOptional<z.ZodString>;
|
|
429
451
|
expiresAt: z.ZodOptional<z.ZodString>;
|
|
430
|
-
}, z.core.$
|
|
452
|
+
}, z.core.$strict> | z.ZodObject<{
|
|
431
453
|
enclaveType: z.ZodEnum<{
|
|
432
454
|
meeting_sync: "meeting_sync";
|
|
433
455
|
}>;
|
|
434
456
|
purpose: z.ZodString;
|
|
435
457
|
participants: z.ZodArray<z.ZodString>;
|
|
436
458
|
expiresAt: z.ZodString;
|
|
437
|
-
}, z.core.$
|
|
459
|
+
}, z.core.$strict>;
|
package/dist/models/intent.js
CHANGED
|
@@ -19,35 +19,45 @@ export const IntentTypeSchema = z.enum([
|
|
|
19
19
|
"multi_party_sync",
|
|
20
20
|
]);
|
|
21
21
|
// --- Intent Payloads ---
|
|
22
|
+
// Reusable scalar caps. Timestamps cap at 64 chars (ISO-8601 fits in
|
|
23
|
+
// ~30), correlation/message IDs at 256, DIDs at 512. URL fields cap
|
|
24
|
+
// at 2048 BEFORE `.url()` parsing so the parser never runs on attacker-
|
|
25
|
+
// sized strings. Every exported schema is `.strict()` so adopters using
|
|
26
|
+
// the schemas directly (without `validateMessage()`) still get the
|
|
27
|
+
// same unknown-field rejection that the central validator applies.
|
|
28
|
+
const TIMESTAMP_MAX = 64;
|
|
29
|
+
const ID_MAX = 256;
|
|
30
|
+
const DID_MAX = 512;
|
|
31
|
+
const URL_MAX = 2048;
|
|
22
32
|
export const ScheduleMeetingPayloadSchema = z.object({
|
|
23
|
-
proposedTimes: z.array(z.string()).min(1).max(10),
|
|
33
|
+
proposedTimes: z.array(z.string().max(TIMESTAMP_MAX)).min(1).max(10),
|
|
24
34
|
topic: z.string().max(500),
|
|
25
35
|
format: z.enum(["video", "phone", "in_person", "async"]),
|
|
26
36
|
urgency: z.enum(["low", "normal", "urgent"]),
|
|
27
37
|
context: z.string().max(2000).optional(),
|
|
28
38
|
location: z.string().max(500).optional(),
|
|
29
|
-
});
|
|
39
|
+
}).strict();
|
|
30
40
|
export const ScheduleMeetingResponsePayloadSchema = z.object({
|
|
31
41
|
status: z.enum(["accepted", "declined", "countered"]),
|
|
32
|
-
confirmedTime: z.string().optional(),
|
|
33
|
-
counterTimes: z.array(z.string()).max(10).optional(),
|
|
34
|
-
meetingLink: z.string().url().optional(),
|
|
42
|
+
confirmedTime: z.string().max(TIMESTAMP_MAX).optional(),
|
|
43
|
+
counterTimes: z.array(z.string().max(TIMESTAMP_MAX)).max(10).optional(),
|
|
44
|
+
meetingLink: z.string().max(URL_MAX).url().optional(),
|
|
35
45
|
note: z.string().max(1000).optional(),
|
|
36
46
|
declineReason: z
|
|
37
47
|
.enum(["unavailable", "not_interested", "too_busy", "deferred"])
|
|
38
48
|
.optional(),
|
|
39
|
-
});
|
|
49
|
+
}).strict();
|
|
40
50
|
export const IntroRequestPayloadSchema = z.object({
|
|
41
|
-
target: z.string(),
|
|
51
|
+
target: z.string().max(DID_MAX),
|
|
42
52
|
reason: z.string().max(2000),
|
|
43
53
|
context: z.string().max(2000).optional(),
|
|
44
54
|
urgency: z.enum(["low", "normal"]),
|
|
45
|
-
});
|
|
55
|
+
}).strict();
|
|
46
56
|
export const IntroResponsePayloadSchema = z.object({
|
|
47
57
|
status: z.enum(["forwarded", "declined", "pending_target"]),
|
|
48
58
|
note: z.string().max(1000).optional(),
|
|
49
59
|
targetResponse: z.enum(["accepted", "declined", "pending"]).optional(),
|
|
50
|
-
});
|
|
60
|
+
}).strict();
|
|
51
61
|
export const OpportunityPayloadSchema = z.object({
|
|
52
62
|
type: z.enum([
|
|
53
63
|
"role",
|
|
@@ -61,60 +71,60 @@ export const OpportunityPayloadSchema = z.object({
|
|
|
61
71
|
org: z.string().max(200).optional(),
|
|
62
72
|
description: z.string().max(5000),
|
|
63
73
|
matchReason: z.string().max(2000),
|
|
64
|
-
expiresAt: z.string().optional(),
|
|
65
|
-
url: z.string().url().optional(),
|
|
66
|
-
});
|
|
74
|
+
expiresAt: z.string().max(TIMESTAMP_MAX).optional(),
|
|
75
|
+
url: z.string().max(URL_MAX).url().optional(),
|
|
76
|
+
}).strict();
|
|
67
77
|
export const OpportunityResponsePayloadSchema = z.object({
|
|
68
78
|
status: z.enum(["interested", "not_interested", "maybe_later"]),
|
|
69
79
|
note: z.string().max(1000).optional(),
|
|
70
80
|
followUpIntent: IntentTypeSchema.optional(),
|
|
71
|
-
});
|
|
81
|
+
}).strict();
|
|
72
82
|
export const ConnectionRequestPayloadSchema = z.object({
|
|
73
83
|
method: z.enum(["qr", "intro", "discovery", "import"]),
|
|
74
|
-
introducedBy: z.string().optional(),
|
|
84
|
+
introducedBy: z.string().max(DID_MAX).optional(),
|
|
75
85
|
context: z.string().max(2000),
|
|
76
86
|
profileSnapshot: ProfileSnapshotSchema,
|
|
77
|
-
});
|
|
87
|
+
}).strict();
|
|
78
88
|
export const ConnectionResponsePayloadSchema = z.object({
|
|
79
89
|
status: z.enum(["accepted", "declined", "pending"]),
|
|
80
90
|
profileSnapshot: ProfileSnapshotSchema.optional(),
|
|
81
91
|
note: z.string().max(1000).optional(),
|
|
82
|
-
});
|
|
92
|
+
}).strict();
|
|
83
93
|
export const FollowUpPayloadSchema = z.object({
|
|
84
|
-
referenceId: z.string(),
|
|
94
|
+
referenceId: z.string().max(ID_MAX),
|
|
85
95
|
message: z.string().max(5000),
|
|
86
96
|
actionRequested: z.enum(["reply", "schedule", "review", "none"]).optional(),
|
|
87
|
-
});
|
|
97
|
+
}).strict();
|
|
88
98
|
export const AskPayloadSchema = z.object({
|
|
89
99
|
question: z.string().max(5000),
|
|
90
100
|
context: z.string().max(2000).optional(),
|
|
91
101
|
responseFormat: z.enum(["text", "choice"]).optional(),
|
|
92
102
|
choices: z.array(z.string().max(500)).max(10).optional(),
|
|
93
|
-
deadline: z.string().optional(),
|
|
94
|
-
});
|
|
103
|
+
deadline: z.string().max(TIMESTAMP_MAX).optional(),
|
|
104
|
+
}).strict();
|
|
95
105
|
export const AskResponsePayloadSchema = z.object({
|
|
96
106
|
answer: z.string().max(5000),
|
|
97
107
|
choiceIndex: z.number().int().min(0).optional(),
|
|
98
|
-
});
|
|
108
|
+
}).strict();
|
|
99
109
|
export const PingPayloadSchema = z.object({
|
|
100
110
|
note: z.string().max(1000).optional(),
|
|
101
|
-
});
|
|
111
|
+
}).strict();
|
|
102
112
|
export const RetractPayloadSchema = z.object({
|
|
103
|
-
targetMessageId: z.string(),
|
|
113
|
+
targetMessageId: z.string().max(ID_MAX),
|
|
104
114
|
reason: z.string().max(1000).optional(),
|
|
105
|
-
});
|
|
115
|
+
}).strict();
|
|
106
116
|
export const ContextSharePayloadSchema = z.object({
|
|
107
117
|
context: z.string().max(5000),
|
|
108
118
|
category: z.enum(["professional_background", "project_update", "expertise", "availability", "general"]),
|
|
109
|
-
referenceId: z.string().optional(),
|
|
110
|
-
expiresAt: z.string().optional(),
|
|
111
|
-
});
|
|
119
|
+
referenceId: z.string().max(ID_MAX).optional(),
|
|
120
|
+
expiresAt: z.string().max(TIMESTAMP_MAX).optional(),
|
|
121
|
+
}).strict();
|
|
112
122
|
export const MultiPartySyncPayloadSchema = z.object({
|
|
113
123
|
enclaveType: z.enum(["meeting_sync"]),
|
|
114
124
|
purpose: z.string().max(500),
|
|
115
|
-
participants: z.array(z.string()).min(2).max(20),
|
|
116
|
-
expiresAt: z.string(),
|
|
117
|
-
});
|
|
125
|
+
participants: z.array(z.string().max(DID_MAX)).min(2).max(20),
|
|
126
|
+
expiresAt: z.string().max(TIMESTAMP_MAX),
|
|
127
|
+
}).strict();
|
|
118
128
|
// --- Payload discriminated union ---
|
|
119
129
|
const payloadSchemas = {
|
|
120
130
|
schedule_meeting: ScheduleMeetingPayloadSchema,
|
|
@@ -134,25 +144,48 @@ const payloadSchemas = {
|
|
|
134
144
|
multi_party_sync: MultiPartySyncPayloadSchema,
|
|
135
145
|
};
|
|
136
146
|
// --- Message Envelope ---
|
|
147
|
+
// Caps for envelope-level fields. Signatures are base64url-encoded
|
|
148
|
+
// Ed25519 (64 bytes raw → 86 chars base64url, plus the legacy keyId=
|
|
149
|
+
// suffix). 256 is comfortable headroom without permitting megabyte
|
|
150
|
+
// signature blobs.
|
|
151
|
+
const SIGNATURE_MAX = 256;
|
|
152
|
+
const KEY_ID_MAX = 128;
|
|
137
153
|
export const MessageProvenanceSchema = z.object({
|
|
138
154
|
origin: z.enum(["human", "agent_approved", "agent_autonomous"]),
|
|
139
|
-
extensionId: z.string(),
|
|
155
|
+
extensionId: z.string().max(ID_MAX),
|
|
140
156
|
installationId: z.string().uuid(),
|
|
141
|
-
}).optional();
|
|
157
|
+
}).strict().optional();
|
|
158
|
+
/**
|
|
159
|
+
* INK protocol versions a receiver accepts. ink/0.1 is the original wire
|
|
160
|
+
* version; ink/0.2 differs only in the body-signature domain (see
|
|
161
|
+
* src/crypto/sign.ts). The enum is strict: an unknown version is rejected
|
|
162
|
+
* at schema validation, never inferred. Senders still emit ink/0.1 by
|
|
163
|
+
* default; emitting ink/0.2 is a later, negotiated step.
|
|
164
|
+
*/
|
|
165
|
+
export const INK_PROTOCOL_VERSIONS = ["ink/0.1", "ink/0.2"];
|
|
166
|
+
export const ProtocolVersionSchema = z.enum(INK_PROTOCOL_VERSIONS);
|
|
142
167
|
export const MessageEnvelopeSchema = z.object({
|
|
143
|
-
protocol:
|
|
144
|
-
id: z.string(),
|
|
145
|
-
correlationId: z.string(),
|
|
146
|
-
createdAt: z.string(),
|
|
147
|
-
expiresAt: z.string().optional(),
|
|
148
|
-
from: z.string(),
|
|
149
|
-
to: z.string(),
|
|
168
|
+
protocol: ProtocolVersionSchema,
|
|
169
|
+
id: z.string().max(ID_MAX),
|
|
170
|
+
correlationId: z.string().max(ID_MAX),
|
|
171
|
+
createdAt: z.string().max(TIMESTAMP_MAX),
|
|
172
|
+
expiresAt: z.string().max(TIMESTAMP_MAX).optional(),
|
|
173
|
+
from: z.string().max(DID_MAX),
|
|
174
|
+
to: z.string().max(DID_MAX),
|
|
150
175
|
intent: IntentTypeSchema,
|
|
151
176
|
payload: z.unknown(),
|
|
152
|
-
signature: z.string(),
|
|
153
|
-
signingKeyId: z.string().optional(),
|
|
177
|
+
signature: z.string().max(SIGNATURE_MAX),
|
|
178
|
+
signingKeyId: z.string().max(KEY_ID_MAX).optional(),
|
|
179
|
+
// HTTP §3.3 transport-auth metadata that rides alongside the
|
|
180
|
+
// canonical envelope fields. The body-level signature commits to
|
|
181
|
+
// both (they cannot be tampered in transit) and `verifyInkAuth`
|
|
182
|
+
// reads them from the body for freshness + replay checks. Explicit
|
|
183
|
+
// optional capped declarations are required for `.strict()` to keep
|
|
184
|
+
// accepting documented sender envelopes (see README signing example).
|
|
185
|
+
timestamp: z.string().max(TIMESTAMP_MAX).optional(),
|
|
186
|
+
nonce: z.string().max(ID_MAX).optional(),
|
|
154
187
|
provenance: MessageProvenanceSchema,
|
|
155
|
-
});
|
|
188
|
+
}).strict();
|
|
156
189
|
/**
|
|
157
190
|
* Validate a message envelope AND its payload based on the intent type.
|
|
158
191
|
* Returns the validated message or throws a ZodError.
|
|
@@ -166,7 +199,12 @@ export function validateMessage(raw) {
|
|
|
166
199
|
}
|
|
167
200
|
/**
|
|
168
201
|
* Get the payload schema for a given intent type.
|
|
202
|
+
*
|
|
203
|
+
* Runtime-validates the `intent` argument against IntentTypeSchema so a
|
|
204
|
+
* JS caller cannot pass an arbitrary string and silently get `undefined`
|
|
205
|
+
* back; the function instead throws ZodError on an invalid intent.
|
|
169
206
|
*/
|
|
170
207
|
export function getPayloadSchema(intent) {
|
|
208
|
+
IntentTypeSchema.parse(intent);
|
|
171
209
|
return payloadSchemas[intent];
|
|
172
210
|
}
|
package/dist/models/profile.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export declare const AvailabilityConfigSchema: z.ZodObject<{
|
|
|
3
3
|
timezone: z.ZodString;
|
|
4
4
|
meetingHours: z.ZodOptional<z.ZodString>;
|
|
5
5
|
responseSla: z.ZodOptional<z.ZodString>;
|
|
6
|
-
}, z.core.$
|
|
6
|
+
}, z.core.$strict>;
|
|
7
7
|
export declare const ProfileSnapshotSchema: z.ZodObject<{
|
|
8
8
|
headline: z.ZodString;
|
|
9
9
|
skills: z.ZodArray<z.ZodString>;
|
|
@@ -12,9 +12,9 @@ export declare const ProfileSnapshotSchema: z.ZodObject<{
|
|
|
12
12
|
timezone: z.ZodString;
|
|
13
13
|
meetingHours: z.ZodOptional<z.ZodString>;
|
|
14
14
|
responseSla: z.ZodOptional<z.ZodString>;
|
|
15
|
-
}, z.core.$
|
|
15
|
+
}, z.core.$strict>>;
|
|
16
16
|
openTo: z.ZodArray<z.ZodString>;
|
|
17
|
-
}, z.core.$
|
|
17
|
+
}, z.core.$strict>;
|
|
18
18
|
export declare const ProfileSchema: z.ZodObject<{
|
|
19
19
|
agentId: z.ZodString;
|
|
20
20
|
handle: z.ZodString;
|
|
@@ -29,9 +29,9 @@ export declare const ProfileSchema: z.ZodObject<{
|
|
|
29
29
|
timezone: z.ZodString;
|
|
30
30
|
meetingHours: z.ZodOptional<z.ZodString>;
|
|
31
31
|
responseSla: z.ZodOptional<z.ZodString>;
|
|
32
|
-
}, z.core.$
|
|
32
|
+
}, z.core.$strict>>;
|
|
33
33
|
openTo: z.ZodArray<z.ZodString>;
|
|
34
|
-
}, z.core.$
|
|
34
|
+
}, z.core.$strict>;
|
|
35
35
|
connected: z.ZodObject<{
|
|
36
36
|
headline: z.ZodString;
|
|
37
37
|
skills: z.ZodArray<z.ZodString>;
|
|
@@ -40,9 +40,9 @@ export declare const ProfileSchema: z.ZodObject<{
|
|
|
40
40
|
timezone: z.ZodString;
|
|
41
41
|
meetingHours: z.ZodOptional<z.ZodString>;
|
|
42
42
|
responseSla: z.ZodOptional<z.ZodString>;
|
|
43
|
-
}, z.core.$
|
|
43
|
+
}, z.core.$strict>>;
|
|
44
44
|
openTo: z.ZodArray<z.ZodString>;
|
|
45
|
-
}, z.core.$
|
|
45
|
+
}, z.core.$strict>;
|
|
46
46
|
custom: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
47
47
|
headline: z.ZodString;
|
|
48
48
|
skills: z.ZodArray<z.ZodString>;
|
|
@@ -51,9 +51,9 @@ export declare const ProfileSchema: z.ZodObject<{
|
|
|
51
51
|
timezone: z.ZodString;
|
|
52
52
|
meetingHours: z.ZodOptional<z.ZodString>;
|
|
53
53
|
responseSla: z.ZodOptional<z.ZodString>;
|
|
54
|
-
}, z.core.$
|
|
54
|
+
}, z.core.$strict>>;
|
|
55
55
|
openTo: z.ZodArray<z.ZodString>;
|
|
56
|
-
}, z.core.$
|
|
56
|
+
}, z.core.$strict>>;
|
|
57
57
|
}, z.core.$strip>;
|
|
58
58
|
}, z.core.$strip>;
|
|
59
59
|
export type AvailabilityConfig = z.infer<typeof AvailabilityConfigSchema>;
|
package/dist/models/profile.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export const AvailabilityConfigSchema = z.object({
|
|
3
|
-
timezone
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
// IANA timezone name. The longest legitimate value is ~50 chars.
|
|
4
|
+
timezone: z.string().max(64),
|
|
5
|
+
// Free-text availability description ("9-5 PT weekdays") capped
|
|
6
|
+
// to a sane display length. Larger values are almost certainly
|
|
7
|
+
// garbage or an attempted DoS.
|
|
8
|
+
meetingHours: z.string().max(200).optional(),
|
|
9
|
+
responseSla: z.string().max(200).optional(),
|
|
10
|
+
}).strict();
|
|
7
11
|
export const ProfileSnapshotSchema = z.object({
|
|
8
12
|
headline: z.string().max(500),
|
|
9
13
|
skills: z.array(z.string().max(100)).max(50),
|
|
10
14
|
interests: z.array(z.string().max(100)).max(50),
|
|
11
15
|
availability: AvailabilityConfigSchema.optional(),
|
|
12
16
|
openTo: z.array(z.string().max(100)).max(20),
|
|
13
|
-
});
|
|
17
|
+
}).strict();
|
|
14
18
|
export const ProfileSchema = z.object({
|
|
15
19
|
agentId: z.string(),
|
|
16
20
|
handle: z.string(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adastracomputing/ink",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Library and specification for the INK (Inter-agent Networking Kernel) protocol",
|
|
5
5
|
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"author": "Ad Astra Computing Inc.",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"lint": "eslint src/ test/ scripts/",
|
|
50
50
|
"check:surface": "tsx scripts/check-public-surface.ts",
|
|
51
51
|
"check:pack": "./scripts/check-pack.sh",
|
|
52
|
+
"gen:body-vectors": "tsx scripts/gen-body-signature-vectors.ts",
|
|
52
53
|
"prepack": "npm run build",
|
|
53
54
|
"prepublishOnly": "npm run build"
|
|
54
55
|
},
|
package/test-vectors/README.md
CHANGED
|
@@ -7,16 +7,17 @@ Reference test vectors for INK v0.1 signing, encryption, replay protection, hand
|
|
|
7
7
|
| File | Covers | Vector count |
|
|
8
8
|
|------|--------|-------------|
|
|
9
9
|
| `keys.json` | Fixed Ed25519 and X25519 key pairs for Alice and Bob (hex-encoded) |, |
|
|
10
|
-
| `signing.json` |
|
|
10
|
+
| `signing.json` | Transport-auth signature generation and verification (§3.3) | 3 |
|
|
11
|
+
| `body-signature.json` | Version-keyed body message signature: legacy vs ink/0.2 domain, plus cross-version and tamper cases | 9 |
|
|
11
12
|
| `encryption.json` | ECIES encryption/decryption (§3.4) | 2 |
|
|
12
|
-
| `jcs.json` | JCS canonicalization (RFC 8785) |
|
|
13
|
+
| `jcs.json` | JCS canonicalization (RFC 8785) | 2 |
|
|
13
14
|
| `replay.json` | Replay protection acceptance/rejection (§3.5) | 6 |
|
|
14
15
|
| `receipts-and-audit.json` | Receipt signatures, audit query signatures, hash-chained audit events and fork detection (Auditability §1–§3) | 4 |
|
|
15
16
|
| `handshake.json` | Challenge (Stage 2a), rejection (Stage 2b) and resolution (Stage 3), valid signatures, path/recipient/body binding failures, replay protection | 22 |
|
|
16
17
|
| `witness.json` | Audit submit and query with INK transport auth, plus cross-service interop cases | 15 |
|
|
17
18
|
| `key-rotation.json` | Auth header keyId format, rotated-key verification, historical verification, revoked-key rejection, refresh-on-miss, keyId precedence, unknown keyId fallthrough, audit event signingKeyId tracking | 8 |
|
|
18
19
|
|
|
19
|
-
**Total:
|
|
20
|
+
**Total: 71 deterministic vectors across 10 families**
|
|
20
21
|
|
|
21
22
|
## Vector categories
|
|
22
23
|
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "INK body message signature: domain is keyed off the signed protocol field (ink/0.2 -> ink/sign, else tulpa/sign). Verify each body with the signer public key; signatureVerifies is the expected verifyMessage result.",
|
|
3
|
+
"vectors": [
|
|
4
|
+
{
|
|
5
|
+
"description": "ink/0.1 body signed under the legacy tulpa/sign domain verifies",
|
|
6
|
+
"input": {
|
|
7
|
+
"body": {
|
|
8
|
+
"protocol": "ink/0.1",
|
|
9
|
+
"id": "01HVECTORID0000000000000000",
|
|
10
|
+
"from": "did:key:zAlice",
|
|
11
|
+
"to": "did:key:zBob",
|
|
12
|
+
"intent": "connection_request",
|
|
13
|
+
"payload": {
|
|
14
|
+
"method": "discovery"
|
|
15
|
+
},
|
|
16
|
+
"timestamp": "2026-06-03T00:00:00Z",
|
|
17
|
+
"nonce": "ZmtmaXhlZG5vbmNl",
|
|
18
|
+
"signature": "W44kkGyQFg348NADetWQPq5Ogi7rL_72CwjmK-XVn2hL8sXYuSM7cFaDVidGV5LeK3dmmqW6iu5QiWkm6qboAQ"
|
|
19
|
+
},
|
|
20
|
+
"signerPublicKeyHex": "79b5562e8fe654f94078b112e8a98ba7901f853ae695bed7e0e3910bad049664"
|
|
21
|
+
},
|
|
22
|
+
"expected": {
|
|
23
|
+
"signatureVerifies": true
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"description": "ink/0.2 body signed under the ink/sign domain verifies",
|
|
28
|
+
"input": {
|
|
29
|
+
"body": {
|
|
30
|
+
"protocol": "ink/0.2",
|
|
31
|
+
"id": "01HVECTORID0000000000000000",
|
|
32
|
+
"from": "did:key:zAlice",
|
|
33
|
+
"to": "did:key:zBob",
|
|
34
|
+
"intent": "connection_request",
|
|
35
|
+
"payload": {
|
|
36
|
+
"method": "discovery"
|
|
37
|
+
},
|
|
38
|
+
"timestamp": "2026-06-03T00:00:00Z",
|
|
39
|
+
"nonce": "ZmtmaXhlZG5vbmNl",
|
|
40
|
+
"signature": "UAITw3Qqcg96s4r5tmxHXGpuHCfzJBgxihVRPdR8FYcQKk2nYcYxrV8fRFUH3NB_-z-006tFWgZfzJbFILw4Bg"
|
|
41
|
+
},
|
|
42
|
+
"signerPublicKeyHex": "79b5562e8fe654f94078b112e8a98ba7901f853ae695bed7e0e3910bad049664"
|
|
43
|
+
},
|
|
44
|
+
"expected": {
|
|
45
|
+
"signatureVerifies": true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"description": "protocol-less body signed under the legacy domain verifies",
|
|
50
|
+
"input": {
|
|
51
|
+
"body": {
|
|
52
|
+
"id": "01HVECTORID0000000000000000",
|
|
53
|
+
"from": "did:key:zAlice",
|
|
54
|
+
"to": "did:key:zBob",
|
|
55
|
+
"intent": "connection_request",
|
|
56
|
+
"payload": {
|
|
57
|
+
"method": "discovery"
|
|
58
|
+
},
|
|
59
|
+
"timestamp": "2026-06-03T00:00:00Z",
|
|
60
|
+
"nonce": "ZmtmaXhlZG5vbmNl",
|
|
61
|
+
"signature": "qP1oxHKCEImzkYT8Iz00N4Crqi5prbKRguKj_zg8YlLyCrE4CmElrNWECEBWBe-8XV_rNB4oMc1wReXwHqOFCA"
|
|
62
|
+
},
|
|
63
|
+
"signerPublicKeyHex": "79b5562e8fe654f94078b112e8a98ba7901f853ae695bed7e0e3910bad049664"
|
|
64
|
+
},
|
|
65
|
+
"expected": {
|
|
66
|
+
"signatureVerifies": true
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"description": "ink/0.2 body relabelled ink/0.1 (domain mismatch) does not verify",
|
|
71
|
+
"input": {
|
|
72
|
+
"body": {
|
|
73
|
+
"protocol": "ink/0.1",
|
|
74
|
+
"id": "01HVECTORID0000000000000000",
|
|
75
|
+
"from": "did:key:zAlice",
|
|
76
|
+
"to": "did:key:zBob",
|
|
77
|
+
"intent": "connection_request",
|
|
78
|
+
"payload": {
|
|
79
|
+
"method": "discovery"
|
|
80
|
+
},
|
|
81
|
+
"timestamp": "2026-06-03T00:00:00Z",
|
|
82
|
+
"nonce": "ZmtmaXhlZG5vbmNl",
|
|
83
|
+
"signature": "UAITw3Qqcg96s4r5tmxHXGpuHCfzJBgxihVRPdR8FYcQKk2nYcYxrV8fRFUH3NB_-z-006tFWgZfzJbFILw4Bg"
|
|
84
|
+
},
|
|
85
|
+
"signerPublicKeyHex": "79b5562e8fe654f94078b112e8a98ba7901f853ae695bed7e0e3910bad049664"
|
|
86
|
+
},
|
|
87
|
+
"expected": {
|
|
88
|
+
"signatureVerifies": false
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"description": "ink/0.1 body relabelled ink/0.2 (domain mismatch) does not verify",
|
|
93
|
+
"input": {
|
|
94
|
+
"body": {
|
|
95
|
+
"protocol": "ink/0.2",
|
|
96
|
+
"id": "01HVECTORID0000000000000000",
|
|
97
|
+
"from": "did:key:zAlice",
|
|
98
|
+
"to": "did:key:zBob",
|
|
99
|
+
"intent": "connection_request",
|
|
100
|
+
"payload": {
|
|
101
|
+
"method": "discovery"
|
|
102
|
+
},
|
|
103
|
+
"timestamp": "2026-06-03T00:00:00Z",
|
|
104
|
+
"nonce": "ZmtmaXhlZG5vbmNl",
|
|
105
|
+
"signature": "W44kkGyQFg348NADetWQPq5Ogi7rL_72CwjmK-XVn2hL8sXYuSM7cFaDVidGV5LeK3dmmqW6iu5QiWkm6qboAQ"
|
|
106
|
+
},
|
|
107
|
+
"signerPublicKeyHex": "79b5562e8fe654f94078b112e8a98ba7901f853ae695bed7e0e3910bad049664"
|
|
108
|
+
},
|
|
109
|
+
"expected": {
|
|
110
|
+
"signatureVerifies": false
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"description": "ink/0.2 body with protocol removed (falls back to legacy domain) does not verify",
|
|
115
|
+
"input": {
|
|
116
|
+
"body": {
|
|
117
|
+
"id": "01HVECTORID0000000000000000",
|
|
118
|
+
"from": "did:key:zAlice",
|
|
119
|
+
"to": "did:key:zBob",
|
|
120
|
+
"intent": "connection_request",
|
|
121
|
+
"payload": {
|
|
122
|
+
"method": "discovery"
|
|
123
|
+
},
|
|
124
|
+
"timestamp": "2026-06-03T00:00:00Z",
|
|
125
|
+
"nonce": "ZmtmaXhlZG5vbmNl",
|
|
126
|
+
"signature": "UAITw3Qqcg96s4r5tmxHXGpuHCfzJBgxihVRPdR8FYcQKk2nYcYxrV8fRFUH3NB_-z-006tFWgZfzJbFILw4Bg"
|
|
127
|
+
},
|
|
128
|
+
"signerPublicKeyHex": "79b5562e8fe654f94078b112e8a98ba7901f853ae695bed7e0e3910bad049664"
|
|
129
|
+
},
|
|
130
|
+
"expected": {
|
|
131
|
+
"signatureVerifies": false
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"description": "ink/0.1 body with a flipped payload field does not verify",
|
|
136
|
+
"input": {
|
|
137
|
+
"body": {
|
|
138
|
+
"protocol": "ink/0.1",
|
|
139
|
+
"id": "01HVECTORID0000000000000000",
|
|
140
|
+
"from": "did:key:zAlice",
|
|
141
|
+
"to": "did:key:zBob",
|
|
142
|
+
"intent": "connection_request",
|
|
143
|
+
"payload": {
|
|
144
|
+
"method": "qr"
|
|
145
|
+
},
|
|
146
|
+
"timestamp": "2026-06-03T00:00:00Z",
|
|
147
|
+
"nonce": "ZmtmaXhlZG5vbmNl",
|
|
148
|
+
"signature": "W44kkGyQFg348NADetWQPq5Ogi7rL_72CwjmK-XVn2hL8sXYuSM7cFaDVidGV5LeK3dmmqW6iu5QiWkm6qboAQ"
|
|
149
|
+
},
|
|
150
|
+
"signerPublicKeyHex": "79b5562e8fe654f94078b112e8a98ba7901f853ae695bed7e0e3910bad049664"
|
|
151
|
+
},
|
|
152
|
+
"expected": {
|
|
153
|
+
"signatureVerifies": false
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"description": "ink/0.2 body signed under the legacy domain does not verify (a verifier must not try both domains)",
|
|
158
|
+
"input": {
|
|
159
|
+
"body": {
|
|
160
|
+
"protocol": "ink/0.2",
|
|
161
|
+
"id": "01HVECTORID0000000000000000",
|
|
162
|
+
"from": "did:key:zAlice",
|
|
163
|
+
"to": "did:key:zBob",
|
|
164
|
+
"intent": "connection_request",
|
|
165
|
+
"payload": {
|
|
166
|
+
"method": "discovery"
|
|
167
|
+
},
|
|
168
|
+
"timestamp": "2026-06-03T00:00:00Z",
|
|
169
|
+
"nonce": "ZmtmaXhlZG5vbmNl",
|
|
170
|
+
"signature": "axpZvQqF8KPG-Mh1q3hnfZhnaSUHbYfToUz-wA_WD7PV0qKOnVHpuTu8DTaR0OTtGBVHoqpoQFlfMVskELfgDg"
|
|
171
|
+
},
|
|
172
|
+
"signerPublicKeyHex": "79b5562e8fe654f94078b112e8a98ba7901f853ae695bed7e0e3910bad049664"
|
|
173
|
+
},
|
|
174
|
+
"expected": {
|
|
175
|
+
"signatureVerifies": false
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"description": "unknown protocol string uses the legacy body-signature domain and verifies",
|
|
180
|
+
"input": {
|
|
181
|
+
"body": {
|
|
182
|
+
"protocol": "ink/0.3",
|
|
183
|
+
"id": "01HVECTORID0000000000000000",
|
|
184
|
+
"from": "did:key:zAlice",
|
|
185
|
+
"to": "did:key:zBob",
|
|
186
|
+
"intent": "connection_request",
|
|
187
|
+
"payload": {
|
|
188
|
+
"method": "discovery"
|
|
189
|
+
},
|
|
190
|
+
"timestamp": "2026-06-03T00:00:00Z",
|
|
191
|
+
"nonce": "ZmtmaXhlZG5vbmNl",
|
|
192
|
+
"signature": "I3JIzt0kg9zncGvRU9nSZ2ldVrE4L9JnolDJAgW4kNUAqmp6bLAfPptfbYttqp1nTX4OB3oCCOOBPFCA7Fw4Cw"
|
|
193
|
+
},
|
|
194
|
+
"signerPublicKeyHex": "79b5562e8fe654f94078b112e8a98ba7901f853ae695bed7e0e3910bad049664"
|
|
195
|
+
},
|
|
196
|
+
"expected": {
|
|
197
|
+
"signatureVerifies": true
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
}
|