@metalabel/dfos-protocol 0.50.0 → 0.52.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 +71 -23
- package/dist/chain/index.js +7 -5
- package/dist/{chunk-IDVYITX7.js → chunk-F7RHI2CK.js} +9 -1
- package/dist/{chunk-MHSBBYDO.js → chunk-IV3TIYKP.js} +28 -19
- package/dist/{chunk-JGFFADPR.js → chunk-OU2DPHCN.js} +128 -51
- package/dist/{chunk-JVSC67DC.js → chunk-QRCOMLAP.js} +4 -9
- package/dist/{chunk-4LG2GEB2.js → chunk-QTJZGXMH.js} +140 -25
- package/dist/credentials/index.d.ts +21 -20
- package/dist/credentials/index.js +3 -3
- package/dist/crypto/index.d.ts +23 -1
- package/dist/crypto/index.js +3 -1
- package/dist/{dfos-credential-BtiYPqBT.d.ts → dfos-credential-j-kHtFvG.d.ts} +73 -21
- package/dist/index.d.ts +3 -3
- package/dist/index.js +9 -5
- package/dist/key-proof/index.d.ts +14 -13
- package/dist/key-proof/index.js +3 -3
- 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-j-kHtFvG.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-j-kHtFvG.js';
|
|
3
3
|
import 'zod';
|
|
4
4
|
|
|
5
5
|
/** Ed25519 public key multicodec value */
|
|
@@ -22,6 +22,17 @@ declare const decodeMultikey: (multibase: string) => {
|
|
|
22
22
|
keyBytes: Uint8Array;
|
|
23
23
|
codec: number;
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Decode a Multikey multibase string that MUST carry an Ed25519 PUBLIC key
|
|
27
|
+
*
|
|
28
|
+
* `decodeMultikey` also accepts the `ed25519-priv` prefix and reports it in
|
|
29
|
+
* `codec`, which a caller that destructures only `{ keyBytes }` silently
|
|
30
|
+
* discards — so a private-key-tagged multibase string would verify as if it were
|
|
31
|
+
* a public key, where the Go reference (DecodeMultikey) accepts the 0xed01
|
|
32
|
+
* prefix and nothing else. This is the decode every signature path takes, so the
|
|
33
|
+
* codec assertion cannot be forgotten at the next call site.
|
|
34
|
+
*/
|
|
35
|
+
declare const decodeEd25519PublicMultikey: (multibase: string) => Uint8Array;
|
|
25
36
|
|
|
26
37
|
/**
|
|
27
38
|
* Derive a prefixed chain identifier from CID bytes
|
|
@@ -54,13 +65,26 @@ declare const signIdentityOperation: (input: {
|
|
|
54
65
|
* Verify a log of JWS identity operations and derive the identity
|
|
55
66
|
*
|
|
56
67
|
* Walks the chain from genesis, verifying signatures and chain integrity, and
|
|
57
|
-
* folds the possession proofs alongside. Returns the
|
|
58
|
-
*
|
|
68
|
+
* folds the possession proofs alongside. Returns the verified identity state:
|
|
69
|
+
* EFFECTIVE key arrays, with the declared arrays and the void memberships
|
|
59
70
|
* beside them.
|
|
71
|
+
*
|
|
72
|
+
* THE BASIS SELECTS WHICH STATE COMES BACK, never how much of the log is
|
|
73
|
+
* verified. With `asOf` set, the whole log is walked and validated exactly as
|
|
74
|
+
* without it, and the state returned is the one the last operation dated at or
|
|
75
|
+
* before the basis folds to — the identity's state as of that instant
|
|
76
|
+
* (PROTOCOL, Time basis). The comparison is byte-wise on the `createdAt`
|
|
77
|
+
* strings, per PROTOCOL's Comparison basis. A basis earlier than genesis has no
|
|
78
|
+
* state to name and throws, and so does an empty basis.
|
|
60
79
|
*/
|
|
61
80
|
declare const verifyIdentityChain: (input: {
|
|
62
81
|
didPrefix: string;
|
|
63
82
|
log: string[];
|
|
83
|
+
/**
|
|
84
|
+
* Basis time, in the `createdAt` grammar. Omitted = the chain head, which is
|
|
85
|
+
* the state as of now.
|
|
86
|
+
*/
|
|
87
|
+
asOf?: string;
|
|
64
88
|
}) => Promise<VerifiedIdentity>;
|
|
65
89
|
/**
|
|
66
90
|
* Verify a single new operation against already-verified identity state
|
|
@@ -70,10 +94,13 @@ declare const verifyIdentityChain: (input: {
|
|
|
70
94
|
* verified genesis). This function performs one signature verification and one
|
|
71
95
|
* state transition — constant time regardless of chain length.
|
|
72
96
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
97
|
+
* KEY-ID CONSISTENCY IS CHECKED HERE, on the same terms as the full walk. The
|
|
98
|
+
* trusted state carries `seenKeys` — the id-to-material binding the walk already
|
|
99
|
+
* enforced — so an operation that re-points an existing key id at new material
|
|
100
|
+
* is REJECTED on this path exactly as a replay of the same two operations would
|
|
101
|
+
* reject it. Without that the fast path would accept a chain its own
|
|
102
|
+
* re-verification refuses, and a relay's linear path is the path almost every
|
|
103
|
+
* operation takes.
|
|
77
104
|
*
|
|
78
105
|
* THE POSSESSION FOLD RUNS HERE TOO, and it needs both halves of the trusted
|
|
79
106
|
* state: the EFFECTIVE arrays (to know what an introduction is a transition out
|
|
@@ -164,8 +191,11 @@ declare const signContentOperation: (input: {
|
|
|
164
191
|
*/
|
|
165
192
|
declare const verifyContentChain: (input: {
|
|
166
193
|
log: string[];
|
|
167
|
-
/**
|
|
168
|
-
|
|
194
|
+
/**
|
|
195
|
+
* Resolve a kid (DID URL) to the raw Ed25519 public key bytes, in the signing
|
|
196
|
+
* identity's state as of `basis` — each operation's own `createdAt`.
|
|
197
|
+
*/
|
|
198
|
+
resolveKey: (kid: string, basis?: string) => Promise<Uint8Array>;
|
|
169
199
|
/**
|
|
170
200
|
* Enforce creator-sovereignty authorization. When true, non-creator signers
|
|
171
201
|
* must include a DFOS credential in the operation's `authorization` field
|
|
@@ -173,10 +203,11 @@ declare const verifyContentChain: (input: {
|
|
|
173
203
|
*/
|
|
174
204
|
enforceAuthorization?: boolean;
|
|
175
205
|
/**
|
|
176
|
-
* Resolve a DID to a
|
|
177
|
-
* is true, as credential verification needs identity
|
|
206
|
+
* Resolve a DID to a ResolvedIdentity as of `basis`. Required when
|
|
207
|
+
* `enforceAuthorization` is true, as credential verification needs identity
|
|
208
|
+
* resolution.
|
|
178
209
|
*/
|
|
179
|
-
resolveIdentity?: (did: string) => Promise<
|
|
210
|
+
resolveIdentity?: (did: string, basis?: string) => Promise<ResolvedIdentity | undefined>;
|
|
180
211
|
/**
|
|
181
212
|
* Check whether a credential (leaf or parent) has been revoked. Called with
|
|
182
213
|
* `asOfUnix` = each operation's own `createdAt`, so a fold of committed
|
|
@@ -198,12 +229,15 @@ declare const verifyContentExtensionFromTrustedState: (input: {
|
|
|
198
229
|
lastCreatedAt: string;
|
|
199
230
|
/** The new JWS operation to verify */
|
|
200
231
|
newOp: string;
|
|
201
|
-
/**
|
|
202
|
-
|
|
232
|
+
/**
|
|
233
|
+
* Resolve a kid (DID URL) to the raw Ed25519 public key bytes, in the signing
|
|
234
|
+
* identity's state as of `basis` — the new operation's own `createdAt`.
|
|
235
|
+
*/
|
|
236
|
+
resolveKey: (kid: string, basis?: string) => Promise<Uint8Array>;
|
|
203
237
|
/** Enforce creator-sovereignty authorization (see verifyContentChain) */
|
|
204
238
|
enforceAuthorization?: boolean;
|
|
205
|
-
/** Resolve a DID to a
|
|
206
|
-
resolveIdentity?: (did: string) => Promise<
|
|
239
|
+
/** Resolve a DID to a ResolvedIdentity as of `basis`. Required when enforceAuthorization is true. */
|
|
240
|
+
resolveIdentity?: (did: string, basis?: string) => Promise<ResolvedIdentity | undefined>;
|
|
207
241
|
/**
|
|
208
242
|
* Check whether a credential (leaf or parent) has been revoked. Called with
|
|
209
243
|
* `asOfUnix` = the new operation's own `createdAt`. See `RevocationChecker`.
|
|
@@ -242,10 +276,15 @@ declare const signCountersignature: (input: {
|
|
|
242
276
|
* Checks: valid signature, CID integrity, payload schema. Does NOT check
|
|
243
277
|
* whether the target exists or whether the witness differs from the target
|
|
244
278
|
* author — those are relay-level semantic checks.
|
|
279
|
+
*
|
|
280
|
+
* The countersignature's own `createdAt` is the basis: a committed statement
|
|
281
|
+
* resolves its signer in the state that held when it was signed (PROTOCOL, Time
|
|
282
|
+
* basis).
|
|
245
283
|
*/
|
|
246
284
|
declare const verifyCountersignature: (input: {
|
|
247
285
|
jwsToken: string;
|
|
248
|
-
|
|
286
|
+
/** Resolve a kid to key bytes in the signer's state as of `basis`. */
|
|
287
|
+
resolveKey: (kid: string, basis?: string) => Promise<Uint8Array>;
|
|
249
288
|
}) => Promise<VerifiedCountersignature>;
|
|
250
289
|
|
|
251
290
|
interface VerifiedArtifact {
|
|
@@ -267,10 +306,14 @@ declare const signArtifact: (input: {
|
|
|
267
306
|
}>;
|
|
268
307
|
/**
|
|
269
308
|
* Verify an artifact JWS — signature, CID, payload schema, size limit
|
|
309
|
+
*
|
|
310
|
+
* The artifact's own `createdAt` is the basis: a committed statement resolves
|
|
311
|
+
* its signer in the state that held when it was signed (PROTOCOL, Time basis).
|
|
270
312
|
*/
|
|
271
313
|
declare const verifyArtifact: (input: {
|
|
272
314
|
jwsToken: string;
|
|
273
|
-
|
|
315
|
+
/** Resolve a kid to key bytes in the signer's state as of `basis`. */
|
|
316
|
+
resolveKey: (kid: string, basis?: string) => Promise<Uint8Array>;
|
|
274
317
|
}) => Promise<VerifiedArtifact>;
|
|
275
318
|
|
|
276
319
|
interface VerifiedRevocation {
|
|
@@ -299,10 +342,14 @@ declare const signRevocation: (input: {
|
|
|
299
342
|
}>;
|
|
300
343
|
/**
|
|
301
344
|
* Verify a revocation JWS — signature, CID, payload schema, signer match
|
|
345
|
+
*
|
|
346
|
+
* The revocation's own `createdAt` is the basis: a committed statement resolves
|
|
347
|
+
* its signer in the state that held when it was signed (PROTOCOL, Time basis).
|
|
302
348
|
*/
|
|
303
349
|
declare const verifyRevocation: (input: {
|
|
304
350
|
jwsToken: string;
|
|
305
|
-
|
|
351
|
+
/** Resolve a kid to key bytes in the signer's state as of `basis`. */
|
|
352
|
+
resolveKey: (kid: string, basis?: string) => Promise<Uint8Array>;
|
|
306
353
|
}) => Promise<VerifiedRevocation>;
|
|
307
354
|
|
|
308
355
|
interface VerifiedCreditClaim {
|
|
@@ -322,7 +369,7 @@ interface VerifiedCreditClaim {
|
|
|
322
369
|
claimCID: string;
|
|
323
370
|
}
|
|
324
371
|
/**
|
|
325
|
-
* The four states a `credits[]` entry resolves to (see `specs/
|
|
372
|
+
* The four states a `credits[]` entry resolves to (see `specs/CONTENT-MODEL.md`).
|
|
326
373
|
*
|
|
327
374
|
* `invalid` and `unverifiable` are deliberately distinct and MUST NOT be
|
|
328
375
|
* collapsed: `invalid` means "checked and failed" (a positive signal that
|
|
@@ -493,7 +540,8 @@ declare const buildSignRequest: (input: {
|
|
|
493
540
|
requestCID: string;
|
|
494
541
|
}>;
|
|
495
542
|
/**
|
|
496
|
-
* Verify a sign-request envelope in
|
|
543
|
+
* Verify a sign-request envelope in RELAY.md, Envelope verification's exact 1–9
|
|
544
|
+
* order.
|
|
497
545
|
*
|
|
498
546
|
* `resolveIdentity` supplies CURRENT identity state. A missing identity or
|
|
499
547
|
* resolver failure is `unverifiable`; a deleted identity, missing current key,
|
|
@@ -512,4 +560,4 @@ declare const assertCanonicalSignRequestPayload: (payloadTyp: string, payloadByt
|
|
|
512
560
|
subject: string;
|
|
513
561
|
}) => void;
|
|
514
562
|
|
|
515
|
-
export { type AnchorKind, ArtifactPayload, ContentOperation, CountersignPayload, type CreditClaimFailureReason, CreditClaimVerifyError, type CreditEntry, type CreditEntryState, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, IdentityOperation, RECOGNIZED_SERVICE_TYPES, ServiceEntry, type SignRequestFailureReason, SignRequestVerifyError, Signer, type VerifiedArtifact, type VerifiedContentChain, type VerifiedCountersignature, type VerifiedCreditClaim, type VerifiedCreditEntry, VerifiedIdentity, type VerifiedRevocation, type 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 };
|
|
563
|
+
export { type AnchorKind, ArtifactPayload, ContentOperation, CountersignPayload, type CreditClaimFailureReason, CreditClaimVerifyError, type CreditEntry, type CreditEntryState, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, IdentityOperation, RECOGNIZED_SERVICE_TYPES, ServiceEntry, type SignRequestFailureReason, SignRequestVerifyError, Signer, type VerifiedArtifact, type VerifiedContentChain, type VerifiedCountersignature, type VerifiedCreditClaim, type VerifiedCreditEntry, VerifiedIdentity, type VerifiedRevocation, type VerifiedSignRequest, anchorsByLabel, assertCanonicalSignRequestPayload, assertServicesWithinCap, buildSignRequest, classifyAnchor, decodeEd25519PublicMultikey, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, isRecognizedServiceType, relayEndpoints, signArtifact, signContentOperation, signCountersignature, signCreditClaim, signIdentityOperation, signRevocation, verifyArtifact, verifyContentChain, verifyContentExtensionFromTrustedState, verifyCountersignature, verifyCreditClaim, verifyCreditEntry, verifyIdentityChain, verifyIdentityExtensionFromTrustedState, verifyRevocation, verifySignRequest };
|
package/dist/chain/index.js
CHANGED
|
@@ -52,16 +52,17 @@ import {
|
|
|
52
52
|
verifyIdentityExtensionFromTrustedState,
|
|
53
53
|
verifyRevocation,
|
|
54
54
|
verifySignRequest
|
|
55
|
-
} from "../chunk-
|
|
56
|
-
import "../chunk-
|
|
57
|
-
import "../chunk-
|
|
55
|
+
} from "../chunk-OU2DPHCN.js";
|
|
56
|
+
import "../chunk-IV3TIYKP.js";
|
|
57
|
+
import "../chunk-QRCOMLAP.js";
|
|
58
58
|
import {
|
|
59
59
|
ED25519_PRIV_MULTICODEC,
|
|
60
60
|
ED25519_PUB_MULTICODEC,
|
|
61
|
+
decodeEd25519PublicMultikey,
|
|
61
62
|
decodeMultikey,
|
|
62
63
|
encodeEd25519Multikey
|
|
63
|
-
} from "../chunk-
|
|
64
|
-
import "../chunk-
|
|
64
|
+
} from "../chunk-F7RHI2CK.js";
|
|
65
|
+
import "../chunk-QTJZGXMH.js";
|
|
65
66
|
export {
|
|
66
67
|
ARTIFACT_CID_ANCHOR_RE,
|
|
67
68
|
ArtifactPayload,
|
|
@@ -97,6 +98,7 @@ export {
|
|
|
97
98
|
assertServicesWithinCap,
|
|
98
99
|
buildSignRequest,
|
|
99
100
|
classifyAnchor,
|
|
101
|
+
decodeEd25519PublicMultikey,
|
|
100
102
|
decodeMultikey,
|
|
101
103
|
deriveChainIdentifier,
|
|
102
104
|
deriveContentId,
|
|
@@ -36,10 +36,18 @@ var decodeMultikey = (multibase) => {
|
|
|
36
36
|
`unsupported multikey codec: [0x${bytes[0]?.toString(16)}, 0x${bytes[1]?.toString(16)}]`
|
|
37
37
|
);
|
|
38
38
|
};
|
|
39
|
+
var decodeEd25519PublicMultikey = (multibase) => {
|
|
40
|
+
const { keyBytes, codec } = decodeMultikey(multibase);
|
|
41
|
+
if (codec !== ED25519_PUB_MULTICODEC) {
|
|
42
|
+
throw new Error("publicKeyMultibase is not an Ed25519 public key");
|
|
43
|
+
}
|
|
44
|
+
return keyBytes;
|
|
45
|
+
};
|
|
39
46
|
|
|
40
47
|
export {
|
|
41
48
|
ED25519_PUB_MULTICODEC,
|
|
42
49
|
ED25519_PRIV_MULTICODEC,
|
|
43
50
|
encodeEd25519Multikey,
|
|
44
|
-
decodeMultikey
|
|
51
|
+
decodeMultikey,
|
|
52
|
+
decodeEd25519PublicMultikey
|
|
45
53
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./chunk-
|
|
2
|
+
decodeEd25519PublicMultikey
|
|
3
|
+
} from "./chunk-F7RHI2CK.js";
|
|
4
4
|
import {
|
|
5
5
|
assertJwsProfile,
|
|
6
6
|
base64urlDecode,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
decodeJwsUnsafe,
|
|
11
11
|
sha256,
|
|
12
12
|
verifyJws
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-QTJZGXMH.js";
|
|
14
14
|
|
|
15
15
|
// src/credentials/schemas.ts
|
|
16
16
|
import { z } from "zod";
|
|
@@ -355,7 +355,10 @@ var verifyProofEnvelope = async (input, shape, resolvePresenter) => {
|
|
|
355
355
|
const key = state.keys.find((candidate) => candidate.id === presenterKeyId);
|
|
356
356
|
if (!key) throw invalidProof(`${shape.label} signing key is not a current key of the presenter`);
|
|
357
357
|
try {
|
|
358
|
-
verifyJws({
|
|
358
|
+
verifyJws({
|
|
359
|
+
token: input.proof,
|
|
360
|
+
publicKey: decodeEd25519PublicMultikey(key.publicKeyMultibase)
|
|
361
|
+
});
|
|
359
362
|
} catch (err) {
|
|
360
363
|
throw invalidProof(err instanceof Error ? err.message : `invalid ${shape.label} signature`);
|
|
361
364
|
}
|
|
@@ -370,20 +373,26 @@ var isDependencyMissing = (err) => err instanceof Error && err.dependencyMissing
|
|
|
370
373
|
var carryDependencyMissing = (cause, wrapped) => isDependencyMissing(cause) ? markDependencyMissing(wrapped) : wrapped;
|
|
371
374
|
|
|
372
375
|
// src/credentials/dfos-credential.ts
|
|
373
|
-
var resolveKeyFromIdentity = (identity, kid) => {
|
|
376
|
+
var resolveKeyFromIdentity = (identity, kid, determinate) => {
|
|
374
377
|
const hashIdx = kid.indexOf("#");
|
|
375
378
|
if (hashIdx < 0) throw new CredentialVerificationError("kid must be a DID URL");
|
|
376
379
|
const keyId = kid.substring(hashIdx + 1);
|
|
377
380
|
const allKeys = [...identity.authKeys, ...identity.assertKeys, ...identity.controllerKeys];
|
|
378
381
|
const key = allKeys.find((k) => k.id === keyId);
|
|
379
382
|
if (!key) {
|
|
380
|
-
|
|
381
|
-
|
|
383
|
+
const miss = new CredentialVerificationError(
|
|
384
|
+
`unknown key ${keyId} on identity ${identity.did}`
|
|
382
385
|
);
|
|
386
|
+
throw determinate ? miss : markDependencyMissing(miss);
|
|
383
387
|
}
|
|
384
|
-
const
|
|
388
|
+
const keyBytes = decodeEd25519PublicMultikey(key.publicKeyMultibase);
|
|
385
389
|
return keyBytes;
|
|
386
390
|
};
|
|
391
|
+
var basisUnixSeconds = (basis) => {
|
|
392
|
+
const ms = Date.parse(basis);
|
|
393
|
+
if (Number.isNaN(ms)) throw new CredentialVerificationError(`invalid basis time: ${basis}`);
|
|
394
|
+
return Math.floor(ms / 1e3);
|
|
395
|
+
};
|
|
387
396
|
var createDFOSCredential = async (options) => {
|
|
388
397
|
const kid = `${options.issuerDID}#${options.keyId}`;
|
|
389
398
|
const now = options.iat ?? Math.floor(Date.now() / 1e3);
|
|
@@ -435,7 +444,7 @@ var verifyDFOSCredential = async (jwsToken, options) => {
|
|
|
435
444
|
if (kidDid !== payload.iss) {
|
|
436
445
|
throw new CredentialVerificationError("credential kid DID does not match iss");
|
|
437
446
|
}
|
|
438
|
-
const identity = await options.resolveIdentity(payload.iss);
|
|
447
|
+
const identity = await options.resolveIdentity(payload.iss, options.basis);
|
|
439
448
|
if (!identity) {
|
|
440
449
|
throw markDependencyMissing(
|
|
441
450
|
new CredentialVerificationError(`issuer identity not found: ${payload.iss}`)
|
|
@@ -444,13 +453,13 @@ var verifyDFOSCredential = async (jwsToken, options) => {
|
|
|
444
453
|
if (identity.isDeleted) {
|
|
445
454
|
throw new CredentialVerificationError(`issuer identity is deleted: ${payload.iss}`);
|
|
446
455
|
}
|
|
447
|
-
const publicKey = resolveKeyFromIdentity(identity, kid);
|
|
456
|
+
const publicKey = resolveKeyFromIdentity(identity, kid, identity.basisDeterminate === true);
|
|
448
457
|
try {
|
|
449
458
|
verifyJws({ token: jwsToken, publicKey });
|
|
450
459
|
} catch {
|
|
451
460
|
throw new CredentialVerificationError("invalid credential signature");
|
|
452
461
|
}
|
|
453
|
-
const encoded = await dagCborCanonicalEncode(payload);
|
|
462
|
+
const encoded = await dagCborCanonicalEncode(decoded.payload);
|
|
454
463
|
const credentialCID = encoded.cid.toString();
|
|
455
464
|
if (!decoded.header.cid) {
|
|
456
465
|
throw new CredentialVerificationError("missing cid in credential header");
|
|
@@ -458,11 +467,8 @@ var verifyDFOSCredential = async (jwsToken, options) => {
|
|
|
458
467
|
if (decoded.header.cid !== credentialCID) {
|
|
459
468
|
throw new CredentialVerificationError("credential cid mismatch");
|
|
460
469
|
}
|
|
461
|
-
const
|
|
462
|
-
if (payload.
|
|
463
|
-
throw new CredentialVerificationError("credential not yet valid (iat is in the future)");
|
|
464
|
-
}
|
|
465
|
-
if (payload.exp <= now) {
|
|
470
|
+
const basisSeconds = options.basis !== void 0 ? basisUnixSeconds(options.basis) : options.nowUnix ?? Math.floor(Date.now() / 1e3);
|
|
471
|
+
if (payload.exp <= basisSeconds) {
|
|
466
472
|
throw new CredentialVerificationError("credential expired");
|
|
467
473
|
}
|
|
468
474
|
return {
|
|
@@ -478,6 +484,7 @@ var verifyDFOSCredential = async (jwsToken, options) => {
|
|
|
478
484
|
};
|
|
479
485
|
var verifyDelegationChain = async (credential, options) => {
|
|
480
486
|
const chain = [credential];
|
|
487
|
+
const revocationBasis = options.basis !== void 0 ? basisUnixSeconds(options.basis) : void 0;
|
|
481
488
|
let current = credential;
|
|
482
489
|
const maxDepth = 16;
|
|
483
490
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
@@ -496,10 +503,11 @@ var verifyDelegationChain = async (credential, options) => {
|
|
|
496
503
|
}
|
|
497
504
|
const parent = await verifyDFOSCredential(current.prf[0], {
|
|
498
505
|
resolveIdentity: options.resolveIdentity,
|
|
499
|
-
...options.
|
|
506
|
+
...options.basis !== void 0 ? { basis: options.basis } : {},
|
|
507
|
+
...options.nowUnix !== void 0 ? { nowUnix: options.nowUnix } : {}
|
|
500
508
|
});
|
|
501
509
|
if (options.isRevoked) {
|
|
502
|
-
const revoked = await options.isRevoked(parent.iss, parent.credentialCID,
|
|
510
|
+
const revoked = await options.isRevoked(parent.iss, parent.credentialCID, revocationBasis);
|
|
503
511
|
if (revoked) {
|
|
504
512
|
throw new CredentialVerificationError("parent credential in delegation chain is revoked");
|
|
505
513
|
}
|
|
@@ -529,8 +537,9 @@ var parseResource = (resource) => {
|
|
|
529
537
|
if (colonIdx < 0) return null;
|
|
530
538
|
return { type: resource.substring(0, colonIdx), id: resource.substring(colonIdx + 1) };
|
|
531
539
|
};
|
|
540
|
+
var ASCII_TRIM_RE = /^[\t\n\v\f\r ]+|[\t\n\v\f\r ]+$/g;
|
|
532
541
|
var parseActions = (action) => new Set(
|
|
533
|
-
action.split(",").map((a) => a.
|
|
542
|
+
action.split(",").map((a) => a.replace(ASCII_TRIM_RE, "")).filter((a) => a !== "")
|
|
534
543
|
);
|
|
535
544
|
var isAttenuated = (parentAtt, childAtt) => {
|
|
536
545
|
return childAtt.every((childEntry) => {
|