dbgate-api 6.6.1 → 6.6.2
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 +5 -5
- package/src/auth/authProvider.js +13 -1
- package/src/controllers/auth.js +2 -1
- package/src/controllers/config.js +8 -5
- package/src/controllers/connections.js +8 -7
- package/src/controllers/databaseConnections.js +137 -72
- package/src/controllers/files.js +25 -15
- package/src/controllers/plugins.js +7 -4
- package/src/controllers/runners.js +3 -0
- package/src/controllers/scheduler.js +3 -2
- package/src/controllers/serverConnections.js +65 -10
- package/src/controllers/sessions.js +4 -1
- package/src/controllers/storage.js +0 -4
- package/src/currentVersion.js +2 -2
- package/src/index.js +2 -1
- package/src/proc/databaseConnectionProcess.js +24 -1
- package/src/proc/serverConnectionProcess.js +26 -0
- package/src/storageModel.js +726 -105
- package/src/utility/hasPermission.js +286 -71
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dbgate-api",
|
|
3
3
|
"main": "src/index.js",
|
|
4
|
-
"version": "6.6.
|
|
4
|
+
"version": "6.6.2",
|
|
5
5
|
"homepage": "https://dbgate.org/",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"compare-versions": "^3.6.0",
|
|
31
31
|
"cors": "^2.8.5",
|
|
32
32
|
"cross-env": "^6.0.3",
|
|
33
|
-
"dbgate-datalib": "^6.6.
|
|
33
|
+
"dbgate-datalib": "^6.6.2",
|
|
34
34
|
"dbgate-query-splitter": "^4.11.5",
|
|
35
|
-
"dbgate-sqltree": "^6.6.
|
|
36
|
-
"dbgate-tools": "^6.6.
|
|
35
|
+
"dbgate-sqltree": "^6.6.2",
|
|
36
|
+
"dbgate-tools": "^6.6.2",
|
|
37
37
|
"debug": "^4.3.4",
|
|
38
38
|
"diff": "^5.0.0",
|
|
39
39
|
"diff2html": "^3.4.13",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@types/fs-extra": "^9.0.11",
|
|
88
88
|
"@types/lodash": "^4.14.149",
|
|
89
|
-
"dbgate-types": "^6.6.
|
|
89
|
+
"dbgate-types": "^6.6.2",
|
|
90
90
|
"env-cmd": "^10.1.0",
|
|
91
91
|
"jsdoc-to-markdown": "^9.0.5",
|
|
92
92
|
"node-loader": "^1.0.2",
|
package/src/auth/authProvider.js
CHANGED
|
@@ -36,12 +36,24 @@ class AuthProviderBase {
|
|
|
36
36
|
return !!req?.user || !!req?.auth;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
getCurrentPermissions(req) {
|
|
39
|
+
async getCurrentPermissions(req) {
|
|
40
40
|
const login = this.getCurrentLogin(req);
|
|
41
41
|
const permissions = process.env[`LOGIN_PERMISSIONS_${login}`];
|
|
42
42
|
return permissions || process.env.PERMISSIONS;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
async checkCurrentConnectionPermission(req, conid) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async getCurrentDatabasePermissions(req) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async getCurrentTablePermissions(req) {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
|
|
45
57
|
getLoginPageConnections() {
|
|
46
58
|
return null;
|
|
47
59
|
}
|
package/src/controllers/auth.js
CHANGED
|
@@ -51,6 +51,7 @@ function authMiddleware(req, res, next) {
|
|
|
51
51
|
'/auth/oauth-token',
|
|
52
52
|
'/auth/login',
|
|
53
53
|
'/auth/redirect',
|
|
54
|
+
'/redirect',
|
|
54
55
|
'/stream',
|
|
55
56
|
'/storage/get-connections-for-login-page',
|
|
56
57
|
'/storage/set-admin-password',
|
|
@@ -139,9 +140,9 @@ module.exports = {
|
|
|
139
140
|
const accessToken = jwt.sign(
|
|
140
141
|
{
|
|
141
142
|
login: 'superadmin',
|
|
142
|
-
permissions: await storage.loadSuperadminPermissions(),
|
|
143
143
|
roleId: -3,
|
|
144
144
|
licenseUid,
|
|
145
|
+
amoid: 'superadmin',
|
|
145
146
|
},
|
|
146
147
|
getTokenSecret(),
|
|
147
148
|
{
|
|
@@ -3,7 +3,7 @@ const os = require('os');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const axios = require('axios');
|
|
5
5
|
const { datadir, getLogsFilePath } = require('../utility/directories');
|
|
6
|
-
const { hasPermission } = require('../utility/hasPermission');
|
|
6
|
+
const { hasPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
|
7
7
|
const socket = require('../utility/socket');
|
|
8
8
|
const _ = require('lodash');
|
|
9
9
|
const AsyncLock = require('async-lock');
|
|
@@ -46,7 +46,7 @@ module.exports = {
|
|
|
46
46
|
async get(_params, req) {
|
|
47
47
|
const authProvider = getAuthProviderFromReq(req);
|
|
48
48
|
const login = authProvider.getCurrentLogin(req);
|
|
49
|
-
const permissions = authProvider.getCurrentPermissions(req);
|
|
49
|
+
const permissions = await authProvider.getCurrentPermissions(req);
|
|
50
50
|
const isUserLoggedIn = authProvider.isUserLoggedIn(req);
|
|
51
51
|
|
|
52
52
|
const singleConid = authProvider.getSingleConnectionId(req);
|
|
@@ -280,7 +280,8 @@ module.exports = {
|
|
|
280
280
|
|
|
281
281
|
updateSettings_meta: true,
|
|
282
282
|
async updateSettings(values, req) {
|
|
283
|
-
|
|
283
|
+
const loadedPermissions = await loadPermissionsFromRequest(req);
|
|
284
|
+
if (!hasPermission(`settings/change`, loadedPermissions)) return false;
|
|
284
285
|
cachedSettingsValue = null;
|
|
285
286
|
|
|
286
287
|
const res = await lock.acquire('settings', async () => {
|
|
@@ -392,7 +393,8 @@ module.exports = {
|
|
|
392
393
|
|
|
393
394
|
exportConnectionsAndSettings_meta: true,
|
|
394
395
|
async exportConnectionsAndSettings(_params, req) {
|
|
395
|
-
|
|
396
|
+
const loadedPermissions = await loadPermissionsFromRequest(req);
|
|
397
|
+
if (!hasPermission(`admin/config`, loadedPermissions)) {
|
|
396
398
|
throw new Error('Permission denied: admin/config');
|
|
397
399
|
}
|
|
398
400
|
|
|
@@ -416,7 +418,8 @@ module.exports = {
|
|
|
416
418
|
|
|
417
419
|
importConnectionsAndSettings_meta: true,
|
|
418
420
|
async importConnectionsAndSettings({ db }, req) {
|
|
419
|
-
|
|
421
|
+
const loadedPermissions = await loadPermissionsFromRequest(req);
|
|
422
|
+
if (!hasPermission(`admin/config`, loadedPermissions)) {
|
|
420
423
|
throw new Error('Permission denied: admin/config');
|
|
421
424
|
}
|
|
422
425
|
|
|
@@ -14,7 +14,7 @@ const JsonLinesDatabase = require('../utility/JsonLinesDatabase');
|
|
|
14
14
|
const processArgs = require('../utility/processArgs');
|
|
15
15
|
const { safeJsonParse, getLogger, extractErrorLogData } = require('dbgate-tools');
|
|
16
16
|
const platformInfo = require('../utility/platformInfo');
|
|
17
|
-
const { connectionHasPermission, testConnectionPermission } = require('../utility/hasPermission');
|
|
17
|
+
const { connectionHasPermission, testConnectionPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
|
18
18
|
const pipeForkLogs = require('../utility/pipeForkLogs');
|
|
19
19
|
const requireEngineDriver = require('../utility/requireEngineDriver');
|
|
20
20
|
const { getAuthProviderById } = require('../auth/authProvider');
|
|
@@ -227,6 +227,7 @@ module.exports = {
|
|
|
227
227
|
list_meta: true,
|
|
228
228
|
async list(_params, req) {
|
|
229
229
|
const storage = require('./storage');
|
|
230
|
+
const loadedPermissions = await loadPermissionsFromRequest(req);
|
|
230
231
|
|
|
231
232
|
const storageConnections = await storage.connections(req);
|
|
232
233
|
if (storageConnections) {
|
|
@@ -234,9 +235,9 @@ module.exports = {
|
|
|
234
235
|
}
|
|
235
236
|
if (portalConnections) {
|
|
236
237
|
if (platformInfo.allowShellConnection) return portalConnections;
|
|
237
|
-
return portalConnections.map(maskConnection).filter(x => connectionHasPermission(x,
|
|
238
|
+
return portalConnections.map(maskConnection).filter(x => connectionHasPermission(x, loadedPermissions));
|
|
238
239
|
}
|
|
239
|
-
return (await this.datastore.find()).filter(x => connectionHasPermission(x,
|
|
240
|
+
return (await this.datastore.find()).filter(x => connectionHasPermission(x, loadedPermissions));
|
|
240
241
|
},
|
|
241
242
|
|
|
242
243
|
async getUsedEngines() {
|
|
@@ -375,7 +376,7 @@ module.exports = {
|
|
|
375
376
|
update_meta: true,
|
|
376
377
|
async update({ _id, values }, req) {
|
|
377
378
|
if (portalConnections) return;
|
|
378
|
-
testConnectionPermission(_id, req);
|
|
379
|
+
await testConnectionPermission(_id, req);
|
|
379
380
|
const res = await this.datastore.patch(_id, values);
|
|
380
381
|
socket.emitChanged('connection-list-changed');
|
|
381
382
|
return res;
|
|
@@ -392,7 +393,7 @@ module.exports = {
|
|
|
392
393
|
updateDatabase_meta: true,
|
|
393
394
|
async updateDatabase({ conid, database, values }, req) {
|
|
394
395
|
if (portalConnections) return;
|
|
395
|
-
testConnectionPermission(conid, req);
|
|
396
|
+
await testConnectionPermission(conid, req);
|
|
396
397
|
const conn = await this.datastore.get(conid);
|
|
397
398
|
let databases = (conn && conn.databases) || [];
|
|
398
399
|
if (databases.find(x => x.name == database)) {
|
|
@@ -410,7 +411,7 @@ module.exports = {
|
|
|
410
411
|
delete_meta: true,
|
|
411
412
|
async delete(connection, req) {
|
|
412
413
|
if (portalConnections) return;
|
|
413
|
-
testConnectionPermission(connection, req);
|
|
414
|
+
await testConnectionPermission(connection, req);
|
|
414
415
|
const res = await this.datastore.remove(connection._id);
|
|
415
416
|
socket.emitChanged('connection-list-changed');
|
|
416
417
|
return res;
|
|
@@ -452,7 +453,7 @@ module.exports = {
|
|
|
452
453
|
_id: '__model',
|
|
453
454
|
};
|
|
454
455
|
}
|
|
455
|
-
testConnectionPermission(conid, req);
|
|
456
|
+
await testConnectionPermission(conid, req);
|
|
456
457
|
return this.getCore({ conid, mask: true });
|
|
457
458
|
},
|
|
458
459
|
|
|
@@ -29,7 +29,7 @@ const generateDeploySql = require('../shell/generateDeploySql');
|
|
|
29
29
|
const { createTwoFilesPatch } = require('diff');
|
|
30
30
|
const diff2htmlPage = require('../utility/diff2htmlPage');
|
|
31
31
|
const processArgs = require('../utility/processArgs');
|
|
32
|
-
const { testConnectionPermission } = require('../utility/hasPermission');
|
|
32
|
+
const { testConnectionPermission, hasPermission, loadPermissionsFromRequest, loadTablePermissionsFromRequest, getTablePermissionRole, loadDatabasePermissionsFromRequest, getDatabasePermissionRole, getTablePermissionRoleLevelIndex, testDatabaseRolePermission } = require('../utility/hasPermission');
|
|
33
33
|
const { MissingCredentialsError } = require('../utility/exceptions');
|
|
34
34
|
const pipeForkLogs = require('../utility/pipeForkLogs');
|
|
35
35
|
const crypto = require('crypto');
|
|
@@ -100,7 +100,7 @@ module.exports = {
|
|
|
100
100
|
socket.emitChanged(`database-status-changed`, { conid, database });
|
|
101
101
|
},
|
|
102
102
|
|
|
103
|
-
handle_ping() {},
|
|
103
|
+
handle_ping() { },
|
|
104
104
|
|
|
105
105
|
// session event handlers
|
|
106
106
|
|
|
@@ -235,7 +235,7 @@ module.exports = {
|
|
|
235
235
|
|
|
236
236
|
queryData_meta: true,
|
|
237
237
|
async queryData({ conid, database, sql }, req) {
|
|
238
|
-
testConnectionPermission(conid, req);
|
|
238
|
+
await testConnectionPermission(conid, req);
|
|
239
239
|
logger.info({ conid, database, sql }, 'DBGM-00007 Processing query');
|
|
240
240
|
const opened = await this.ensureOpened(conid, database);
|
|
241
241
|
// if (opened && opened.status && opened.status.name == 'error') {
|
|
@@ -247,7 +247,7 @@ module.exports = {
|
|
|
247
247
|
|
|
248
248
|
sqlSelect_meta: true,
|
|
249
249
|
async sqlSelect({ conid, database, select, auditLogSessionGroup }, req) {
|
|
250
|
-
testConnectionPermission(conid, req);
|
|
250
|
+
await testConnectionPermission(conid, req);
|
|
251
251
|
const opened = await this.ensureOpened(conid, database);
|
|
252
252
|
const res = await this.sendRequest(
|
|
253
253
|
opened,
|
|
@@ -256,24 +256,23 @@ module.exports = {
|
|
|
256
256
|
auditLogger:
|
|
257
257
|
auditLogSessionGroup && select?.from?.name?.pureName
|
|
258
258
|
? response => {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
select?.from?.name?.pureName
|
|
259
|
+
sendToAuditLog(req, {
|
|
260
|
+
category: 'dbop',
|
|
261
|
+
component: 'DatabaseConnectionsController',
|
|
262
|
+
event: 'sql.select',
|
|
263
|
+
action: 'select',
|
|
264
|
+
severity: 'info',
|
|
265
|
+
conid,
|
|
266
|
+
database,
|
|
267
|
+
schemaName: select?.from?.name?.schemaName,
|
|
268
|
+
pureName: select?.from?.name?.pureName,
|
|
269
|
+
sumint1: response?.rows?.length,
|
|
270
|
+
sessionParam: `${conid}::${database}::${select?.from?.name?.schemaName || '0'}::${select?.from?.name?.pureName
|
|
272
271
|
}`,
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
272
|
+
sessionGroup: auditLogSessionGroup,
|
|
273
|
+
message: `Loaded table data from ${select?.from?.name?.pureName}`,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
277
276
|
: null,
|
|
278
277
|
}
|
|
279
278
|
);
|
|
@@ -282,7 +281,9 @@ module.exports = {
|
|
|
282
281
|
|
|
283
282
|
runScript_meta: true,
|
|
284
283
|
async runScript({ conid, database, sql, useTransaction, logMessage }, req) {
|
|
285
|
-
|
|
284
|
+
const loadedPermissions = await loadPermissionsFromRequest(req);
|
|
285
|
+
await testConnectionPermission(conid, req, loadedPermissions);
|
|
286
|
+
await testDatabaseRolePermission(conid, database, 'run_script', req);
|
|
286
287
|
logger.info({ conid, database, sql }, 'DBGM-00008 Processing script');
|
|
287
288
|
const opened = await this.ensureOpened(conid, database);
|
|
288
289
|
sendToAuditLog(req, {
|
|
@@ -303,7 +304,7 @@ module.exports = {
|
|
|
303
304
|
|
|
304
305
|
runOperation_meta: true,
|
|
305
306
|
async runOperation({ conid, database, operation, useTransaction }, req) {
|
|
306
|
-
testConnectionPermission(conid, req);
|
|
307
|
+
await testConnectionPermission(conid, req);
|
|
307
308
|
logger.info({ conid, database, operation }, 'DBGM-00009 Processing operation');
|
|
308
309
|
|
|
309
310
|
sendToAuditLog(req, {
|
|
@@ -325,7 +326,7 @@ module.exports = {
|
|
|
325
326
|
|
|
326
327
|
collectionData_meta: true,
|
|
327
328
|
async collectionData({ conid, database, options, auditLogSessionGroup }, req) {
|
|
328
|
-
testConnectionPermission(conid, req);
|
|
329
|
+
await testConnectionPermission(conid, req);
|
|
329
330
|
const opened = await this.ensureOpened(conid, database);
|
|
330
331
|
const res = await this.sendRequest(
|
|
331
332
|
opened,
|
|
@@ -334,21 +335,21 @@ module.exports = {
|
|
|
334
335
|
auditLogger:
|
|
335
336
|
auditLogSessionGroup && options?.pureName
|
|
336
337
|
? response => {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
338
|
+
sendToAuditLog(req, {
|
|
339
|
+
category: 'dbop',
|
|
340
|
+
component: 'DatabaseConnectionsController',
|
|
341
|
+
event: 'nosql.collectionData',
|
|
342
|
+
action: 'select',
|
|
343
|
+
severity: 'info',
|
|
344
|
+
conid,
|
|
345
|
+
database,
|
|
346
|
+
pureName: options?.pureName,
|
|
347
|
+
sumint1: response?.result?.rows?.length,
|
|
348
|
+
sessionParam: `${conid}::${database}::${options?.pureName}`,
|
|
349
|
+
sessionGroup: auditLogSessionGroup,
|
|
350
|
+
message: `Loaded collection data ${options?.pureName}`,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
352
353
|
: null,
|
|
353
354
|
}
|
|
354
355
|
);
|
|
@@ -356,7 +357,7 @@ module.exports = {
|
|
|
356
357
|
},
|
|
357
358
|
|
|
358
359
|
async loadDataCore(msgtype, { conid, database, ...args }, req) {
|
|
359
|
-
testConnectionPermission(conid, req);
|
|
360
|
+
await testConnectionPermission(conid, req);
|
|
360
361
|
const opened = await this.ensureOpened(conid, database);
|
|
361
362
|
const res = await this.sendRequest(opened, { msgtype, ...args });
|
|
362
363
|
if (res.errorMessage) {
|
|
@@ -371,7 +372,7 @@ module.exports = {
|
|
|
371
372
|
|
|
372
373
|
schemaList_meta: true,
|
|
373
374
|
async schemaList({ conid, database }, req) {
|
|
374
|
-
testConnectionPermission(conid, req);
|
|
375
|
+
await testConnectionPermission(conid, req);
|
|
375
376
|
return this.loadDataCore('schemaList', { conid, database });
|
|
376
377
|
},
|
|
377
378
|
|
|
@@ -383,43 +384,43 @@ module.exports = {
|
|
|
383
384
|
|
|
384
385
|
loadKeys_meta: true,
|
|
385
386
|
async loadKeys({ conid, database, root, filter, limit }, req) {
|
|
386
|
-
testConnectionPermission(conid, req);
|
|
387
|
+
await testConnectionPermission(conid, req);
|
|
387
388
|
return this.loadDataCore('loadKeys', { conid, database, root, filter, limit });
|
|
388
389
|
},
|
|
389
390
|
|
|
390
391
|
scanKeys_meta: true,
|
|
391
392
|
async scanKeys({ conid, database, root, pattern, cursor, count }, req) {
|
|
392
|
-
testConnectionPermission(conid, req);
|
|
393
|
+
await testConnectionPermission(conid, req);
|
|
393
394
|
return this.loadDataCore('scanKeys', { conid, database, root, pattern, cursor, count });
|
|
394
395
|
},
|
|
395
396
|
|
|
396
397
|
exportKeys_meta: true,
|
|
397
398
|
async exportKeys({ conid, database, options }, req) {
|
|
398
|
-
testConnectionPermission(conid, req);
|
|
399
|
+
await testConnectionPermission(conid, req);
|
|
399
400
|
return this.loadDataCore('exportKeys', { conid, database, options });
|
|
400
401
|
},
|
|
401
402
|
|
|
402
403
|
loadKeyInfo_meta: true,
|
|
403
404
|
async loadKeyInfo({ conid, database, key }, req) {
|
|
404
|
-
testConnectionPermission(conid, req);
|
|
405
|
+
await testConnectionPermission(conid, req);
|
|
405
406
|
return this.loadDataCore('loadKeyInfo', { conid, database, key });
|
|
406
407
|
},
|
|
407
408
|
|
|
408
409
|
loadKeyTableRange_meta: true,
|
|
409
410
|
async loadKeyTableRange({ conid, database, key, cursor, count }, req) {
|
|
410
|
-
testConnectionPermission(conid, req);
|
|
411
|
+
await testConnectionPermission(conid, req);
|
|
411
412
|
return this.loadDataCore('loadKeyTableRange', { conid, database, key, cursor, count });
|
|
412
413
|
},
|
|
413
414
|
|
|
414
415
|
loadFieldValues_meta: true,
|
|
415
416
|
async loadFieldValues({ conid, database, schemaName, pureName, field, search, dataType }, req) {
|
|
416
|
-
testConnectionPermission(conid, req);
|
|
417
|
+
await testConnectionPermission(conid, req);
|
|
417
418
|
return this.loadDataCore('loadFieldValues', { conid, database, schemaName, pureName, field, search, dataType });
|
|
418
419
|
},
|
|
419
420
|
|
|
420
421
|
callMethod_meta: true,
|
|
421
422
|
async callMethod({ conid, database, method, args }, req) {
|
|
422
|
-
testConnectionPermission(conid, req);
|
|
423
|
+
await testConnectionPermission(conid, req);
|
|
423
424
|
return this.loadDataCore('callMethod', { conid, database, method, args });
|
|
424
425
|
|
|
425
426
|
// const opened = await this.ensureOpened(conid, database);
|
|
@@ -432,7 +433,8 @@ module.exports = {
|
|
|
432
433
|
|
|
433
434
|
updateCollection_meta: true,
|
|
434
435
|
async updateCollection({ conid, database, changeSet }, req) {
|
|
435
|
-
testConnectionPermission(conid, req);
|
|
436
|
+
await testConnectionPermission(conid, req);
|
|
437
|
+
|
|
436
438
|
const opened = await this.ensureOpened(conid, database);
|
|
437
439
|
const res = await this.sendRequest(opened, { msgtype: 'updateCollection', changeSet });
|
|
438
440
|
if (res.errorMessage) {
|
|
@@ -443,6 +445,36 @@ module.exports = {
|
|
|
443
445
|
return res.result || null;
|
|
444
446
|
},
|
|
445
447
|
|
|
448
|
+
saveTableData_meta: true,
|
|
449
|
+
async saveTableData({ conid, database, changeSet }, req) {
|
|
450
|
+
await testConnectionPermission(conid, req);
|
|
451
|
+
|
|
452
|
+
const databasePermissions = await loadDatabasePermissionsFromRequest(req);
|
|
453
|
+
const tablePermissions = await loadTablePermissionsFromRequest(req);
|
|
454
|
+
const fieldsAndRoles = [
|
|
455
|
+
[changeSet.inserts, 'create_update_delete'],
|
|
456
|
+
[changeSet.deletes, 'create_update_delete'],
|
|
457
|
+
[changeSet.updates, 'update_only'],
|
|
458
|
+
]
|
|
459
|
+
for (const [operations, requiredRole] of fieldsAndRoles) {
|
|
460
|
+
for (const operation of operations) {
|
|
461
|
+
const role = getTablePermissionRole(conid, database, 'tables', operation.schemaName, operation.pureName, tablePermissions, databasePermissions);
|
|
462
|
+
if (getTablePermissionRoleLevelIndex(role) < getTablePermissionRoleLevelIndex(requiredRole)) {
|
|
463
|
+
throw new Error('DBGM-00262 Permission not granted');
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const opened = await this.ensureOpened(conid, database);
|
|
469
|
+
const res = await this.sendRequest(opened, { msgtype: 'saveTableData', changeSet });
|
|
470
|
+
if (res.errorMessage) {
|
|
471
|
+
return {
|
|
472
|
+
errorMessage: res.errorMessage,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
return res.result || null;
|
|
476
|
+
},
|
|
477
|
+
|
|
446
478
|
status_meta: true,
|
|
447
479
|
async status({ conid, database }, req) {
|
|
448
480
|
if (!conid) {
|
|
@@ -451,7 +483,7 @@ module.exports = {
|
|
|
451
483
|
message: 'No connection',
|
|
452
484
|
};
|
|
453
485
|
}
|
|
454
|
-
testConnectionPermission(conid, req);
|
|
486
|
+
await testConnectionPermission(conid, req);
|
|
455
487
|
const existing = this.opened.find(x => x.conid == conid && x.database == database);
|
|
456
488
|
if (existing) {
|
|
457
489
|
return {
|
|
@@ -474,7 +506,7 @@ module.exports = {
|
|
|
474
506
|
|
|
475
507
|
ping_meta: true,
|
|
476
508
|
async ping({ conid, database }, req) {
|
|
477
|
-
testConnectionPermission(conid, req);
|
|
509
|
+
await testConnectionPermission(conid, req);
|
|
478
510
|
let existing = this.opened.find(x => x.conid == conid && x.database == database);
|
|
479
511
|
|
|
480
512
|
if (existing) {
|
|
@@ -502,7 +534,7 @@ module.exports = {
|
|
|
502
534
|
|
|
503
535
|
refresh_meta: true,
|
|
504
536
|
async refresh({ conid, database, keepOpen }, req) {
|
|
505
|
-
testConnectionPermission(conid, req);
|
|
537
|
+
await testConnectionPermission(conid, req);
|
|
506
538
|
if (!keepOpen) this.close(conid, database);
|
|
507
539
|
|
|
508
540
|
await this.ensureOpened(conid, database);
|
|
@@ -516,7 +548,7 @@ module.exports = {
|
|
|
516
548
|
return { status: 'ok' };
|
|
517
549
|
}
|
|
518
550
|
|
|
519
|
-
testConnectionPermission(conid, req);
|
|
551
|
+
await testConnectionPermission(conid, req);
|
|
520
552
|
const conn = await this.ensureOpened(conid, database);
|
|
521
553
|
conn.subprocess.send({ msgtype: 'syncModel', isFullRefresh });
|
|
522
554
|
return { status: 'ok' };
|
|
@@ -553,7 +585,7 @@ module.exports = {
|
|
|
553
585
|
|
|
554
586
|
disconnect_meta: true,
|
|
555
587
|
async disconnect({ conid, database }, req) {
|
|
556
|
-
testConnectionPermission(conid, req);
|
|
588
|
+
await testConnectionPermission(conid, req);
|
|
557
589
|
await this.close(conid, database, true);
|
|
558
590
|
return { status: 'ok' };
|
|
559
591
|
},
|
|
@@ -563,8 +595,9 @@ module.exports = {
|
|
|
563
595
|
if (!conid || !database) {
|
|
564
596
|
return {};
|
|
565
597
|
}
|
|
598
|
+
const loadedPermissions = await loadPermissionsFromRequest(req);
|
|
566
599
|
|
|
567
|
-
testConnectionPermission(conid, req);
|
|
600
|
+
await testConnectionPermission(conid, req, loadedPermissions);
|
|
568
601
|
if (conid == '__model') {
|
|
569
602
|
const model = await importDbModel(database);
|
|
570
603
|
const trans = await loadModelTransform(modelTransFile);
|
|
@@ -586,6 +619,38 @@ module.exports = {
|
|
|
586
619
|
message: `Loaded database structure for ${database}`,
|
|
587
620
|
});
|
|
588
621
|
|
|
622
|
+
if (!hasPermission(`all-tables`, loadedPermissions)) {
|
|
623
|
+
// filter databases by permissions
|
|
624
|
+
const tablePermissions = await loadTablePermissionsFromRequest(req);
|
|
625
|
+
const databasePermissions = await loadDatabasePermissionsFromRequest(req);
|
|
626
|
+
const databasePermissionRole = getDatabasePermissionRole(conid, database, databasePermissions);
|
|
627
|
+
|
|
628
|
+
function applyTablePermissionRole(list, objectTypeField) {
|
|
629
|
+
const res = [];
|
|
630
|
+
for (const item of list ?? []) {
|
|
631
|
+
const tablePermissionRole = getTablePermissionRole(conid, database, objectTypeField, item.schemaName, item.pureName, tablePermissions, databasePermissionRole);
|
|
632
|
+
if (tablePermissionRole != 'deny') {
|
|
633
|
+
res.push({
|
|
634
|
+
...item,
|
|
635
|
+
tablePermissionRole,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return res;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const res = {
|
|
643
|
+
...opened.structure,
|
|
644
|
+
tables: applyTablePermissionRole(opened.structure.tables, 'tables'),
|
|
645
|
+
views: applyTablePermissionRole(opened.structure.views, 'views'),
|
|
646
|
+
procedures: applyTablePermissionRole(opened.structure.procedures, 'procedures'),
|
|
647
|
+
functions: applyTablePermissionRole(opened.structure.functions, 'functions'),
|
|
648
|
+
triggers: applyTablePermissionRole(opened.structure.triggers, 'triggers'),
|
|
649
|
+
collections: applyTablePermissionRole(opened.structure.collections, 'collections'),
|
|
650
|
+
}
|
|
651
|
+
return res;
|
|
652
|
+
}
|
|
653
|
+
|
|
589
654
|
return opened.structure;
|
|
590
655
|
// const existing = this.opened.find((x) => x.conid == conid && x.database == database);
|
|
591
656
|
// if (existing) return existing.status;
|
|
@@ -600,7 +665,7 @@ module.exports = {
|
|
|
600
665
|
if (!conid) {
|
|
601
666
|
return null;
|
|
602
667
|
}
|
|
603
|
-
testConnectionPermission(conid, req);
|
|
668
|
+
await testConnectionPermission(conid, req);
|
|
604
669
|
if (!conid) return null;
|
|
605
670
|
const opened = await this.ensureOpened(conid, database);
|
|
606
671
|
return opened.serverVersion || null;
|
|
@@ -608,7 +673,7 @@ module.exports = {
|
|
|
608
673
|
|
|
609
674
|
sqlPreview_meta: true,
|
|
610
675
|
async sqlPreview({ conid, database, objects, options }, req) {
|
|
611
|
-
testConnectionPermission(conid, req);
|
|
676
|
+
await testConnectionPermission(conid, req);
|
|
612
677
|
// wait for structure
|
|
613
678
|
await this.structure({ conid, database });
|
|
614
679
|
|
|
@@ -619,7 +684,7 @@ module.exports = {
|
|
|
619
684
|
|
|
620
685
|
exportModel_meta: true,
|
|
621
686
|
async exportModel({ conid, database, outputFolder, schema }, req) {
|
|
622
|
-
testConnectionPermission(conid, req);
|
|
687
|
+
await testConnectionPermission(conid, req);
|
|
623
688
|
|
|
624
689
|
const realFolder = outputFolder.startsWith('archive:')
|
|
625
690
|
? resolveArchiveFolder(outputFolder.substring('archive:'.length))
|
|
@@ -637,7 +702,7 @@ module.exports = {
|
|
|
637
702
|
|
|
638
703
|
exportModelSql_meta: true,
|
|
639
704
|
async exportModelSql({ conid, database, outputFolder, outputFile, schema }, req) {
|
|
640
|
-
testConnectionPermission(conid, req);
|
|
705
|
+
await testConnectionPermission(conid, req);
|
|
641
706
|
|
|
642
707
|
const connection = await connections.getCore({ conid });
|
|
643
708
|
const driver = requireEngineDriver(connection);
|
|
@@ -651,7 +716,7 @@ module.exports = {
|
|
|
651
716
|
|
|
652
717
|
generateDeploySql_meta: true,
|
|
653
718
|
async generateDeploySql({ conid, database, archiveFolder }, req) {
|
|
654
|
-
testConnectionPermission(conid, req);
|
|
719
|
+
await testConnectionPermission(conid, req);
|
|
655
720
|
const opened = await this.ensureOpened(conid, database);
|
|
656
721
|
const res = await this.sendRequest(opened, {
|
|
657
722
|
msgtype: 'generateDeploySql',
|
|
@@ -816,17 +881,17 @@ module.exports = {
|
|
|
816
881
|
return {
|
|
817
882
|
...(command == 'backup'
|
|
818
883
|
? driver.backupDatabaseCommand(
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
884
|
+
connection,
|
|
885
|
+
{ outputFile, database, options, selectedTables, skippedTables, argsFormat },
|
|
886
|
+
// @ts-ignore
|
|
887
|
+
externalTools
|
|
888
|
+
)
|
|
824
889
|
: driver.restoreDatabaseCommand(
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
890
|
+
connection,
|
|
891
|
+
{ inputFile, database, options, argsFormat },
|
|
892
|
+
// @ts-ignore
|
|
893
|
+
externalTools
|
|
894
|
+
)),
|
|
830
895
|
transformMessage: driver.transformNativeCommandMessage
|
|
831
896
|
? message => driver.transformNativeCommandMessage(message, command)
|
|
832
897
|
: null,
|
|
@@ -923,7 +988,7 @@ module.exports = {
|
|
|
923
988
|
|
|
924
989
|
executeSessionQuery_meta: true,
|
|
925
990
|
async executeSessionQuery({ sesid, conid, database, sql }, req) {
|
|
926
|
-
testConnectionPermission(conid, req);
|
|
991
|
+
await testConnectionPermission(conid, req);
|
|
927
992
|
logger.info({ sesid, sql }, 'DBGM-00010 Processing query');
|
|
928
993
|
sessions.dispatchMessage(sesid, 'Query execution started');
|
|
929
994
|
|
|
@@ -935,7 +1000,7 @@ module.exports = {
|
|
|
935
1000
|
|
|
936
1001
|
evalJsonScript_meta: true,
|
|
937
1002
|
async evalJsonScript({ conid, database, script, runid }, req) {
|
|
938
|
-
testConnectionPermission(conid, req);
|
|
1003
|
+
await testConnectionPermission(conid, req);
|
|
939
1004
|
const opened = await this.ensureOpened(conid, database);
|
|
940
1005
|
|
|
941
1006
|
opened.subprocess.send({ msgtype: 'evalJsonScript', script, runid });
|