@twin.org/node-core 0.0.2-next.9 → 0.0.3-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +1 -1
  2. package/dist/es/bootstrap.js +374 -0
  3. package/dist/es/bootstrap.js.map +1 -0
  4. package/dist/es/builders/engineEnvBuilder.js +1051 -0
  5. package/dist/es/builders/engineEnvBuilder.js.map +1 -0
  6. package/dist/es/builders/engineServerEnvBuilder.js +197 -0
  7. package/dist/es/builders/engineServerEnvBuilder.js.map +1 -0
  8. package/dist/es/builders/extensionsBuilder.js +100 -0
  9. package/dist/es/builders/extensionsBuilder.js.map +1 -0
  10. package/dist/es/defaults.js +9 -0
  11. package/dist/es/defaults.js.map +1 -0
  12. package/dist/es/identity.js +169 -0
  13. package/dist/es/identity.js.map +1 -0
  14. package/dist/es/index.js +23 -0
  15. package/dist/es/index.js.map +1 -0
  16. package/dist/es/models/ICacheMetadata.js +4 -0
  17. package/dist/es/models/ICacheMetadata.js.map +1 -0
  18. package/dist/es/models/IEngineEnvironmentVariables.js +4 -0
  19. package/dist/es/models/IEngineEnvironmentVariables.js.map +1 -0
  20. package/dist/es/models/IEngineServerEnvironmentVariables.js +2 -0
  21. package/dist/es/models/IEngineServerEnvironmentVariables.js.map +1 -0
  22. package/dist/es/models/IModuleProtocol.js +2 -0
  23. package/dist/es/models/IModuleProtocol.js.map +1 -0
  24. package/dist/es/models/INodeEngineConfig.js +2 -0
  25. package/dist/es/models/INodeEngineConfig.js.map +1 -0
  26. package/dist/es/models/INodeEngineState.js +2 -0
  27. package/dist/es/models/INodeEngineState.js.map +1 -0
  28. package/dist/es/models/INodeEnvironmentVariables.js +2 -0
  29. package/dist/es/models/INodeEnvironmentVariables.js.map +1 -0
  30. package/dist/es/models/INodeOptions.js +2 -0
  31. package/dist/es/models/INodeOptions.js.map +1 -0
  32. package/dist/es/models/IProtocolHandlerResult.js +4 -0
  33. package/dist/es/models/IProtocolHandlerResult.js.map +1 -0
  34. package/dist/es/models/moduleProtocol.js +29 -0
  35. package/dist/es/models/moduleProtocol.js.map +1 -0
  36. package/dist/es/models/nodeExtensionMethods.js +2 -0
  37. package/dist/es/models/nodeExtensionMethods.js.map +1 -0
  38. package/dist/es/models/nodeFeatures.js +21 -0
  39. package/dist/es/models/nodeFeatures.js.map +1 -0
  40. package/dist/es/node.js +265 -0
  41. package/dist/es/node.js.map +1 -0
  42. package/dist/es/server.js +74 -0
  43. package/dist/es/server.js.map +1 -0
  44. package/dist/es/utils.js +418 -0
  45. package/dist/es/utils.js.map +1 -0
  46. package/dist/types/bootstrap.d.ts +27 -10
  47. package/dist/types/builders/engineEnvBuilder.d.ts +3 -2
  48. package/dist/types/builders/engineServerEnvBuilder.d.ts +4 -3
  49. package/dist/types/builders/extensionsBuilder.d.ts +32 -0
  50. package/dist/types/defaults.d.ts +6 -0
  51. package/dist/types/identity.d.ts +14 -0
  52. package/dist/types/index.d.ts +20 -11
  53. package/dist/types/models/ICacheMetadata.d.ts +17 -0
  54. package/dist/types/models/IEngineEnvironmentVariables.d.ts +132 -24
  55. package/dist/types/models/IEngineServerEnvironmentVariables.d.ts +12 -3
  56. package/dist/types/models/IModuleProtocol.d.ts +18 -0
  57. package/dist/types/models/INodeEngineConfig.d.ts +6 -0
  58. package/dist/types/models/INodeEngineState.d.ts +22 -0
  59. package/dist/types/models/INodeEnvironmentVariables.d.ts +50 -10
  60. package/dist/types/models/INodeOptions.d.ts +14 -3
  61. package/dist/types/models/IProtocolHandlerResult.d.ts +13 -0
  62. package/dist/types/models/moduleProtocol.d.ts +29 -0
  63. package/dist/types/models/nodeExtensionMethods.d.ts +27 -0
  64. package/dist/types/models/nodeFeatures.d.ts +5 -5
  65. package/dist/types/node.d.ts +17 -7
  66. package/dist/types/server.d.ts +9 -6
  67. package/dist/types/utils.d.ts +87 -2
  68. package/docs/changelog.md +178 -0
  69. package/docs/detailed-guide.md +129 -0
  70. package/docs/reference/functions/bootstrap.md +1 -1
  71. package/docs/reference/functions/bootstrapAuth.md +1 -1
  72. package/docs/reference/functions/bootstrapBlobEncryption.md +1 -1
  73. package/docs/reference/functions/bootstrapContextIdHandlers.md +35 -0
  74. package/docs/reference/functions/bootstrapImmutableProofMethod.md +1 -1
  75. package/docs/reference/functions/{bootstrapNodeUser.md → bootstrapNodeAdminUser.md} +3 -3
  76. package/docs/reference/functions/{bootstrapNodeIdentity.md → bootstrapNodeId.md} +3 -3
  77. package/docs/reference/functions/bootstrapSynchronisedStorage.md +1 -1
  78. package/docs/reference/functions/bootstrapTenantId.md +35 -0
  79. package/docs/reference/functions/buildConfiguration.md +2 -2
  80. package/docs/reference/functions/buildEngineConfiguration.md +8 -2
  81. package/docs/reference/functions/buildEngineServerConfiguration.md +9 -3
  82. package/docs/reference/functions/createModuleImportUrl.md +21 -0
  83. package/docs/reference/functions/directoryExists.md +19 -0
  84. package/docs/reference/functions/extensionsConfiguration.md +25 -0
  85. package/docs/reference/functions/extensionsInitialiseEngine.md +25 -0
  86. package/docs/reference/functions/extensionsInitialiseEngineServer.md +31 -0
  87. package/docs/reference/functions/getExtensionsCacheDir.md +31 -0
  88. package/docs/reference/functions/getFiles.md +19 -0
  89. package/docs/reference/functions/getSubFolders.md +19 -0
  90. package/docs/reference/functions/handleHttpsProtocol.md +49 -0
  91. package/docs/reference/functions/handleNpmProtocol.md +31 -0
  92. package/docs/reference/functions/hashUrl.md +19 -0
  93. package/docs/reference/functions/isCacheExpired.md +31 -0
  94. package/docs/reference/functions/overrideModuleImport.md +8 -2
  95. package/docs/reference/functions/parseModuleProtocol.md +19 -0
  96. package/docs/reference/functions/resolvePackageEntryPoint.md +32 -0
  97. package/docs/reference/functions/run.md +3 -3
  98. package/docs/reference/functions/shutdownExtensions.md +25 -0
  99. package/docs/reference/functions/start.md +11 -5
  100. package/docs/reference/index.md +36 -2
  101. package/docs/reference/interfaces/ICacheMetadata.md +27 -0
  102. package/docs/reference/interfaces/IEngineEnvironmentVariables.md +255 -37
  103. package/docs/reference/interfaces/IEngineServerEnvironmentVariables.md +1696 -5
  104. package/docs/reference/interfaces/IModuleProtocol.md +27 -0
  105. package/docs/reference/interfaces/INodeEngineConfig.md +7 -0
  106. package/docs/reference/interfaces/INodeEngineState.md +39 -0
  107. package/docs/reference/interfaces/INodeEnvironmentVariables.md +609 -165
  108. package/docs/reference/interfaces/INodeOptions.md +27 -3
  109. package/docs/reference/interfaces/IProtocolHandlerResult.md +19 -0
  110. package/docs/reference/type-aliases/ModuleProtocol.md +5 -0
  111. package/docs/reference/type-aliases/NodeExtensionInitialiseEngineMethod.md +18 -0
  112. package/docs/reference/type-aliases/NodeExtensionInitialiseEngineServerMethod.md +24 -0
  113. package/docs/reference/type-aliases/NodeExtensionInitialiseMethod.md +23 -0
  114. package/docs/reference/type-aliases/NodeExtensionShutdownMethod.md +10 -0
  115. package/docs/reference/variables/ATTESTATION_VERIFICATION_METHOD_ID.md +3 -0
  116. package/docs/reference/variables/AUTH_SIGNING_KEY_ID.md +3 -0
  117. package/docs/reference/variables/BLOB_STORAGE_ENCRYPTION_KEY_ID.md +3 -0
  118. package/docs/reference/variables/IMMUTABLE_PROOF_VERIFICATION_METHOD_ID.md +3 -0
  119. package/docs/reference/variables/ModuleProtocol.md +37 -0
  120. package/docs/reference/variables/NodeFeatures.md +7 -7
  121. package/docs/reference/variables/SYNCHRONISED_STORAGE_BLOB_STORAGE_ENCRYPTION_KEY_ID.md +3 -0
  122. package/docs/reference/variables/VC_AUTHENTICATION_VERIFICATION_METHOD_ID.md +3 -0
  123. package/locales/en.json +27 -9
  124. package/package.json +27 -9
  125. package/dist/cjs/index.cjs +0 -1910
  126. package/dist/esm/index.mjs +0 -1870
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TWIN Node Core
2
2
 
