dbgate-api-premium 5.5.7-alpha.45

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 (125) hide show
  1. package/.env +19 -0
  2. package/.yarnrc +2 -0
  3. package/README.md +1 -0
  4. package/env/dblogin/.env +14 -0
  5. package/env/portal/.env +70 -0
  6. package/env/singledb/.env +17 -0
  7. package/env/storage/.env +43 -0
  8. package/package.json +89 -0
  9. package/src/auth/authCommon.js +16 -0
  10. package/src/auth/authProvider.js +343 -0
  11. package/src/auth/storageAuthProvider.js +393 -0
  12. package/src/controllers/apps.js +280 -0
  13. package/src/controllers/archive.js +217 -0
  14. package/src/controllers/auth.js +136 -0
  15. package/src/controllers/config.js +271 -0
  16. package/src/controllers/connections.js +486 -0
  17. package/src/controllers/databaseConnections.js +561 -0
  18. package/src/controllers/files.js +222 -0
  19. package/src/controllers/jsldata.js +296 -0
  20. package/src/controllers/metadata.js +47 -0
  21. package/src/controllers/plugins.js +216 -0
  22. package/src/controllers/queryHistory.js +54 -0
  23. package/src/controllers/runners.js +234 -0
  24. package/src/controllers/scheduler.js +46 -0
  25. package/src/controllers/serverConnections.js +271 -0
  26. package/src/controllers/sessions.js +243 -0
  27. package/src/controllers/storage.js +380 -0
  28. package/src/controllers/storageDb.js +215 -0
  29. package/src/controllers/uploads.js +133 -0
  30. package/src/currentVersion.js +5 -0
  31. package/src/gistSecret.js +2 -0
  32. package/src/index.js +139 -0
  33. package/src/main.js +202 -0
  34. package/src/packagedPluginsContent.js +1 -0
  35. package/src/proc/connectProcess.js +38 -0
  36. package/src/proc/databaseConnectionProcess.js +431 -0
  37. package/src/proc/index.js +15 -0
  38. package/src/proc/jslDatastoreProcess.js +60 -0
  39. package/src/proc/serverConnectionProcess.js +188 -0
  40. package/src/proc/sessionProcess.js +390 -0
  41. package/src/proc/sshForwardProcess.js +75 -0
  42. package/src/shell/archiveReader.js +11 -0
  43. package/src/shell/archiveWriter.js +22 -0
  44. package/src/shell/autoIndexForeignKeysTransform.js +19 -0
  45. package/src/shell/collectorWriter.js +33 -0
  46. package/src/shell/consoleObjectWriter.js +16 -0
  47. package/src/shell/copyStream.js +48 -0
  48. package/src/shell/dataDuplicator.js +63 -0
  49. package/src/shell/dataTypeMapperTransform.js +21 -0
  50. package/src/shell/dbModelToJson.js +16 -0
  51. package/src/shell/deployDb.js +56 -0
  52. package/src/shell/download.js +15 -0
  53. package/src/shell/dropAllDbObjects.js +42 -0
  54. package/src/shell/dumpDatabase.js +49 -0
  55. package/src/shell/executeQuery.js +39 -0
  56. package/src/shell/fakeObjectReader.js +35 -0
  57. package/src/shell/finalizer.js +12 -0
  58. package/src/shell/generateDeploySql.js +95 -0
  59. package/src/shell/generateModelSql.js +30 -0
  60. package/src/shell/importDatabase.js +85 -0
  61. package/src/shell/index.js +80 -0
  62. package/src/shell/initializeApiEnvironment.js +9 -0
  63. package/src/shell/jslDataReader.js +9 -0
  64. package/src/shell/jsonLinesReader.js +52 -0
  65. package/src/shell/jsonLinesWriter.js +36 -0
  66. package/src/shell/jsonReader.js +84 -0
  67. package/src/shell/jsonToDbModel.js +9 -0
  68. package/src/shell/jsonWriter.js +97 -0
  69. package/src/shell/loadDatabase.js +27 -0
  70. package/src/shell/loadFile.js +10 -0
  71. package/src/shell/modifyJsonLinesReader.js +148 -0
  72. package/src/shell/queryReader.js +30 -0
  73. package/src/shell/registerPlugins.js +9 -0
  74. package/src/shell/requirePlugin.js +43 -0
  75. package/src/shell/runScript.js +19 -0
  76. package/src/shell/sqlDataWriter.js +52 -0
  77. package/src/shell/sqlTextReplacementTransform.js +32 -0
  78. package/src/shell/tableReader.js +39 -0
  79. package/src/shell/tableWriter.js +18 -0
  80. package/src/storageModel.js +819 -0
  81. package/src/utility/ColumnMapTransformStream.js +21 -0
  82. package/src/utility/DatastoreProxy.js +106 -0
  83. package/src/utility/EnsureStreamHeaderStream.js +31 -0
  84. package/src/utility/JsonLinesDatabase.js +148 -0
  85. package/src/utility/JsonLinesDatastore.js +232 -0
  86. package/src/utility/LineReader.js +88 -0
  87. package/src/utility/SSHConnection.js +251 -0
  88. package/src/utility/authProxy.js +133 -0
  89. package/src/utility/checkLicense.js +186 -0
  90. package/src/utility/childProcessChecker.js +21 -0
  91. package/src/utility/cleanDirectory.js +24 -0
  92. package/src/utility/cloudUpgrade.js +61 -0
  93. package/src/utility/connectUtility.js +111 -0
  94. package/src/utility/crypting.js +105 -0
  95. package/src/utility/diff2htmlPage.js +8 -0
  96. package/src/utility/directories.js +179 -0
  97. package/src/utility/downloadPackage.js +51 -0
  98. package/src/utility/downloader.js +25 -0
  99. package/src/utility/exceptions.js +9 -0
  100. package/src/utility/exportDbModel.js +31 -0
  101. package/src/utility/exportDbModelSql.js +80 -0
  102. package/src/utility/getChartExport.js +55 -0
  103. package/src/utility/getDiagramExport.js +25 -0
  104. package/src/utility/getExpressPath.js +10 -0
  105. package/src/utility/getJslFileName.js +16 -0
  106. package/src/utility/getMapExport.js +77 -0
  107. package/src/utility/hardwareFingerprint.js +89 -0
  108. package/src/utility/hasPermission.js +101 -0
  109. package/src/utility/importDbModel.js +9 -0
  110. package/src/utility/loadFilesRecursive.js +20 -0
  111. package/src/utility/loadModelFolder.js +29 -0
  112. package/src/utility/loadModelTransform.js +36 -0
  113. package/src/utility/pipeForkLogs.js +19 -0
  114. package/src/utility/platformInfo.js +62 -0
  115. package/src/utility/processArgs.js +39 -0
  116. package/src/utility/processComm.js +18 -0
  117. package/src/utility/requireEngineDriver.js +26 -0
  118. package/src/utility/requirePluginFunction.js +16 -0
  119. package/src/utility/socket.js +68 -0
  120. package/src/utility/sshTunnel.js +106 -0
  121. package/src/utility/sshTunnelProxy.js +36 -0
  122. package/src/utility/timingSafeCheckToken.js +9 -0
  123. package/src/utility/useController.js +99 -0
  124. package/tsconfig.json +13 -0
  125. package/webpack.config.js +55 -0
