@metalabel/dfos-protocol 0.50.0 → 0.51.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/README.md +8 -11
- package/dist/chain/index.d.ts +57 -21
- package/dist/chain/index.js +2 -2
- package/dist/{chunk-JGFFADPR.js → chunk-LMAPBTDW.js} +102 -29
- package/dist/{chunk-MHSBBYDO.js → chunk-T2YR5KWQ.js} +17 -12
- package/dist/credentials/index.d.ts +1 -1
- package/dist/credentials/index.js +1 -1
- package/dist/{dfos-credential-BtiYPqBT.d.ts → dfos-credential-CtG0_n4P.d.ts} +71 -20
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/schemas/credit-claim.v1.json +1 -1
- package/schemas/post.v1.json +1 -1
package/README.md
CHANGED
|
@@ -38,17 +38,14 @@ import { signKeyProof, verifyKeyProof } from '@metalabel/dfos-protocol/key-proof
|
|
|
38
38
|
|
|
39
39
|
## Specifications
|
|
40
40
|
|
|
41
|
-
| Document | Description
|
|
42
|
-
| ------------------------------------------------ |
|
|
43
|
-
| [PROTOCOL.md](../../specs/PROTOCOL.md) | Core protocol — chains, signatures, verification, test vectors
|
|
44
|
-
| [DID-METHOD.md](../../specs/DID-METHOD.md) | W3C DID method specification for `did:dfos`
|
|
45
|
-
| [CONTENT-MODEL.md](../../specs/CONTENT-MODEL.md) | Standard content schemas (post, profile)
|
|
46
|
-
| [CREDENTIALS.md](../../specs/CREDENTIALS.md) | UCAN-style authorization credentials for the DFOS protocol
|
|
47
|
-
| [
|
|
48
|
-
| [
|
|
49
|
-
| [SIWD.md](../../specs/SIWD.md) | Sign In With DFOS — cryptographic identity verification for third-party apps |
|
|
50
|
-
| [API-AUTH.md](../../specs/API-AUTH.md) | Proof-of-possession authentication for credential-gated HTTP APIs |
|
|
51
|
-
| [KEY-PROOF.md](../../specs/KEY-PROOF.md) | Challenge-bound, single-shot proof that a candidate key is held |
|
|
41
|
+
| Document | Description |
|
|
42
|
+
| ------------------------------------------------ | ------------------------------------------------------------------------------- |
|
|
43
|
+
| [PROTOCOL.md](../../specs/PROTOCOL.md) | Core protocol — chains, signatures, key possession, verification, test vectors |
|
|
44
|
+
| [DID-METHOD.md](../../specs/DID-METHOD.md) | W3C DID method specification for `did:dfos` |
|
|
45
|
+
| [CONTENT-MODEL.md](../../specs/CONTENT-MODEL.md) | Standard content schemas (post, profile) and verifiable attribution |
|
|
46
|
+
| [CREDENTIALS.md](../../specs/CREDENTIALS.md) | UCAN-style authorization credentials for the DFOS protocol |
|
|
47
|
+
| [RELAY.md](../../specs/RELAY.md) | The relay HTTP surface, including the sign-request envelope and signing mailbox |
|
|
48
|
+
| [INTEGRATIONS.md](../../specs/INTEGRATIONS.md) | Sign in, API authentication, origin binding, and key ceremonies |
|
|
52
49
|
|
|
53
50
|
Release history lives at https://github.com/metalabel/dfos/releases.
|
|
54
51
|
|
package/dist/chain/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as IdentityOperation,
|
|
2
|
-
export { A as ARTIFACT_CID_ANCHOR_RE, C as CONTENT_ID_ANCHOR_RE, f as CreditClaimPayload, g as DeclaredKeyState, h as Iso8601, M as MAX_ARTIFACT_PAYLOAD_SIZE, j as MAX_CREDIT_CLAIM_SIZE, k as MAX_KEY_PROOFS, l as MAX_OPERATION_SIZE, m as MAX_SERVICES_ENTRIES, n as MAX_SERVICES_PAYLOAD_SIZE, o as MAX_SIGN_REQUEST_PAYLOAD_SIZE, p as MAX_SIGN_REQUEST_SIZE, q as MultikeyPublicKey,
|
|
1
|
+
import { I as IdentityOperation, v as Signer, x as VerifiedIdentity, S as ServiceEntry, c as ContentOperation, R as ResolvedIdentity, r as RevocationChecker, d as CountersignPayload, a as ArtifactPayload } from '../dfos-credential-CtG0_n4P.js';
|
|
2
|
+
export { A as ARTIFACT_CID_ANCHOR_RE, C as CONTENT_ID_ANCHOR_RE, f as CreditClaimPayload, g as DeclaredKeyState, h as Iso8601, M as MAX_ARTIFACT_PAYLOAD_SIZE, j as MAX_CREDIT_CLAIM_SIZE, k as MAX_KEY_PROOFS, l as MAX_OPERATION_SIZE, m as MAX_SERVICES_ENTRIES, n as MAX_SERVICES_PAYLOAD_SIZE, o as MAX_SIGN_REQUEST_PAYLOAD_SIZE, p as MAX_SIGN_REQUEST_SIZE, q as MultikeyPublicKey, s as RevocationPayload, t as ServicesArray, u as SignRequestPayload, y as VoidKeyMembership, G as parseProtocolTimestampUnix } from '../dfos-credential-CtG0_n4P.js';
|
|
3
3
|
import 'zod';
|
|
4
4
|
|
|
5
5
|
/** Ed25519 public key multicodec value */
|
|
@@ -54,13 +54,26 @@ declare const signIdentityOperation: (input: {
|
|
|
54
54
|
* Verify a log of JWS identity operations and derive the identity
|
|
55
55
|
*
|
|
56
56
|
* Walks the chain from genesis, verifying signatures and chain integrity, and
|
|
57
|
-
* folds the possession proofs alongside. Returns the
|
|
58
|
-
*
|
|
57
|
+
* folds the possession proofs alongside. Returns the verified identity state:
|
|
58
|
+
* EFFECTIVE key arrays, with the declared arrays and the void memberships
|
|
59
59
|
* beside them.
|
|
60
|
+
*
|
|
61
|
+
* THE BASIS SELECTS WHICH STATE COMES BACK, never how much of the log is
|
|
62
|
+
* verified. With `asOf` set, the whole log is walked and validated exactly as
|
|
63
|
+
* without it, and the state returned is the one the last operation dated at or
|
|
64
|
+
* before the basis folds to — the identity's state as of that instant
|
|
65
|
+
* (PROTOCOL, Time basis). The comparison is byte-wise on the `createdAt`
|
|
66
|
+
* strings, per PROTOCOL's Comparison basis. A basis earlier than genesis has no
|
|
67
|
+
* state to name and throws, and so does an empty basis.
|
|
60
68
|
*/
|
|
61
69
|
declare const verifyIdentityChain: (input: {
|
|
62
70
|
didPrefix: string;
|
|
63
71
|
log: string[];
|
|
72
|
+
/**
|
|
73
|
+
* Basis time, in the `createdAt` grammar. Omitted = the chain head, which is
|
|
74
|
+
* the state as of now.
|
|
75
|
+
*/
|
|
76
|
+
asOf?: string;
|
|
64
77
|
}) => Promise<VerifiedIdentity>;
|
|
65
78
|
/**
|
|
66
79
|
* Verify a single new operation against already-verified identity state
|
|
@@ -70,10 +83,13 @@ declare const verifyIdentityChain: (input: {
|
|
|
70
83
|
* verified genesis). This function performs one signature verification and one
|
|
71
84
|
* state transition — constant time regardless of chain length.
|
|
72
85
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
86
|
+
* KEY-ID CONSISTENCY IS CHECKED HERE, on the same terms as the full walk. The
|
|
87
|
+
* trusted state carries `seenKeys` — the id-to-material binding the walk already
|
|
88
|
+
* enforced — so an operation that re-points an existing key id at new material
|
|
89
|
+
* is REJECTED on this path exactly as a replay of the same two operations would
|
|
90
|
+
* reject it. Without that the fast path would accept a chain its own
|
|
91
|
+
* re-verification refuses, and a relay's linear path is the path almost every
|
|
92
|
+
* operation takes.
|
|
77
93
|
*
|
|
78
94
|
* THE POSSESSION FOLD RUNS HERE TOO, and it needs both halves of the trusted
|
|
79
95
|
* state: the EFFECTIVE arrays (to know what an introduction is a transition out
|
|
@@ -164,8 +180,11 @@ declare const signContentOperation: (input: {
|
|
|
164
180
|
*/
|
|
165
181
|
declare const verifyContentChain: (input: {
|
|
166
182
|
log: string[];
|
|
167
|
-
/**
|
|
168
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Resolve a kid (DID URL) to the raw Ed25519 public key bytes, in the signing
|
|
185
|
+
* identity's state as of `basis` — each operation's own `createdAt`.
|
|
186
|
+
*/
|
|
187
|
+
resolveKey: (kid: string, basis?: string) => Promise<Uint8Array>;
|
|
169
188
|
/**
|
|
170
189
|
* Enforce creator-sovereignty authorization. When true, non-creator signers
|
|
171
190
|
* must include a DFOS credential in the operation's `authorization` field
|
|
@@ -173,10 +192,11 @@ declare const verifyContentChain: (input: {
|
|
|
173
192
|
*/
|
|
174
193
|
enforceAuthorization?: boolean;
|
|
175
194
|
/**
|
|
176
|
-
* Resolve a DID to a
|
|
177
|
-
* is true, as credential verification needs identity
|
|
195
|
+
* Resolve a DID to a ResolvedIdentity as of `basis`. Required when
|
|
196
|
+
* `enforceAuthorization` is true, as credential verification needs identity
|
|
197
|
+
* resolution.
|
|
178
198
|
*/
|
|
179
|
-
resolveIdentity?: (did: string) => Promise<
|
|
199
|
+
resolveIdentity?: (did: string, basis?: string) => Promise<ResolvedIdentity | undefined>;
|
|
180
200
|
/**
|
|
181
201
|
* Check whether a credential (leaf or parent) has been revoked. Called with
|
|
182
202
|
* `asOfUnix` = each operation's own `createdAt`, so a fold of committed
|
|
@@ -198,12 +218,15 @@ declare const verifyContentExtensionFromTrustedState: (input: {
|
|
|
198
218
|
lastCreatedAt: string;
|
|
199
219
|
/** The new JWS operation to verify */
|
|
200
220
|
newOp: string;
|
|
201
|
-
/**
|
|
202
|
-
|
|
221
|
+
/**
|
|
222
|
+
* Resolve a kid (DID URL) to the raw Ed25519 public key bytes, in the signing
|
|
223
|
+
* identity's state as of `basis` — the new operation's own `createdAt`.
|
|
224
|
+
*/
|
|
225
|
+
resolveKey: (kid: string, basis?: string) => Promise<Uint8Array>;
|
|
203
226
|
/** Enforce creator-sovereignty authorization (see verifyContentChain) */
|
|
204
227
|
enforceAuthorization?: boolean;
|
|
205
|
-
/** Resolve a DID to a
|
|
206
|
-
resolveIdentity?: (did: string) => Promise<
|
|
228
|
+
/** Resolve a DID to a ResolvedIdentity as of `basis`. Required when enforceAuthorization is true. */
|
|
229
|
+
resolveIdentity?: (did: string, basis?: string) => Promise<ResolvedIdentity | undefined>;
|
|
207
230
|
/**
|
|
208
231
|
* Check whether a credential (leaf or parent) has been revoked. Called with
|
|
209
232
|
* `asOfUnix` = the new operation's own `createdAt`. See `RevocationChecker`.
|
|
@@ -242,10 +265,15 @@ declare const signCountersignature: (input: {
|
|
|
242
265
|
* Checks: valid signature, CID integrity, payload schema. Does NOT check
|
|
243
266
|
* whether the target exists or whether the witness differs from the target
|
|
244
267
|
* author — those are relay-level semantic checks.
|
|
268
|
+
*
|
|
269
|
+
* The countersignature's own `createdAt` is the basis: a committed statement
|
|
270
|
+
* resolves its signer in the state that held when it was signed (PROTOCOL, Time
|
|
271
|
+
* basis).
|
|
245
272
|
*/
|
|
246
273
|
declare const verifyCountersignature: (input: {
|
|
247
274
|
jwsToken: string;
|
|
248
|
-
|
|
275
|
+
/** Resolve a kid to key bytes in the signer's state as of `basis`. */
|
|
276
|
+
resolveKey: (kid: string, basis?: string) => Promise<Uint8Array>;
|
|
249
277
|
}) => Promise<VerifiedCountersignature>;
|
|
250
278
|
|
|
251
279
|
interface VerifiedArtifact {
|
|
@@ -267,10 +295,14 @@ declare const signArtifact: (input: {
|
|
|
267
295
|
}>;
|
|
268
296
|
/**
|
|
269
297
|
* Verify an artifact JWS — signature, CID, payload schema, size limit
|
|
298
|
+
*
|
|
299
|
+
* The artifact's own `createdAt` is the basis: a committed statement resolves
|
|
300
|
+
* its signer in the state that held when it was signed (PROTOCOL, Time basis).
|
|
270
301
|
*/
|
|
271
302
|
declare const verifyArtifact: (input: {
|
|
272
303
|
jwsToken: string;
|
|
273
|
-
|
|
304
|
+
/** Resolve a kid to key bytes in the signer's state as of `basis`. */
|
|
305
|
+
resolveKey: (kid: string, basis?: string) => Promise<Uint8Array>;
|
|
274
306
|
}) => Promise<VerifiedArtifact>;
|
|
275
307
|
|
|
276
308
|
interface VerifiedRevocation {
|
|
@@ -299,10 +331,14 @@ declare const signRevocation: (input: {
|
|
|
299
331
|
}>;
|
|
300
332
|
/**
|
|
301
333
|
* Verify a revocation JWS — signature, CID, payload schema, signer match
|
|
334
|
+
*
|
|
335
|
+
* The revocation's own `createdAt` is the basis: a committed statement resolves
|
|
336
|
+
* its signer in the state that held when it was signed (PROTOCOL, Time basis).
|
|
302
337
|
*/
|
|
303
338
|
declare const verifyRevocation: (input: {
|
|
304
339
|
jwsToken: string;
|
|
305
|
-
|
|
340
|
+
/** Resolve a kid to key bytes in the signer's state as of `basis`. */
|
|
341
|
+
resolveKey: (kid: string, basis?: string) => Promise<Uint8Array>;
|
|
306
342
|
}) => Promise<VerifiedRevocation>;
|
|
307
343
|
|
|
308
344
|
interface VerifiedCreditClaim {
|
|
@@ -322,7 +358,7 @@ interface VerifiedCreditClaim {
|
|
|
322
358
|
claimCID: string;
|
|
323
359
|
}
|
|
324
360
|
/**
|
|
325
|
-
* The four states a `credits[]` entry resolves to (see `specs/
|
|
361
|
+
* The four states a `credits[]` entry resolves to (see `specs/CONTENT-MODEL.md`).
|
|
326
362
|
*
|
|
327
363
|
* `invalid` and `unverifiable` are deliberately distinct and MUST NOT be
|
|
328
364
|
* collapsed: `invalid` means "checked and failed" (a positive signal that
|
package/dist/chain/index.js
CHANGED
|
@@ -52,8 +52,8 @@ import {
|
|
|
52
52
|
verifyIdentityExtensionFromTrustedState,
|
|
53
53
|
verifyRevocation,
|
|
54
54
|
verifySignRequest
|
|
55
|
-
} from "../chunk-
|
|
56
|
-
import "../chunk-
|
|
55
|
+
} from "../chunk-LMAPBTDW.js";
|
|
56
|
+
import "../chunk-T2YR5KWQ.js";
|
|
57
57
|
import "../chunk-JVSC67DC.js";
|
|
58
58
|
import {
|
|
59
59
|
ED25519_PRIV_MULTICODEC,
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
matchesResource,
|
|
7
7
|
verifyDFOSCredential,
|
|
8
8
|
verifyDelegationChain
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-T2YR5KWQ.js";
|
|
10
10
|
import {
|
|
11
11
|
KEY_ADD_JWS_TYP,
|
|
12
12
|
KEY_ROLES,
|
|
@@ -102,7 +102,7 @@ var IdentityUpdate = z.looseObject({
|
|
|
102
102
|
createdAt: Iso8601,
|
|
103
103
|
/**
|
|
104
104
|
* POSSESSION PROOFS FOR THE KEYS THIS OPERATION INTRODUCES — compact key-proof
|
|
105
|
-
* JWS strings (specs/
|
|
105
|
+
* JWS strings (specs/PROTOCOL.md § Key possession), each signed by the key it speaks for.
|
|
106
106
|
*
|
|
107
107
|
* Optional, and optional in the CID-neutral sense: omitting it encodes
|
|
108
108
|
* identically to an operation that never had it (undefined strips under
|
|
@@ -188,7 +188,31 @@ var VerifiedIdentity = z.strictObject({
|
|
|
188
188
|
* re-deriving it from the raw log under a declared-state rule that quietly
|
|
189
189
|
* disagrees with this one.
|
|
190
190
|
*/
|
|
191
|
-
provedKeys: DeclaredKeyState.optional()
|
|
191
|
+
provedKeys: DeclaredKeyState.optional(),
|
|
192
|
+
/**
|
|
193
|
+
* HAS-EVER-BEEN-DECLARED, as a key-id-to-material binding: one entry per key
|
|
194
|
+
* id the chain has ever written, carrying the Multikey that id went in with,
|
|
195
|
+
* in the order the walk first saw it.
|
|
196
|
+
*
|
|
197
|
+
* A KEY ID IS BOUND TO ONE KEY FOR THE LIFE OF A CHAIN. The full walk enforces
|
|
198
|
+
* that chain-wide and rejects the operation that breaks it — the id is a
|
|
199
|
+
* stable name, so re-pointing it at new material would silently re-aim every
|
|
200
|
+
* artifact that ever referenced it. The incremental extension verifier has no
|
|
201
|
+
* log to re-scan, so it needs the binding handed to it, and this member is how
|
|
202
|
+
* it arrives: with it, the fast path returns the SAME verdict as a full replay
|
|
203
|
+
* on the same operation, which is the property that keeps a relay's linear
|
|
204
|
+
* path from accepting a chain its own re-verification would refuse.
|
|
205
|
+
*
|
|
206
|
+
* Broader than `declared` and than `provedKeys` on purpose. The rule covers
|
|
207
|
+
* every id the chain wrote, including one declared into a void membership and
|
|
208
|
+
* later dropped — neither of the other two members remembers that id, and it
|
|
209
|
+
* is exactly the id an attacker would reuse.
|
|
210
|
+
*
|
|
211
|
+
* Optional because a caller may hand the extension verifier a hand-built or
|
|
212
|
+
* older state. Absent, the binding is read off `declared` and `provedKeys`,
|
|
213
|
+
* which is complete for any chain that never dropped an unproved key id.
|
|
214
|
+
*/
|
|
215
|
+
seenKeys: z.array(MultikeyPublicKey).optional()
|
|
192
216
|
});
|
|
193
217
|
var ContentCreate = z.looseObject({
|
|
194
218
|
version: z.literal(1),
|
|
@@ -333,7 +357,9 @@ var unionProved = (into, next) => {
|
|
|
333
357
|
return merged;
|
|
334
358
|
};
|
|
335
359
|
var foldEffectiveKeyState = (input) => {
|
|
336
|
-
const carried = (role, key) => input.priorEffective[ROLE_ARRAY[role]].some(
|
|
360
|
+
const carried = (role, key) => input.priorEffective[ROLE_ARRAY[role]].some(
|
|
361
|
+
(prior) => prior.id === key.id && prior.type === key.type && prior.publicKeyMultibase === key.publicKeyMultibase
|
|
362
|
+
);
|
|
337
363
|
const introduced = /* @__PURE__ */ new Map();
|
|
338
364
|
for (const role of KEY_ROLES) {
|
|
339
365
|
for (const key of input.declared[ROLE_ARRAY[role]]) {
|
|
@@ -379,6 +405,26 @@ var foldEffectiveKeyState = (input) => {
|
|
|
379
405
|
}
|
|
380
406
|
return { effective, voidKeys };
|
|
381
407
|
};
|
|
408
|
+
var admitKeyMaterial = (index, keys) => {
|
|
409
|
+
for (const key of keys) {
|
|
410
|
+
const existing = index.get(key.id);
|
|
411
|
+
if (!existing) {
|
|
412
|
+
index.set(key.id, key);
|
|
413
|
+
} else if (existing.publicKeyMultibase !== key.publicKeyMultibase || existing.type !== key.type) {
|
|
414
|
+
throw new Error(`key ${key.id} type or public key inconsistency`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
var keyMaterialIndex = (keys) => {
|
|
419
|
+
const index = /* @__PURE__ */ new Map();
|
|
420
|
+
for (const key of keys) if (!index.has(key.id)) index.set(key.id, key);
|
|
421
|
+
return index;
|
|
422
|
+
};
|
|
423
|
+
var flatKeys = (state) => [
|
|
424
|
+
...state.authKeys,
|
|
425
|
+
...state.assertKeys,
|
|
426
|
+
...state.controllerKeys
|
|
427
|
+
];
|
|
382
428
|
var assertSingleKeyGenesis = (op) => {
|
|
383
429
|
if (op.authKeys.length !== 1 || op.assertKeys.length !== 1 || op.controllerKeys.length !== 1) {
|
|
384
430
|
throw new Error("create must declare exactly one key in each of auth, assert and controller");
|
|
@@ -407,6 +453,7 @@ var signIdentityOperation = async (input) => {
|
|
|
407
453
|
};
|
|
408
454
|
var verifyIdentityChain = async (input) => {
|
|
409
455
|
if (input.log.length === 0) throw new Error("log must have at least one operation");
|
|
456
|
+
if (input.asOf === "") throw new Error("basis must not be empty");
|
|
410
457
|
const state = {
|
|
411
458
|
did: void 0,
|
|
412
459
|
isDeleted: false,
|
|
@@ -422,6 +469,7 @@ var verifyIdentityChain = async (input) => {
|
|
|
422
469
|
services: [],
|
|
423
470
|
seenKeys: /* @__PURE__ */ new Map()
|
|
424
471
|
};
|
|
472
|
+
let asOfState;
|
|
425
473
|
for (const [idx, jwsToken] of input.log.entries()) {
|
|
426
474
|
const decoded = decodeJwsUnsafe(jwsToken);
|
|
427
475
|
if (!decoded) throw new Error(`log[${idx}]: failed to decode JWS`);
|
|
@@ -472,19 +520,15 @@ var verifyIdentityChain = async (input) => {
|
|
|
472
520
|
}
|
|
473
521
|
}
|
|
474
522
|
if (op.type === "create" || op.type === "update") {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
state.seenKeys.set(k.id, k);
|
|
485
|
-
} else if (existing.publicKeyMultibase !== k.publicKeyMultibase || existing.type !== k.type) {
|
|
486
|
-
throw new Error(`log[${idx}]: key ${k.id} type or public key inconsistency`);
|
|
487
|
-
}
|
|
523
|
+
try {
|
|
524
|
+
admitKeyMaterial(state.seenKeys, [
|
|
525
|
+
...flatKeys(state.declared),
|
|
526
|
+
...op.authKeys,
|
|
527
|
+
...op.assertKeys,
|
|
528
|
+
...op.controllerKeys
|
|
529
|
+
]);
|
|
530
|
+
} catch (e) {
|
|
531
|
+
throw new Error(`log[${idx}]: ${e.message}`);
|
|
488
532
|
}
|
|
489
533
|
[op.authKeys, op.assertKeys, op.controllerKeys].forEach((keys) => {
|
|
490
534
|
const set = new Set(keys.map((k) => k.id));
|
|
@@ -578,8 +622,26 @@ var verifyIdentityChain = async (input) => {
|
|
|
578
622
|
state.isDeleted = false;
|
|
579
623
|
break;
|
|
580
624
|
}
|
|
625
|
+
if (input.asOf !== void 0 && op.createdAt <= input.asOf) {
|
|
626
|
+
asOfState = {
|
|
627
|
+
did,
|
|
628
|
+
isDeleted: state.isDeleted,
|
|
629
|
+
authKeys: state.effective.authKeys,
|
|
630
|
+
assertKeys: state.effective.assertKeys,
|
|
631
|
+
controllerKeys: state.effective.controllerKeys,
|
|
632
|
+
services: state.services,
|
|
633
|
+
declared: state.declared,
|
|
634
|
+
voidKeys: state.voidKeys,
|
|
635
|
+
provedKeys: state.provedKeys,
|
|
636
|
+
seenKeys: [...state.seenKeys.values()]
|
|
637
|
+
};
|
|
638
|
+
}
|
|
581
639
|
}
|
|
582
640
|
if (!state.did) throw new Error("did is not set");
|
|
641
|
+
if (input.asOf !== void 0) {
|
|
642
|
+
if (!asOfState) throw new Error(`identity has no state as of ${input.asOf}`);
|
|
643
|
+
return asOfState;
|
|
644
|
+
}
|
|
583
645
|
return {
|
|
584
646
|
did: state.did,
|
|
585
647
|
isDeleted: state.isDeleted,
|
|
@@ -590,7 +652,10 @@ var verifyIdentityChain = async (input) => {
|
|
|
590
652
|
services: state.services,
|
|
591
653
|
declared: state.declared,
|
|
592
654
|
voidKeys: state.voidKeys,
|
|
593
|
-
provedKeys: state.provedKeys
|
|
655
|
+
provedKeys: state.provedKeys,
|
|
656
|
+
// The id-to-material binding the walk enforced, handed on so an incremental
|
|
657
|
+
// extension of this state can enforce the identical rule without the log.
|
|
658
|
+
seenKeys: [...state.seenKeys.values()]
|
|
594
659
|
};
|
|
595
660
|
};
|
|
596
661
|
var verifyIdentityExtensionFromTrustedState = async (input) => {
|
|
@@ -598,6 +663,10 @@ var verifyIdentityExtensionFromTrustedState = async (input) => {
|
|
|
598
663
|
const priorEffective = keyStateOf(currentState);
|
|
599
664
|
const priorDeclared = currentState.declared ?? priorEffective;
|
|
600
665
|
const priorProved = currentState.provedKeys ?? priorEffective;
|
|
666
|
+
const seenKeys = keyMaterialIndex(
|
|
667
|
+
currentState.seenKeys ?? [...flatKeys(priorDeclared), ...flatKeys(priorProved)]
|
|
668
|
+
);
|
|
669
|
+
const priorSeenKeys = [...seenKeys.values()];
|
|
601
670
|
const decoded = decodeJwsUnsafe(newOp);
|
|
602
671
|
if (!decoded) throw new Error("failed to decode JWS");
|
|
603
672
|
const result = IdentityOperation.safeParse(decoded.payload);
|
|
@@ -653,6 +722,7 @@ var verifyIdentityExtensionFromTrustedState = async (input) => {
|
|
|
653
722
|
throw new Error("invalid signature");
|
|
654
723
|
}
|
|
655
724
|
if (op.type === "update") {
|
|
725
|
+
admitKeyMaterial(seenKeys, [...op.authKeys, ...op.assertKeys, ...op.controllerKeys]);
|
|
656
726
|
[op.authKeys, op.assertKeys, op.controllerKeys].forEach((keys) => {
|
|
657
727
|
const set = new Set(keys.map((k) => k.id));
|
|
658
728
|
if (set.size !== keys.length) {
|
|
@@ -682,7 +752,8 @@ var verifyIdentityExtensionFromTrustedState = async (input) => {
|
|
|
682
752
|
services: op.services ?? [],
|
|
683
753
|
declared,
|
|
684
754
|
voidKeys: folded.voidKeys,
|
|
685
|
-
provedKeys: unionProved(priorProved, folded.effective)
|
|
755
|
+
provedKeys: unionProved(priorProved, folded.effective),
|
|
756
|
+
seenKeys: [...seenKeys.values()]
|
|
686
757
|
};
|
|
687
758
|
}
|
|
688
759
|
// delete and restore introduce nothing, so both key states — and the void
|
|
@@ -697,7 +768,8 @@ var verifyIdentityExtensionFromTrustedState = async (input) => {
|
|
|
697
768
|
services: currentState.services,
|
|
698
769
|
declared: priorDeclared,
|
|
699
770
|
voidKeys: currentState.voidKeys ?? [],
|
|
700
|
-
provedKeys: priorProved
|
|
771
|
+
provedKeys: priorProved,
|
|
772
|
+
seenKeys: priorSeenKeys
|
|
701
773
|
};
|
|
702
774
|
case "restore":
|
|
703
775
|
return {
|
|
@@ -709,7 +781,8 @@ var verifyIdentityExtensionFromTrustedState = async (input) => {
|
|
|
709
781
|
services: currentState.services,
|
|
710
782
|
declared: priorDeclared,
|
|
711
783
|
voidKeys: currentState.voidKeys ?? [],
|
|
712
|
-
provedKeys: priorProved
|
|
784
|
+
provedKeys: priorProved,
|
|
785
|
+
seenKeys: priorSeenKeys
|
|
713
786
|
};
|
|
714
787
|
}
|
|
715
788
|
})();
|
|
@@ -750,7 +823,7 @@ var verifyOperationAuthorization = async (input) => {
|
|
|
750
823
|
const opCreatedAtUnix = Math.floor(new Date(input.createdAt).getTime() / 1e3);
|
|
751
824
|
const credential = await verifyDFOSCredential(input.authorization, {
|
|
752
825
|
resolveIdentity: input.resolveIdentity,
|
|
753
|
-
|
|
826
|
+
basis: input.createdAt
|
|
754
827
|
});
|
|
755
828
|
if (input.isRevoked && await input.isRevoked(credential.iss, credential.credentialCID, opCreatedAtUnix)) {
|
|
756
829
|
throw new Error("credential is revoked");
|
|
@@ -758,8 +831,8 @@ var verifyOperationAuthorization = async (input) => {
|
|
|
758
831
|
await verifyDelegationChain(credential, {
|
|
759
832
|
resolveIdentity: input.resolveIdentity,
|
|
760
833
|
rootDID: input.creatorDID,
|
|
761
|
-
|
|
762
|
-
...input.isRevoked ? { isRevoked: input.isRevoked
|
|
834
|
+
basis: input.createdAt,
|
|
835
|
+
...input.isRevoked ? { isRevoked: input.isRevoked } : {}
|
|
763
836
|
});
|
|
764
837
|
if (credential.aud !== "*" && credential.aud !== input.operationDID) {
|
|
765
838
|
throw new Error(
|
|
@@ -821,7 +894,7 @@ var verifyContentChain = async (input) => {
|
|
|
821
894
|
if (kidDid !== op.did) {
|
|
822
895
|
throw new Error(`log[${idx}]: kid DID does not match operation did`);
|
|
823
896
|
}
|
|
824
|
-
const publicKey = await input.resolveKey(kid);
|
|
897
|
+
const publicKey = await input.resolveKey(kid, op.createdAt);
|
|
825
898
|
try {
|
|
826
899
|
verifyJws({ token: jwsToken, publicKey });
|
|
827
900
|
} catch {
|
|
@@ -931,7 +1004,7 @@ var verifyContentExtensionFromTrustedState = async (input) => {
|
|
|
931
1004
|
if (kidDid !== op.did) {
|
|
932
1005
|
throw new Error("kid DID does not match operation did");
|
|
933
1006
|
}
|
|
934
|
-
const publicKey = await resolveKey(kid);
|
|
1007
|
+
const publicKey = await resolveKey(kid, op.createdAt);
|
|
935
1008
|
try {
|
|
936
1009
|
verifyJws({ token: newOp, publicKey });
|
|
937
1010
|
} catch {
|
|
@@ -1009,7 +1082,7 @@ var verifyCountersignature = async (input) => {
|
|
|
1009
1082
|
if (kidDid !== payload.did) {
|
|
1010
1083
|
throw new Error("countersignature kid DID does not match payload did");
|
|
1011
1084
|
}
|
|
1012
|
-
const publicKey = await input.resolveKey(kid);
|
|
1085
|
+
const publicKey = await input.resolveKey(kid, payload.createdAt);
|
|
1013
1086
|
try {
|
|
1014
1087
|
verifyJws({ token: input.jwsToken, publicKey });
|
|
1015
1088
|
} catch {
|
|
@@ -1062,7 +1135,7 @@ var verifyArtifact = async (input) => {
|
|
|
1062
1135
|
if (kidDid !== payload.did) {
|
|
1063
1136
|
throw new Error("artifact kid DID does not match payload did");
|
|
1064
1137
|
}
|
|
1065
|
-
const publicKey = await input.resolveKey(kid);
|
|
1138
|
+
const publicKey = await input.resolveKey(kid, payload.createdAt);
|
|
1066
1139
|
try {
|
|
1067
1140
|
verifyJws({ token: input.jwsToken, publicKey });
|
|
1068
1141
|
} catch {
|
|
@@ -1119,7 +1192,7 @@ var verifyRevocation = async (input) => {
|
|
|
1119
1192
|
if (kidDid !== payload.did) {
|
|
1120
1193
|
throw new Error("revocation kid DID does not match payload did");
|
|
1121
1194
|
}
|
|
1122
|
-
const publicKey = await input.resolveKey(kid);
|
|
1195
|
+
const publicKey = await input.resolveKey(kid, payload.createdAt);
|
|
1123
1196
|
try {
|
|
1124
1197
|
verifyJws({ token: input.jwsToken, publicKey });
|
|
1125
1198
|
} catch {
|
|
@@ -370,20 +370,26 @@ var isDependencyMissing = (err) => err instanceof Error && err.dependencyMissing
|
|
|
370
370
|
var carryDependencyMissing = (cause, wrapped) => isDependencyMissing(cause) ? markDependencyMissing(wrapped) : wrapped;
|
|
371
371
|
|
|
372
372
|
// src/credentials/dfos-credential.ts
|
|
373
|
-
var resolveKeyFromIdentity = (identity, kid) => {
|
|
373
|
+
var resolveKeyFromIdentity = (identity, kid, determinate) => {
|
|
374
374
|
const hashIdx = kid.indexOf("#");
|
|
375
375
|
if (hashIdx < 0) throw new CredentialVerificationError("kid must be a DID URL");
|
|
376
376
|
const keyId = kid.substring(hashIdx + 1);
|
|
377
377
|
const allKeys = [...identity.authKeys, ...identity.assertKeys, ...identity.controllerKeys];
|
|
378
378
|
const key = allKeys.find((k) => k.id === keyId);
|
|
379
379
|
if (!key) {
|
|
380
|
-
|
|
381
|
-
|
|
380
|
+
const miss = new CredentialVerificationError(
|
|
381
|
+
`unknown key ${keyId} on identity ${identity.did}`
|
|
382
382
|
);
|
|
383
|
+
throw determinate ? miss : markDependencyMissing(miss);
|
|
383
384
|
}
|
|
384
385
|
const { keyBytes } = decodeMultikey(key.publicKeyMultibase);
|
|
385
386
|
return keyBytes;
|
|
386
387
|
};
|
|
388
|
+
var basisUnixSeconds = (basis) => {
|
|
389
|
+
const ms = Date.parse(basis);
|
|
390
|
+
if (Number.isNaN(ms)) throw new CredentialVerificationError(`invalid basis time: ${basis}`);
|
|
391
|
+
return Math.floor(ms / 1e3);
|
|
392
|
+
};
|
|
387
393
|
var createDFOSCredential = async (options) => {
|
|
388
394
|
const kid = `${options.issuerDID}#${options.keyId}`;
|
|
389
395
|
const now = options.iat ?? Math.floor(Date.now() / 1e3);
|
|
@@ -435,7 +441,7 @@ var verifyDFOSCredential = async (jwsToken, options) => {
|
|
|
435
441
|
if (kidDid !== payload.iss) {
|
|
436
442
|
throw new CredentialVerificationError("credential kid DID does not match iss");
|
|
437
443
|
}
|
|
438
|
-
const identity = await options.resolveIdentity(payload.iss);
|
|
444
|
+
const identity = await options.resolveIdentity(payload.iss, options.basis);
|
|
439
445
|
if (!identity) {
|
|
440
446
|
throw markDependencyMissing(
|
|
441
447
|
new CredentialVerificationError(`issuer identity not found: ${payload.iss}`)
|
|
@@ -444,7 +450,7 @@ var verifyDFOSCredential = async (jwsToken, options) => {
|
|
|
444
450
|
if (identity.isDeleted) {
|
|
445
451
|
throw new CredentialVerificationError(`issuer identity is deleted: ${payload.iss}`);
|
|
446
452
|
}
|
|
447
|
-
const publicKey = resolveKeyFromIdentity(identity, kid);
|
|
453
|
+
const publicKey = resolveKeyFromIdentity(identity, kid, identity.basisDeterminate === true);
|
|
448
454
|
try {
|
|
449
455
|
verifyJws({ token: jwsToken, publicKey });
|
|
450
456
|
} catch {
|
|
@@ -458,11 +464,8 @@ var verifyDFOSCredential = async (jwsToken, options) => {
|
|
|
458
464
|
if (decoded.header.cid !== credentialCID) {
|
|
459
465
|
throw new CredentialVerificationError("credential cid mismatch");
|
|
460
466
|
}
|
|
461
|
-
const
|
|
462
|
-
if (payload.
|
|
463
|
-
throw new CredentialVerificationError("credential not yet valid (iat is in the future)");
|
|
464
|
-
}
|
|
465
|
-
if (payload.exp <= now) {
|
|
467
|
+
const basisSeconds = options.basis !== void 0 ? basisUnixSeconds(options.basis) : options.nowUnix ?? Math.floor(Date.now() / 1e3);
|
|
468
|
+
if (payload.exp <= basisSeconds) {
|
|
466
469
|
throw new CredentialVerificationError("credential expired");
|
|
467
470
|
}
|
|
468
471
|
return {
|
|
@@ -478,6 +481,7 @@ var verifyDFOSCredential = async (jwsToken, options) => {
|
|
|
478
481
|
};
|
|
479
482
|
var verifyDelegationChain = async (credential, options) => {
|
|
480
483
|
const chain = [credential];
|
|
484
|
+
const revocationBasis = options.basis !== void 0 ? basisUnixSeconds(options.basis) : void 0;
|
|
481
485
|
let current = credential;
|
|
482
486
|
const maxDepth = 16;
|
|
483
487
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
@@ -496,10 +500,11 @@ var verifyDelegationChain = async (credential, options) => {
|
|
|
496
500
|
}
|
|
497
501
|
const parent = await verifyDFOSCredential(current.prf[0], {
|
|
498
502
|
resolveIdentity: options.resolveIdentity,
|
|
499
|
-
...options.
|
|
503
|
+
...options.basis !== void 0 ? { basis: options.basis } : {},
|
|
504
|
+
...options.nowUnix !== void 0 ? { nowUnix: options.nowUnix } : {}
|
|
500
505
|
});
|
|
501
506
|
if (options.isRevoked) {
|
|
502
|
-
const revoked = await options.isRevoked(parent.iss, parent.credentialCID,
|
|
507
|
+
const revoked = await options.isRevoked(parent.iss, parent.credentialCID, revocationBasis);
|
|
503
508
|
if (revoked) {
|
|
504
509
|
throw new CredentialVerificationError("parent credential in delegation chain is revoked");
|
|
505
510
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { b as Attenuation, e as CredentialVerificationError, D as DFOSCredentialPayload, i as MAX_CREDENTIAL_SIZE, R as RevocationChecker, V as VerifiedDFOSCredential,
|
|
1
|
+
export { b as Attenuation, e as CredentialVerificationError, D as DFOSCredentialPayload, i as MAX_CREDENTIAL_SIZE, R as ResolvedIdentity, r as RevocationChecker, V as VerifiedDFOSCredential, w as VerifiedDelegationChain, z as createDFOSCredential, B as decodeDFOSCredentialUnsafe, E as isAttenuated, F as matchesResource, H as verifyDFOSCredential, J as verifyDelegationChain } from '../dfos-credential-CtG0_n4P.js';
|
|
2
2
|
import 'zod';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -294,6 +294,11 @@ declare const VerifiedIdentity: z.ZodObject<{
|
|
|
294
294
|
publicKeyMultibase: z.ZodString;
|
|
295
295
|
}, z.core.$loose>>;
|
|
296
296
|
}, z.core.$strict>>;
|
|
297
|
+
seenKeys: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
298
|
+
id: z.ZodString;
|
|
299
|
+
type: z.ZodLiteral<"Multikey">;
|
|
300
|
+
publicKeyMultibase: z.ZodString;
|
|
301
|
+
}, z.core.$loose>>>;
|
|
297
302
|
}, z.core.$strict>;
|
|
298
303
|
type VerifiedIdentity = z.infer<typeof VerifiedIdentity>;
|
|
299
304
|
declare const ContentOperation: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -377,7 +382,7 @@ declare const MAX_CREDIT_CLAIM_SIZE = 4096;
|
|
|
377
382
|
* Credit claim: a claimant's signed assertion that it holds a named role on a
|
|
378
383
|
* content chain. A document-plane artifact — it is NOT gossiped and relays are not
|
|
379
384
|
* credit-claim aware; a claim travels inside the document bytes that embed it (see
|
|
380
|
-
* `specs/
|
|
385
|
+
* `specs/CONTENT-MODEL.md`).
|
|
381
386
|
*
|
|
382
387
|
* `contentId` is the binder — the STABLE 31-char content chain id, never a
|
|
383
388
|
* documentCID or a chain head CID. Binding to the chain (not a document) is what
|
|
@@ -500,6 +505,24 @@ interface VerifiedDFOSCredential {
|
|
|
500
505
|
/** kid from the JWS header */
|
|
501
506
|
signerKeyId: string;
|
|
502
507
|
}
|
|
508
|
+
/**
|
|
509
|
+
* The identity a resolver answers with, plus the one fact about that answer only
|
|
510
|
+
* the resolver knows: whether it is FINAL for the basis it was asked about.
|
|
511
|
+
*
|
|
512
|
+
* A resolver whose copy of the chain runs past the basis answers determinately,
|
|
513
|
+
* and a key missing from that state is a verdict. A resolver answering from a
|
|
514
|
+
* copy that ends at or before the basis does not: an operation dated at or
|
|
515
|
+
* before the basis can still arrive and add the key, so the miss is a dependency
|
|
516
|
+
* miss the caller retries. Absent is the retryable reading, which is the safe
|
|
517
|
+
* default: only a resolver that can say its answer is final gets a verdict.
|
|
518
|
+
*/
|
|
519
|
+
type ResolvedIdentity = VerifiedIdentity & {
|
|
520
|
+
/**
|
|
521
|
+
* True when no operation dated at or before the basis can still arrive and
|
|
522
|
+
* change this key state.
|
|
523
|
+
*/
|
|
524
|
+
basisDeterminate?: boolean;
|
|
525
|
+
};
|
|
503
526
|
interface VerifiedDelegationChain {
|
|
504
527
|
/** The leaf credential */
|
|
505
528
|
credential: VerifiedDFOSCredential;
|
|
@@ -512,8 +535,8 @@ interface VerifiedDelegationChain {
|
|
|
512
535
|
* Check whether a credential (leaf or any parent) has been revoked.
|
|
513
536
|
*
|
|
514
537
|
* `asOfUnix` selects WHICH question is being asked, and the two are different
|
|
515
|
-
* decisions: **acceptance is a freshness decision; verification
|
|
516
|
-
*
|
|
538
|
+
* decisions: **acceptance is a freshness decision; verification at a basis is a
|
|
539
|
+
* validity decision.**
|
|
517
540
|
*
|
|
518
541
|
* - **Omitted, or `<= 0` (timeless)** — "is this credential revoked as far as you
|
|
519
542
|
* know right now?". The freshness question. Used by acceptance gates: relay
|
|
@@ -524,10 +547,10 @@ interface VerifiedDelegationChain {
|
|
|
524
547
|
* 1970) therefore gets the stricter answer in both languages.
|
|
525
548
|
* - **Positive (as-of)** — "was this credential already revoked at `asOfUnix`?".
|
|
526
549
|
* The validity question. Return true only if a revocation exists AND its
|
|
527
|
-
* signed `createdAt` is ≤ `asOfUnix`. Used when verifying
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
550
|
+
* signed `createdAt` is ≤ `asOfUnix`. Used when verifying an artifact against
|
|
551
|
+
* a basis, where `asOfUnix` is the basis in integer Unix seconds. A revocation
|
|
552
|
+
* signed AFTER the basis does not invalidate the artifact — see CREDENTIALS.md
|
|
553
|
+
* "Revocation against the basis".
|
|
531
554
|
*
|
|
532
555
|
* An implementation that ignores `asOfUnix` degrades to the timeless answer,
|
|
533
556
|
* which is always the stricter (safe) direction — it can only reject history
|
|
@@ -559,13 +582,35 @@ declare const createDFOSCredential: (options: {
|
|
|
559
582
|
/**
|
|
560
583
|
* Verify a DFOS credential — signature, schema, expiry, CID integrity
|
|
561
584
|
*
|
|
585
|
+
* Every check runs against ONE basis time (PROTOCOL, Time basis): the issuer's
|
|
586
|
+
* key must be effective in the identity's state as of the basis, and `exp` must
|
|
587
|
+
* be strictly greater than the basis in integer Unix seconds. `iat` is
|
|
588
|
+
* informational and gates nothing.
|
|
589
|
+
*
|
|
562
590
|
* Does NOT verify the delegation chain. Use `verifyDelegationChain` for full
|
|
563
591
|
* chain verification including attenuation enforcement.
|
|
564
592
|
*/
|
|
565
593
|
declare const verifyDFOSCredential: (jwsToken: string, options: {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
594
|
+
/**
|
|
595
|
+
* Resolve a DID to its verified identity state AS OF `basis`. Called with
|
|
596
|
+
* the basis this verification runs at, or with none when the presentation is
|
|
597
|
+
* ephemeral and the answer is head state. A resolver that knows its answer
|
|
598
|
+
* is final for the basis says so on the result (`ResolvedIdentity`).
|
|
599
|
+
*/
|
|
600
|
+
resolveIdentity: (did: string, basis?: string) => Promise<ResolvedIdentity | undefined>;
|
|
601
|
+
/**
|
|
602
|
+
* The basis time, in the `createdAt` grammar — the operation's own
|
|
603
|
+
* `createdAt` for a credential carried inline in a committed operation.
|
|
604
|
+
* Omitted for an ephemeral presentation, where the basis is now.
|
|
605
|
+
*/
|
|
606
|
+
basis?: string;
|
|
607
|
+
/**
|
|
608
|
+
* The ephemeral clock in integer Unix seconds, for a caller that carries its
|
|
609
|
+
* own. It reaches `exp` and nothing else: key resolution on the ephemeral
|
|
610
|
+
* path is head state, which is what "the basis is now" means. Ignored when
|
|
611
|
+
* `basis` is present, and defaults to `floor(Date.now() / 1000)`.
|
|
612
|
+
*/
|
|
613
|
+
nowUnix?: number;
|
|
569
614
|
}) => Promise<VerifiedDFOSCredential>;
|
|
570
615
|
/**
|
|
571
616
|
* Verify a full delegation chain — walk `prf`, confirm monotonic attenuation,
|
|
@@ -578,23 +623,29 @@ declare const verifyDFOSCredential: (jwsToken: string, options: {
|
|
|
578
623
|
*
|
|
579
624
|
* The chain terminates when a credential has `prf: []` (root credential). The
|
|
580
625
|
* root credential's `iss` must equal `rootDID`.
|
|
626
|
+
*
|
|
627
|
+
* ONE BASIS FOR THE WHOLE WALK. Every hop — each parent's signing key, each
|
|
628
|
+
* `exp`, each revocation — resolves against the same basis the leaf did, so a
|
|
629
|
+
* chain either held at that instant or it did not.
|
|
581
630
|
*/
|
|
582
631
|
declare const verifyDelegationChain: (credential: VerifiedDFOSCredential, options: {
|
|
583
|
-
|
|
632
|
+
/** Resolve a DID to its verified identity state as of `basis`. */
|
|
633
|
+
resolveIdentity: (did: string, basis?: string) => Promise<ResolvedIdentity | undefined>;
|
|
584
634
|
/** The expected root authority DID (e.g., content chain creator) */
|
|
585
635
|
rootDID: string;
|
|
586
|
-
/** Current time in seconds (defaults to Date.now() / 1000) */
|
|
587
|
-
now?: number;
|
|
588
636
|
/** Check if a credential has been revoked (checked at every level of the chain) */
|
|
589
637
|
isRevoked?: RevocationChecker;
|
|
590
638
|
/**
|
|
591
|
-
*
|
|
592
|
-
* `
|
|
593
|
-
*
|
|
594
|
-
|
|
595
|
-
|
|
639
|
+
* The basis time, in the `createdAt` grammar. Omitted for an ephemeral
|
|
640
|
+
* presentation: `exp` runs against the wall clock and revocation is asked
|
|
641
|
+
* timelessly, which is the stricter direction (see `RevocationChecker`).
|
|
642
|
+
*/
|
|
643
|
+
basis?: string;
|
|
644
|
+
/**
|
|
645
|
+
* The ephemeral clock in integer Unix seconds, threaded to every hop's `exp`
|
|
646
|
+
* and nothing else. Ignored when `basis` is present.
|
|
596
647
|
*/
|
|
597
|
-
|
|
648
|
+
nowUnix?: number;
|
|
598
649
|
}) => Promise<VerifiedDelegationChain>;
|
|
599
650
|
/**
|
|
600
651
|
* Check if `childAtt` is a valid attenuation of `parentAtt`
|
|
@@ -639,4 +690,4 @@ declare class CredentialVerificationError extends Error {
|
|
|
639
690
|
constructor(message: string);
|
|
640
691
|
}
|
|
641
692
|
|
|
642
|
-
export { ARTIFACT_CID_ANCHOR_RE as A,
|
|
693
|
+
export { ARTIFACT_CID_ANCHOR_RE as A, decodeDFOSCredentialUnsafe as B, CONTENT_ID_ANCHOR_RE as C, DFOSCredentialPayload as D, isAttenuated as E, matchesResource as F, parseProtocolTimestampUnix as G, verifyDFOSCredential as H, IdentityOperation as I, verifyDelegationChain as J, MAX_ARTIFACT_PAYLOAD_SIZE as M, type ResolvedIdentity as R, ServiceEntry as S, type VerifiedDFOSCredential as V, ArtifactPayload as a, Attenuation as b, ContentOperation as c, CountersignPayload as d, CredentialVerificationError as e, CreditClaimPayload as f, DeclaredKeyState as g, Iso8601 as h, MAX_CREDENTIAL_SIZE as i, MAX_CREDIT_CLAIM_SIZE as j, MAX_KEY_PROOFS as k, MAX_OPERATION_SIZE as l, MAX_SERVICES_ENTRIES as m, MAX_SERVICES_PAYLOAD_SIZE as n, MAX_SIGN_REQUEST_PAYLOAD_SIZE as o, MAX_SIGN_REQUEST_SIZE as p, MultikeyPublicKey as q, type RevocationChecker as r, RevocationPayload as s, ServicesArray as t, SignRequestPayload as u, type Signer as v, type VerifiedDelegationChain as w, VerifiedIdentity as x, VoidKeyMembership as y, createDFOSCredential as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { JwsHeader, JwsVerificationError, JwtClaims, JwtCreateOptions, JwtHeader, JwtVerificationError, JwtVerifyOptions, PrefixedID, assertJwsProfile, base64urlDecode, base64urlEncode, createJws, createJwt, createNewEd25519Keypair, dagCborCanonicalEncode, decodeJwsUnsafe, decodeJwtUnsafe, generateId, generateIdNoPrefix, importEd25519Keypair, isCanonicallyEqual, isValidEd25519Signature, isValidId, normalizedId, parseDagCborCID, sha256, signPayloadEd25519, verifyJws, verifyJwt } from './crypto/index.js';
|
|
2
|
-
export { A as ARTIFACT_CID_ANCHOR_RE, a as ArtifactPayload, b as Attenuation, C as CONTENT_ID_ANCHOR_RE, c as ContentOperation, d as CountersignPayload, e as CredentialVerificationError, f as CreditClaimPayload, D as DFOSCredentialPayload, g as DeclaredKeyState, I as IdentityOperation, h as Iso8601, M as MAX_ARTIFACT_PAYLOAD_SIZE, i as MAX_CREDENTIAL_SIZE, j as MAX_CREDIT_CLAIM_SIZE, k as MAX_KEY_PROOFS, l as MAX_OPERATION_SIZE, m as MAX_SERVICES_ENTRIES, n as MAX_SERVICES_PAYLOAD_SIZE, o as MAX_SIGN_REQUEST_PAYLOAD_SIZE, p as MAX_SIGN_REQUEST_SIZE, q as MultikeyPublicKey, R as
|
|
2
|
+
export { A as ARTIFACT_CID_ANCHOR_RE, a as ArtifactPayload, b as Attenuation, C as CONTENT_ID_ANCHOR_RE, c as ContentOperation, d as CountersignPayload, e as CredentialVerificationError, f as CreditClaimPayload, D as DFOSCredentialPayload, g as DeclaredKeyState, I as IdentityOperation, h as Iso8601, M as MAX_ARTIFACT_PAYLOAD_SIZE, i as MAX_CREDENTIAL_SIZE, j as MAX_CREDIT_CLAIM_SIZE, k as MAX_KEY_PROOFS, l as MAX_OPERATION_SIZE, m as MAX_SERVICES_ENTRIES, n as MAX_SERVICES_PAYLOAD_SIZE, o as MAX_SIGN_REQUEST_PAYLOAD_SIZE, p as MAX_SIGN_REQUEST_SIZE, q as MultikeyPublicKey, R as ResolvedIdentity, r as RevocationChecker, s as RevocationPayload, S as ServiceEntry, t as ServicesArray, u as SignRequestPayload, v as Signer, V as VerifiedDFOSCredential, w as VerifiedDelegationChain, x as VerifiedIdentity, y as VoidKeyMembership, z as createDFOSCredential, B as decodeDFOSCredentialUnsafe, E as isAttenuated, F as matchesResource, G as parseProtocolTimestampUnix, H as verifyDFOSCredential, J as verifyDelegationChain } from './dfos-credential-CtG0_n4P.js';
|
|
3
3
|
export { AnchorKind, CreditClaimFailureReason, CreditClaimVerifyError, CreditEntry, CreditEntryState, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, RECOGNIZED_SERVICE_TYPES, SignRequestFailureReason, SignRequestVerifyError, VerifiedArtifact, VerifiedContentChain, VerifiedCountersignature, VerifiedCreditClaim, VerifiedCreditEntry, VerifiedRevocation, VerifiedSignRequest, anchorsByLabel, assertCanonicalSignRequestPayload, assertServicesWithinCap, buildSignRequest, classifyAnchor, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, isRecognizedServiceType, relayEndpoints, signArtifact, signContentOperation, signCountersignature, signCreditClaim, signIdentityOperation, signRevocation, verifyArtifact, verifyContentChain, verifyContentExtensionFromTrustedState, verifyCountersignature, verifyCreditClaim, verifyCreditEntry, verifyIdentityChain, verifyIdentityExtensionFromTrustedState, verifyRevocation, verifySignRequest } from './chain/index.js';
|
|
4
4
|
export { ApiRequestVerifyError, DEFAULT_PROOF_SKEW_SECONDS, DEFAULT_PROOF_WINDOW_SECONDS, DFOS_AUTH_SCHEME, EMPTY_BODY_SHA256, IDENTITY_PROOF_JWS_TYP, IdentityProofPayload, MAX_BODY_BYTES, MAX_PROOF_FRESHNESS_SPAN_SECONDS, MAX_REQUEST_PROOF_SIZE, ParsedProofPayload, ProofEnvelopeInput, ProofExtraMembers, ProofPresenterState, REQUEST_PROOF_JWS_TYP, RequestProofFailurePhase, RequestProofFailureReason, RequestProofPayload, ResolveProofPresenter, SignApiIdentityRequestInput, SignApiRequestInput, VerifiedProofEnvelope, apiIdentitySigningInput, apiRequestSigningInput, assertProofVerifierConfig, buildApiAuthHeaders, buildApiIdentityHeaders, canonicalExtraMembers, invalidProof, misconfiguredProof, parseDfosAuthorization, sha256BodyHash, signApiIdentityRequest, signApiRequest, unverifiableProof, verifyIdentityProofEnvelope, verifyRequestProofEnvelope } from './credentials/index.js';
|
|
5
5
|
export { DEFAULT_KEY_PROOF_SKEW_SECONDS, KEY_ADD_JWS_TYP, KEY_ROLES, KeyProofFailureReason, KeyProofPayload, KeyProofVerifyError, KeyRole, MAX_KEY_PROOF_SIZE, SignKeyProofInput, VerifiedKeyProof, VerifyChainKeyProofOptions, VerifyKeyProofOptions, isCanonicalRoleSet, keyProofSigningInput, keyWordFingerprint, parseRoleSet, roleSetCovers, serializeRoleSet, signKeyProof, unsafeKeyProofSubject, verifyChainKeyProof, verifyKeyProof } from './key-proof/index.js';
|
package/dist/index.js
CHANGED
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
verifyIdentityExtensionFromTrustedState,
|
|
53
53
|
verifyRevocation,
|
|
54
54
|
verifySignRequest
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-LMAPBTDW.js";
|
|
56
56
|
import {
|
|
57
57
|
ApiRequestVerifyError,
|
|
58
58
|
Attenuation,
|
|
@@ -92,7 +92,7 @@ import {
|
|
|
92
92
|
verifyDelegationChain,
|
|
93
93
|
verifyIdentityProofEnvelope,
|
|
94
94
|
verifyRequestProofEnvelope
|
|
95
|
-
} from "./chunk-
|
|
95
|
+
} from "./chunk-T2YR5KWQ.js";
|
|
96
96
|
import {
|
|
97
97
|
DEFAULT_KEY_PROOF_SKEW_SECONDS,
|
|
98
98
|
KEY_ADD_JWS_TYP,
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://schemas.dfos.com/credit-claim/v1",
|
|
4
4
|
"title": "Credit Claim",
|
|
5
|
-
"description": "The payload of a did:dfos:credit-claim JWS — a claimant's own signed assertion that it holds a named role on a content chain. Unlike post/v1, profile/v1, and index/v1, this is NOT a document committed to a chain by CID: it is an envelope payload carried inside document bytes, in the claim field of a credits entry (see $defs/creditEntry). Attribution, not authorization — a credit claim grants nothing. Unknown top-level fields are deliberately NOT rejected here (no additionalProperties: false, unlike the document schemas): this is a wire payload under the protocol's MUST-ignore-unknown rule, and the CID commits to the exact bytes, so a verifier that stripped unknown keys would fail its own CID check. Full semantics, the two-way bind, and the four verification states: https://protocol.dfos.com/credits",
|
|
5
|
+
"description": "The payload of a did:dfos:credit-claim JWS — a claimant's own signed assertion that it holds a named role on a content chain. Unlike post/v1, profile/v1, and index/v1, this is NOT a document committed to a chain by CID: it is an envelope payload carried inside document bytes, in the claim field of a credits entry (see $defs/creditEntry). Attribution, not authorization — a credit claim grants nothing. Unknown top-level fields are deliberately NOT rejected here (no additionalProperties: false, unlike the document schemas): this is a wire payload under the protocol's MUST-ignore-unknown rule, and the CID commits to the exact bytes, so a verifier that stripped unknown keys would fail its own CID check. Full semantics, the two-way bind, and the four verification states: https://protocol.dfos.com/content-model#credits",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"required": ["version", "type", "contentId", "did", "role", "createdAt"],
|
|
8
8
|
"properties": {
|
package/schemas/post.v1.json
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"items": {
|
|
44
44
|
"$ref": "#/$defs/credit"
|
|
45
45
|
},
|
|
46
|
-
"description": "Ordered authorship credits. Array order is display order; the first entry is the primary author. Omit entirely for unattributed content. A bare entry is the assertion tier of the authorship lattice — the operation signer asserts it; a credited DID upgrades its credit to proof by adding a credit claim in the entry's claim field (see https://protocol.dfos.com/credits)."
|
|
46
|
+
"description": "Ordered authorship credits. Array order is display order; the first entry is the primary author. Omit entirely for unattributed content. A bare entry is the assertion tier of the authorship lattice — the operation signer asserts it; a credited DID upgrades its credit to proof by adding a credit claim in the entry's claim field (see https://protocol.dfos.com/content-model#credits)."
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
"additionalProperties": false,
|