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.
- package/.env +19 -0
- package/.yarnrc +2 -0
- package/README.md +1 -0
- package/env/dblogin/.env +14 -0
- package/env/portal/.env +70 -0
- package/env/singledb/.env +17 -0
- package/env/storage/.env +43 -0
- package/package.json +89 -0
- package/src/auth/authCommon.js +16 -0
- package/src/auth/authProvider.js +343 -0
- package/src/auth/storageAuthProvider.js +393 -0
- package/src/controllers/apps.js +280 -0
- package/src/controllers/archive.js +217 -0
- package/src/controllers/auth.js +136 -0
- package/src/controllers/config.js +271 -0
- package/src/controllers/connections.js +486 -0
- package/src/controllers/databaseConnections.js +561 -0
- package/src/controllers/files.js +222 -0
- package/src/controllers/jsldata.js +296 -0
- package/src/controllers/metadata.js +47 -0
- package/src/controllers/plugins.js +216 -0
- package/src/controllers/queryHistory.js +54 -0
- package/src/controllers/runners.js +234 -0
- package/src/controllers/scheduler.js +46 -0
- package/src/controllers/serverConnections.js +271 -0
- package/src/controllers/sessions.js +243 -0
- package/src/controllers/storage.js +380 -0
- package/src/controllers/storageDb.js +215 -0
- package/src/controllers/uploads.js +133 -0
- package/src/currentVersion.js +5 -0
- package/src/gistSecret.js +2 -0
- package/src/index.js +139 -0
- package/src/main.js +202 -0
- package/src/packagedPluginsContent.js +1 -0
- package/src/proc/connectProcess.js +38 -0
- package/src/proc/databaseConnectionProcess.js +431 -0
- package/src/proc/index.js +15 -0
- package/src/proc/jslDatastoreProcess.js +60 -0
- package/src/proc/serverConnectionProcess.js +188 -0
- package/src/proc/sessionProcess.js +390 -0
- package/src/proc/sshForwardProcess.js +75 -0
- package/src/shell/archiveReader.js +11 -0
- package/src/shell/archiveWriter.js +22 -0
- package/src/shell/autoIndexForeignKeysTransform.js +19 -0
- package/src/shell/collectorWriter.js +33 -0
- package/src/shell/consoleObjectWriter.js +16 -0
- package/src/shell/copyStream.js +48 -0
- package/src/shell/dataDuplicator.js +63 -0
- package/src/shell/dataTypeMapperTransform.js +21 -0
- package/src/shell/dbModelToJson.js +16 -0
- package/src/shell/deployDb.js +56 -0
- package/src/shell/download.js +15 -0
- package/src/shell/dropAllDbObjects.js +42 -0
- package/src/shell/dumpDatabase.js +49 -0
- package/src/shell/executeQuery.js +39 -0
- package/src/shell/fakeObjectReader.js +35 -0
- package/src/shell/finalizer.js +12 -0
- package/src/shell/generateDeploySql.js +95 -0
- package/src/shell/generateModelSql.js +30 -0
- package/src/shell/importDatabase.js +85 -0
- package/src/shell/index.js +80 -0
- package/src/shell/initializeApiEnvironment.js +9 -0
- package/src/shell/jslDataReader.js +9 -0
- package/src/shell/jsonLinesReader.js +52 -0
- package/src/shell/jsonLinesWriter.js +36 -0
- package/src/shell/jsonReader.js +84 -0
- package/src/shell/jsonToDbModel.js +9 -0
- package/src/shell/jsonWriter.js +97 -0
- package/src/shell/loadDatabase.js +27 -0
- package/src/shell/loadFile.js +10 -0
- package/src/shell/modifyJsonLinesReader.js +148 -0
- package/src/shell/queryReader.js +30 -0
- package/src/shell/registerPlugins.js +9 -0
- package/src/shell/requirePlugin.js +43 -0
- package/src/shell/runScript.js +19 -0
- package/src/shell/sqlDataWriter.js +52 -0
- package/src/shell/sqlTextReplacementTransform.js +32 -0
- package/src/shell/tableReader.js +39 -0
- package/src/shell/tableWriter.js +18 -0
- package/src/storageModel.js +819 -0
- package/src/utility/ColumnMapTransformStream.js +21 -0
- package/src/utility/DatastoreProxy.js +106 -0
- package/src/utility/EnsureStreamHeaderStream.js +31 -0
- package/src/utility/JsonLinesDatabase.js +148 -0
- package/src/utility/JsonLinesDatastore.js +232 -0
- package/src/utility/LineReader.js +88 -0
- package/src/utility/SSHConnection.js +251 -0
- package/src/utility/authProxy.js +133 -0
- package/src/utility/checkLicense.js +186 -0
- package/src/utility/childProcessChecker.js +21 -0
- package/src/utility/cleanDirectory.js +24 -0
- package/src/utility/cloudUpgrade.js +61 -0
- package/src/utility/connectUtility.js +111 -0
- package/src/utility/crypting.js +105 -0
- package/src/utility/diff2htmlPage.js +8 -0
- package/src/utility/directories.js +179 -0
- package/src/utility/downloadPackage.js +51 -0
- package/src/utility/downloader.js +25 -0
- package/src/utility/exceptions.js +9 -0
- package/src/utility/exportDbModel.js +31 -0
- package/src/utility/exportDbModelSql.js +80 -0
- package/src/utility/getChartExport.js +55 -0
- package/src/utility/getDiagramExport.js +25 -0
- package/src/utility/getExpressPath.js +10 -0
- package/src/utility/getJslFileName.js +16 -0
- package/src/utility/getMapExport.js +77 -0
- package/src/utility/hardwareFingerprint.js +89 -0
- package/src/utility/hasPermission.js +101 -0
- package/src/utility/importDbModel.js +9 -0
- package/src/utility/loadFilesRecursive.js +20 -0
- package/src/utility/loadModelFolder.js +29 -0
- package/src/utility/loadModelTransform.js +36 -0
- package/src/utility/pipeForkLogs.js +19 -0
- package/src/utility/platformInfo.js +62 -0
- package/src/utility/processArgs.js +39 -0
- package/src/utility/processComm.js +18 -0
- package/src/utility/requireEngineDriver.js +26 -0
- package/src/utility/requirePluginFunction.js +16 -0
- package/src/utility/socket.js +68 -0
- package/src/utility/sshTunnel.js +106 -0
- package/src/utility/sshTunnelProxy.js +36 -0
- package/src/utility/timingSafeCheckToken.js +9 -0
- package/src/utility/useController.js +99 -0
- package/tsconfig.json +13 -0
- 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
|
+
};
|