@rodit/rodit-auth-be 9.11.14
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/CHANGELOG.md +54 -0
- package/README.md +3543 -0
- package/index.js +1884 -0
- package/lib/auth/authentication.js +1971 -0
- package/lib/auth/roditmanager.js +627 -0
- package/lib/auth/sessionmanager.js +1302 -0
- package/lib/auth/tokenservice.js +2418 -0
- package/lib/blockchain/blockchainservice.js +1715 -0
- package/lib/blockchain/statemanager.js +1614 -0
- package/lib/middleware/authenticationmw.js +2301 -0
- package/lib/middleware/environcredentialstoremw.js +176 -0
- package/lib/middleware/filecredentialstoremw.js +158 -0
- package/lib/middleware/loggingmw.js +82 -0
- package/lib/middleware/performanceexamplemw.js +58 -0
- package/lib/middleware/performancemw.js +172 -0
- package/lib/middleware/ratelimitmw.js +171 -0
- package/lib/middleware/validatepermissionsmw.js +439 -0
- package/lib/middleware/vaultcredentialstoremw.js +617 -0
- package/lib/middleware/versioningmw.js +142 -0
- package/lib/middleware/webhookhandlermw.js +1388 -0
- package/package.json +57 -0
- package/services/configsdk.js +588 -0
- package/services/env.js +34 -0
- package/services/error-response.js +29 -0
- package/services/logger.js +160 -0
- package/services/performanceservice.js +568 -0
- package/services/utils.js +1024 -0
- package/services/versionmanager.js +81 -0
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RODIT manager for handling RODIT-specific operations
|
|
3
|
+
* Copyright (c) 2026 Discernible IO. All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { ulid } = require("ulid");
|
|
7
|
+
const config = require("../../services/configsdk");
|
|
8
|
+
const logger = require("../../services/logger");
|
|
9
|
+
const { createLogContext, logErrorWithMetrics } = logger;
|
|
10
|
+
// Dynamically select credential store based on config/env (flat key only)
|
|
11
|
+
const RODIT_NEAR_CREDENTIALS_SOURCE = config.get("RODIT_NEAR_CREDENTIALS_SOURCE");
|
|
12
|
+
logger.debugWithContext(
|
|
13
|
+
"Selecting credential store",
|
|
14
|
+
createLogContext("RoditManager", "credentialStoreSelect", {
|
|
15
|
+
source: RODIT_NEAR_CREDENTIALS_SOURCE,
|
|
16
|
+
})
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
let credentialStoreModule;
|
|
20
|
+
if (RODIT_NEAR_CREDENTIALS_SOURCE === "file") {
|
|
21
|
+
credentialStoreModule = require("../middleware/filecredentialstoremw");
|
|
22
|
+
} else if (RODIT_NEAR_CREDENTIALS_SOURCE === "env") {
|
|
23
|
+
credentialStoreModule = require("../middleware/environcredentialstoremw");
|
|
24
|
+
} else {
|
|
25
|
+
credentialStoreModule = require("../middleware/vaultcredentialstoremw");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// const credentialStoreModule = require("../middleware/filecredentialstoremw");
|
|
29
|
+
|
|
30
|
+
const {
|
|
31
|
+
initializeCredentialStore,
|
|
32
|
+
setupSecretStorageTokenRenewal,
|
|
33
|
+
getCredentials,
|
|
34
|
+
vault,
|
|
35
|
+
} = credentialStoreModule;
|
|
36
|
+
const {
|
|
37
|
+
nearorg_rpc_state,
|
|
38
|
+
nearorg_rpc_tokensfromaccountid,
|
|
39
|
+
} = require("../blockchain/blockchainservice");
|
|
40
|
+
const stateManager = require("../blockchain/statemanager");
|
|
41
|
+
|
|
42
|
+
const baseModuleContext = createLogContext("ModuleLoader", "RoditManager", {
|
|
43
|
+
loadedAt: new Date().toISOString(),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
logger.debugWithContext("Loading roditmanager.js module", baseModuleContext);
|
|
47
|
+
/**
|
|
48
|
+
* RoditManager class
|
|
49
|
+
* Singleton class for managing RODiT configurations and credentials
|
|
50
|
+
*/
|
|
51
|
+
class RoditManager {
|
|
52
|
+
constructor() {
|
|
53
|
+
const instanceId = ulid();
|
|
54
|
+
|
|
55
|
+
const constructorContext = createLogContext("RoditManager", "constructor", {
|
|
56
|
+
instanceId,
|
|
57
|
+
hasExistingInstance: !!RoditManager.instance,
|
|
58
|
+
existingInstanceId: RoditManager.instance
|
|
59
|
+
? RoditManager.instance._instanceId
|
|
60
|
+
: null,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
logger.debugWithContext(
|
|
64
|
+
"RoditManager constructor called",
|
|
65
|
+
constructorContext
|
|
66
|
+
);
|
|
67
|
+
if (RoditManager.instance) {
|
|
68
|
+
logger.debugWithContext("Returning existing RoditManager instance", {
|
|
69
|
+
...constructorContext,
|
|
70
|
+
instanceId: RoditManager.instance._instanceId,
|
|
71
|
+
});
|
|
72
|
+
return RoditManager.instance;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this._instanceId = instanceId; // Store the instance ID
|
|
76
|
+
logger.debug("Creating new RoditManager instance", {
|
|
77
|
+
component: "RoditManager",
|
|
78
|
+
instanceId: this._instanceId,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
this.stateManager = stateManager;
|
|
82
|
+
|
|
83
|
+
RoditManager.instance = this;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async initializeCredentialsStore() {
|
|
87
|
+
const requestId = ulid();
|
|
88
|
+
|
|
89
|
+
logger.debug("Initializing CredentialManager", {
|
|
90
|
+
component: "RoditManager",
|
|
91
|
+
method: "initializeCredentialsStore",
|
|
92
|
+
requestId,
|
|
93
|
+
instanceId: this._instanceId,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const credentialstoreInstance =
|
|
98
|
+
await initializeCredentialStore();
|
|
99
|
+
await setupSecretStorageTokenRenewal(credentialstoreInstance);
|
|
100
|
+
|
|
101
|
+
logger.debug(
|
|
102
|
+
"CredentialStore initialization completed through CredentialManager",
|
|
103
|
+
{
|
|
104
|
+
component: "RoditManager",
|
|
105
|
+
method: "initializeCredentialsStore",
|
|
106
|
+
requestId,
|
|
107
|
+
instanceId: this._instanceId,
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
return credentialstoreInstance;
|
|
112
|
+
} catch (error) {
|
|
113
|
+
logger.error("Error during CredentialStore initialization", {
|
|
114
|
+
component: "RoditManager",
|
|
115
|
+
method: "initializeCredentialsStore",
|
|
116
|
+
requestId,
|
|
117
|
+
errorMessage: error.message,
|
|
118
|
+
errorCode: error.code || "UNKNOWN_ERROR",
|
|
119
|
+
stack: error.stack,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async initializeRoditConfig(type, targetStateManager = null) {
|
|
127
|
+
const requestId = ulid();
|
|
128
|
+
const startTime = Date.now();
|
|
129
|
+
|
|
130
|
+
// Use the provided stateManager or fall back to the singleton
|
|
131
|
+
const stateManagerToUse = targetStateManager || this.stateManager;
|
|
132
|
+
|
|
133
|
+
// Create a base context for this method
|
|
134
|
+
const baseContext = createLogContext(
|
|
135
|
+
"RoditManager",
|
|
136
|
+
"initializeRoditConfig",
|
|
137
|
+
{
|
|
138
|
+
requestId,
|
|
139
|
+
configType: type,
|
|
140
|
+
usingTestStateManager: !!targetStateManager,
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
logger.infoWithContext("Starting RODiT config initialization", baseContext);
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
logger.debugWithContext("Getting credentials", {
|
|
148
|
+
...baseContext,
|
|
149
|
+
step: "fetchCredentials",
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
let credentials = await getCredentials(type);
|
|
153
|
+
|
|
154
|
+
if (!credentials) {
|
|
155
|
+
logErrorWithMetrics({
|
|
156
|
+
error: new Error(`Credentials not available for ${type}`),
|
|
157
|
+
context: {
|
|
158
|
+
...baseContext,
|
|
159
|
+
step: "credentialCheck",
|
|
160
|
+
},
|
|
161
|
+
metrics: [
|
|
162
|
+
{
|
|
163
|
+
name: "credential_retrieval_failures",
|
|
164
|
+
value: 1,
|
|
165
|
+
tags: { configType: type },
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
});
|
|
169
|
+
throw new Error(`Credentials not available for ${type}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Handle case where credentials might be in an object with account_id as key
|
|
173
|
+
if (
|
|
174
|
+
typeof credentials === "object" &&
|
|
175
|
+
Object.keys(credentials).length === 1
|
|
176
|
+
) {
|
|
177
|
+
credentials = Object.values(credentials)[0];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Require implicit_account_id
|
|
181
|
+
const account_id = credentials.implicit_account_id;
|
|
182
|
+
if (!account_id) {
|
|
183
|
+
throw new Error("Credentials must contain implicit_account_id");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
logger.infoWithContext("Using account for initialization", {
|
|
187
|
+
...baseContext,
|
|
188
|
+
accountId: account_id,
|
|
189
|
+
step: "accountSetup",
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
logger.debugWithContext("Checking account state on blockchain", {
|
|
193
|
+
...baseContext,
|
|
194
|
+
accountId: account_id,
|
|
195
|
+
step: "blockchainCheck",
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const accountState = await nearorg_rpc_state(account_id);
|
|
199
|
+
|
|
200
|
+
if (!accountState) {
|
|
201
|
+
logger.warnWithContext("Account has no balance in network", {
|
|
202
|
+
...baseContext,
|
|
203
|
+
accountId: account_id,
|
|
204
|
+
step: "blockchainCheck",
|
|
205
|
+
});
|
|
206
|
+
} else {
|
|
207
|
+
logger.infoWithContext("Account state verified on blockchain", {
|
|
208
|
+
...baseContext,
|
|
209
|
+
accountId: account_id,
|
|
210
|
+
step: "blockchainCheck",
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
logger.debugWithContext("Fetching RODiT tokens for account", {
|
|
215
|
+
...baseContext,
|
|
216
|
+
accountId: account_id,
|
|
217
|
+
step: "tokenFetch",
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const own_rodit = await nearorg_rpc_tokensfromaccountid(account_id);
|
|
221
|
+
|
|
222
|
+
// Check if we have a real RODiT token
|
|
223
|
+
if (!own_rodit || !own_rodit.token_id) {
|
|
224
|
+
logger.warnWithContext(
|
|
225
|
+
"No RODiT instances found, proceeding with partial initialization",
|
|
226
|
+
{
|
|
227
|
+
...baseContext,
|
|
228
|
+
accountId: account_id,
|
|
229
|
+
step: "tokenCheck",
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
// Create a minimal configuration for signroot
|
|
234
|
+
const minimalConfig = {
|
|
235
|
+
own_rodit: {
|
|
236
|
+
token_id: "",
|
|
237
|
+
owner_id: account_id,
|
|
238
|
+
metadata: {
|
|
239
|
+
subjectuniqueidentifier_url: "api-url-not-set.example.com",
|
|
240
|
+
serviceprovider_id: "",
|
|
241
|
+
not_after: "2030-01-01",
|
|
242
|
+
not_before: "2020-01-01",
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
own_rodit_bytes_private_key: credentials.signing_bytes_key,
|
|
246
|
+
apiEndpoint: "localhost",
|
|
247
|
+
port: "",
|
|
248
|
+
iso639: config.get("API_DEFAULT_OPTIONS.ISO639"),
|
|
249
|
+
iso3166: config.get("API_DEFAULT_OPTIONS.ISO3166"),
|
|
250
|
+
iso15924: config.get("API_DEFAULT_OPTIONS.ISO15924"),
|
|
251
|
+
timeoptions: config.get("API_DEFAULT_OPTIONS.TIMEOPTIONS"),
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
await stateManagerToUse.setConfigOwnRodit(minimalConfig);
|
|
255
|
+
|
|
256
|
+
const session_base64url_jwk_public_key = Buffer.from(
|
|
257
|
+
account_id,
|
|
258
|
+
"hex"
|
|
259
|
+
).toString("base64url");
|
|
260
|
+
|
|
261
|
+
logger.debugWithContext("Converting implicit account ID to base64url", {
|
|
262
|
+
...baseContext,
|
|
263
|
+
step: "keyConversion",
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
logger.debugWithContext("Setting session base64url JWK public key", {
|
|
267
|
+
...baseContext,
|
|
268
|
+
step: "setSessionKey",
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
await stateManagerToUse.setOwnBase64urlJwkPublicKey(
|
|
272
|
+
session_base64url_jwk_public_key
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
const duration = Date.now() - startTime;
|
|
276
|
+
logger.infoWithContext(
|
|
277
|
+
"RODiT config initialized with minimal configuration",
|
|
278
|
+
{
|
|
279
|
+
...baseContext,
|
|
280
|
+
duration,
|
|
281
|
+
configLevel: "partial",
|
|
282
|
+
step: "complete",
|
|
283
|
+
}
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
// Emit metrics for dashboards
|
|
287
|
+
logger.metric("rodit_initialization_duration_ms", duration, {
|
|
288
|
+
success: true,
|
|
289
|
+
configType: type,
|
|
290
|
+
configLevel: "partial",
|
|
291
|
+
component: "RoditManager",
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
return minimalConfig;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
logger.infoWithContext("RODiT config initialized successfully", {
|
|
298
|
+
...baseContext,
|
|
299
|
+
roditId: own_rodit.token_id,
|
|
300
|
+
duration: Date.now() - startTime,
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Port configuration removed as requested
|
|
304
|
+
|
|
305
|
+
if (
|
|
306
|
+
!own_rodit.metadata ||
|
|
307
|
+
!own_rodit.metadata.subjectuniqueidentifier_url
|
|
308
|
+
) {
|
|
309
|
+
logger.errorWithContext("Missing required metadata in RODiT", {
|
|
310
|
+
...baseContext,
|
|
311
|
+
missingField: "subjectuniqueidentifier_url",
|
|
312
|
+
step: "metadataCheck",
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
throw new Error(
|
|
316
|
+
"Missing required metadata: subjectuniqueidentifier_url"
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const apiendpoint = own_rodit.metadata.subjectuniqueidentifier_url;
|
|
321
|
+
|
|
322
|
+
logger.debugWithContext("Constructed API endpoint", {
|
|
323
|
+
...baseContext,
|
|
324
|
+
api_ep: apiendpoint,
|
|
325
|
+
step: "apiEndpointCreation",
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
logger.infoWithContext("Building full configuration object", {
|
|
329
|
+
...baseContext,
|
|
330
|
+
step: "fullConfigCreation",
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Validate private key format before storing in config object
|
|
334
|
+
let privateKeyToUse = credentials.signing_bytes_key;
|
|
335
|
+
|
|
336
|
+
// Validate private key format (sensitive data not logged per security policy)
|
|
337
|
+
|
|
338
|
+
// Detailed private key format validation and logging
|
|
339
|
+
logger.debugWithContext("Private key format validation", {
|
|
340
|
+
...baseContext,
|
|
341
|
+
keyType: typeof privateKeyToUse,
|
|
342
|
+
isUint8Array: privateKeyToUse instanceof Uint8Array,
|
|
343
|
+
isBuffer: Buffer.isBuffer(privateKeyToUse),
|
|
344
|
+
length: privateKeyToUse?.length,
|
|
345
|
+
step: "privateKeyValidation",
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Ensure private key is in the correct format (Uint8Array)
|
|
349
|
+
if (privateKeyToUse && !(privateKeyToUse instanceof Uint8Array)) {
|
|
350
|
+
if (Buffer.isBuffer(privateKeyToUse)) {
|
|
351
|
+
logger.debugWithContext(
|
|
352
|
+
"Converting Buffer to Uint8Array for private key",
|
|
353
|
+
{
|
|
354
|
+
...baseContext,
|
|
355
|
+
step: "privateKeyConversion",
|
|
356
|
+
bufferLength: privateKeyToUse.length,
|
|
357
|
+
}
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
// Store original buffer for comparison
|
|
361
|
+
const originalBuffer = Buffer.from(privateKeyToUse);
|
|
362
|
+
|
|
363
|
+
// Convert to Uint8Array
|
|
364
|
+
privateKeyToUse = new Uint8Array(privateKeyToUse);
|
|
365
|
+
|
|
366
|
+
// Verify conversion was successful
|
|
367
|
+
logger.debugWithContext("Buffer to Uint8Array conversion result", {
|
|
368
|
+
...baseContext,
|
|
369
|
+
step: "privateKeyConversionResult",
|
|
370
|
+
originalType: "Buffer",
|
|
371
|
+
convertedType: privateKeyToUse.constructor.name,
|
|
372
|
+
isUint8Array: privateKeyToUse instanceof Uint8Array,
|
|
373
|
+
originalLength: originalBuffer.length,
|
|
374
|
+
convertedLength: privateKeyToUse.length,
|
|
375
|
+
});
|
|
376
|
+
} else if (
|
|
377
|
+
typeof privateKeyToUse === "object" &&
|
|
378
|
+
privateKeyToUse !== null
|
|
379
|
+
) {
|
|
380
|
+
// Try to recover from a JSON-serialized Uint8Array or similar object
|
|
381
|
+
logger.warnWithContext(
|
|
382
|
+
"Attempting to recover private key from non-standard format",
|
|
383
|
+
{
|
|
384
|
+
...baseContext,
|
|
385
|
+
recoveryAttempt: true,
|
|
386
|
+
objectKeys: Object.keys(privateKeyToUse).join(","),
|
|
387
|
+
hasLength: privateKeyToUse.length !== undefined,
|
|
388
|
+
lengthType: typeof privateKeyToUse.length,
|
|
389
|
+
}
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
try {
|
|
393
|
+
// If it's an array-like object, try to convert it to Uint8Array
|
|
394
|
+
if (
|
|
395
|
+
Array.isArray(privateKeyToUse) ||
|
|
396
|
+
(privateKeyToUse.length !== undefined &&
|
|
397
|
+
typeof privateKeyToUse.length === "number")
|
|
398
|
+
) {
|
|
399
|
+
const originalData = privateKeyToUse;
|
|
400
|
+
privateKeyToUse = new Uint8Array(
|
|
401
|
+
Array.isArray(privateKeyToUse)
|
|
402
|
+
? privateKeyToUse
|
|
403
|
+
: Array.from(privateKeyToUse)
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
logger.infoWithContext(
|
|
407
|
+
"Successfully recovered private key from array-like object",
|
|
408
|
+
{
|
|
409
|
+
...baseContext,
|
|
410
|
+
recoveredKeyLength: privateKeyToUse.length,
|
|
411
|
+
recoveredIsUint8Array: privateKeyToUse instanceof Uint8Array,
|
|
412
|
+
originalType: originalData.constructor.name,
|
|
413
|
+
}
|
|
414
|
+
);
|
|
415
|
+
} else {
|
|
416
|
+
throw new Error("Cannot recover key - not an array-like object");
|
|
417
|
+
}
|
|
418
|
+
} catch (recoveryError) {
|
|
419
|
+
logErrorWithMetrics({
|
|
420
|
+
error: new Error(
|
|
421
|
+
`Private key recovery failed: ${recoveryError.message}`
|
|
422
|
+
),
|
|
423
|
+
context: {
|
|
424
|
+
...baseContext,
|
|
425
|
+
keyType: typeof privateKeyToUse,
|
|
426
|
+
step: "privateKeyRecoveryFailed",
|
|
427
|
+
recoveryError: recoveryError.message,
|
|
428
|
+
},
|
|
429
|
+
metrics: [
|
|
430
|
+
{
|
|
431
|
+
name: "private_key_recovery_failures",
|
|
432
|
+
value: 1,
|
|
433
|
+
tags: { configType: type },
|
|
434
|
+
},
|
|
435
|
+
],
|
|
436
|
+
});
|
|
437
|
+
throw new Error("Private key must be a Uint8Array or Buffer");
|
|
438
|
+
}
|
|
439
|
+
} else {
|
|
440
|
+
logErrorWithMetrics({
|
|
441
|
+
error: new Error("Private key must be a Uint8Array or Buffer"),
|
|
442
|
+
context: {
|
|
443
|
+
...baseContext,
|
|
444
|
+
keyType: typeof privateKeyToUse,
|
|
445
|
+
step: "privateKeyValidation",
|
|
446
|
+
},
|
|
447
|
+
metrics: [
|
|
448
|
+
{
|
|
449
|
+
name: "private_key_format_errors",
|
|
450
|
+
value: 1,
|
|
451
|
+
tags: { configType: type },
|
|
452
|
+
},
|
|
453
|
+
],
|
|
454
|
+
});
|
|
455
|
+
throw new Error("Private key must be a Uint8Array or Buffer");
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Private key validated and ready for storage (sensitive data not logged per security policy)
|
|
460
|
+
|
|
461
|
+
const roditClient = {
|
|
462
|
+
own_rodit,
|
|
463
|
+
own_rodit_bytes_private_key: privateKeyToUse, // Use validated private key
|
|
464
|
+
apiendpoint,
|
|
465
|
+
port: "",
|
|
466
|
+
iso639: config.get("API_DEFAULT_OPTIONS.ISO639"),
|
|
467
|
+
iso3166: config.get("API_DEFAULT_OPTIONS.ISO3166"),
|
|
468
|
+
iso15924: config.get("API_DEFAULT_OPTIONS.ISO15924"),
|
|
469
|
+
timeoptions: config.get("API_DEFAULT_OPTIONS.TIMEOPTIONS"),
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
logger.debugWithContext("Using RODiT token for configuration", {
|
|
473
|
+
...baseContext,
|
|
474
|
+
roditId: own_rodit.token_id,
|
|
475
|
+
accountId: account_id,
|
|
476
|
+
step: "tokenUse",
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
logger.debugWithContext("Storing configuration in state manager", {
|
|
480
|
+
...baseContext,
|
|
481
|
+
step: "storeConfig",
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
await stateManagerToUse.setConfigOwnRodit(roditClient);
|
|
485
|
+
|
|
486
|
+
logger.infoWithContext("Configuration stored successfully", {
|
|
487
|
+
...baseContext,
|
|
488
|
+
step: "configStored",
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
logger.debugWithContext("Converting implicit account ID to base64url", {
|
|
492
|
+
...baseContext,
|
|
493
|
+
step: "keyConversion",
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
const session_base64url_jwk_public_key = Buffer.from(
|
|
497
|
+
account_id,
|
|
498
|
+
"hex"
|
|
499
|
+
).toString("base64url");
|
|
500
|
+
|
|
501
|
+
logger.debugWithContext("Setting session base64url JWK public key", {
|
|
502
|
+
...baseContext,
|
|
503
|
+
step: "setSessionKey",
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
// Set the client's own public key from the implicit account ID
|
|
507
|
+
await stateManagerToUse.setOwnBase64urlJwkPublicKey(
|
|
508
|
+
session_base64url_jwk_public_key
|
|
509
|
+
);
|
|
510
|
+
|
|
511
|
+
// Note: The server's public key should be set separately when it's received
|
|
512
|
+
// during the handshake or authentication process
|
|
513
|
+
|
|
514
|
+
const duration = Date.now() - startTime;
|
|
515
|
+
logger.infoWithContext("RODiT configuration completed", {
|
|
516
|
+
...baseContext,
|
|
517
|
+
duration,
|
|
518
|
+
configLevel: "full",
|
|
519
|
+
step: "complete",
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
// Emit metrics for dashboards
|
|
523
|
+
logger.metric("rodit_initialization_duration_ms", duration, {
|
|
524
|
+
success: true,
|
|
525
|
+
configType: type,
|
|
526
|
+
configLevel: "full",
|
|
527
|
+
component: "RoditManager",
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
return roditClient;
|
|
531
|
+
} catch (error) {
|
|
532
|
+
const duration = Date.now() - startTime;
|
|
533
|
+
|
|
534
|
+
logErrorWithMetrics({
|
|
535
|
+
error,
|
|
536
|
+
context: {
|
|
537
|
+
...baseContext,
|
|
538
|
+
duration,
|
|
539
|
+
},
|
|
540
|
+
metrics: [
|
|
541
|
+
{
|
|
542
|
+
name: "rodit_config_initialization_errors",
|
|
543
|
+
value: 1,
|
|
544
|
+
tags: { configType: type, errorType: error.name || "Unknown" },
|
|
545
|
+
},
|
|
546
|
+
],
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
// Emit metrics for dashboards
|
|
550
|
+
logger.metric("rodit_initialization_duration_ms", duration, {
|
|
551
|
+
success: false,
|
|
552
|
+
configType: type,
|
|
553
|
+
component: "RoditManager",
|
|
554
|
+
errorType: error.code || "UNKNOWN_ERROR",
|
|
555
|
+
});
|
|
556
|
+
logger.metric("rodit_initialization_errors_total", 1, {
|
|
557
|
+
errorType: error.code || "UNKNOWN_ERROR",
|
|
558
|
+
configType: type,
|
|
559
|
+
component: "RoditManager",
|
|
560
|
+
step: error.step || "unknown",
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
throw error;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Initialize RODiT SDK with the specified role
|
|
568
|
+
async initializeRoditSdk(roles = {}) {
|
|
569
|
+
const role = roles.role || "client";
|
|
570
|
+
|
|
571
|
+
try {
|
|
572
|
+
// Initialize vault and configuration using SDK
|
|
573
|
+
await this.initializeCredentialsStore();
|
|
574
|
+
|
|
575
|
+
// Initialize RODiT configuration for the specified role
|
|
576
|
+
await this.initializeRoditConfig(role);
|
|
577
|
+
|
|
578
|
+
logger.info(
|
|
579
|
+
`Credentials (${RODIT_NEAR_CREDENTIALS_SOURCE}) initialized and RODiT configuration loaded for role: ${role}`
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
// Get and validate the configuration
|
|
583
|
+
const roditClient = await stateManager.getConfigOwnRodit();
|
|
584
|
+
if (!roditClient) {
|
|
585
|
+
throw new Error(
|
|
586
|
+
"Failed to initialize RODiT configuration: No configuration returned"
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Apply rate limiting if configured
|
|
591
|
+
const { own_rodit } = roditClient;
|
|
592
|
+
if (
|
|
593
|
+
own_rodit?.metadata?.max_requests &&
|
|
594
|
+
own_rodit?.metadata?.maxrq_window
|
|
595
|
+
) {
|
|
596
|
+
// This function should be provided by the application
|
|
597
|
+
if (typeof stateManager.updateRateLimit === "function") {
|
|
598
|
+
stateManager.updateRateLimit(
|
|
599
|
+
own_rodit.metadata.max_requests,
|
|
600
|
+
own_rodit.metadata.maxrq_window
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
return roditClient;
|
|
606
|
+
} catch (error) {
|
|
607
|
+
logger.error(`Failed to initialize RODiT SDK: ${error.message}`, {
|
|
608
|
+
error,
|
|
609
|
+
});
|
|
610
|
+
throw new Error(`SDK initialization failed: ${error.message}`);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Get credentials for a specific type
|
|
615
|
+
* @param {string} type - The credential type (e.g., 'sanctum', 'portal')
|
|
616
|
+
* @returns {Promise<Object>} The credentials object
|
|
617
|
+
*/
|
|
618
|
+
async getCredentials(type) {
|
|
619
|
+
return await getCredentials(type);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Create and export a singleton instance
|
|
624
|
+
const roditManager = new RoditManager();
|
|
625
|
+
|
|
626
|
+
// Export the singleton instance directly to avoid any issues with destructuring
|
|
627
|
+
module.exports = roditManager;
|