@metalabel/dfos-protocol 0.0.3 → 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/CONTENT-MODEL.md +63 -22
- package/DID-METHOD.md +7 -8
- package/PROTOCOL.md +414 -94
- package/README.md +17 -11
- package/dist/chain/index.d.ts +115 -2
- package/dist/chain/index.js +14 -1
- package/dist/chunk-CZSEEZLL.js +258 -0
- package/dist/chunk-E5CFQG2B.js +99 -0
- package/dist/{chunk-VEBMLR37.js → chunk-GEVJ3SEV.js} +232 -6
- package/dist/credentials/index.d.ts +206 -0
- package/dist/credentials/index.js +35 -0
- package/dist/index.d.ts +3 -4
- package/dist/index.js +58 -32
- package/dist/merkle/index.d.ts +45 -0
- package/dist/merkle/index.js +14 -0
- package/examples/beacon.json +14 -0
- package/examples/content-delegated.json +44 -0
- package/examples/content-delete.json +5 -4
- package/examples/content-lifecycle.json +9 -7
- package/examples/credential-read.json +12 -0
- package/examples/credential-write.json +14 -0
- package/examples/merkle-tree.json +28 -0
- package/package.json +10 -9
- package/schemas/manifest.v1.json +29 -0
- package/schemas/post.v1.json +5 -0
- package/schemas/profile.v1.json +5 -0
- package/REGISTRY-API.md +0 -242
- package/dist/chunk-U6DANYPT.js +0 -311
- package/dist/registry/index.d.ts +0 -143
- package/dist/registry/index.js +0 -34
- package/openapi.yaml +0 -376
- package/schemas/document-envelope.v1.json +0 -37
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VC_TYPE_CONTENT_WRITE,
|
|
3
|
+
decodeCredentialUnsafe,
|
|
4
|
+
verifyCredential
|
|
5
|
+
} from "./chunk-CZSEEZLL.js";
|
|
1
6
|
import {
|
|
2
7
|
createJws,
|
|
3
8
|
dagCborCanonicalEncode,
|
|
@@ -13,6 +18,7 @@ var MAX_PUBLIC_KEY_MULTIBASE = 128;
|
|
|
13
18
|
var MAX_CID = 256;
|
|
14
19
|
var MAX_NOTE = 256;
|
|
15
20
|
var MAX_KEYS_PER_ROLE = 16;
|
|
21
|
+
var MAX_DID = 256;
|
|
16
22
|
var MultikeyPublicKey = z.strictObject({
|
|
17
23
|
id: z.string().max(MAX_KEY_ID),
|
|
18
24
|
type: z.literal("Multikey"),
|
|
@@ -49,7 +55,7 @@ var IdentityOperation = z.discriminatedUnion("type", [
|
|
|
49
55
|
IdentityDelete
|
|
50
56
|
]);
|
|
51
57
|
var VerifiedIdentity = z.strictObject({
|
|
52
|
-
did: z.string(),
|
|
58
|
+
did: z.string().max(MAX_DID),
|
|
53
59
|
isDeleted: z.boolean(),
|
|
54
60
|
authKeys: z.array(MultikeyPublicKey).max(MAX_KEYS_PER_ROLE),
|
|
55
61
|
assertKeys: z.array(MultikeyPublicKey).max(MAX_KEYS_PER_ROLE),
|
|
@@ -58,30 +64,46 @@ var VerifiedIdentity = z.strictObject({
|
|
|
58
64
|
var ContentCreate = z.strictObject({
|
|
59
65
|
version: z.literal(1),
|
|
60
66
|
type: z.literal("create"),
|
|
67
|
+
did: z.string().max(MAX_DID),
|
|
61
68
|
documentCID: CIDString,
|
|
69
|
+
baseDocumentCID: CIDString.nullable(),
|
|
62
70
|
createdAt: Iso8601,
|
|
63
71
|
note: z.string().max(MAX_NOTE).nullable()
|
|
64
72
|
});
|
|
65
73
|
var ContentUpdate = z.strictObject({
|
|
66
74
|
version: z.literal(1),
|
|
67
75
|
type: z.literal("update"),
|
|
76
|
+
did: z.string().max(MAX_DID),
|
|
68
77
|
previousOperationCID: CIDString,
|
|
69
78
|
documentCID: CIDString.nullable(),
|
|
79
|
+
baseDocumentCID: CIDString.nullable(),
|
|
70
80
|
createdAt: Iso8601,
|
|
71
|
-
note: z.string().max(MAX_NOTE).nullable()
|
|
81
|
+
note: z.string().max(MAX_NOTE).nullable(),
|
|
82
|
+
/** VC-JWT authorizing this operation when signer is not the chain creator */
|
|
83
|
+
authorization: z.string().optional()
|
|
72
84
|
});
|
|
73
85
|
var ContentDelete = z.strictObject({
|
|
74
86
|
version: z.literal(1),
|
|
75
87
|
type: z.literal("delete"),
|
|
88
|
+
did: z.string().max(MAX_DID),
|
|
76
89
|
previousOperationCID: CIDString,
|
|
77
90
|
createdAt: Iso8601,
|
|
78
|
-
note: z.string().max(MAX_NOTE).nullable()
|
|
91
|
+
note: z.string().max(MAX_NOTE).nullable(),
|
|
92
|
+
/** VC-JWT authorizing this operation when signer is not the chain creator */
|
|
93
|
+
authorization: z.string().optional()
|
|
79
94
|
});
|
|
80
95
|
var ContentOperation = z.discriminatedUnion("type", [
|
|
81
96
|
ContentCreate,
|
|
82
97
|
ContentUpdate,
|
|
83
98
|
ContentDelete
|
|
84
99
|
]);
|
|
100
|
+
var BeaconPayload = z.strictObject({
|
|
101
|
+
version: z.literal(1),
|
|
102
|
+
type: z.literal("beacon"),
|
|
103
|
+
did: z.string().max(MAX_DID),
|
|
104
|
+
merkleRoot: z.string().regex(/^[0-9a-f]{64}$/),
|
|
105
|
+
createdAt: Iso8601
|
|
106
|
+
});
|
|
85
107
|
|
|
86
108
|
// src/chain/multikey.ts
|
|
87
109
|
import { base58btc } from "multiformats/bases/base58";
|
|
@@ -164,6 +186,9 @@ var verifyIdentityChain = async (input) => {
|
|
|
164
186
|
throw new Error(`log[${idx}]: ${messages}`);
|
|
165
187
|
}
|
|
166
188
|
const op = result.data;
|
|
189
|
+
if (decoded.header.typ !== "did:dfos:identity-op") {
|
|
190
|
+
throw new Error(`log[${idx}]: invalid typ: ${decoded.header.typ}`);
|
|
191
|
+
}
|
|
167
192
|
if (state.isDeleted) throw new Error(`log[${idx}]: cannot modify a deleted identity`);
|
|
168
193
|
if (idx === 0 && op.type !== "create") {
|
|
169
194
|
throw new Error(`log[${idx}]: first operation must be create`);
|
|
@@ -295,7 +320,8 @@ var verifyContentChain = async (input) => {
|
|
|
295
320
|
isDeleted: false,
|
|
296
321
|
currentDocumentCID: null,
|
|
297
322
|
previousCID: null,
|
|
298
|
-
lastCreatedAt: null
|
|
323
|
+
lastCreatedAt: null,
|
|
324
|
+
creatorDID: null
|
|
299
325
|
};
|
|
300
326
|
for (const [idx, jwsToken] of input.log.entries()) {
|
|
301
327
|
const decoded = decodeJwsUnsafe(jwsToken);
|
|
@@ -306,6 +332,9 @@ var verifyContentChain = async (input) => {
|
|
|
306
332
|
throw new Error(`log[${idx}]: ${messages}`);
|
|
307
333
|
}
|
|
308
334
|
const op = result.data;
|
|
335
|
+
if (decoded.header.typ !== "did:dfos:content-op") {
|
|
336
|
+
throw new Error(`log[${idx}]: invalid typ: ${decoded.header.typ}`);
|
|
337
|
+
}
|
|
309
338
|
if (state.isDeleted) throw new Error(`log[${idx}]: cannot extend a deleted chain`);
|
|
310
339
|
if (idx === 0 && op.type !== "create") {
|
|
311
340
|
throw new Error(`log[${idx}]: first operation must be create`);
|
|
@@ -323,12 +352,63 @@ var verifyContentChain = async (input) => {
|
|
|
323
352
|
}
|
|
324
353
|
}
|
|
325
354
|
const kid = decoded.header.kid;
|
|
355
|
+
const hashIdx = kid.indexOf("#");
|
|
356
|
+
if (hashIdx < 0) throw new Error(`log[${idx}]: kid must be a DID URL`);
|
|
357
|
+
const kidDid = kid.substring(0, hashIdx);
|
|
358
|
+
if (kidDid !== op.did) {
|
|
359
|
+
throw new Error(`log[${idx}]: kid DID does not match operation did`);
|
|
360
|
+
}
|
|
326
361
|
const publicKey = await input.resolveKey(kid);
|
|
327
362
|
try {
|
|
328
363
|
verifyJws({ token: jwsToken, publicKey });
|
|
329
364
|
} catch {
|
|
330
365
|
throw new Error(`log[${idx}]: invalid signature`);
|
|
331
366
|
}
|
|
367
|
+
if (idx === 0) {
|
|
368
|
+
state.creatorDID = op.did;
|
|
369
|
+
} else if (op.did !== state.creatorDID && input.enforceAuthorization) {
|
|
370
|
+
const authorization = op.type !== "create" ? op.authorization : void 0;
|
|
371
|
+
if (!authorization) {
|
|
372
|
+
throw new Error(
|
|
373
|
+
`log[${idx}]: signer ${op.did} is not the chain creator \u2014 authorization VC required`
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
const vcDecoded = decodeCredentialUnsafe(authorization);
|
|
377
|
+
if (!vcDecoded) {
|
|
378
|
+
throw new Error(`log[${idx}]: failed to decode authorization VC`);
|
|
379
|
+
}
|
|
380
|
+
const vcKid = vcDecoded.header.kid;
|
|
381
|
+
if (!vcKid || !vcKid.includes("#")) {
|
|
382
|
+
throw new Error(`log[${idx}]: authorization VC kid must be a DID URL`);
|
|
383
|
+
}
|
|
384
|
+
let creatorPublicKey;
|
|
385
|
+
try {
|
|
386
|
+
creatorPublicKey = await input.resolveKey(vcKid);
|
|
387
|
+
} catch {
|
|
388
|
+
throw new Error(`log[${idx}]: cannot resolve creator key for authorization verification`);
|
|
389
|
+
}
|
|
390
|
+
const opCreatedAtUnix = Math.floor(new Date(op.createdAt).getTime() / 1e3);
|
|
391
|
+
try {
|
|
392
|
+
const credential = verifyCredential({
|
|
393
|
+
token: authorization,
|
|
394
|
+
publicKey: creatorPublicKey,
|
|
395
|
+
subject: op.did,
|
|
396
|
+
expectedType: VC_TYPE_CONTENT_WRITE,
|
|
397
|
+
currentTime: opCreatedAtUnix
|
|
398
|
+
});
|
|
399
|
+
if (credential.iss !== state.creatorDID) {
|
|
400
|
+
throw new Error("VC issuer is not the chain creator");
|
|
401
|
+
}
|
|
402
|
+
if (credential.contentId && credential.contentId !== state.contentId) {
|
|
403
|
+
throw new Error(
|
|
404
|
+
`VC contentId ${credential.contentId} does not match chain ${state.contentId}`
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
} catch (err) {
|
|
408
|
+
const message = err instanceof Error ? err.message : "unknown error";
|
|
409
|
+
throw new Error(`log[${idx}]: authorization verification failed: ${message}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
332
412
|
const encoded = await dagCborCanonicalEncode(op);
|
|
333
413
|
const operationCID = encoded.cid.toString();
|
|
334
414
|
if (!decoded.header.cid) {
|
|
@@ -363,7 +443,147 @@ var verifyContentChain = async (input) => {
|
|
|
363
443
|
headCID: state.headCID,
|
|
364
444
|
isDeleted: state.isDeleted,
|
|
365
445
|
currentDocumentCID: state.currentDocumentCID,
|
|
366
|
-
length: input.log.length
|
|
446
|
+
length: input.log.length,
|
|
447
|
+
creatorDID: state.creatorDID
|
|
448
|
+
};
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
// src/chain/beacon.ts
|
|
452
|
+
var signBeacon = async (input) => {
|
|
453
|
+
const encoded = await dagCborCanonicalEncode(input.payload);
|
|
454
|
+
const beaconCID = encoded.cid.toString();
|
|
455
|
+
const jwsToken = await createJws({
|
|
456
|
+
header: { alg: "EdDSA", typ: "did:dfos:beacon", kid: input.kid, cid: beaconCID },
|
|
457
|
+
payload: input.payload,
|
|
458
|
+
sign: input.signer
|
|
459
|
+
});
|
|
460
|
+
return { jwsToken, beaconCID };
|
|
461
|
+
};
|
|
462
|
+
var MAX_FUTURE_MS = 5 * 60 * 1e3;
|
|
463
|
+
var verifyBeacon = async (input) => {
|
|
464
|
+
const decoded = decodeJwsUnsafe(input.jwsToken);
|
|
465
|
+
if (!decoded) throw new Error("failed to decode beacon JWS");
|
|
466
|
+
const result = BeaconPayload.safeParse(decoded.payload);
|
|
467
|
+
if (!result.success) {
|
|
468
|
+
const messages = result.error.issues.map((e) => e.message).join(", ");
|
|
469
|
+
throw new Error(`invalid beacon payload: ${messages}`);
|
|
470
|
+
}
|
|
471
|
+
const payload = result.data;
|
|
472
|
+
if (decoded.header.typ !== "did:dfos:beacon") {
|
|
473
|
+
throw new Error(`invalid beacon typ: ${decoded.header.typ}`);
|
|
474
|
+
}
|
|
475
|
+
const kid = decoded.header.kid;
|
|
476
|
+
const hashIdx = kid.indexOf("#");
|
|
477
|
+
if (hashIdx < 0) throw new Error("beacon kid must be a DID URL");
|
|
478
|
+
const kidDid = kid.substring(0, hashIdx);
|
|
479
|
+
if (kidDid !== payload.did) {
|
|
480
|
+
throw new Error("beacon kid DID does not match payload did");
|
|
481
|
+
}
|
|
482
|
+
const publicKey = await input.resolveKey(kid);
|
|
483
|
+
try {
|
|
484
|
+
verifyJws({ token: input.jwsToken, publicKey });
|
|
485
|
+
} catch {
|
|
486
|
+
throw new Error("invalid beacon signature");
|
|
487
|
+
}
|
|
488
|
+
const encoded = await dagCborCanonicalEncode(payload);
|
|
489
|
+
const beaconCID = encoded.cid.toString();
|
|
490
|
+
if (!decoded.header.cid) throw new Error("missing cid in beacon header");
|
|
491
|
+
if (decoded.header.cid !== beaconCID) throw new Error("beacon cid mismatch");
|
|
492
|
+
const now = input.now ?? Date.now();
|
|
493
|
+
const beaconTime = new Date(payload.createdAt).getTime();
|
|
494
|
+
if (beaconTime > now + MAX_FUTURE_MS) {
|
|
495
|
+
throw new Error("beacon createdAt is too far in the future");
|
|
496
|
+
}
|
|
497
|
+
return { payload, beaconCID };
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
// src/chain/countersign.ts
|
|
501
|
+
var signCountersignature = async (input) => {
|
|
502
|
+
const encoded = await dagCborCanonicalEncode(input.operationPayload);
|
|
503
|
+
const operationCID = encoded.cid.toString();
|
|
504
|
+
const jwsToken = await createJws({
|
|
505
|
+
header: { alg: "EdDSA", typ: "did:dfos:content-op", kid: input.kid, cid: operationCID },
|
|
506
|
+
payload: input.operationPayload,
|
|
507
|
+
sign: input.signer
|
|
508
|
+
});
|
|
509
|
+
return { jwsToken, operationCID };
|
|
510
|
+
};
|
|
511
|
+
var verifyCountersignature = async (input) => {
|
|
512
|
+
const decoded = decodeJwsUnsafe(input.jwsToken);
|
|
513
|
+
if (!decoded) throw new Error("failed to decode countersignature JWS");
|
|
514
|
+
if (decoded.header.typ !== "did:dfos:content-op") {
|
|
515
|
+
throw new Error(`invalid countersignature typ: ${decoded.header.typ}`);
|
|
516
|
+
}
|
|
517
|
+
const result = ContentOperation.safeParse(decoded.payload);
|
|
518
|
+
if (!result.success) {
|
|
519
|
+
const messages = result.error.issues.map((e) => e.message).join(", ");
|
|
520
|
+
throw new Error(`invalid operation payload: ${messages}`);
|
|
521
|
+
}
|
|
522
|
+
const op = result.data;
|
|
523
|
+
const encoded = await dagCborCanonicalEncode(op);
|
|
524
|
+
const operationCID = encoded.cid.toString();
|
|
525
|
+
if (operationCID !== input.expectedCID) {
|
|
526
|
+
throw new Error("countersignature CID does not match expected CID");
|
|
527
|
+
}
|
|
528
|
+
if (decoded.header.cid !== operationCID) {
|
|
529
|
+
throw new Error("countersignature header cid mismatch");
|
|
530
|
+
}
|
|
531
|
+
const kid = decoded.header.kid;
|
|
532
|
+
const publicKey = await input.resolveKey(kid);
|
|
533
|
+
try {
|
|
534
|
+
verifyJws({ token: input.jwsToken, publicKey });
|
|
535
|
+
} catch {
|
|
536
|
+
throw new Error("invalid countersignature");
|
|
537
|
+
}
|
|
538
|
+
const hashIdx = kid.indexOf("#");
|
|
539
|
+
if (hashIdx < 0) throw new Error("countersignature kid must be a DID URL");
|
|
540
|
+
const witnessDID = kid.substring(0, hashIdx);
|
|
541
|
+
if (witnessDID === op.did) {
|
|
542
|
+
throw new Error("countersignature kid DID must differ from operation did (not a witness)");
|
|
543
|
+
}
|
|
544
|
+
return {
|
|
545
|
+
operationCID,
|
|
546
|
+
authorDID: op.did,
|
|
547
|
+
witnessDID
|
|
548
|
+
};
|
|
549
|
+
};
|
|
550
|
+
var verifyBeaconCountersignature = async (input) => {
|
|
551
|
+
const decoded = decodeJwsUnsafe(input.jwsToken);
|
|
552
|
+
if (!decoded) throw new Error("failed to decode beacon countersignature JWS");
|
|
553
|
+
if (decoded.header.typ !== "did:dfos:beacon") {
|
|
554
|
+
throw new Error(`invalid beacon countersignature typ: ${decoded.header.typ}`);
|
|
555
|
+
}
|
|
556
|
+
const result = BeaconPayload.safeParse(decoded.payload);
|
|
557
|
+
if (!result.success) {
|
|
558
|
+
const messages = result.error.issues.map((e) => e.message).join(", ");
|
|
559
|
+
throw new Error(`invalid beacon payload: ${messages}`);
|
|
560
|
+
}
|
|
561
|
+
const beacon = result.data;
|
|
562
|
+
const encoded = await dagCborCanonicalEncode(beacon);
|
|
563
|
+
const beaconCID = encoded.cid.toString();
|
|
564
|
+
if (beaconCID !== input.expectedCID) {
|
|
565
|
+
throw new Error("beacon countersignature CID does not match expected CID");
|
|
566
|
+
}
|
|
567
|
+
if (decoded.header.cid !== beaconCID) {
|
|
568
|
+
throw new Error("beacon countersignature header cid mismatch");
|
|
569
|
+
}
|
|
570
|
+
const kid = decoded.header.kid;
|
|
571
|
+
const publicKey = await input.resolveKey(kid);
|
|
572
|
+
try {
|
|
573
|
+
verifyJws({ token: input.jwsToken, publicKey });
|
|
574
|
+
} catch {
|
|
575
|
+
throw new Error("invalid beacon countersignature");
|
|
576
|
+
}
|
|
577
|
+
const hashIdx = kid.indexOf("#");
|
|
578
|
+
if (hashIdx < 0) throw new Error("beacon countersignature kid must be a DID URL");
|
|
579
|
+
const witnessDID = kid.substring(0, hashIdx);
|
|
580
|
+
if (witnessDID === beacon.did) {
|
|
581
|
+
throw new Error("beacon countersignature kid DID must differ from beacon did (not a witness)");
|
|
582
|
+
}
|
|
583
|
+
return {
|
|
584
|
+
beaconCID,
|
|
585
|
+
controllerDID: beacon.did,
|
|
586
|
+
witnessDID
|
|
367
587
|
};
|
|
368
588
|
};
|
|
369
589
|
|
|
@@ -372,6 +592,7 @@ export {
|
|
|
372
592
|
IdentityOperation,
|
|
373
593
|
VerifiedIdentity,
|
|
374
594
|
ContentOperation,
|
|
595
|
+
BeaconPayload,
|
|
375
596
|
ED25519_PUB_MULTICODEC,
|
|
376
597
|
ED25519_PRIV_MULTICODEC,
|
|
377
598
|
encodeEd25519Multikey,
|
|
@@ -381,5 +602,10 @@ export {
|
|
|
381
602
|
signIdentityOperation,
|
|
382
603
|
verifyIdentityChain,
|
|
383
604
|
signContentOperation,
|
|
384
|
-
verifyContentChain
|
|
605
|
+
verifyContentChain,
|
|
606
|
+
signBeacon,
|
|
607
|
+
verifyBeacon,
|
|
608
|
+
signCountersignature,
|
|
609
|
+
verifyCountersignature,
|
|
610
|
+
verifyBeaconCountersignature
|
|
385
611
|
};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/** VC type for authorizing content chain writes (delegated operations) */
|
|
4
|
+
declare const VC_TYPE_CONTENT_WRITE = "DFOSContentWrite";
|
|
5
|
+
/** VC type for authorizing content plane reads (relay access) */
|
|
6
|
+
declare const VC_TYPE_CONTENT_READ = "DFOSContentRead";
|
|
7
|
+
/** All known DFOS VC types */
|
|
8
|
+
declare const DFOSCredentialType: z.ZodEnum<{
|
|
9
|
+
DFOSContentWrite: "DFOSContentWrite";
|
|
10
|
+
DFOSContentRead: "DFOSContentRead";
|
|
11
|
+
}>;
|
|
12
|
+
type DFOSCredentialType = z.infer<typeof DFOSCredentialType>;
|
|
13
|
+
/** Claims for a DID-signed auth token (relay AuthN) */
|
|
14
|
+
declare const AuthTokenClaims: z.ZodObject<{
|
|
15
|
+
/** Issuer — the DID proving identity */
|
|
16
|
+
iss: z.ZodString;
|
|
17
|
+
/** Subject — same as iss for auth tokens */
|
|
18
|
+
sub: z.ZodString;
|
|
19
|
+
/** Audience — target relay hostname (prevents cross-relay replay) */
|
|
20
|
+
aud: z.ZodString;
|
|
21
|
+
/** Expiration — unix seconds, short-lived (minutes) */
|
|
22
|
+
exp: z.ZodNumber;
|
|
23
|
+
/** Issued at — unix seconds */
|
|
24
|
+
iat: z.ZodNumber;
|
|
25
|
+
}, z.core.$strict>;
|
|
26
|
+
type AuthTokenClaims = z.infer<typeof AuthTokenClaims>;
|
|
27
|
+
/** Credential subject for content write authorization */
|
|
28
|
+
declare const ContentWriteSubject: z.ZodObject<{
|
|
29
|
+
/** Optional content chain narrowing — if absent, grants broad write access */
|
|
30
|
+
contentId: z.ZodOptional<z.ZodString>;
|
|
31
|
+
}, z.core.$strict>;
|
|
32
|
+
type ContentWriteSubject = z.infer<typeof ContentWriteSubject>;
|
|
33
|
+
/** Credential subject for content read authorization */
|
|
34
|
+
declare const ContentReadSubject: z.ZodObject<{
|
|
35
|
+
/** Optional content chain narrowing — if absent, grants broad read access */
|
|
36
|
+
contentId: z.ZodOptional<z.ZodString>;
|
|
37
|
+
}, z.core.$strict>;
|
|
38
|
+
type ContentReadSubject = z.infer<typeof ContentReadSubject>;
|
|
39
|
+
/** The `vc` claim in a VC-JWT payload */
|
|
40
|
+
declare const VCClaim: z.ZodObject<{
|
|
41
|
+
'@context': z.ZodTuple<[z.ZodLiteral<"https://www.w3.org/ns/credentials/v2">], null>;
|
|
42
|
+
type: z.ZodPipe<z.ZodTuple<[z.ZodLiteral<"VerifiableCredential">, z.ZodEnum<{
|
|
43
|
+
DFOSContentWrite: "DFOSContentWrite";
|
|
44
|
+
DFOSContentRead: "DFOSContentRead";
|
|
45
|
+
}>], null>, z.ZodTransform<[string, "DFOSContentWrite" | "DFOSContentRead"], ["VerifiableCredential", "DFOSContentWrite" | "DFOSContentRead"]>>;
|
|
46
|
+
credentialSubject: z.ZodUnion<readonly [z.ZodObject<{
|
|
47
|
+
/** Optional content chain narrowing — if absent, grants broad write access */
|
|
48
|
+
contentId: z.ZodOptional<z.ZodString>;
|
|
49
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
50
|
+
/** Optional content chain narrowing — if absent, grants broad read access */
|
|
51
|
+
contentId: z.ZodOptional<z.ZodString>;
|
|
52
|
+
}, z.core.$strict>]>;
|
|
53
|
+
}, z.core.$strict>;
|
|
54
|
+
type VCClaim = z.infer<typeof VCClaim>;
|
|
55
|
+
/** Full VC-JWT payload claims */
|
|
56
|
+
declare const CredentialClaims: z.ZodObject<{
|
|
57
|
+
/** Issuer — the DID granting the credential */
|
|
58
|
+
iss: z.ZodString;
|
|
59
|
+
/** Subject — the DID receiving the credential */
|
|
60
|
+
sub: z.ZodString;
|
|
61
|
+
/** Expiration — unix seconds */
|
|
62
|
+
exp: z.ZodNumber;
|
|
63
|
+
/** Issued at — unix seconds */
|
|
64
|
+
iat: z.ZodNumber;
|
|
65
|
+
/** Verifiable credential claim */
|
|
66
|
+
vc: z.ZodObject<{
|
|
67
|
+
'@context': z.ZodTuple<[z.ZodLiteral<"https://www.w3.org/ns/credentials/v2">], null>;
|
|
68
|
+
type: z.ZodPipe<z.ZodTuple<[z.ZodLiteral<"VerifiableCredential">, z.ZodEnum<{
|
|
69
|
+
DFOSContentWrite: "DFOSContentWrite";
|
|
70
|
+
DFOSContentRead: "DFOSContentRead";
|
|
71
|
+
}>], null>, z.ZodTransform<[string, "DFOSContentWrite" | "DFOSContentRead"], ["VerifiableCredential", "DFOSContentWrite" | "DFOSContentRead"]>>;
|
|
72
|
+
credentialSubject: z.ZodUnion<readonly [z.ZodObject<{
|
|
73
|
+
/** Optional content chain narrowing — if absent, grants broad write access */
|
|
74
|
+
contentId: z.ZodOptional<z.ZodString>;
|
|
75
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
76
|
+
/** Optional content chain narrowing — if absent, grants broad read access */
|
|
77
|
+
contentId: z.ZodOptional<z.ZodString>;
|
|
78
|
+
}, z.core.$strict>]>;
|
|
79
|
+
}, z.core.$strict>;
|
|
80
|
+
}, z.core.$strict>;
|
|
81
|
+
type CredentialClaims = z.infer<typeof CredentialClaims>;
|
|
82
|
+
|
|
83
|
+
interface AuthTokenCreateOptions {
|
|
84
|
+
/** The DID proving identity */
|
|
85
|
+
iss: string;
|
|
86
|
+
/** Target relay hostname (prevents cross-relay replay) */
|
|
87
|
+
aud: string;
|
|
88
|
+
/** Expiration — unix seconds */
|
|
89
|
+
exp: number;
|
|
90
|
+
/** kid — DID URL: "did:dfos:xxx#key_yyy" */
|
|
91
|
+
kid: string;
|
|
92
|
+
/** Issued-at override — unix seconds (defaults to Date.now()) */
|
|
93
|
+
iat?: number;
|
|
94
|
+
/** Signer function */
|
|
95
|
+
sign: (message: Uint8Array) => Promise<Uint8Array>;
|
|
96
|
+
}
|
|
97
|
+
interface AuthTokenVerifyOptions {
|
|
98
|
+
/** The JWT token string */
|
|
99
|
+
token: string;
|
|
100
|
+
/** Raw Ed25519 public key bytes (32 bytes) */
|
|
101
|
+
publicKey: Uint8Array;
|
|
102
|
+
/** Expected audience (relay hostname) */
|
|
103
|
+
audience: string;
|
|
104
|
+
/** Current time in seconds (defaults to Date.now() / 1000) */
|
|
105
|
+
currentTime?: number;
|
|
106
|
+
}
|
|
107
|
+
interface VerifiedAuthToken {
|
|
108
|
+
/** The DID that created the token */
|
|
109
|
+
iss: string;
|
|
110
|
+
/** The target relay */
|
|
111
|
+
aud: string;
|
|
112
|
+
/** Token expiration (unix seconds) */
|
|
113
|
+
exp: number;
|
|
114
|
+
/** kid from the JWT header */
|
|
115
|
+
kid: string;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Create a DID-signed auth token JWT for relay authentication
|
|
119
|
+
*/
|
|
120
|
+
declare const createAuthToken: (options: AuthTokenCreateOptions) => Promise<string>;
|
|
121
|
+
/**
|
|
122
|
+
* Verify a DID-signed auth token JWT
|
|
123
|
+
*
|
|
124
|
+
* Checks signature, expiration, audience, and payload structure.
|
|
125
|
+
*/
|
|
126
|
+
declare const verifyAuthToken: (options: AuthTokenVerifyOptions) => VerifiedAuthToken;
|
|
127
|
+
declare class AuthTokenVerificationError extends Error {
|
|
128
|
+
constructor(message: string);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
interface CredentialCreateOptions {
|
|
132
|
+
/** The DID granting the credential (content creator/controller) */
|
|
133
|
+
iss: string;
|
|
134
|
+
/** The DID receiving the credential (collaborator/reader) */
|
|
135
|
+
sub: string;
|
|
136
|
+
/** Expiration — unix seconds */
|
|
137
|
+
exp: number;
|
|
138
|
+
/** kid — DID URL of the issuer: "did:dfos:xxx#key_yyy" */
|
|
139
|
+
kid: string;
|
|
140
|
+
/** Credential type */
|
|
141
|
+
type: DFOSCredentialType;
|
|
142
|
+
/** Optional content chain narrowing */
|
|
143
|
+
contentId?: string;
|
|
144
|
+
/** Issued-at override — unix seconds (defaults to Date.now()) */
|
|
145
|
+
iat?: number;
|
|
146
|
+
/** Signer function */
|
|
147
|
+
sign: (message: Uint8Array) => Promise<Uint8Array>;
|
|
148
|
+
}
|
|
149
|
+
interface CredentialVerifyOptions {
|
|
150
|
+
/** The VC-JWT token string */
|
|
151
|
+
token: string;
|
|
152
|
+
/** Raw Ed25519 public key bytes (32 bytes) of the issuer */
|
|
153
|
+
publicKey: Uint8Array;
|
|
154
|
+
/** Expected subject DID (optional — if provided, sub must match) */
|
|
155
|
+
subject?: string;
|
|
156
|
+
/** Expected credential type (optional — if provided, type must match) */
|
|
157
|
+
expectedType?: DFOSCredentialType;
|
|
158
|
+
/** Current time in seconds (defaults to Date.now() / 1000) */
|
|
159
|
+
currentTime?: number;
|
|
160
|
+
}
|
|
161
|
+
interface VerifiedCredential {
|
|
162
|
+
/** The DID that issued the credential */
|
|
163
|
+
iss: string;
|
|
164
|
+
/** The DID the credential was issued to */
|
|
165
|
+
sub: string;
|
|
166
|
+
/** Credential expiration (unix seconds) */
|
|
167
|
+
exp: number;
|
|
168
|
+
/** The DFOS credential type */
|
|
169
|
+
type: DFOSCredentialType;
|
|
170
|
+
/** kid from the JWT header */
|
|
171
|
+
kid: string;
|
|
172
|
+
/** Optional content chain narrowing */
|
|
173
|
+
contentId?: string;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Create a VC-JWT credential
|
|
177
|
+
*
|
|
178
|
+
* The credential is a JWT with `typ: "vc+jwt"` in the header and a `vc`
|
|
179
|
+
* claim in the payload following W3C VC Data Model v2.
|
|
180
|
+
*/
|
|
181
|
+
declare const createCredential: (options: CredentialCreateOptions) => Promise<string>;
|
|
182
|
+
/**
|
|
183
|
+
* Verify a VC-JWT credential
|
|
184
|
+
*
|
|
185
|
+
* Checks signature, expiration, payload structure, and optionally subject
|
|
186
|
+
* and credential type.
|
|
187
|
+
*/
|
|
188
|
+
declare const verifyCredential: (options: CredentialVerifyOptions) => VerifiedCredential;
|
|
189
|
+
/**
|
|
190
|
+
* Decode a VC-JWT credential without verifying the signature
|
|
191
|
+
*
|
|
192
|
+
* Returns null if the token is malformed or claims are invalid.
|
|
193
|
+
*/
|
|
194
|
+
declare const decodeCredentialUnsafe: (token: string) => {
|
|
195
|
+
header: {
|
|
196
|
+
alg: string;
|
|
197
|
+
typ: string;
|
|
198
|
+
kid: string;
|
|
199
|
+
};
|
|
200
|
+
claims: CredentialClaims;
|
|
201
|
+
} | null;
|
|
202
|
+
declare class CredentialVerificationError extends Error {
|
|
203
|
+
constructor(message: string);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export { AuthTokenClaims, type AuthTokenCreateOptions, AuthTokenVerificationError, type AuthTokenVerifyOptions, ContentReadSubject, ContentWriteSubject, CredentialClaims, type CredentialCreateOptions, CredentialVerificationError, type CredentialVerifyOptions, DFOSCredentialType, VCClaim, VC_TYPE_CONTENT_READ, VC_TYPE_CONTENT_WRITE, type VerifiedAuthToken, type VerifiedCredential, createAuthToken, createCredential, decodeCredentialUnsafe, verifyAuthToken, verifyCredential };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuthTokenClaims,
|
|
3
|
+
AuthTokenVerificationError,
|
|
4
|
+
ContentReadSubject,
|
|
5
|
+
ContentWriteSubject,
|
|
6
|
+
CredentialClaims,
|
|
7
|
+
CredentialVerificationError,
|
|
8
|
+
DFOSCredentialType,
|
|
9
|
+
VCClaim,
|
|
10
|
+
VC_TYPE_CONTENT_READ,
|
|
11
|
+
VC_TYPE_CONTENT_WRITE,
|
|
12
|
+
createAuthToken,
|
|
13
|
+
createCredential,
|
|
14
|
+
decodeCredentialUnsafe,
|
|
15
|
+
verifyAuthToken,
|
|
16
|
+
verifyCredential
|
|
17
|
+
} from "../chunk-CZSEEZLL.js";
|
|
18
|
+
import "../chunk-ZXXP5W5N.js";
|
|
19
|
+
export {
|
|
20
|
+
AuthTokenClaims,
|
|
21
|
+
AuthTokenVerificationError,
|
|
22
|
+
ContentReadSubject,
|
|
23
|
+
ContentWriteSubject,
|
|
24
|
+
CredentialClaims,
|
|
25
|
+
CredentialVerificationError,
|
|
26
|
+
DFOSCredentialType,
|
|
27
|
+
VCClaim,
|
|
28
|
+
VC_TYPE_CONTENT_READ,
|
|
29
|
+
VC_TYPE_CONTENT_WRITE,
|
|
30
|
+
createAuthToken,
|
|
31
|
+
createCredential,
|
|
32
|
+
decodeCredentialUnsafe,
|
|
33
|
+
verifyAuthToken,
|
|
34
|
+
verifyCredential
|
|
35
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
export { JwsHeader, JwsVerificationError, JwtClaims, JwtCreateOptions, JwtHeader, JwtVerificationError, JwtVerifyOptions, PrefixedID, base64urlDecode, base64urlEncode, createJws, createJwt, createNewEd25519Keypair, dagCborCanonicalEncode, decodeJwsUnsafe, decodeJwtUnsafe, generateId, generateIdNoPrefix, importEd25519Keypair, isCanonicallyEqual, isValidEd25519Signature, isValidId, normalizedId, parseDagCborCID, signPayloadEd25519, verifyJws, verifyJwt } from './crypto/index.js';
|
|
2
|
-
export { ContentOperation, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, IdentityOperation, MultikeyPublicKey, Signer, VerifiedContentChain, VerifiedIdentity, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, signContentOperation, signIdentityOperation, verifyContentChain, verifyIdentityChain } from './chain/index.js';
|
|
3
|
-
export {
|
|
2
|
+
export { BeaconPayload, ContentOperation, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, IdentityOperation, MultikeyPublicKey, Signer, VerifiedBeacon, VerifiedBeaconCountersignature, VerifiedContentChain, VerifiedCountersignature, VerifiedIdentity, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, signBeacon, signContentOperation, signCountersignature, signIdentityOperation, verifyBeacon, verifyBeaconCountersignature, verifyContentChain, verifyCountersignature, verifyIdentityChain } from './chain/index.js';
|
|
3
|
+
export { MerkleProof, buildMerkleTree, generateMerkleProof, hashLeaf, hexToBytes, verifyMerkleProof } from './merkle/index.js';
|
|
4
|
+
export { AuthTokenClaims, AuthTokenCreateOptions, AuthTokenVerificationError, AuthTokenVerifyOptions, ContentReadSubject, ContentWriteSubject, CredentialClaims, CredentialCreateOptions, CredentialVerificationError, CredentialVerifyOptions, DFOSCredentialType, VCClaim, VC_TYPE_CONTENT_READ, VC_TYPE_CONTENT_WRITE, VerifiedAuthToken, VerifiedCredential, createAuthToken, createCredential, decodeCredentialUnsafe, verifyAuthToken, verifyCredential } from './credentials/index.js';
|
|
4
5
|
import 'multiformats';
|
|
5
6
|
import 'multiformats/cid';
|
|
6
7
|
import 'zod';
|
|
7
|
-
import 'hono/types';
|
|
8
|
-
import 'hono';
|