@@ -0,0 +1,380 @@
1
+ const fs = require('fs-extra');
2
+ const _ = require('lodash');
3
+ const { setAuthProviders, getAuthProviderById } = require('../auth/authProvider');
4
+ const { createStorageAuthProvider } = require('../auth/storageAuthProvider');
5
+ const {
6
+ getStorageConnection,
7
+ getDbConnectionParams,
8
+ storageSelectFmt,
9
+ storageReadUserRolePermissions,
10
+ loadSuperadminPermissions,
11
+ storageReadConfig,
12
+ storageWriteConfig,
13
+ getStorageConnectionError,
14
+ } = require('./storageDb');
15
+ const { hasPermission } = require('../utility/hasPermission');
16
+ const { changeSetToSql, removeSchemaFromChangeSet } = require('dbgate-datalib');
17
+ const storageModel = require('../storageModel');
18
+ const { dumpSqlCommand } = require('dbgate-sqltree');
19
+ const { runCommandOnDriver } = require('dbgate-tools');
20
+ const socket = require('../utility/socket');
21
+
22
+ function mapConnection(connnection) {
23
+ return {
24
+ ...connnection,
25
+ _id: connnection.conid,
26
+ };
27
+ }
28
+
29
+ async function runQueryFmt(driver, conn, query, ...args) {
30
+ const dmp = driver.createDumper();
31
+ dmp.put(query, ...args);
32
+ await driver.query(conn, dmp.s);
33
+ }
34
+
35
+ module.exports = {
36
+ async _init() {
37
+ if (!process.env.STORAGE_DATABASE) {
38
+ return;
39
+ }
40
+ const authConfigs = await this.readAuthConfig();
41
+ const enabledConfig = authConfigs.filter(x => !x.isDisabled);
42
+ const providers = enabledConfig.map(cfg => createStorageAuthProvider(cfg));
43
+ let defIndex = enabledConfig.findIndex(x => x.isDefault);
44
+ if (defIndex < 0) {
45
+ defIndex = enabledConfig.findIndex(x => x.type == 'local');
46
+ }
47
+
48
+ setAuthProviders(providers, providers[defIndex]);
49
+ },
50
+
51
+ connections_meta: true,
52
+ async connections(req) {
53
+ if (!process.env.STORAGE_DATABASE) {
54
+ return null;
55
+ }
56
+
57
+ const userId = req?.user?.userId;
58
+ const roleId = req?.user?.roleId;
59
+
60
+ let resp = null;
61
+
62
+ if (hasPermission('all-connections', req)) {
63
+ resp = await storageSelectFmt(`select ~connections.* from ~connections`);
64
+ } else if (userId) {
65
+ resp = await storageSelectFmt(
66
+ `select ~connections.* from ~connections
67
+ where exists (
68
+ select * from ~user_connections where ~user_connections.~connection_id = ~connections.~id and ~user_connections.~user_id = %v
69
+ ) or exists (
70
+ select * from ~role_connections
71
+ inner join ~user_roles on ~role_connections.~role_id = ~user_roles.~role_id
72
+ where ~role_connections.~connection_id = ~connections.~id and ~user_roles.~user_id = %v
73
+ ) or exists (
74
+ select * from ~role_connections
75
+ where ~role_connections.~connection_id = ~connections.~id and ~role_connections.~role_id = -2
76
+ )
77
+ `,
78
+ userId,
79
+ userId
80
+ );
81
+ } else {
82
+ resp = await storageSelectFmt(
83
+ `select distinct ~connections.* from ~connections
84
+ inner join ~role_connections on ~connections.~id = ~role_connections.~connection_id
85
+ where ~role_connections.~role_id = %v`,
86
+ roleId ?? -1
87
+ );
88
+ }
89
+
90
+ if (!resp) {
91
+ return [];
92
+ }
93
+ const res = [];
94
+ if (hasPermission('internal-storage', req)) {
95
+ res.push(await this.getConnection({ conid: '__storage' }));
96
+ }
97
+ if (resp) {
98
+ res.push(...resp.map(x => mapConnection(x)));
99
+ }
100
+ return res;
101
+ },
102
+
103
+ async getConnection({ conid }) {
104
+ if (conid == '__storage') {
105
+ return {
106
+ _id: '__storage',
107
+ displayName: 'Internal storage',
108
+ defaultDatabase: process.env.STORAGE_DATABASE,
109
+ singleDatabase: true,
110
+ ...getDbConnectionParams(),
111
+ };
112
+ }
113
+
114
+ const [conn, driver] = await getStorageConnection();
115
+ if (!conn) {
116
+ return null;
117
+ }
118
+
119
+ const resp = await storageSelectFmt('select * from ~connections where ~conid = %v', conid);
120
+ return mapConnection(resp[0]);
121
+ },
122
+
123
+ readConfig_meta: true,
124
+ async readConfig({ group }) {
125
+ return await storageReadConfig(group);
126
+ },
127
+
128
+ readAuthConfig_meta: true,
129
+ async readAuthConfig() {
130
+ const authMethodsResp = await storageSelectFmt('select * from ~auth_methods');
131
+ const authMethodsConfig = await storageSelectFmt('select * from ~auth_methods_config');
132
+ const authMethods = authMethodsResp.map(x => {
133
+ const config = _.fromPairs(authMethodsConfig.filter(y => y.auth_method_id == x.id).map(y => [y.key, y.value]));
134
+ return {
135
+ ...config,
136
+ name: x.name,
137
+ type: x.type,
138
+ amoid: x.amoid,
139
+ isDisabled: x.is_disabled,
140
+ isDefault: x.is_default,
141
+ isCollapsed: x.is_collapsed,
142
+ id: x.id,
143
+ };
144
+ });
145
+ return authMethods;
146
+ },
147
+
148
+ writeAuthConfig_meta: true,
149
+ async writeAuthConfig({ authMethods }) {
150
+ const [conn, driver] = await getStorageConnection();
151
+ if (!conn) {
152
+ return null;
153
+ }
154
+
155
+ await runQueryFmt(driver, conn, 'delete from auth_methods_config');
156
+ await runQueryFmt(driver, conn, 'delete from auth_methods where id > 0');
157
+
158
+ let id = 1;
159
+ for (const method of authMethods) {
160
+ if (method.id < 0) {
161
+ await runQueryFmt(
162
+ driver,
163
+ conn,
164
+ 'update auth_methods set is_disabled=%v, is_default = %v, is_collapsed = %v where id = %v',
165
+ method.isDisabled,
166
+ method.isDefault,
167
+ method.isCollapsed,
168
+ method.id
169
+ );
170
+ } else {
171
+ await runQueryFmt(
172
+ driver,
173
+ conn,
174
+ 'insert into auth_methods (%i, %i, %i, %i, %i, %i, %i) values (%v, %v, %v, %v, %v, %v, %v)',
175
+ 'id',
176
+ 'name',
177
+ 'type',
178
+ 'is_disabled',
179
+ 'is_default',
180
+ 'is_collapsed',
181
+ 'amoid',
182
+ id,
183
+ method.name,
184
+ method.type,
185
+ method.isDisabled ? 1 : 0,
186
+ method.isDefault ? 1 : 0,
187
+ method.isCollapsed ? 1 : 0,
188
+ method.amoid
189
+ );
190
+ }
191
+
192
+ for (const key in method) {
193
+ if (['id', 'name', 'type', 'isDisabled', 'isDefault', 'isCollapsed', 'amoid'].includes(key)) {
194
+ continue;
195
+ }
196
+ await runQueryFmt(
197
+ driver,
198
+ conn,
199
+ 'insert into auth_methods_config (%i, %i, %i) values (%v, %v, %v)',
200
+ 'auth_method_id',
201
+ 'key',
202
+ 'value',
203
+ method.id < 0 ? method.id : id,
204
+ key,
205
+ method[key]
206
+ );
207
+ }
208
+
209
+ if (!(method.id < 0)) {
210
+ id += 1;
211
+ }
212
+ }
213
+
214
+ await this._init();
215
+
216
+ return true;
217
+ },
218
+
219
+ writeConfig_meta: true,
220
+ async writeConfig({ group, config }) {
221
+ await storageWriteConfig(group, config);
222
+ await this._init();
223
+ return null;
224
+ },
225
+
226
+ readPermissions_meta: true,
227
+ async readPermissions({ tableName, filterColumn, filterValue }) {
228
+ const resp = Array.isArray(filterValue)
229
+ ? await storageSelectFmt('select * from %i where %i in (%,v)', tableName, filterColumn, filterValue)
230
+ : await storageSelectFmt('select * from %i where %i = %v', tableName, filterColumn, filterValue);
231
+ if (!resp) {
232
+ return null;
233
+ }
234
+ return resp.map(x => x.permission);
235
+ },
236
+
237
+ writePermissions_meta: true,
238
+ async writePermissions({ tableName, filterColumn, filterValue, permissions }) {
239
+ const [conn, driver] = await getStorageConnection();
240
+ if (!conn) {
241
+ return null;
242
+ }
243
+
244
+ await runQueryFmt(driver, conn, 'delete from %i where %i = %v', tableName, filterColumn, filterValue);
245
+
246
+ for (const perm of permissions) {
247
+ await runQueryFmt(
248
+ driver,
249
+ conn,
250
+ 'insert into %i (%i, %i) values (%v, %v)',
251
+ tableName,
252
+ filterColumn,
253
+ 'permission',
254
+ filterValue,
255
+ perm
256
+ );
257
+ }
258
+
259
+ return null;
260
+ },
261
+
262
+ readUserRolePermissions_meta: true,
263
+ async readUserRolePermissions({ userId }) {
264
+ return storageReadUserRolePermissions(userId);
265
+ },
266
+
267
+ async loadSuperadminPermissions() {
268
+ return loadSuperadminPermissions();
269
+ },
270
+
271
+ getConnectionsForLoginPage_meta: true,
272
+ getConnectionsForLoginPage({ amoid }) {
273
+ return getAuthProviderById(amoid).getLoginPageConnections();
274
+ },
275
+
276
+ saveAdminData_meta: true,
277
+ async saveAdminData({ changeSet, fireEvents }) {
278
+ const [conn, driver] = await getStorageConnection();
279
+ if (!conn) {
280
+ return null;
281
+ }
282
+
283
+ try {
284
+ runCommandOnDriver(conn, driver, dmp => dmp.beginTransaction());
285
+ const script = changeSetToSql(
286
+ // storage model is without schema
287
+ removeSchemaFromChangeSet(changeSet),
288
+ // @ts-ignore
289
+ storageModel
290
+ );
291
+ for (const item of script) {
292
+ await runCommandOnDriver(conn, driver, dmp => dumpSqlCommand(dmp, item));
293
+ }
294
+ await runCommandOnDriver(conn, driver, dmp => dmp.commitTransaction());
295
+ } catch (err) {
296
+ await runCommandOnDriver(conn, driver, dmp => dmp.rollbackTransaction());
297
+ return {
298
+ errorMessage: err.message,
299
+ };
300
+ }
301
+
302
+ if (fireEvents) {
303
+ for (const event of fireEvents ?? []) {
304
+ socket.emit(event);
305
+ }
306
+ }
307
+
308
+ return { status: 'ok' };
309
+ },
310
+
311
+ setAdminPassword_meta: true,
312
+ async setAdminPassword({ denyUseAdminPassword, oldPassword, newPassword, repeatPassword }) {
313
+ const [conn, driver] = await getStorageConnection();
314
+ if (!conn) {
315
+ return { status: 'error', errorMessage: 'Storage connection error' };
316
+ }
317
+
318
+ if (denyUseAdminPassword) {
319
+ await runQueryFmt(
320
+ driver,
321
+ conn,
322
+ "delete from ~config where ~group = 'admin' and ~key in ('adminPassword', 'adminPasswordState')"
323
+ );
324
+ await runQueryFmt(
325
+ driver,
326
+ conn,
327
+ "insert into ~config (~group, ~key, ~value) values ('admin', 'adminPasswordState', 'no')"
328
+ );
329
+
330
+ return { status: 'ok' };
331
+ }
332
+
333
+ const adminConfig = await storageReadConfig('admin');
334
+ if (adminConfig?.adminPasswordState == 'set') {
335
+ if (adminConfig.adminPassword != oldPassword) {
336
+ return {
337
+ status: 'error',
338
+ errorMessage: 'Invalid password - please check current password field',
339
+ };
340
+ }
341
+ }
342
+
343
+ if (newPassword != repeatPassword) {
344
+ return {
345
+ status: 'error',
346
+ errorMessage: 'Passwords do not match',
347
+ };
348
+ }
349
+
350
+ if (newPassword.length < 4) {
351
+ return {
352
+ status: 'error',
353
+ errorMessage: 'Password is too short, minimum length is 4 characters',
354
+ };
355
+ }
356
+
357
+ await runQueryFmt(
358
+ driver,
359
+ conn,
360
+ "delete from ~config where ~group = 'admin' and ~key in ('adminPassword', 'adminPasswordState')"
361
+ );
362
+ await runQueryFmt(
363
+ driver,
364
+ conn,
365
+ "insert into ~config (~group, ~key, ~value) values ('admin', 'adminPasswordState', 'set')"
366
+ );
367
+ await runQueryFmt(
368
+ driver,
369
+ conn,
370
+ "insert into ~config (~group, ~key, ~value) values ('admin', 'adminPassword', %v)",
371
+ newPassword
372
+ );
373
+
374
+ return { status: 'ok' };
375
+ },
376
+
377
+ getStorageConnectionError() {
378
+ return getStorageConnectionError();
379
+ },
380
+ };
@@ -0,0 +1,215 @@
1
+ const requireEngineDriver = require('../utility/requireEngineDriver');
2
+ const storageModel = require('../storageModel');
3
+ const dbgateApi = require('../shell');
4
+ const { getPredefinedPermissions, getLogger, extractErrorLogData } = require('dbgate-tools');
5
+ const _ = require('lodash');
6
+ const logger = getLogger('storageDb');
7
+
8
+ function getDbConnectionParams() {
9
+ const server = process.env.STORAGE_SERVER;
10
+ const port = process.env.STORAGE_PORT;
11
+ const user = process.env.STORAGE_USER;
12
+ const password = process.env.STORAGE_PASSWORD;
13
+ const database = process.env.STORAGE_DATABASE;
14
+ const engine = process.env.STORAGE_ENGINE;
15
+ const serviceName = process.env.STORAGE_SERVICE_NAME;
16
+
17
+ if (!server || !user || !password || !database || !engine) {
18
+ if (database) {
19
+ if (!server) {
20
+ throw new Error('Incorrect storage configuration, missing env variable STORAGE_SERVER');
21
+ }
22
+ if (!port) {
23
+ throw new Error('Incorrect storage configuration, missing env variable STORAGE_PORT');
24
+ }
25
+ if (!user) {
26
+ throw new Error('Incorrect storage configuration, missing env variable STORAGE_USER');
27
+ }
28
+ if (!password) {
29
+ throw new Error('Incorrect storage configuration, missing env variable STORAGE_PASSWORD');
30
+ }
31
+ if (!engine) {
32
+ throw new Error('Incorrect storage configuration, missing env variable STORAGE_ENGINE');
33
+ }
34
+ }
35
+ return null;
36
+ }
37
+
38
+ return { server, port, user, password, database, engine, serviceName };
39
+ }
40
+
41
+ let storageConnection = null;
42
+ let storageDriver = null;
43
+ let storageConnectionError = null;
44
+
45
+ async function getStorageConnectionCore() {
46
+ if (storageConnection) {
47
+ return [storageConnection, storageDriver];
48
+ }
49
+
50
+ const dbConnectionParams = getDbConnectionParams();
51
+
52
+ if (!dbConnectionParams) {
53
+ return [null, null];
54
+ }
55
+
56
+ storageDriver = requireEngineDriver(dbConnectionParams.engine);
57
+
58
+ let newConnection = null;
59
+ while (!newConnection) {
60
+ try {
61
+ newConnection = await storageDriver.connect(dbConnectionParams);
62
+ const version = await storageDriver.getVersion(newConnection);
63
+ logger.info(`Connected to storage database ${dbConnectionParams.engine}, version ${version?.versionText}`);
64
+ storageConnectionError = null;
65
+ } catch (err) {
66
+ storageConnectionError = err;
67
+ if (newConnection) {
68
+ try {
69
+ await storageDriver.close(newConnection);
70
+ } catch (err) {}
71
+ newConnection = null;
72
+ }
73
+ logger.error(extractErrorLogData(err), 'Error connecting to storage database, retrying in 5 seconds');
74
+ // sleep 5 seconds
75
+ await new Promise(resolve => setTimeout(resolve, 5000));
76
+ }
77
+ }
78
+
79
+ // @ts-ignore
80
+ await dbgateApi.deployDb({
81
+ systemConnection: newConnection,
82
+ driver: storageDriver,
83
+ loadedDbModel: storageModel,
84
+ });
85
+
86
+ storageConnection = newConnection;
87
+ return [storageConnection, storageDriver];
88
+ }
89
+
90
+ let gettingStorageConnectionPromise = null;
91
+
92
+ function getStorageConnection() {
93
+ // const timeoutPromise = new Promise((resolve, reject) => {
94
+ // setTimeout(() => reject(new Error(storageConnectionError?.message ?? 'Storage connection timeout')), 1000);
95
+ // });
96
+
97
+ if (gettingStorageConnectionPromise) {
98
+ // return Promise.race([gettingStorageConnectionPromise, timeoutPromise]);
99
+ return gettingStorageConnectionPromise;
100
+ }
101
+ gettingStorageConnectionPromise = getStorageConnectionCore();
102
+ gettingStorageConnectionPromise
103
+ .then(() => {
104
+ gettingStorageConnectionPromise = null;
105
+ })
106
+ .catch(err => {
107
+ logger.error(extractErrorLogData(err), 'Error connecting to storage database');
108
+ gettingStorageConnectionPromise = null;
109
+ });
110
+
111
+ // return Promise.race([gettingStorageConnectionPromise, timeoutPromise]);
112
+ return gettingStorageConnectionPromise;
113
+ }
114
+
115
+ async function storageSelectFmt(sql, ...params) {
116
+ const [conn, driver] = await getStorageConnection();
117
+ if (!conn) {
118
+ return null;
119
+ }
120
+
121
+ const dmp = driver.createDumper();
122
+ dmp.put(sql, ...params);
123
+ const resp = await storageDriver.query(storageConnection, dmp.s);
124
+ return resp.rows;
125
+ }
126
+
127
+ async function storageReadUserRolePermissions(userId) {
128
+ const resp = await storageSelectFmt(
129
+ `
130
+ select *
131
+ from ~role_permissions
132
+ inner join ~user_roles on ~role_permissions.~role_id = ~user_roles.~role_id
133
+ where ~user_roles.~user_id = %v`,
134
+ userId
135
+ );
136
+ if (!resp) {
137
+ return [];
138
+ }
139
+ return resp.map(x => x.permission);
140
+ }
141
+
142
+ async function storageReadUserPermissions(userId) {
143
+ const resp = await storageSelectFmt(
144
+ `
145
+ select *
146
+ from ~user_permissions
147
+ where ~user_permissions.~user_id = %v`,
148
+ userId
149
+ );
150
+ if (!resp) {
151
+ return [];
152
+ }
153
+ return resp.map(x => x.permission);
154
+ }
155
+
156
+ async function storageReadRolePermissions(roleId) {
157
+ const resp = await storageSelectFmt(
158
+ `
159
+ select *
160
+ from ~role_permissions
161
+ where ~role_permissions.~role_id = %v`,
162
+ roleId
163
+ );
164
+ if (!resp) {
165
+ return [];
166
+ }
167
+ return resp.map(x => x.permission);
168
+ }
169
+
170
+ async function loadSuperadminPermissions() {
171
+ const rolePermissions = await storageReadRolePermissions(-3);
172
+ return [...getPredefinedPermissions('superadmin'), ...rolePermissions];
173
+ }
174
+
175
+ async function storageReadConfig(group) {
176
+ const resp = await storageSelectFmt('select * from ~config where ~group = %v', group);
177
+ if (!resp) {
178
+ return null;
179
+ }
180
+ return _.fromPairs(resp.map(x => [x.key, x.value]));
181
+ }
182
+
183
+ async function storageWriteConfig(group, config) {
184
+ const [conn, driver] = await getStorageConnection();
185
+ if (!conn) {
186
+ return null;
187
+ }
188
+
189
+ const dmp = driver.createDumper();
190
+ dmp.put('delete from ~config where ~group = %v', group);
191
+ await driver.query(conn, dmp.s);
192
+
193
+ for (const key in config) {
194
+ const dmp = driver.createDumper();
195
+ dmp.put('insert into config (~group, ~key, ~value) values (%v, %v, %v)', group, key, config[key]);
196
+ await driver.query(conn, dmp.s);
197
+ }
198
+ }
199
+
200
+ function getStorageConnectionError() {
201
+ return storageConnectionError;
202
+ }
203
+
204
+ module.exports = {
205
+ getStorageConnection,
206
+ storageSelectFmt,
207
+ getDbConnectionParams,
208
+ storageReadUserRolePermissions,
209
+ storageReadUserPermissions,
210
+ storageReadRolePermissions,
211
+ loadSuperadminPermissions,
212
+ storageReadConfig,
213
+ storageWriteConfig,
214
+ getStorageConnectionError,
215
+ };