dbgate-api-premium 6.3.2 → 6.4.0
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/package.json +9 -7
- package/src/auth/storageAuthProvider.js +2 -1
- package/src/controllers/archive.js +99 -6
- package/src/controllers/auth.js +3 -1
- package/src/controllers/config.js +135 -22
- package/src/controllers/connections.js +35 -2
- package/src/controllers/databaseConnections.js +101 -2
- package/src/controllers/files.js +59 -0
- package/src/controllers/jsldata.js +9 -0
- package/src/controllers/runners.js +25 -5
- package/src/controllers/serverConnections.js +22 -2
- package/src/controllers/storage.js +341 -8
- package/src/controllers/storageDb.js +59 -1
- package/src/controllers/uploads.js +0 -46
- package/src/currentVersion.js +2 -2
- package/src/main.js +7 -1
- package/src/proc/connectProcess.js +14 -2
- package/src/proc/databaseConnectionProcess.js +70 -5
- package/src/proc/serverConnectionProcess.js +7 -1
- package/src/proc/sessionProcess.js +15 -178
- package/src/shell/archiveReader.js +3 -1
- package/src/shell/collectorWriter.js +2 -2
- package/src/shell/copyStream.js +1 -0
- package/src/shell/dataReplicator.js +96 -0
- package/src/shell/download.js +22 -6
- package/src/shell/index.js +12 -2
- package/src/shell/jsonLinesWriter.js +4 -3
- package/src/shell/queryReader.js +10 -3
- package/src/shell/unzipDirectory.js +91 -0
- package/src/shell/unzipJsonLinesData.js +60 -0
- package/src/shell/unzipJsonLinesFile.js +59 -0
- package/src/shell/zipDirectory.js +49 -0
- package/src/shell/zipJsonLinesData.js +49 -0
- package/src/utility/DatastoreProxy.js +4 -0
- package/src/utility/cloudUpgrade.js +14 -1
- package/src/utility/connectUtility.js +3 -1
- package/src/utility/crypting.js +137 -22
- package/src/utility/extractSingleFileFromZip.js +77 -0
- package/src/utility/getMapExport.js +2 -0
- package/src/utility/handleQueryStream.js +186 -0
- package/src/utility/healthStatus.js +12 -1
- package/src/utility/listZipEntries.js +41 -0
- package/src/utility/processArgs.js +5 -0
- package/src/utility/sshTunnel.js +13 -2
- package/src/utility/storageReplicatorItems.js +88 -0
- package/src/shell/dataDuplicator.js +0 -61
package/src/controllers/files.js
CHANGED
|
@@ -9,6 +9,9 @@ const scheduler = require('./scheduler');
|
|
|
9
9
|
const getDiagramExport = require('../utility/getDiagramExport');
|
|
10
10
|
const apps = require('./apps');
|
|
11
11
|
const getMapExport = require('../utility/getMapExport');
|
|
12
|
+
const dbgateApi = require('../shell');
|
|
13
|
+
const { getLogger } = require('dbgate-tools');
|
|
14
|
+
const logger = getLogger('files');
|
|
12
15
|
|
|
13
16
|
function serialize(format, data) {
|
|
14
17
|
if (format == 'text') return data;
|
|
@@ -219,4 +222,60 @@ module.exports = {
|
|
|
219
222
|
return path.join(dir, file);
|
|
220
223
|
}
|
|
221
224
|
},
|
|
225
|
+
|
|
226
|
+
createZipFromJsons_meta: true,
|
|
227
|
+
async createZipFromJsons({ db, filePath }) {
|
|
228
|
+
logger.info(`Creating zip file from JSONS ${filePath}`);
|
|
229
|
+
await dbgateApi.zipJsonLinesData(db, filePath);
|
|
230
|
+
return true;
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
getJsonsFromZip_meta: true,
|
|
234
|
+
async getJsonsFromZip({ filePath }) {
|
|
235
|
+
const res = await dbgateApi.unzipJsonLinesData(filePath);
|
|
236
|
+
return res;
|
|
237
|
+
},
|
|
238
|
+
|
|
239
|
+
downloadText_meta: true,
|
|
240
|
+
async downloadText({ uri }, req) {
|
|
241
|
+
if (!uri) return null;
|
|
242
|
+
const filePath = await dbgateApi.download(uri);
|
|
243
|
+
const text = await fs.readFile(filePath, {
|
|
244
|
+
encoding: 'utf-8',
|
|
245
|
+
});
|
|
246
|
+
return text;
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
saveUploadedFile_meta: true,
|
|
250
|
+
async saveUploadedFile({ filePath, fileName }) {
|
|
251
|
+
const FOLDERS = ['sql', 'sqlite'];
|
|
252
|
+
for (const folder of FOLDERS) {
|
|
253
|
+
if (fileName.toLowerCase().endsWith('.' + folder)) {
|
|
254
|
+
logger.info(`Saving ${folder} file ${fileName}`);
|
|
255
|
+
await fs.copyFile(filePath, path.join(filesdir(), folder, fileName));
|
|
256
|
+
|
|
257
|
+
socket.emitChanged(`files-changed`, { folder: folder });
|
|
258
|
+
socket.emitChanged(`all-files-changed`);
|
|
259
|
+
return {
|
|
260
|
+
name: path.basename(filePath),
|
|
261
|
+
folder: folder,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
throw new Error(`${fileName} doesn't have one of supported extensions: ${FOLDERS.join(', ')}`);
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
exportFile_meta: true,
|
|
270
|
+
async exportFile({ folder, file, filePath }, req) {
|
|
271
|
+
if (!hasPermission(`files/${folder}/read`, req)) return false;
|
|
272
|
+
await fs.copyFile(path.join(filesdir(), folder, file), filePath);
|
|
273
|
+
return true;
|
|
274
|
+
},
|
|
275
|
+
|
|
276
|
+
simpleCopy_meta: true,
|
|
277
|
+
async simpleCopy({ sourceFilePath, targetFilePath }, req) {
|
|
278
|
+
await fs.copyFile(sourceFilePath, targetFilePath);
|
|
279
|
+
return true;
|
|
280
|
+
},
|
|
222
281
|
};
|
|
@@ -8,6 +8,8 @@ const getJslFileName = require('../utility/getJslFileName');
|
|
|
8
8
|
const JsonLinesDatastore = require('../utility/JsonLinesDatastore');
|
|
9
9
|
const requirePluginFunction = require('../utility/requirePluginFunction');
|
|
10
10
|
const socket = require('../utility/socket');
|
|
11
|
+
const crypto = require('crypto');
|
|
12
|
+
const dbgateApi = require('../shell');
|
|
11
13
|
|
|
12
14
|
function readFirstLine(file) {
|
|
13
15
|
return new Promise((resolve, reject) => {
|
|
@@ -293,4 +295,11 @@ module.exports = {
|
|
|
293
295
|
})),
|
|
294
296
|
};
|
|
295
297
|
},
|
|
298
|
+
|
|
299
|
+
downloadJslData_meta: true,
|
|
300
|
+
async downloadJslData({ uri }) {
|
|
301
|
+
const jslid = crypto.randomUUID();
|
|
302
|
+
await dbgateApi.download(uri, { targetFile: getJslFileName(jslid) });
|
|
303
|
+
return { jslid };
|
|
304
|
+
},
|
|
296
305
|
};
|
|
@@ -8,7 +8,7 @@ const { fork, spawn } = require('child_process');
|
|
|
8
8
|
const { rundir, uploadsdir, pluginsdir, getPluginBackendPath, packagedPluginList } = require('../utility/directories');
|
|
9
9
|
const {
|
|
10
10
|
extractShellApiPlugins,
|
|
11
|
-
|
|
11
|
+
compileShellApiFunctionName,
|
|
12
12
|
jsonScriptToJavascript,
|
|
13
13
|
getLogger,
|
|
14
14
|
safeJsonParse,
|
|
@@ -58,7 +58,7 @@ dbgateApi.initializeApiEnvironment();
|
|
|
58
58
|
${requirePluginsTemplate(extractShellApiPlugins(functionName, props))}
|
|
59
59
|
require=null;
|
|
60
60
|
async function run() {
|
|
61
|
-
const reader=await ${
|
|
61
|
+
const reader=await ${compileShellApiFunctionName(functionName)}(${JSON.stringify(props)});
|
|
62
62
|
const writer=await dbgateApi.collectorWriter({runid: '${runid}'});
|
|
63
63
|
await dbgateApi.copyStream(reader, writer);
|
|
64
64
|
}
|
|
@@ -96,9 +96,9 @@ module.exports = {
|
|
|
96
96
|
|
|
97
97
|
handle_ping() {},
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
handle_dataResult(runid, { dataResult }) {
|
|
100
100
|
const { resolve } = this.requests[runid];
|
|
101
|
-
resolve(
|
|
101
|
+
resolve(dataResult);
|
|
102
102
|
delete this.requests[runid];
|
|
103
103
|
},
|
|
104
104
|
|
|
@@ -273,7 +273,7 @@ module.exports = {
|
|
|
273
273
|
const runid = crypto.randomUUID();
|
|
274
274
|
|
|
275
275
|
if (script.type == 'json') {
|
|
276
|
-
const js = jsonScriptToJavascript(script);
|
|
276
|
+
const js = await jsonScriptToJavascript(script);
|
|
277
277
|
return this.startCore(runid, scriptTemplate(js, false));
|
|
278
278
|
}
|
|
279
279
|
|
|
@@ -328,4 +328,24 @@ module.exports = {
|
|
|
328
328
|
});
|
|
329
329
|
return promise;
|
|
330
330
|
},
|
|
331
|
+
|
|
332
|
+
scriptResult_meta: true,
|
|
333
|
+
async scriptResult({ script }) {
|
|
334
|
+
if (script.type != 'json') {
|
|
335
|
+
return { errorMessage: 'Only JSON scripts are allowed' };
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const promise = new Promise(async (resolve, reject) => {
|
|
339
|
+
const runid = crypto.randomUUID();
|
|
340
|
+
this.requests[runid] = { resolve, reject, exitOnStreamError: true };
|
|
341
|
+
const cloned = _.cloneDeepWith(script, node => {
|
|
342
|
+
if (node?.$replace == 'runid') {
|
|
343
|
+
return runid;
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
const js = await jsonScriptToJavascript(cloned);
|
|
347
|
+
this.startCore(runid, scriptTemplate(js, false));
|
|
348
|
+
});
|
|
349
|
+
return promise;
|
|
350
|
+
},
|
|
331
351
|
};
|
|
@@ -54,6 +54,9 @@ module.exports = {
|
|
|
54
54
|
if (!connection) {
|
|
55
55
|
throw new Error(`Connection with conid="${conid}" not found`);
|
|
56
56
|
}
|
|
57
|
+
if (connection.singleDatabase) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
57
60
|
if (connection.passwordMode == 'askPassword' || connection.passwordMode == 'askUser') {
|
|
58
61
|
throw new MissingCredentialsError({ conid, passwordMode: connection.passwordMode });
|
|
59
62
|
}
|
|
@@ -98,6 +101,11 @@ module.exports = {
|
|
|
98
101
|
if (newOpened.disconnected) return;
|
|
99
102
|
this.close(conid, false);
|
|
100
103
|
});
|
|
104
|
+
subprocess.on('error', err => {
|
|
105
|
+
logger.error(extractErrorLogData(err), 'Error in server connection subprocess');
|
|
106
|
+
if (newOpened.disconnected) return;
|
|
107
|
+
this.close(conid, false);
|
|
108
|
+
});
|
|
101
109
|
subprocess.send({ msgtype: 'connect', ...connection, globalSettings: await config.getSettings() });
|
|
102
110
|
return newOpened;
|
|
103
111
|
});
|
|
@@ -137,14 +145,14 @@ module.exports = {
|
|
|
137
145
|
if (conid == '__model') return [];
|
|
138
146
|
testConnectionPermission(conid, req);
|
|
139
147
|
const opened = await this.ensureOpened(conid);
|
|
140
|
-
return opened
|
|
148
|
+
return opened?.databases ?? [];
|
|
141
149
|
},
|
|
142
150
|
|
|
143
151
|
version_meta: true,
|
|
144
152
|
async version({ conid }, req) {
|
|
145
153
|
testConnectionPermission(conid, req);
|
|
146
154
|
const opened = await this.ensureOpened(conid);
|
|
147
|
-
return opened
|
|
155
|
+
return opened?.version ?? null;
|
|
148
156
|
},
|
|
149
157
|
|
|
150
158
|
serverStatus_meta: true,
|
|
@@ -165,6 +173,9 @@ module.exports = {
|
|
|
165
173
|
}
|
|
166
174
|
this.lastPinged[conid] = new Date().getTime();
|
|
167
175
|
const opened = await this.ensureOpened(conid);
|
|
176
|
+
if (!opened) {
|
|
177
|
+
return Promise.resolve();
|
|
178
|
+
}
|
|
168
179
|
try {
|
|
169
180
|
opened.subprocess.send({ msgtype: 'ping' });
|
|
170
181
|
} catch (err) {
|
|
@@ -189,6 +200,9 @@ module.exports = {
|
|
|
189
200
|
async sendDatabaseOp({ conid, msgtype, name }, req) {
|
|
190
201
|
testConnectionPermission(conid, req);
|
|
191
202
|
const opened = await this.ensureOpened(conid);
|
|
203
|
+
if (!opened) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
192
206
|
if (opened.connection.isReadOnly) return false;
|
|
193
207
|
const res = await this.sendRequest(opened, { msgtype, name });
|
|
194
208
|
if (res.errorMessage) {
|
|
@@ -228,6 +242,9 @@ module.exports = {
|
|
|
228
242
|
async loadDataCore(msgtype, { conid, ...args }, req) {
|
|
229
243
|
testConnectionPermission(conid, req);
|
|
230
244
|
const opened = await this.ensureOpened(conid);
|
|
245
|
+
if (!opened) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
231
248
|
const res = await this.sendRequest(opened, { msgtype, ...args });
|
|
232
249
|
if (res.errorMessage) {
|
|
233
250
|
console.error(res.errorMessage);
|
|
@@ -249,6 +266,9 @@ module.exports = {
|
|
|
249
266
|
async summaryCommand({ conid, command, row }, req) {
|
|
250
267
|
testConnectionPermission(conid, req);
|
|
251
268
|
const opened = await this.ensureOpened(conid);
|
|
269
|
+
if (!opened) {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
252
272
|
if (opened.connection.isReadOnly) return false;
|
|
253
273
|
return this.loadDataCore('summaryCommand', { conid, command, row });
|
|
254
274
|
},
|
|
@@ -12,15 +12,32 @@ const {
|
|
|
12
12
|
storageReadConfig,
|
|
13
13
|
storageWriteConfig,
|
|
14
14
|
getStorageConnectionError,
|
|
15
|
+
storageSaveRelationDiff,
|
|
16
|
+
selectStorageIdentity,
|
|
15
17
|
} = require('./storageDb');
|
|
16
18
|
const { hasPermission } = require('../utility/hasPermission');
|
|
17
19
|
const { changeSetToSql, removeSchemaFromChangeSet } = require('dbgate-datalib');
|
|
18
20
|
const storageModel = require('../storageModel');
|
|
19
21
|
const { dumpSqlCommand } = require('dbgate-sqltree');
|
|
20
|
-
const {
|
|
22
|
+
const {
|
|
23
|
+
runCommandOnDriver,
|
|
24
|
+
getLogger,
|
|
25
|
+
runQueryFmt,
|
|
26
|
+
getPredefinedPermissions,
|
|
27
|
+
runQueryOnDriver,
|
|
28
|
+
} = require('dbgate-tools');
|
|
21
29
|
const socket = require('../utility/socket');
|
|
22
30
|
const { obtainRefreshedLicense } = require('../utility/authProxy');
|
|
23
31
|
const { datadir } = require('../utility/directories');
|
|
32
|
+
const {
|
|
33
|
+
loadEncryptionKeyFromExternal,
|
|
34
|
+
encryptUser,
|
|
35
|
+
encryptConnection,
|
|
36
|
+
encryptPasswordString,
|
|
37
|
+
} = require('../utility/crypting');
|
|
38
|
+
const crypto = require('crypto');
|
|
39
|
+
const dataReplicator = require('../shell/dataReplicator');
|
|
40
|
+
const storageReplicatorItems = require('../utility/storageReplicatorItems');
|
|
24
41
|
|
|
25
42
|
const logger = getLogger('storage');
|
|
26
43
|
|
|
@@ -31,7 +48,6 @@ function mapConnection(connnection) {
|
|
|
31
48
|
};
|
|
32
49
|
}
|
|
33
50
|
|
|
34
|
-
|
|
35
51
|
let refreshLicenseStarted = false;
|
|
36
52
|
|
|
37
53
|
module.exports = {
|
|
@@ -48,6 +64,22 @@ module.exports = {
|
|
|
48
64
|
}
|
|
49
65
|
|
|
50
66
|
setAuthProviders(providers, providers[defIndex]);
|
|
67
|
+
|
|
68
|
+
const keyResult = await storageSelectFmt(
|
|
69
|
+
"select ~value from ~config where ~group = 'admin' and ~key = 'encryptionKey'"
|
|
70
|
+
);
|
|
71
|
+
const [conn, driver] = await getStorageConnection();
|
|
72
|
+
|
|
73
|
+
await loadEncryptionKeyFromExternal(keyResult[0]?.value, async key => {
|
|
74
|
+
await runQueryFmt(
|
|
75
|
+
driver,
|
|
76
|
+
conn,
|
|
77
|
+
'insert into ~config (~group, ~key, ~value) values (%v, %v, %v)',
|
|
78
|
+
'admin',
|
|
79
|
+
'encryptionKey',
|
|
80
|
+
key
|
|
81
|
+
);
|
|
82
|
+
});
|
|
51
83
|
},
|
|
52
84
|
|
|
53
85
|
async startRefreshLicense() {
|
|
@@ -135,7 +167,7 @@ module.exports = {
|
|
|
135
167
|
displayName: 'Internal storage',
|
|
136
168
|
defaultDatabase: process.env.STORAGE_DATABASE,
|
|
137
169
|
singleDatabase: true,
|
|
138
|
-
...await getDbConnectionParams(),
|
|
170
|
+
...(await getDbConnectionParams()),
|
|
139
171
|
};
|
|
140
172
|
}
|
|
141
173
|
|
|
@@ -183,8 +215,8 @@ module.exports = {
|
|
|
183
215
|
return null;
|
|
184
216
|
}
|
|
185
217
|
|
|
186
|
-
await runQueryFmt(driver, conn, 'delete from auth_methods_config');
|
|
187
|
-
await runQueryFmt(driver, conn, 'delete from auth_methods where id > 0');
|
|
218
|
+
await runQueryFmt(driver, conn, 'delete from ~auth_methods_config');
|
|
219
|
+
await runQueryFmt(driver, conn, 'delete from ~auth_methods where ~id > 0');
|
|
188
220
|
|
|
189
221
|
let id = 1;
|
|
190
222
|
for (const method of authMethods) {
|
|
@@ -192,7 +224,7 @@ module.exports = {
|
|
|
192
224
|
await runQueryFmt(
|
|
193
225
|
driver,
|
|
194
226
|
conn,
|
|
195
|
-
'update auth_methods set name=%v, is_disabled=%v, is_default = %v, is_collapsed = %v where id = %v',
|
|
227
|
+
'update ~auth_methods set ~name=%v, ~is_disabled=%v, ~is_default = %v, ~is_collapsed = %v where ~id = %v',
|
|
196
228
|
method.name,
|
|
197
229
|
method.isDisabled,
|
|
198
230
|
method.isDefault,
|
|
@@ -228,7 +260,7 @@ module.exports = {
|
|
|
228
260
|
await runQueryFmt(
|
|
229
261
|
driver,
|
|
230
262
|
conn,
|
|
231
|
-
'insert into auth_methods_config (%i, %i, %i) values (%v, %v, %v)',
|
|
263
|
+
'insert into ~auth_methods_config (%i, %i, %i) values (%v, %v, %v)',
|
|
232
264
|
'auth_method_id',
|
|
233
265
|
'key',
|
|
234
266
|
'value',
|
|
@@ -400,7 +432,7 @@ module.exports = {
|
|
|
400
432
|
driver,
|
|
401
433
|
conn,
|
|
402
434
|
"insert into ~config (~group, ~key, ~value) values ('admin', 'adminPassword', %v)",
|
|
403
|
-
newPassword
|
|
435
|
+
encryptPasswordString(newPassword)
|
|
404
436
|
);
|
|
405
437
|
|
|
406
438
|
return { status: 'ok' };
|
|
@@ -409,4 +441,305 @@ module.exports = {
|
|
|
409
441
|
getStorageConnectionError() {
|
|
410
442
|
return getStorageConnectionError();
|
|
411
443
|
},
|
|
444
|
+
|
|
445
|
+
getUserList_meta: true,
|
|
446
|
+
async getUserList() {
|
|
447
|
+
const resp = await storageSelectFmt(`select ~users.~id,~users.~login,~users.~password,~users.~email from ~users`);
|
|
448
|
+
const usedRoles = await storageSelectFmt(`select ~roles.~name, ~user_roles.~user_id from
|
|
449
|
+
~user_roles inner join ~roles ON ~user_roles.~role_id = ~roles.~id`);
|
|
450
|
+
const usedPermissions = await storageSelectFmt(`select * from ~user_permissions`);
|
|
451
|
+
return resp.map(x => ({
|
|
452
|
+
...x,
|
|
453
|
+
password: x.password?.startsWith('crypt:') ? 'crypted' : x.password ? 'plain' : 'no',
|
|
454
|
+
usedRoles: usedRoles.filter(y => y.user_id == x.id).map(y => y.name),
|
|
455
|
+
usedPermissions: usedPermissions.filter(y => y.user_id == x.id).map(y => y.permission),
|
|
456
|
+
}));
|
|
457
|
+
},
|
|
458
|
+
|
|
459
|
+
getUserDetail_meta: true,
|
|
460
|
+
async getUserDetail({ id }) {
|
|
461
|
+
const resp =
|
|
462
|
+
id == 'new'
|
|
463
|
+
? {}
|
|
464
|
+
: await storageSelectFmt(
|
|
465
|
+
`select ~users.~id,~users.~login,~users.password, ~users.~email from ~users where ~users.~id = %v`,
|
|
466
|
+
id
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
const rolePermissions = id == 'new' ? [] : await storageReadUserRolePermissions(id);
|
|
470
|
+
const basePermissions = [...getPredefinedPermissions('logged-user'), ...rolePermissions];
|
|
471
|
+
const permissions =
|
|
472
|
+
id == 'new'
|
|
473
|
+
? []
|
|
474
|
+
: (await storageSelectFmt('select * from ~user_permissions where ~user_id = %v', id)).map(x => x.permission);
|
|
475
|
+
const allRoles = await storageSelectFmt('select * from ~roles');
|
|
476
|
+
const usedRoles =
|
|
477
|
+
id == 'new'
|
|
478
|
+
? []
|
|
479
|
+
: (
|
|
480
|
+
await storageSelectFmt(`select ~user_roles.~role_id from ~user_roles where ~user_roles.~user_id = %v`, id)
|
|
481
|
+
).map(x => x.role_id);
|
|
482
|
+
const allConnections = await storageSelectFmt('select * from ~connections');
|
|
483
|
+
const usedConnections =
|
|
484
|
+
id == 'new'
|
|
485
|
+
? []
|
|
486
|
+
: (await storageSelectFmt('select ~connection_id from ~user_connections where ~user_id = %v', id)).map(
|
|
487
|
+
x => x.connection_id
|
|
488
|
+
);
|
|
489
|
+
|
|
490
|
+
return {
|
|
491
|
+
...resp[0],
|
|
492
|
+
basePermissions,
|
|
493
|
+
permissions,
|
|
494
|
+
allRoles,
|
|
495
|
+
usedRoles,
|
|
496
|
+
allConnections,
|
|
497
|
+
usedConnections,
|
|
498
|
+
encryptPassword: !!(resp[0]?.password?.startsWith('crypt:') || id == 'new'),
|
|
499
|
+
};
|
|
500
|
+
},
|
|
501
|
+
|
|
502
|
+
saveUserDetail_meta: true,
|
|
503
|
+
async saveUserDetail(user) {
|
|
504
|
+
const [conn, driver] = await getStorageConnection();
|
|
505
|
+
|
|
506
|
+
const { login, password, email, usedRoles, usedConnections, permissions } = encryptUser(user);
|
|
507
|
+
let id = user.id;
|
|
508
|
+
|
|
509
|
+
if (id == null) {
|
|
510
|
+
await runQueryFmt(
|
|
511
|
+
driver,
|
|
512
|
+
conn,
|
|
513
|
+
'insert into ~users (~login, ~password, ~email) values (%v, %v, %v)',
|
|
514
|
+
login,
|
|
515
|
+
password,
|
|
516
|
+
email
|
|
517
|
+
);
|
|
518
|
+
id = await selectStorageIdentity('users');
|
|
519
|
+
} else {
|
|
520
|
+
await runQueryFmt(
|
|
521
|
+
driver,
|
|
522
|
+
conn,
|
|
523
|
+
'update ~users set ~login=%v, ~password=%v, ~email=%v where ~id = %v',
|
|
524
|
+
login,
|
|
525
|
+
password,
|
|
526
|
+
email,
|
|
527
|
+
id
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
await storageSaveRelationDiff('user_permissions', 'user_id', 'permission', id, permissions);
|
|
532
|
+
await storageSaveRelationDiff('user_roles', 'user_id', 'role_id', id, usedRoles);
|
|
533
|
+
await storageSaveRelationDiff('user_connections', 'user_id', 'connection_id', id, usedConnections);
|
|
534
|
+
|
|
535
|
+
return true;
|
|
536
|
+
},
|
|
537
|
+
|
|
538
|
+
deleteUser_meta: true,
|
|
539
|
+
async deleteUser({ id }) {
|
|
540
|
+
const [conn, driver] = await getStorageConnection();
|
|
541
|
+
|
|
542
|
+
await runQueryFmt(driver, conn, 'delete from ~users where ~id = %v', id);
|
|
543
|
+
|
|
544
|
+
return true;
|
|
545
|
+
},
|
|
546
|
+
|
|
547
|
+
getConnectionList_meta: true,
|
|
548
|
+
async getConnectionList() {
|
|
549
|
+
const resp = await storageSelectFmt(
|
|
550
|
+
`select ~connections.~id,~connections.~engine,~connections.~displayName,~connections.~server,~connections.~user from ~connections`
|
|
551
|
+
);
|
|
552
|
+
return resp;
|
|
553
|
+
},
|
|
554
|
+
|
|
555
|
+
getConnectionDetail_meta: true,
|
|
556
|
+
async getConnectionDetail({ id }) {
|
|
557
|
+
if (id == 'new') {
|
|
558
|
+
return {
|
|
559
|
+
conid: crypto.randomUUID(),
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const resp = await storageSelectFmt(`select * from ~connections where ~id = %v`, id);
|
|
564
|
+
return resp[0];
|
|
565
|
+
},
|
|
566
|
+
|
|
567
|
+
saveConnectionDetail_meta: true,
|
|
568
|
+
async saveConnectionDetail(savedConnection) {
|
|
569
|
+
const [conn, driver] = await getStorageConnection();
|
|
570
|
+
|
|
571
|
+
const connection = encryptConnection(savedConnection);
|
|
572
|
+
|
|
573
|
+
const tableConnections = storageModel.tables.find(x => x.pureName == 'connections');
|
|
574
|
+
const id = connection.id;
|
|
575
|
+
|
|
576
|
+
const usedColumns = _.difference(
|
|
577
|
+
_.intersection(
|
|
578
|
+
tableConnections.columns.map(x => x.columnName),
|
|
579
|
+
Object.keys(connection)
|
|
580
|
+
),
|
|
581
|
+
['id']
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
if (id) {
|
|
585
|
+
await runQueryOnDriver(conn, driver, dmp => {
|
|
586
|
+
dmp.put(`update ~connections set`);
|
|
587
|
+
dmp.putCollection(',', usedColumns, col => {
|
|
588
|
+
dmp.put(`%i = %v`, col, connection[col]);
|
|
589
|
+
});
|
|
590
|
+
dmp.put(` where ~id = %v`, id);
|
|
591
|
+
});
|
|
592
|
+
} else {
|
|
593
|
+
await runQueryFmt(
|
|
594
|
+
driver,
|
|
595
|
+
conn,
|
|
596
|
+
`insert into ~connections (%,i) values (%,v)`,
|
|
597
|
+
usedColumns,
|
|
598
|
+
usedColumns.map(x => connection[x])
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
socket.emitChanged('connection-list-changed');
|
|
603
|
+
|
|
604
|
+
return true;
|
|
605
|
+
},
|
|
606
|
+
|
|
607
|
+
deleteConnection_meta: true,
|
|
608
|
+
async deleteConnection({ id }) {
|
|
609
|
+
const [conn, driver] = await getStorageConnection();
|
|
610
|
+
if (!conn) {
|
|
611
|
+
return null;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
await runQueryFmt(driver, conn, 'delete from ~connections where ~id = %v', id);
|
|
615
|
+
|
|
616
|
+
socket.emitChanged('connection-list-changed');
|
|
617
|
+
|
|
618
|
+
return true;
|
|
619
|
+
},
|
|
620
|
+
|
|
621
|
+
getRoleList_meta: true,
|
|
622
|
+
async getRoleList() {
|
|
623
|
+
const resp = await storageSelectFmt(`select ~roles.~id,~roles.~name from ~roles`);
|
|
624
|
+
const usedPermissions = await storageSelectFmt(`select * from ~role_permissions`);
|
|
625
|
+
return resp.map(x => ({
|
|
626
|
+
...x,
|
|
627
|
+
usedPermissions: usedPermissions.filter(y => y.role_id == x.id).map(y => y.permission),
|
|
628
|
+
}));
|
|
629
|
+
},
|
|
630
|
+
|
|
631
|
+
getRoleDetail_meta: true,
|
|
632
|
+
async getRoleDetail({ id }) {
|
|
633
|
+
const resp =
|
|
634
|
+
id == 'new' ? {} : await storageSelectFmt(`select ~roles.~id,~roles.~name from ~roles where ~roles.~id = %v`, id);
|
|
635
|
+
|
|
636
|
+
const basePermissions = getPredefinedPermissions(id < 0 && resp[0]?.name ? resp[0]?.name : 'logged-user');
|
|
637
|
+
const permissions =
|
|
638
|
+
id == 'new'
|
|
639
|
+
? []
|
|
640
|
+
: (await storageSelectFmt('select * from ~role_permissions where ~role_id = %v', id)).map(x => x.permission);
|
|
641
|
+
const allUsers = await storageSelectFmt('select * from ~users');
|
|
642
|
+
const usedUsers =
|
|
643
|
+
id == 'new'
|
|
644
|
+
? []
|
|
645
|
+
: (
|
|
646
|
+
await storageSelectFmt(`select ~user_roles.~user_id from ~user_roles where ~user_roles.~role_id = %v`, id)
|
|
647
|
+
).map(x => x.user_id);
|
|
648
|
+
const allConnections = await storageSelectFmt('select * from ~connections');
|
|
649
|
+
const usedConnections =
|
|
650
|
+
id == 'new'
|
|
651
|
+
? []
|
|
652
|
+
: (await storageSelectFmt('select ~connection_id from ~role_connections where ~role_id = %v', id)).map(
|
|
653
|
+
x => x.connection_id
|
|
654
|
+
);
|
|
655
|
+
|
|
656
|
+
return {
|
|
657
|
+
...resp[0],
|
|
658
|
+
basePermissions,
|
|
659
|
+
permissions,
|
|
660
|
+
allUsers,
|
|
661
|
+
usedUsers,
|
|
662
|
+
allConnections,
|
|
663
|
+
usedConnections,
|
|
664
|
+
};
|
|
665
|
+
},
|
|
666
|
+
|
|
667
|
+
deleteRole_meta: true,
|
|
668
|
+
async deleteRole({ id }) {
|
|
669
|
+
const [conn, driver] = await getStorageConnection();
|
|
670
|
+
if (!conn) {
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
await runQueryFmt(driver, conn, 'delete from ~roles where ~id = %v', id);
|
|
675
|
+
|
|
676
|
+
return true;
|
|
677
|
+
},
|
|
678
|
+
|
|
679
|
+
saveRoleDetail_meta: true,
|
|
680
|
+
async saveRoleDetail(role) {
|
|
681
|
+
const [conn, driver] = await getStorageConnection();
|
|
682
|
+
|
|
683
|
+
const { name, usedConnections, usedUsers, permissions } = encryptUser(role);
|
|
684
|
+
let id = role.id;
|
|
685
|
+
|
|
686
|
+
if (id == null) {
|
|
687
|
+
await runQueryFmt(driver, conn, 'insert into ~roles (~name) values (%v)', name);
|
|
688
|
+
id = await selectStorageIdentity('roles');
|
|
689
|
+
} else {
|
|
690
|
+
if (id > 0) {
|
|
691
|
+
await runQueryFmt(driver, conn, 'update ~roles set ~name=%v where ~id = %v', name, id);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
await storageSaveRelationDiff('role_permissions', 'role_id', 'permission', id, permissions);
|
|
696
|
+
await storageSaveRelationDiff('user_roles', 'role_id', 'user_id', id, usedUsers);
|
|
697
|
+
await storageSaveRelationDiff('role_connections', 'role_id', 'connection_id', id, usedConnections);
|
|
698
|
+
|
|
699
|
+
return true;
|
|
700
|
+
},
|
|
701
|
+
|
|
702
|
+
async getExportedDatabase() {
|
|
703
|
+
const connections = await storageSelectFmt(`select * from ~connections`);
|
|
704
|
+
const user_permissions = await storageSelectFmt(`select * from ~user_permissions`);
|
|
705
|
+
const users = await storageSelectFmt(`select * from ~users`);
|
|
706
|
+
const auth_methods = await storageSelectFmt(`select * from ~auth_methods`);
|
|
707
|
+
const role_connections = await storageSelectFmt(`select * from ~role_connections`);
|
|
708
|
+
const user_connections = await storageSelectFmt(`select * from ~user_connections`);
|
|
709
|
+
const user_roles = await storageSelectFmt(`select * from ~user_roles`);
|
|
710
|
+
const config = await storageSelectFmt(`select * from ~config`);
|
|
711
|
+
const auth_methods_config = await storageSelectFmt(`select * from ~auth_methods_config`);
|
|
712
|
+
const role_permissions = await storageSelectFmt(`select * from ~role_permissions`);
|
|
713
|
+
const roles = await storageSelectFmt(`select * from ~roles`);
|
|
714
|
+
|
|
715
|
+
return {
|
|
716
|
+
connections,
|
|
717
|
+
user_permissions,
|
|
718
|
+
users,
|
|
719
|
+
auth_methods,
|
|
720
|
+
role_connections,
|
|
721
|
+
user_connections,
|
|
722
|
+
user_roles,
|
|
723
|
+
config,
|
|
724
|
+
auth_methods_config,
|
|
725
|
+
role_permissions,
|
|
726
|
+
roles,
|
|
727
|
+
};
|
|
728
|
+
},
|
|
729
|
+
|
|
730
|
+
async replicateImportedDatabase(db) {
|
|
731
|
+
const [conn, driver] = await getStorageConnection();
|
|
732
|
+
// @ts-ignore
|
|
733
|
+
await dataReplicator({
|
|
734
|
+
systemConnection: conn,
|
|
735
|
+
driver,
|
|
736
|
+
items: storageReplicatorItems
|
|
737
|
+
.map(item => ({
|
|
738
|
+
...item,
|
|
739
|
+
jsonArray: db[item.name],
|
|
740
|
+
}))
|
|
741
|
+
.filter(x => x.jsonArray),
|
|
742
|
+
});
|
|
743
|
+
socket.emitChanged('connection-list-changed');
|
|
744
|
+
},
|
|
412
745
|
};
|