3
- TWIN Node Core for serving APIs using the specified configuration
3
+ Core components for running TWIN nodes with dynamic extension loading and protocol-based module resolution.
4
4
 
5
5
  ## Installation
6
6
 
@@ -0,0 +1,374 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { PasswordHelper } from "@twin.org/api-auth-entity-storage-service";
4
+ import { TenantIdContextIdHandler, TenantIdHelper } from "@twin.org/api-tenant-processor";
5
+ import { ContextIdHandlerFactory, ContextIdKeys, ContextIdStore } from "@twin.org/context";
6
+ import { Coerce, ComponentFactory, Converter, I18n, Is, RandomHelper } from "@twin.org/core";
7
+ import { PasswordGenerator } from "@twin.org/crypto";
8
+ import { AuthenticationComponentType } from "@twin.org/engine-server-types";
9
+ import { EntityStorageConnectorFactory } from "@twin.org/entity-storage-models";
10
+ import { DidContextIdHandler, DocumentHelper, IdentityConnectorFactory, IdentityProfileConnectorFactory, IdentityResolverConnectorFactory } from "@twin.org/identity-models";
11
+ import { VaultConnectorFactory, VaultKeyType } from "@twin.org/vault-models";
12
+ import { ATTESTATION_VERIFICATION_METHOD_ID, AUTH_SIGNING_KEY_ID, BLOB_STORAGE_ENCRYPTION_KEY_ID, IMMUTABLE_PROOF_VERIFICATION_METHOD_ID, SYNCHRONISED_STORAGE_BLOB_STORAGE_ENCRYPTION_KEY_ID, VC_AUTHENTICATION_VERIFICATION_METHOD_ID } from "./defaults.js";
13
+ import { createIdentity } from "./identity.js";
14
+ import { NodeFeatures } from "./models/nodeFeatures.js";
15
+ import { getFeatures } from "./utils.js";
16
+ const DEFAULT_NODE_ADMIN_USERNAME = "admin@node";
17
+ /**
18
+ * Bootstrap the application.
19
+ * @param engineCore The engine core for the node.
20
+ * @param context The context for the node.
21
+ * @param envVars The environment variables for the node.
22
+ */
23
+ export async function bootstrap(engineCore, context, envVars) {
24
+ const features = getFeatures(envVars);
25
+ await bootstrapContextIdHandlers(engineCore, context, envVars, features);
26
+ await bootstrapNodeId(engineCore, context, envVars, features);
27
+ await ContextIdStore.run(engineCore.getContextIds() ?? {}, async () => {
28
+ await bootstrapTenantId(engineCore, context, envVars, features);
29
+ await bootstrapNodeAdminUser(engineCore, context, envVars, features);
30
+ await bootstrapAuth(engineCore, context, envVars, features);
31
+ await bootstrapBlobEncryption(engineCore, context, envVars, features);
32
+ const defaultAttestationConnectorType = engineCore.getRegisteredInstanceTypeOptional("attestationConnector");
33
+ if (!Is.empty(defaultAttestationConnectorType) &&
34
+ Is.stringValue(context.state.nodeOrganizationId)) {
35
+ await addVerificationMethod(engineCore, context, context.state.nodeOrganizationId, "attestation", envVars.attestationVerificationMethodId ?? ATTESTATION_VERIFICATION_METHOD_ID);
36
+ }
37
+ const defaultImmutableProofComponentType = engineCore.getRegisteredInstanceTypeOptional("immutableProofComponent");
38
+ if (!Is.empty(defaultImmutableProofComponentType) &&
39
+ Is.stringValue(context.state.nodeOrganizationId)) {
40
+ await addVerificationMethod(engineCore, context, context.state.nodeOrganizationId, "immutable proof", envVars.immutableProofVerificationMethodId ?? IMMUTABLE_PROOF_VERIFICATION_METHOD_ID);
41
+ }
42
+ if ((Coerce.boolean(envVars.vcAuthenticationEnabled) ?? false) &&
43
+ Is.stringValue(context.state.nodeId)) {
44
+ await addVerificationMethod(engineCore, context, context.state.nodeId, "verifiable credential authentication", envVars.vcAuthenticationVerificationMethodId ?? VC_AUTHENTICATION_VERIFICATION_METHOD_ID);
45
+ }
46
+ await bootstrapSynchronisedStorage(engineCore, context, envVars, features);
47
+ });
48
+ }
49
+ /**
50
+ * Bootstrap the context id handlers creating any necessary resources.
51
+ * @param engineCore The engine core for the node.
52
+ * @param context The context for the node.
53
+ * @param envVars The environment variables for the node.
54
+ * @param features The features that are enabled on the node. The features that are enabled on the node.
55
+ */
56
+ export async function bootstrapContextIdHandlers(engineCore, context, envVars, features) {
57
+ ContextIdHandlerFactory.register(ContextIdKeys.Node, () => new DidContextIdHandler());
58
+ ContextIdHandlerFactory.register(ContextIdKeys.Tenant, () => new TenantIdContextIdHandler());
59
+ ContextIdHandlerFactory.register(ContextIdKeys.Organization, () => new DidContextIdHandler());
60
+ ContextIdHandlerFactory.register(ContextIdKeys.User, () => new DidContextIdHandler());
61
+ }
62
+ /**
63
+ * Bootstrap the node creating any necessary resources.
64
+ * @param engineCore The engine core for the node.
65
+ * @param context The context for the node.
66
+ * @param envVars The environment variables for the node.
67
+ * @param features The features that are enabled on the node. The features that are enabled on the node.
68
+ */
69
+ export async function bootstrapNodeId(engineCore, context, envVars, features) {
70
+ if (features.includes(NodeFeatures.NodeId)) {
71
+ const existingNodeId = envVars.nodeIdentity ?? context.state.nodeId;
72
+ context.state.nodeId = await createIdentity(engineCore, envVars, existingNodeId, envVars.nodeMnemonic, existingNodeId, "node", features.includes(NodeFeatures.NodeWallet));
73
+ context.stateDirty = true;
74
+ engineCore.logInfo(I18n.formatMessage("node.nodeId", {
75
+ identity: context.state.nodeId
76
+ }));
77
+ engineCore.addContextId(ContextIdKeys.Node, context.state.nodeId);
78
+ }
79
+ }
80
+ /**
81
+ * Bootstrap the node creating any necessary resources.
82
+ * @param engineCore The engine core for the node.
83
+ * @param context The context for the node.
84
+ * @param envVars The environment variables for the node.
85
+ * @param features The features that are enabled on the node. The features that are enabled on the node.
86
+ */
87
+ export async function bootstrapTenantId(engineCore, context, envVars, features) {
88
+ // If tenants are enabled we need to add a context id for the node
89
+ // so that services such a logging have a default tenant context id
90
+ // this will get overwritten by any incoming API requests with the tenant context id
91
+ if (Coerce.boolean(envVars.tenantEnabled) ?? false) {
92
+ let tenantId = envVars.tenantId ?? context.state.nodeTenantId;
93
+ if (!Is.stringValue(tenantId)) {
94
+ const tenantAdminServiceComponentType = engineCore.getRegisteredInstanceType("tenantAdminComponent");
95
+ const tenantAdminService = ComponentFactory.get(tenantAdminServiceComponentType);
96
+ tenantId = TenantIdHelper.generateTenantId();
97
+ const apiKey = envVars.tenantApiKey ?? TenantIdHelper.generateApiKey();
98
+ await tenantAdminService.set({
99
+ id: tenantId,
100
+ apiKey,
101
+ dateCreated: new Date(Date.now()).toISOString(),
102
+ label: "node-tenant"
103
+ });
104
+ engineCore.logInfo(I18n.formatMessage("node.createdTenantId", {
105
+ identity: tenantId,
106
+ apiKey
107
+ }));
108
+ }
109
+ else {
110
+ engineCore.logInfo(I18n.formatMessage("node.existingTenantId", {
111
+ identity: context.state.nodeTenantId
112
+ }));
113
+ }
114
+ context.state.nodeTenantId = tenantId;
115
+ context.stateDirty = true;
116
+ engineCore.addContextId(ContextIdKeys.Tenant, context.state.nodeTenantId);
117
+ }
118
+ }
119
+ /**
120
+ * Bootstrap the user.
121
+ * @param engineCore The engine core for the node.
122
+ * @param context The context for the node.
123
+ * @param envVars The environment variables for the node.
124
+ * @param features The features that are enabled on the node.
125
+ */
126
+ export async function bootstrapNodeAdminUser(engineCore, context, envVars, features) {
127
+ if (features.includes(NodeFeatures.NodeAdminUser)) {
128
+ context.state.nodeOrganizationId =
129
+ envVars.organizationIdentity ?? context.state.nodeOrganizationId;
130
+ context.state.nodeAdminUserId = envVars.adminUserIdentity ?? context.state.nodeAdminUserId;
131
+ const defaultAuthenticationComponentType = engineCore.getRegisteredInstanceType("authenticationComponent");
132
+ if (defaultAuthenticationComponentType.startsWith(AuthenticationComponentType.EntityStorage) &&
133
+ Is.stringValue(context.state.nodeId)) {
134
+ const authUserEntityStorage = EntityStorageConnectorFactory.get("authentication-user");
135
+ // If we don't have an organization identity, create one
136
+ if (!Is.stringValue(context.state.nodeOrganizationId)) {
137
+ context.state.nodeOrganizationId = await createIdentity(engineCore, envVars, context.state.nodeOrganizationId, envVars.organizationMnemonic, context.state.nodeId, "organization", features.includes(NodeFeatures.NodeWallet));
138
+ context.stateDirty = true;
139
+ }
140
+ if (!Is.stringValue(context.state.nodeAdminUserId)) {
141
+ context.state.nodeAdminUserId = await createIdentity(engineCore, envVars, context.state.nodeAdminUserId, envVars.adminUserMnemonic, context.state.nodeOrganizationId, "user", false);
142
+ context.stateDirty = true;
143
+ }
144
+ const adminEmail = envVars.adminUserName ?? DEFAULT_NODE_ADMIN_USERNAME;
145
+ let nodeAdminUser = await authUserEntityStorage.get(adminEmail);
146
+ // If the node admin user doesn't exist, create it
147
+ if (Is.empty(nodeAdminUser)) {
148
+ engineCore.logInfo(I18n.formatMessage("node.creatingUser", { email: adminEmail }));
149
+ const generatedPassword = envVars.adminUserPassword ?? PasswordGenerator.generate(16);
150
+ const passwordBytes = Converter.utf8ToBytes(generatedPassword);
151
+ const saltBytes = RandomHelper.generate(16);
152
+ const hashedPassword = await PasswordHelper.hashPassword(passwordBytes, saltBytes);
153
+ nodeAdminUser = {
154
+ email: adminEmail,
155
+ password: hashedPassword,
156
+ salt: Converter.bytesToBase64(saltBytes),
157
+ identity: context.state.nodeAdminUserId,
158
+ organization: context.state.nodeOrganizationId
159
+ };
160
+ engineCore.logInfo(I18n.formatMessage("node.nodeAdminUserEmail", { email: adminEmail }));
161
+ engineCore.logInfo(I18n.formatMessage("node.nodeAdminUserPassword", { password: generatedPassword }));
162
+ await authUserEntityStorage.set(nodeAdminUser);
163
+ }
164
+ else {
165
+ engineCore.logInfo(I18n.formatMessage("node.existingUser", { email: adminEmail }));
166
+ // The user already exists, so double check the other details match
167
+ let needsUpdate = false;
168
+ if (nodeAdminUser.identity !== context.state.nodeAdminUserId) {
169
+ nodeAdminUser.identity = context.state.nodeAdminUserId;
170
+ needsUpdate = true;
171
+ }
172
+ if (Is.stringValue(envVars.adminUserPassword)) {
173
+ const passwordBytes = Converter.utf8ToBytes(envVars.adminUserPassword);
174
+ const saltBytes = Converter.base64ToBytes(nodeAdminUser.salt);
175
+ const hashedPassword = await PasswordHelper.hashPassword(passwordBytes, saltBytes);
176
+ if (nodeAdminUser.password !== hashedPassword) {
177
+ nodeAdminUser.password = hashedPassword;
178
+ needsUpdate = true;
179
+ }
180
+ }
181
+ if (needsUpdate) {
182
+ await authUserEntityStorage.set(nodeAdminUser);
183
+ }
184
+ }
185
+ // We have create a node user, now we need to create a profile for the user
186
+ const defaultIdentityProfileConnectorType = engineCore.getRegisteredInstanceType("identityProfileConnector");
187
+ const identityProfileConnector = IdentityProfileConnectorFactory.get(defaultIdentityProfileConnectorType);
188
+ if (identityProfileConnector) {
189
+ // Add the organization context id when creating the profile
190
+ // so that it is partitioned under the organization
191
+ const contextIds = (await ContextIdStore.getContextIds()) ?? {};
192
+ contextIds[ContextIdKeys.Organization] = context.state.nodeOrganizationId;
193
+ await ContextIdStore.run(contextIds, async () => {
194
+ let userProfile;
195
+ if (Is.stringValue(nodeAdminUser.identity)) {
196
+ try {
197
+ userProfile = await identityProfileConnector.get(nodeAdminUser.identity);
198
+ }
199
+ catch { }
200
+ }
201
+ if (Is.empty(userProfile)) {
202
+ engineCore.logInfo(I18n.formatMessage("node.creatingUserProfile", {
203
+ identity: nodeAdminUser.identity
204
+ }));
205
+ const publicProfile = {
206
+ "@context": "https://schema.org",
207
+ "@type": "Person",
208
+ name: "Node Administrator"
209
+ };
210
+ const privateProfile = {
211
+ "@context": "https://schema.org",
212
+ "@type": "Person",
213
+ givenName: "Node",
214
+ familyName: "Administrator",
215
+ email: adminEmail
216
+ };
217
+ await identityProfileConnector.create(nodeAdminUser.identity, publicProfile, privateProfile);
218
+ }
219
+ else {
220
+ engineCore.logInfo(I18n.formatMessage("node.existingUserProfile", {
221
+ identity: nodeAdminUser.identity
222
+ }));
223
+ }
224
+ });
225
+ }
226
+ }
227
+ }
228
+ }
229
+ /**
230
+ * Bootstrap the immutable proof verification methods.
231
+ * @param engineCore The engine core for the node.
232
+ * @param context The context for the node.
233
+ * @param envVars The environment variables for the node.
234
+ * @param features The features that are enabled on the node.
235
+ */
236
+ export async function bootstrapImmutableProofMethod(engineCore, context, envVars, features) { }
237
+ /**
238
+ * Bootstrap the keys for blob encryption.
239
+ * @param engineCore The engine core for the node.
240
+ * @param context The context for the node.
241
+ * @param envVars The environment variables for the node.
242
+ * @param features The features that are enabled on the node.
243
+ */
244
+ export async function bootstrapBlobEncryption(engineCore, context, envVars, features) {
245
+ if ((Coerce.boolean(envVars.blobStorageEnableEncryption) ?? false) &&
246
+ Is.stringValue(context.state.nodeOrganizationId)) {
247
+ // Create a new key for encrypting blobs
248
+ const defaultVaultConnectorType = engineCore.getRegisteredInstanceType("vaultConnector");
249
+ const vaultConnector = VaultConnectorFactory.get(defaultVaultConnectorType);
250
+ const keyName = `${context.state.nodeOrganizationId}/${envVars.blobStorageEncryptionKeyId ?? BLOB_STORAGE_ENCRYPTION_KEY_ID}`;
251
+ let existingKey;
252
+ try {
253
+ existingKey = await vaultConnector.getKey(keyName);
254
+ }
255
+ catch { }
256
+ if (Is.empty(existingKey)) {
257
+ if (Is.stringBase64(envVars.blobStorageSymmetricEncryptionKey)) {
258
+ engineCore.logInfo(I18n.formatMessage("node.addingBlobEncryptionKey", { keyName }));
259
+ await vaultConnector.addKey(keyName, VaultKeyType.ChaCha20Poly1305, Converter.base64ToBytes(envVars.blobStorageSymmetricEncryptionKey));
260
+ }
261
+ else {
262
+ engineCore.logInfo(I18n.formatMessage("node.creatingBlobEncryptionKey", { keyName }));
263
+ const key = await vaultConnector.createKey(keyName, VaultKeyType.ChaCha20Poly1305);
264
+ engineCore.logInfo(I18n.formatMessage("node.createdBlobEncryptionKey", {
265
+ keyName,
266
+ keyValue: Converter.bytesToBase64(key)
267
+ }));
268
+ }
269
+ }
270
+ else {
271
+ engineCore.logInfo(I18n.formatMessage("node.existingBlobEncryptionKey", { keyName }));
272
+ }
273
+ }
274
+ }
275
+ /**
276
+ * Bootstrap the JWT signing key.
277
+ * @param engineCore The engine core for the node.
278
+ * @param context The context for the node.
279
+ * @param envVars The environment variables for the node.
280
+ * @param features The features that are enabled on the node.
281
+ */
282
+ export async function bootstrapAuth(engineCore, context, envVars, features) {
283
+ const defaultAuthenticationComponentType = engineCore.getRegisteredInstanceTypeOptional("authenticationComponent");
284
+ if (Is.stringValue(defaultAuthenticationComponentType) &&
285
+ defaultAuthenticationComponentType.startsWith(AuthenticationComponentType.EntityStorage) &&
286
+ Is.stringValue(context.state.nodeId)) {
287
+ // Create a new JWT signing key and a user login for the node
288
+ const defaultVaultConnectorType = engineCore.getRegisteredInstanceType("vaultConnector");
289
+ const vaultConnector = VaultConnectorFactory.get(defaultVaultConnectorType);
290
+ const keyName = `${context.state.nodeId}/${envVars.authSigningKeyId ?? AUTH_SIGNING_KEY_ID}`;
291
+ let existingKey;
292
+ try {
293
+ existingKey = await vaultConnector.getKey(keyName);
294
+ }
295
+ catch { }
296
+ if (Is.empty(existingKey)) {
297
+ engineCore.logInfo(I18n.formatMessage("node.creatingAuthKey", { keyName }));
298
+ await vaultConnector.createKey(keyName, VaultKeyType.Ed25519);
299
+ }
300
+ else {
301
+ engineCore.logInfo(I18n.formatMessage("node.existingAuthKey", { keyName }));
302
+ }
303
+ }
304
+ }
305
+ /**
306
+ * Bootstrap the synchronised storage blob encryption and verification methods.
307
+ * @param engineCore The engine core for the node.
308
+ * @param context The context for the node.
309
+ * @param envVars The environment variables for the node.
310
+ * @param features The features that are enabled on the node.
311
+ */
312
+ export async function bootstrapSynchronisedStorage(engineCore, context, envVars, features) {
313
+ if (Coerce.boolean(envVars.synchronisedStorageEnabled) ?? false) {
314
+ // If this is a trusted node we need to add the blob encryption key pair
315
+ if (Is.stringBase64(envVars.synchronisedStorageBlobStorageKey)) {
316
+ const defaultVaultConnectorType = engineCore.getRegisteredInstanceType("vaultConnector");
317
+ const vaultConnector = VaultConnectorFactory.get(defaultVaultConnectorType);
318
+ const keyName = envVars.synchronisedStorageBlobStorageEncryptionKeyId ??
319
+ SYNCHRONISED_STORAGE_BLOB_STORAGE_ENCRYPTION_KEY_ID;
320
+ let existingKey;
321
+ try {
322
+ existingKey = await vaultConnector.getKey(keyName);
323
+ }
324
+ catch { }
325
+ if (Is.empty(existingKey)) {
326
+ engineCore.logInfo(I18n.formatMessage("node.addingSynchronisedStorageBlobEncryptionKey", { keyName }));
327
+ await vaultConnector.addKey(keyName, VaultKeyType.ChaCha20Poly1305, Converter.base64ToBytes(envVars.synchronisedStorageBlobStorageKey));
328
+ }
329
+ else {
330
+ engineCore.logInfo(I18n.formatMessage("node.existingSynchronisedStorageBlobEncryptionKey", { keyName }));
331
+ }
332
+ }
333
+ }
334
+ }
335
+ /**
336
+ * Add a verification method if it doesn't exist.
337
+ * @param engineCore The engine core for the node.
338
+ * @param context The context for the node.
339
+ * @param identity The identity to add the verification method to.
340
+ * @param verificationMethodTitle The verification method title.
341
+ * @param verificationMethodId The verification method ID.
342
+ */
343
+ async function addVerificationMethod(engineCore, context, identity, verificationMethodTitle, verificationMethodId) {
344
+ if (Is.stringValue(identity) &&
345
+ Is.arrayValue(context.config.types.identityConnector) &&
346
+ Is.stringValue(verificationMethodId)) {
347
+ const defaultIdentityConnectorType = engineCore.getRegisteredInstanceType("identityConnector");
348
+ const identityConnector = IdentityConnectorFactory.get(defaultIdentityConnectorType);
349
+ const defaultIdentityResolverConnectorType = engineCore.getRegisteredInstanceType("identityResolverConnector");
350
+ const identityResolverConnector = IdentityResolverConnectorFactory.get(defaultIdentityResolverConnectorType);
351
+ const identityDocument = await identityResolverConnector.resolveDocument(identity);
352
+ const fullMethodId = `${identityDocument.id}#${verificationMethodId}`;
353
+ let exists = false;
354
+ try {
355
+ DocumentHelper.getVerificationMethod(identityDocument, fullMethodId, "assertionMethod");
356
+ exists = true;
357
+ }
358
+ catch { }
359
+ if (!exists) {
360
+ engineCore.logInfo(I18n.formatMessage("node.addingVerificationMethod", {
361
+ title: verificationMethodTitle,
362
+ methodId: fullMethodId
363
+ }));
364
+ await identityConnector.addVerificationMethod(identity, identity, "assertionMethod", verificationMethodId);
365
+ }
366
+ else {
367
+ engineCore.logInfo(I18n.formatMessage("node.existingVerificationMethod", {
368
+ title: verificationMethodTitle,
369
+ methodId: fullMethodId
370
+ }));
371
+ }
372
+ }
373
+ }
374
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/bootstrap.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { PasswordHelper, type AuthenticationUser } from \"@twin.org/api-auth-entity-storage-service\";\nimport {\n\tTenantIdContextIdHandler,\n\tTenantIdHelper,\n\ttype ITenantAdminComponent\n} from \"@twin.org/api-tenant-processor\";\nimport { ContextIdHandlerFactory, ContextIdKeys, ContextIdStore } from \"@twin.org/context\";\nimport { Coerce, ComponentFactory, Converter, I18n, Is, RandomHelper } from \"@twin.org/core\";\nimport { PasswordGenerator } from \"@twin.org/crypto\";\nimport type { IEngineCore, IEngineCoreContext } from \"@twin.org/engine-models\";\nimport {\n\tAuthenticationComponentType,\n\ttype IEngineServerConfig\n} from \"@twin.org/engine-server-types\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport {\n\tDidContextIdHandler,\n\tDocumentHelper,\n\tIdentityConnectorFactory,\n\tIdentityProfileConnectorFactory,\n\tIdentityResolverConnectorFactory\n} from \"@twin.org/identity-models\";\nimport { nameofKebabCase } from \"@twin.org/nameof\";\nimport { VaultConnectorFactory, VaultKeyType } from \"@twin.org/vault-models\";\nimport type { Person, WithContext } from \"schema-dts\";\nimport {\n\tATTESTATION_VERIFICATION_METHOD_ID,\n\tAUTH_SIGNING_KEY_ID,\n\tBLOB_STORAGE_ENCRYPTION_KEY_ID,\n\tIMMUTABLE_PROOF_VERIFICATION_METHOD_ID,\n\tSYNCHRONISED_STORAGE_BLOB_STORAGE_ENCRYPTION_KEY_ID,\n\tVC_AUTHENTICATION_VERIFICATION_METHOD_ID\n} from \"./defaults.js\";\nimport { createIdentity } from \"./identity.js\";\nimport type { INodeEngineState } from \"./models/INodeEngineState.js\";\nimport type { INodeEnvironmentVariables } from \"./models/INodeEnvironmentVariables.js\";\nimport { NodeFeatures } from \"./models/nodeFeatures.js\";\nimport { getFeatures } from \"./utils.js\";\n\nconst DEFAULT_NODE_ADMIN_USERNAME = \"admin@node\";\n\n/**\n * Bootstrap the application.\n * @param engineCore The engine core for the node.\n * @param context The context for the node.\n * @param envVars The environment variables for the node.\n */\nexport async function bootstrap(\n\tengineCore: IEngineCore,\n\tcontext: IEngineCoreContext<IEngineServerConfig, INodeEngineState>,\n\tenvVars: INodeEnvironmentVariables\n): Promise<void> {\n\tconst features = getFeatures(envVars);\n\n\tawait bootstrapContextIdHandlers(engineCore, context, envVars, features);\n\n\tawait bootstrapNodeId(engineCore, context, envVars, features);\n\n\tawait ContextIdStore.run(engineCore.getContextIds() ?? {}, async () => {\n\t\tawait bootstrapTenantId(engineCore, context, envVars, features);\n\n\t\tawait bootstrapNodeAdminUser(engineCore, context, envVars, features);\n\t\tawait bootstrapAuth(engineCore, context, envVars, features);\n\t\tawait bootstrapBlobEncryption(engineCore, context, envVars, features);\n\n\t\tconst defaultAttestationConnectorType =\n\t\t\tengineCore.getRegisteredInstanceTypeOptional(\"attestationConnector\");\n\t\tif (\n\t\t\t!Is.empty(defaultAttestationConnectorType) &&\n\t\t\tIs.stringValue(context.state.nodeOrganizationId)\n\t\t) {\n\t\t\tawait addVerificationMethod(\n\t\t\t\tengineCore,\n\t\t\t\tcontext,\n\t\t\t\tcontext.state.nodeOrganizationId,\n\t\t\t\t\"attestation\",\n\t\t\t\tenvVars.attestationVerificationMethodId ?? ATTESTATION_VERIFICATION_METHOD_ID\n\t\t\t);\n\t\t}\n\n\t\tconst defaultImmutableProofComponentType =\n\t\t\tengineCore.getRegisteredInstanceTypeOptional(\"immutableProofComponent\");\n\n\t\tif (\n\t\t\t!Is.empty(defaultImmutableProofComponentType) &&\n\t\t\tIs.stringValue(context.state.nodeOrganizationId)\n\t\t) {\n\t\t\tawait addVerificationMethod(\n\t\t\t\tengineCore,\n\t\t\t\tcontext,\n\t\t\t\tcontext.state.nodeOrganizationId,\n\t\t\t\t\"immutable proof\",\n\t\t\t\tenvVars.immutableProofVerificationMethodId ?? IMMUTABLE_PROOF_VERIFICATION_METHOD_ID\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\t(Coerce.boolean(envVars.vcAuthenticationEnabled) ?? false) &&\n\t\t\tIs.stringValue(context.state.nodeId)\n\t\t) {\n\t\t\tawait addVerificationMethod(\n\t\t\t\tengineCore,\n\t\t\t\tcontext,\n\t\t\t\tcontext.state.nodeId,\n\t\t\t\t\"verifiable credential authentication\",\n\t\t\t\tenvVars.vcAuthenticationVerificationMethodId ?? VC_AUTHENTICATION_VERIFICATION_METHOD_ID\n\t\t\t);\n\t\t}\n\n\t\tawait bootstrapSynchronisedStorage(engineCore, context, envVars, features);\n\t});\n}\n\n/**\n * Bootstrap the context id handlers creating any necessary resources.\n * @param engineCore The engine core for the node.\n * @param context The context for the node.\n * @param envVars The environment variables for the node.\n * @param features The features that are enabled on the node. The features that are enabled on the node.\n */\nexport async function bootstrapContextIdHandlers(\n\tengineCore: IEngineCore,\n\tcontext: IEngineCoreContext<IEngineServerConfig, INodeEngineState>,\n\tenvVars: INodeEnvironmentVariables,\n\tfeatures: NodeFeatures[]\n): Promise<void> {\n\tContextIdHandlerFactory.register(ContextIdKeys.Node, () => new DidContextIdHandler());\n\tContextIdHandlerFactory.register(ContextIdKeys.Tenant, () => new TenantIdContextIdHandler());\n\tContextIdHandlerFactory.register(ContextIdKeys.Organization, () => new DidContextIdHandler());\n\tContextIdHandlerFactory.register(ContextIdKeys.User, () => new DidContextIdHandler());\n}\n\n/**\n * Bootstrap the node creating any necessary resources.\n * @param engineCore The engine core for the node.\n * @param context The context for the node.\n * @param envVars The environment variables for the node.\n * @param features The features that are enabled on the node. The features that are enabled on the node.\n */\nexport async function bootstrapNodeId(\n\tengineCore: IEngineCore,\n\tcontext: IEngineCoreContext<IEngineServerConfig, INodeEngineState>,\n\tenvVars: INodeEnvironmentVariables,\n\tfeatures: NodeFeatures[]\n): Promise<void> {\n\tif (features.includes(NodeFeatures.NodeId)) {\n\t\tconst existingNodeId = envVars.nodeIdentity ?? context.state.nodeId;\n\n\t\tcontext.state.nodeId = await createIdentity(\n\t\t\tengineCore,\n\t\t\tenvVars,\n\t\t\texistingNodeId,\n\t\t\tenvVars.nodeMnemonic,\n\t\t\texistingNodeId,\n\t\t\t\"node\",\n\t\t\tfeatures.includes(NodeFeatures.NodeWallet)\n\t\t);\n\t\tcontext.stateDirty = true;\n\n\t\tengineCore.logInfo(\n\t\t\tI18n.formatMessage(\"node.nodeId\", {\n\t\t\t\tidentity: context.state.nodeId\n\t\t\t})\n\t\t);\n\n\t\tengineCore.addContextId(ContextIdKeys.Node, context.state.nodeId);\n\t}\n}\n\n/**\n * Bootstrap the node creating any necessary resources.\n * @param engineCore The engine core for the node.\n * @param context The context for the node.\n * @param envVars The environment variables for the node.\n * @param features The features that are enabled on the node. The features that are enabled on the node.\n */\nexport async function bootstrapTenantId(\n\tengineCore: IEngineCore,\n\tcontext: IEngineCoreContext<IEngineServerConfig, INodeEngineState>,\n\tenvVars: INodeEnvironmentVariables,\n\tfeatures: NodeFeatures[]\n): Promise<void> {\n\t// If tenants are enabled we need to add a context id for the node\n\t// so that services such a logging have a default tenant context id\n\t// this will get overwritten by any incoming API requests with the tenant context id\n\tif (Coerce.boolean(envVars.tenantEnabled) ?? false) {\n\t\tlet tenantId = envVars.tenantId ?? context.state.nodeTenantId;\n\n\t\tif (!Is.stringValue(tenantId)) {\n\t\t\tconst tenantAdminServiceComponentType =\n\t\t\t\tengineCore.getRegisteredInstanceType(\"tenantAdminComponent\");\n\n\t\t\tconst tenantAdminService = ComponentFactory.get<ITenantAdminComponent>(\n\t\t\t\ttenantAdminServiceComponentType\n\t\t\t);\n\n\t\t\ttenantId = TenantIdHelper.generateTenantId();\n\t\t\tconst apiKey = envVars.tenantApiKey ?? TenantIdHelper.generateApiKey();\n\n\t\t\tawait tenantAdminService.set({\n\t\t\t\tid: tenantId,\n\t\t\t\tapiKey,\n\t\t\t\tdateCreated: new Date(Date.now()).toISOString(),\n\t\t\t\tlabel: \"node-tenant\"\n\t\t\t});\n\n\t\t\tengineCore.logInfo(\n\t\t\t\tI18n.formatMessage(\"node.createdTenantId\", {\n\t\t\t\t\tidentity: tenantId,\n\t\t\t\t\tapiKey\n\t\t\t\t})\n\t\t\t);\n\t\t} else {\n\t\t\tengineCore.logInfo(\n\t\t\t\tI18n.formatMessage(\"node.existingTenantId\", {\n\t\t\t\t\tidentity: context.state.nodeTenantId\n\t\t\t\t})\n\t\t\t);\n\t\t}\n\n\t\tcontext.state.nodeTenantId = tenantId;\n\t\tcontext.stateDirty = true;\n\n\t\tengineCore.addContextId(ContextIdKeys.Tenant, context.state.nodeTenantId);\n\t}\n}\n\n/**\n * Bootstrap the user.\n * @param engineCore The engine core for the node.\n * @param context The context for the node.\n * @param envVars The environment variables for the node.\n * @param features The features that are enabled on the node.\n */\nexport async function bootstrapNodeAdminUser(\n\tengineCore: IEngineCore,\n\tcontext: IEngineCoreContext<IEngineServerConfig, INodeEngineState>,\n\tenvVars: INodeEnvironmentVariables,\n\tfeatures: NodeFeatures[]\n): Promise<void> {\n\tif (features.includes(NodeFeatures.NodeAdminUser)) {\n\t\tcontext.state.nodeOrganizationId =\n\t\t\tenvVars.organizationIdentity ?? context.state.nodeOrganizationId;\n\t\tcontext.state.nodeAdminUserId = envVars.adminUserIdentity ?? context.state.nodeAdminUserId;\n\n\t\tconst defaultAuthenticationComponentType =\n\t\t\tengineCore.getRegisteredInstanceType(\"authenticationComponent\");\n\t\tif (\n\t\t\tdefaultAuthenticationComponentType.startsWith(AuthenticationComponentType.EntityStorage) &&\n\t\t\tIs.stringValue(context.state.nodeId)\n\t\t) {\n\t\t\tconst authUserEntityStorage =\n\t\t\t\tEntityStorageConnectorFactory.get<IEntityStorageConnector<AuthenticationUser>>(\n\t\t\t\t\tnameofKebabCase<AuthenticationUser>()\n\t\t\t\t);\n\n\t\t\t// If we don't have an organization identity, create one\n\t\t\tif (!Is.stringValue(context.state.nodeOrganizationId)) {\n\t\t\t\tcontext.state.nodeOrganizationId = await createIdentity(\n\t\t\t\t\tengineCore,\n\t\t\t\t\tenvVars,\n\t\t\t\t\tcontext.state.nodeOrganizationId,\n\t\t\t\t\tenvVars.organizationMnemonic,\n\t\t\t\t\tcontext.state.nodeId,\n\t\t\t\t\t\"organization\",\n\t\t\t\t\tfeatures.includes(NodeFeatures.NodeWallet)\n\t\t\t\t);\n\t\t\t\tcontext.stateDirty = true;\n\t\t\t}\n\n\t\t\tif (!Is.stringValue(context.state.nodeAdminUserId)) {\n\t\t\t\tcontext.state.nodeAdminUserId = await createIdentity(\n\t\t\t\t\tengineCore,\n\t\t\t\t\tenvVars,\n\t\t\t\t\tcontext.state.nodeAdminUserId,\n\t\t\t\t\tenvVars.adminUserMnemonic,\n\t\t\t\t\tcontext.state.nodeOrganizationId,\n\t\t\t\t\t\"user\",\n\t\t\t\t\tfalse\n\t\t\t\t);\n\t\t\t\tcontext.stateDirty = true;\n\t\t\t}\n\n\t\t\tconst adminEmail = envVars.adminUserName ?? DEFAULT_NODE_ADMIN_USERNAME;\n\n\t\t\tlet nodeAdminUser = await authUserEntityStorage.get(adminEmail);\n\n\t\t\t// If the node admin user doesn't exist, create it\n\t\t\tif (Is.empty(nodeAdminUser)) {\n\t\t\t\tengineCore.logInfo(I18n.formatMessage(\"node.creatingUser\", { email: adminEmail }));\n\n\t\t\t\tconst generatedPassword = envVars.adminUserPassword ?? PasswordGenerator.generate(16);\n\t\t\t\tconst passwordBytes = Converter.utf8ToBytes(generatedPassword);\n\t\t\t\tconst saltBytes = RandomHelper.generate(16);\n\t\t\t\tconst hashedPassword = await PasswordHelper.hashPassword(passwordBytes, saltBytes);\n\n\t\t\t\tnodeAdminUser = {\n\t\t\t\t\temail: adminEmail,\n\t\t\t\t\tpassword: hashedPassword,\n\t\t\t\t\tsalt: Converter.bytesToBase64(saltBytes),\n\t\t\t\t\tidentity: context.state.nodeAdminUserId,\n\t\t\t\t\torganization: context.state.nodeOrganizationId\n\t\t\t\t};\n\n\t\t\t\tengineCore.logInfo(I18n.formatMessage(\"node.nodeAdminUserEmail\", { email: adminEmail }));\n\t\t\t\tengineCore.logInfo(\n\t\t\t\t\tI18n.formatMessage(\"node.nodeAdminUserPassword\", { password: generatedPassword })\n\t\t\t\t);\n\n\t\t\t\tawait authUserEntityStorage.set(nodeAdminUser);\n\t\t\t} else {\n\t\t\t\tengineCore.logInfo(I18n.formatMessage(\"node.existingUser\", { email: adminEmail }));\n\n\t\t\t\t// The user already exists, so double check the other details match\n\t\t\t\tlet needsUpdate = false;\n\n\t\t\t\tif (nodeAdminUser.identity !== context.state.nodeAdminUserId) {\n\t\t\t\t\tnodeAdminUser.identity = context.state.nodeAdminUserId;\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t}\n\n\t\t\t\tif (Is.stringValue(envVars.adminUserPassword)) {\n\t\t\t\t\tconst passwordBytes = Converter.utf8ToBytes(envVars.adminUserPassword);\n\t\t\t\t\tconst saltBytes = Converter.base64ToBytes(nodeAdminUser.salt);\n\t\t\t\t\tconst hashedPassword = await PasswordHelper.hashPassword(passwordBytes, saltBytes);\n\n\t\t\t\t\tif (nodeAdminUser.password !== hashedPassword) {\n\t\t\t\t\t\tnodeAdminUser.password = hashedPassword;\n\t\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (needsUpdate) {\n\t\t\t\t\tawait authUserEntityStorage.set(nodeAdminUser);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// We have create a node user, now we need to create a profile for the user\n\t\t\tconst defaultIdentityProfileConnectorType = engineCore.getRegisteredInstanceType(\n\t\t\t\t\"identityProfileConnector\"\n\t\t\t);\n\t\t\tconst identityProfileConnector = IdentityProfileConnectorFactory.get(\n\t\t\t\tdefaultIdentityProfileConnectorType\n\t\t\t);\n\n\t\t\tif (identityProfileConnector) {\n\t\t\t\t// Add the organization context id when creating the profile\n\t\t\t\t// so that it is partitioned under the organization\n\t\t\t\tconst contextIds = (await ContextIdStore.getContextIds()) ?? {};\n\t\t\t\tcontextIds[ContextIdKeys.Organization] = context.state.nodeOrganizationId;\n\t\t\t\tawait ContextIdStore.run(contextIds, async () => {\n\t\t\t\t\tlet userProfile;\n\t\t\t\t\tif (Is.stringValue(nodeAdminUser.identity)) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tuserProfile = await identityProfileConnector.get(nodeAdminUser.identity);\n\t\t\t\t\t\t} catch {}\n\t\t\t\t\t}\n\t\t\t\t\tif (Is.empty(userProfile)) {\n\t\t\t\t\t\tengineCore.logInfo(\n\t\t\t\t\t\t\tI18n.formatMessage(\"node.creatingUserProfile\", {\n\t\t\t\t\t\t\t\tidentity: nodeAdminUser.identity\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst publicProfile: WithContext<Person> = {\n\t\t\t\t\t\t\t\"@context\": \"https://schema.org\",\n\t\t\t\t\t\t\t\"@type\": \"Person\",\n\t\t\t\t\t\t\tname: \"Node Administrator\"\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst privateProfile: WithContext<Person> = {\n\t\t\t\t\t\t\t\"@context\": \"https://schema.org\",\n\t\t\t\t\t\t\t\"@type\": \"Person\",\n\t\t\t\t\t\t\tgivenName: \"Node\",\n\t\t\t\t\t\t\tfamilyName: \"Administrator\",\n\t\t\t\t\t\t\temail: adminEmail\n\t\t\t\t\t\t};\n\t\t\t\t\t\tawait identityProfileConnector.create(\n\t\t\t\t\t\t\tnodeAdminUser.identity,\n\t\t\t\t\t\t\tpublicProfile,\n\t\t\t\t\t\t\tprivateProfile\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tengineCore.logInfo(\n\t\t\t\t\t\t\tI18n.formatMessage(\"node.existingUserProfile\", {\n\t\t\t\t\t\t\t\tidentity: nodeAdminUser.identity\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Bootstrap the immutable proof verification methods.\n * @param engineCore The engine core for the node.\n * @param context The context for the node.\n * @param envVars The environment variables for the node.\n * @param features The features that are enabled on the node.\n */\nexport async function bootstrapImmutableProofMethod(\n\tengineCore: IEngineCore,\n\tcontext: IEngineCoreContext<IEngineServerConfig, INodeEngineState>,\n\tenvVars: INodeEnvironmentVariables,\n\tfeatures: NodeFeatures[]\n): Promise<void> {}\n\n/**\n * Bootstrap the keys for blob encryption.\n * @param engineCore The engine core for the node.\n * @param context The context for the node.\n * @param envVars The environment variables for the node.\n * @param features The features that are enabled on the node.\n */\nexport async function bootstrapBlobEncryption(\n\tengineCore: IEngineCore,\n\tcontext: IEngineCoreContext<IEngineServerConfig, INodeEngineState>,\n\tenvVars: INodeEnvironmentVariables,\n\tfeatures: NodeFeatures[]\n): Promise<void> {\n\tif (\n\t\t(Coerce.boolean(envVars.blobStorageEnableEncryption) ?? false) &&\n\t\tIs.stringValue(context.state.nodeOrganizationId)\n\t) {\n\t\t// Create a new key for encrypting blobs\n\t\tconst defaultVaultConnectorType = engineCore.getRegisteredInstanceType(\"vaultConnector\");\n\t\tconst vaultConnector = VaultConnectorFactory.get(defaultVaultConnectorType);\n\n\t\tconst keyName = `${context.state.nodeOrganizationId}/${envVars.blobStorageEncryptionKeyId ?? BLOB_STORAGE_ENCRYPTION_KEY_ID}`;\n\n\t\tlet existingKey;\n\n\t\ttry {\n\t\t\texistingKey = await vaultConnector.getKey(keyName);\n\t\t} catch {}\n\n\t\tif (Is.empty(existingKey)) {\n\t\t\tif (Is.stringBase64(envVars.blobStorageSymmetricEncryptionKey)) {\n\t\t\t\tengineCore.logInfo(I18n.formatMessage(\"node.addingBlobEncryptionKey\", { keyName }));\n\t\t\t\tawait vaultConnector.addKey(\n\t\t\t\t\tkeyName,\n\t\t\t\t\tVaultKeyType.ChaCha20Poly1305,\n\t\t\t\t\tConverter.base64ToBytes(envVars.blobStorageSymmetricEncryptionKey)\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tengineCore.logInfo(I18n.formatMessage(\"node.creatingBlobEncryptionKey\", { keyName }));\n\t\t\t\tconst key = await vaultConnector.createKey(keyName, VaultKeyType.ChaCha20Poly1305);\n\t\t\t\tengineCore.logInfo(\n\t\t\t\t\tI18n.formatMessage(\"node.createdBlobEncryptionKey\", {\n\t\t\t\t\t\tkeyName,\n\t\t\t\t\t\tkeyValue: Converter.bytesToBase64(key)\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tengineCore.logInfo(I18n.formatMessage(\"node.existingBlobEncryptionKey\", { keyName }));\n\t\t}\n\t}\n}\n\n/**\n * Bootstrap the JWT signing key.\n * @param engineCore The engine core for the node.\n * @param context The context for the node.\n * @param envVars The environment variables for the node.\n * @param features The features that are enabled on the node.\n */\nexport async function bootstrapAuth(\n\tengineCore: IEngineCore,\n\tcontext: IEngineCoreContext<IEngineServerConfig, INodeEngineState>,\n\tenvVars: INodeEnvironmentVariables,\n\tfeatures: NodeFeatures[]\n): Promise<void> {\n\tconst defaultAuthenticationComponentType =\n\t\tengineCore.getRegisteredInstanceTypeOptional(\"authenticationComponent\");\n\tif (\n\t\tIs.stringValue(defaultAuthenticationComponentType) &&\n\t\tdefaultAuthenticationComponentType.startsWith(AuthenticationComponentType.EntityStorage) &&\n\t\tIs.stringValue(context.state.nodeId)\n\t) {\n\t\t// Create a new JWT signing key and a user login for the node\n\t\tconst defaultVaultConnectorType = engineCore.getRegisteredInstanceType(\"vaultConnector\");\n\t\tconst vaultConnector = VaultConnectorFactory.get(defaultVaultConnectorType);\n\n\t\tconst keyName = `${context.state.nodeId}/${envVars.authSigningKeyId ?? AUTH_SIGNING_KEY_ID}`;\n\n\t\tlet existingKey;\n\t\ttry {\n\t\t\texistingKey = await vaultConnector.getKey(keyName);\n\t\t} catch {}\n\n\t\tif (Is.empty(existingKey)) {\n\t\t\tengineCore.logInfo(I18n.formatMessage(\"node.creatingAuthKey\", { keyName }));\n\t\t\tawait vaultConnector.createKey(keyName, VaultKeyType.Ed25519);\n\t\t} else {\n\t\t\tengineCore.logInfo(I18n.formatMessage(\"node.existingAuthKey\", { keyName }));\n\t\t}\n\t}\n}\n\n/**\n * Bootstrap the synchronised storage blob encryption and verification methods.\n * @param engineCore The engine core for the node.\n * @param context The context for the node.\n * @param envVars The environment variables for the node.\n * @param features The features that are enabled on the node.\n */\nexport async function bootstrapSynchronisedStorage(\n\tengineCore: IEngineCore,\n\tcontext: IEngineCoreContext<IEngineServerConfig, INodeEngineState>,\n\tenvVars: INodeEnvironmentVariables,\n\tfeatures: NodeFeatures[]\n): Promise<void> {\n\tif (Coerce.boolean(envVars.synchronisedStorageEnabled) ?? false) {\n\t\t// If this is a trusted node we need to add the blob encryption key pair\n\t\tif (Is.stringBase64(envVars.synchronisedStorageBlobStorageKey)) {\n\t\t\tconst defaultVaultConnectorType = engineCore.getRegisteredInstanceType(\"vaultConnector\");\n\t\t\tconst vaultConnector = VaultConnectorFactory.get(defaultVaultConnectorType);\n\n\t\t\tconst keyName =\n\t\t\t\tenvVars.synchronisedStorageBlobStorageEncryptionKeyId ??\n\t\t\t\tSYNCHRONISED_STORAGE_BLOB_STORAGE_ENCRYPTION_KEY_ID;\n\t\t\tlet existingKey;\n\n\t\t\ttry {\n\t\t\t\texistingKey = await vaultConnector.getKey(keyName);\n\t\t\t} catch {}\n\n\t\t\tif (Is.empty(existingKey)) {\n\t\t\t\tengineCore.logInfo(\n\t\t\t\t\tI18n.formatMessage(\"node.addingSynchronisedStorageBlobEncryptionKey\", { keyName })\n\t\t\t\t);\n\t\t\t\tawait vaultConnector.addKey(\n\t\t\t\t\tkeyName,\n\t\t\t\t\tVaultKeyType.ChaCha20Poly1305,\n\t\t\t\t\tConverter.base64ToBytes(envVars.synchronisedStorageBlobStorageKey)\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tengineCore.logInfo(\n\t\t\t\t\tI18n.formatMessage(\"node.existingSynchronisedStorageBlobEncryptionKey\", { keyName })\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Add a verification method if it doesn't exist.\n * @param engineCore The engine core for the node.\n * @param context The context for the node.\n * @param identity The identity to add the verification method to.\n * @param verificationMethodTitle The verification method title.\n * @param verificationMethodId The verification method ID.\n */\nasync function addVerificationMethod(\n\tengineCore: IEngineCore,\n\tcontext: IEngineCoreContext<IEngineServerConfig, INodeEngineState>,\n\tidentity: string,\n\tverificationMethodTitle: string,\n\tverificationMethodId: string | undefined\n): Promise<void> {\n\tif (\n\t\tIs.stringValue(identity) &&\n\t\tIs.arrayValue(context.config.types.identityConnector) &&\n\t\tIs.stringValue(verificationMethodId)\n\t) {\n\t\tconst defaultIdentityConnectorType = engineCore.getRegisteredInstanceType(\"identityConnector\");\n\t\tconst identityConnector = IdentityConnectorFactory.get(defaultIdentityConnectorType);\n\n\t\tconst defaultIdentityResolverConnectorType = engineCore.getRegisteredInstanceType(\n\t\t\t\"identityResolverConnector\"\n\t\t);\n\t\tconst identityResolverConnector = IdentityResolverConnectorFactory.get(\n\t\t\tdefaultIdentityResolverConnectorType\n\t\t);\n\n\t\tconst identityDocument = await identityResolverConnector.resolveDocument(identity);\n\n\t\tconst fullMethodId = `${identityDocument.id}#${verificationMethodId}`;\n\n\t\tlet exists = false;\n\t\ttry {\n\t\t\tDocumentHelper.getVerificationMethod(identityDocument, fullMethodId, \"assertionMethod\");\n\t\t\texists = true;\n\t\t} catch {}\n\n\t\tif (!exists) {\n\t\t\tengineCore.logInfo(\n\t\t\t\tI18n.formatMessage(\"node.addingVerificationMethod\", {\n\t\t\t\t\ttitle: verificationMethodTitle,\n\t\t\t\t\tmethodId: fullMethodId\n\t\t\t\t})\n\t\t\t);\n\t\t\tawait identityConnector.addVerificationMethod(\n\t\t\t\tidentity,\n\t\t\t\tidentity,\n\t\t\t\t\"assertionMethod\",\n\t\t\t\tverificationMethodId\n\t\t\t);\n\t\t} else {\n\t\t\tengineCore.logInfo(\n\t\t\t\tI18n.formatMessage(\"node.existingVerificationMethod\", {\n\t\t\t\t\ttitle: verificationMethodTitle,\n\t\t\t\t\tmethodId: fullMethodId\n\t\t\t\t})\n\t\t\t);\n\t\t}\n\t}\n}\n"]}