@learncard/openid4vc-plugin 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +592 -0
- package/dist/dcql/adapt.d.ts +80 -0
- package/dist/dcql/adapt.d.ts.map +1 -0
- package/dist/dcql/build.d.ts +122 -0
- package/dist/dcql/build.d.ts.map +1 -0
- package/dist/dcql/compose.d.ts +78 -0
- package/dist/dcql/compose.d.ts.map +1 -0
- package/dist/dcql/index.d.ts +18 -0
- package/dist/dcql/index.d.ts.map +1 -0
- package/dist/dcql/parse.d.ts +16 -0
- package/dist/dcql/parse.d.ts.map +1 -0
- package/dist/dcql/respond.d.ts +115 -0
- package/dist/dcql/respond.d.ts.map +1 -0
- package/dist/dcql/select.d.ts +63 -0
- package/dist/dcql/select.d.ts.map +1 -0
- package/dist/dcql/types.d.ts +93 -0
- package/dist/dcql/types.d.ts.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/offer/index.d.ts +4 -0
- package/dist/offer/index.d.ts.map +1 -0
- package/dist/offer/normalize.d.ts +15 -0
- package/dist/offer/normalize.d.ts.map +1 -0
- package/dist/offer/parse.d.ts +24 -0
- package/dist/offer/parse.d.ts.map +1 -0
- package/dist/offer/types.d.ts +92 -0
- package/dist/offer/types.d.ts.map +1 -0
- package/dist/openid4vc-plugin.cjs.development.js +27402 -0
- package/dist/openid4vc-plugin.cjs.development.js.map +7 -0
- package/dist/openid4vc-plugin.cjs.production.min.js +146 -0
- package/dist/openid4vc-plugin.cjs.production.min.js.map +7 -0
- package/dist/openid4vc-plugin.esm.js +27396 -0
- package/dist/openid4vc-plugin.esm.js.map +7 -0
- package/dist/plugin.d.ts +12 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/siop/index.d.ts +11 -0
- package/dist/siop/index.d.ts.map +1 -0
- package/dist/siop/sign.d.ts +92 -0
- package/dist/siop/sign.d.ts.map +1 -0
- package/dist/types.d.ts +359 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/vci/accept.d.ts +24 -0
- package/dist/vci/accept.d.ts.map +1 -0
- package/dist/vci/auth-code.d.ts +148 -0
- package/dist/vci/auth-code.d.ts.map +1 -0
- package/dist/vci/decode.d.ts +65 -0
- package/dist/vci/decode.d.ts.map +1 -0
- package/dist/vci/errors.d.ts +22 -0
- package/dist/vci/errors.d.ts.map +1 -0
- package/dist/vci/index.d.ts +12 -0
- package/dist/vci/index.d.ts.map +1 -0
- package/dist/vci/metadata.d.ts +25 -0
- package/dist/vci/metadata.d.ts.map +1 -0
- package/dist/vci/pkce.d.ts +85 -0
- package/dist/vci/pkce.d.ts.map +1 -0
- package/dist/vci/proof.d.ts +43 -0
- package/dist/vci/proof.d.ts.map +1 -0
- package/dist/vci/request.d.ts +48 -0
- package/dist/vci/request.d.ts.map +1 -0
- package/dist/vci/store.d.ts +89 -0
- package/dist/vci/store.d.ts.map +1 -0
- package/dist/vci/token.d.ts +16 -0
- package/dist/vci/token.d.ts.map +1 -0
- package/dist/vci/types.d.ts +156 -0
- package/dist/vci/types.d.ts.map +1 -0
- package/dist/vp/client-id-prefix.d.ts +115 -0
- package/dist/vp/client-id-prefix.d.ts.map +1 -0
- package/dist/vp/encrypt.d.ts +221 -0
- package/dist/vp/encrypt.d.ts.map +1 -0
- package/dist/vp/index.d.ts +27 -0
- package/dist/vp/index.d.ts.map +1 -0
- package/dist/vp/parse.d.ts +60 -0
- package/dist/vp/parse.d.ts.map +1 -0
- package/dist/vp/pex.d.ts +83 -0
- package/dist/vp/pex.d.ts.map +1 -0
- package/dist/vp/present.d.ts +126 -0
- package/dist/vp/present.d.ts.map +1 -0
- package/dist/vp/request-object.d.ts +99 -0
- package/dist/vp/request-object.d.ts.map +1 -0
- package/dist/vp/select.d.ts +137 -0
- package/dist/vp/select.d.ts.map +1 -0
- package/dist/vp/sign.d.ts +125 -0
- package/dist/vp/sign.d.ts.map +1 -0
- package/dist/vp/submit.d.ts +175 -0
- package/dist/vp/submit.d.ts.map +1 -0
- package/dist/vp/types.d.ts +255 -0
- package/dist/vp/types.d.ts.map +1 -0
- package/package.json +52 -0
package/dist/vp/pex.d.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Field, InputDescriptor } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Presentation Exchange v2 matcher — tests whether a single candidate VC
|
|
4
|
+
* satisfies an input_descriptor's constraints.
|
|
5
|
+
*
|
|
6
|
+
* Scope (what PEX expressions we support in Slice 6):
|
|
7
|
+
*
|
|
8
|
+
* **JSONPath subset (field.path[])**
|
|
9
|
+
* - `$` root
|
|
10
|
+
* - `$.foo`, `$.foo.bar` dotted properties
|
|
11
|
+
* - `$['foo']`, `$["foo bar"]` bracketed property names (quoted literals)
|
|
12
|
+
* - `$.foo[0]` numeric index
|
|
13
|
+
* - `$.foo[*]` array wildcard
|
|
14
|
+
* - `$..foo` recursive descent
|
|
15
|
+
* - `$.foo[?(@.bar=='x')]` filter predicates — NOT yet supported, and
|
|
16
|
+
* they're rare in real-world PD docs. Paths
|
|
17
|
+
* that need predicates throw a descriptive
|
|
18
|
+
* error rather than silently evaluating to
|
|
19
|
+
* nothing.
|
|
20
|
+
*
|
|
21
|
+
* **JSON Schema filter subset (field.filter)**
|
|
22
|
+
* - `type`, `const`, `enum`, `pattern`
|
|
23
|
+
* - `minimum`, `maximum`, `exclusiveMinimum`, `exclusiveMaximum`
|
|
24
|
+
* - `minLength`, `maxLength`
|
|
25
|
+
* - `contains` (on arrays)
|
|
26
|
+
* - `items` (on arrays — applied to every element)
|
|
27
|
+
* - Anything else is treated as "unknown constraint" and passes by
|
|
28
|
+
* default. Verifiers relying on more exotic keywords will want the
|
|
29
|
+
* full-ajv upgrade path noted in the README.
|
|
30
|
+
*
|
|
31
|
+
* Format / holder-binding checks live in the higher-level select.ts
|
|
32
|
+
* layer (Slice 6d) since they depend on knowing the candidate's format
|
|
33
|
+
* and the PD's `format` designation together.
|
|
34
|
+
*/
|
|
35
|
+
/** Per-field evaluation result. */
|
|
36
|
+
export interface FieldMatch {
|
|
37
|
+
matched: boolean;
|
|
38
|
+
/** First JSONPath from `field.path[]` that yielded a matching value. */
|
|
39
|
+
matchedPath?: string;
|
|
40
|
+
/** The value at `matchedPath`. */
|
|
41
|
+
value?: unknown;
|
|
42
|
+
/** Diagnostic reason when `matched === false`. */
|
|
43
|
+
reason?: string;
|
|
44
|
+
}
|
|
45
|
+
/** Per-descriptor evaluation result. */
|
|
46
|
+
export interface DescriptorMatch {
|
|
47
|
+
matched: boolean;
|
|
48
|
+
descriptorId: string;
|
|
49
|
+
/** One entry per declared field, in order. */
|
|
50
|
+
fields: FieldMatch[];
|
|
51
|
+
/** Diagnostic reason summarizing the first failure, when `matched === false`. */
|
|
52
|
+
reason?: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Evaluate a single PEX field against a candidate credential.
|
|
56
|
+
*
|
|
57
|
+
* Walks `field.path[]` in declared order, returning the first path that
|
|
58
|
+
* resolves AND — if `field.filter` is present — whose value satisfies
|
|
59
|
+
* the filter. Optional fields that find no value still succeed.
|
|
60
|
+
*/
|
|
61
|
+
export declare const evaluateField: (candidate: unknown, field: Field) => FieldMatch;
|
|
62
|
+
/**
|
|
63
|
+
* Evaluate a full input_descriptor against a candidate credential.
|
|
64
|
+
*
|
|
65
|
+
* Short-circuits on the first required-field failure so a single bad
|
|
66
|
+
* field produces a useful reason instead of a wall of mismatches.
|
|
67
|
+
*/
|
|
68
|
+
export declare const matchInputDescriptor: (candidate: unknown, descriptor: InputDescriptor) => DescriptorMatch;
|
|
69
|
+
/**
|
|
70
|
+
* Evaluate a supported JSONPath expression against `root` and return all
|
|
71
|
+
* matching values. Throws if the expression uses unsupported features
|
|
72
|
+
* (filter predicates, slicing, unions, scripting) so callers surface an
|
|
73
|
+
* actionable error rather than silently returning nothing.
|
|
74
|
+
*/
|
|
75
|
+
export declare const queryJsonPath: (root: unknown, path: string) => unknown[];
|
|
76
|
+
/**
|
|
77
|
+
* Return whether `value` satisfies the PEX-sanctioned subset of JSON
|
|
78
|
+
* Schema. Unknown keywords are ignored (lenient mode) — wallets that
|
|
79
|
+
* reject on unknown keywords force verifier upgrades in lockstep, which
|
|
80
|
+
* is incompatible with the "meet them where they are" design goal.
|
|
81
|
+
*/
|
|
82
|
+
export declare const satisfiesFilter: (value: unknown, filter: Record<string, unknown>) => boolean;
|
|
83
|
+
//# sourceMappingURL=pex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pex.d.ts","sourceRoot":"","sources":["../../src/vp/pex.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAW9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,mCAAmC;AACnC,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wCAAwC;AACxC,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,cAAe,OAAO,SAAS,KAAK,KAAG,UA6DhE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,cAClB,OAAO,cACN,eAAe,KAC5B,eAyBF,CAAC;AAYF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,SAAU,OAAO,QAAQ,MAAM,KAAG,OAAO,EA0DlE,CAAC;AAmIF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,UAAW,OAAO,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,OA6GjF,CAAC"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { UnsignedVP } from '@learncard/types';
|
|
2
|
+
import type { CandidateCredential, PresentationSubmission } from './select';
|
|
3
|
+
import { PresentationDefinition } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Slice 7a — **Verifiable Presentation construction**.
|
|
6
|
+
*
|
|
7
|
+
* Given a user's per-descriptor credential picks and the verifier's
|
|
8
|
+
* Presentation Definition, produce:
|
|
9
|
+
*
|
|
10
|
+
* 1. An unsigned W3C `VerifiablePresentation` object ready to be
|
|
11
|
+
* signed (via `learnCard.invoke.issuePresentation` for `ldp_vp`, or
|
|
12
|
+
* via the Slice 7b JWT signer for `jwt_vp_json`).
|
|
13
|
+
* 2. A DIF PEX v2 `PresentationSubmission` whose `descriptor_map`
|
|
14
|
+
* paths correctly target each credential inside the final
|
|
15
|
+
* `vp_token` for the chosen envelope format.
|
|
16
|
+
* 3. The envelope format id (`ldp_vp` | `jwt_vp_json`) so the caller
|
|
17
|
+
* knows which signing path to invoke.
|
|
18
|
+
*
|
|
19
|
+
* **Pure and synchronous.** This layer never signs, never POSTs, and
|
|
20
|
+
* never touches the holder's private keys. All transport /
|
|
21
|
+
* cryptographic work happens in Slices 7b and 7c.
|
|
22
|
+
*
|
|
23
|
+
* ## Descriptor map semantics
|
|
24
|
+
*
|
|
25
|
+
* The DIF PEX spec (§6 "Presentation Submission") evaluates
|
|
26
|
+
* `descriptor_map[n].path` as a JSONPath over the vp_token **after
|
|
27
|
+
* decoding** when the outer token is a JWT. We emit paths that match
|
|
28
|
+
* what every mainstream verifier (walt.id, Sphereon, EUDI, Animo)
|
|
29
|
+
* actually resolves:
|
|
30
|
+
*
|
|
31
|
+
* - Outer `ldp_vp` envelope → `path: "$.verifiableCredential[N]"`
|
|
32
|
+
* - Outer `jwt_vp_json` envelope → `path: "$.vp.verifiableCredential[N]"`
|
|
33
|
+
*
|
|
34
|
+
* For mixed inner formats (e.g. a `jwt_vc_json` VC embedded alongside
|
|
35
|
+
* an `ldp_vc` inside an `ldp_vp`), the per-credential `format` field
|
|
36
|
+
* discriminates without needing `path_nested` — the path still
|
|
37
|
+
* resolves directly to the credential value at that index.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Envelope format for the outer Verifiable Presentation.
|
|
41
|
+
*
|
|
42
|
+
* - `ldp_vp` — plain JSON-LD VP, signed with a Linked-Data / Data
|
|
43
|
+
* Integrity proof (Slice 7b routes this through
|
|
44
|
+
* `learnCard.invoke.issuePresentation`).
|
|
45
|
+
* - `jwt_vp_json` — compact JWS whose payload wraps the VP under a
|
|
46
|
+
* top-level `vp` claim (VCDM §6.3.1).
|
|
47
|
+
*/
|
|
48
|
+
export type VpFormat = 'ldp_vp' | 'jwt_vp_json';
|
|
49
|
+
/**
|
|
50
|
+
* A single user pick: "this candidate satisfies this input_descriptor".
|
|
51
|
+
* Wallets typically build this list from the SelectionResult by showing
|
|
52
|
+
* the per-descriptor candidate lists and letting the user tap once per
|
|
53
|
+
* row.
|
|
54
|
+
*/
|
|
55
|
+
export interface ChosenCredential {
|
|
56
|
+
descriptorId: string;
|
|
57
|
+
candidate: CandidateCredential;
|
|
58
|
+
}
|
|
59
|
+
export interface BuildPresentationOptions {
|
|
60
|
+
/** The verifier's Presentation Definition (used for `definition_id` + format hints). */
|
|
61
|
+
pd: PresentationDefinition;
|
|
62
|
+
/**
|
|
63
|
+
* The holder's picks, in presentation order. The resulting VP's
|
|
64
|
+
* `verifiableCredential` array mirrors this order, and every
|
|
65
|
+
* `descriptor_map` entry points at the matching index.
|
|
66
|
+
*/
|
|
67
|
+
chosen: ChosenCredential[];
|
|
68
|
+
/** Holder DID, emitted as `unsignedVp.holder`. Required for VCDM §4.1.1 compliance. */
|
|
69
|
+
holder: string;
|
|
70
|
+
/**
|
|
71
|
+
* Override the envelope format. By default we infer from
|
|
72
|
+
* `pd.format` (if the verifier declared preference) and fall back
|
|
73
|
+
* to matching the chosen credentials' inner format.
|
|
74
|
+
*/
|
|
75
|
+
envelopeFormat?: VpFormat;
|
|
76
|
+
/** Override the submission id. Defaults to a short random hex id. */
|
|
77
|
+
submissionId?: string;
|
|
78
|
+
/** Override the VP id. Defaults to `urn:uuid:<v4>`. */
|
|
79
|
+
presentationId?: string;
|
|
80
|
+
/** Seam for deterministic tests. Defaults to a `crypto.getRandomValues`-backed id. */
|
|
81
|
+
makeId?: () => string;
|
|
82
|
+
}
|
|
83
|
+
export interface PreparedPresentation {
|
|
84
|
+
/**
|
|
85
|
+
* Unsigned W3C Verifiable Presentation. Shape is the same for both
|
|
86
|
+
* envelope formats; the signing step differs.
|
|
87
|
+
*
|
|
88
|
+
* - For `ldp_vp`: pass this straight to
|
|
89
|
+
* `learnCard.invoke.issuePresentation(unsignedVp, signingOptions)`.
|
|
90
|
+
* - For `jwt_vp_json`: wrap as the `vp` claim of a JWT and sign
|
|
91
|
+
* (Slice 7b).
|
|
92
|
+
*/
|
|
93
|
+
unsignedVp: UnsignedVP;
|
|
94
|
+
/** Ready-to-submit DIF PEX v2 Presentation Submission. */
|
|
95
|
+
submission: PresentationSubmission;
|
|
96
|
+
/** Outer envelope format id. */
|
|
97
|
+
vpFormat: VpFormat;
|
|
98
|
+
/**
|
|
99
|
+
* Per-credential format id, in the same order as
|
|
100
|
+
* `unsignedVp.verifiableCredential`. Slice 7b / 7c use this to
|
|
101
|
+
* decide serialization (compact JWS string vs. JSON object).
|
|
102
|
+
*/
|
|
103
|
+
innerFormats: string[];
|
|
104
|
+
}
|
|
105
|
+
export type BuildPresentationErrorCode = 'no_selections' | 'unknown_descriptor' | 'unknown_credential_format' | 'invalid_jwt_vc';
|
|
106
|
+
export declare class BuildPresentationError extends Error {
|
|
107
|
+
readonly code: BuildPresentationErrorCode;
|
|
108
|
+
constructor(code: BuildPresentationErrorCode, message: string);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Build a VerifiablePresentation + PresentationSubmission from a
|
|
112
|
+
* user's credential picks. See module doc for behavior.
|
|
113
|
+
*
|
|
114
|
+
* Validates input eagerly so callers get actionable errors instead of
|
|
115
|
+
* a malformed VP that the verifier silently rejects:
|
|
116
|
+
*
|
|
117
|
+
* - `no_selections` — `chosen` is empty.
|
|
118
|
+
* - `unknown_descriptor` — a pick references an id that doesn't exist
|
|
119
|
+
* in the PD's input_descriptors.
|
|
120
|
+
* - `unknown_credential_format` — a candidate's format can't be
|
|
121
|
+
* inferred AND wasn't explicitly declared.
|
|
122
|
+
* - `invalid_jwt_vc` — a candidate tagged `jwt_vc_json` has neither a
|
|
123
|
+
* compact JWS string nor a `proof.jwt` we can extract.
|
|
124
|
+
*/
|
|
125
|
+
export declare const buildPresentation: (options: BuildPresentationOptions) => PreparedPresentation;
|
|
126
|
+
//# sourceMappingURL=present.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"present.d.ts","sourceRoot":"","sources":["../../src/vp/present.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,OAAO,KAAK,EACR,mBAAmB,EACnB,sBAAsB,EAEzB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAMH;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,aAAa,CAAC;AAEhD;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,mBAAmB,CAAC;CAClC;AAED,MAAM,WAAW,wBAAwB;IACrC,wFAAwF;IACxF,EAAE,EAAE,sBAAsB,CAAC;IAE3B;;;;OAIG;IACH,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAE3B,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;IAEf;;;;OAIG;IACH,cAAc,CAAC,EAAE,QAAQ,CAAC;IAE1B,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACjC;;;;;;;;OAQG;IACH,UAAU,EAAE,UAAU,CAAC;IAEvB,0DAA0D;IAC1D,UAAU,EAAE,sBAAsB,CAAC;IAEnC,gCAAgC;IAChC,QAAQ,EAAE,QAAQ,CAAC;IAEnB;;;;OAIG;IACH,YAAY,EAAE,MAAM,EAAE,CAAC;CAC1B;AAMD,MAAM,MAAM,0BAA0B,GAChC,eAAe,GACf,oBAAoB,GACpB,2BAA2B,GAC3B,gBAAgB,CAAC;AAEvB,qBAAa,sBAAuB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,EAAE,0BAA0B,CAAC;gBAE9B,IAAI,EAAE,0BAA0B,EAAE,OAAO,EAAE,MAAM;CAKhE;AAMD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iBAAiB,YACjB,wBAAwB,KAClC,oBAwDF,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { JWK } from 'jose';
|
|
2
|
+
import { AuthorizationRequest } from './types';
|
|
3
|
+
export type RequestObjectErrorCode = 'invalid_request_object' | 'request_fetch_failed' | 'missing_client_id_scheme' | 'unsupported_client_id_scheme' | 'client_id_mismatch' | 'request_signature_invalid' | 'request_signer_untrusted' | 'did_resolution_failed' | 'unsafe_mode_rejected';
|
|
4
|
+
export declare class RequestObjectError extends Error {
|
|
5
|
+
readonly code: RequestObjectErrorCode;
|
|
6
|
+
constructor(code: RequestObjectErrorCode, message: string, options?: {
|
|
7
|
+
cause?: unknown;
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Minimal DID Document shape the resolver surface consumes. We avoid
|
|
12
|
+
* re-modeling the full spec — consumers only need enough to pull a
|
|
13
|
+
* `publicKeyJwk` out.
|
|
14
|
+
*/
|
|
15
|
+
export interface VerificationMethod {
|
|
16
|
+
id: string;
|
|
17
|
+
type: string;
|
|
18
|
+
controller?: string;
|
|
19
|
+
publicKeyJwk?: JWK;
|
|
20
|
+
publicKeyMultibase?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface DidDocument {
|
|
23
|
+
id: string;
|
|
24
|
+
verificationMethod?: VerificationMethod[];
|
|
25
|
+
authentication?: Array<string | VerificationMethod>;
|
|
26
|
+
assertionMethod?: Array<string | VerificationMethod>;
|
|
27
|
+
}
|
|
28
|
+
export type DidResolver = (did: string) => Promise<DidDocument>;
|
|
29
|
+
export interface VerifyRequestObjectOptions {
|
|
30
|
+
/** The `request_uri` to fetch. Mutually exclusive with `inlineJwt`. */
|
|
31
|
+
requestUri?: string;
|
|
32
|
+
/** The inline `request=<jws>` parameter value. Mutually exclusive with `requestUri`. */
|
|
33
|
+
inlineJwt?: string;
|
|
34
|
+
/**
|
|
35
|
+
* `client_id` from the outer URL params. Some verifiers let the
|
|
36
|
+
* `client_id` live in the URL while the JWS payload just repeats
|
|
37
|
+
* it; we cross-check them. Optional — only used as a consistency
|
|
38
|
+
* check when provided.
|
|
39
|
+
*/
|
|
40
|
+
urlClientId?: string;
|
|
41
|
+
/**
|
|
42
|
+
* `client_id_scheme` from the outer URL params. Same cross-check
|
|
43
|
+
* rationale as `urlClientId`.
|
|
44
|
+
*/
|
|
45
|
+
urlClientIdScheme?: string;
|
|
46
|
+
fetchImpl?: typeof fetch;
|
|
47
|
+
/**
|
|
48
|
+
* DID resolver override. When omitted, a built-in resolver handles
|
|
49
|
+
* `did:jwk` (offline) and `did:web` (over `fetchImpl`). Host apps
|
|
50
|
+
* that ship `did:key`/`did:ion`/… wire their own resolver here.
|
|
51
|
+
*/
|
|
52
|
+
didResolver?: DidResolver;
|
|
53
|
+
/**
|
|
54
|
+
* Trusted X.509 root certificates (PEM strings). When scheme is
|
|
55
|
+
* `x509_san_dns`, the chain presented in `x5c` MUST root to one of
|
|
56
|
+
* these. If this list is empty and `unsafeAllowSelfSigned` is
|
|
57
|
+
* false, we refuse to verify x509-signed Request Objects.
|
|
58
|
+
*/
|
|
59
|
+
trustedX509Roots?: readonly string[];
|
|
60
|
+
/**
|
|
61
|
+
* **Dangerous.** Accept self-signed / untrusted x509 chains for
|
|
62
|
+
* local development. The harness flips this on when a user
|
|
63
|
+
* explicitly opts in; production wallets must leave it off.
|
|
64
|
+
*/
|
|
65
|
+
unsafeAllowSelfSigned?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* **Maximally dangerous.** Skip JWS signature verification on the
|
|
68
|
+
* Request Object entirely — claims are decoded but their
|
|
69
|
+
* authenticity is not checked at all. Strictly an interop /
|
|
70
|
+
* test-harness escape hatch for verifiers whose signing keys
|
|
71
|
+
* are pre-shared out-of-band and not published in any in-band
|
|
72
|
+
* channel (e.g. EUDI's reference verifier in `pre-registered`
|
|
73
|
+
* mode, which embeds `kid: "access_certificate"` referencing a
|
|
74
|
+
* keystore inside the verifier container with no JWKS endpoint).
|
|
75
|
+
*
|
|
76
|
+
* Production wallets MUST leave this off. Tampered Request
|
|
77
|
+
* Objects bypass detection when this flag is set. The other
|
|
78
|
+
* binding checks (`urlClientId` ↔ signed `client_id`) still run
|
|
79
|
+
* because they're integrity checks against the host-supplied
|
|
80
|
+
* URL, not against the JWS signature.
|
|
81
|
+
*/
|
|
82
|
+
unsafeSkipRequestObjectSignatureVerification?: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Fetch-and-verify a signed OpenID4VP Authorization Request Object.
|
|
86
|
+
*
|
|
87
|
+
* Returns the canonical {@link AuthorizationRequest} shape built from
|
|
88
|
+
* the verified JWS payload. On any failure — fetch, decode, signature,
|
|
89
|
+
* trust-anchor — throws {@link RequestObjectError} with a stable code.
|
|
90
|
+
*/
|
|
91
|
+
export declare const verifyAndDecodeRequestObject: (opts: VerifyRequestObjectOptions) => Promise<AuthorizationRequest>;
|
|
92
|
+
/**
|
|
93
|
+
* Built-in DID resolver covering the two methods wallet-side holder
|
|
94
|
+
* traffic most often uses: `did:jwk` (keys inline in the identifier)
|
|
95
|
+
* and `did:web` (DID docs over HTTPS). Other methods should be handled
|
|
96
|
+
* via the caller's `didResolver` override.
|
|
97
|
+
*/
|
|
98
|
+
export declare const builtInDidResolver: (fetchImpl?: typeof fetch | undefined) => DidResolver;
|
|
99
|
+
//# sourceMappingURL=request-object.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-object.d.ts","sourceRoot":"","sources":["../../src/vp/request-object.ts"],"names":[],"mappings":"AAwCA,OAAO,EAAoC,GAAG,EAAE,MAAM,MAAM,CAAC;AAE7D,OAAO,EACH,oBAAoB,EAGvB,MAAM,SAAS,CAAC;AAYjB,MAAM,MAAM,sBAAsB,GAC5B,wBAAwB,GACxB,sBAAsB,GACtB,0BAA0B,GAC1B,8BAA8B,GAC9B,oBAAoB,GACpB,2BAA2B,GAC3B,0BAA0B,GAC1B,uBAAuB,GACvB,sBAAsB,CAAC;AAE7B,qBAAa,kBAAmB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;gBAGlC,IAAI,EAAE,sBAAsB,EAC5B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CASpC;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,kBAAkB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC1C,cAAc,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,kBAAkB,CAAC,CAAC;IACpD,eAAe,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,kBAAkB,CAAC,CAAC;CACxD;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;AAEhE,MAAM,WAAW,0BAA0B;IACvC,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,wFAAwF;IACxF,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAEzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAE1B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAErC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;;;;;;;;;;;;;;OAeG;IACH,4CAA4C,CAAC,EAAE,OAAO,CAAC;CAC1D;AAMD;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,SAC/B,0BAA0B,KACjC,OAAO,CAAC,oBAAoB,CAwG9B,CAAC;AA0fF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,eAChB,OAAO,KAAK,GAAG,SAAS,KACpC,WAaF,CAAC"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { DescriptorMatch } from './pex';
|
|
2
|
+
import { PresentationDefinition } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Given the holder's full credential pool and a verifier's Presentation
|
|
5
|
+
* Definition, figure out which credentials are eligible to satisfy each
|
|
6
|
+
* `input_descriptor`, whether the overall submission is possible, and
|
|
7
|
+
* produce a ready-to-serialize PresentationSubmission skeleton.
|
|
8
|
+
*
|
|
9
|
+
* This is the "preview" half of the OID4VP flow: the UI shows the user
|
|
10
|
+
* the candidates returned here, they pick one per descriptor, and Slice
|
|
11
|
+
* 7 builds + signs the actual `vp_token` using those selections.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* A single credential paired with its inferred / declared format id.
|
|
15
|
+
* Callers always pass in strings they've indexed themselves; we never
|
|
16
|
+
* attempt to decrypt or verify the credential here.
|
|
17
|
+
*/
|
|
18
|
+
export interface CandidateCredential {
|
|
19
|
+
/** The raw credential value — a JSON-LD object for ldp_vc or a compact JWT string for jwt_vc_json. */
|
|
20
|
+
credential: unknown;
|
|
21
|
+
/** Credential format id. Inferred via {@link inferCredentialFormat} when omitted. */
|
|
22
|
+
format?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Caller-provided identifier (URI, DB row id, etc.) used when
|
|
25
|
+
* building audit logs and when binding selections back to storage.
|
|
26
|
+
* Not part of the DIF PEX spec — ours alone.
|
|
27
|
+
*/
|
|
28
|
+
id?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface DescriptorCandidate {
|
|
31
|
+
descriptorId: string;
|
|
32
|
+
candidate: CandidateCredential;
|
|
33
|
+
match: DescriptorMatch;
|
|
34
|
+
/**
|
|
35
|
+
* Absolute position in the caller's original `candidates` array.
|
|
36
|
+
* Lets callers reconstruct their own state without string-matching.
|
|
37
|
+
*/
|
|
38
|
+
candidateIndex: number;
|
|
39
|
+
}
|
|
40
|
+
export interface DescriptorSelection {
|
|
41
|
+
descriptorId: string;
|
|
42
|
+
/** Candidates that satisfied every required field + format constraint. */
|
|
43
|
+
candidates: DescriptorCandidate[];
|
|
44
|
+
/** Reason this descriptor has zero candidates (when applicable). */
|
|
45
|
+
reason?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface SelectionResult {
|
|
48
|
+
/** One entry per input_descriptor, in the PD's declared order. */
|
|
49
|
+
descriptors: DescriptorSelection[];
|
|
50
|
+
/**
|
|
51
|
+
* `true` when the Presentation Definition's submission requirements
|
|
52
|
+
* (or, if none, all descriptors) can be satisfied by the candidate
|
|
53
|
+
* pool. UIs use this to disable the "Share" button up front.
|
|
54
|
+
*/
|
|
55
|
+
canSatisfy: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Human-readable reason shown to the user when `canSatisfy` is
|
|
58
|
+
* false. Example: `"The verifier requires a UniversityDegree
|
|
59
|
+
* credential and you don't have one."`
|
|
60
|
+
*/
|
|
61
|
+
reason?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* DIF PEX v2 Presentation Submission — what the wallet returns inside
|
|
65
|
+
* the vp_token to tell the verifier which VC answered which descriptor.
|
|
66
|
+
*/
|
|
67
|
+
export interface PresentationSubmission {
|
|
68
|
+
id: string;
|
|
69
|
+
definition_id: string;
|
|
70
|
+
descriptor_map: PresentationSubmissionDescriptor[];
|
|
71
|
+
}
|
|
72
|
+
export interface PresentationSubmissionDescriptor {
|
|
73
|
+
id: string;
|
|
74
|
+
format: string;
|
|
75
|
+
path: string;
|
|
76
|
+
path_nested?: PresentationSubmissionDescriptor;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Input to {@link buildPresentationSubmission}: the user's per-descriptor
|
|
80
|
+
* selection, along with the VP-internal path where the chosen VC will
|
|
81
|
+
* appear (typically `$.verifiableCredential[N]`).
|
|
82
|
+
*/
|
|
83
|
+
export interface SelectedDescriptor {
|
|
84
|
+
descriptorId: string;
|
|
85
|
+
format: string;
|
|
86
|
+
/**
|
|
87
|
+
* JSONPath inside the outer vp_token where the credential will sit.
|
|
88
|
+
* For a JSON-LD VP: `$.verifiableCredential[0]`.
|
|
89
|
+
* For a JWT VP wrapping JSON-LD VCs: `$.vp.verifiableCredential[0]`.
|
|
90
|
+
*/
|
|
91
|
+
path: string;
|
|
92
|
+
/**
|
|
93
|
+
* JSONPath inside a nested envelope. For jwt_vc_json credentials
|
|
94
|
+
* embedded in a JSON-LD VP: `$` (the VC JWT is the whole value).
|
|
95
|
+
* Only set when the credential is itself a wrapped envelope (JWT).
|
|
96
|
+
*/
|
|
97
|
+
pathNested?: string;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Run the holder's candidate pool against every input_descriptor in the
|
|
101
|
+
* PD. Each candidate must pass (a) any format constraint declared on
|
|
102
|
+
* the descriptor (or, if the descriptor has none, on the PD itself),
|
|
103
|
+
* and (b) every required field in `constraints.fields[]`.
|
|
104
|
+
*
|
|
105
|
+
* The result preserves the PD's declared descriptor order so UIs can
|
|
106
|
+
* render "one row per descriptor".
|
|
107
|
+
*/
|
|
108
|
+
export declare const selectCredentials: (candidates: CandidateCredential[], pd: PresentationDefinition) => SelectionResult;
|
|
109
|
+
/**
|
|
110
|
+
* Build a DIF PEX v2 Presentation Submission descriptor map. The
|
|
111
|
+
* caller is responsible for ordering selections (and computing the
|
|
112
|
+
* `path` into their final vp_token shape) so this function is purely
|
|
113
|
+
* a well-typed assembler — it never rearranges, never substitutes, and
|
|
114
|
+
* never validates the selection against the PD.
|
|
115
|
+
*
|
|
116
|
+
* The `definition_id` must come from the original PD to satisfy
|
|
117
|
+
* verifiers that cross-check the submission.
|
|
118
|
+
*/
|
|
119
|
+
export declare const buildPresentationSubmission: (pd: PresentationDefinition, selections: SelectedDescriptor[], options?: {
|
|
120
|
+
submissionId?: string;
|
|
121
|
+
makeId?: () => string;
|
|
122
|
+
}) => PresentationSubmission;
|
|
123
|
+
/**
|
|
124
|
+
* Best-effort inference of the credential format id from the value's
|
|
125
|
+
* shape. Covers the two formats we've exercised end-to-end:
|
|
126
|
+
*
|
|
127
|
+
* - **`jwt_vc_json`** — compact JWS string (three base64url segments
|
|
128
|
+
* separated by `.`), OR a decoded VC whose `proof.type ===
|
|
129
|
+
* 'JwtProof2020'` (the shape WaltID returns).
|
|
130
|
+
* - **`ldp_vc`** — a JSON-LD VC with a Data Integrity / JCS / legacy
|
|
131
|
+
* `proof.type` (Ed25519Signature2020, DataIntegrityProof, etc.).
|
|
132
|
+
*
|
|
133
|
+
* Unknown shapes fall through to the caller-default `undefined`, which
|
|
134
|
+
* surfaces in the selection pipeline as "no format declared".
|
|
135
|
+
*/
|
|
136
|
+
export declare const inferCredentialFormat: (credential: unknown) => string | undefined;
|
|
137
|
+
//# sourceMappingURL=select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../src/vp/select.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,eAAe,EAAE,MAAM,OAAO,CAAC;AAC9D,OAAO,EAGH,sBAAsB,EAEzB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;GASG;AAMH;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAChC,sGAAsG;IACtG,UAAU,EAAE,OAAO,CAAC;IACpB,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,mBAAmB,CAAC;IAC/B,KAAK,EAAE,eAAe,CAAC;IACvB;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC5B,kEAAkE;IAClE,WAAW,EAAE,mBAAmB,EAAE,CAAC;IAEnC;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;IAEpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,gCAAgC,EAAE,CAAC;CACtD;AAED,MAAM,WAAW,gCAAgC;IAC7C,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,gCAAgC,CAAC;CAClD;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,eACd,mBAAmB,EAAE,MAC7B,sBAAsB,KAC3B,eAwDF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,OAChC,sBAAsB,cACd,kBAAkB,EAAE,YACvB;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,MAAM,CAAA;CAAE,KAC1D,sBAwBF,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,eAAgB,OAAO,KAAG,MAAM,GAAG,SAwBpE,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { UnsignedVP, VP } from '@learncard/types';
|
|
2
|
+
import { ProofJwtSigner } from '../vci/types';
|
|
3
|
+
import { VpFormat } from './present';
|
|
4
|
+
/**
|
|
5
|
+
* Slice 7b — **Verifiable Presentation signing**.
|
|
6
|
+
*
|
|
7
|
+
* Takes the unsigned VP produced by {@link buildPresentation} and turns
|
|
8
|
+
* it into a signed `vp_token` ready for Slice 7c's `direct_post`
|
|
9
|
+
* transport. Two envelope formats are supported, matching
|
|
10
|
+
* {@link VpFormat}:
|
|
11
|
+
*
|
|
12
|
+
* - **`jwt_vp_json`** — wrap the VP as a JWT per VCDM §6.3.1:
|
|
13
|
+
* - `iss` = holder DID
|
|
14
|
+
* - `sub` = holder DID (VCDM §6.3.1.1 — "identifier of the
|
|
15
|
+
* expected holder")
|
|
16
|
+
* - `aud` = verifier's `client_id` (from the OID4VP Authorization
|
|
17
|
+
* Request)
|
|
18
|
+
* - `nonce` = verifier's nonce (replay-binding)
|
|
19
|
+
* - `jti` = VP id
|
|
20
|
+
* - `iat` = now (epoch seconds)
|
|
21
|
+
* - `vp` = the unsigned VP JSON
|
|
22
|
+
* The JWS is signed with the holder's {@link ProofJwtSigner} — the
|
|
23
|
+
* same interface the VCI proof-of-possession path uses.
|
|
24
|
+
*
|
|
25
|
+
* - **`ldp_vp`** — delegate to the host's Linked-Data proof pipeline.
|
|
26
|
+
* The plugin wires this to `learnCard.invoke.issuePresentation` in
|
|
27
|
+
* Slice 7c, passing `domain = audience` and `challenge = nonce` per
|
|
28
|
+
* OID4VP §6.1 so the verifier can detect replay.
|
|
29
|
+
*
|
|
30
|
+
* Pure + dependency-injected: this module never talks to the network
|
|
31
|
+
* and never accesses LearnCard directly. Tests supply trivial mock
|
|
32
|
+
* signers; the plugin supplies real ones.
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* The vp_token value ready for OID4VP `direct_post`:
|
|
36
|
+
*
|
|
37
|
+
* - `string` — compact JWS (used for `jwt_vp_json`).
|
|
38
|
+
* - `VP` — signed JSON-LD VP object (used for `ldp_vp`).
|
|
39
|
+
*
|
|
40
|
+
* The transport layer (Slice 7c) serializes these two shapes
|
|
41
|
+
* uniformly: both go into `application/x-www-form-urlencoded` as the
|
|
42
|
+
* `vp_token` field, with JSON objects JSON-stringified first.
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
45
|
+
* Wire-shape of the OID4VP `vp_token` form field across BOTH query
|
|
46
|
+
* languages:
|
|
47
|
+
*
|
|
48
|
+
* - `string` — PEX `jwt_vp_json` compact JWS, OR a single DCQL entry
|
|
49
|
+
* that's a `jwt_vc_json` presentation.
|
|
50
|
+
* - `VP` — PEX `ldp_vp` signed VP object.
|
|
51
|
+
* - `Record<string, string | VP>` — DCQL response object keyed by
|
|
52
|
+
* `credential_query_id` (OID4VP 1.0 §6.4); values are
|
|
53
|
+
* per-query signed presentations.
|
|
54
|
+
*
|
|
55
|
+
* The submit layer JSON-encodes whichever non-string variant arrives
|
|
56
|
+
* before form-urlencoding it.
|
|
57
|
+
*/
|
|
58
|
+
export type VpToken = string | VP | Record<string, string | VP>;
|
|
59
|
+
/**
|
|
60
|
+
* Linked-Data VP signer contract. The plugin binds this to
|
|
61
|
+
* `learnCard.invoke.issuePresentation`, passing through OID4VP's
|
|
62
|
+
* replay-binding via `domain`/`challenge`.
|
|
63
|
+
*/
|
|
64
|
+
export interface LdpVpSigner {
|
|
65
|
+
sign: (unsignedVp: UnsignedVP, options: {
|
|
66
|
+
domain: string;
|
|
67
|
+
challenge: string;
|
|
68
|
+
}) => Promise<VP>;
|
|
69
|
+
}
|
|
70
|
+
export interface SignPresentationOptions {
|
|
71
|
+
/** Unsigned VP from {@link buildPresentation}. */
|
|
72
|
+
unsignedVp: UnsignedVP;
|
|
73
|
+
/** Envelope format from {@link buildPresentation}. */
|
|
74
|
+
vpFormat: VpFormat;
|
|
75
|
+
/**
|
|
76
|
+
* Verifier's `client_id` (from the Authorization Request). For
|
|
77
|
+
* `jwt_vp_json` this becomes the JWT `aud`; for `ldp_vp` it
|
|
78
|
+
* becomes the LD-proof `domain`.
|
|
79
|
+
*/
|
|
80
|
+
audience: string;
|
|
81
|
+
/**
|
|
82
|
+
* Verifier's `nonce` (from the Authorization Request). For
|
|
83
|
+
* `jwt_vp_json` this becomes the JWT `nonce`; for `ldp_vp` it
|
|
84
|
+
* becomes the LD-proof `challenge`.
|
|
85
|
+
*/
|
|
86
|
+
nonce: string;
|
|
87
|
+
/**
|
|
88
|
+
* Holder DID. Must equal `unsignedVp.holder`; we re-validate to
|
|
89
|
+
* prevent the signer from silently signing a VP whose holder
|
|
90
|
+
* field was tampered with between construction and signing.
|
|
91
|
+
*/
|
|
92
|
+
holder: string;
|
|
93
|
+
/** Override the JWT `jti`. Defaults to `unsignedVp.id`. */
|
|
94
|
+
jti?: string;
|
|
95
|
+
/** Override `iat` for deterministic tests. Defaults to `Math.floor(Date.now() / 1000)`. */
|
|
96
|
+
iat?: number;
|
|
97
|
+
}
|
|
98
|
+
export interface SignPresentationHelpers {
|
|
99
|
+
/** Required when `vpFormat === 'jwt_vp_json'`. */
|
|
100
|
+
jwtSigner?: ProofJwtSigner;
|
|
101
|
+
/** Required when `vpFormat === 'ldp_vp'`. */
|
|
102
|
+
ldpVpSigner?: LdpVpSigner;
|
|
103
|
+
}
|
|
104
|
+
export interface SignPresentationResult {
|
|
105
|
+
vpToken: VpToken;
|
|
106
|
+
vpFormat: VpFormat;
|
|
107
|
+
}
|
|
108
|
+
export type VpSignErrorCode = 'missing_jwt_signer' | 'missing_ldp_signer' | 'jwt_sign_failed' | 'ldp_sign_failed' | 'holder_mismatch' | 'invalid_input';
|
|
109
|
+
export declare class VpSignError extends Error {
|
|
110
|
+
readonly code: VpSignErrorCode;
|
|
111
|
+
constructor(code: VpSignErrorCode, message: string, options?: {
|
|
112
|
+
cause?: unknown;
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Sign a prepared Verifiable Presentation. See module doc for
|
|
117
|
+
* envelope semantics.
|
|
118
|
+
*
|
|
119
|
+
* All cryptographic work happens inside the injected signer(s) —
|
|
120
|
+
* unsupported combinations (e.g. `jwt_vp_json` with no `jwtSigner`)
|
|
121
|
+
* throw `VpSignError` with a typed code so callers can surface
|
|
122
|
+
* actionable UI instead of a generic "signing failed".
|
|
123
|
+
*/
|
|
124
|
+
export declare const signPresentation: (options: SignPresentationOptions, helpers: SignPresentationHelpers) => Promise<SignPresentationResult>;
|
|
125
|
+
//# sourceMappingURL=sign.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../../src/vp/sign.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAMH;;;;;;;;;GASG;AACH;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC;AAEhE;;;;GAIG;AACH,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,CACF,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,KAC7C,OAAO,CAAC,EAAE,CAAC,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACpC,kDAAkD;IAClD,UAAU,EAAE,UAAU,CAAC;IAEvB,sDAAsD;IACtD,QAAQ,EAAE,QAAQ,CAAC;IAEnB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,2FAA2F;IAC3F,GAAG,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,uBAAuB;IACpC,kDAAkD;IAClD,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,6CAA6C;IAC7C,WAAW,CAAC,EAAE,WAAW,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;CACtB;AAMD,MAAM,MAAM,eAAe,GACrB,oBAAoB,GACpB,oBAAoB,GACpB,iBAAiB,GACjB,iBAAiB,GACjB,iBAAiB,GACjB,eAAe,CAAC;AAEtB,qBAAa,WAAY,SAAQ,KAAK;IAClC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;gBAEnB,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAQpF;AAMD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,YAChB,uBAAuB,WACvB,uBAAuB,KACjC,OAAO,CAAC,sBAAsB,CAQhC,CAAC"}
|