@twin.org/node-core 0.0.2-next.8 → 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.
- package/README.md +1 -1
- package/dist/es/bootstrap.js +374 -0
- package/dist/es/bootstrap.js.map +1 -0
- package/dist/es/builders/engineEnvBuilder.js +1051 -0
- package/dist/es/builders/engineEnvBuilder.js.map +1 -0
- package/dist/es/builders/engineServerEnvBuilder.js +197 -0
- package/dist/es/builders/engineServerEnvBuilder.js.map +1 -0
- package/dist/es/builders/extensionsBuilder.js +100 -0
- package/dist/es/builders/extensionsBuilder.js.map +1 -0
- package/dist/es/defaults.js +9 -0
- package/dist/es/defaults.js.map +1 -0
- package/dist/es/identity.js +169 -0
- package/dist/es/identity.js.map +1 -0
- package/dist/es/index.js +23 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/models/ICacheMetadata.js +4 -0
- package/dist/es/models/ICacheMetadata.js.map +1 -0
- package/dist/es/models/IEngineEnvironmentVariables.js +4 -0
- package/dist/es/models/IEngineEnvironmentVariables.js.map +1 -0
- package/dist/es/models/IEngineServerEnvironmentVariables.js +2 -0
- package/dist/es/models/IEngineServerEnvironmentVariables.js.map +1 -0
- package/dist/es/models/IModuleProtocol.js +2 -0
- package/dist/es/models/IModuleProtocol.js.map +1 -0
- package/dist/es/models/INodeEngineConfig.js +2 -0
- package/dist/es/models/INodeEngineConfig.js.map +1 -0
- package/dist/es/models/INodeEngineState.js +2 -0
- package/dist/es/models/INodeEngineState.js.map +1 -0
- package/dist/es/models/INodeEnvironmentVariables.js +2 -0
- package/dist/es/models/INodeEnvironmentVariables.js.map +1 -0
- package/dist/es/models/INodeOptions.js +2 -0
- package/dist/es/models/INodeOptions.js.map +1 -0
- package/dist/es/models/IProtocolHandlerResult.js +4 -0
- package/dist/es/models/IProtocolHandlerResult.js.map +1 -0
- package/dist/es/models/moduleProtocol.js +29 -0
- package/dist/es/models/moduleProtocol.js.map +1 -0
- package/dist/es/models/nodeExtensionMethods.js +2 -0
- package/dist/es/models/nodeExtensionMethods.js.map +1 -0
- package/dist/es/models/nodeFeatures.js +21 -0
- package/dist/es/models/nodeFeatures.js.map +1 -0
- package/dist/es/node.js +265 -0
- package/dist/es/node.js.map +1 -0
- package/dist/es/server.js +74 -0
- package/dist/es/server.js.map +1 -0
- package/dist/es/utils.js +418 -0
- package/dist/es/utils.js.map +1 -0
- package/dist/types/bootstrap.d.ts +27 -10
- package/dist/types/builders/engineEnvBuilder.d.ts +3 -2
- package/dist/types/builders/engineServerEnvBuilder.d.ts +4 -3
- package/dist/types/builders/extensionsBuilder.d.ts +32 -0
- package/dist/types/defaults.d.ts +6 -0
- package/dist/types/identity.d.ts +14 -0
- package/dist/types/index.d.ts +20 -11
- package/dist/types/models/ICacheMetadata.d.ts +17 -0
- package/dist/types/models/IEngineEnvironmentVariables.d.ts +132 -24
- package/dist/types/models/IEngineServerEnvironmentVariables.d.ts +12 -3
- package/dist/types/models/IModuleProtocol.d.ts +18 -0
- package/dist/types/models/INodeEngineConfig.d.ts +6 -0
- package/dist/types/models/INodeEngineState.d.ts +22 -0
- package/dist/types/models/INodeEnvironmentVariables.d.ts +50 -10
- package/dist/types/models/INodeOptions.d.ts +14 -3
- package/dist/types/models/IProtocolHandlerResult.d.ts +13 -0
- package/dist/types/models/moduleProtocol.d.ts +29 -0
- package/dist/types/models/nodeExtensionMethods.d.ts +27 -0
- package/dist/types/models/nodeFeatures.d.ts +5 -5
- package/dist/types/node.d.ts +17 -7
- package/dist/types/server.d.ts +9 -6
- package/dist/types/utils.d.ts +87 -2
- package/docs/changelog.md +185 -0
- package/docs/detailed-guide.md +129 -0
- package/docs/reference/functions/bootstrap.md +1 -1
- package/docs/reference/functions/bootstrapAuth.md +1 -1
- package/docs/reference/functions/bootstrapBlobEncryption.md +1 -1
- package/docs/reference/functions/bootstrapContextIdHandlers.md +35 -0
- package/docs/reference/functions/bootstrapImmutableProofMethod.md +1 -1
- package/docs/reference/functions/{bootstrapNodeUser.md → bootstrapNodeAdminUser.md} +3 -3
- package/docs/reference/functions/{bootstrapNodeIdentity.md → bootstrapNodeId.md} +3 -3
- package/docs/reference/functions/bootstrapSynchronisedStorage.md +1 -1
- package/docs/reference/functions/bootstrapTenantId.md +35 -0
- package/docs/reference/functions/buildConfiguration.md +2 -2
- package/docs/reference/functions/buildEngineConfiguration.md +8 -2
- package/docs/reference/functions/buildEngineServerConfiguration.md +9 -3
- package/docs/reference/functions/createModuleImportUrl.md +21 -0
- package/docs/reference/functions/directoryExists.md +19 -0
- package/docs/reference/functions/extensionsConfiguration.md +25 -0
- package/docs/reference/functions/extensionsInitialiseEngine.md +25 -0
- package/docs/reference/functions/extensionsInitialiseEngineServer.md +31 -0
- package/docs/reference/functions/getExtensionsCacheDir.md +31 -0
- package/docs/reference/functions/getFiles.md +19 -0
- package/docs/reference/functions/getSubFolders.md +19 -0
- package/docs/reference/functions/handleHttpsProtocol.md +49 -0
- package/docs/reference/functions/handleNpmProtocol.md +31 -0
- package/docs/reference/functions/hashUrl.md +19 -0
- package/docs/reference/functions/isCacheExpired.md +31 -0
- package/docs/reference/functions/overrideModuleImport.md +8 -2
- package/docs/reference/functions/parseModuleProtocol.md +19 -0
- package/docs/reference/functions/resolvePackageEntryPoint.md +32 -0
- package/docs/reference/functions/run.md +3 -3
- package/docs/reference/functions/shutdownExtensions.md +25 -0
- package/docs/reference/functions/start.md +11 -5
- package/docs/reference/index.md +36 -2
- package/docs/reference/interfaces/ICacheMetadata.md +27 -0
- package/docs/reference/interfaces/IEngineEnvironmentVariables.md +255 -37
- package/docs/reference/interfaces/IEngineServerEnvironmentVariables.md +1696 -5
- package/docs/reference/interfaces/IModuleProtocol.md +27 -0
- package/docs/reference/interfaces/INodeEngineConfig.md +7 -0
- package/docs/reference/interfaces/INodeEngineState.md +39 -0
- package/docs/reference/interfaces/INodeEnvironmentVariables.md +609 -165
- package/docs/reference/interfaces/INodeOptions.md +27 -3
- package/docs/reference/interfaces/IProtocolHandlerResult.md +19 -0
- package/docs/reference/type-aliases/ModuleProtocol.md +5 -0
- package/docs/reference/type-aliases/NodeExtensionInitialiseEngineMethod.md +18 -0
- package/docs/reference/type-aliases/NodeExtensionInitialiseEngineServerMethod.md +24 -0
- package/docs/reference/type-aliases/NodeExtensionInitialiseMethod.md +23 -0
- package/docs/reference/type-aliases/NodeExtensionShutdownMethod.md +10 -0
- package/docs/reference/variables/ATTESTATION_VERIFICATION_METHOD_ID.md +3 -0
- package/docs/reference/variables/AUTH_SIGNING_KEY_ID.md +3 -0
- package/docs/reference/variables/BLOB_STORAGE_ENCRYPTION_KEY_ID.md +3 -0
- package/docs/reference/variables/IMMUTABLE_PROOF_VERIFICATION_METHOD_ID.md +3 -0
- package/docs/reference/variables/ModuleProtocol.md +37 -0
- package/docs/reference/variables/NodeFeatures.md +8 -8
- package/docs/reference/variables/SYNCHRONISED_STORAGE_BLOB_STORAGE_ENCRYPTION_KEY_ID.md +3 -0
- package/docs/reference/variables/VC_AUTHENTICATION_VERIFICATION_METHOD_ID.md +3 -0
- package/locales/en.json +27 -9
- package/package.json +27 -9
- package/dist/cjs/index.cjs +0 -1910
- package/dist/esm/index.mjs +0 -1870
package/README.md
CHANGED
|
@@ -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"]}
|