@sphereon/ssi-sdk.vc-status-list-issuer 0.34.1-next.3 → 0.34.1-next.322
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +539 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +59 -2
- package/dist/index.d.ts +59 -2
- package/dist/index.js +526 -0
- package/dist/index.js.map +1 -1
- package/package.json +20 -19
- package/src/agent/StatusListPlugin.ts +17 -0
- package/src/functions.ts +5 -4
- package/src/index.ts +1 -0
- package/src/types.ts +9 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,10 +1,67 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StatusListResult, IStatusListPlugin } from '@sphereon/ssi-sdk.vc-status-list';
|
|
2
|
+
import { StatusListManagementOptions, IStatusListDriver } from '@sphereon/ssi-sdk.vc-status-list-issuer-drivers';
|
|
2
3
|
import { OrPromise } from '@sphereon/ssi-types';
|
|
3
4
|
import { DataSource } from 'typeorm';
|
|
5
|
+
import { DataSources } from '@sphereon/ssi-sdk.agent-config';
|
|
6
|
+
import { IAgentPlugin } from '@veramo/core';
|
|
4
7
|
|
|
5
8
|
type StatusListInstance = StatusListManagementOptions & {
|
|
6
9
|
dataSource?: OrPromise<DataSource>;
|
|
7
10
|
issuer?: string;
|
|
8
11
|
};
|
|
12
|
+
interface IDriverAndStatusListResult {
|
|
13
|
+
slDriver: IStatusListDriver;
|
|
14
|
+
statusList: StatusListRef;
|
|
15
|
+
}
|
|
16
|
+
type StatusListRef = Pick<StatusListResult, 'id' | 'correlationId' | 'type' | 'oauthStatusList' | 'bitstringStatusList'>;
|
|
9
17
|
|
|
10
|
-
|
|
18
|
+
declare class StatusListPlugin implements IAgentPlugin {
|
|
19
|
+
private readonly instances;
|
|
20
|
+
private readonly defaultStatusListId?;
|
|
21
|
+
private readonly allDataSources;
|
|
22
|
+
private initialized;
|
|
23
|
+
readonly methods: IStatusListPlugin;
|
|
24
|
+
constructor(opts: {
|
|
25
|
+
instances?: Array<StatusListInstance>;
|
|
26
|
+
defaultStatusListId?: string;
|
|
27
|
+
allDataSources?: DataSources;
|
|
28
|
+
autoCreateInstances?: boolean;
|
|
29
|
+
});
|
|
30
|
+
private init;
|
|
31
|
+
private slImportStatusLists;
|
|
32
|
+
private createStatusListInstance;
|
|
33
|
+
private getDriverForStatusListOption;
|
|
34
|
+
private slGetStatusList;
|
|
35
|
+
private selectDatasource;
|
|
36
|
+
private slCreateStatusList;
|
|
37
|
+
/**
|
|
38
|
+
* Selects bitsPerStatus from the used status list type when applicable
|
|
39
|
+
* @param sl
|
|
40
|
+
* @private
|
|
41
|
+
*/
|
|
42
|
+
private selectBitsPerStatus;
|
|
43
|
+
/**
|
|
44
|
+
* Adds status information to a credential by either:
|
|
45
|
+
* 1. Using existing status ID from the credential if present
|
|
46
|
+
* 2. Using provided status list options
|
|
47
|
+
* 3. Falling back to the default status list ID
|
|
48
|
+
*
|
|
49
|
+
* @param args Contains credential and status options
|
|
50
|
+
* @param context Required agent context
|
|
51
|
+
* @returns Credential with added status information
|
|
52
|
+
*/
|
|
53
|
+
private slAddStatusToCredential;
|
|
54
|
+
/**
|
|
55
|
+
* Adds status information to an SD-JWT credential by either:
|
|
56
|
+
* 1. Using existing status URI from the credential if present
|
|
57
|
+
* 2. Using provided status list options
|
|
58
|
+
* 3. Falling back to the default status list ID
|
|
59
|
+
*
|
|
60
|
+
* @param args Contains SD-JWT credential and status options
|
|
61
|
+
* @param context Required agent context
|
|
62
|
+
* @returns SD-JWT credential with added status information
|
|
63
|
+
*/
|
|
64
|
+
private slAddStatusToSdJwtCredential;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export { type IDriverAndStatusListResult, type StatusListInstance, StatusListPlugin, type StatusListRef };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,67 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StatusListResult, IStatusListPlugin } from '@sphereon/ssi-sdk.vc-status-list';
|
|
2
|
+
import { StatusListManagementOptions, IStatusListDriver } from '@sphereon/ssi-sdk.vc-status-list-issuer-drivers';
|
|
2
3
|
import { OrPromise } from '@sphereon/ssi-types';
|
|
3
4
|
import { DataSource } from 'typeorm';
|
|
5
|
+
import { DataSources } from '@sphereon/ssi-sdk.agent-config';
|
|
6
|
+
import { IAgentPlugin } from '@veramo/core';
|
|
4
7
|
|
|
5
8
|
type StatusListInstance = StatusListManagementOptions & {
|
|
6
9
|
dataSource?: OrPromise<DataSource>;
|
|
7
10
|
issuer?: string;
|
|
8
11
|
};
|
|
12
|
+
interface IDriverAndStatusListResult {
|
|
13
|
+
slDriver: IStatusListDriver;
|
|
14
|
+
statusList: StatusListRef;
|
|
15
|
+
}
|
|
16
|
+
type StatusListRef = Pick<StatusListResult, 'id' | 'correlationId' | 'type' | 'oauthStatusList' | 'bitstringStatusList'>;
|
|
9
17
|
|
|
10
|
-
|
|
18
|
+
declare class StatusListPlugin implements IAgentPlugin {
|
|
19
|
+
private readonly instances;
|
|
20
|
+
private readonly defaultStatusListId?;
|
|
21
|
+
private readonly allDataSources;
|
|
22
|
+
private initialized;
|
|
23
|
+
readonly methods: IStatusListPlugin;
|
|
24
|
+
constructor(opts: {
|
|
25
|
+
instances?: Array<StatusListInstance>;
|
|
26
|
+
defaultStatusListId?: string;
|
|
27
|
+
allDataSources?: DataSources;
|
|
28
|
+
autoCreateInstances?: boolean;
|
|
29
|
+
});
|
|
30
|
+
private init;
|
|
31
|
+
private slImportStatusLists;
|
|
32
|
+
private createStatusListInstance;
|
|
33
|
+
private getDriverForStatusListOption;
|
|
34
|
+
private slGetStatusList;
|
|
35
|
+
private selectDatasource;
|
|
36
|
+
private slCreateStatusList;
|
|
37
|
+
/**
|
|
38
|
+
* Selects bitsPerStatus from the used status list type when applicable
|
|
39
|
+
* @param sl
|
|
40
|
+
* @private
|
|
41
|
+
*/
|
|
42
|
+
private selectBitsPerStatus;
|
|
43
|
+
/**
|
|
44
|
+
* Adds status information to a credential by either:
|
|
45
|
+
* 1. Using existing status ID from the credential if present
|
|
46
|
+
* 2. Using provided status list options
|
|
47
|
+
* 3. Falling back to the default status list ID
|
|
48
|
+
*
|
|
49
|
+
* @param args Contains credential and status options
|
|
50
|
+
* @param context Required agent context
|
|
51
|
+
* @returns Credential with added status information
|
|
52
|
+
*/
|
|
53
|
+
private slAddStatusToCredential;
|
|
54
|
+
/**
|
|
55
|
+
* Adds status information to an SD-JWT credential by either:
|
|
56
|
+
* 1. Using existing status URI from the credential if present
|
|
57
|
+
* 2. Using provided status list options
|
|
58
|
+
* 3. Falling back to the default status list ID
|
|
59
|
+
*
|
|
60
|
+
* @param args Contains SD-JWT credential and status options
|
|
61
|
+
* @param context Required agent context
|
|
62
|
+
* @returns SD-JWT credential with added status information
|
|
63
|
+
*/
|
|
64
|
+
private slAddStatusToSdJwtCredential;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export { type IDriverAndStatusListResult, type StatusListInstance, StatusListPlugin, type StatusListRef };
|
package/dist/index.js
CHANGED
|
@@ -1 +1,527 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/agent/StatusListPlugin.ts
|
|
5
|
+
import { DataSources } from "@sphereon/ssi-sdk.agent-config";
|
|
6
|
+
import { createNewStatusList } from "@sphereon/ssi-sdk.vc-status-list";
|
|
7
|
+
import { getDriver as getDriver2 } from "@sphereon/ssi-sdk.vc-status-list-issuer-drivers";
|
|
8
|
+
import { Loggers as Loggers2 } from "@sphereon/ssi-types";
|
|
9
|
+
|
|
10
|
+
// src/functions.ts
|
|
11
|
+
import { getDriver } from "@sphereon/ssi-sdk.vc-status-list-issuer-drivers";
|
|
12
|
+
import debug from "debug";
|
|
13
|
+
import { Loggers } from "@sphereon/ssi-types";
|
|
14
|
+
var logger = Loggers.DEFAULT.get("sphereon:ssi-sdk:vc-status-list-issuer");
|
|
15
|
+
async function getDriverAndStatusList(statusListId, opts) {
|
|
16
|
+
const slDriver = opts?.driver ?? await getDriver({
|
|
17
|
+
id: statusListId,
|
|
18
|
+
dataSource: opts?.dataSource
|
|
19
|
+
});
|
|
20
|
+
const statusList = await slDriver.statusListStore.getStatusList({
|
|
21
|
+
id: statusListId
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
slDriver,
|
|
25
|
+
statusList
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
__name(getDriverAndStatusList, "getDriverAndStatusList");
|
|
29
|
+
function getCredentialStatusListOpts(credential, opts) {
|
|
30
|
+
const statusListOpts = [
|
|
31
|
+
...opts?.statusLists ?? []
|
|
32
|
+
];
|
|
33
|
+
if (statusListOpts.length === 0 && credential.credentialStatus) {
|
|
34
|
+
if (Array.isArray(credential.credentialStatus)) {
|
|
35
|
+
for (const credStatus of credential.credentialStatus) {
|
|
36
|
+
if (credStatus.statusListCredential) {
|
|
37
|
+
statusListOpts.push({
|
|
38
|
+
statusListId: credStatus.statusListCredential,
|
|
39
|
+
statusListIndex: credStatus.statusListIndex,
|
|
40
|
+
statusListCorrelationId: credStatus.statusListCorrelationId,
|
|
41
|
+
statusEntryCorrelationId: credStatus.statusEntryCorrelationId
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
} else if (credential.credentialStatus.statusListCredential) {
|
|
46
|
+
statusListOpts.push({
|
|
47
|
+
statusListId: credential.credentialStatus.statusListCredential,
|
|
48
|
+
statusListIndex: credential.credentialStatus.statusListIndex,
|
|
49
|
+
statusListCorrelationId: credential.credentialStatus.statusListCorrelationId,
|
|
50
|
+
statusEntryCorrelationId: credential.credentialStatus.statusEntryCorrelationId
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return statusListOpts;
|
|
55
|
+
}
|
|
56
|
+
__name(getCredentialStatusListOpts, "getCredentialStatusListOpts");
|
|
57
|
+
function getSdJwtStatusListOpts(credential, opts) {
|
|
58
|
+
const statusListOpts = [
|
|
59
|
+
...opts?.statusLists ?? []
|
|
60
|
+
];
|
|
61
|
+
if (statusListOpts.length === 0 && credential.status?.status_list) {
|
|
62
|
+
statusListOpts.push({
|
|
63
|
+
statusListId: credential.status.status_list.uri,
|
|
64
|
+
statusListIndex: credential.status.status_list.idx
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return statusListOpts;
|
|
68
|
+
}
|
|
69
|
+
__name(getSdJwtStatusListOpts, "getSdJwtStatusListOpts");
|
|
70
|
+
async function processStatusListEntry(params) {
|
|
71
|
+
let existingEntry = void 0;
|
|
72
|
+
if (params.credentialId) {
|
|
73
|
+
existingEntry = await params.slDriver.getStatusListEntryByCredentialId({
|
|
74
|
+
statusListId: params.statusList.id,
|
|
75
|
+
credentialId: params.credentialId,
|
|
76
|
+
errorOnNotFound: false
|
|
77
|
+
});
|
|
78
|
+
if (existingEntry) {
|
|
79
|
+
debug(`Existing statusList entry and index ${existingEntry.statusListIndex} found for ${params.debugCredentialInfo}. Will reuse the index`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
let statusListIndex = existingEntry?.statusListIndex ?? params.currentIndex;
|
|
83
|
+
if (params.useIndexCondition(statusListIndex)) {
|
|
84
|
+
existingEntry = await params.slDriver.getStatusListEntryByIndex({
|
|
85
|
+
statusListId: params.statusList.id,
|
|
86
|
+
statusListIndex,
|
|
87
|
+
errorOnNotFound: false
|
|
88
|
+
});
|
|
89
|
+
logger.debug(`${!existingEntry && "no"} existing statusList entry and index ${existingEntry?.statusListIndex} for ${params.debugCredentialInfo}. Will reuse the index`);
|
|
90
|
+
if (existingEntry && params.credentialId && existingEntry.credentialId && existingEntry.credentialId !== params.credentialId && params.checkCredentialIdMismatch) {
|
|
91
|
+
params.checkCredentialIdMismatch(existingEntry, params.credentialId, statusListIndex);
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
debug(`Will generate a new random statusListIndex since the credential did not contain a statusListIndex for ${params.debugCredentialInfo}...`);
|
|
95
|
+
statusListIndex = await params.slDriver.getRandomNewStatusListIndex({
|
|
96
|
+
correlationId: params.statusList.correlationId
|
|
97
|
+
});
|
|
98
|
+
debug(`Random statusListIndex ${statusListIndex} assigned for ${params.debugCredentialInfo}`);
|
|
99
|
+
}
|
|
100
|
+
const updateArgs = {
|
|
101
|
+
statusListId: params.statusListId,
|
|
102
|
+
statusListIndex,
|
|
103
|
+
correlationId: params.statusEntryCorrelationId,
|
|
104
|
+
value: params.opts?.value ?? "0",
|
|
105
|
+
...params.statusList.type === "BitstringStatusList" && {
|
|
106
|
+
bitsPerStatus: params.statusList.bitstringStatusList?.bitsPerStatus ?? 1
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
if (params.credentialId) {
|
|
110
|
+
updateArgs.credentialId = params.credentialId;
|
|
111
|
+
}
|
|
112
|
+
const updateResult = await params.slDriver.updateStatusListEntry(updateArgs);
|
|
113
|
+
return {
|
|
114
|
+
statusListIndex,
|
|
115
|
+
updateResult
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
__name(processStatusListEntry, "processStatusListEntry");
|
|
119
|
+
var createStatusList = /* @__PURE__ */ __name(async (args, dataSource, context) => {
|
|
120
|
+
let statusList;
|
|
121
|
+
try {
|
|
122
|
+
statusList = await context.agent.slGetStatusList({
|
|
123
|
+
...args.id && {
|
|
124
|
+
id: args.id
|
|
125
|
+
},
|
|
126
|
+
...args.correlationId && {
|
|
127
|
+
correlationId: args.correlationId
|
|
128
|
+
},
|
|
129
|
+
...args.dbName && {
|
|
130
|
+
dbName: args.dbName
|
|
131
|
+
},
|
|
132
|
+
dataSource: await dataSource
|
|
133
|
+
});
|
|
134
|
+
} catch (e) {
|
|
135
|
+
const id = args.id;
|
|
136
|
+
const correlationId = args.correlationId;
|
|
137
|
+
if (!id || !correlationId) {
|
|
138
|
+
return Promise.reject(Error(`No correlation id and id provided for status list`));
|
|
139
|
+
}
|
|
140
|
+
statusList = await context.agent.slCreateStatusList(args);
|
|
141
|
+
}
|
|
142
|
+
return statusList;
|
|
143
|
+
}, "createStatusList");
|
|
144
|
+
var handleCredentialStatus = /* @__PURE__ */ __name(async (credential, credentialStatusOpts) => {
|
|
145
|
+
logger.debug(`Starting status update for credential ${credential.id ?? "without ID"}`);
|
|
146
|
+
const statusListOpts = getCredentialStatusListOpts(credential, credentialStatusOpts);
|
|
147
|
+
if (statusListOpts.length === 0) {
|
|
148
|
+
logger.debug("No status list options found, skipping update");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const credentialId = credential.id ?? credentialStatusOpts?.credentialId;
|
|
152
|
+
for (const statusListOpt of statusListOpts) {
|
|
153
|
+
const statusListId = statusListOpt.statusListId;
|
|
154
|
+
if (!statusListId) {
|
|
155
|
+
logger.debug("Skipping status list option without ID");
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
logger.debug(`Processing status list ${statusListId} for credential ${credentialId ?? "without ID"}`);
|
|
159
|
+
const { slDriver, statusList } = await getDriverAndStatusList(statusListId, credentialStatusOpts);
|
|
160
|
+
const currentIndex = statusListOpt.statusListIndex ?? 0;
|
|
161
|
+
const { updateResult } = await processStatusListEntry({
|
|
162
|
+
statusListId,
|
|
163
|
+
statusList,
|
|
164
|
+
credentialId,
|
|
165
|
+
currentIndex,
|
|
166
|
+
statusEntryCorrelationId: statusListOpt.statusEntryCorrelationId,
|
|
167
|
+
opts: credentialStatusOpts,
|
|
168
|
+
slDriver,
|
|
169
|
+
debugCredentialInfo: `credential with id ${credentialId} and statusListId ${statusListId}`,
|
|
170
|
+
useIndexCondition: /* @__PURE__ */ __name((index) => Boolean(index), "useIndexCondition"),
|
|
171
|
+
checkCredentialIdMismatch: /* @__PURE__ */ __name((existingEntry, credentialId2, index) => {
|
|
172
|
+
throw Error(`A credential with new id (${credentialId2}) is issued, but its id does not match a registered statusListEntry id ${existingEntry.credentialId} for index ${index}`);
|
|
173
|
+
}, "checkCredentialIdMismatch")
|
|
174
|
+
});
|
|
175
|
+
if (!credential.credentialStatus || Array.isArray(credential.credentialStatus)) {
|
|
176
|
+
credential.credentialStatus = {
|
|
177
|
+
id: `${statusListId}`,
|
|
178
|
+
statusListCredential: statusListId,
|
|
179
|
+
...updateResult.credentialStatus
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
logger.debug(`Completed status updates for credential ${credentialId ?? "without ID"}`);
|
|
184
|
+
}, "handleCredentialStatus");
|
|
185
|
+
var handleSdJwtCredentialStatus = /* @__PURE__ */ __name(async (credential, credentialStatusOpts) => {
|
|
186
|
+
logger.debug("Starting status update for SD\u2011JWT credential");
|
|
187
|
+
const statusListOpts = getSdJwtStatusListOpts(credential, credentialStatusOpts);
|
|
188
|
+
if (statusListOpts.length === 0) {
|
|
189
|
+
throw Error("No status list options available from credential or options");
|
|
190
|
+
}
|
|
191
|
+
for (const statusListOpt of statusListOpts) {
|
|
192
|
+
const statusListId = statusListOpt.statusListId;
|
|
193
|
+
if (!statusListId) {
|
|
194
|
+
logger.debug("Skipping status list option without ID");
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
logger.info(`Processing status list ${statusListId}`);
|
|
198
|
+
const { slDriver, statusList } = await getDriverAndStatusList(statusListId, credentialStatusOpts);
|
|
199
|
+
const currentIndex = statusListOpt.statusListIndex ?? 0;
|
|
200
|
+
const { statusListIndex } = await processStatusListEntry({
|
|
201
|
+
statusListId,
|
|
202
|
+
statusList,
|
|
203
|
+
currentIndex,
|
|
204
|
+
statusEntryCorrelationId: statusListOpt.statusEntryCorrelationId,
|
|
205
|
+
opts: credentialStatusOpts,
|
|
206
|
+
slDriver,
|
|
207
|
+
debugCredentialInfo: `credential with statusListId ${statusListId}`,
|
|
208
|
+
useIndexCondition: /* @__PURE__ */ __name((index) => index > 0, "useIndexCondition")
|
|
209
|
+
});
|
|
210
|
+
if (!credential.status) {
|
|
211
|
+
credential.status = {
|
|
212
|
+
status_list: {
|
|
213
|
+
uri: statusListId,
|
|
214
|
+
idx: statusListIndex
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
} else if (!credential.status.status_list) {
|
|
218
|
+
credential.status.status_list = {
|
|
219
|
+
uri: statusListId,
|
|
220
|
+
idx: statusListIndex
|
|
221
|
+
};
|
|
222
|
+
} else {
|
|
223
|
+
credential.status.status_list = {
|
|
224
|
+
uri: credential.status.status_list.uri || statusListId,
|
|
225
|
+
idx: statusListIndex
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
logger.debug("Completed SD\u2011JWT credential status update");
|
|
230
|
+
}, "handleSdJwtCredentialStatus");
|
|
231
|
+
|
|
232
|
+
// src/agent/StatusListPlugin.ts
|
|
233
|
+
var logger2 = Loggers2.DEFAULT.get("sphereon:ssi-sdk:vc-status-list");
|
|
234
|
+
var StatusListPlugin = class {
|
|
235
|
+
static {
|
|
236
|
+
__name(this, "StatusListPlugin");
|
|
237
|
+
}
|
|
238
|
+
instances = new Array();
|
|
239
|
+
defaultStatusListId;
|
|
240
|
+
allDataSources;
|
|
241
|
+
initialized = false;
|
|
242
|
+
methods = {
|
|
243
|
+
slAddStatusToCredential: this.slAddStatusToCredential.bind(this),
|
|
244
|
+
slAddStatusToSdJwtCredential: this.slAddStatusToSdJwtCredential.bind(this),
|
|
245
|
+
slCreateStatusList: this.slCreateStatusList.bind(this),
|
|
246
|
+
slGetStatusList: this.slGetStatusList.bind(this),
|
|
247
|
+
slImportStatusLists: this.slImportStatusLists.bind(this)
|
|
248
|
+
};
|
|
249
|
+
constructor(opts) {
|
|
250
|
+
this.instances = opts.instances ?? [];
|
|
251
|
+
const instanceId = opts.defaultStatusListId ?? opts.instances?.[0]?.id;
|
|
252
|
+
if (!instanceId) {
|
|
253
|
+
logger2.warning(`Could not deduce the default instance id from the status lists, so no default status list will be used. Please configure the default instance id in the agent configuration.`);
|
|
254
|
+
}
|
|
255
|
+
this.defaultStatusListId = instanceId;
|
|
256
|
+
this.allDataSources = opts.allDataSources ?? DataSources.singleInstance();
|
|
257
|
+
}
|
|
258
|
+
async init() {
|
|
259
|
+
if (!this.initialized) {
|
|
260
|
+
for (const dbName of this.allDataSources.getDbNames()) {
|
|
261
|
+
const driver = await getDriver2({
|
|
262
|
+
dbName,
|
|
263
|
+
dataSources: this.allDataSources
|
|
264
|
+
});
|
|
265
|
+
const statusLists = await driver.getStatusLists();
|
|
266
|
+
const instances = await Promise.all(statusLists.map((statusList) => {
|
|
267
|
+
const dataSource = this.allDataSources.getDbConnection(dbName);
|
|
268
|
+
return this.createStatusListInstance(statusList, dataSource, driver);
|
|
269
|
+
}));
|
|
270
|
+
this.instances.push(...instances);
|
|
271
|
+
}
|
|
272
|
+
this.initialized = true;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
async slImportStatusLists(imports, context) {
|
|
276
|
+
await this.init();
|
|
277
|
+
for (const instanceImport of imports) {
|
|
278
|
+
const dataSource = this.allDataSources.getDbConnection(instanceImport.dbName ?? "default");
|
|
279
|
+
await createStatusList(instanceImport, dataSource, context);
|
|
280
|
+
}
|
|
281
|
+
return true;
|
|
282
|
+
}
|
|
283
|
+
createStatusListInstance(statusList, dataSource, driver) {
|
|
284
|
+
return {
|
|
285
|
+
id: statusList.id,
|
|
286
|
+
correlationId: statusList.correlationId,
|
|
287
|
+
issuer: typeof statusList.issuer === "string" ? statusList.issuer : statusList.issuer.id,
|
|
288
|
+
dataSource,
|
|
289
|
+
driverOptions: driver.getOptions(),
|
|
290
|
+
driverType: driver.getType()
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
async getDriverForStatusListOption(effectiveStatusListId, correlationId) {
|
|
294
|
+
let instance;
|
|
295
|
+
if (correlationId && correlationId.trim() !== "") {
|
|
296
|
+
instance = this.instances.find((inst) => inst.correlationId === correlationId);
|
|
297
|
+
} else {
|
|
298
|
+
instance = this.instances.find((inst) => inst.id === effectiveStatusListId);
|
|
299
|
+
}
|
|
300
|
+
if (!instance) {
|
|
301
|
+
throw Error(`Status list with identifier ${correlationId ?? effectiveStatusListId} is not managed by the status list plugin`);
|
|
302
|
+
}
|
|
303
|
+
if (!instance.dataSource && !instance.driverOptions?.dbName) {
|
|
304
|
+
throw Error(`Either a datasource or dbName needs to be supplied`);
|
|
305
|
+
}
|
|
306
|
+
const dataSource = instance.dataSource ? await instance.dataSource : await this.allDataSources.getDbConnection(instance.driverOptions.dbName);
|
|
307
|
+
const driver = correlationId && correlationId.trim() !== "" ? await getDriver2({
|
|
308
|
+
dataSource,
|
|
309
|
+
correlationId
|
|
310
|
+
}) : await getDriver2({
|
|
311
|
+
dataSource,
|
|
312
|
+
id: effectiveStatusListId
|
|
313
|
+
});
|
|
314
|
+
return driver;
|
|
315
|
+
}
|
|
316
|
+
async slGetStatusList(args) {
|
|
317
|
+
await this.init();
|
|
318
|
+
const sl = this.instances.find((instance) => instance.id === args.id || instance.correlationId === args.correlationId);
|
|
319
|
+
const dataSource = await this.selectDatasource({
|
|
320
|
+
dbName: args.dbName,
|
|
321
|
+
dataSource: args.dataSource ?? sl?.dataSource,
|
|
322
|
+
instance: sl
|
|
323
|
+
});
|
|
324
|
+
const driver = await getDriver2({
|
|
325
|
+
id: args.id ?? sl?.id,
|
|
326
|
+
correlationId: args.correlationId ?? sl?.correlationId,
|
|
327
|
+
dataSource
|
|
328
|
+
});
|
|
329
|
+
return await driver.getStatusList();
|
|
330
|
+
}
|
|
331
|
+
async selectDatasource(args) {
|
|
332
|
+
const dbName = args.dbName ?? this.allDataSources.getDbNames()[0];
|
|
333
|
+
if (args?.dataSource) {
|
|
334
|
+
return args.dataSource;
|
|
335
|
+
} else if (args.instance?.dataSource) {
|
|
336
|
+
return args.instance.dataSource;
|
|
337
|
+
} else if (args.dbName) {
|
|
338
|
+
return await this.allDataSources.getDbConnection(dbName);
|
|
339
|
+
} else {
|
|
340
|
+
return await this.allDataSources.getDbConnection(dbName);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async slCreateStatusList(args, context) {
|
|
344
|
+
await this.init();
|
|
345
|
+
const sl = await createNewStatusList(args, context);
|
|
346
|
+
const dataSource = await this.selectDatasource({
|
|
347
|
+
dbName: args.dbName,
|
|
348
|
+
dataSource: args.dataSource
|
|
349
|
+
});
|
|
350
|
+
const driver = await getDriver2({
|
|
351
|
+
id: sl.id,
|
|
352
|
+
correlationId: sl.correlationId,
|
|
353
|
+
dataSource
|
|
354
|
+
});
|
|
355
|
+
let statusListDetails = void 0;
|
|
356
|
+
try {
|
|
357
|
+
statusListDetails = await this.slGetStatusList(args);
|
|
358
|
+
} catch (e) {
|
|
359
|
+
}
|
|
360
|
+
if (statusListDetails && this.instances.find((instance) => instance.id === args.id || instance.correlationId === args.correlationId)) {
|
|
361
|
+
return Promise.reject(Error(`Status list with id ${args.id} or correlation id ${args.correlationId} already exists`));
|
|
362
|
+
} else {
|
|
363
|
+
statusListDetails = await driver.createStatusList({
|
|
364
|
+
statusListType: sl.type,
|
|
365
|
+
statusListCredential: sl.statusListCredential,
|
|
366
|
+
correlationId: sl.correlationId,
|
|
367
|
+
bitsPerStatus: this.selectBitsPerStatus(sl)
|
|
368
|
+
});
|
|
369
|
+
this.instances.push(this.createStatusListInstance(statusListDetails, dataSource, driver));
|
|
370
|
+
}
|
|
371
|
+
return statusListDetails;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Selects bitsPerStatus from the used status list type when applicable
|
|
375
|
+
* @param sl
|
|
376
|
+
* @private
|
|
377
|
+
*/
|
|
378
|
+
selectBitsPerStatus(sl) {
|
|
379
|
+
if (sl.bitstringStatusList) {
|
|
380
|
+
return sl.bitstringStatusList.bitsPerStatus;
|
|
381
|
+
}
|
|
382
|
+
if (sl.oauthStatusList) {
|
|
383
|
+
return sl.oauthStatusList.bitsPerStatus;
|
|
384
|
+
}
|
|
385
|
+
return 1;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Adds status information to a credential by either:
|
|
389
|
+
* 1. Using existing status ID from the credential if present
|
|
390
|
+
* 2. Using provided status list options
|
|
391
|
+
* 3. Falling back to the default status list ID
|
|
392
|
+
*
|
|
393
|
+
* @param args Contains credential and status options
|
|
394
|
+
* @param context Required agent context
|
|
395
|
+
* @returns Credential with added status information
|
|
396
|
+
*/
|
|
397
|
+
async slAddStatusToCredential(args, context) {
|
|
398
|
+
const { credential, ...rest } = args;
|
|
399
|
+
logger2.debug(`Adding status to credential ${credential.id ?? "without ID"}`);
|
|
400
|
+
await this.init();
|
|
401
|
+
const credentialStatus = credential.credentialStatus;
|
|
402
|
+
if (credentialStatus && (!rest.statusLists || rest.statusLists.length == 0)) {
|
|
403
|
+
let existingStatusId;
|
|
404
|
+
if (Array.isArray(credentialStatus)) {
|
|
405
|
+
for (const stat of credentialStatus) {
|
|
406
|
+
if (stat.id && stat.id.trim() !== "") {
|
|
407
|
+
existingStatusId = stat.id.split("#")[0];
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
} else if (credentialStatus.id && credentialStatus.id.trim() !== "") {
|
|
412
|
+
existingStatusId = credentialStatus.id.split("#")[0];
|
|
413
|
+
}
|
|
414
|
+
if (existingStatusId) {
|
|
415
|
+
logger2.debug(`Using existing status ID ${existingStatusId} for credential ${credential.id ?? "without ID"}`);
|
|
416
|
+
const instance = this.instances.find((inst) => inst.id === existingStatusId);
|
|
417
|
+
if (!instance) {
|
|
418
|
+
throw Error(`Status list with id ${existingStatusId} is not managed by the status list plugin`);
|
|
419
|
+
}
|
|
420
|
+
if (!instance.dataSource && !instance.driverOptions?.dbName) {
|
|
421
|
+
throw Error(`Either a datasource or dbName needs to be supplied`);
|
|
422
|
+
}
|
|
423
|
+
const credentialId2 = credential.id ?? rest.credentialId;
|
|
424
|
+
const dataSource = instance.dataSource ? await instance.dataSource : await this.allDataSources.getDbConnection(instance.driverOptions.dbName);
|
|
425
|
+
const driver = await getDriver2({
|
|
426
|
+
dataSource,
|
|
427
|
+
id: existingStatusId
|
|
428
|
+
});
|
|
429
|
+
await handleCredentialStatus(credential, {
|
|
430
|
+
...rest,
|
|
431
|
+
credentialId: credentialId2,
|
|
432
|
+
statusLists: [
|
|
433
|
+
{
|
|
434
|
+
statusListId: existingStatusId
|
|
435
|
+
}
|
|
436
|
+
],
|
|
437
|
+
driver
|
|
438
|
+
});
|
|
439
|
+
return credential;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
const statusListOpts = rest.statusLists?.length ? rest.statusLists : [];
|
|
443
|
+
logger2.debug(`Adding new status using ${statusListOpts.length} status list option(s)`);
|
|
444
|
+
const credentialId = credential.id ?? rest.credentialId;
|
|
445
|
+
for (const opt of statusListOpts) {
|
|
446
|
+
const effectiveStatusListId = opt.statusListId ?? this.defaultStatusListId;
|
|
447
|
+
if (!effectiveStatusListId) {
|
|
448
|
+
return Promise.reject(Error(`No status list ID provided and no default status list ID configured. Please provide a status list ID or configure a default status list ID in the agent configuration.`));
|
|
449
|
+
}
|
|
450
|
+
const driver = await this.getDriverForStatusListOption(effectiveStatusListId, opt.statusListCorrelationId);
|
|
451
|
+
await handleCredentialStatus(credential, {
|
|
452
|
+
...rest,
|
|
453
|
+
credentialId,
|
|
454
|
+
statusLists: [
|
|
455
|
+
{
|
|
456
|
+
...opt,
|
|
457
|
+
statusListId: effectiveStatusListId
|
|
458
|
+
}
|
|
459
|
+
],
|
|
460
|
+
driver
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
logger2.debug(`Successfully added status information to credential ${credential.id ?? "without ID"}`);
|
|
464
|
+
return credential;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Adds status information to an SD-JWT credential by either:
|
|
468
|
+
* 1. Using existing status URI from the credential if present
|
|
469
|
+
* 2. Using provided status list options
|
|
470
|
+
* 3. Falling back to the default status list ID
|
|
471
|
+
*
|
|
472
|
+
* @param args Contains SD-JWT credential and status options
|
|
473
|
+
* @param context Required agent context
|
|
474
|
+
* @returns SD-JWT credential with added status information
|
|
475
|
+
*/
|
|
476
|
+
async slAddStatusToSdJwtCredential(args, context) {
|
|
477
|
+
const { credential, ...rest } = args;
|
|
478
|
+
logger2.debug(`Adding status to SD-JWT credential`);
|
|
479
|
+
await this.init();
|
|
480
|
+
const credentialStatus = credential.status;
|
|
481
|
+
if (credentialStatus && (!rest.statusLists || rest.statusLists.length == 0)) {
|
|
482
|
+
let existingStatusUri;
|
|
483
|
+
if (credentialStatus.status_list && credentialStatus.status_list.uri && credentialStatus.status_list.uri.trim() !== "") {
|
|
484
|
+
existingStatusUri = credentialStatus.status_list.uri;
|
|
485
|
+
}
|
|
486
|
+
if (existingStatusUri) {
|
|
487
|
+
logger2.debug(`Using existing status URI ${existingStatusUri} for SD-JWT credential`);
|
|
488
|
+
const driver2 = await this.getDriverForStatusListOption(existingStatusUri);
|
|
489
|
+
await handleSdJwtCredentialStatus(credential, {
|
|
490
|
+
...rest,
|
|
491
|
+
statusLists: [
|
|
492
|
+
{
|
|
493
|
+
...rest.statusLists,
|
|
494
|
+
statusListId: existingStatusUri
|
|
495
|
+
}
|
|
496
|
+
],
|
|
497
|
+
driver: driver2
|
|
498
|
+
});
|
|
499
|
+
return credential;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
const statusListOpts = rest.statusLists?.length ? rest.statusLists : [];
|
|
503
|
+
logger2.info(`Adding new status using status list options with ID ${statusListOpts[0].statusListId ?? this.defaultStatusListId}`);
|
|
504
|
+
const firstOpt = statusListOpts[0];
|
|
505
|
+
const effectiveStatusListId = firstOpt.statusListId ?? this.defaultStatusListId;
|
|
506
|
+
if (!effectiveStatusListId) {
|
|
507
|
+
return Promise.reject(Error(`No status list ID provided and no default status list ID configured. Please provide a status list ID or configure a default status list ID in the agent configuration.`));
|
|
508
|
+
}
|
|
509
|
+
const driver = await this.getDriverForStatusListOption(effectiveStatusListId, firstOpt.statusListCorrelationId);
|
|
510
|
+
await handleSdJwtCredentialStatus(credential, {
|
|
511
|
+
...rest,
|
|
512
|
+
statusLists: [
|
|
513
|
+
{
|
|
514
|
+
...firstOpt,
|
|
515
|
+
statusListId: effectiveStatusListId
|
|
516
|
+
}
|
|
517
|
+
],
|
|
518
|
+
driver
|
|
519
|
+
});
|
|
520
|
+
logger2.debug(`Successfully added status information to SD-JWT credential`);
|
|
521
|
+
return credential;
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
export {
|
|
525
|
+
StatusListPlugin
|
|
526
|
+
};
|
|
1
527
|
//# sourceMappingURL=index.js.map
|