@twin.org/federated-catalogue-service 0.0.1-next.10
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 +201 -0
- package/README.md +21 -0
- package/dist/cjs/index.cjs +2122 -0
- package/dist/esm/index.mjs +2104 -0
- package/dist/types/entities/dataResourceEntry.d.ts +59 -0
- package/dist/types/entities/dataSpaceConnectorEntry.d.ts +66 -0
- package/dist/types/entities/participantEntry.d.ts +42 -0
- package/dist/types/entities/serviceOfferingEntry.d.ts +55 -0
- package/dist/types/federatedCatalogueRoutes.d.ts +113 -0
- package/dist/types/federatedCatalogueService.d.ts +142 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/models/IFederatedCatalogueServiceConfig.d.ts +15 -0
- package/dist/types/models/IFederatedCatalogueServiceConstructorOptions.d.ts +38 -0
- package/dist/types/restEntryPoints.d.ts +2 -0
- package/dist/types/schema.d.ts +4 -0
- package/dist/types/verification/complianceCredentialVerificationService.d.ts +32 -0
- package/docs/changelog.md +143 -0
- package/docs/examples.md +1 -0
- package/docs/open-api/spec.json +3434 -0
- package/docs/reference/classes/DataResourceEntry.md +118 -0
- package/docs/reference/classes/DataSpaceConnectorEntry.md +133 -0
- package/docs/reference/classes/FederatedCatalogueService.md +389 -0
- package/docs/reference/classes/ParticipantEntry.md +85 -0
- package/docs/reference/classes/ServiceOfferingEntry.md +109 -0
- package/docs/reference/functions/complianceCredentialPresentation.md +37 -0
- package/docs/reference/functions/dataResourceCredentialPresentation.md +37 -0
- package/docs/reference/functions/dataResourceGet.md +31 -0
- package/docs/reference/functions/dataResourceList.md +31 -0
- package/docs/reference/functions/dataSpaceConnectorCredentialPresentation.md +37 -0
- package/docs/reference/functions/dataSpaceConnectorGet.md +31 -0
- package/docs/reference/functions/dataSpaceConnectorList.md +31 -0
- package/docs/reference/functions/generateRestRoutesFederatedCatalogue.md +25 -0
- package/docs/reference/functions/initSchema.md +9 -0
- package/docs/reference/functions/participantGet.md +31 -0
- package/docs/reference/functions/participantList.md +31 -0
- package/docs/reference/functions/serviceOfferingCredentialPresentation.md +37 -0
- package/docs/reference/functions/serviceOfferingGet.md +31 -0
- package/docs/reference/functions/serviceOfferingList.md +31 -0
- package/docs/reference/index.md +36 -0
- package/docs/reference/interfaces/IFederatedCatalogueServiceConfig.md +21 -0
- package/docs/reference/interfaces/IFederatedCatalogueServiceConstructorOptions.md +83 -0
- package/docs/reference/variables/restEntryPoints.md +3 -0
- package/docs/reference/variables/tagsFederatedCatalogue.md +5 -0
- package/locales/en.json +21 -0
- package/package.json +52 -0
|
@@ -0,0 +1,2104 @@
|
|
|
1
|
+
import { Guards, ComponentFactory, Coerce, Is, ObjectHelper, JsonHelper, Converter, UnprocessableError, StringHelper, GeneralError, NotFoundError, ArrayHelper } from '@twin.org/core';
|
|
2
|
+
import { FederatedCatalogueContextInstances, FederatedCatalogueTypes, VerificationFailureReasons } from '@twin.org/federated-catalogue-models';
|
|
3
|
+
import { GaiaXTypes } from '@twin.org/standards-gaia-x';
|
|
4
|
+
import { SchemaOrgTypes, SchemaOrgDataTypes } from '@twin.org/standards-schema-org';
|
|
5
|
+
import { MimeTypes, HttpStatusCode, FetchHelper } from '@twin.org/web';
|
|
6
|
+
import { JsonLdProcessor } from '@twin.org/data-json-ld';
|
|
7
|
+
import { ComparisonOperator, property, SortDirection, entity, EntitySchemaFactory, EntitySchemaHelper } from '@twin.org/entity';
|
|
8
|
+
import { EntityStorageConnectorFactory } from '@twin.org/entity-storage-models';
|
|
9
|
+
import { DocumentHelper, VerificationHelper } from '@twin.org/identity-models';
|
|
10
|
+
import { LoggingConnectorFactory } from '@twin.org/logging-models';
|
|
11
|
+
import { Sha256, Sha512 } from '@twin.org/crypto';
|
|
12
|
+
import { ProofHelper } from '@twin.org/standards-w3c-did';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The source used when communicating about these routes.
|
|
16
|
+
*/
|
|
17
|
+
const ROUTES_SOURCE = "federatedCatalogueRoutes";
|
|
18
|
+
/**
|
|
19
|
+
* Participants route.
|
|
20
|
+
*/
|
|
21
|
+
const PARTICIPANTS_ROUTE = "participants";
|
|
22
|
+
/**
|
|
23
|
+
* Service offering route.
|
|
24
|
+
*/
|
|
25
|
+
const SERVICE_OFFERING_ROUTE = "service-offerings";
|
|
26
|
+
/**
|
|
27
|
+
* Data Resource route.
|
|
28
|
+
*/
|
|
29
|
+
const DATA_RESOURCE_ROUTE = "data-resources";
|
|
30
|
+
/**
|
|
31
|
+
* Data Space Connector route.
|
|
32
|
+
*/
|
|
33
|
+
const DATA_SPACE_CONNECTOR_ROUTE = "data-space-connectors";
|
|
34
|
+
/**
|
|
35
|
+
* The tag to associate with the routes.
|
|
36
|
+
*/
|
|
37
|
+
const tagsFederatedCatalogue = [
|
|
38
|
+
{
|
|
39
|
+
name: "Federated Catalogue",
|
|
40
|
+
description: "Endpoints to access a Federated Catalogue."
|
|
41
|
+
}
|
|
42
|
+
];
|
|
43
|
+
/**
|
|
44
|
+
* The REST routes for Federated Catalogue.
|
|
45
|
+
* @param baseRouteName Prefix to prepend to the paths.
|
|
46
|
+
* @param factoryServiceName The name of the service to use in the routes store in the ServiceFactory.
|
|
47
|
+
* @returns The generated routes.
|
|
48
|
+
*/
|
|
49
|
+
function generateRestRoutesFederatedCatalogue(baseRouteName, factoryServiceName) {
|
|
50
|
+
const createParticipantRoute = {
|
|
51
|
+
operationId: "compliancePresentationRequest",
|
|
52
|
+
summary: "Present a Compliance Credential",
|
|
53
|
+
tag: tagsFederatedCatalogue[0].name,
|
|
54
|
+
method: "POST",
|
|
55
|
+
path: `${baseRouteName}/participant-credentials`,
|
|
56
|
+
handler: async (httpRequestContext, request) => complianceCredentialPresentation(baseRouteName, httpRequestContext, factoryServiceName, request),
|
|
57
|
+
requestType: {
|
|
58
|
+
mimeType: MimeTypes.Jwt,
|
|
59
|
+
type: "ICompliancePresentationRequest",
|
|
60
|
+
examples: [
|
|
61
|
+
{
|
|
62
|
+
id: "compliancePresentationRequestExample",
|
|
63
|
+
request: {
|
|
64
|
+
body: "ey..."
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
responseType: [
|
|
70
|
+
{
|
|
71
|
+
type: "ICreatedResponse"
|
|
72
|
+
},
|
|
73
|
+
{ type: "IUnprocessableEntityResponse" }
|
|
74
|
+
]
|
|
75
|
+
};
|
|
76
|
+
const createServiceOfferingRoute = {
|
|
77
|
+
operationId: "serviceOfferingPresentationRequest",
|
|
78
|
+
summary: "Present a Service Offering Credential",
|
|
79
|
+
tag: tagsFederatedCatalogue[0].name,
|
|
80
|
+
method: "POST",
|
|
81
|
+
path: `${baseRouteName}/service-offering-credentials`,
|
|
82
|
+
handler: async (httpRequestContext, request) => serviceOfferingCredentialPresentation(baseRouteName, httpRequestContext, factoryServiceName, request),
|
|
83
|
+
requestType: {
|
|
84
|
+
mimeType: MimeTypes.Jwt,
|
|
85
|
+
type: "ICompliancePresentationRequest",
|
|
86
|
+
examples: [
|
|
87
|
+
{
|
|
88
|
+
id: "serviceOfferingPresentationRequestExample",
|
|
89
|
+
request: {
|
|
90
|
+
body: "ey..."
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
responseType: [
|
|
96
|
+
{
|
|
97
|
+
type: "ICreatedResponse"
|
|
98
|
+
},
|
|
99
|
+
{ type: "IUnprocessableEntityResponse" }
|
|
100
|
+
]
|
|
101
|
+
};
|
|
102
|
+
const createDataSpaceConnectorRoute = {
|
|
103
|
+
operationId: "dataSpaceConnectorPresentationRequest",
|
|
104
|
+
summary: "Present a Data Space Connector Credential",
|
|
105
|
+
tag: tagsFederatedCatalogue[0].name,
|
|
106
|
+
method: "POST",
|
|
107
|
+
path: `${baseRouteName}/data-space-connector-credentials`,
|
|
108
|
+
handler: async (httpRequestContext, request) => dataSpaceConnectorCredentialPresentation(baseRouteName, httpRequestContext, factoryServiceName, request),
|
|
109
|
+
requestType: {
|
|
110
|
+
mimeType: MimeTypes.Jwt,
|
|
111
|
+
type: "ICompliancePresentationRequest",
|
|
112
|
+
examples: [
|
|
113
|
+
{
|
|
114
|
+
id: "dataSpaceConnectorPresentationRequestExample",
|
|
115
|
+
request: {
|
|
116
|
+
body: "ey..."
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
responseType: [
|
|
122
|
+
{
|
|
123
|
+
type: "ICreatedResponse"
|
|
124
|
+
},
|
|
125
|
+
{ type: "IUnprocessableEntityResponse" }
|
|
126
|
+
]
|
|
127
|
+
};
|
|
128
|
+
const createDataResourceRoute = {
|
|
129
|
+
operationId: "dataResourcePresentationRequest",
|
|
130
|
+
summary: "Present a Data Resource Credential",
|
|
131
|
+
tag: tagsFederatedCatalogue[0].name,
|
|
132
|
+
method: "POST",
|
|
133
|
+
path: `${baseRouteName}/data-resource-credentials`,
|
|
134
|
+
handler: async (httpRequestContext, request) => dataResourceCredentialPresentation(baseRouteName, httpRequestContext, factoryServiceName, request),
|
|
135
|
+
requestType: {
|
|
136
|
+
mimeType: MimeTypes.Jwt,
|
|
137
|
+
type: "ICompliancePresentationRequest",
|
|
138
|
+
examples: [
|
|
139
|
+
{
|
|
140
|
+
id: "dataResourcePresentationRequestExample",
|
|
141
|
+
request: {
|
|
142
|
+
body: "ey..."
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
},
|
|
147
|
+
responseType: [
|
|
148
|
+
{
|
|
149
|
+
type: "ICreatedResponse"
|
|
150
|
+
},
|
|
151
|
+
{ type: "IUnprocessableEntityResponse" }
|
|
152
|
+
]
|
|
153
|
+
};
|
|
154
|
+
const participantEntryExample = {
|
|
155
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY,
|
|
156
|
+
id: "did:iota:xxx",
|
|
157
|
+
type: GaiaXTypes.Participant,
|
|
158
|
+
registrationNumber: {
|
|
159
|
+
type: GaiaXTypes.LocalRegistrationNumber,
|
|
160
|
+
local: "P1234567"
|
|
161
|
+
},
|
|
162
|
+
legalName: "A Inc.",
|
|
163
|
+
issuer: "did:iota:zzz",
|
|
164
|
+
legalAddress: {
|
|
165
|
+
type: GaiaXTypes.Address,
|
|
166
|
+
countryCode: "KE"
|
|
167
|
+
},
|
|
168
|
+
validFrom: "2024-08-01T12:00:00Z",
|
|
169
|
+
validUntil: "2025-08-01T12:00:00Z",
|
|
170
|
+
dateCreated: "2024-08-02T13:45:00Z",
|
|
171
|
+
evidence: ["https://credentials.example.org/1234567"]
|
|
172
|
+
};
|
|
173
|
+
const listParticipantsRoute = {
|
|
174
|
+
operationId: "federatedCatalogueListParticipants",
|
|
175
|
+
summary: "Get a list of the participant entries",
|
|
176
|
+
tag: tagsFederatedCatalogue[0].name,
|
|
177
|
+
method: "GET",
|
|
178
|
+
path: `${baseRouteName}/${PARTICIPANTS_ROUTE}`,
|
|
179
|
+
handler: async (httpRequestContext, request) => participantList(httpRequestContext, factoryServiceName, request),
|
|
180
|
+
requestType: {
|
|
181
|
+
type: "IParticipantListRequest",
|
|
182
|
+
examples: [
|
|
183
|
+
{
|
|
184
|
+
id: "participantListRequestExample",
|
|
185
|
+
request: {
|
|
186
|
+
query: {
|
|
187
|
+
registrationNumber: "abc"
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
},
|
|
193
|
+
responseType: [
|
|
194
|
+
{
|
|
195
|
+
type: "IParticipantListResponse",
|
|
196
|
+
examples: [
|
|
197
|
+
{
|
|
198
|
+
id: "participantListResponseExample",
|
|
199
|
+
response: {
|
|
200
|
+
body: {
|
|
201
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST,
|
|
202
|
+
type: SchemaOrgTypes.ItemList,
|
|
203
|
+
itemListElement: [participantEntryExample]
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
};
|
|
211
|
+
const getParticipantRoute = {
|
|
212
|
+
operationId: "federatedCatalogueGetParticipant",
|
|
213
|
+
summary: "Get a participant",
|
|
214
|
+
tag: tagsFederatedCatalogue[0].name,
|
|
215
|
+
method: "GET",
|
|
216
|
+
path: `${baseRouteName}/${PARTICIPANTS_ROUTE}/:id`,
|
|
217
|
+
handler: async (httpRequestContext, request) => participantGet(httpRequestContext, factoryServiceName, request),
|
|
218
|
+
requestType: {
|
|
219
|
+
type: "ICatalogueEntryGetRequest",
|
|
220
|
+
examples: [
|
|
221
|
+
{
|
|
222
|
+
id: "participantGetRequestExample",
|
|
223
|
+
request: {
|
|
224
|
+
pathParams: {
|
|
225
|
+
id: "did:iota:123456"
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
]
|
|
230
|
+
},
|
|
231
|
+
responseType: [
|
|
232
|
+
{
|
|
233
|
+
type: "IParticipantGetResponse",
|
|
234
|
+
examples: [
|
|
235
|
+
{
|
|
236
|
+
id: "participantGetResponseExample",
|
|
237
|
+
response: {
|
|
238
|
+
body: participantEntryExample
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
]
|
|
242
|
+
}
|
|
243
|
+
]
|
|
244
|
+
};
|
|
245
|
+
const servicePolicyExample = {
|
|
246
|
+
"@context": [
|
|
247
|
+
"https://www.w3.org/ns/odrl/2/",
|
|
248
|
+
{
|
|
249
|
+
twin: "https://schema.twindev.org/odrl/",
|
|
250
|
+
jsonPathSelector: "twin:jsonPathSelector"
|
|
251
|
+
}
|
|
252
|
+
],
|
|
253
|
+
"@type": "Agreement",
|
|
254
|
+
uid: "http://example.com/policy:1010",
|
|
255
|
+
assigner: "did:iota:testnet:0x1a7bded4d22dc54722435d624e4323e10fcbc570cd57462eabbf3a5ab2ced24f",
|
|
256
|
+
assignee: "did:iota:testnet:0x119adb64d01d3b0fa0d308c67db90ab1c6e0df6aebe5b7e0250783f57cd10c21",
|
|
257
|
+
permission: [
|
|
258
|
+
{
|
|
259
|
+
target: {
|
|
260
|
+
type: "https://vocabulary.uncefact.org/Document",
|
|
261
|
+
refinement: {
|
|
262
|
+
leftOperand: {
|
|
263
|
+
"@id": "https://w3id.org/twin/odrl/propertyValue",
|
|
264
|
+
jsonPathSelector: ".documentTypeCode"
|
|
265
|
+
},
|
|
266
|
+
operator: "eq",
|
|
267
|
+
rightOperand: "https://vocabulary.uncefact.org/DocumentCodeList#331"
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
action: "extract"
|
|
271
|
+
}
|
|
272
|
+
]
|
|
273
|
+
};
|
|
274
|
+
const serviceOfferingEntryExample = {
|
|
275
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY,
|
|
276
|
+
id: "http://example.org/is123456",
|
|
277
|
+
name: "Service 1",
|
|
278
|
+
type: GaiaXTypes.ServiceOffering,
|
|
279
|
+
servicePolicy: [servicePolicyExample],
|
|
280
|
+
endpoint: {
|
|
281
|
+
type: GaiaXTypes.Endpoint,
|
|
282
|
+
endpointURL: "https://endpoint.example.org/api"
|
|
283
|
+
},
|
|
284
|
+
issuer: "did:iota:7890",
|
|
285
|
+
providedBy: "did:iota:1234567",
|
|
286
|
+
validFrom: "2024-08-01T12:00:00Z",
|
|
287
|
+
validUntil: "2025-08-01T12:00:00Z",
|
|
288
|
+
dateCreated: "2024-08-02T13:45:00Z",
|
|
289
|
+
evidence: ["https://credentials.example.org/1234567"]
|
|
290
|
+
};
|
|
291
|
+
const listServicesRoute = {
|
|
292
|
+
operationId: "federatedCatalogueListServices",
|
|
293
|
+
summary: "Get a list of the service entries",
|
|
294
|
+
tag: tagsFederatedCatalogue[0].name,
|
|
295
|
+
method: "GET",
|
|
296
|
+
path: `${baseRouteName}/${SERVICE_OFFERING_ROUTE}`,
|
|
297
|
+
handler: async (httpRequestContext, request) => serviceOfferingList(httpRequestContext, factoryServiceName, request),
|
|
298
|
+
requestType: {
|
|
299
|
+
type: "IServiceOfferingListRequest",
|
|
300
|
+
examples: [
|
|
301
|
+
{
|
|
302
|
+
id: "serviceOfferingListRequestExample",
|
|
303
|
+
request: {
|
|
304
|
+
query: {
|
|
305
|
+
providedBy: "did:iota:1234"
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
]
|
|
310
|
+
},
|
|
311
|
+
responseType: [
|
|
312
|
+
{
|
|
313
|
+
type: "IServiceOfferingListResponse",
|
|
314
|
+
examples: [
|
|
315
|
+
{
|
|
316
|
+
id: "serviceOfferingListResponseExample",
|
|
317
|
+
response: {
|
|
318
|
+
body: {
|
|
319
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST,
|
|
320
|
+
type: SchemaOrgTypes.ItemList,
|
|
321
|
+
itemListElement: [serviceOfferingEntryExample]
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
]
|
|
326
|
+
}
|
|
327
|
+
]
|
|
328
|
+
};
|
|
329
|
+
const getServiceRoute = {
|
|
330
|
+
operationId: "federatedCatalogueGetService",
|
|
331
|
+
summary: "Get a Service Offering entry",
|
|
332
|
+
tag: tagsFederatedCatalogue[0].name,
|
|
333
|
+
method: "GET",
|
|
334
|
+
path: `${baseRouteName}/${SERVICE_OFFERING_ROUTE}/:id`,
|
|
335
|
+
handler: async (httpRequestContext, request) => serviceOfferingGet(httpRequestContext, factoryServiceName, request),
|
|
336
|
+
requestType: {
|
|
337
|
+
type: "ICatalogueEntryGetRequest",
|
|
338
|
+
examples: [
|
|
339
|
+
{
|
|
340
|
+
id: "serviceOfferingGetRequestExample",
|
|
341
|
+
request: {
|
|
342
|
+
pathParams: {
|
|
343
|
+
id: "https://my-services.example.org/service1"
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
]
|
|
348
|
+
},
|
|
349
|
+
responseType: [
|
|
350
|
+
{
|
|
351
|
+
type: "IServiceOfferingGetResponse",
|
|
352
|
+
examples: [
|
|
353
|
+
{
|
|
354
|
+
id: "serviceOfferingGetResponseExample",
|
|
355
|
+
response: {
|
|
356
|
+
body: serviceOfferingEntryExample
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
]
|
|
360
|
+
}
|
|
361
|
+
]
|
|
362
|
+
};
|
|
363
|
+
const resourcePolicyExample = {
|
|
364
|
+
"@context": "https://www.w3.org/ns/odrl/2/",
|
|
365
|
+
"@type": "Offer",
|
|
366
|
+
uid: "http://example.com/policy:1010",
|
|
367
|
+
assigner: "did:iota:testnet:0x1a7bded4d22dc54722435d624e4323e10fcbc570cd57462eabbf3a5ab2ced24f",
|
|
368
|
+
permission: [
|
|
369
|
+
{
|
|
370
|
+
target: {
|
|
371
|
+
type: "https://vocabulary.uncefact.org/Document"
|
|
372
|
+
},
|
|
373
|
+
action: "extract"
|
|
374
|
+
}
|
|
375
|
+
]
|
|
376
|
+
};
|
|
377
|
+
const dataResourceEntryExample = {
|
|
378
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY,
|
|
379
|
+
id: "http://example.org/is123456",
|
|
380
|
+
name: "Data Resource 1",
|
|
381
|
+
type: "DataResource",
|
|
382
|
+
copyrightOwnedBy: "did:iota:1234",
|
|
383
|
+
license: "http://licenses.example.org/12345",
|
|
384
|
+
resourcePolicy: [resourcePolicyExample],
|
|
385
|
+
exposedThrough: "https://ds-connectors.example.org/ds1",
|
|
386
|
+
producedBy: "did:iota:1234567",
|
|
387
|
+
issuer: "did:iota:987654",
|
|
388
|
+
validFrom: "2024-08-01T12:00:00Z",
|
|
389
|
+
validUntil: "2025-08-01T12:00:00Z",
|
|
390
|
+
dateCreated: "2024-08-02T13:45:00Z",
|
|
391
|
+
evidence: ["https://credentials.example.org/1234567"]
|
|
392
|
+
};
|
|
393
|
+
const listDataResourcesRoute = {
|
|
394
|
+
operationId: "federatedCatalogueListResources",
|
|
395
|
+
summary: "Get a list of the data resource entries",
|
|
396
|
+
tag: tagsFederatedCatalogue[0].name,
|
|
397
|
+
method: "GET",
|
|
398
|
+
path: `${baseRouteName}/${DATA_RESOURCE_ROUTE}`,
|
|
399
|
+
handler: async (httpRequestContext, request) => dataResourceList(httpRequestContext, factoryServiceName, request),
|
|
400
|
+
requestType: {
|
|
401
|
+
type: "IDataResourceListRequest",
|
|
402
|
+
examples: [
|
|
403
|
+
{
|
|
404
|
+
id: "dataResourceListRequestExample",
|
|
405
|
+
request: {
|
|
406
|
+
query: {
|
|
407
|
+
producedBy: "did:iota:1234"
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
]
|
|
412
|
+
},
|
|
413
|
+
responseType: [
|
|
414
|
+
{
|
|
415
|
+
type: "IDataResourceListResponse",
|
|
416
|
+
examples: [
|
|
417
|
+
{
|
|
418
|
+
id: "dataResourceListResponseExample",
|
|
419
|
+
response: {
|
|
420
|
+
body: {
|
|
421
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST,
|
|
422
|
+
type: SchemaOrgTypes.ItemList,
|
|
423
|
+
itemListElement: [dataResourceEntryExample]
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
]
|
|
428
|
+
}
|
|
429
|
+
]
|
|
430
|
+
};
|
|
431
|
+
const getDataResourceRoute = {
|
|
432
|
+
operationId: "federatedCatalogueGetDataResource",
|
|
433
|
+
summary: "Get a Data Resource entry",
|
|
434
|
+
tag: tagsFederatedCatalogue[0].name,
|
|
435
|
+
method: "GET",
|
|
436
|
+
path: `${baseRouteName}/${DATA_RESOURCE_ROUTE}/:id`,
|
|
437
|
+
handler: async (httpRequestContext, request) => dataResourceGet(httpRequestContext, factoryServiceName, request),
|
|
438
|
+
requestType: {
|
|
439
|
+
type: "IDataResourceListRequest",
|
|
440
|
+
examples: [
|
|
441
|
+
{
|
|
442
|
+
id: "dataResourceListRequestExample",
|
|
443
|
+
request: {
|
|
444
|
+
pathParams: {
|
|
445
|
+
id: "https://data-resources.example.org/drs1"
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
]
|
|
450
|
+
},
|
|
451
|
+
responseType: [
|
|
452
|
+
{
|
|
453
|
+
type: "IDataResourceGetResponse",
|
|
454
|
+
examples: [
|
|
455
|
+
{
|
|
456
|
+
id: "dataResourceGetResponseExample",
|
|
457
|
+
response: {
|
|
458
|
+
body: dataResourceEntryExample
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
]
|
|
462
|
+
}
|
|
463
|
+
]
|
|
464
|
+
};
|
|
465
|
+
const dataSpaceConnectorEntryExample = {
|
|
466
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY,
|
|
467
|
+
id: "https://my-ds-connectors.example.org/ds-connector-ABCD",
|
|
468
|
+
type: [GaiaXTypes.DataExchangeComponent, FederatedCatalogueTypes.DataSpaceConnector],
|
|
469
|
+
identity: "did:iota:testnet:123456",
|
|
470
|
+
defaultEndpoint: {
|
|
471
|
+
type: GaiaXTypes.Endpoint,
|
|
472
|
+
endpointURL: "https://my-twin-node.example.org:9000/twin-ds-connector"
|
|
473
|
+
},
|
|
474
|
+
subscriptionActivityEndpoint: {
|
|
475
|
+
type: GaiaXTypes.Endpoint,
|
|
476
|
+
endpointURL: "/subscriptions"
|
|
477
|
+
},
|
|
478
|
+
pushActivityEndpoint: {
|
|
479
|
+
type: GaiaXTypes.Endpoint,
|
|
480
|
+
endpointURL: "/notify"
|
|
481
|
+
},
|
|
482
|
+
pullDataEndpoint: {
|
|
483
|
+
type: GaiaXTypes.Endpoint,
|
|
484
|
+
endpointURL: "/data"
|
|
485
|
+
},
|
|
486
|
+
maintainer: "did:iota:99999",
|
|
487
|
+
offeredResource: ["https://my-data-resource.example.org"],
|
|
488
|
+
issuer: "did:iota:987654",
|
|
489
|
+
validFrom: "2024-08-01T12:00:00Z",
|
|
490
|
+
validUntil: "2025-08-01T12:00:00Z",
|
|
491
|
+
dateCreated: "2024-08-02T13:45:00Z",
|
|
492
|
+
evidence: ["https://credentials.example.org/1234567"]
|
|
493
|
+
};
|
|
494
|
+
const listDataSpaceConnectorsRoute = {
|
|
495
|
+
operationId: "federatedCatalogueListDataSpaceConnectors",
|
|
496
|
+
summary: "Get a list of the Data Space connectors entries",
|
|
497
|
+
tag: tagsFederatedCatalogue[0].name,
|
|
498
|
+
method: "GET",
|
|
499
|
+
path: `${baseRouteName}/${DATA_SPACE_CONNECTOR_ROUTE}`,
|
|
500
|
+
handler: async (httpRequestContext, request) => dataSpaceConnectorList(httpRequestContext, factoryServiceName, request),
|
|
501
|
+
requestType: {
|
|
502
|
+
type: "IDataSpaceConnectorListRequest",
|
|
503
|
+
examples: [
|
|
504
|
+
{
|
|
505
|
+
id: "dataSpaceConnectorListRequestExample",
|
|
506
|
+
request: {
|
|
507
|
+
query: {
|
|
508
|
+
maintainedBy: "did:iota:1234"
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
]
|
|
513
|
+
},
|
|
514
|
+
responseType: [
|
|
515
|
+
{
|
|
516
|
+
type: "IDataSpaceConnectorListResponse",
|
|
517
|
+
examples: [
|
|
518
|
+
{
|
|
519
|
+
id: "dataSpaceConnectorListResponseExample",
|
|
520
|
+
response: {
|
|
521
|
+
body: {
|
|
522
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST,
|
|
523
|
+
type: SchemaOrgTypes.ItemList,
|
|
524
|
+
itemListElement: [dataSpaceConnectorEntryExample]
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
]
|
|
529
|
+
}
|
|
530
|
+
]
|
|
531
|
+
};
|
|
532
|
+
const getDataSpaceConnectorRoute = {
|
|
533
|
+
operationId: "federatedCatalogueGetDataSpaceConnector",
|
|
534
|
+
summary: "Get a Data Space Connector entry",
|
|
535
|
+
tag: tagsFederatedCatalogue[0].name,
|
|
536
|
+
method: "GET",
|
|
537
|
+
path: `${baseRouteName}/${DATA_SPACE_CONNECTOR_ROUTE}/:id`,
|
|
538
|
+
handler: async (httpRequestContext, request) => dataSpaceConnectorGet(httpRequestContext, factoryServiceName, request),
|
|
539
|
+
requestType: {
|
|
540
|
+
type: "ICatalogueEntryGetRequest",
|
|
541
|
+
examples: [
|
|
542
|
+
{
|
|
543
|
+
id: "dataSpaceConnectorGetRequestExample",
|
|
544
|
+
request: {
|
|
545
|
+
pathParams: {
|
|
546
|
+
id: "https://ds-connectors.example.org/ds1"
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
]
|
|
551
|
+
},
|
|
552
|
+
responseType: [
|
|
553
|
+
{
|
|
554
|
+
type: "IDataSpaceConnectorGetResponse",
|
|
555
|
+
examples: [
|
|
556
|
+
{
|
|
557
|
+
id: "dataSpaceConnectorGetResponseExample",
|
|
558
|
+
response: {
|
|
559
|
+
body: dataSpaceConnectorEntryExample
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
]
|
|
563
|
+
}
|
|
564
|
+
]
|
|
565
|
+
};
|
|
566
|
+
return [
|
|
567
|
+
createParticipantRoute,
|
|
568
|
+
createServiceOfferingRoute,
|
|
569
|
+
createDataResourceRoute,
|
|
570
|
+
createDataSpaceConnectorRoute,
|
|
571
|
+
listParticipantsRoute,
|
|
572
|
+
getParticipantRoute,
|
|
573
|
+
listServicesRoute,
|
|
574
|
+
getServiceRoute,
|
|
575
|
+
listDataResourcesRoute,
|
|
576
|
+
getDataResourceRoute,
|
|
577
|
+
listDataSpaceConnectorsRoute,
|
|
578
|
+
getDataSpaceConnectorRoute
|
|
579
|
+
];
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Register a new participant.
|
|
583
|
+
* @param baseRouteName The base route name.
|
|
584
|
+
* @param httpRequestContext The request context for the API.
|
|
585
|
+
* @param factoryServiceName The name of the service to use in the routes.
|
|
586
|
+
* @param request The request.
|
|
587
|
+
* @returns The response object with additional http response properties.
|
|
588
|
+
*/
|
|
589
|
+
async function complianceCredentialPresentation(baseRouteName, httpRequestContext, factoryServiceName, request) {
|
|
590
|
+
Guards.object(ROUTES_SOURCE, "request", request);
|
|
591
|
+
Guards.stringValue(ROUTES_SOURCE, "request.body", request.body);
|
|
592
|
+
const service = ComponentFactory.get(factoryServiceName);
|
|
593
|
+
const participantId = await service.registerComplianceCredential(request.body);
|
|
594
|
+
const searchParams = new URLSearchParams();
|
|
595
|
+
searchParams.append("id", participantId);
|
|
596
|
+
return {
|
|
597
|
+
headers: {
|
|
598
|
+
location: `${baseRouteName}/${PARTICIPANTS_ROUTE}?${searchParams.toString()}`
|
|
599
|
+
},
|
|
600
|
+
statusCode: HttpStatusCode.created
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Get a list of the participant entries.
|
|
605
|
+
* @param httpRequestContext The request context for the API.
|
|
606
|
+
* @param factoryServiceName The name of the service to use in the routes.
|
|
607
|
+
* @param request The request.
|
|
608
|
+
* @returns The response object with additional http response properties.
|
|
609
|
+
*/
|
|
610
|
+
async function participantList(httpRequestContext, factoryServiceName, request) {
|
|
611
|
+
const service = ComponentFactory.get(factoryServiceName);
|
|
612
|
+
const itemsAndCursor = await service.queryParticipants(request?.query?.id, request?.query?.registrationNumber, request?.query?.lrnType, request?.query?.cursor, Coerce.number(request?.query?.pageSize));
|
|
613
|
+
return {
|
|
614
|
+
body: itemsAndCursor
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Get a Participant entry.
|
|
619
|
+
* @param httpRequestContext The request context for the API.
|
|
620
|
+
* @param factoryServiceName The name of the service to use in the routes.
|
|
621
|
+
* @param request The request.
|
|
622
|
+
* @returns The response object with additional http response properties.
|
|
623
|
+
*/
|
|
624
|
+
async function participantGet(httpRequestContext, factoryServiceName, request) {
|
|
625
|
+
const service = ComponentFactory.get(factoryServiceName);
|
|
626
|
+
const id = request?.pathParams.id;
|
|
627
|
+
Guards.stringValue(ROUTES_SOURCE, "id", id);
|
|
628
|
+
return {
|
|
629
|
+
body: (await service.getEntry(GaiaXTypes.Participant, id))
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Register a new service offering.
|
|
634
|
+
* @param baseRouteName The base route used.
|
|
635
|
+
* @param httpRequestContext The request context for the API.
|
|
636
|
+
* @param factoryServiceName The name of the service to use in the routes.
|
|
637
|
+
* @param request The request.
|
|
638
|
+
* @returns The response object with additional http response properties.
|
|
639
|
+
*/
|
|
640
|
+
async function serviceOfferingCredentialPresentation(baseRouteName, httpRequestContext, factoryServiceName, request) {
|
|
641
|
+
Guards.object(ROUTES_SOURCE, "request", request);
|
|
642
|
+
Guards.stringValue(ROUTES_SOURCE, "request.body", request.body);
|
|
643
|
+
const service = ComponentFactory.get(factoryServiceName);
|
|
644
|
+
const serviceOfferingsCreated = await service.registerServiceOfferingCredential(request.body);
|
|
645
|
+
// Prepare the Ids to be returned
|
|
646
|
+
const searchParams = new URLSearchParams();
|
|
647
|
+
for (const serviceOffering of serviceOfferingsCreated) {
|
|
648
|
+
searchParams.append("id", serviceOffering);
|
|
649
|
+
}
|
|
650
|
+
return {
|
|
651
|
+
headers: {
|
|
652
|
+
location: `${baseRouteName}/${SERVICE_OFFERING_ROUTE}?${searchParams.toString()}`
|
|
653
|
+
},
|
|
654
|
+
statusCode: HttpStatusCode.created
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Get a list of the service offering entries.
|
|
659
|
+
* @param httpRequestContext The request context for the API.
|
|
660
|
+
* @param factoryServiceName The name of the service to use in the routes.
|
|
661
|
+
* @param request The request.
|
|
662
|
+
* @returns The response object with additional http response properties.
|
|
663
|
+
*/
|
|
664
|
+
async function serviceOfferingList(httpRequestContext, factoryServiceName, request) {
|
|
665
|
+
const service = ComponentFactory.get(factoryServiceName);
|
|
666
|
+
const itemsAndCursor = await service.queryServiceOfferings(request?.query.id, request?.query.providedBy, request?.query.cursor, Coerce.number(request?.query?.pageSize));
|
|
667
|
+
return {
|
|
668
|
+
body: itemsAndCursor
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Get a Service Offering entry.
|
|
673
|
+
* @param httpRequestContext The request context for the API.
|
|
674
|
+
* @param factoryServiceName The name of the service to use in the routes.
|
|
675
|
+
* @param request The request.
|
|
676
|
+
* @returns The response object with additional http response properties.
|
|
677
|
+
*/
|
|
678
|
+
async function serviceOfferingGet(httpRequestContext, factoryServiceName, request) {
|
|
679
|
+
const service = ComponentFactory.get(factoryServiceName);
|
|
680
|
+
const id = request?.pathParams.id;
|
|
681
|
+
Guards.stringValue(ROUTES_SOURCE, "id", id);
|
|
682
|
+
return {
|
|
683
|
+
body: (await service.getEntry(GaiaXTypes.ServiceOffering, id))
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Register a new data resource.
|
|
688
|
+
* @param baseRouteName The base route name.
|
|
689
|
+
* @param httpRequestContext The request context for the API.
|
|
690
|
+
* @param factoryServiceName The name of the service to use in the routes.
|
|
691
|
+
* @param request The request.
|
|
692
|
+
* @returns The response object with additional http response properties.
|
|
693
|
+
*/
|
|
694
|
+
async function dataResourceCredentialPresentation(baseRouteName, httpRequestContext, factoryServiceName, request) {
|
|
695
|
+
Guards.object(ROUTES_SOURCE, "request", request);
|
|
696
|
+
Guards.stringValue(ROUTES_SOURCE, "request.body", request.body);
|
|
697
|
+
const service = ComponentFactory.get(factoryServiceName);
|
|
698
|
+
const dataResourcesCreated = await service.registerDataResourceCredential(request.body);
|
|
699
|
+
// Prepare the Ids to be returned
|
|
700
|
+
const searchParams = new URLSearchParams();
|
|
701
|
+
for (const dataResource of dataResourcesCreated) {
|
|
702
|
+
searchParams.append("id", dataResource);
|
|
703
|
+
}
|
|
704
|
+
return {
|
|
705
|
+
headers: {
|
|
706
|
+
location: `${baseRouteName}/${DATA_RESOURCE_ROUTE}?${searchParams.toString()}`
|
|
707
|
+
},
|
|
708
|
+
statusCode: HttpStatusCode.created
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Get a list of the data resource entries.
|
|
713
|
+
* @param httpRequestContext The request context for the API.
|
|
714
|
+
* @param factoryServiceName The name of the service to use in the routes.
|
|
715
|
+
* @param request The request.
|
|
716
|
+
* @returns The response object with additional http response properties.
|
|
717
|
+
*/
|
|
718
|
+
async function dataResourceList(httpRequestContext, factoryServiceName, request) {
|
|
719
|
+
const service = ComponentFactory.get(factoryServiceName);
|
|
720
|
+
const itemsAndCursor = await service.queryDataResources(request?.query.id, request?.query.producedBy, request?.query.cursor, Coerce.number(request?.query?.pageSize));
|
|
721
|
+
return {
|
|
722
|
+
body: itemsAndCursor
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Get a Data Resource entry.
|
|
727
|
+
* @param httpRequestContext The request context for the API.
|
|
728
|
+
* @param factoryServiceName The name of the service to use in the routes.
|
|
729
|
+
* @param request The request.
|
|
730
|
+
* @returns The response object with additional http response properties.
|
|
731
|
+
*/
|
|
732
|
+
async function dataResourceGet(httpRequestContext, factoryServiceName, request) {
|
|
733
|
+
const service = ComponentFactory.get(factoryServiceName);
|
|
734
|
+
const id = request?.pathParams.id;
|
|
735
|
+
Guards.stringValue(ROUTES_SOURCE, "id", id);
|
|
736
|
+
return {
|
|
737
|
+
body: (await service.getEntry(GaiaXTypes.DataResource, id))
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Register a new data space connector.
|
|
742
|
+
* @param baseRouteName the base route name.
|
|
743
|
+
* @param httpRequestContext The request context for the API.
|
|
744
|
+
* @param factoryServiceName The name of the service to use in the routes.
|
|
745
|
+
* @param request The request.
|
|
746
|
+
* @returns The response object with additional http response properties.
|
|
747
|
+
*/
|
|
748
|
+
async function dataSpaceConnectorCredentialPresentation(baseRouteName, httpRequestContext, factoryServiceName, request) {
|
|
749
|
+
Guards.object(ROUTES_SOURCE, "request", request);
|
|
750
|
+
Guards.stringValue(ROUTES_SOURCE, "request.body", request.body);
|
|
751
|
+
const service = ComponentFactory.get(factoryServiceName);
|
|
752
|
+
const dataSpaceConnectorId = await service.registerDataSpaceConnectorCredential(request.body);
|
|
753
|
+
const searchParams = new URLSearchParams();
|
|
754
|
+
searchParams.append("id", dataSpaceConnectorId);
|
|
755
|
+
return {
|
|
756
|
+
headers: {
|
|
757
|
+
location: `${baseRouteName}/${DATA_SPACE_CONNECTOR_ROUTE}?${searchParams.toString()}`
|
|
758
|
+
},
|
|
759
|
+
statusCode: HttpStatusCode.created
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Get a list of the data space connector entries.
|
|
764
|
+
* @param httpRequestContext The request context for the API.
|
|
765
|
+
* @param factoryServiceName The name of the service to use in the routes.
|
|
766
|
+
* @param request The request.
|
|
767
|
+
* @returns The response object with additional http response properties.
|
|
768
|
+
*/
|
|
769
|
+
async function dataSpaceConnectorList(httpRequestContext, factoryServiceName, request) {
|
|
770
|
+
const service = ComponentFactory.get(factoryServiceName);
|
|
771
|
+
const itemsAndCursor = await service.queryDataSpaceConnectors(request?.query.id, request?.query.maintainedBy, request?.query.cursor, Coerce.number(request?.query?.pageSize));
|
|
772
|
+
return {
|
|
773
|
+
body: itemsAndCursor
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Get a Data Space Connector entry.
|
|
778
|
+
* @param httpRequestContext The request context for the API.
|
|
779
|
+
* @param factoryServiceName The name of the service to use in the routes.
|
|
780
|
+
* @param request The request.
|
|
781
|
+
* @returns The response object with additional http response properties.
|
|
782
|
+
*/
|
|
783
|
+
async function dataSpaceConnectorGet(httpRequestContext, factoryServiceName, request) {
|
|
784
|
+
const service = ComponentFactory.get(factoryServiceName);
|
|
785
|
+
const id = request?.pathParams.id;
|
|
786
|
+
Guards.stringValue(ROUTES_SOURCE, "id", id);
|
|
787
|
+
return {
|
|
788
|
+
body: (await service.getEntry(GaiaXTypes.DataExchangeComponent, id))
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// Copyright 2024 IOTA Stiftung.
|
|
793
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
794
|
+
/**
|
|
795
|
+
* Compliance Credential Verification Service.
|
|
796
|
+
*/
|
|
797
|
+
class ComplianceCredentialVerificationService {
|
|
798
|
+
/**
|
|
799
|
+
* Class name
|
|
800
|
+
*/
|
|
801
|
+
CLASS_NAME = "ComplianceCredentialVerificationService";
|
|
802
|
+
/**
|
|
803
|
+
* Resolver component.
|
|
804
|
+
* @internal
|
|
805
|
+
*/
|
|
806
|
+
_resolver;
|
|
807
|
+
/**
|
|
808
|
+
* Resolver component.
|
|
809
|
+
* @internal
|
|
810
|
+
*/
|
|
811
|
+
_subResourceCacheTtlMs;
|
|
812
|
+
/**
|
|
813
|
+
* Logging Component.
|
|
814
|
+
* @internal
|
|
815
|
+
*/
|
|
816
|
+
_logger;
|
|
817
|
+
/**
|
|
818
|
+
* List of clearing houses tha are approvers.
|
|
819
|
+
* @internal
|
|
820
|
+
*/
|
|
821
|
+
_clearingHouseApproverList;
|
|
822
|
+
/**
|
|
823
|
+
* Constructor.
|
|
824
|
+
* @param clearingHouseApproverList The list of clearing house identities approved.
|
|
825
|
+
* @param resolver The resolver used for DID.
|
|
826
|
+
* @param subResourceCacheTtlMs The time to live (in ms) of sub-resource objects in the cache. undefined means no cache. 0 means live in cache forever.
|
|
827
|
+
* @param logger The Logger Component.
|
|
828
|
+
*/
|
|
829
|
+
constructor(clearingHouseApproverList, resolver, subResourceCacheTtlMs, logger) {
|
|
830
|
+
this._clearingHouseApproverList = clearingHouseApproverList;
|
|
831
|
+
this._resolver = resolver;
|
|
832
|
+
this._subResourceCacheTtlMs = subResourceCacheTtlMs;
|
|
833
|
+
this._logger = logger;
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Verifies a Compliance Credential.
|
|
837
|
+
* @param credential The Credential to be verified
|
|
838
|
+
* @returns The Verification Result.
|
|
839
|
+
*/
|
|
840
|
+
async verify(credential) {
|
|
841
|
+
if (!Is.arrayValue(credential.type) ||
|
|
842
|
+
!credential.type.includes(FederatedCatalogueTypes.ComplianceCredential)) {
|
|
843
|
+
return {
|
|
844
|
+
verified: false,
|
|
845
|
+
verificationFailureReason: VerificationFailureReasons.InvalidCredentialType,
|
|
846
|
+
credentials: []
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
const issuer = Is.string(credential.issuer)
|
|
850
|
+
? credential.issuer
|
|
851
|
+
: Coerce.object(credential.issuer)?.id;
|
|
852
|
+
if (Is.undefined(issuer)) {
|
|
853
|
+
return {
|
|
854
|
+
verified: false,
|
|
855
|
+
verificationFailureReason: VerificationFailureReasons.InvalidIssuer,
|
|
856
|
+
credentials: []
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
if (!this._clearingHouseApproverList.includes(issuer)) {
|
|
860
|
+
return {
|
|
861
|
+
verified: false,
|
|
862
|
+
verificationFailureReason: VerificationFailureReasons.InvalidIssuer,
|
|
863
|
+
credentials: []
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
const validFrom = credential.validFrom;
|
|
867
|
+
const validFromDate = Coerce.dateTime(validFrom);
|
|
868
|
+
if (Is.undefined(validFromDate) || validFromDate.getTime() > Date.now()) {
|
|
869
|
+
return {
|
|
870
|
+
verified: false,
|
|
871
|
+
verificationFailureReason: VerificationFailureReasons.NotValidYet,
|
|
872
|
+
credentials: []
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
const validUntilDate = Coerce.dateTime(credential.validUntil);
|
|
876
|
+
if (Is.undefined(validUntilDate)) {
|
|
877
|
+
return {
|
|
878
|
+
verified: false,
|
|
879
|
+
verificationFailureReason: VerificationFailureReasons.NoValidityEndPeriod,
|
|
880
|
+
credentials: []
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
if (validUntilDate.getTime() <= Date.now()) {
|
|
884
|
+
return {
|
|
885
|
+
verified: false,
|
|
886
|
+
verificationFailureReason: VerificationFailureReasons.Expired,
|
|
887
|
+
credentials: []
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
const subject = credential.credentialSubject;
|
|
891
|
+
if (!subject) {
|
|
892
|
+
return {
|
|
893
|
+
verified: false,
|
|
894
|
+
verificationFailureReason: VerificationFailureReasons.MissingSubject,
|
|
895
|
+
credentials: []
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
const evidences = Is.array(credential.evidence) ? credential.evidence : [credential.evidence];
|
|
899
|
+
if (evidences.length === 0) {
|
|
900
|
+
return {
|
|
901
|
+
verified: false,
|
|
902
|
+
verificationFailureReason: VerificationFailureReasons.MissingEvidences,
|
|
903
|
+
credentials: []
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
const finalResult = {
|
|
907
|
+
verified: true,
|
|
908
|
+
credentials: []
|
|
909
|
+
};
|
|
910
|
+
for (const evidence of evidences) {
|
|
911
|
+
const verResult = await this.verifyEvidence(evidence);
|
|
912
|
+
if (!verResult.verified) {
|
|
913
|
+
return {
|
|
914
|
+
verified: false,
|
|
915
|
+
verificationFailureReason: VerificationFailureReasons.EvidenceCannotBeVerified,
|
|
916
|
+
evidenceVerificationResult: verResult,
|
|
917
|
+
credentials: [],
|
|
918
|
+
evidenceFailedToVerify: [evidence.id]
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
finalResult.credentials.push(verResult.credential);
|
|
922
|
+
}
|
|
923
|
+
return finalResult;
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* Verifies the evidence supplied as part of a Compliance Credential.
|
|
927
|
+
* @param evidence The compliance evidence
|
|
928
|
+
* @returns The verification result with the original credentials that served as evidence
|
|
929
|
+
*/
|
|
930
|
+
async verifyEvidence(evidence) {
|
|
931
|
+
// The credential associated to the evidence has to be retrieved, then verified
|
|
932
|
+
Guards.object(this.CLASS_NAME, "IComplianceEvidence", evidence);
|
|
933
|
+
const credentialUrl = evidence.id;
|
|
934
|
+
this._logger?.log({
|
|
935
|
+
source: this.CLASS_NAME,
|
|
936
|
+
level: "info",
|
|
937
|
+
message: "verifyingEvidenceCredential",
|
|
938
|
+
ts: Date.now(),
|
|
939
|
+
data: {
|
|
940
|
+
credentialUrl
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
const credentialResponse = await FetchHelper.fetch(this.CLASS_NAME, credentialUrl, "GET", undefined, { cacheTtlMs: this._subResourceCacheTtlMs });
|
|
944
|
+
if (!credentialResponse.ok) {
|
|
945
|
+
this._logger?.log({
|
|
946
|
+
source: this.CLASS_NAME,
|
|
947
|
+
level: "error",
|
|
948
|
+
message: "credentialCannotBeRetrieved",
|
|
949
|
+
ts: Date.now(),
|
|
950
|
+
data: {
|
|
951
|
+
credentialUrl,
|
|
952
|
+
statusCode: credentialResponse.status
|
|
953
|
+
}
|
|
954
|
+
});
|
|
955
|
+
return {
|
|
956
|
+
verified: false,
|
|
957
|
+
verificationFailureReason: VerificationFailureReasons.EvidenceCannotBeRetrieved
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
const originalCredential = await credentialResponse.json();
|
|
961
|
+
const theCredential = ObjectHelper.clone(originalCredential);
|
|
962
|
+
const proof = theCredential.proof;
|
|
963
|
+
// The proof is not taken into account to calculate the hash
|
|
964
|
+
delete theCredential.proof;
|
|
965
|
+
// Checking the hash
|
|
966
|
+
const canonicalized = JsonHelper.canonicalize(theCredential);
|
|
967
|
+
const hashingDetails = evidence.digestSRI;
|
|
968
|
+
const [hashingAlg, hash] = hashingDetails.split("-");
|
|
969
|
+
let hashToCheck = "";
|
|
970
|
+
if (hashingAlg === "sha256") {
|
|
971
|
+
hashToCheck = Converter.bytesToBase64(Sha256.sum256(Converter.utf8ToBytes(canonicalized)));
|
|
972
|
+
}
|
|
973
|
+
else if (hashingAlg === "sha512") {
|
|
974
|
+
hashToCheck = Converter.bytesToBase64(Sha512.sum512(Converter.utf8ToBytes(canonicalized)));
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
throw new UnprocessableError(this.CLASS_NAME, "unknownHashingAlgorithm", { hashingAlg });
|
|
978
|
+
}
|
|
979
|
+
if (hashToCheck !== hash) {
|
|
980
|
+
return {
|
|
981
|
+
verified: false,
|
|
982
|
+
verificationFailureReason: VerificationFailureReasons.IntegrityCheckFailed
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
const { id } = DocumentHelper.parseId(proof.verificationMethod);
|
|
986
|
+
const documentId = theCredential.issuer ?? id;
|
|
987
|
+
Guards.stringValue(this.CLASS_NAME, "documentId", documentId);
|
|
988
|
+
let verified = false;
|
|
989
|
+
try {
|
|
990
|
+
const document = await this._resolver.identityResolve(documentId);
|
|
991
|
+
const jwk = DocumentHelper.getJwk(document, proof.verificationMethod);
|
|
992
|
+
verified = await ProofHelper.verifyProof(theCredential, proof, jwk);
|
|
993
|
+
}
|
|
994
|
+
catch (error) {
|
|
995
|
+
this._logger?.log({
|
|
996
|
+
source: this.CLASS_NAME,
|
|
997
|
+
level: "error",
|
|
998
|
+
message: "credentialVerificationError",
|
|
999
|
+
ts: Date.now(),
|
|
1000
|
+
error: error,
|
|
1001
|
+
data: {
|
|
1002
|
+
credentialUrl
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
return {
|
|
1006
|
+
verified,
|
|
1007
|
+
verificationFailureReason: VerificationFailureReasons.GeneralVerificationError
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
this._logger?.log({
|
|
1011
|
+
source: this.CLASS_NAME,
|
|
1012
|
+
level: "info",
|
|
1013
|
+
message: "credentialEvidenceVerified",
|
|
1014
|
+
ts: Date.now(),
|
|
1015
|
+
data: {
|
|
1016
|
+
credentialUrl
|
|
1017
|
+
}
|
|
1018
|
+
});
|
|
1019
|
+
return {
|
|
1020
|
+
verified: true,
|
|
1021
|
+
credential: originalCredential
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
// Copyright 2024 IOTA Stiftung.
|
|
1027
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
1028
|
+
/**
|
|
1029
|
+
* Service for performing logging operations to a connector.
|
|
1030
|
+
*/
|
|
1031
|
+
class FederatedCatalogueService {
|
|
1032
|
+
/**
|
|
1033
|
+
* The namespace for the service.
|
|
1034
|
+
*/
|
|
1035
|
+
static NAMESPACE = "fedcat";
|
|
1036
|
+
/**
|
|
1037
|
+
* Fields to skip when persisting entries to the Catalogue
|
|
1038
|
+
* @internal
|
|
1039
|
+
*/
|
|
1040
|
+
static _FIELDS_TO_SKIP = ["@context", "type"];
|
|
1041
|
+
/**
|
|
1042
|
+
* Runtime name for the class.
|
|
1043
|
+
*/
|
|
1044
|
+
CLASS_NAME = "FederatedCatalogueService";
|
|
1045
|
+
/**
|
|
1046
|
+
* The identity resolver used to dereference DIDs.
|
|
1047
|
+
* @internal
|
|
1048
|
+
*/
|
|
1049
|
+
_resolver;
|
|
1050
|
+
/**
|
|
1051
|
+
* Logging service.
|
|
1052
|
+
* @internal
|
|
1053
|
+
*/
|
|
1054
|
+
_loggingService;
|
|
1055
|
+
/**
|
|
1056
|
+
* Storage service for participants.
|
|
1057
|
+
* @internal
|
|
1058
|
+
*/
|
|
1059
|
+
_entityStorageParticipants;
|
|
1060
|
+
/**
|
|
1061
|
+
* Storage service for service offering.
|
|
1062
|
+
* @internal
|
|
1063
|
+
*/
|
|
1064
|
+
_entityStorageServiceOfferings;
|
|
1065
|
+
/**
|
|
1066
|
+
* Storage service for data resources.
|
|
1067
|
+
* @internal
|
|
1068
|
+
*/
|
|
1069
|
+
_entityStorageDataResources;
|
|
1070
|
+
/**
|
|
1071
|
+
* Storage service for data resources.
|
|
1072
|
+
* @internal
|
|
1073
|
+
*/
|
|
1074
|
+
_entityStorageDataSpaceConnectors;
|
|
1075
|
+
/**
|
|
1076
|
+
* Compliance Credential Verifier service.
|
|
1077
|
+
* @internal
|
|
1078
|
+
*/
|
|
1079
|
+
_complianceCredentialVerifier;
|
|
1080
|
+
/**
|
|
1081
|
+
* Create a new instance of FederatedCatalogue service.
|
|
1082
|
+
* @param options The options for the connector.
|
|
1083
|
+
*/
|
|
1084
|
+
constructor(options) {
|
|
1085
|
+
this._loggingService = LoggingConnectorFactory.getIfExists(options?.loggingConnectorType ?? "logging");
|
|
1086
|
+
this._entityStorageParticipants = EntityStorageConnectorFactory.get(options.participantEntityStorageType ?? StringHelper.kebabCase("ParticipantEntry"));
|
|
1087
|
+
this._entityStorageServiceOfferings = EntityStorageConnectorFactory.get(options.serviceOfferingEntityStorageType ??
|
|
1088
|
+
StringHelper.kebabCase("ServiceOfferingEntry"));
|
|
1089
|
+
this._entityStorageDataResources = EntityStorageConnectorFactory.get(options.dataResourceEntityStorageType ?? StringHelper.kebabCase("DataResourceEntry"));
|
|
1090
|
+
this._entityStorageDataSpaceConnectors = EntityStorageConnectorFactory.get(options.dataSpaceConnectorStorageType ??
|
|
1091
|
+
StringHelper.kebabCase("DataSpaceConnectorEntry"));
|
|
1092
|
+
this._resolver = ComponentFactory.get(options.identityResolverComponentType ?? "identity-resolver");
|
|
1093
|
+
this._complianceCredentialVerifier = new ComplianceCredentialVerificationService(options.config.clearingHouseApproverList, this._resolver, options.config.subResourceCacheTtlMs, this._loggingService);
|
|
1094
|
+
SchemaOrgDataTypes.registerRedirects();
|
|
1095
|
+
}
|
|
1096
|
+
/**
|
|
1097
|
+
* Registers a Participant's compliance Credential.
|
|
1098
|
+
* @param credentialJwt The credential (wrapped into a presentation) as JWT.
|
|
1099
|
+
* @returns The Id of the Participant (DID usually).
|
|
1100
|
+
*/
|
|
1101
|
+
async registerComplianceCredential(credentialJwt) {
|
|
1102
|
+
Guards.string(this.CLASS_NAME, "credentialJwt", credentialJwt);
|
|
1103
|
+
// This will raise exceptions as it has been coded reusing code from Gaia-X
|
|
1104
|
+
const complianceCredential = await this.decodeJwt(credentialJwt);
|
|
1105
|
+
const result = await this._complianceCredentialVerifier.verify(complianceCredential);
|
|
1106
|
+
if (!result.verified) {
|
|
1107
|
+
this._loggingService?.log({
|
|
1108
|
+
level: "error",
|
|
1109
|
+
source: this.CLASS_NAME,
|
|
1110
|
+
ts: Date.now(),
|
|
1111
|
+
message: "complianceCredentialNotVerified",
|
|
1112
|
+
data: { result }
|
|
1113
|
+
});
|
|
1114
|
+
throw new UnprocessableError(this.CLASS_NAME, "complianceCredentialNotVerified", {
|
|
1115
|
+
reason: result.verificationFailureReason
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
const targetCredential = result.credentials.find(credential => credential.credentialSubject.type === GaiaXTypes.Participant);
|
|
1119
|
+
if (Is.undefined(targetCredential)) {
|
|
1120
|
+
throw new UnprocessableError(this.CLASS_NAME, "noEvidence");
|
|
1121
|
+
}
|
|
1122
|
+
const participantEntry = this.extractParticipantEntry(complianceCredential, targetCredential);
|
|
1123
|
+
const theEntry = ObjectHelper.omit(participantEntry, FederatedCatalogueService._FIELDS_TO_SKIP);
|
|
1124
|
+
await this._entityStorageParticipants.set(theEntry);
|
|
1125
|
+
await this._loggingService?.log({
|
|
1126
|
+
level: "info",
|
|
1127
|
+
source: this.CLASS_NAME,
|
|
1128
|
+
ts: Date.now(),
|
|
1129
|
+
message: "complianceCredentialVerified",
|
|
1130
|
+
data: {
|
|
1131
|
+
participantId: complianceCredential.credentialSubject?.id,
|
|
1132
|
+
trustedIssuer: complianceCredential.issuer
|
|
1133
|
+
}
|
|
1134
|
+
});
|
|
1135
|
+
return participantEntry.id;
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Query the federated catalogue.
|
|
1139
|
+
* @param id The identity of the participant.
|
|
1140
|
+
* @param legalRegistrationNumber The legal registration number.
|
|
1141
|
+
* @param lrnType The legal registration number type (EORI, VATID, GLEIF, KENYA_PIN, etc.)
|
|
1142
|
+
* @param cursor The cursor to request the next page of entities.
|
|
1143
|
+
* @param pageSize The maximum number of entities in a page.
|
|
1144
|
+
* @returns All the entities for the storage matching the conditions,
|
|
1145
|
+
* and a cursor which can be used to request more entities.
|
|
1146
|
+
* @throws NotImplementedError if the implementation does not support retrieval.
|
|
1147
|
+
*/
|
|
1148
|
+
async queryParticipants(id, legalRegistrationNumber, lrnType, cursor, pageSize) {
|
|
1149
|
+
const conditions = [];
|
|
1150
|
+
if (Is.stringValue(id)) {
|
|
1151
|
+
const condition = {
|
|
1152
|
+
property: "id",
|
|
1153
|
+
value: id,
|
|
1154
|
+
comparison: ComparisonOperator.Equals
|
|
1155
|
+
};
|
|
1156
|
+
conditions.push(condition);
|
|
1157
|
+
}
|
|
1158
|
+
if (Is.stringValue(lrnType)) {
|
|
1159
|
+
const condition = {
|
|
1160
|
+
property: "lrnType",
|
|
1161
|
+
value: lrnType,
|
|
1162
|
+
comparison: ComparisonOperator.Equals
|
|
1163
|
+
};
|
|
1164
|
+
conditions.push(condition);
|
|
1165
|
+
}
|
|
1166
|
+
if (Is.stringValue(legalRegistrationNumber)) {
|
|
1167
|
+
const condition = {
|
|
1168
|
+
property: "registrationNumber",
|
|
1169
|
+
value: legalRegistrationNumber,
|
|
1170
|
+
comparison: ComparisonOperator.Equals
|
|
1171
|
+
};
|
|
1172
|
+
conditions.push(condition);
|
|
1173
|
+
}
|
|
1174
|
+
const entries = await this._entityStorageParticipants.query({ conditions }, undefined, undefined, cursor, pageSize);
|
|
1175
|
+
const itemList = entries.entities.map(entry => {
|
|
1176
|
+
entry.type = GaiaXTypes.Participant;
|
|
1177
|
+
return entry;
|
|
1178
|
+
});
|
|
1179
|
+
const result = {
|
|
1180
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST,
|
|
1181
|
+
type: SchemaOrgTypes.ItemList,
|
|
1182
|
+
itemListElement: itemList,
|
|
1183
|
+
nextItem: entries.cursor
|
|
1184
|
+
};
|
|
1185
|
+
return JsonLdProcessor.compact(result, result["@context"]);
|
|
1186
|
+
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Returns a Federated Catalogue entry.
|
|
1189
|
+
* @param entryType The type of entry.
|
|
1190
|
+
* @param entryId The entry's id.
|
|
1191
|
+
* @returns Catalogue Entry
|
|
1192
|
+
* @throws NotFoundError if not found.
|
|
1193
|
+
*/
|
|
1194
|
+
async getEntry(entryType, entryId) {
|
|
1195
|
+
Guards.stringValue(this.CLASS_NAME, "entryId", entryId);
|
|
1196
|
+
let itemsAndCursor;
|
|
1197
|
+
switch (entryType) {
|
|
1198
|
+
case GaiaXTypes.Participant:
|
|
1199
|
+
itemsAndCursor = await this.queryParticipants(entryId);
|
|
1200
|
+
break;
|
|
1201
|
+
case GaiaXTypes.DataExchangeComponent:
|
|
1202
|
+
case FederatedCatalogueTypes.DataSpaceConnector:
|
|
1203
|
+
itemsAndCursor = await this.queryDataSpaceConnectors(entryId);
|
|
1204
|
+
break;
|
|
1205
|
+
case GaiaXTypes.ServiceOffering:
|
|
1206
|
+
itemsAndCursor = await this.queryServiceOfferings(entryId);
|
|
1207
|
+
break;
|
|
1208
|
+
case GaiaXTypes.DataResource:
|
|
1209
|
+
itemsAndCursor = await this.queryDataResources(entryId);
|
|
1210
|
+
break;
|
|
1211
|
+
default:
|
|
1212
|
+
throw new GeneralError(this.CLASS_NAME, "unknownEntryType", { entryType });
|
|
1213
|
+
}
|
|
1214
|
+
if (Is.arrayValue(itemsAndCursor?.itemListElement)) {
|
|
1215
|
+
const entry = {
|
|
1216
|
+
...itemsAndCursor.itemListElement[0],
|
|
1217
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY
|
|
1218
|
+
};
|
|
1219
|
+
const result = await JsonLdProcessor.compact(entry, entry["@context"]);
|
|
1220
|
+
return result;
|
|
1221
|
+
}
|
|
1222
|
+
throw new NotFoundError(this.CLASS_NAME, "entryNotFound", entryId);
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* Registers a compliance Credential concerning a Data Space Connector.
|
|
1226
|
+
* @param credentialJwt The credential (wrapped into a presentation) as JWT.
|
|
1227
|
+
* @returns The identifier of the Data Space Connector registered.
|
|
1228
|
+
*/
|
|
1229
|
+
async registerDataSpaceConnectorCredential(credentialJwt) {
|
|
1230
|
+
Guards.string(this.CLASS_NAME, "credentialJwt", credentialJwt);
|
|
1231
|
+
// This will raise exceptions as it has been coded reusing code from Gaia-X
|
|
1232
|
+
const complianceCredential = await this.decodeJwt(credentialJwt);
|
|
1233
|
+
const result = await this._complianceCredentialVerifier.verify(complianceCredential);
|
|
1234
|
+
if (!result.verified) {
|
|
1235
|
+
this._loggingService?.log({
|
|
1236
|
+
level: "error",
|
|
1237
|
+
source: this.CLASS_NAME,
|
|
1238
|
+
ts: Date.now(),
|
|
1239
|
+
message: "complianceCredentialNotVerified",
|
|
1240
|
+
data: { result }
|
|
1241
|
+
});
|
|
1242
|
+
throw new UnprocessableError(this.CLASS_NAME, "complianceCredentialNotVerified", {
|
|
1243
|
+
reason: result.verificationFailureReason
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
const targetCredential = result.credentials.find(credential => {
|
|
1247
|
+
if (Is.array(credential.credentialSubject.type)) {
|
|
1248
|
+
return credential.credentialSubject.type.includes(FederatedCatalogueTypes.DataSpaceConnector);
|
|
1249
|
+
}
|
|
1250
|
+
return credential.credentialSubject.type === FederatedCatalogueTypes.DataSpaceConnector;
|
|
1251
|
+
});
|
|
1252
|
+
const dataResourceCredentials = result.credentials.filter(credential => credential.credentialSubject.type === GaiaXTypes.DataResource);
|
|
1253
|
+
if (Is.undefined(targetCredential)) {
|
|
1254
|
+
throw new UnprocessableError(this.CLASS_NAME, "noEvidence");
|
|
1255
|
+
}
|
|
1256
|
+
await this.checkParticipantExists(targetCredential.issuer);
|
|
1257
|
+
const dataSpaceConnectorEntry = this.extractDataSpaceConnectorEntry(complianceCredential, result.credentials[0]);
|
|
1258
|
+
const theEntry = ObjectHelper.omit(dataSpaceConnectorEntry, FederatedCatalogueService._FIELDS_TO_SKIP);
|
|
1259
|
+
await this._entityStorageDataSpaceConnectors.set(theEntry);
|
|
1260
|
+
for (const dataResourceCredential of dataResourceCredentials) {
|
|
1261
|
+
await this.checkParticipantExists(dataResourceCredential.issuer);
|
|
1262
|
+
const dataResourceEntry = this.extractDataResourceEntry(complianceCredential, dataResourceCredential);
|
|
1263
|
+
const drEntry = ObjectHelper.omit(dataResourceEntry, FederatedCatalogueService._FIELDS_TO_SKIP);
|
|
1264
|
+
await this._entityStorageDataResources.set(drEntry);
|
|
1265
|
+
}
|
|
1266
|
+
await this._loggingService?.log({
|
|
1267
|
+
level: "info",
|
|
1268
|
+
source: this.CLASS_NAME,
|
|
1269
|
+
ts: Date.now(),
|
|
1270
|
+
message: "complianceCredentialVerified",
|
|
1271
|
+
data: {
|
|
1272
|
+
dataSpaceConnectorId: complianceCredential.credentialSubject?.id,
|
|
1273
|
+
trustedIssuer: complianceCredential.issuer
|
|
1274
|
+
}
|
|
1275
|
+
});
|
|
1276
|
+
return dataSpaceConnectorEntry.id;
|
|
1277
|
+
}
|
|
1278
|
+
/**
|
|
1279
|
+
* Registers a data resource Credential concerning a Data Space Connector.
|
|
1280
|
+
* @param credentialJwt The credential (wrapped into a presentation) as JWT.
|
|
1281
|
+
* @returns The list of Data Resources created.
|
|
1282
|
+
*/
|
|
1283
|
+
async registerDataResourceCredential(credentialJwt) {
|
|
1284
|
+
Guards.string(this.CLASS_NAME, "credentialJwt", credentialJwt);
|
|
1285
|
+
const complianceCredential = await this.decodeJwt(credentialJwt);
|
|
1286
|
+
const result = await this._complianceCredentialVerifier.verify(complianceCredential);
|
|
1287
|
+
if (!result.verified) {
|
|
1288
|
+
this._loggingService?.log({
|
|
1289
|
+
level: "error",
|
|
1290
|
+
source: this.CLASS_NAME,
|
|
1291
|
+
ts: Date.now(),
|
|
1292
|
+
message: "complianceCredentialNotVerified",
|
|
1293
|
+
data: { result }
|
|
1294
|
+
});
|
|
1295
|
+
throw new UnprocessableError(this.CLASS_NAME, "complianceCredentialNotVerified", {
|
|
1296
|
+
reason: result.verificationFailureReason
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
const dataResourceCredentials = result.credentials.filter(credential => credential.credentialSubject.type === GaiaXTypes.DataResource);
|
|
1300
|
+
if (dataResourceCredentials.length === 0) {
|
|
1301
|
+
throw new UnprocessableError(this.CLASS_NAME, "noEvidence");
|
|
1302
|
+
}
|
|
1303
|
+
const dataResourceIds = [];
|
|
1304
|
+
for (const dataResourceCredential of dataResourceCredentials) {
|
|
1305
|
+
await this.checkParticipantExists(dataResourceCredential.issuer);
|
|
1306
|
+
const dataResourceEntry = this.extractDataResourceEntry(complianceCredential, dataResourceCredential);
|
|
1307
|
+
const theEntry = ObjectHelper.omit(dataResourceEntry, FederatedCatalogueService._FIELDS_TO_SKIP);
|
|
1308
|
+
await this._entityStorageDataResources.set(theEntry);
|
|
1309
|
+
dataResourceIds.push(dataResourceEntry.id);
|
|
1310
|
+
}
|
|
1311
|
+
await this._loggingService?.log({
|
|
1312
|
+
level: "info",
|
|
1313
|
+
source: this.CLASS_NAME,
|
|
1314
|
+
ts: Date.now(),
|
|
1315
|
+
message: "complianceCredentialVerified",
|
|
1316
|
+
data: {
|
|
1317
|
+
dataResourceIds,
|
|
1318
|
+
trustedIssuer: complianceCredential.issuer
|
|
1319
|
+
}
|
|
1320
|
+
});
|
|
1321
|
+
return dataResourceIds;
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Query the federated catalogue.
|
|
1325
|
+
* @param id The identity of the participant.
|
|
1326
|
+
* @param maintainer The DS Connector maintainer.
|
|
1327
|
+
* @param cursor The cursor to request the next page of entities.
|
|
1328
|
+
* @param pageSize The maximum number of entities in a page.
|
|
1329
|
+
* @returns All the entities for the storage matching the conditions,
|
|
1330
|
+
* and a cursor which can be used to request more entities.
|
|
1331
|
+
* @throws NotImplementedError if the implementation does not support retrieval.
|
|
1332
|
+
*/
|
|
1333
|
+
async queryDataSpaceConnectors(id, maintainer, cursor, pageSize) {
|
|
1334
|
+
const conditions = [];
|
|
1335
|
+
if (Is.stringValue(id)) {
|
|
1336
|
+
const condition = {
|
|
1337
|
+
property: "id",
|
|
1338
|
+
value: id,
|
|
1339
|
+
comparison: ComparisonOperator.Equals
|
|
1340
|
+
};
|
|
1341
|
+
conditions.push(condition);
|
|
1342
|
+
}
|
|
1343
|
+
if (Is.stringValue(maintainer)) {
|
|
1344
|
+
const condition = {
|
|
1345
|
+
property: "maintainer",
|
|
1346
|
+
value: maintainer,
|
|
1347
|
+
comparison: ComparisonOperator.Equals
|
|
1348
|
+
};
|
|
1349
|
+
conditions.push(condition);
|
|
1350
|
+
}
|
|
1351
|
+
const entries = await this._entityStorageDataSpaceConnectors.query({ conditions }, undefined, undefined, cursor, pageSize);
|
|
1352
|
+
const itemList = entries.entities.map(entry => {
|
|
1353
|
+
entry.type = [
|
|
1354
|
+
GaiaXTypes.DataExchangeComponent,
|
|
1355
|
+
FederatedCatalogueTypes.DataSpaceConnector
|
|
1356
|
+
];
|
|
1357
|
+
return entry;
|
|
1358
|
+
});
|
|
1359
|
+
const result = {
|
|
1360
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST,
|
|
1361
|
+
type: SchemaOrgTypes.ItemList,
|
|
1362
|
+
itemListElement: itemList,
|
|
1363
|
+
nextItem: entries.cursor
|
|
1364
|
+
};
|
|
1365
|
+
return JsonLdProcessor.compact(result, result["@context"]);
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* Registers a Service Offering Credential.
|
|
1369
|
+
* @param credentialJwt The credential (wrapped into a presentation) as JWT.
|
|
1370
|
+
* @returns Nothing.
|
|
1371
|
+
*/
|
|
1372
|
+
async registerServiceOfferingCredential(credentialJwt) {
|
|
1373
|
+
Guards.string(this.CLASS_NAME, "credentialJwt", credentialJwt);
|
|
1374
|
+
// This will raise exceptions as it has been coded reusing code from Gaia-X
|
|
1375
|
+
const sdComplianceCredential = await this.decodeJwt(credentialJwt);
|
|
1376
|
+
const result = await this._complianceCredentialVerifier.verify(sdComplianceCredential);
|
|
1377
|
+
if (!result.verified) {
|
|
1378
|
+
this._loggingService?.log({
|
|
1379
|
+
level: "error",
|
|
1380
|
+
source: this.CLASS_NAME,
|
|
1381
|
+
ts: Date.now(),
|
|
1382
|
+
message: "complianceCredentialNotVerified",
|
|
1383
|
+
data: { result }
|
|
1384
|
+
});
|
|
1385
|
+
throw new UnprocessableError(this.CLASS_NAME, "complianceCredentialNotVerified", {
|
|
1386
|
+
reason: result.verificationFailureReason
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
const serviceOfferingCredentials = result.credentials.filter(credential => credential.credentialSubject.type === GaiaXTypes.ServiceOffering);
|
|
1390
|
+
const dataResourceCredentials = result.credentials.filter(credential => credential.credentialSubject.type === GaiaXTypes.DataResource);
|
|
1391
|
+
if (serviceOfferingCredentials.length === 0) {
|
|
1392
|
+
throw new UnprocessableError(this.CLASS_NAME, "noEvidence");
|
|
1393
|
+
}
|
|
1394
|
+
const serviceOfferingIds = [];
|
|
1395
|
+
for (const serviceOfferingCredential of serviceOfferingCredentials) {
|
|
1396
|
+
const serviceIssuer = serviceOfferingCredential.issuer;
|
|
1397
|
+
await this.checkParticipantExists(serviceIssuer);
|
|
1398
|
+
const serviceOfferingEntry = this.extractServiceOfferingEntry(sdComplianceCredential, serviceOfferingCredential);
|
|
1399
|
+
const theEntry = ObjectHelper.omit(serviceOfferingEntry, FederatedCatalogueService._FIELDS_TO_SKIP);
|
|
1400
|
+
await this._entityStorageServiceOfferings.set(theEntry);
|
|
1401
|
+
serviceOfferingIds.push(serviceOfferingEntry.id);
|
|
1402
|
+
}
|
|
1403
|
+
for (const dataResourceCredential of dataResourceCredentials) {
|
|
1404
|
+
await this.checkParticipantExists(dataResourceCredential.issuer);
|
|
1405
|
+
const dataResourceEntry = this.extractDataResourceEntry(sdComplianceCredential, dataResourceCredential);
|
|
1406
|
+
await this._entityStorageDataResources.set(dataResourceEntry);
|
|
1407
|
+
}
|
|
1408
|
+
await this._loggingService?.log({
|
|
1409
|
+
level: "info",
|
|
1410
|
+
source: this.CLASS_NAME,
|
|
1411
|
+
ts: Date.now(),
|
|
1412
|
+
message: "complianceCredentialVerified",
|
|
1413
|
+
data: {
|
|
1414
|
+
serviceOfferingIds,
|
|
1415
|
+
trustedIssuer: sdComplianceCredential.issuer
|
|
1416
|
+
}
|
|
1417
|
+
});
|
|
1418
|
+
return serviceOfferingIds;
|
|
1419
|
+
}
|
|
1420
|
+
/**
|
|
1421
|
+
* Query the federated catalogue.
|
|
1422
|
+
* @param id Service Id.
|
|
1423
|
+
* @param providedBy The identity of the participant.
|
|
1424
|
+
* @param cursor The cursor to request the next page of entities.
|
|
1425
|
+
* @param pageSize The maximum number of entities in a page.
|
|
1426
|
+
* @returns All the entities for the storage matching the conditions,
|
|
1427
|
+
* and a cursor which can be used to request more entities.
|
|
1428
|
+
* @throws NotImplementedError if the implementation does not support retrieval.
|
|
1429
|
+
*/
|
|
1430
|
+
async queryServiceOfferings(id, providedBy, cursor, pageSize) {
|
|
1431
|
+
const conditions = [];
|
|
1432
|
+
if (Is.stringValue(providedBy)) {
|
|
1433
|
+
const condition = {
|
|
1434
|
+
property: "providedBy",
|
|
1435
|
+
value: providedBy,
|
|
1436
|
+
comparison: ComparisonOperator.Equals
|
|
1437
|
+
};
|
|
1438
|
+
conditions.push(condition);
|
|
1439
|
+
}
|
|
1440
|
+
if (Is.stringValue(id)) {
|
|
1441
|
+
const condition = {
|
|
1442
|
+
property: "id",
|
|
1443
|
+
value: id,
|
|
1444
|
+
comparison: ComparisonOperator.Equals
|
|
1445
|
+
};
|
|
1446
|
+
conditions.push(condition);
|
|
1447
|
+
}
|
|
1448
|
+
const entries = await this._entityStorageServiceOfferings.query({ conditions }, undefined, undefined, cursor, pageSize);
|
|
1449
|
+
const itemList = entries.entities.map(entry => {
|
|
1450
|
+
entry.type = GaiaXTypes.ServiceOffering;
|
|
1451
|
+
return entry;
|
|
1452
|
+
});
|
|
1453
|
+
const result = {
|
|
1454
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST,
|
|
1455
|
+
type: SchemaOrgTypes.ItemList,
|
|
1456
|
+
itemListElement: itemList,
|
|
1457
|
+
nextItem: entries.cursor
|
|
1458
|
+
};
|
|
1459
|
+
return JsonLdProcessor.compact(result, result["@context"]);
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Query the federated catalogue.
|
|
1463
|
+
* @param id The identity of the DataResource.
|
|
1464
|
+
* @param producedBy The identity of the participant.
|
|
1465
|
+
* @param cursor The cursor to request the next page of entities.
|
|
1466
|
+
* @param pageSize The maximum number of entities in a page.
|
|
1467
|
+
* @returns All the entities for the storage matching the conditions,
|
|
1468
|
+
* and a cursor which can be used to request more entities.
|
|
1469
|
+
* @throws NotImplementedError if the implementation does not support retrieval.
|
|
1470
|
+
*/
|
|
1471
|
+
async queryDataResources(id, producedBy, cursor, pageSize) {
|
|
1472
|
+
const conditions = [];
|
|
1473
|
+
if (Is.stringValue(producedBy)) {
|
|
1474
|
+
const condition = {
|
|
1475
|
+
property: "producedBy",
|
|
1476
|
+
value: producedBy,
|
|
1477
|
+
comparison: ComparisonOperator.Equals
|
|
1478
|
+
};
|
|
1479
|
+
conditions.push(condition);
|
|
1480
|
+
}
|
|
1481
|
+
if (Is.stringValue(id)) {
|
|
1482
|
+
const condition = {
|
|
1483
|
+
property: "id",
|
|
1484
|
+
value: id,
|
|
1485
|
+
comparison: ComparisonOperator.Equals
|
|
1486
|
+
};
|
|
1487
|
+
conditions.push(condition);
|
|
1488
|
+
}
|
|
1489
|
+
const entries = await this._entityStorageDataResources.query({ conditions }, undefined, undefined, cursor, pageSize);
|
|
1490
|
+
const itemList = entries.entities.map(entry => {
|
|
1491
|
+
entry.type = GaiaXTypes.DataResource;
|
|
1492
|
+
return entry;
|
|
1493
|
+
});
|
|
1494
|
+
const result = {
|
|
1495
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY_LIST,
|
|
1496
|
+
type: SchemaOrgTypes.ItemList,
|
|
1497
|
+
itemListElement: itemList,
|
|
1498
|
+
nextItem: entries.cursor
|
|
1499
|
+
};
|
|
1500
|
+
return JsonLdProcessor.compact(result, result["@context"]);
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Decodes the JWT.
|
|
1504
|
+
* @param jwt JWT.
|
|
1505
|
+
* @returns Decoded.
|
|
1506
|
+
*/
|
|
1507
|
+
async decodeJwt(jwt) {
|
|
1508
|
+
const { payload } = await VerificationHelper.verifyJwt(this._resolver, jwt);
|
|
1509
|
+
return payload;
|
|
1510
|
+
}
|
|
1511
|
+
/**
|
|
1512
|
+
* Returns the trusted Issuer id.
|
|
1513
|
+
* @param complianceCredential The compliance credential.
|
|
1514
|
+
* @returns The trusted issuer.
|
|
1515
|
+
*/
|
|
1516
|
+
getTrustedIssuerId(complianceCredential) {
|
|
1517
|
+
const trustedIssuerId = Is.object(complianceCredential.issuer)
|
|
1518
|
+
? complianceCredential.issuer.id
|
|
1519
|
+
: complianceCredential.issuer;
|
|
1520
|
+
return trustedIssuerId;
|
|
1521
|
+
}
|
|
1522
|
+
/**
|
|
1523
|
+
* Extracts participant entry from the credentials.
|
|
1524
|
+
* @param complianceCredential Compliance credential
|
|
1525
|
+
* @param participantCredential The Participant credential extracted.
|
|
1526
|
+
* @returns Participant Entry to be saved on the Database.
|
|
1527
|
+
*/
|
|
1528
|
+
extractParticipantEntry(complianceCredential, participantCredential) {
|
|
1529
|
+
const participantData = participantCredential.credentialSubject;
|
|
1530
|
+
Guards.objectValue(this.CLASS_NAME, "participantData", participantData);
|
|
1531
|
+
const evidences = [];
|
|
1532
|
+
for (const evidence of complianceCredential.evidence) {
|
|
1533
|
+
evidences.push(evidence.id);
|
|
1534
|
+
}
|
|
1535
|
+
const result = {
|
|
1536
|
+
...participantData,
|
|
1537
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY,
|
|
1538
|
+
issuer: this.getTrustedIssuerId(complianceCredential),
|
|
1539
|
+
validFrom: complianceCredential.validFrom,
|
|
1540
|
+
validUntil: complianceCredential.validUntil,
|
|
1541
|
+
dateCreated: new Date().toISOString(),
|
|
1542
|
+
evidence: evidences
|
|
1543
|
+
};
|
|
1544
|
+
return result;
|
|
1545
|
+
}
|
|
1546
|
+
/**
|
|
1547
|
+
* Extracts Data Space Connector description entry from the credentials.
|
|
1548
|
+
* @param complianceCredential Compliance Credential.
|
|
1549
|
+
* @param dataSpaceConnectorCredential Evidence Credential.
|
|
1550
|
+
* @returns Service Description Entry to be saved on the Database.
|
|
1551
|
+
*/
|
|
1552
|
+
extractDataSpaceConnectorEntry(complianceCredential, dataSpaceConnectorCredential) {
|
|
1553
|
+
const credentialData = dataSpaceConnectorCredential.credentialSubject;
|
|
1554
|
+
Guards.objectValue(this.CLASS_NAME, "credentialData", credentialData);
|
|
1555
|
+
const { offeredResource, ...deStructuredData } = credentialData;
|
|
1556
|
+
const result = {
|
|
1557
|
+
...deStructuredData,
|
|
1558
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY,
|
|
1559
|
+
offeredResource: Object.keys(offeredResource),
|
|
1560
|
+
issuer: this.getTrustedIssuerId(complianceCredential),
|
|
1561
|
+
validFrom: complianceCredential.validFrom,
|
|
1562
|
+
validUntil: complianceCredential.validUntil,
|
|
1563
|
+
dateCreated: new Date().toISOString(),
|
|
1564
|
+
evidence: [dataSpaceConnectorCredential.id]
|
|
1565
|
+
};
|
|
1566
|
+
return result;
|
|
1567
|
+
}
|
|
1568
|
+
/**
|
|
1569
|
+
* Extracts service offering entry from the credentials.
|
|
1570
|
+
* @param complianceCredential The Compliance Credential.
|
|
1571
|
+
* @param serviceOfferingCredential Service Offering credential (evidence).
|
|
1572
|
+
* @returns Service Offering Entry to be saved on the Database.
|
|
1573
|
+
*/
|
|
1574
|
+
extractServiceOfferingEntry(complianceCredential, serviceOfferingCredential) {
|
|
1575
|
+
const credentialData = serviceOfferingCredential.credentialSubject;
|
|
1576
|
+
Guards.objectValue(this.CLASS_NAME, "credentialData", credentialData);
|
|
1577
|
+
const { providedBy, aggregationOfResources, servicePolicy, ...deStructuredData } = credentialData;
|
|
1578
|
+
const result = {
|
|
1579
|
+
...deStructuredData,
|
|
1580
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY,
|
|
1581
|
+
providedBy: Is.string(providedBy) ? providedBy : providedBy.id,
|
|
1582
|
+
aggregationOfResources: aggregationOfResources,
|
|
1583
|
+
issuer: this.getTrustedIssuerId(complianceCredential),
|
|
1584
|
+
validFrom: complianceCredential.validFrom,
|
|
1585
|
+
validUntil: complianceCredential.validUntil,
|
|
1586
|
+
dateCreated: new Date().toISOString(),
|
|
1587
|
+
evidence: [serviceOfferingCredential.id],
|
|
1588
|
+
servicePolicy: ArrayHelper.fromObjectOrArray(servicePolicy)
|
|
1589
|
+
};
|
|
1590
|
+
return result;
|
|
1591
|
+
}
|
|
1592
|
+
/**
|
|
1593
|
+
* Extracts data resource entry from the credentials.
|
|
1594
|
+
* @param complianceCredential The Compliance Credential.
|
|
1595
|
+
* @param dataResourceCredential Data Resource credential.
|
|
1596
|
+
* @returns DataResource Entry to be saved on the Database.
|
|
1597
|
+
*/
|
|
1598
|
+
extractDataResourceEntry(complianceCredential, dataResourceCredential) {
|
|
1599
|
+
const credentialData = dataResourceCredential.credentialSubject;
|
|
1600
|
+
Guards.objectValue(this.CLASS_NAME, "credentialData", credentialData);
|
|
1601
|
+
const { producedBy, copyrightOwnedBy, exposedThrough, resourcePolicy, ...deStructuredData } = credentialData;
|
|
1602
|
+
let producedByValue = producedBy;
|
|
1603
|
+
if (Is.object(producedByValue)) {
|
|
1604
|
+
producedByValue = producedByValue.id;
|
|
1605
|
+
}
|
|
1606
|
+
let copyrightOwnedByValue = copyrightOwnedBy;
|
|
1607
|
+
if (Is.object(copyrightOwnedByValue)) {
|
|
1608
|
+
copyrightOwnedByValue = copyrightOwnedByValue.id;
|
|
1609
|
+
}
|
|
1610
|
+
const result = {
|
|
1611
|
+
...deStructuredData,
|
|
1612
|
+
"@context": FederatedCatalogueContextInstances.DEFAULT_LD_CONTEXT_ENTRY,
|
|
1613
|
+
issuer: this.getTrustedIssuerId(complianceCredential),
|
|
1614
|
+
producedBy: producedByValue,
|
|
1615
|
+
copyrightOwnedBy: copyrightOwnedByValue,
|
|
1616
|
+
exposedThrough: exposedThrough,
|
|
1617
|
+
validFrom: complianceCredential.validFrom,
|
|
1618
|
+
validUntil: complianceCredential.validUntil,
|
|
1619
|
+
dateCreated: new Date().toISOString(),
|
|
1620
|
+
evidence: [dataResourceCredential.id],
|
|
1621
|
+
resourcePolicy: ArrayHelper.fromObjectOrArray(resourcePolicy)
|
|
1622
|
+
};
|
|
1623
|
+
return result;
|
|
1624
|
+
}
|
|
1625
|
+
/**
|
|
1626
|
+
* Checks whether the Participant exists.
|
|
1627
|
+
* @param participantId The Participant identifier
|
|
1628
|
+
*/
|
|
1629
|
+
async checkParticipantExists(participantId) {
|
|
1630
|
+
const participantData = await this._entityStorageParticipants.get(participantId);
|
|
1631
|
+
if (!participantData) {
|
|
1632
|
+
this._loggingService?.log({
|
|
1633
|
+
level: "error",
|
|
1634
|
+
source: this.CLASS_NAME,
|
|
1635
|
+
ts: Date.now(),
|
|
1636
|
+
message: "providerIsNotParticipant",
|
|
1637
|
+
data: { providedBy: participantId }
|
|
1638
|
+
});
|
|
1639
|
+
throw new UnprocessableError(this.CLASS_NAME, "providerIsNotParticipant", {
|
|
1640
|
+
providedBy: participantId
|
|
1641
|
+
});
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
const restEntryPoints = [
|
|
1647
|
+
{
|
|
1648
|
+
name: "federated-catalogue",
|
|
1649
|
+
defaultBaseRoute: "federated-catalogue",
|
|
1650
|
+
tags: tagsFederatedCatalogue,
|
|
1651
|
+
generateRoutes: generateRestRoutesFederatedCatalogue
|
|
1652
|
+
}
|
|
1653
|
+
];
|
|
1654
|
+
|
|
1655
|
+
// Copyright 2024 IOTA Stiftung.
|
|
1656
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
1657
|
+
/**
|
|
1658
|
+
* Data Resource Entry.
|
|
1659
|
+
*/
|
|
1660
|
+
let DataResourceEntry = class DataResourceEntry {
|
|
1661
|
+
/**
|
|
1662
|
+
* The Id.
|
|
1663
|
+
*/
|
|
1664
|
+
id;
|
|
1665
|
+
/**
|
|
1666
|
+
* The trusted issuer of the compliance credential
|
|
1667
|
+
*/
|
|
1668
|
+
issuer;
|
|
1669
|
+
/**
|
|
1670
|
+
* The name.
|
|
1671
|
+
*/
|
|
1672
|
+
name;
|
|
1673
|
+
/**
|
|
1674
|
+
* The description.
|
|
1675
|
+
*/
|
|
1676
|
+
description;
|
|
1677
|
+
/**
|
|
1678
|
+
* The Id of the producer of the data described by this Data Resource.
|
|
1679
|
+
*/
|
|
1680
|
+
producedBy;
|
|
1681
|
+
/**
|
|
1682
|
+
* The copyright owner
|
|
1683
|
+
*/
|
|
1684
|
+
copyrightOwnedBy;
|
|
1685
|
+
/**
|
|
1686
|
+
* The license
|
|
1687
|
+
*/
|
|
1688
|
+
license;
|
|
1689
|
+
/**
|
|
1690
|
+
* The data exchange component used to expose the Data Resource.
|
|
1691
|
+
* Only a URL pointing to the resource is stored
|
|
1692
|
+
*/
|
|
1693
|
+
exposedThrough;
|
|
1694
|
+
/**
|
|
1695
|
+
* The Data Resource policy
|
|
1696
|
+
*/
|
|
1697
|
+
resourcePolicy;
|
|
1698
|
+
/**
|
|
1699
|
+
* Valid from
|
|
1700
|
+
*/
|
|
1701
|
+
validFrom;
|
|
1702
|
+
/**
|
|
1703
|
+
* Valid to
|
|
1704
|
+
*/
|
|
1705
|
+
validUntil;
|
|
1706
|
+
/**
|
|
1707
|
+
* Date created
|
|
1708
|
+
*/
|
|
1709
|
+
dateCreated;
|
|
1710
|
+
/**
|
|
1711
|
+
* Evidences
|
|
1712
|
+
*/
|
|
1713
|
+
evidence;
|
|
1714
|
+
};
|
|
1715
|
+
__decorate([
|
|
1716
|
+
property({ type: "string", isPrimary: true }),
|
|
1717
|
+
__metadata("design:type", String)
|
|
1718
|
+
], DataResourceEntry.prototype, "id", void 0);
|
|
1719
|
+
__decorate([
|
|
1720
|
+
property({ type: "string" }),
|
|
1721
|
+
__metadata("design:type", String)
|
|
1722
|
+
], DataResourceEntry.prototype, "issuer", void 0);
|
|
1723
|
+
__decorate([
|
|
1724
|
+
property({ type: "string" }),
|
|
1725
|
+
__metadata("design:type", String)
|
|
1726
|
+
], DataResourceEntry.prototype, "name", void 0);
|
|
1727
|
+
__decorate([
|
|
1728
|
+
property({ type: "string", optional: true }),
|
|
1729
|
+
__metadata("design:type", String)
|
|
1730
|
+
], DataResourceEntry.prototype, "description", void 0);
|
|
1731
|
+
__decorate([
|
|
1732
|
+
property({ type: "string", isSecondary: true }),
|
|
1733
|
+
__metadata("design:type", String)
|
|
1734
|
+
], DataResourceEntry.prototype, "producedBy", void 0);
|
|
1735
|
+
__decorate([
|
|
1736
|
+
property({ type: "string" }),
|
|
1737
|
+
__metadata("design:type", String)
|
|
1738
|
+
], DataResourceEntry.prototype, "copyrightOwnedBy", void 0);
|
|
1739
|
+
__decorate([
|
|
1740
|
+
property({ type: "string" }),
|
|
1741
|
+
__metadata("design:type", String)
|
|
1742
|
+
], DataResourceEntry.prototype, "license", void 0);
|
|
1743
|
+
__decorate([
|
|
1744
|
+
property({ type: "string" }),
|
|
1745
|
+
__metadata("design:type", String)
|
|
1746
|
+
], DataResourceEntry.prototype, "exposedThrough", void 0);
|
|
1747
|
+
__decorate([
|
|
1748
|
+
property({ type: "array" }),
|
|
1749
|
+
__metadata("design:type", Array)
|
|
1750
|
+
], DataResourceEntry.prototype, "resourcePolicy", void 0);
|
|
1751
|
+
__decorate([
|
|
1752
|
+
property({ type: "string", format: "date-time" }),
|
|
1753
|
+
__metadata("design:type", String)
|
|
1754
|
+
], DataResourceEntry.prototype, "validFrom", void 0);
|
|
1755
|
+
__decorate([
|
|
1756
|
+
property({ type: "string", format: "date-time" }),
|
|
1757
|
+
__metadata("design:type", String)
|
|
1758
|
+
], DataResourceEntry.prototype, "validUntil", void 0);
|
|
1759
|
+
__decorate([
|
|
1760
|
+
property({ type: "string", format: "date-time", sortDirection: SortDirection.Descending }),
|
|
1761
|
+
__metadata("design:type", String)
|
|
1762
|
+
], DataResourceEntry.prototype, "dateCreated", void 0);
|
|
1763
|
+
__decorate([
|
|
1764
|
+
property({ type: "array" }),
|
|
1765
|
+
__metadata("design:type", Array)
|
|
1766
|
+
], DataResourceEntry.prototype, "evidence", void 0);
|
|
1767
|
+
DataResourceEntry = __decorate([
|
|
1768
|
+
entity()
|
|
1769
|
+
], DataResourceEntry);
|
|
1770
|
+
|
|
1771
|
+
// Copyright 2024 IOTA Stiftung.
|
|
1772
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
1773
|
+
/**
|
|
1774
|
+
* Data Space Connector Entry.
|
|
1775
|
+
*/
|
|
1776
|
+
let DataSpaceConnectorEntry = class DataSpaceConnectorEntry {
|
|
1777
|
+
/**
|
|
1778
|
+
* The Id.
|
|
1779
|
+
*/
|
|
1780
|
+
id;
|
|
1781
|
+
/**
|
|
1782
|
+
* The trusted issuer of the compliance credential.
|
|
1783
|
+
*/
|
|
1784
|
+
issuer;
|
|
1785
|
+
/**
|
|
1786
|
+
* The name.
|
|
1787
|
+
*/
|
|
1788
|
+
name;
|
|
1789
|
+
/**
|
|
1790
|
+
* The description.
|
|
1791
|
+
*/
|
|
1792
|
+
description;
|
|
1793
|
+
/**
|
|
1794
|
+
* The identity of the Data Space Connector
|
|
1795
|
+
*/
|
|
1796
|
+
identity;
|
|
1797
|
+
/**
|
|
1798
|
+
* Who maintains the Data Space Connector
|
|
1799
|
+
*/
|
|
1800
|
+
maintainer;
|
|
1801
|
+
/**
|
|
1802
|
+
* The default endpoint
|
|
1803
|
+
*/
|
|
1804
|
+
defaultEndpoint;
|
|
1805
|
+
/**
|
|
1806
|
+
* The activity push endpoint
|
|
1807
|
+
*/
|
|
1808
|
+
pushActivityEndpoint;
|
|
1809
|
+
/**
|
|
1810
|
+
* The activity subscribe endpoint
|
|
1811
|
+
*/
|
|
1812
|
+
subscriptionActivityEndpoint;
|
|
1813
|
+
/**
|
|
1814
|
+
* The pull data endpoint
|
|
1815
|
+
*/
|
|
1816
|
+
pullDataEndpoint;
|
|
1817
|
+
/**
|
|
1818
|
+
* The pull data endpoint
|
|
1819
|
+
*/
|
|
1820
|
+
offeredResource;
|
|
1821
|
+
/**
|
|
1822
|
+
* Valid from
|
|
1823
|
+
*/
|
|
1824
|
+
validFrom;
|
|
1825
|
+
/**
|
|
1826
|
+
* Valid to
|
|
1827
|
+
*/
|
|
1828
|
+
validUntil;
|
|
1829
|
+
/**
|
|
1830
|
+
* Date created
|
|
1831
|
+
*/
|
|
1832
|
+
dateCreated;
|
|
1833
|
+
/**
|
|
1834
|
+
* Evidences
|
|
1835
|
+
*/
|
|
1836
|
+
evidence;
|
|
1837
|
+
};
|
|
1838
|
+
__decorate([
|
|
1839
|
+
property({ type: "string", isPrimary: true }),
|
|
1840
|
+
__metadata("design:type", String)
|
|
1841
|
+
], DataSpaceConnectorEntry.prototype, "id", void 0);
|
|
1842
|
+
__decorate([
|
|
1843
|
+
property({ type: "string" }),
|
|
1844
|
+
__metadata("design:type", String)
|
|
1845
|
+
], DataSpaceConnectorEntry.prototype, "issuer", void 0);
|
|
1846
|
+
__decorate([
|
|
1847
|
+
property({ type: "string", optional: true }),
|
|
1848
|
+
__metadata("design:type", String)
|
|
1849
|
+
], DataSpaceConnectorEntry.prototype, "name", void 0);
|
|
1850
|
+
__decorate([
|
|
1851
|
+
property({ type: "string", optional: true }),
|
|
1852
|
+
__metadata("design:type", String)
|
|
1853
|
+
], DataSpaceConnectorEntry.prototype, "description", void 0);
|
|
1854
|
+
__decorate([
|
|
1855
|
+
property({ type: "string" }),
|
|
1856
|
+
__metadata("design:type", String)
|
|
1857
|
+
], DataSpaceConnectorEntry.prototype, "identity", void 0);
|
|
1858
|
+
__decorate([
|
|
1859
|
+
property({ type: "string", isSecondary: true }),
|
|
1860
|
+
__metadata("design:type", String)
|
|
1861
|
+
], DataSpaceConnectorEntry.prototype, "maintainer", void 0);
|
|
1862
|
+
__decorate([
|
|
1863
|
+
property({ type: "object" }),
|
|
1864
|
+
__metadata("design:type", Object)
|
|
1865
|
+
], DataSpaceConnectorEntry.prototype, "defaultEndpoint", void 0);
|
|
1866
|
+
__decorate([
|
|
1867
|
+
property({ type: "object" }),
|
|
1868
|
+
__metadata("design:type", Object)
|
|
1869
|
+
], DataSpaceConnectorEntry.prototype, "pushActivityEndpoint", void 0);
|
|
1870
|
+
__decorate([
|
|
1871
|
+
property({ type: "object", optional: true }),
|
|
1872
|
+
__metadata("design:type", Object)
|
|
1873
|
+
], DataSpaceConnectorEntry.prototype, "subscriptionActivityEndpoint", void 0);
|
|
1874
|
+
__decorate([
|
|
1875
|
+
property({ type: "object" }),
|
|
1876
|
+
__metadata("design:type", Object)
|
|
1877
|
+
], DataSpaceConnectorEntry.prototype, "pullDataEndpoint", void 0);
|
|
1878
|
+
__decorate([
|
|
1879
|
+
property({ type: "array" }),
|
|
1880
|
+
__metadata("design:type", Array)
|
|
1881
|
+
], DataSpaceConnectorEntry.prototype, "offeredResource", void 0);
|
|
1882
|
+
__decorate([
|
|
1883
|
+
property({ type: "string", format: "date-time" }),
|
|
1884
|
+
__metadata("design:type", String)
|
|
1885
|
+
], DataSpaceConnectorEntry.prototype, "validFrom", void 0);
|
|
1886
|
+
__decorate([
|
|
1887
|
+
property({ type: "string", format: "date-time" }),
|
|
1888
|
+
__metadata("design:type", String)
|
|
1889
|
+
], DataSpaceConnectorEntry.prototype, "validUntil", void 0);
|
|
1890
|
+
__decorate([
|
|
1891
|
+
property({ type: "string", format: "date-time", sortDirection: SortDirection.Descending }),
|
|
1892
|
+
__metadata("design:type", String)
|
|
1893
|
+
], DataSpaceConnectorEntry.prototype, "dateCreated", void 0);
|
|
1894
|
+
__decorate([
|
|
1895
|
+
property({ type: "array" }),
|
|
1896
|
+
__metadata("design:type", Array)
|
|
1897
|
+
], DataSpaceConnectorEntry.prototype, "evidence", void 0);
|
|
1898
|
+
DataSpaceConnectorEntry = __decorate([
|
|
1899
|
+
entity()
|
|
1900
|
+
], DataSpaceConnectorEntry);
|
|
1901
|
+
|
|
1902
|
+
// Copyright 2024 IOTA Stiftung.
|
|
1903
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
1904
|
+
/**
|
|
1905
|
+
* Participant entry.
|
|
1906
|
+
*/
|
|
1907
|
+
let ParticipantEntry = class ParticipantEntry {
|
|
1908
|
+
/**
|
|
1909
|
+
* The participant Id.
|
|
1910
|
+
*/
|
|
1911
|
+
id;
|
|
1912
|
+
/**
|
|
1913
|
+
* The trusted issuer of the compliance credential
|
|
1914
|
+
*/
|
|
1915
|
+
issuer;
|
|
1916
|
+
/**
|
|
1917
|
+
* The legal registration number.
|
|
1918
|
+
*/
|
|
1919
|
+
registrationNumber;
|
|
1920
|
+
/**
|
|
1921
|
+
* The legal name.
|
|
1922
|
+
*/
|
|
1923
|
+
legalName;
|
|
1924
|
+
/**
|
|
1925
|
+
* Address
|
|
1926
|
+
*/
|
|
1927
|
+
legalAddress;
|
|
1928
|
+
/**
|
|
1929
|
+
* Valid from
|
|
1930
|
+
*/
|
|
1931
|
+
validFrom;
|
|
1932
|
+
/**
|
|
1933
|
+
* Valid to
|
|
1934
|
+
*/
|
|
1935
|
+
validUntil;
|
|
1936
|
+
/**
|
|
1937
|
+
* Date created
|
|
1938
|
+
*/
|
|
1939
|
+
dateCreated;
|
|
1940
|
+
/**
|
|
1941
|
+
* Evidences
|
|
1942
|
+
*/
|
|
1943
|
+
evidence;
|
|
1944
|
+
};
|
|
1945
|
+
__decorate([
|
|
1946
|
+
property({ type: "string", isPrimary: true }),
|
|
1947
|
+
__metadata("design:type", String)
|
|
1948
|
+
], ParticipantEntry.prototype, "id", void 0);
|
|
1949
|
+
__decorate([
|
|
1950
|
+
property({ type: "string" }),
|
|
1951
|
+
__metadata("design:type", String)
|
|
1952
|
+
], ParticipantEntry.prototype, "issuer", void 0);
|
|
1953
|
+
__decorate([
|
|
1954
|
+
property({ type: "object", isSecondary: true }),
|
|
1955
|
+
__metadata("design:type", Object)
|
|
1956
|
+
], ParticipantEntry.prototype, "registrationNumber", void 0);
|
|
1957
|
+
__decorate([
|
|
1958
|
+
property({ type: "string", isSecondary: true }),
|
|
1959
|
+
__metadata("design:type", String)
|
|
1960
|
+
], ParticipantEntry.prototype, "legalName", void 0);
|
|
1961
|
+
__decorate([
|
|
1962
|
+
property({ type: "object" }),
|
|
1963
|
+
__metadata("design:type", Object)
|
|
1964
|
+
], ParticipantEntry.prototype, "legalAddress", void 0);
|
|
1965
|
+
__decorate([
|
|
1966
|
+
property({ type: "string", format: "date-time" }),
|
|
1967
|
+
__metadata("design:type", String)
|
|
1968
|
+
], ParticipantEntry.prototype, "validFrom", void 0);
|
|
1969
|
+
__decorate([
|
|
1970
|
+
property({ type: "string", format: "date-time" }),
|
|
1971
|
+
__metadata("design:type", String)
|
|
1972
|
+
], ParticipantEntry.prototype, "validUntil", void 0);
|
|
1973
|
+
__decorate([
|
|
1974
|
+
property({ type: "string", format: "date-time", sortDirection: SortDirection.Descending }),
|
|
1975
|
+
__metadata("design:type", String)
|
|
1976
|
+
], ParticipantEntry.prototype, "dateCreated", void 0);
|
|
1977
|
+
__decorate([
|
|
1978
|
+
property({ type: "array" }),
|
|
1979
|
+
__metadata("design:type", Array)
|
|
1980
|
+
], ParticipantEntry.prototype, "evidence", void 0);
|
|
1981
|
+
ParticipantEntry = __decorate([
|
|
1982
|
+
entity()
|
|
1983
|
+
], ParticipantEntry);
|
|
1984
|
+
|
|
1985
|
+
// Copyright 2024 IOTA Stiftung.
|
|
1986
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
1987
|
+
/**
|
|
1988
|
+
* Service Offering Entry.
|
|
1989
|
+
*/
|
|
1990
|
+
let ServiceOfferingEntry = class ServiceOfferingEntry {
|
|
1991
|
+
/**
|
|
1992
|
+
* The service Id.
|
|
1993
|
+
*/
|
|
1994
|
+
id;
|
|
1995
|
+
/**
|
|
1996
|
+
* The trusted issuer of the compliance credential associated with
|
|
1997
|
+
*/
|
|
1998
|
+
issuer;
|
|
1999
|
+
/**
|
|
2000
|
+
* The service name.
|
|
2001
|
+
*/
|
|
2002
|
+
name;
|
|
2003
|
+
/**
|
|
2004
|
+
* The service description.
|
|
2005
|
+
*/
|
|
2006
|
+
description;
|
|
2007
|
+
/**
|
|
2008
|
+
* The provider Id
|
|
2009
|
+
*/
|
|
2010
|
+
providedBy;
|
|
2011
|
+
/**
|
|
2012
|
+
* The REST endpoint
|
|
2013
|
+
*/
|
|
2014
|
+
endpoint;
|
|
2015
|
+
/**
|
|
2016
|
+
* The policy
|
|
2017
|
+
*/
|
|
2018
|
+
servicePolicy;
|
|
2019
|
+
/**
|
|
2020
|
+
* Resources aggregated
|
|
2021
|
+
*/
|
|
2022
|
+
aggregationOfResources;
|
|
2023
|
+
/**
|
|
2024
|
+
* Valid from
|
|
2025
|
+
*/
|
|
2026
|
+
validFrom;
|
|
2027
|
+
/**
|
|
2028
|
+
* Valid to
|
|
2029
|
+
*/
|
|
2030
|
+
validUntil;
|
|
2031
|
+
/**
|
|
2032
|
+
* Date created
|
|
2033
|
+
*/
|
|
2034
|
+
dateCreated;
|
|
2035
|
+
/**
|
|
2036
|
+
* Evidences
|
|
2037
|
+
*/
|
|
2038
|
+
evidence;
|
|
2039
|
+
};
|
|
2040
|
+
__decorate([
|
|
2041
|
+
property({ type: "string", isPrimary: true }),
|
|
2042
|
+
__metadata("design:type", String)
|
|
2043
|
+
], ServiceOfferingEntry.prototype, "id", void 0);
|
|
2044
|
+
__decorate([
|
|
2045
|
+
property({ type: "string" }),
|
|
2046
|
+
__metadata("design:type", String)
|
|
2047
|
+
], ServiceOfferingEntry.prototype, "issuer", void 0);
|
|
2048
|
+
__decorate([
|
|
2049
|
+
property({ type: "string" }),
|
|
2050
|
+
__metadata("design:type", String)
|
|
2051
|
+
], ServiceOfferingEntry.prototype, "name", void 0);
|
|
2052
|
+
__decorate([
|
|
2053
|
+
property({ type: "string", optional: true }),
|
|
2054
|
+
__metadata("design:type", String)
|
|
2055
|
+
], ServiceOfferingEntry.prototype, "description", void 0);
|
|
2056
|
+
__decorate([
|
|
2057
|
+
property({ type: "string", isSecondary: true }),
|
|
2058
|
+
__metadata("design:type", String)
|
|
2059
|
+
], ServiceOfferingEntry.prototype, "providedBy", void 0);
|
|
2060
|
+
__decorate([
|
|
2061
|
+
property({ type: "object" }),
|
|
2062
|
+
__metadata("design:type", Object)
|
|
2063
|
+
], ServiceOfferingEntry.prototype, "endpoint", void 0);
|
|
2064
|
+
__decorate([
|
|
2065
|
+
property({ type: "array" }),
|
|
2066
|
+
__metadata("design:type", Array)
|
|
2067
|
+
], ServiceOfferingEntry.prototype, "servicePolicy", void 0);
|
|
2068
|
+
__decorate([
|
|
2069
|
+
property({ type: "array", optional: true }),
|
|
2070
|
+
__metadata("design:type", Array)
|
|
2071
|
+
], ServiceOfferingEntry.prototype, "aggregationOfResources", void 0);
|
|
2072
|
+
__decorate([
|
|
2073
|
+
property({ type: "string", format: "date-time" }),
|
|
2074
|
+
__metadata("design:type", String)
|
|
2075
|
+
], ServiceOfferingEntry.prototype, "validFrom", void 0);
|
|
2076
|
+
__decorate([
|
|
2077
|
+
property({ type: "string", format: "date-time" }),
|
|
2078
|
+
__metadata("design:type", String)
|
|
2079
|
+
], ServiceOfferingEntry.prototype, "validUntil", void 0);
|
|
2080
|
+
__decorate([
|
|
2081
|
+
property({ type: "string", format: "date-time", sortDirection: SortDirection.Descending }),
|
|
2082
|
+
__metadata("design:type", String)
|
|
2083
|
+
], ServiceOfferingEntry.prototype, "dateCreated", void 0);
|
|
2084
|
+
__decorate([
|
|
2085
|
+
property({ type: "array" }),
|
|
2086
|
+
__metadata("design:type", Array)
|
|
2087
|
+
], ServiceOfferingEntry.prototype, "evidence", void 0);
|
|
2088
|
+
ServiceOfferingEntry = __decorate([
|
|
2089
|
+
entity()
|
|
2090
|
+
], ServiceOfferingEntry);
|
|
2091
|
+
|
|
2092
|
+
// Copyright 2024 IOTA Stiftung.
|
|
2093
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
2094
|
+
/**
|
|
2095
|
+
* Inits schemas.
|
|
2096
|
+
*/
|
|
2097
|
+
function initSchema() {
|
|
2098
|
+
EntitySchemaFactory.register("ParticipantEntry", () => EntitySchemaHelper.getSchema(ParticipantEntry));
|
|
2099
|
+
EntitySchemaFactory.register("DataResourceEntry", () => EntitySchemaHelper.getSchema(DataResourceEntry));
|
|
2100
|
+
EntitySchemaFactory.register("ServiceOfferingEntry", () => EntitySchemaHelper.getSchema(ServiceOfferingEntry));
|
|
2101
|
+
EntitySchemaFactory.register("DataSpaceConnectorEntry", () => EntitySchemaHelper.getSchema(DataSpaceConnectorEntry));
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
export { DataResourceEntry, DataSpaceConnectorEntry, FederatedCatalogueService, ParticipantEntry, ServiceOfferingEntry, complianceCredentialPresentation, dataResourceCredentialPresentation, dataResourceGet, dataResourceList, dataSpaceConnectorCredentialPresentation, dataSpaceConnectorGet, dataSpaceConnectorList, generateRestRoutesFederatedCatalogue, initSchema, participantGet, participantList, restEntryPoints, serviceOfferingCredentialPresentation, serviceOfferingGet, serviceOfferingList, tagsFederatedCatalogue };
|