@animo-id/eudi-wallet-functionality 0.0.0-alpha-20250603091506
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/dist/index.d.mts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +244 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +207 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +57 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AgentContext } from '@credo-ts/core';
|
|
2
|
+
import { OpenId4VpResolvedAuthorizationRequest } from '@credo-ts/openid4vc';
|
|
3
|
+
|
|
4
|
+
type VerifyAuthorizationRequestOptions = {
|
|
5
|
+
resolvedAuthorizationRequest: OpenId4VpResolvedAuthorizationRequest;
|
|
6
|
+
trustedCertificates?: Array<string>;
|
|
7
|
+
allowUntrustedSigned?: boolean;
|
|
8
|
+
};
|
|
9
|
+
declare const verifyOpenid4VpAuthorizationRequest: (agentContext: AgentContext, { resolvedAuthorizationRequest: { authorizationRequestPayload, signedAuthorizationRequest, dcql }, trustedCertificates, allowUntrustedSigned, }: VerifyAuthorizationRequestOptions) => Promise<{
|
|
10
|
+
isValidButUntrusted: boolean;
|
|
11
|
+
isValidAndTrusted: boolean;
|
|
12
|
+
}[] | undefined>;
|
|
13
|
+
|
|
14
|
+
export { verifyOpenid4VpAuthorizationRequest };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AgentContext } from '@credo-ts/core';
|
|
2
|
+
import { OpenId4VpResolvedAuthorizationRequest } from '@credo-ts/openid4vc';
|
|
3
|
+
|
|
4
|
+
type VerifyAuthorizationRequestOptions = {
|
|
5
|
+
resolvedAuthorizationRequest: OpenId4VpResolvedAuthorizationRequest;
|
|
6
|
+
trustedCertificates?: Array<string>;
|
|
7
|
+
allowUntrustedSigned?: boolean;
|
|
8
|
+
};
|
|
9
|
+
declare const verifyOpenid4VpAuthorizationRequest: (agentContext: AgentContext, { resolvedAuthorizationRequest: { authorizationRequestPayload, signedAuthorizationRequest, dcql }, trustedCertificates, allowUntrustedSigned, }: VerifyAuthorizationRequestOptions) => Promise<{
|
|
10
|
+
isValidButUntrusted: boolean;
|
|
11
|
+
isValidAndTrusted: boolean;
|
|
12
|
+
}[] | undefined>;
|
|
13
|
+
|
|
14
|
+
export { verifyOpenid4VpAuthorizationRequest };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
verifyOpenid4VpAuthorizationRequest: () => verifyOpenid4VpAuthorizationRequest
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
|
|
37
|
+
// src/verifyOpenid4VpAuthorizationRequest.ts
|
|
38
|
+
var import_core2 = require("@credo-ts/core");
|
|
39
|
+
var import_zod = __toESM(require("zod"));
|
|
40
|
+
|
|
41
|
+
// src/isDcqlQueryEqualOrSubset.ts
|
|
42
|
+
var import_core = require("@credo-ts/core");
|
|
43
|
+
function isDcqlQueryEqualOrSubset(arq, rcq) {
|
|
44
|
+
if (rcq.credential_sets) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (rcq.credentials.some((c) => c.id)) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
if (arq.credentials.some((c) => c.format !== "mso_mdoc" && c.format !== "vc+sd-jwt" && c.format !== "dc+sd-jwt")) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
credentialQueryLoop: for (const credentialQuery of arq.credentials) {
|
|
54
|
+
const matchingRcqCredentialQueriesBasedOnFormat = rcq.credentials.filter((c) => c.format === credentialQuery.format);
|
|
55
|
+
if (matchingRcqCredentialQueriesBasedOnFormat.length === 0) return false;
|
|
56
|
+
switch (credentialQuery.format) {
|
|
57
|
+
case "mso_mdoc": {
|
|
58
|
+
const doctypeValue = credentialQuery.meta?.doctype_value;
|
|
59
|
+
if (!doctypeValue) return false;
|
|
60
|
+
if (typeof credentialQuery.meta?.doctype_value !== "string") return false;
|
|
61
|
+
const foundMatchingRequests = matchingRcqCredentialQueriesBasedOnFormat.filter(
|
|
62
|
+
(c) => !!(c.format === "mso_mdoc" && c.meta && c.meta.doctype_value === doctypeValue)
|
|
63
|
+
);
|
|
64
|
+
if (foundMatchingRequests.length === 0) return false;
|
|
65
|
+
let foundFullyMatching = false;
|
|
66
|
+
for (const matchedRequest of foundMatchingRequests) {
|
|
67
|
+
if (!matchedRequest.claims) continue credentialQueryLoop;
|
|
68
|
+
if (!credentialQuery.claims) continue credentialQueryLoop;
|
|
69
|
+
const isEveryClaimAllowedToBeRequested = credentialQuery.claims.every(
|
|
70
|
+
(c) => "path" in c && matchedRequest.claims?.some(
|
|
71
|
+
(mrc) => "path" in mrc && c.path[0] === mrc.path[0] && c.path[1] === mrc.path[1]
|
|
72
|
+
)
|
|
73
|
+
);
|
|
74
|
+
if (isEveryClaimAllowedToBeRequested) {
|
|
75
|
+
foundFullyMatching = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!foundFullyMatching) return false;
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case "dc+sd-jwt":
|
|
82
|
+
case "vc+sd-jwt": {
|
|
83
|
+
const vctValues = credentialQuery.meta?.vct_values;
|
|
84
|
+
if (!vctValues) return false;
|
|
85
|
+
if (credentialQuery.meta?.vct_values?.length === 0) return false;
|
|
86
|
+
const foundMatchingRequests = matchingRcqCredentialQueriesBasedOnFormat.filter(
|
|
87
|
+
(c) => !!((c.format === "dc+sd-jwt" || c.format === "vc+sd-jwt") && c.meta?.vct_values && (0, import_core.equalsIgnoreOrder)(c.meta.vct_values, vctValues))
|
|
88
|
+
);
|
|
89
|
+
if (foundMatchingRequests.length === 0) return false;
|
|
90
|
+
let foundFullyMatching = false;
|
|
91
|
+
for (const matchedRequest of foundMatchingRequests) {
|
|
92
|
+
if (!matchedRequest.claims) continue credentialQueryLoop;
|
|
93
|
+
if (!credentialQuery.claims) continue credentialQueryLoop;
|
|
94
|
+
const isEveryClaimAllowedToBeRequested = credentialQuery.claims.every(
|
|
95
|
+
(c) => "path" in c && matchedRequest.claims?.some((mrc) => "path" in mrc && (0, import_core.equalsWithOrder)(c.path, mrc.path))
|
|
96
|
+
);
|
|
97
|
+
if (isEveryClaimAllowedToBeRequested) {
|
|
98
|
+
foundFullyMatching = true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (!foundFullyMatching) return false;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
default:
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/verifyOpenid4VpAuthorizationRequest.ts
|
|
112
|
+
var verifyOpenid4VpAuthorizationRequest = async (agentContext, {
|
|
113
|
+
resolvedAuthorizationRequest: { authorizationRequestPayload, signedAuthorizationRequest, dcql },
|
|
114
|
+
trustedCertificates,
|
|
115
|
+
allowUntrustedSigned
|
|
116
|
+
}) => {
|
|
117
|
+
const results = [];
|
|
118
|
+
if (!authorizationRequestPayload.verifier_attestations) return;
|
|
119
|
+
for (const va of authorizationRequestPayload.verifier_attestations) {
|
|
120
|
+
if (va.format === "jwt") {
|
|
121
|
+
if (typeof va.data !== "string") {
|
|
122
|
+
throw new Error("Only inline JWTs are supported");
|
|
123
|
+
}
|
|
124
|
+
const jwsService = agentContext.resolve(import_core2.JwsService);
|
|
125
|
+
let isValidButUntrusted = false;
|
|
126
|
+
let isValidAndTrusted = false;
|
|
127
|
+
const jwt = import_core2.Jwt.fromSerializedJwt(va.data);
|
|
128
|
+
try {
|
|
129
|
+
const { isValid } = await jwsService.verifyJws(agentContext, {
|
|
130
|
+
jws: va.data,
|
|
131
|
+
trustedCertificates
|
|
132
|
+
});
|
|
133
|
+
isValidAndTrusted = isValid;
|
|
134
|
+
} catch {
|
|
135
|
+
if (allowUntrustedSigned) {
|
|
136
|
+
const { isValid } = await jwsService.verifyJws(agentContext, {
|
|
137
|
+
jws: va.data,
|
|
138
|
+
trustedCertificates: jwt.header.x5c ?? []
|
|
139
|
+
});
|
|
140
|
+
isValidButUntrusted = isValid;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (jwt.header.typ !== "rc-rp+jwt") {
|
|
144
|
+
throw new Error(`only 'rc-rp+jwt' is supported as header typ. Request included: ${jwt.header.typ}`);
|
|
145
|
+
}
|
|
146
|
+
if (!signedAuthorizationRequest) {
|
|
147
|
+
throw new Error("Request must be signed for the registration certificate");
|
|
148
|
+
}
|
|
149
|
+
if (signedAuthorizationRequest.signer.method !== "x5c") {
|
|
150
|
+
throw new Error("x5c is only supported for registration certificate");
|
|
151
|
+
}
|
|
152
|
+
const registrationCertificateHeaderSchema = import_zod.default.object({
|
|
153
|
+
typ: import_zod.default.literal("rc-rp+jwt"),
|
|
154
|
+
alg: import_zod.default.string(),
|
|
155
|
+
// sprin-d did not define this
|
|
156
|
+
x5u: import_zod.default.string().url().optional(),
|
|
157
|
+
// sprin-d did not define this
|
|
158
|
+
"x5t#s256": import_zod.default.string().optional()
|
|
159
|
+
}).passthrough();
|
|
160
|
+
const registrationCertificatePayloadSchema = import_zod.default.object({
|
|
161
|
+
credentials: import_zod.default.array(
|
|
162
|
+
import_zod.default.object({
|
|
163
|
+
format: import_zod.default.string(),
|
|
164
|
+
multiple: import_zod.default.boolean().default(false),
|
|
165
|
+
meta: import_zod.default.object({
|
|
166
|
+
vct_values: import_zod.default.array(import_zod.default.string()).optional(),
|
|
167
|
+
doctype_value: import_zod.default.string().optional()
|
|
168
|
+
}).optional(),
|
|
169
|
+
trusted_authorities: import_zod.default.array(import_zod.default.object({ type: import_zod.default.string(), values: import_zod.default.array(import_zod.default.string()) })).nonempty().optional(),
|
|
170
|
+
require_cryptographic_holder_binding: import_zod.default.boolean().default(true),
|
|
171
|
+
claims: import_zod.default.array(
|
|
172
|
+
import_zod.default.object({
|
|
173
|
+
id: import_zod.default.string().optional(),
|
|
174
|
+
path: import_zod.default.array(import_zod.default.string()).nonempty().nonempty(),
|
|
175
|
+
values: import_zod.default.array(import_zod.default.number().or(import_zod.default.boolean())).optional()
|
|
176
|
+
})
|
|
177
|
+
).nonempty().optional(),
|
|
178
|
+
claim_sets: import_zod.default.array(import_zod.default.array(import_zod.default.string())).nonempty().optional()
|
|
179
|
+
})
|
|
180
|
+
),
|
|
181
|
+
contact: import_zod.default.object({
|
|
182
|
+
website: import_zod.default.string().url(),
|
|
183
|
+
"e-mail": import_zod.default.string().email(),
|
|
184
|
+
phone: import_zod.default.string()
|
|
185
|
+
}),
|
|
186
|
+
sub: import_zod.default.string(),
|
|
187
|
+
// Should be service
|
|
188
|
+
services: import_zod.default.array(import_zod.default.object({ lang: import_zod.default.string(), name: import_zod.default.string() })),
|
|
189
|
+
public_body: import_zod.default.boolean().default(false),
|
|
190
|
+
entitlements: import_zod.default.array(import_zod.default.any()),
|
|
191
|
+
provided_attestations: import_zod.default.array(
|
|
192
|
+
import_zod.default.object({
|
|
193
|
+
format: import_zod.default.string(),
|
|
194
|
+
meta: import_zod.default.any()
|
|
195
|
+
})
|
|
196
|
+
).optional(),
|
|
197
|
+
privacy_policy: import_zod.default.string().url(),
|
|
198
|
+
iat: import_zod.default.number().optional(),
|
|
199
|
+
exp: import_zod.default.number().optional(),
|
|
200
|
+
purpose: import_zod.default.array(
|
|
201
|
+
import_zod.default.object({
|
|
202
|
+
locale: import_zod.default.string().optional(),
|
|
203
|
+
lang: import_zod.default.string().optional(),
|
|
204
|
+
name: import_zod.default.string()
|
|
205
|
+
})
|
|
206
|
+
).optional(),
|
|
207
|
+
status: import_zod.default.any()
|
|
208
|
+
}).passthrough();
|
|
209
|
+
registrationCertificateHeaderSchema.parse(jwt.header);
|
|
210
|
+
const parsedPayload = registrationCertificatePayloadSchema.parse(jwt.payload.toJson());
|
|
211
|
+
const [rpCertEncoded] = signedAuthorizationRequest.signer.x5c;
|
|
212
|
+
const rpCert = import_core2.X509Certificate.fromEncodedCertificate(rpCertEncoded);
|
|
213
|
+
if (rpCert.subject !== parsedPayload.sub) {
|
|
214
|
+
throw new Error(
|
|
215
|
+
`Subject in the certificate of the auth request: '${rpCert.subject}' is not equal to the subject of the registration certificate: '${parsedPayload.sub}'`
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
if (parsedPayload.iat && (/* @__PURE__ */ new Date()).getTime() / 1e3 <= parsedPayload.iat) {
|
|
219
|
+
throw new Error("Issued at timestamp of the registration certificate is in the future");
|
|
220
|
+
}
|
|
221
|
+
if (!dcql) {
|
|
222
|
+
throw new Error("DCQL must be used when working registration certificates");
|
|
223
|
+
}
|
|
224
|
+
if (authorizationRequestPayload.presentation_definition || authorizationRequestPayload.presentation_definition_uri) {
|
|
225
|
+
throw new Error("Presentation Exchange is not supported for the registration certificate");
|
|
226
|
+
}
|
|
227
|
+
const isValidDcqlQuery = isDcqlQueryEqualOrSubset(dcql.queryResult, parsedPayload);
|
|
228
|
+
if (!isValidDcqlQuery) {
|
|
229
|
+
throw new Error(
|
|
230
|
+
"DCQL query in the authorization request is not equal or a valid subset of the DCQl query provided in the registration certificate"
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
results.push({ isValidButUntrusted, isValidAndTrusted });
|
|
234
|
+
} else {
|
|
235
|
+
throw new Error(`only format of 'jwt' is supported`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return results;
|
|
239
|
+
};
|
|
240
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
241
|
+
0 && (module.exports = {
|
|
242
|
+
verifyOpenid4VpAuthorizationRequest
|
|
243
|
+
});
|
|
244
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/verifyOpenid4VpAuthorizationRequest.ts","../src/isDcqlQueryEqualOrSubset.ts"],"sourcesContent":["export { verifyOpenid4VpAuthorizationRequest } from './verifyOpenid4VpAuthorizationRequest'\n","import { allowedNodeEnvironmentFlags } from 'node:process'\nimport { type AgentContext, type DcqlQuery, JwsService, Jwt, X509Certificate } from '@credo-ts/core'\nimport type { OpenId4VpResolvedAuthorizationRequest } from '@credo-ts/openid4vc'\nimport z from 'zod'\nimport { isDcqlQueryEqualOrSubset } from './isDcqlQueryEqualOrSubset'\n\nexport type VerifyAuthorizationRequestOptions = {\n resolvedAuthorizationRequest: OpenId4VpResolvedAuthorizationRequest\n trustedCertificates?: Array<string>\n allowUntrustedSigned?: boolean\n}\n\nexport const verifyOpenid4VpAuthorizationRequest = async (\n agentContext: AgentContext,\n {\n resolvedAuthorizationRequest: { authorizationRequestPayload, signedAuthorizationRequest, dcql },\n trustedCertificates,\n allowUntrustedSigned,\n }: VerifyAuthorizationRequestOptions\n) => {\n const results = []\n if (!authorizationRequestPayload.verifier_attestations) return\n for (const va of authorizationRequestPayload.verifier_attestations) {\n // Here we verify it as a registration certificate according to\n // https://bmi.usercontent.opencode.de/eudi-wallet/eidas-2.0-architekturkonzept/flows/Wallet-Relying-Party-Authentication/#registration-certificate\n if (va.format === 'jwt') {\n if (typeof va.data !== 'string') {\n throw new Error('Only inline JWTs are supported')\n }\n\n const jwsService = agentContext.resolve(JwsService)\n\n let isValidButUntrusted = false\n let isValidAndTrusted = false\n\n const jwt = Jwt.fromSerializedJwt(va.data)\n\n try {\n const { isValid } = await jwsService.verifyJws(agentContext, {\n jws: va.data,\n trustedCertificates,\n })\n isValidAndTrusted = isValid\n } catch {\n if (allowUntrustedSigned) {\n const { isValid } = await jwsService.verifyJws(agentContext, {\n jws: va.data,\n trustedCertificates: jwt.header.x5c ?? [],\n })\n isValidButUntrusted = isValid\n }\n }\n\n if (jwt.header.typ !== 'rc-rp+jwt') {\n throw new Error(`only 'rc-rp+jwt' is supported as header typ. Request included: ${jwt.header.typ}`)\n }\n\n if (!signedAuthorizationRequest) {\n throw new Error('Request must be signed for the registration certificate')\n }\n\n if (signedAuthorizationRequest.signer.method !== 'x5c') {\n throw new Error('x5c is only supported for registration certificate')\n }\n\n const registrationCertificateHeaderSchema = z\n .object({\n typ: z.literal('rc-rp+jwt'),\n alg: z.string(),\n // sprin-d did not define this\n x5u: z.string().url().optional(),\n // sprin-d did not define this\n 'x5t#s256': z.string().optional(),\n })\n .passthrough()\n\n // TODO: does not support intermediaries\n const registrationCertificatePayloadSchema = z\n .object({\n credentials: z.array(\n z.object({\n format: z.string(),\n multiple: z.boolean().default(false),\n meta: z\n .object({\n vct_values: z.array(z.string()).optional(),\n doctype_value: z.string().optional(),\n })\n .optional(),\n trusted_authorities: z\n .array(z.object({ type: z.string(), values: z.array(z.string()) }))\n .nonempty()\n .optional(),\n require_cryptographic_holder_binding: z.boolean().default(true),\n claims: z\n .array(\n z.object({\n id: z.string().optional(),\n path: z.array(z.string()).nonempty().nonempty(),\n values: z.array(z.number().or(z.boolean())).optional(),\n })\n )\n .nonempty()\n .optional(),\n claim_sets: z.array(z.array(z.string())).nonempty().optional(),\n })\n ),\n contact: z.object({\n website: z.string().url(),\n 'e-mail': z.string().email(),\n phone: z.string(),\n }),\n sub: z.string(),\n // Should be service\n services: z.array(z.object({ lang: z.string(), name: z.string() })),\n public_body: z.boolean().default(false),\n entitlements: z.array(z.any()),\n provided_attestations: z\n .array(\n z.object({\n format: z.string(),\n meta: z.any(),\n })\n )\n .optional(),\n privacy_policy: z.string().url(),\n iat: z.number().optional(),\n exp: z.number().optional(),\n purpose: z\n .array(\n z.object({\n locale: z.string().optional(),\n lang: z.string().optional(),\n name: z.string(),\n })\n )\n .optional(),\n status: z.any(),\n })\n .passthrough()\n\n registrationCertificateHeaderSchema.parse(jwt.header)\n const parsedPayload = registrationCertificatePayloadSchema.parse(jwt.payload.toJson())\n\n const [rpCertEncoded] = signedAuthorizationRequest.signer.x5c\n const rpCert = X509Certificate.fromEncodedCertificate(rpCertEncoded)\n\n if (rpCert.subject !== parsedPayload.sub) {\n throw new Error(\n `Subject in the certificate of the auth request: '${rpCert.subject}' is not equal to the subject of the registration certificate: '${parsedPayload.sub}'`\n )\n }\n\n if (parsedPayload.iat && new Date().getTime() / 1000 <= parsedPayload.iat) {\n throw new Error('Issued at timestamp of the registration certificate is in the future')\n }\n\n // TODO: check the status of the registration certificate\n\n if (!dcql) {\n throw new Error('DCQL must be used when working registration certificates')\n }\n\n if (\n authorizationRequestPayload.presentation_definition ||\n authorizationRequestPayload.presentation_definition_uri\n ) {\n throw new Error('Presentation Exchange is not supported for the registration certificate')\n }\n\n const isValidDcqlQuery = isDcqlQueryEqualOrSubset(dcql.queryResult, parsedPayload as unknown as DcqlQuery)\n\n if (!isValidDcqlQuery) {\n throw new Error(\n 'DCQL query in the authorization request is not equal or a valid subset of the DCQl query provided in the registration certificate'\n )\n }\n\n results.push({ isValidButUntrusted, isValidAndTrusted })\n } else {\n throw new Error(`only format of 'jwt' is supported`)\n }\n }\n return results\n}\n","import { type DcqlQuery, equalsIgnoreOrder, equalsWithOrder } from '@credo-ts/core'\n\nexport function isDcqlQueryEqualOrSubset(arq: DcqlQuery, rcq: DcqlQuery): boolean {\n if (rcq.credential_sets) {\n return false\n }\n\n if (rcq.credentials.some((c) => c.id)) {\n return false\n }\n\n // only sd-jwt and mdoc are supported\n if (arq.credentials.some((c) => c.format !== 'mso_mdoc' && c.format !== 'vc+sd-jwt' && c.format !== 'dc+sd-jwt')) {\n return false\n }\n\n credentialQueryLoop: for (const credentialQuery of arq.credentials) {\n const matchingRcqCredentialQueriesBasedOnFormat = rcq.credentials.filter((c) => c.format === credentialQuery.format)\n\n if (matchingRcqCredentialQueriesBasedOnFormat.length === 0) return false\n\n switch (credentialQuery.format) {\n case 'mso_mdoc': {\n const doctypeValue = credentialQuery.meta?.doctype_value\n if (!doctypeValue) return false\n if (typeof credentialQuery.meta?.doctype_value !== 'string') return false\n\n const foundMatchingRequests = matchingRcqCredentialQueriesBasedOnFormat.filter(\n (c): c is typeof c & { format: 'mso_mdoc' } =>\n !!(c.format === 'mso_mdoc' && c.meta && c.meta.doctype_value === doctypeValue)\n )\n\n // We do not know which one we have to pick based on the meta+format\n if (foundMatchingRequests.length === 0) return false\n\n let foundFullyMatching = false\n for (const matchedRequest of foundMatchingRequests) {\n // credentialQuery.claims must match or be subset of matchedRequest\n\n // If the claims is empty, everything within the specific format+meta is allowed\n if (!matchedRequest.claims) continue credentialQueryLoop\n\n // If no specific claims are request, we allow it as the format+meta is allowed to be requested\n // but this requests no additional claims\n if (!credentialQuery.claims) continue credentialQueryLoop\n\n // Every claim request in the authorization request must be found in the registration certificate\n // for mdoc, this means matching the `path[0]` (namespace) and `path[1]` (value name)\n const isEveryClaimAllowedToBeRequested = credentialQuery.claims.every(\n (c) =>\n 'path' in c &&\n matchedRequest.claims?.some(\n (mrc) => 'path' in mrc && c.path[0] === mrc.path[0] && c.path[1] === mrc.path[1]\n )\n )\n if (isEveryClaimAllowedToBeRequested) {\n foundFullyMatching = true\n }\n }\n\n if (!foundFullyMatching) return false\n\n break\n }\n case 'dc+sd-jwt':\n case 'vc+sd-jwt': {\n const vctValues = credentialQuery.meta?.vct_values\n if (!vctValues) return false\n if (credentialQuery.meta?.vct_values?.length === 0) return false\n\n const foundMatchingRequests = matchingRcqCredentialQueriesBasedOnFormat.filter(\n (c): c is typeof c & ({ format: 'dc+sd-jwt' } | { format: 'vc+sd-jwt' }) =>\n !!(\n (c.format === 'dc+sd-jwt' || c.format === 'vc+sd-jwt') &&\n c.meta?.vct_values &&\n equalsIgnoreOrder(c.meta.vct_values, vctValues)\n )\n )\n\n // We do not know which one we have to pick based on the meta+format\n if (foundMatchingRequests.length === 0) return false\n\n let foundFullyMatching = false\n for (const matchedRequest of foundMatchingRequests) {\n // credentialQuery.claims must match or be subset of matchedRequest\n\n // If the claims is empty, everything within the specific format+meta is allowed\n if (!matchedRequest.claims) continue credentialQueryLoop\n\n // If no specific claims are request, we allow it as the format+meta is allowed to be requested\n // but this requests no additional claims\n if (!credentialQuery.claims) continue credentialQueryLoop\n\n // Every claim request in the authorization request must be found in the registration certificate\n // for sd-jwt, this means making sure that every `path[n]` is in the registration certificate\n const isEveryClaimAllowedToBeRequested = credentialQuery.claims.every(\n (c) =>\n 'path' in c && matchedRequest.claims?.some((mrc) => 'path' in mrc && equalsWithOrder(c.path, mrc.path))\n )\n if (isEveryClaimAllowedToBeRequested) {\n foundFullyMatching = true\n }\n }\n\n if (!foundFullyMatching) return false\n\n break\n }\n default:\n return false\n }\n }\n\n return true\n}\n"],"mappings":"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","names":["import_core","z"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// src/verifyOpenid4VpAuthorizationRequest.ts
|
|
2
|
+
import { JwsService, Jwt, X509Certificate } from "@credo-ts/core";
|
|
3
|
+
import z from "zod";
|
|
4
|
+
|
|
5
|
+
// src/isDcqlQueryEqualOrSubset.ts
|
|
6
|
+
import { equalsIgnoreOrder, equalsWithOrder } from "@credo-ts/core";
|
|
7
|
+
function isDcqlQueryEqualOrSubset(arq, rcq) {
|
|
8
|
+
if (rcq.credential_sets) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
if (rcq.credentials.some((c) => c.id)) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (arq.credentials.some((c) => c.format !== "mso_mdoc" && c.format !== "vc+sd-jwt" && c.format !== "dc+sd-jwt")) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
credentialQueryLoop: for (const credentialQuery of arq.credentials) {
|
|
18
|
+
const matchingRcqCredentialQueriesBasedOnFormat = rcq.credentials.filter((c) => c.format === credentialQuery.format);
|
|
19
|
+
if (matchingRcqCredentialQueriesBasedOnFormat.length === 0) return false;
|
|
20
|
+
switch (credentialQuery.format) {
|
|
21
|
+
case "mso_mdoc": {
|
|
22
|
+
const doctypeValue = credentialQuery.meta?.doctype_value;
|
|
23
|
+
if (!doctypeValue) return false;
|
|
24
|
+
if (typeof credentialQuery.meta?.doctype_value !== "string") return false;
|
|
25
|
+
const foundMatchingRequests = matchingRcqCredentialQueriesBasedOnFormat.filter(
|
|
26
|
+
(c) => !!(c.format === "mso_mdoc" && c.meta && c.meta.doctype_value === doctypeValue)
|
|
27
|
+
);
|
|
28
|
+
if (foundMatchingRequests.length === 0) return false;
|
|
29
|
+
let foundFullyMatching = false;
|
|
30
|
+
for (const matchedRequest of foundMatchingRequests) {
|
|
31
|
+
if (!matchedRequest.claims) continue credentialQueryLoop;
|
|
32
|
+
if (!credentialQuery.claims) continue credentialQueryLoop;
|
|
33
|
+
const isEveryClaimAllowedToBeRequested = credentialQuery.claims.every(
|
|
34
|
+
(c) => "path" in c && matchedRequest.claims?.some(
|
|
35
|
+
(mrc) => "path" in mrc && c.path[0] === mrc.path[0] && c.path[1] === mrc.path[1]
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
if (isEveryClaimAllowedToBeRequested) {
|
|
39
|
+
foundFullyMatching = true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!foundFullyMatching) return false;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
case "dc+sd-jwt":
|
|
46
|
+
case "vc+sd-jwt": {
|
|
47
|
+
const vctValues = credentialQuery.meta?.vct_values;
|
|
48
|
+
if (!vctValues) return false;
|
|
49
|
+
if (credentialQuery.meta?.vct_values?.length === 0) return false;
|
|
50
|
+
const foundMatchingRequests = matchingRcqCredentialQueriesBasedOnFormat.filter(
|
|
51
|
+
(c) => !!((c.format === "dc+sd-jwt" || c.format === "vc+sd-jwt") && c.meta?.vct_values && equalsIgnoreOrder(c.meta.vct_values, vctValues))
|
|
52
|
+
);
|
|
53
|
+
if (foundMatchingRequests.length === 0) return false;
|
|
54
|
+
let foundFullyMatching = false;
|
|
55
|
+
for (const matchedRequest of foundMatchingRequests) {
|
|
56
|
+
if (!matchedRequest.claims) continue credentialQueryLoop;
|
|
57
|
+
if (!credentialQuery.claims) continue credentialQueryLoop;
|
|
58
|
+
const isEveryClaimAllowedToBeRequested = credentialQuery.claims.every(
|
|
59
|
+
(c) => "path" in c && matchedRequest.claims?.some((mrc) => "path" in mrc && equalsWithOrder(c.path, mrc.path))
|
|
60
|
+
);
|
|
61
|
+
if (isEveryClaimAllowedToBeRequested) {
|
|
62
|
+
foundFullyMatching = true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (!foundFullyMatching) return false;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
default:
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/verifyOpenid4VpAuthorizationRequest.ts
|
|
76
|
+
var verifyOpenid4VpAuthorizationRequest = async (agentContext, {
|
|
77
|
+
resolvedAuthorizationRequest: { authorizationRequestPayload, signedAuthorizationRequest, dcql },
|
|
78
|
+
trustedCertificates,
|
|
79
|
+
allowUntrustedSigned
|
|
80
|
+
}) => {
|
|
81
|
+
const results = [];
|
|
82
|
+
if (!authorizationRequestPayload.verifier_attestations) return;
|
|
83
|
+
for (const va of authorizationRequestPayload.verifier_attestations) {
|
|
84
|
+
if (va.format === "jwt") {
|
|
85
|
+
if (typeof va.data !== "string") {
|
|
86
|
+
throw new Error("Only inline JWTs are supported");
|
|
87
|
+
}
|
|
88
|
+
const jwsService = agentContext.resolve(JwsService);
|
|
89
|
+
let isValidButUntrusted = false;
|
|
90
|
+
let isValidAndTrusted = false;
|
|
91
|
+
const jwt = Jwt.fromSerializedJwt(va.data);
|
|
92
|
+
try {
|
|
93
|
+
const { isValid } = await jwsService.verifyJws(agentContext, {
|
|
94
|
+
jws: va.data,
|
|
95
|
+
trustedCertificates
|
|
96
|
+
});
|
|
97
|
+
isValidAndTrusted = isValid;
|
|
98
|
+
} catch {
|
|
99
|
+
if (allowUntrustedSigned) {
|
|
100
|
+
const { isValid } = await jwsService.verifyJws(agentContext, {
|
|
101
|
+
jws: va.data,
|
|
102
|
+
trustedCertificates: jwt.header.x5c ?? []
|
|
103
|
+
});
|
|
104
|
+
isValidButUntrusted = isValid;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (jwt.header.typ !== "rc-rp+jwt") {
|
|
108
|
+
throw new Error(`only 'rc-rp+jwt' is supported as header typ. Request included: ${jwt.header.typ}`);
|
|
109
|
+
}
|
|
110
|
+
if (!signedAuthorizationRequest) {
|
|
111
|
+
throw new Error("Request must be signed for the registration certificate");
|
|
112
|
+
}
|
|
113
|
+
if (signedAuthorizationRequest.signer.method !== "x5c") {
|
|
114
|
+
throw new Error("x5c is only supported for registration certificate");
|
|
115
|
+
}
|
|
116
|
+
const registrationCertificateHeaderSchema = z.object({
|
|
117
|
+
typ: z.literal("rc-rp+jwt"),
|
|
118
|
+
alg: z.string(),
|
|
119
|
+
// sprin-d did not define this
|
|
120
|
+
x5u: z.string().url().optional(),
|
|
121
|
+
// sprin-d did not define this
|
|
122
|
+
"x5t#s256": z.string().optional()
|
|
123
|
+
}).passthrough();
|
|
124
|
+
const registrationCertificatePayloadSchema = z.object({
|
|
125
|
+
credentials: z.array(
|
|
126
|
+
z.object({
|
|
127
|
+
format: z.string(),
|
|
128
|
+
multiple: z.boolean().default(false),
|
|
129
|
+
meta: z.object({
|
|
130
|
+
vct_values: z.array(z.string()).optional(),
|
|
131
|
+
doctype_value: z.string().optional()
|
|
132
|
+
}).optional(),
|
|
133
|
+
trusted_authorities: z.array(z.object({ type: z.string(), values: z.array(z.string()) })).nonempty().optional(),
|
|
134
|
+
require_cryptographic_holder_binding: z.boolean().default(true),
|
|
135
|
+
claims: z.array(
|
|
136
|
+
z.object({
|
|
137
|
+
id: z.string().optional(),
|
|
138
|
+
path: z.array(z.string()).nonempty().nonempty(),
|
|
139
|
+
values: z.array(z.number().or(z.boolean())).optional()
|
|
140
|
+
})
|
|
141
|
+
).nonempty().optional(),
|
|
142
|
+
claim_sets: z.array(z.array(z.string())).nonempty().optional()
|
|
143
|
+
})
|
|
144
|
+
),
|
|
145
|
+
contact: z.object({
|
|
146
|
+
website: z.string().url(),
|
|
147
|
+
"e-mail": z.string().email(),
|
|
148
|
+
phone: z.string()
|
|
149
|
+
}),
|
|
150
|
+
sub: z.string(),
|
|
151
|
+
// Should be service
|
|
152
|
+
services: z.array(z.object({ lang: z.string(), name: z.string() })),
|
|
153
|
+
public_body: z.boolean().default(false),
|
|
154
|
+
entitlements: z.array(z.any()),
|
|
155
|
+
provided_attestations: z.array(
|
|
156
|
+
z.object({
|
|
157
|
+
format: z.string(),
|
|
158
|
+
meta: z.any()
|
|
159
|
+
})
|
|
160
|
+
).optional(),
|
|
161
|
+
privacy_policy: z.string().url(),
|
|
162
|
+
iat: z.number().optional(),
|
|
163
|
+
exp: z.number().optional(),
|
|
164
|
+
purpose: z.array(
|
|
165
|
+
z.object({
|
|
166
|
+
locale: z.string().optional(),
|
|
167
|
+
lang: z.string().optional(),
|
|
168
|
+
name: z.string()
|
|
169
|
+
})
|
|
170
|
+
).optional(),
|
|
171
|
+
status: z.any()
|
|
172
|
+
}).passthrough();
|
|
173
|
+
registrationCertificateHeaderSchema.parse(jwt.header);
|
|
174
|
+
const parsedPayload = registrationCertificatePayloadSchema.parse(jwt.payload.toJson());
|
|
175
|
+
const [rpCertEncoded] = signedAuthorizationRequest.signer.x5c;
|
|
176
|
+
const rpCert = X509Certificate.fromEncodedCertificate(rpCertEncoded);
|
|
177
|
+
if (rpCert.subject !== parsedPayload.sub) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`Subject in the certificate of the auth request: '${rpCert.subject}' is not equal to the subject of the registration certificate: '${parsedPayload.sub}'`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
if (parsedPayload.iat && (/* @__PURE__ */ new Date()).getTime() / 1e3 <= parsedPayload.iat) {
|
|
183
|
+
throw new Error("Issued at timestamp of the registration certificate is in the future");
|
|
184
|
+
}
|
|
185
|
+
if (!dcql) {
|
|
186
|
+
throw new Error("DCQL must be used when working registration certificates");
|
|
187
|
+
}
|
|
188
|
+
if (authorizationRequestPayload.presentation_definition || authorizationRequestPayload.presentation_definition_uri) {
|
|
189
|
+
throw new Error("Presentation Exchange is not supported for the registration certificate");
|
|
190
|
+
}
|
|
191
|
+
const isValidDcqlQuery = isDcqlQueryEqualOrSubset(dcql.queryResult, parsedPayload);
|
|
192
|
+
if (!isValidDcqlQuery) {
|
|
193
|
+
throw new Error(
|
|
194
|
+
"DCQL query in the authorization request is not equal or a valid subset of the DCQl query provided in the registration certificate"
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
results.push({ isValidButUntrusted, isValidAndTrusted });
|
|
198
|
+
} else {
|
|
199
|
+
throw new Error(`only format of 'jwt' is supported`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return results;
|
|
203
|
+
};
|
|
204
|
+
export {
|
|
205
|
+
verifyOpenid4VpAuthorizationRequest
|
|
206
|
+
};
|
|
207
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/verifyOpenid4VpAuthorizationRequest.ts","../src/isDcqlQueryEqualOrSubset.ts"],"sourcesContent":["import { allowedNodeEnvironmentFlags } from 'node:process'\nimport { type AgentContext, type DcqlQuery, JwsService, Jwt, X509Certificate } from '@credo-ts/core'\nimport type { OpenId4VpResolvedAuthorizationRequest } from '@credo-ts/openid4vc'\nimport z from 'zod'\nimport { isDcqlQueryEqualOrSubset } from './isDcqlQueryEqualOrSubset'\n\nexport type VerifyAuthorizationRequestOptions = {\n resolvedAuthorizationRequest: OpenId4VpResolvedAuthorizationRequest\n trustedCertificates?: Array<string>\n allowUntrustedSigned?: boolean\n}\n\nexport const verifyOpenid4VpAuthorizationRequest = async (\n agentContext: AgentContext,\n {\n resolvedAuthorizationRequest: { authorizationRequestPayload, signedAuthorizationRequest, dcql },\n trustedCertificates,\n allowUntrustedSigned,\n }: VerifyAuthorizationRequestOptions\n) => {\n const results = []\n if (!authorizationRequestPayload.verifier_attestations) return\n for (const va of authorizationRequestPayload.verifier_attestations) {\n // Here we verify it as a registration certificate according to\n // https://bmi.usercontent.opencode.de/eudi-wallet/eidas-2.0-architekturkonzept/flows/Wallet-Relying-Party-Authentication/#registration-certificate\n if (va.format === 'jwt') {\n if (typeof va.data !== 'string') {\n throw new Error('Only inline JWTs are supported')\n }\n\n const jwsService = agentContext.resolve(JwsService)\n\n let isValidButUntrusted = false\n let isValidAndTrusted = false\n\n const jwt = Jwt.fromSerializedJwt(va.data)\n\n try {\n const { isValid } = await jwsService.verifyJws(agentContext, {\n jws: va.data,\n trustedCertificates,\n })\n isValidAndTrusted = isValid\n } catch {\n if (allowUntrustedSigned) {\n const { isValid } = await jwsService.verifyJws(agentContext, {\n jws: va.data,\n trustedCertificates: jwt.header.x5c ?? [],\n })\n isValidButUntrusted = isValid\n }\n }\n\n if (jwt.header.typ !== 'rc-rp+jwt') {\n throw new Error(`only 'rc-rp+jwt' is supported as header typ. Request included: ${jwt.header.typ}`)\n }\n\n if (!signedAuthorizationRequest) {\n throw new Error('Request must be signed for the registration certificate')\n }\n\n if (signedAuthorizationRequest.signer.method !== 'x5c') {\n throw new Error('x5c is only supported for registration certificate')\n }\n\n const registrationCertificateHeaderSchema = z\n .object({\n typ: z.literal('rc-rp+jwt'),\n alg: z.string(),\n // sprin-d did not define this\n x5u: z.string().url().optional(),\n // sprin-d did not define this\n 'x5t#s256': z.string().optional(),\n })\n .passthrough()\n\n // TODO: does not support intermediaries\n const registrationCertificatePayloadSchema = z\n .object({\n credentials: z.array(\n z.object({\n format: z.string(),\n multiple: z.boolean().default(false),\n meta: z\n .object({\n vct_values: z.array(z.string()).optional(),\n doctype_value: z.string().optional(),\n })\n .optional(),\n trusted_authorities: z\n .array(z.object({ type: z.string(), values: z.array(z.string()) }))\n .nonempty()\n .optional(),\n require_cryptographic_holder_binding: z.boolean().default(true),\n claims: z\n .array(\n z.object({\n id: z.string().optional(),\n path: z.array(z.string()).nonempty().nonempty(),\n values: z.array(z.number().or(z.boolean())).optional(),\n })\n )\n .nonempty()\n .optional(),\n claim_sets: z.array(z.array(z.string())).nonempty().optional(),\n })\n ),\n contact: z.object({\n website: z.string().url(),\n 'e-mail': z.string().email(),\n phone: z.string(),\n }),\n sub: z.string(),\n // Should be service\n services: z.array(z.object({ lang: z.string(), name: z.string() })),\n public_body: z.boolean().default(false),\n entitlements: z.array(z.any()),\n provided_attestations: z\n .array(\n z.object({\n format: z.string(),\n meta: z.any(),\n })\n )\n .optional(),\n privacy_policy: z.string().url(),\n iat: z.number().optional(),\n exp: z.number().optional(),\n purpose: z\n .array(\n z.object({\n locale: z.string().optional(),\n lang: z.string().optional(),\n name: z.string(),\n })\n )\n .optional(),\n status: z.any(),\n })\n .passthrough()\n\n registrationCertificateHeaderSchema.parse(jwt.header)\n const parsedPayload = registrationCertificatePayloadSchema.parse(jwt.payload.toJson())\n\n const [rpCertEncoded] = signedAuthorizationRequest.signer.x5c\n const rpCert = X509Certificate.fromEncodedCertificate(rpCertEncoded)\n\n if (rpCert.subject !== parsedPayload.sub) {\n throw new Error(\n `Subject in the certificate of the auth request: '${rpCert.subject}' is not equal to the subject of the registration certificate: '${parsedPayload.sub}'`\n )\n }\n\n if (parsedPayload.iat && new Date().getTime() / 1000 <= parsedPayload.iat) {\n throw new Error('Issued at timestamp of the registration certificate is in the future')\n }\n\n // TODO: check the status of the registration certificate\n\n if (!dcql) {\n throw new Error('DCQL must be used when working registration certificates')\n }\n\n if (\n authorizationRequestPayload.presentation_definition ||\n authorizationRequestPayload.presentation_definition_uri\n ) {\n throw new Error('Presentation Exchange is not supported for the registration certificate')\n }\n\n const isValidDcqlQuery = isDcqlQueryEqualOrSubset(dcql.queryResult, parsedPayload as unknown as DcqlQuery)\n\n if (!isValidDcqlQuery) {\n throw new Error(\n 'DCQL query in the authorization request is not equal or a valid subset of the DCQl query provided in the registration certificate'\n )\n }\n\n results.push({ isValidButUntrusted, isValidAndTrusted })\n } else {\n throw new Error(`only format of 'jwt' is supported`)\n }\n }\n return results\n}\n","import { type DcqlQuery, equalsIgnoreOrder, equalsWithOrder } from '@credo-ts/core'\n\nexport function isDcqlQueryEqualOrSubset(arq: DcqlQuery, rcq: DcqlQuery): boolean {\n if (rcq.credential_sets) {\n return false\n }\n\n if (rcq.credentials.some((c) => c.id)) {\n return false\n }\n\n // only sd-jwt and mdoc are supported\n if (arq.credentials.some((c) => c.format !== 'mso_mdoc' && c.format !== 'vc+sd-jwt' && c.format !== 'dc+sd-jwt')) {\n return false\n }\n\n credentialQueryLoop: for (const credentialQuery of arq.credentials) {\n const matchingRcqCredentialQueriesBasedOnFormat = rcq.credentials.filter((c) => c.format === credentialQuery.format)\n\n if (matchingRcqCredentialQueriesBasedOnFormat.length === 0) return false\n\n switch (credentialQuery.format) {\n case 'mso_mdoc': {\n const doctypeValue = credentialQuery.meta?.doctype_value\n if (!doctypeValue) return false\n if (typeof credentialQuery.meta?.doctype_value !== 'string') return false\n\n const foundMatchingRequests = matchingRcqCredentialQueriesBasedOnFormat.filter(\n (c): c is typeof c & { format: 'mso_mdoc' } =>\n !!(c.format === 'mso_mdoc' && c.meta && c.meta.doctype_value === doctypeValue)\n )\n\n // We do not know which one we have to pick based on the meta+format\n if (foundMatchingRequests.length === 0) return false\n\n let foundFullyMatching = false\n for (const matchedRequest of foundMatchingRequests) {\n // credentialQuery.claims must match or be subset of matchedRequest\n\n // If the claims is empty, everything within the specific format+meta is allowed\n if (!matchedRequest.claims) continue credentialQueryLoop\n\n // If no specific claims are request, we allow it as the format+meta is allowed to be requested\n // but this requests no additional claims\n if (!credentialQuery.claims) continue credentialQueryLoop\n\n // Every claim request in the authorization request must be found in the registration certificate\n // for mdoc, this means matching the `path[0]` (namespace) and `path[1]` (value name)\n const isEveryClaimAllowedToBeRequested = credentialQuery.claims.every(\n (c) =>\n 'path' in c &&\n matchedRequest.claims?.some(\n (mrc) => 'path' in mrc && c.path[0] === mrc.path[0] && c.path[1] === mrc.path[1]\n )\n )\n if (isEveryClaimAllowedToBeRequested) {\n foundFullyMatching = true\n }\n }\n\n if (!foundFullyMatching) return false\n\n break\n }\n case 'dc+sd-jwt':\n case 'vc+sd-jwt': {\n const vctValues = credentialQuery.meta?.vct_values\n if (!vctValues) return false\n if (credentialQuery.meta?.vct_values?.length === 0) return false\n\n const foundMatchingRequests = matchingRcqCredentialQueriesBasedOnFormat.filter(\n (c): c is typeof c & ({ format: 'dc+sd-jwt' } | { format: 'vc+sd-jwt' }) =>\n !!(\n (c.format === 'dc+sd-jwt' || c.format === 'vc+sd-jwt') &&\n c.meta?.vct_values &&\n equalsIgnoreOrder(c.meta.vct_values, vctValues)\n )\n )\n\n // We do not know which one we have to pick based on the meta+format\n if (foundMatchingRequests.length === 0) return false\n\n let foundFullyMatching = false\n for (const matchedRequest of foundMatchingRequests) {\n // credentialQuery.claims must match or be subset of matchedRequest\n\n // If the claims is empty, everything within the specific format+meta is allowed\n if (!matchedRequest.claims) continue credentialQueryLoop\n\n // If no specific claims are request, we allow it as the format+meta is allowed to be requested\n // but this requests no additional claims\n if (!credentialQuery.claims) continue credentialQueryLoop\n\n // Every claim request in the authorization request must be found in the registration certificate\n // for sd-jwt, this means making sure that every `path[n]` is in the registration certificate\n const isEveryClaimAllowedToBeRequested = credentialQuery.claims.every(\n (c) =>\n 'path' in c && matchedRequest.claims?.some((mrc) => 'path' in mrc && equalsWithOrder(c.path, mrc.path))\n )\n if (isEveryClaimAllowedToBeRequested) {\n foundFullyMatching = true\n }\n }\n\n if (!foundFullyMatching) return false\n\n break\n }\n default:\n return false\n }\n }\n\n return true\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@animo-id/eudi-wallet-functionality",
|
|
3
|
+
"description": "EUDI Wallet Functionality",
|
|
4
|
+
"version": "0.0.0-alpha-20250603091506",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "Animo Solutions",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.mjs",
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/animo/eudi-wallet-functionality"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@credo-ts/core": "*",
|
|
27
|
+
"@credo-ts/openid4vc": "*"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@biomejs/biome": "^1.9.4",
|
|
31
|
+
"@changesets/cli": "^2.29.4",
|
|
32
|
+
"@credo-ts/askar": "0.6.0-alpha-20250602122957",
|
|
33
|
+
"@credo-ts/core": "0.6.0-alpha-20250602122957",
|
|
34
|
+
"@credo-ts/node": "0.6.0-alpha-20250602122957",
|
|
35
|
+
"@credo-ts/openid4vc": "0.6.0-alpha-20250602122957",
|
|
36
|
+
"@openwallet-foundation/askar-nodejs": "^0.3.2",
|
|
37
|
+
"@types/node": "^22.15.29",
|
|
38
|
+
"tsup": "^8.5.0",
|
|
39
|
+
"tsx": "^4.19.4",
|
|
40
|
+
"typescript": "~5.8.3"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"zod": "^3.25.42"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"types:check": "tsc --noEmit",
|
|
47
|
+
"style:check": "biome check --unsafe",
|
|
48
|
+
"style:fix": "biome check --write --unsafe",
|
|
49
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean --sourcemap",
|
|
50
|
+
"test": "node --import tsx --test tests/*.test.ts",
|
|
51
|
+
"release": "pnpm build && pnpm changeset publish --no-git-tag",
|
|
52
|
+
"changeset-version": "pnpm changeset version && pnpm style:fix"
|
|
53
|
+
},
|
|
54
|
+
"main": "./dist/index.js",
|
|
55
|
+
"module": "./dist/index.mjs",
|
|
56
|
+
"types": "./dist/index.d.ts"
|
|
57
|
+
}
|