@kya-os/contracts 1.5.3-canary.2 → 1.5.3-canary.20
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/.turbo/turbo-build.log +17 -0
- package/.turbo/turbo-test$colon$coverage.log +85 -0
- package/.turbo/turbo-test.log +32 -0
- package/coverage/coverage-final.json +38 -0
- package/dist/agentshield-api/admin-schemas.d.ts +2 -2
- package/dist/agentshield-api/index.d.ts +1 -1
- package/dist/agentshield-api/schemas.d.ts +150 -48
- package/dist/agentshield-api/schemas.js +32 -4
- package/dist/agentshield-api/types.d.ts +31 -4
- package/dist/audit/index.d.ts +193 -0
- package/dist/audit/index.js +100 -0
- package/dist/config/identity.d.ts +205 -2
- package/dist/config/identity.js +28 -0
- package/dist/config/index.d.ts +2 -1
- package/dist/config/tool-context.d.ts +34 -0
- package/dist/config/tool-context.js +13 -0
- package/dist/consent/schemas.d.ts +119 -93
- package/dist/consent/schemas.js +111 -64
- package/dist/dashboard-config/schemas.d.ts +1949 -693
- package/dist/handshake.d.ts +14 -14
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/tool-protection/index.d.ts +430 -2
- package/dist/tool-protection/index.js +62 -2
- package/dist/verifier/index.d.ts +1 -0
- package/dist/verifier/index.js +18 -0
- package/dist/well-known/index.d.ts +2 -2
- package/package.json +43 -122
- package/schemas/cli/register-output/v1.0.0.json +69 -0
- package/schemas/identity/v1.0.0.json +46 -0
- package/schemas/proof/v1.0.0.json +80 -0
- package/schemas/registry/receipt-v1.0.0.json +60 -0
- package/schemas/verifier/verify-page/v1.0.0.json +94 -0
- package/schemas/well-known/agent/v1.0.0.json +67 -0
- package/schemas/well-known/did/v1.0.0.json +174 -0
- package/scripts/emit-schemas.js +11 -0
- package/src/agentshield-api/admin-schemas.ts +31 -0
- package/src/agentshield-api/admin-types.ts +47 -0
- package/src/agentshield-api/endpoints.ts +60 -0
- package/src/agentshield-api/index.ts +70 -0
- package/src/agentshield-api/schemas.ts +304 -0
- package/src/agentshield-api/types.ts +317 -0
- package/src/audit/index.ts +128 -0
- package/src/cli.ts +156 -0
- package/src/config/base.ts +107 -0
- package/src/config/builder.ts +97 -0
- package/src/config/delegation.ts +232 -0
- package/src/config/identity.ts +252 -0
- package/src/config/index.ts +78 -0
- package/src/config/proofing.ts +138 -0
- package/src/config/tool-context.ts +41 -0
- package/src/config/tool-protection.ts +174 -0
- package/src/consent/index.ts +32 -0
- package/src/consent/schemas.ts +334 -0
- package/src/consent/types.ts +199 -0
- package/src/dashboard-config/default-config.json +86 -0
- package/src/dashboard-config/default-config.ts +266 -0
- package/src/dashboard-config/index.ts +48 -0
- package/src/dashboard-config/schemas.ts +286 -0
- package/src/dashboard-config/types.ts +404 -0
- package/src/delegation/constraints.ts +267 -0
- package/src/delegation/index.ts +8 -0
- package/src/delegation/schemas.ts +595 -0
- package/src/did/index.ts +9 -0
- package/src/did/resolve-contract.ts +255 -0
- package/src/did/schemas.ts +190 -0
- package/src/did/types.ts +224 -0
- package/src/env/constants.ts +70 -0
- package/src/env/index.ts +5 -0
- package/src/handshake.ts +125 -0
- package/src/index.ts +45 -0
- package/src/proof/index.ts +31 -0
- package/src/proof/proof-record.ts +163 -0
- package/src/proof/signing-spec.ts +146 -0
- package/src/proof.ts +99 -0
- package/src/registry.ts +146 -0
- package/src/runtime/errors.ts +153 -0
- package/src/runtime/headers.ts +136 -0
- package/src/runtime/index.ts +6 -0
- package/src/test.ts +143 -0
- package/src/tlkrc/index.ts +5 -0
- package/src/tlkrc/rotation.ts +153 -0
- package/src/tool-protection/index.ts +343 -0
- package/src/utils/validation.ts +93 -0
- package/src/vc/index.ts +8 -0
- package/src/vc/schemas.ts +277 -0
- package/src/vc/statuslist.ts +279 -0
- package/src/verifier/index.ts +2 -0
- package/src/verifier.ts +92 -0
- package/src/well-known/index.ts +237 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verifiable Credentials (W3C 1.1) Schemas
|
|
3
|
+
*
|
|
4
|
+
* Zod schemas and TypeScript types for W3C Verifiable Credentials Data Model 1.1.
|
|
5
|
+
* These schemas provide runtime validation and can emit JSON Schemas for interoperability.
|
|
6
|
+
*
|
|
7
|
+
* Related Spec: MCP-I §3, W3C VC Data Model 1.1
|
|
8
|
+
* Python Reference: Credential-Documentation.md, Credential-Service.md
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Standard W3C Verifiable Credentials context
|
|
15
|
+
*/
|
|
16
|
+
export const VC_CONTEXT = ['https://www.w3.org/2018/credentials/v1'] as const;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Additional context for StatusList2021
|
|
20
|
+
*/
|
|
21
|
+
export const STATUS_LIST_CONTEXT =
|
|
22
|
+
'https://w3id.org/vc/status-list/2021/v1' as const;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Context Entry Schema
|
|
26
|
+
*
|
|
27
|
+
* Supports both string URLs and context objects
|
|
28
|
+
*/
|
|
29
|
+
export const ContextEntrySchema = z.union([
|
|
30
|
+
z.string().url(),
|
|
31
|
+
z.record(z.any()),
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @context Schema
|
|
36
|
+
*
|
|
37
|
+
* The @context property establishes the semantic context of the credential.
|
|
38
|
+
* MUST include the base VC context and MAY include additional contexts.
|
|
39
|
+
*/
|
|
40
|
+
export const ContextSchema = z
|
|
41
|
+
.array(ContextEntrySchema)
|
|
42
|
+
.nonempty()
|
|
43
|
+
.refine(
|
|
44
|
+
(contexts) => {
|
|
45
|
+
// First context must be the base VC context
|
|
46
|
+
const firstContext = contexts[0];
|
|
47
|
+
return (
|
|
48
|
+
typeof firstContext === 'string' &&
|
|
49
|
+
firstContext === VC_CONTEXT[0]
|
|
50
|
+
);
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
message:
|
|
54
|
+
'First @context must be "https://www.w3.org/2018/credentials/v1"',
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Issuer Schema
|
|
60
|
+
*
|
|
61
|
+
* The issuer can be a DID string or an object with an id field
|
|
62
|
+
*/
|
|
63
|
+
export const IssuerSchema = z.union([
|
|
64
|
+
z.string().min(1),
|
|
65
|
+
z.object({
|
|
66
|
+
id: z.string().min(1),
|
|
67
|
+
}).passthrough(), // Allow additional properties
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Credential Subject Schema
|
|
72
|
+
*
|
|
73
|
+
* The subject of the credential. Can be a single object or array of objects.
|
|
74
|
+
* MUST have an id property that is a DID or URI.
|
|
75
|
+
*/
|
|
76
|
+
export const CredentialSubjectSchema = z.union([
|
|
77
|
+
z.record(z.any()),
|
|
78
|
+
z.array(z.record(z.any())),
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Credential Status Schema (StatusList2021Entry)
|
|
83
|
+
*
|
|
84
|
+
* References a position in a StatusList2021 credential for revocation/suspension checking.
|
|
85
|
+
*/
|
|
86
|
+
export const CredentialStatusSchema = z.object({
|
|
87
|
+
/** URI of this status entry */
|
|
88
|
+
id: z.string().url(),
|
|
89
|
+
|
|
90
|
+
/** Type MUST be StatusList2021Entry */
|
|
91
|
+
type: z.literal('StatusList2021Entry'),
|
|
92
|
+
|
|
93
|
+
/** Purpose of the status list (revocation or suspension) */
|
|
94
|
+
statusPurpose: z.enum(['revocation', 'suspension']),
|
|
95
|
+
|
|
96
|
+
/** Index of this credential in the status list (as string per spec) */
|
|
97
|
+
statusListIndex: z.string().regex(/^\d+$/, 'Must be a numeric string'),
|
|
98
|
+
|
|
99
|
+
/** URL of the StatusList2021Credential */
|
|
100
|
+
statusListCredential: z.string().url(),
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Proof Schema
|
|
105
|
+
*
|
|
106
|
+
* Cryptographic proof for the credential.
|
|
107
|
+
* This is a flexible schema as proof formats vary.
|
|
108
|
+
*/
|
|
109
|
+
export const ProofSchema = z
|
|
110
|
+
.object({
|
|
111
|
+
type: z.string().min(1),
|
|
112
|
+
created: z.string().optional(),
|
|
113
|
+
verificationMethod: z.string().optional(),
|
|
114
|
+
proofPurpose: z.string().optional(),
|
|
115
|
+
})
|
|
116
|
+
.passthrough(); // Allow additional proof-specific fields
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Verifiable Credential Schema (W3C 1.1)
|
|
120
|
+
*
|
|
121
|
+
* Core schema for W3C Verifiable Credentials.
|
|
122
|
+
* Supports all required and common optional fields.
|
|
123
|
+
*/
|
|
124
|
+
export const VerifiableCredentialSchema = z.object({
|
|
125
|
+
/** JSON-LD context */
|
|
126
|
+
'@context': ContextSchema,
|
|
127
|
+
|
|
128
|
+
/** Unique identifier for the credential (optional per spec) */
|
|
129
|
+
id: z.string().url().optional(),
|
|
130
|
+
|
|
131
|
+
/** Type of the credential, MUST include "VerifiableCredential" */
|
|
132
|
+
type: z
|
|
133
|
+
.array(z.string())
|
|
134
|
+
.min(1)
|
|
135
|
+
.refine((types) => types.includes('VerifiableCredential'), {
|
|
136
|
+
message: 'type must include "VerifiableCredential"',
|
|
137
|
+
}),
|
|
138
|
+
|
|
139
|
+
/** Issuer of the credential (DID or issuer object) */
|
|
140
|
+
issuer: IssuerSchema,
|
|
141
|
+
|
|
142
|
+
/** Issuance date in ISO 8601 format */
|
|
143
|
+
issuanceDate: z.string().datetime(),
|
|
144
|
+
|
|
145
|
+
/** Expiration date in ISO 8601 format (optional) */
|
|
146
|
+
expirationDate: z.string().datetime().optional(),
|
|
147
|
+
|
|
148
|
+
/** The subject(s) of the credential */
|
|
149
|
+
credentialSubject: CredentialSubjectSchema,
|
|
150
|
+
|
|
151
|
+
/** Status information for revocation/suspension (optional) */
|
|
152
|
+
credentialStatus: CredentialStatusSchema.optional(),
|
|
153
|
+
|
|
154
|
+
/** Cryptographic proof (optional, may be added as external proof) */
|
|
155
|
+
proof: ProofSchema.optional(),
|
|
156
|
+
|
|
157
|
+
/** Allow additional properties for extensibility */
|
|
158
|
+
}).passthrough();
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Type exports
|
|
162
|
+
*/
|
|
163
|
+
export type ContextEntry = z.infer<typeof ContextEntrySchema>;
|
|
164
|
+
export type Context = z.infer<typeof ContextSchema>;
|
|
165
|
+
export type Issuer = z.infer<typeof IssuerSchema>;
|
|
166
|
+
export type CredentialSubject = z.infer<typeof CredentialSubjectSchema>;
|
|
167
|
+
export type CredentialStatus = z.infer<typeof CredentialStatusSchema>;
|
|
168
|
+
export type Proof = z.infer<typeof ProofSchema>;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Verifiable Credential Type
|
|
172
|
+
*
|
|
173
|
+
* Use this type for type-safe credential handling.
|
|
174
|
+
*/
|
|
175
|
+
export type VerifiableCredential = z.infer<typeof VerifiableCredentialSchema>;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Verifiable Presentation Schema
|
|
179
|
+
*
|
|
180
|
+
* Schema for presenting one or more credentials.
|
|
181
|
+
*/
|
|
182
|
+
export const VerifiablePresentationSchema = z.object({
|
|
183
|
+
'@context': ContextSchema,
|
|
184
|
+
id: z.string().url().optional(),
|
|
185
|
+
type: z
|
|
186
|
+
.array(z.string())
|
|
187
|
+
.min(1)
|
|
188
|
+
.refine((types) => types.includes('VerifiablePresentation'), {
|
|
189
|
+
message: 'type must include "VerifiablePresentation"',
|
|
190
|
+
}),
|
|
191
|
+
holder: z.string().min(1).optional(),
|
|
192
|
+
verifiableCredential: z
|
|
193
|
+
.union([
|
|
194
|
+
VerifiableCredentialSchema,
|
|
195
|
+
z.array(VerifiableCredentialSchema),
|
|
196
|
+
])
|
|
197
|
+
.optional(),
|
|
198
|
+
proof: ProofSchema.optional(),
|
|
199
|
+
}).passthrough();
|
|
200
|
+
|
|
201
|
+
export type VerifiablePresentation = z.infer<
|
|
202
|
+
typeof VerifiablePresentationSchema
|
|
203
|
+
>;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Validation Helpers
|
|
207
|
+
*/
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Validate a verifiable credential
|
|
211
|
+
*
|
|
212
|
+
* @param credential - The credential to validate
|
|
213
|
+
* @returns Validation result with parsed credential or errors
|
|
214
|
+
*/
|
|
215
|
+
export function validateVerifiableCredential(credential: unknown) {
|
|
216
|
+
return VerifiableCredentialSchema.safeParse(credential);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Validate a verifiable presentation
|
|
221
|
+
*
|
|
222
|
+
* @param presentation - The presentation to validate
|
|
223
|
+
* @returns Validation result with parsed presentation or errors
|
|
224
|
+
*/
|
|
225
|
+
export function validateVerifiablePresentation(presentation: unknown) {
|
|
226
|
+
return VerifiablePresentationSchema.safeParse(presentation);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Check if a credential is expired
|
|
231
|
+
*
|
|
232
|
+
* @param credential - The credential to check
|
|
233
|
+
* @returns true if expired, false otherwise
|
|
234
|
+
*/
|
|
235
|
+
export function isCredentialExpired(credential: VerifiableCredential): boolean {
|
|
236
|
+
if (!credential.expirationDate) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
const expirationDate = new Date(credential.expirationDate);
|
|
242
|
+
const now = new Date();
|
|
243
|
+
return expirationDate < now;
|
|
244
|
+
} catch {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Extract issuer DID from credential
|
|
251
|
+
*
|
|
252
|
+
* @param credential - The credential
|
|
253
|
+
* @returns The issuer DID string
|
|
254
|
+
*/
|
|
255
|
+
export function getIssuerDid(credential: VerifiableCredential): string {
|
|
256
|
+
const issuer = credential.issuer as string | { id: string };
|
|
257
|
+
if (typeof issuer === 'string') {
|
|
258
|
+
return issuer;
|
|
259
|
+
}
|
|
260
|
+
return issuer.id;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Extract credential subject DID (if present)
|
|
265
|
+
*
|
|
266
|
+
* @param credential - The credential
|
|
267
|
+
* @returns The subject DID or null if not present
|
|
268
|
+
*/
|
|
269
|
+
export function getSubjectDid(
|
|
270
|
+
credential: VerifiableCredential
|
|
271
|
+
): string | null {
|
|
272
|
+
const subject = Array.isArray(credential.credentialSubject)
|
|
273
|
+
? credential.credentialSubject[0]
|
|
274
|
+
: credential.credentialSubject;
|
|
275
|
+
|
|
276
|
+
return (subject?.id as string) || null;
|
|
277
|
+
}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StatusList2021 Types and Schemas
|
|
3
|
+
*
|
|
4
|
+
* Implementation of the W3C StatusList2021 specification for credential status.
|
|
5
|
+
* Provides types for status list credentials and helpers for bitstring operations.
|
|
6
|
+
*
|
|
7
|
+
* Related Spec: W3C StatusList2021
|
|
8
|
+
* Python Reference: Credential-Documentation.md (StatusList2021 section)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import { ContextSchema, IssuerSchema, ProofSchema } from './schemas.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Status Purpose
|
|
16
|
+
*
|
|
17
|
+
* Indicates the purpose of the status list
|
|
18
|
+
*/
|
|
19
|
+
export type StatusPurpose = 'revocation' | 'suspension';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Status List Credential Subject Schema
|
|
23
|
+
*
|
|
24
|
+
* The credential subject of a StatusList2021Credential
|
|
25
|
+
*/
|
|
26
|
+
export const StatusList2021CredentialSubjectSchema = z.object({
|
|
27
|
+
/** Optional identifier for the status list */
|
|
28
|
+
id: z.string().optional(),
|
|
29
|
+
|
|
30
|
+
/** Type MUST be StatusList2021 */
|
|
31
|
+
type: z.literal('StatusList2021'),
|
|
32
|
+
|
|
33
|
+
/** Purpose of the status list */
|
|
34
|
+
statusPurpose: z.enum(['revocation', 'suspension']),
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Encoded bitstring
|
|
38
|
+
*
|
|
39
|
+
* Base64url-encoded and GZIP-compressed bitstring.
|
|
40
|
+
* Each bit represents the status of a credential:
|
|
41
|
+
* - 0: Not revoked/suspended
|
|
42
|
+
* - 1: Revoked/suspended
|
|
43
|
+
*/
|
|
44
|
+
encodedList: z.string().regex(/^[A-Za-z0-9_-]+$/, {
|
|
45
|
+
message: 'encodedList must be base64url encoded',
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* StatusList2021 Credential Schema
|
|
51
|
+
*
|
|
52
|
+
* A credential that contains a status list for checking revocation/suspension
|
|
53
|
+
* of other credentials.
|
|
54
|
+
*/
|
|
55
|
+
export const StatusList2021CredentialSchema = z.object({
|
|
56
|
+
/** JSON-LD context */
|
|
57
|
+
'@context': ContextSchema.refine(
|
|
58
|
+
(contexts) => {
|
|
59
|
+
// Must include both base VC context and StatusList context
|
|
60
|
+
return (
|
|
61
|
+
contexts.length >= 2 &&
|
|
62
|
+
typeof contexts[0] === 'string' &&
|
|
63
|
+
contexts[0] === 'https://www.w3.org/2018/credentials/v1' &&
|
|
64
|
+
(contexts.includes('https://w3id.org/vc/status-list/2021/v1') ||
|
|
65
|
+
(contexts as any[]).some(
|
|
66
|
+
(ctx) =>
|
|
67
|
+
typeof ctx === 'object' &&
|
|
68
|
+
ctx['StatusList2021Credential'] !== undefined
|
|
69
|
+
))
|
|
70
|
+
);
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
message:
|
|
74
|
+
'@context must include VC context and StatusList2021 context',
|
|
75
|
+
}
|
|
76
|
+
),
|
|
77
|
+
|
|
78
|
+
/** Unique identifier for the status list credential */
|
|
79
|
+
id: z.string().url(),
|
|
80
|
+
|
|
81
|
+
/** Type MUST include VerifiableCredential and StatusList2021Credential */
|
|
82
|
+
type: z
|
|
83
|
+
.tuple([z.literal('VerifiableCredential'), z.literal('StatusList2021Credential')])
|
|
84
|
+
.or(
|
|
85
|
+
z.array(z.string()).refine(
|
|
86
|
+
(types) =>
|
|
87
|
+
types.includes('VerifiableCredential') &&
|
|
88
|
+
types.includes('StatusList2021Credential'),
|
|
89
|
+
{
|
|
90
|
+
message:
|
|
91
|
+
'type must include "VerifiableCredential" and "StatusList2021Credential"',
|
|
92
|
+
}
|
|
93
|
+
)
|
|
94
|
+
),
|
|
95
|
+
|
|
96
|
+
/** Issuer of the status list credential */
|
|
97
|
+
issuer: IssuerSchema,
|
|
98
|
+
|
|
99
|
+
/** Issuance date in ISO 8601 format */
|
|
100
|
+
issuanceDate: z.string().datetime(),
|
|
101
|
+
|
|
102
|
+
/** The status list credential subject */
|
|
103
|
+
credentialSubject: StatusList2021CredentialSubjectSchema,
|
|
104
|
+
|
|
105
|
+
/** Cryptographic proof (optional) */
|
|
106
|
+
proof: ProofSchema.optional(),
|
|
107
|
+
}).passthrough();
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Type exports
|
|
111
|
+
*/
|
|
112
|
+
export type StatusList2021CredentialSubject = z.infer<
|
|
113
|
+
typeof StatusList2021CredentialSubjectSchema
|
|
114
|
+
>;
|
|
115
|
+
export type StatusList2021Credential = z.infer<
|
|
116
|
+
typeof StatusList2021CredentialSchema
|
|
117
|
+
>;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* StatusList2021 Credential Type (traditional TypeScript interface)
|
|
121
|
+
*
|
|
122
|
+
* For use when not using Zod validation
|
|
123
|
+
*/
|
|
124
|
+
export interface StatusList2021CredentialInterface {
|
|
125
|
+
'@context': (string | Record<string, any>)[];
|
|
126
|
+
id: string;
|
|
127
|
+
type: ['VerifiableCredential', 'StatusList2021Credential'];
|
|
128
|
+
issuer: string | { id: string };
|
|
129
|
+
issuanceDate: string;
|
|
130
|
+
credentialSubject: {
|
|
131
|
+
id?: string;
|
|
132
|
+
type: 'StatusList2021';
|
|
133
|
+
statusPurpose: 'revocation' | 'suspension';
|
|
134
|
+
encodedList: string;
|
|
135
|
+
};
|
|
136
|
+
proof?: Record<string, any>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Validation Helpers
|
|
141
|
+
*/
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Validate a StatusList2021 credential
|
|
145
|
+
*
|
|
146
|
+
* @param credential - The credential to validate
|
|
147
|
+
* @returns Validation result with parsed credential or errors
|
|
148
|
+
*/
|
|
149
|
+
export function validateStatusList2021Credential(credential: unknown) {
|
|
150
|
+
return StatusList2021CredentialSchema.safeParse(credential);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Helper Types for Bitstring Operations
|
|
155
|
+
*
|
|
156
|
+
* These types define the interface for bitstring encode/decode operations.
|
|
157
|
+
* Actual implementation would be in a separate utility module.
|
|
158
|
+
*/
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Bitstring encoding options
|
|
162
|
+
*/
|
|
163
|
+
export interface BitStringEncodeOptions {
|
|
164
|
+
/** Total size of the bitstring (number of bits) */
|
|
165
|
+
size: number;
|
|
166
|
+
|
|
167
|
+
/** Positions to set to 1 (revoked/suspended) */
|
|
168
|
+
setBits?: number[];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Bitstring decoding result
|
|
173
|
+
*/
|
|
174
|
+
export interface BitStringDecodeResult {
|
|
175
|
+
/** Total size of the bitstring */
|
|
176
|
+
size: number;
|
|
177
|
+
|
|
178
|
+
/** Positions that are set to 1 */
|
|
179
|
+
setBits: number[];
|
|
180
|
+
|
|
181
|
+
/** Check if a specific index is set */
|
|
182
|
+
isSet: (index: number) => boolean;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Cache entry for StatusList2021 credentials
|
|
187
|
+
*
|
|
188
|
+
* Used for efficient caching of status list credentials with ETag support
|
|
189
|
+
*/
|
|
190
|
+
export interface StatusListCacheEntry {
|
|
191
|
+
/** The cached status list credential */
|
|
192
|
+
credential: StatusList2021Credential;
|
|
193
|
+
|
|
194
|
+
/** ETag from the HTTP response (if applicable) */
|
|
195
|
+
etag?: string;
|
|
196
|
+
|
|
197
|
+
/** Timestamp when cached (milliseconds since epoch) */
|
|
198
|
+
cachedAt: number;
|
|
199
|
+
|
|
200
|
+
/** TTL in seconds */
|
|
201
|
+
ttlSec: number;
|
|
202
|
+
|
|
203
|
+
/** Expires at timestamp (milliseconds since epoch) */
|
|
204
|
+
expiresAt: number;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Status checking result
|
|
209
|
+
*/
|
|
210
|
+
export interface StatusCheckResult {
|
|
211
|
+
/** Whether the credential is valid (not revoked/suspended) */
|
|
212
|
+
valid: boolean;
|
|
213
|
+
|
|
214
|
+
/** The status (active, revoked, suspended) */
|
|
215
|
+
status: 'active' | 'revoked' | 'suspended';
|
|
216
|
+
|
|
217
|
+
/** Optional reason for status */
|
|
218
|
+
reason?: string;
|
|
219
|
+
|
|
220
|
+
/** Timestamp when checked */
|
|
221
|
+
checkedAt: number;
|
|
222
|
+
|
|
223
|
+
/** Whether result came from cache */
|
|
224
|
+
fromCache?: boolean;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Helper to create a minimal status list credential structure
|
|
229
|
+
*
|
|
230
|
+
* This is a type-safe helper, actual credential creation requires
|
|
231
|
+
* proper signing and encoding implementation.
|
|
232
|
+
*
|
|
233
|
+
* @param config - Configuration for the status list credential
|
|
234
|
+
* @returns Partial credential structure (needs proof to be complete)
|
|
235
|
+
*/
|
|
236
|
+
export function createStatusListCredentialStructure(config: {
|
|
237
|
+
id: string;
|
|
238
|
+
issuer: string | { id: string };
|
|
239
|
+
statusPurpose: StatusPurpose;
|
|
240
|
+
encodedList: string;
|
|
241
|
+
}): Omit<StatusList2021Credential, 'proof'> {
|
|
242
|
+
return {
|
|
243
|
+
'@context': [
|
|
244
|
+
'https://www.w3.org/2018/credentials/v1',
|
|
245
|
+
'https://w3id.org/vc/status-list/2021/v1',
|
|
246
|
+
],
|
|
247
|
+
id: config.id,
|
|
248
|
+
type: ['VerifiableCredential', 'StatusList2021Credential'],
|
|
249
|
+
issuer: config.issuer,
|
|
250
|
+
issuanceDate: new Date().toISOString(),
|
|
251
|
+
credentialSubject: {
|
|
252
|
+
type: 'StatusList2021',
|
|
253
|
+
statusPurpose: config.statusPurpose,
|
|
254
|
+
encodedList: config.encodedList,
|
|
255
|
+
},
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Constants
|
|
261
|
+
*/
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Default cache TTL for status list credentials (in seconds)
|
|
265
|
+
* As per spec recommendation
|
|
266
|
+
*/
|
|
267
|
+
export const DEFAULT_STATUSLIST_CACHE_TTL_SEC = 60;
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Maximum reasonable bitstring size
|
|
271
|
+
* Used for validation to prevent memory exhaustion
|
|
272
|
+
*/
|
|
273
|
+
export const MAX_STATUSLIST_SIZE = 1000000; // 1 million entries
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* StatusList2021 context URL
|
|
277
|
+
*/
|
|
278
|
+
export const STATUSLIST_2021_CONTEXT =
|
|
279
|
+
'https://w3id.org/vc/status-list/2021/v1';
|
package/src/verifier.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Verifier middleware schemas and headers
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const AgentContextSchema = z.object({
|
|
8
|
+
did: z.string().min(1),
|
|
9
|
+
kid: z.string().min(1),
|
|
10
|
+
subject: z.string().optional(),
|
|
11
|
+
scopes: z.array(z.string()).default([]),
|
|
12
|
+
session: z.string().min(1),
|
|
13
|
+
confidence: z.literal("verified"),
|
|
14
|
+
delegationRef: z.string().optional(),
|
|
15
|
+
registry: z.string().url(),
|
|
16
|
+
verifiedAt: z.number().int().positive(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const VerifierResultSchema = z.object({
|
|
20
|
+
success: z.boolean(),
|
|
21
|
+
headers: z.record(z.string()).optional(),
|
|
22
|
+
agentContext: AgentContextSchema.optional(),
|
|
23
|
+
error: z
|
|
24
|
+
.object({
|
|
25
|
+
code: z.string(),
|
|
26
|
+
message: z.string(),
|
|
27
|
+
details: z.any().optional(),
|
|
28
|
+
httpStatus: z.number().int().min(400).max(599),
|
|
29
|
+
})
|
|
30
|
+
.optional(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export const StructuredErrorSchema = z.object({
|
|
34
|
+
code: z.string(),
|
|
35
|
+
message: z.string(),
|
|
36
|
+
httpStatus: z.number().int().min(400).max(599),
|
|
37
|
+
details: z
|
|
38
|
+
.object({
|
|
39
|
+
reason: z.string().optional(),
|
|
40
|
+
expected: z.any().optional(),
|
|
41
|
+
received: z.any().optional(),
|
|
42
|
+
remediation: z.string().optional(),
|
|
43
|
+
})
|
|
44
|
+
.optional(),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Type exports
|
|
48
|
+
export type AgentContext = z.infer<typeof AgentContextSchema>;
|
|
49
|
+
export type VerifierResult = z.infer<typeof VerifierResultSchema>;
|
|
50
|
+
export type StructuredError = z.infer<typeof StructuredErrorSchema>;
|
|
51
|
+
|
|
52
|
+
// Header constants (frozen names)
|
|
53
|
+
export const AGENT_HEADERS = {
|
|
54
|
+
DID: "X-Agent-DID",
|
|
55
|
+
KEY_ID: "X-Agent-KeyId",
|
|
56
|
+
SUBJECT: "X-Agent-Subject",
|
|
57
|
+
SCOPES: "X-Agent-Scopes",
|
|
58
|
+
SESSION: "X-Agent-Session",
|
|
59
|
+
CONFIDENCE: "X-Agent-Confidence",
|
|
60
|
+
DELEGATION_REF: "X-Agent-Delegation-Ref",
|
|
61
|
+
REGISTRY: "X-Agent-Registry",
|
|
62
|
+
VERIFIED_AT: "X-Agent-Verified-At",
|
|
63
|
+
} as const;
|
|
64
|
+
|
|
65
|
+
// Verifier-specific error codes
|
|
66
|
+
export const VERIFIER_ERROR_CODES = {
|
|
67
|
+
PROOF_INVALID_TS: "XMCP_I_PROOF_INVALID_TS",
|
|
68
|
+
PROOF_FUTURE_TS: "XMCP_I_PROOF_FUTURE_TS",
|
|
69
|
+
PROOF_TOO_OLD: "XMCP_I_PROOF_TOO_OLD",
|
|
70
|
+
PROOF_SKEW_EXCEEDED: "XMCP_I_PROOF_SKEW_EXCEEDED",
|
|
71
|
+
SESSION_IDLE_EXPIRED: "XMCP_I_SESSION_IDLE_EXPIRED",
|
|
72
|
+
SERVER_TIME_INVALID: "XMCP_I_SERVER_TIME_INVALID",
|
|
73
|
+
} as const;
|
|
74
|
+
|
|
75
|
+
// HTTP status mappings
|
|
76
|
+
export const ERROR_HTTP_STATUS = {
|
|
77
|
+
XMCP_I_EBADPROOF: 403,
|
|
78
|
+
XMCP_I_ENOIDENTITY: 500,
|
|
79
|
+
XMCP_I_EMIRRORPENDING: 200,
|
|
80
|
+
XMCP_I_EHANDSHAKE: 401,
|
|
81
|
+
XMCP_I_ESESSION: 401,
|
|
82
|
+
XMCP_I_ECLAIM: 400,
|
|
83
|
+
XMCP_I_ECONFIG: 500,
|
|
84
|
+
XMCP_I_ERUNTIME: 500,
|
|
85
|
+
// Verifier-specific codes
|
|
86
|
+
[VERIFIER_ERROR_CODES.PROOF_INVALID_TS]: 403,
|
|
87
|
+
[VERIFIER_ERROR_CODES.PROOF_FUTURE_TS]: 403,
|
|
88
|
+
[VERIFIER_ERROR_CODES.PROOF_TOO_OLD]: 403,
|
|
89
|
+
[VERIFIER_ERROR_CODES.PROOF_SKEW_EXCEEDED]: 401,
|
|
90
|
+
[VERIFIER_ERROR_CODES.SESSION_IDLE_EXPIRED]: 401,
|
|
91
|
+
[VERIFIER_ERROR_CODES.SERVER_TIME_INVALID]: 500,
|
|
92
|
+
} as const;
|