@glinr/theauth 0.4.2
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/LICENSE +21 -0
- package/README.md +202 -0
- package/dist/a2a/index.d.ts +2341 -0
- package/dist/a2a/index.js +826 -0
- package/dist/a2a/index.js.map +1 -0
- package/dist/agent/index.d.ts +32 -0
- package/dist/agent/index.js +795 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/audit/index.d.ts +24 -0
- package/dist/audit/index.js +641 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/auth/index.d.ts +3466 -0
- package/dist/auth/index.js +16139 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/crypto/index.d.ts +55 -0
- package/dist/crypto/index.js +186 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/index.d.ts +1711 -0
- package/dist/index.js +23160 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +274 -0
- package/dist/mcp/index.js +1262 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/permission/index.d.ts +89 -0
- package/dist/permission/index.js +801 -0
- package/dist/permission/index.js.map +1 -0
- package/dist/redirect/index.d.ts +118 -0
- package/dist/redirect/index.js +292 -0
- package/dist/redirect/index.js.map +1 -0
- package/dist/standards/index.d.ts +139 -0
- package/dist/standards/index.js +72 -0
- package/dist/standards/index.js.map +1 -0
- package/dist/types-BiUe9e8u.d.ts +426 -0
- package/dist/types-D1sBnWrs.d.ts +9636 -0
- package/dist/types-RJPOU4un.d.ts +9636 -0
- package/dist/vc/index.d.ts +989 -0
- package/dist/vc/index.js +692 -0
- package/dist/vc/index.js.map +1 -0
- package/package.json +139 -0
package/dist/vc/index.js
ADDED
|
@@ -0,0 +1,692 @@
|
|
|
1
|
+
import { importJWK, jwtVerify, SignJWT, CompactSign, errors, compactVerify } from 'jose';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
// src/vc/audit-export.ts
|
|
5
|
+
|
|
6
|
+
// src/crypto/web-crypto.ts
|
|
7
|
+
function generateId() {
|
|
8
|
+
return globalThis.crypto.randomUUID();
|
|
9
|
+
}
|
|
10
|
+
new TextEncoder();
|
|
11
|
+
var VC_CONTEXT_V2 = "https://www.w3.org/ns/credentials/v2";
|
|
12
|
+
var VC_CONTEXT_V1 = "https://www.w3.org/2018/credentials/v1";
|
|
13
|
+
var VC_TYPE_CREDENTIAL = "VerifiableCredential";
|
|
14
|
+
var VC_TYPE_PRESENTATION = "VerifiablePresentation";
|
|
15
|
+
var KAVACH_AGENT_CREDENTIAL = "KavachAgentCredential";
|
|
16
|
+
var KAVACH_PERMISSION_CREDENTIAL = "KavachPermissionCredential";
|
|
17
|
+
var KAVACH_DELEGATION_CREDENTIAL = "KavachDelegationCredential";
|
|
18
|
+
var ProofSchema = z.object({
|
|
19
|
+
type: z.enum(["Ed25519Signature2020", "JsonWebSignature2020"]),
|
|
20
|
+
created: z.string(),
|
|
21
|
+
verificationMethod: z.string(),
|
|
22
|
+
proofPurpose: z.enum(["assertionMethod", "authentication"]),
|
|
23
|
+
proofValue: z.string().optional(),
|
|
24
|
+
jws: z.string().optional()
|
|
25
|
+
});
|
|
26
|
+
var CredentialStatusSchema = z.object({
|
|
27
|
+
id: z.string(),
|
|
28
|
+
type: z.string(),
|
|
29
|
+
statusPurpose: z.enum(["revocation", "suspension"]),
|
|
30
|
+
statusListIndex: z.number().int().nonnegative(),
|
|
31
|
+
statusListCredential: z.string()
|
|
32
|
+
});
|
|
33
|
+
var CredentialSubjectSchema = z.object({
|
|
34
|
+
id: z.string().optional(),
|
|
35
|
+
agentId: z.string().optional(),
|
|
36
|
+
permissions: z.array(z.string()).optional(),
|
|
37
|
+
trustLevel: z.number().min(0).max(1).optional(),
|
|
38
|
+
delegationScope: z.array(z.string()).optional(),
|
|
39
|
+
delegationChain: z.array(
|
|
40
|
+
z.object({
|
|
41
|
+
delegator: z.string(),
|
|
42
|
+
delegatee: z.string(),
|
|
43
|
+
permissions: z.array(z.string()),
|
|
44
|
+
createdAt: z.string()
|
|
45
|
+
})
|
|
46
|
+
).optional(),
|
|
47
|
+
name: z.string().optional(),
|
|
48
|
+
type: z.string().optional()
|
|
49
|
+
}).passthrough();
|
|
50
|
+
var VerifiableCredentialSchema = z.object({
|
|
51
|
+
"@context": z.array(z.string()).min(1),
|
|
52
|
+
id: z.string().optional(),
|
|
53
|
+
type: z.array(z.string()).min(1),
|
|
54
|
+
issuer: z.union([z.string(), z.object({ id: z.string(), name: z.string().optional() })]),
|
|
55
|
+
issuanceDate: z.string(),
|
|
56
|
+
expirationDate: z.string().optional(),
|
|
57
|
+
credentialSubject: CredentialSubjectSchema,
|
|
58
|
+
credentialStatus: CredentialStatusSchema.optional(),
|
|
59
|
+
proof: ProofSchema.optional()
|
|
60
|
+
});
|
|
61
|
+
var VerifiablePresentationSchema = z.object({
|
|
62
|
+
"@context": z.array(z.string()).min(1),
|
|
63
|
+
id: z.string().optional(),
|
|
64
|
+
type: z.array(z.string()).min(1),
|
|
65
|
+
holder: z.string().optional(),
|
|
66
|
+
verifiableCredential: z.array(VerifiableCredentialSchema).min(1),
|
|
67
|
+
proof: ProofSchema.optional()
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// src/vc/audit-export.ts
|
|
71
|
+
var THEAUTH_AUDIT_CREDENTIAL = "TheAuthAuditCredential";
|
|
72
|
+
var THEAUTH_AUDIT_CONTEXT = "https://theauth.com/contexts/audit/v1.jsonld";
|
|
73
|
+
var THEAUTH_VERSION = "0.3.0";
|
|
74
|
+
var DEFAULT_TTL_SECONDS = 86400;
|
|
75
|
+
function toDecision(result) {
|
|
76
|
+
if (result === "allowed") return "allow";
|
|
77
|
+
return "deny";
|
|
78
|
+
}
|
|
79
|
+
function buildAuditCredential(record, issuerDid) {
|
|
80
|
+
const subject = {
|
|
81
|
+
id: record.id,
|
|
82
|
+
agentId: record.agentId,
|
|
83
|
+
...record.userId ? { principalId: record.userId } : {},
|
|
84
|
+
operation: record.action,
|
|
85
|
+
target: record.resource,
|
|
86
|
+
decision: toDecision(record.result),
|
|
87
|
+
...record.reason ? { policyName: record.reason } : {},
|
|
88
|
+
timestamp: record.timestamp.toISOString(),
|
|
89
|
+
theauthVersion: THEAUTH_VERSION
|
|
90
|
+
};
|
|
91
|
+
return {
|
|
92
|
+
"@context": [VC_CONTEXT_V2, THEAUTH_AUDIT_CONTEXT],
|
|
93
|
+
id: `urn:uuid:${generateId()}`,
|
|
94
|
+
type: [VC_TYPE_CREDENTIAL, THEAUTH_AUDIT_CREDENTIAL],
|
|
95
|
+
issuer: issuerDid,
|
|
96
|
+
issuanceDate: (/* @__PURE__ */ new Date()).toISOString(),
|
|
97
|
+
expirationDate: new Date(Date.now() + DEFAULT_TTL_SECONDS * 1e3).toISOString(),
|
|
98
|
+
// Cast: AuditCredentialSubject is intentionally wider than CredentialSubject
|
|
99
|
+
// because the VC schema uses an open-ended subject. The additional fields
|
|
100
|
+
// (operation, target, decision, etc.) are preserved via spread at runtime.
|
|
101
|
+
credentialSubject: subject
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
async function signAsJsonLd(credential, config) {
|
|
105
|
+
const { issuerDid, privateKeyJwk } = config;
|
|
106
|
+
const kid = `${issuerDid}#${issuerDid.split(":").pop() ?? "key-1"}`;
|
|
107
|
+
const key = await importJWK(privateKeyJwk, "EdDSA");
|
|
108
|
+
const { proof: _proof, ...vcWithoutProof } = credential;
|
|
109
|
+
const payload = new TextEncoder().encode(JSON.stringify(vcWithoutProof));
|
|
110
|
+
const jws = await new CompactSign(payload).setProtectedHeader({ alg: "EdDSA", kid }).sign(key);
|
|
111
|
+
const proof = {
|
|
112
|
+
type: "JsonWebSignature2020",
|
|
113
|
+
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
114
|
+
verificationMethod: kid,
|
|
115
|
+
proofPurpose: "assertionMethod",
|
|
116
|
+
jws
|
|
117
|
+
};
|
|
118
|
+
return { ...credential, proof };
|
|
119
|
+
}
|
|
120
|
+
async function signAsJwt(credential, config) {
|
|
121
|
+
const { issuerDid, privateKeyJwk } = config;
|
|
122
|
+
const ttl = config.defaultTtl ?? DEFAULT_TTL_SECONDS;
|
|
123
|
+
const kid = `${issuerDid}#${issuerDid.split(":").pop() ?? "key-1"}`;
|
|
124
|
+
const key = await importJWK(privateKeyJwk, "EdDSA");
|
|
125
|
+
const { proof: _proof, ...vcWithoutProof } = credential;
|
|
126
|
+
const builder = new SignJWT({ vc: vcWithoutProof }).setProtectedHeader({ alg: "EdDSA", kid, typ: "JWT" }).setIssuer(issuerDid).setIssuedAt().setExpirationTime(Math.floor(Date.now() / 1e3) + ttl);
|
|
127
|
+
if (credential.id) builder.setJti(credential.id);
|
|
128
|
+
if (credential.credentialSubject.id) builder.setSubject(credential.credentialSubject.id);
|
|
129
|
+
const jwt = await builder.sign(key);
|
|
130
|
+
return { credential, jwt };
|
|
131
|
+
}
|
|
132
|
+
async function signPresentationAsJsonLd(presentation, config) {
|
|
133
|
+
const { issuerDid, privateKeyJwk } = config;
|
|
134
|
+
const kid = `${issuerDid}#${issuerDid.split(":").pop() ?? "key-1"}`;
|
|
135
|
+
const key = await importJWK(privateKeyJwk, "EdDSA");
|
|
136
|
+
const { proof: _proof, ...vpWithoutProof } = presentation;
|
|
137
|
+
const payload = new TextEncoder().encode(JSON.stringify(vpWithoutProof));
|
|
138
|
+
const jws = await new CompactSign(payload).setProtectedHeader({ alg: "EdDSA", kid }).sign(key);
|
|
139
|
+
const proof = {
|
|
140
|
+
type: "JsonWebSignature2020",
|
|
141
|
+
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
142
|
+
verificationMethod: kid,
|
|
143
|
+
proofPurpose: "assertionMethod",
|
|
144
|
+
jws
|
|
145
|
+
};
|
|
146
|
+
return { ...presentation, proof };
|
|
147
|
+
}
|
|
148
|
+
async function exportAuditAsVC(options) {
|
|
149
|
+
const {
|
|
150
|
+
since,
|
|
151
|
+
until,
|
|
152
|
+
issuerDid,
|
|
153
|
+
issuerConfig,
|
|
154
|
+
format = "ldp_vc",
|
|
155
|
+
output = "individual",
|
|
156
|
+
filter,
|
|
157
|
+
records
|
|
158
|
+
} = options;
|
|
159
|
+
const inRange = records.filter((r) => {
|
|
160
|
+
const t = r.timestamp.getTime();
|
|
161
|
+
return t >= since.getTime() && t <= until.getTime();
|
|
162
|
+
});
|
|
163
|
+
const filtered = filter ? inRange.filter(filter) : inRange;
|
|
164
|
+
if (filtered.length === 0) {
|
|
165
|
+
return {
|
|
166
|
+
credentials: [],
|
|
167
|
+
format,
|
|
168
|
+
issuedAt: /* @__PURE__ */ new Date(),
|
|
169
|
+
count: 0
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const credentials = [];
|
|
173
|
+
const jwts = [];
|
|
174
|
+
for (const record of filtered) {
|
|
175
|
+
const base = buildAuditCredential(record, issuerDid);
|
|
176
|
+
if (format === "jwt_vc") {
|
|
177
|
+
const { credential, jwt } = await signAsJwt(base, issuerConfig);
|
|
178
|
+
credentials.push(credential);
|
|
179
|
+
jwts.push(jwt);
|
|
180
|
+
} else {
|
|
181
|
+
const signed = await signAsJsonLd(base, issuerConfig);
|
|
182
|
+
credentials.push(signed);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const issuedAt = /* @__PURE__ */ new Date();
|
|
186
|
+
if (output === "individual") {
|
|
187
|
+
return {
|
|
188
|
+
credentials,
|
|
189
|
+
...format === "jwt_vc" ? { jwts } : {},
|
|
190
|
+
format,
|
|
191
|
+
issuedAt,
|
|
192
|
+
count: credentials.length
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
const basePresentation = {
|
|
196
|
+
"@context": [VC_CONTEXT_V2, THEAUTH_AUDIT_CONTEXT],
|
|
197
|
+
id: `urn:uuid:${generateId()}`,
|
|
198
|
+
type: [VC_TYPE_PRESENTATION],
|
|
199
|
+
holder: issuerDid,
|
|
200
|
+
verifiableCredential: credentials
|
|
201
|
+
};
|
|
202
|
+
const presentation = format === "jwt_vc" ? basePresentation : await signPresentationAsJsonLd(basePresentation, issuerConfig);
|
|
203
|
+
return {
|
|
204
|
+
credentials,
|
|
205
|
+
...format === "jwt_vc" ? { jwts } : {},
|
|
206
|
+
presentation,
|
|
207
|
+
format,
|
|
208
|
+
issuedAt,
|
|
209
|
+
count: credentials.length
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function listAuditRecords(records, since, until, filter) {
|
|
213
|
+
const inRange = records.filter((r) => {
|
|
214
|
+
const t = r.timestamp.getTime();
|
|
215
|
+
return t >= since.getTime() && t <= until.getTime();
|
|
216
|
+
});
|
|
217
|
+
return filter ? inRange.filter(filter) : inRange;
|
|
218
|
+
}
|
|
219
|
+
var DEFAULT_TTL_SECONDS2 = 86400;
|
|
220
|
+
function makeError(code, message, details) {
|
|
221
|
+
return { code, message, ...{} };
|
|
222
|
+
}
|
|
223
|
+
function nowISO() {
|
|
224
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
225
|
+
}
|
|
226
|
+
function futureISO(seconds) {
|
|
227
|
+
return new Date(Date.now() + seconds * 1e3).toISOString();
|
|
228
|
+
}
|
|
229
|
+
function createVCIssuer(config) {
|
|
230
|
+
const { issuerDid, privateKeyJwk, defaultTtl = DEFAULT_TTL_SECONDS2 } = config;
|
|
231
|
+
const kid = `${issuerDid}#${issuerDid.split(":").pop() ?? "key-1"}`;
|
|
232
|
+
async function signAsJwt2(credential, subject, ttl) {
|
|
233
|
+
try {
|
|
234
|
+
const key = await importJWK(privateKeyJwk, "EdDSA");
|
|
235
|
+
const { proof: _proof, ...vcWithoutProof } = credential;
|
|
236
|
+
const builder = new SignJWT({
|
|
237
|
+
vc: vcWithoutProof
|
|
238
|
+
}).setProtectedHeader({ alg: "EdDSA", kid, typ: "JWT" }).setIssuer(issuerDid).setIssuedAt().setExpirationTime(Math.floor(Date.now() / 1e3) + ttl);
|
|
239
|
+
if (credential.id) {
|
|
240
|
+
builder.setJti(credential.id);
|
|
241
|
+
}
|
|
242
|
+
if (subject) {
|
|
243
|
+
builder.setSubject(subject);
|
|
244
|
+
}
|
|
245
|
+
const jwt = await builder.sign(key);
|
|
246
|
+
return { success: true, data: { credential, jwt } };
|
|
247
|
+
} catch (err) {
|
|
248
|
+
return {
|
|
249
|
+
success: false,
|
|
250
|
+
error: makeError(
|
|
251
|
+
"VC_SIGN_FAILED",
|
|
252
|
+
err instanceof Error ? err.message : "Failed to sign credential as JWT"
|
|
253
|
+
)
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async function signAsJsonLd2(credential) {
|
|
258
|
+
try {
|
|
259
|
+
const key = await importJWK(privateKeyJwk, "EdDSA");
|
|
260
|
+
const { proof: _proof, ...vcWithoutProof } = credential;
|
|
261
|
+
const payload = new TextEncoder().encode(JSON.stringify(vcWithoutProof));
|
|
262
|
+
const { CompactSign: CompactSign2 } = await import('jose');
|
|
263
|
+
const jws = await new CompactSign2(payload).setProtectedHeader({ alg: "EdDSA", kid }).sign(key);
|
|
264
|
+
const proof = {
|
|
265
|
+
type: "JsonWebSignature2020",
|
|
266
|
+
created: nowISO(),
|
|
267
|
+
verificationMethod: kid,
|
|
268
|
+
proofPurpose: "assertionMethod",
|
|
269
|
+
jws
|
|
270
|
+
};
|
|
271
|
+
const signedCredential = {
|
|
272
|
+
...credential,
|
|
273
|
+
proof
|
|
274
|
+
};
|
|
275
|
+
return { success: true, data: { credential: signedCredential } };
|
|
276
|
+
} catch (err) {
|
|
277
|
+
return {
|
|
278
|
+
success: false,
|
|
279
|
+
error: makeError(
|
|
280
|
+
"VC_SIGN_FAILED",
|
|
281
|
+
err instanceof Error ? err.message : "Failed to sign credential as JSON-LD"
|
|
282
|
+
)
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function buildCredential(types, subject, ttl, expirationDate) {
|
|
287
|
+
return {
|
|
288
|
+
"@context": [VC_CONTEXT_V2],
|
|
289
|
+
id: `urn:uuid:${generateId()}`,
|
|
290
|
+
type: [VC_TYPE_CREDENTIAL, ...types],
|
|
291
|
+
issuer: issuerDid,
|
|
292
|
+
issuanceDate: nowISO(),
|
|
293
|
+
expirationDate: futureISO(ttl),
|
|
294
|
+
credentialSubject: subject
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
async function signCredential(credential, subject, ttl, format) {
|
|
298
|
+
if (format === "jwt") {
|
|
299
|
+
return signAsJwt2(credential, subject, ttl);
|
|
300
|
+
}
|
|
301
|
+
return signAsJsonLd2(credential);
|
|
302
|
+
}
|
|
303
|
+
async function issueAgentCredential(input) {
|
|
304
|
+
const {
|
|
305
|
+
agentId,
|
|
306
|
+
name,
|
|
307
|
+
agentType,
|
|
308
|
+
permissions,
|
|
309
|
+
trustLevel,
|
|
310
|
+
ttl = defaultTtl,
|
|
311
|
+
format = "jwt"
|
|
312
|
+
} = input;
|
|
313
|
+
if (!agentId) {
|
|
314
|
+
return {
|
|
315
|
+
success: false,
|
|
316
|
+
error: makeError("VC_INVALID_INPUT", "agentId is required")
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
if (trustLevel !== void 0 && (trustLevel < 0 || trustLevel > 1)) {
|
|
320
|
+
return {
|
|
321
|
+
success: false,
|
|
322
|
+
error: makeError("VC_INVALID_INPUT", "trustLevel must be between 0 and 1")
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
const subject = {
|
|
326
|
+
id: agentId,
|
|
327
|
+
agentId,
|
|
328
|
+
...name !== void 0 ? { name } : {},
|
|
329
|
+
...agentType !== void 0 ? { type: agentType } : {},
|
|
330
|
+
...permissions !== void 0 ? { permissions } : {},
|
|
331
|
+
...trustLevel !== void 0 ? { trustLevel } : {}
|
|
332
|
+
};
|
|
333
|
+
const credential = buildCredential([KAVACH_AGENT_CREDENTIAL], subject, ttl);
|
|
334
|
+
return signCredential(credential, agentId, ttl, format);
|
|
335
|
+
}
|
|
336
|
+
async function issuePermissionCredential(input) {
|
|
337
|
+
const { agentId, permissions, ttl = defaultTtl, format = "jwt" } = input;
|
|
338
|
+
if (!agentId) {
|
|
339
|
+
return {
|
|
340
|
+
success: false,
|
|
341
|
+
error: makeError("VC_INVALID_INPUT", "agentId is required")
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
if (!permissions || permissions.length === 0) {
|
|
345
|
+
return {
|
|
346
|
+
success: false,
|
|
347
|
+
error: makeError("VC_INVALID_INPUT", "At least one permission is required")
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
const subject = {
|
|
351
|
+
id: agentId,
|
|
352
|
+
agentId,
|
|
353
|
+
permissions
|
|
354
|
+
};
|
|
355
|
+
const credential = buildCredential([KAVACH_PERMISSION_CREDENTIAL], subject, ttl);
|
|
356
|
+
return signCredential(credential, agentId, ttl, format);
|
|
357
|
+
}
|
|
358
|
+
async function issueDelegationCredential(input) {
|
|
359
|
+
const { agentId, chain, delegationScope, ttl = defaultTtl, format = "jwt" } = input;
|
|
360
|
+
if (!agentId) {
|
|
361
|
+
return {
|
|
362
|
+
success: false,
|
|
363
|
+
error: makeError("VC_INVALID_INPUT", "agentId is required")
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
if (!chain || chain.length === 0) {
|
|
367
|
+
return {
|
|
368
|
+
success: false,
|
|
369
|
+
error: makeError("VC_INVALID_INPUT", "Delegation chain must have at least one link")
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
const subject = {
|
|
373
|
+
id: agentId,
|
|
374
|
+
agentId,
|
|
375
|
+
delegationChain: chain,
|
|
376
|
+
...delegationScope !== void 0 ? { delegationScope } : {}
|
|
377
|
+
};
|
|
378
|
+
const credential = buildCredential([KAVACH_DELEGATION_CREDENTIAL], subject, ttl);
|
|
379
|
+
return signCredential(credential, agentId, ttl, format);
|
|
380
|
+
}
|
|
381
|
+
return {
|
|
382
|
+
issueAgentCredential,
|
|
383
|
+
issuePermissionCredential,
|
|
384
|
+
issueDelegationCredential,
|
|
385
|
+
issuerDid
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
function makeError2(code, message, details) {
|
|
389
|
+
return { code, message, ...details !== void 0 ? { details } : {} };
|
|
390
|
+
}
|
|
391
|
+
function getIssuerString(issuer) {
|
|
392
|
+
if (typeof issuer === "string") return issuer;
|
|
393
|
+
return issuer.id;
|
|
394
|
+
}
|
|
395
|
+
function createVCVerifier(config = {}) {
|
|
396
|
+
const { resolveDidKey, checkRevocationStatus } = config;
|
|
397
|
+
async function resolveKey(did, providedKey) {
|
|
398
|
+
if (providedKey) {
|
|
399
|
+
return { success: true, data: providedKey };
|
|
400
|
+
}
|
|
401
|
+
if (resolveDidKey) {
|
|
402
|
+
const resolved = await resolveDidKey(did);
|
|
403
|
+
if (resolved) {
|
|
404
|
+
return { success: true, data: resolved };
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
success: false,
|
|
409
|
+
error: makeError2("VC_KEY_NOT_FOUND", `Could not resolve public key for DID: ${did}`)
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
async function verifyJwtCredential(jwt, providedKey) {
|
|
413
|
+
try {
|
|
414
|
+
const parts = jwt.split(".");
|
|
415
|
+
if (parts.length !== 3) {
|
|
416
|
+
return {
|
|
417
|
+
success: false,
|
|
418
|
+
error: makeError2("VC_INVALID_JWT", "JWT must have three parts")
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
const payloadB64 = parts[1];
|
|
422
|
+
if (!payloadB64) {
|
|
423
|
+
return {
|
|
424
|
+
success: false,
|
|
425
|
+
error: makeError2("VC_INVALID_JWT", "JWT payload is missing")
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
const rawPayload = JSON.parse(
|
|
429
|
+
new TextDecoder().decode(
|
|
430
|
+
Uint8Array.from(
|
|
431
|
+
atob(payloadB64.replace(/-/g, "+").replace(/_/g, "/")),
|
|
432
|
+
(c) => c.charCodeAt(0)
|
|
433
|
+
)
|
|
434
|
+
)
|
|
435
|
+
);
|
|
436
|
+
const issuerDid = typeof rawPayload.iss === "string" ? rawPayload.iss : null;
|
|
437
|
+
if (!issuerDid) {
|
|
438
|
+
return {
|
|
439
|
+
success: false,
|
|
440
|
+
error: makeError2("VC_NO_ISSUER", "JWT has no iss claim")
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
const keyResult = await resolveKey(issuerDid, providedKey);
|
|
444
|
+
if (!keyResult.success) return keyResult;
|
|
445
|
+
const publicKey = await importJWK(keyResult.data, "EdDSA");
|
|
446
|
+
const { payload } = await jwtVerify(jwt, publicKey);
|
|
447
|
+
const vcClaim = payload.vc;
|
|
448
|
+
if (!vcClaim) {
|
|
449
|
+
return {
|
|
450
|
+
success: false,
|
|
451
|
+
error: makeError2("VC_MISSING_VC_CLAIM", "JWT does not contain a vc claim")
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
const credential = {
|
|
455
|
+
...vcClaim,
|
|
456
|
+
issuer: issuerDid
|
|
457
|
+
};
|
|
458
|
+
const parsed = VerifiableCredentialSchema.safeParse(credential);
|
|
459
|
+
if (!parsed.success) {
|
|
460
|
+
return {
|
|
461
|
+
success: false,
|
|
462
|
+
error: makeError2("VC_INVALID_CREDENTIAL", "Credential does not match W3C schema", {
|
|
463
|
+
issues: parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`)
|
|
464
|
+
})
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
if (payload.exp && payload.exp < Math.floor(Date.now() / 1e3)) {
|
|
468
|
+
return {
|
|
469
|
+
success: false,
|
|
470
|
+
error: makeError2("VC_EXPIRED", "Credential has expired")
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
if (parsed.data.credentialStatus && checkRevocationStatus) {
|
|
474
|
+
const revoked = await checkRevocationStatus(parsed.data.credentialStatus);
|
|
475
|
+
if (revoked) {
|
|
476
|
+
return {
|
|
477
|
+
success: false,
|
|
478
|
+
error: makeError2("VC_REVOKED", "Credential has been revoked")
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return {
|
|
483
|
+
success: true,
|
|
484
|
+
data: {
|
|
485
|
+
credential: parsed.data,
|
|
486
|
+
format: "jwt",
|
|
487
|
+
issuer: issuerDid,
|
|
488
|
+
issuedAt: new Date((payload.iat ?? 0) * 1e3),
|
|
489
|
+
expiresAt: payload.exp ? new Date(payload.exp * 1e3) : null
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
} catch (err) {
|
|
493
|
+
if (err instanceof errors.JWTExpired) {
|
|
494
|
+
return {
|
|
495
|
+
success: false,
|
|
496
|
+
error: makeError2("VC_EXPIRED", "Credential has expired")
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
return {
|
|
500
|
+
success: false,
|
|
501
|
+
error: makeError2(
|
|
502
|
+
"VC_VERIFY_FAILED",
|
|
503
|
+
err instanceof Error ? err.message : "Failed to verify JWT credential"
|
|
504
|
+
)
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
async function verifyJsonLdCredential(vc, providedKey) {
|
|
509
|
+
const parsed = VerifiableCredentialSchema.safeParse(vc);
|
|
510
|
+
if (!parsed.success) {
|
|
511
|
+
return {
|
|
512
|
+
success: false,
|
|
513
|
+
error: makeError2("VC_INVALID_CREDENTIAL", "Credential does not match W3C schema", {
|
|
514
|
+
issues: parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`)
|
|
515
|
+
})
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
const credential = parsed.data;
|
|
519
|
+
if (!credential.proof) {
|
|
520
|
+
return {
|
|
521
|
+
success: false,
|
|
522
|
+
error: makeError2("VC_NO_PROOF", "JSON-LD credential has no embedded proof")
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
if (!credential.proof.jws) {
|
|
526
|
+
return {
|
|
527
|
+
success: false,
|
|
528
|
+
error: makeError2("VC_NO_JWS", "Proof does not contain a JWS value")
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
const issuerDid = getIssuerString(credential.issuer);
|
|
532
|
+
const keyResult = await resolveKey(issuerDid, providedKey);
|
|
533
|
+
if (!keyResult.success) return keyResult;
|
|
534
|
+
try {
|
|
535
|
+
const publicKey = await importJWK(keyResult.data, "EdDSA");
|
|
536
|
+
const { payload } = await compactVerify(credential.proof.jws, publicKey);
|
|
537
|
+
const { proof: _proof, ...vcWithoutProof } = credential;
|
|
538
|
+
const signedContent = new TextDecoder().decode(payload);
|
|
539
|
+
const currentContent = JSON.stringify(vcWithoutProof);
|
|
540
|
+
if (signedContent !== currentContent) {
|
|
541
|
+
return {
|
|
542
|
+
success: false,
|
|
543
|
+
error: makeError2("VC_TAMPERED", "Credential content does not match the signed payload")
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
if (credential.expirationDate) {
|
|
547
|
+
const expiry = new Date(credential.expirationDate);
|
|
548
|
+
if (expiry <= /* @__PURE__ */ new Date()) {
|
|
549
|
+
return {
|
|
550
|
+
success: false,
|
|
551
|
+
error: makeError2("VC_EXPIRED", "Credential has expired")
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
if (credential.credentialStatus && checkRevocationStatus) {
|
|
556
|
+
const revoked = await checkRevocationStatus(credential.credentialStatus);
|
|
557
|
+
if (revoked) {
|
|
558
|
+
return {
|
|
559
|
+
success: false,
|
|
560
|
+
error: makeError2("VC_REVOKED", "Credential has been revoked")
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return {
|
|
565
|
+
success: true,
|
|
566
|
+
data: {
|
|
567
|
+
credential,
|
|
568
|
+
format: "json-ld",
|
|
569
|
+
issuer: issuerDid,
|
|
570
|
+
issuedAt: new Date(credential.issuanceDate),
|
|
571
|
+
expiresAt: credential.expirationDate ? new Date(credential.expirationDate) : null
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
} catch (err) {
|
|
575
|
+
return {
|
|
576
|
+
success: false,
|
|
577
|
+
error: makeError2(
|
|
578
|
+
"VC_VERIFY_FAILED",
|
|
579
|
+
err instanceof Error ? err.message : "Failed to verify JSON-LD credential"
|
|
580
|
+
)
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
async function verifyCredential(vc, publicKeyJwk) {
|
|
585
|
+
if (typeof vc === "string") {
|
|
586
|
+
return verifyJwtCredential(vc, publicKeyJwk);
|
|
587
|
+
}
|
|
588
|
+
return verifyJsonLdCredential(vc, publicKeyJwk);
|
|
589
|
+
}
|
|
590
|
+
async function verifyPresentation(vp, publicKeyJwk) {
|
|
591
|
+
let presentation;
|
|
592
|
+
if (typeof vp === "string") {
|
|
593
|
+
try {
|
|
594
|
+
const parts = vp.split(".");
|
|
595
|
+
if (parts.length !== 3 || !parts[1]) {
|
|
596
|
+
return {
|
|
597
|
+
success: false,
|
|
598
|
+
error: makeError2("VC_INVALID_JWT", "Presentation JWT must have three parts")
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
const payloadB64 = parts[1];
|
|
602
|
+
const rawPayload = JSON.parse(
|
|
603
|
+
new TextDecoder().decode(
|
|
604
|
+
Uint8Array.from(
|
|
605
|
+
atob(payloadB64.replace(/-/g, "+").replace(/_/g, "/")),
|
|
606
|
+
(c) => c.charCodeAt(0)
|
|
607
|
+
)
|
|
608
|
+
)
|
|
609
|
+
);
|
|
610
|
+
const issuerDid = typeof rawPayload.iss === "string" ? rawPayload.iss : null;
|
|
611
|
+
if (!issuerDid) {
|
|
612
|
+
return {
|
|
613
|
+
success: false,
|
|
614
|
+
error: makeError2("VC_NO_ISSUER", "Presentation JWT has no iss claim")
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
const keyResult = await resolveKey(issuerDid, publicKeyJwk);
|
|
618
|
+
if (!keyResult.success) return keyResult;
|
|
619
|
+
const publicKey = await importJWK(keyResult.data, "EdDSA");
|
|
620
|
+
const { payload } = await jwtVerify(vp, publicKey);
|
|
621
|
+
const vpClaim = payload.vp;
|
|
622
|
+
if (!vpClaim) {
|
|
623
|
+
return {
|
|
624
|
+
success: false,
|
|
625
|
+
error: makeError2("VC_MISSING_VP_CLAIM", "JWT does not contain a vp claim")
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
presentation = vpClaim;
|
|
629
|
+
} catch (err) {
|
|
630
|
+
return {
|
|
631
|
+
success: false,
|
|
632
|
+
error: makeError2(
|
|
633
|
+
"VC_VERIFY_FAILED",
|
|
634
|
+
err instanceof Error ? err.message : "Failed to verify presentation JWT"
|
|
635
|
+
)
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
} else {
|
|
639
|
+
presentation = vp;
|
|
640
|
+
}
|
|
641
|
+
const parsed = VerifiablePresentationSchema.safeParse(presentation);
|
|
642
|
+
if (!parsed.success) {
|
|
643
|
+
return {
|
|
644
|
+
success: false,
|
|
645
|
+
error: makeError2("VC_INVALID_PRESENTATION", "Presentation does not match W3C schema", {
|
|
646
|
+
issues: parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`)
|
|
647
|
+
})
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
const verifiedCredentials = [];
|
|
651
|
+
for (const vc of parsed.data.verifiableCredential) {
|
|
652
|
+
const result = await verifyCredential(vc, publicKeyJwk);
|
|
653
|
+
if (!result.success) {
|
|
654
|
+
return {
|
|
655
|
+
success: false,
|
|
656
|
+
error: makeError2(
|
|
657
|
+
"VC_PRESENTATION_CREDENTIAL_INVALID",
|
|
658
|
+
`Failed to verify credential in presentation: ${result.error.message}`,
|
|
659
|
+
{ originalError: result.error }
|
|
660
|
+
)
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
verifiedCredentials.push(result.data);
|
|
664
|
+
}
|
|
665
|
+
return {
|
|
666
|
+
success: true,
|
|
667
|
+
data: {
|
|
668
|
+
presentation: parsed.data,
|
|
669
|
+
credentials: verifiedCredentials,
|
|
670
|
+
holder: parsed.data.holder ?? null
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
function extractPermissions(vc) {
|
|
675
|
+
const subject = vc.credentialSubject;
|
|
676
|
+
return {
|
|
677
|
+
agentId: subject.agentId ?? subject.id ?? null,
|
|
678
|
+
permissions: subject.permissions ?? [],
|
|
679
|
+
trustLevel: subject.trustLevel ?? null,
|
|
680
|
+
delegationScope: subject.delegationScope ?? []
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
return {
|
|
684
|
+
verifyCredential,
|
|
685
|
+
verifyPresentation,
|
|
686
|
+
extractPermissions
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
export { CredentialStatusSchema, CredentialSubjectSchema, KAVACH_AGENT_CREDENTIAL, KAVACH_DELEGATION_CREDENTIAL, KAVACH_PERMISSION_CREDENTIAL, ProofSchema, THEAUTH_AUDIT_CONTEXT, THEAUTH_AUDIT_CREDENTIAL, VC_CONTEXT_V1, VC_CONTEXT_V2, VC_TYPE_CREDENTIAL, VC_TYPE_PRESENTATION, VerifiableCredentialSchema, VerifiablePresentationSchema, createVCIssuer, createVCVerifier, exportAuditAsVC, listAuditRecords };
|
|
691
|
+
//# sourceMappingURL=index.js.map
|
|
692
|
+
//# sourceMappingURL=index.js.map
|