dbgate-api-premium 6.6.1 → 6.6.3
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/auth/storageAuthProvider.js +87 -20
- 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 +75 -11
- package/src/controllers/storageDb.js +114 -1
- 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/authProxy.js +1 -1
- package/src/utility/hasPermission.js +286 -71
|
@@ -8,7 +8,13 @@ const { handleProcessCommunication } = require('../utility/processComm');
|
|
|
8
8
|
const lock = new AsyncLock();
|
|
9
9
|
const config = require('./config');
|
|
10
10
|
const processArgs = require('../utility/processArgs');
|
|
11
|
-
const {
|
|
11
|
+
const {
|
|
12
|
+
testConnectionPermission,
|
|
13
|
+
loadPermissionsFromRequest,
|
|
14
|
+
hasPermission,
|
|
15
|
+
loadDatabasePermissionsFromRequest,
|
|
16
|
+
getDatabasePermissionRole,
|
|
17
|
+
} = require('../utility/hasPermission');
|
|
12
18
|
const { MissingCredentialsError } = require('../utility/exceptions');
|
|
13
19
|
const pipeForkLogs = require('../utility/pipeForkLogs');
|
|
14
20
|
const { getLogger, extractErrorLogData } = require('dbgate-tools');
|
|
@@ -40,7 +46,7 @@ module.exports = {
|
|
|
40
46
|
existing.status = status;
|
|
41
47
|
socket.emitChanged(`server-status-changed`);
|
|
42
48
|
},
|
|
43
|
-
handle_ping() {},
|
|
49
|
+
handle_ping() { },
|
|
44
50
|
handle_response(conid, { msgid, ...response }) {
|
|
45
51
|
const [resolve, reject] = this.requests[msgid];
|
|
46
52
|
resolve(response);
|
|
@@ -135,7 +141,7 @@ module.exports = {
|
|
|
135
141
|
|
|
136
142
|
disconnect_meta: true,
|
|
137
143
|
async disconnect({ conid }, req) {
|
|
138
|
-
testConnectionPermission(conid, req);
|
|
144
|
+
await testConnectionPermission(conid, req);
|
|
139
145
|
await this.close(conid, true);
|
|
140
146
|
return { status: 'ok' };
|
|
141
147
|
},
|
|
@@ -144,7 +150,9 @@ module.exports = {
|
|
|
144
150
|
async listDatabases({ conid }, req) {
|
|
145
151
|
if (!conid) return [];
|
|
146
152
|
if (conid == '__model') return [];
|
|
147
|
-
|
|
153
|
+
const loadedPermissions = await loadPermissionsFromRequest(req);
|
|
154
|
+
|
|
155
|
+
await testConnectionPermission(conid, req, loadedPermissions);
|
|
148
156
|
const opened = await this.ensureOpened(conid);
|
|
149
157
|
sendToAuditLog(req, {
|
|
150
158
|
category: 'serverop',
|
|
@@ -157,12 +165,29 @@ module.exports = {
|
|
|
157
165
|
sessionGroup: 'listDatabases',
|
|
158
166
|
message: `Loaded databases for connection`,
|
|
159
167
|
});
|
|
168
|
+
|
|
169
|
+
if (!hasPermission(`all-databases`, loadedPermissions)) {
|
|
170
|
+
// filter databases by permissions
|
|
171
|
+
const databasePermissions = await loadDatabasePermissionsFromRequest(req);
|
|
172
|
+
const res = [];
|
|
173
|
+
for (const db of opened?.databases ?? []) {
|
|
174
|
+
const databasePermissionRole = getDatabasePermissionRole(db.id, db.name, databasePermissions);
|
|
175
|
+
if (databasePermissionRole != 'deny') {
|
|
176
|
+
res.push({
|
|
177
|
+
...db,
|
|
178
|
+
databasePermissionRole,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return res;
|
|
183
|
+
}
|
|
184
|
+
|
|
160
185
|
return opened?.databases ?? [];
|
|
161
186
|
},
|
|
162
187
|
|
|
163
188
|
version_meta: true,
|
|
164
189
|
async version({ conid }, req) {
|
|
165
|
-
testConnectionPermission(conid, req);
|
|
190
|
+
await testConnectionPermission(conid, req);
|
|
166
191
|
const opened = await this.ensureOpened(conid);
|
|
167
192
|
return opened?.version ?? null;
|
|
168
193
|
},
|
|
@@ -202,7 +227,7 @@ module.exports = {
|
|
|
202
227
|
|
|
203
228
|
refresh_meta: true,
|
|
204
229
|
async refresh({ conid, keepOpen }, req) {
|
|
205
|
-
testConnectionPermission(conid, req);
|
|
230
|
+
await testConnectionPermission(conid, req);
|
|
206
231
|
if (!keepOpen) this.close(conid);
|
|
207
232
|
|
|
208
233
|
await this.ensureOpened(conid);
|
|
@@ -210,7 +235,7 @@ module.exports = {
|
|
|
210
235
|
},
|
|
211
236
|
|
|
212
237
|
async sendDatabaseOp({ conid, msgtype, name }, req) {
|
|
213
|
-
testConnectionPermission(conid, req);
|
|
238
|
+
await testConnectionPermission(conid, req);
|
|
214
239
|
const opened = await this.ensureOpened(conid);
|
|
215
240
|
if (!opened) {
|
|
216
241
|
return null;
|
|
@@ -252,7 +277,7 @@ module.exports = {
|
|
|
252
277
|
},
|
|
253
278
|
|
|
254
279
|
async loadDataCore(msgtype, { conid, ...args }, req) {
|
|
255
|
-
testConnectionPermission(conid, req);
|
|
280
|
+
await testConnectionPermission(conid, req);
|
|
256
281
|
const opened = await this.ensureOpened(conid);
|
|
257
282
|
if (!opened) {
|
|
258
283
|
return null;
|
|
@@ -270,13 +295,43 @@ module.exports = {
|
|
|
270
295
|
|
|
271
296
|
serverSummary_meta: true,
|
|
272
297
|
async serverSummary({ conid }, req) {
|
|
273
|
-
testConnectionPermission(conid, req);
|
|
298
|
+
await testConnectionPermission(conid, req);
|
|
299
|
+
logger.info({ conid }, 'DBGM-00260 Processing server summary');
|
|
274
300
|
return this.loadDataCore('serverSummary', { conid });
|
|
275
301
|
},
|
|
276
302
|
|
|
303
|
+
listDatabaseProcesses_meta: true,
|
|
304
|
+
async listDatabaseProcesses(ctx, req) {
|
|
305
|
+
const { conid } = ctx;
|
|
306
|
+
// logger.info({ conid }, 'DBGM-00261 Listing processes of database server');
|
|
307
|
+
testConnectionPermission(conid, req);
|
|
308
|
+
|
|
309
|
+
const opened = await this.ensureOpened(conid);
|
|
310
|
+
if (!opened) {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
if (opened.connection.isReadOnly) return false;
|
|
314
|
+
|
|
315
|
+
return this.sendRequest(opened, { msgtype: 'listDatabaseProcesses' });
|
|
316
|
+
},
|
|
317
|
+
|
|
318
|
+
killDatabaseProcess_meta: true,
|
|
319
|
+
async killDatabaseProcess(ctx, req) {
|
|
320
|
+
const { conid, pid } = ctx;
|
|
321
|
+
testConnectionPermission(conid, req);
|
|
322
|
+
|
|
323
|
+
const opened = await this.ensureOpened(conid);
|
|
324
|
+
if (!opened) {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
if (opened.connection.isReadOnly) return false;
|
|
328
|
+
|
|
329
|
+
return this.sendRequest(opened, { msgtype: 'killDatabaseProcess', pid });
|
|
330
|
+
},
|
|
331
|
+
|
|
277
332
|
summaryCommand_meta: true,
|
|
278
333
|
async summaryCommand({ conid, command, row }, req) {
|
|
279
|
-
testConnectionPermission(conid, req);
|
|
334
|
+
await testConnectionPermission(conid, req);
|
|
280
335
|
const opened = await this.ensureOpened(conid);
|
|
281
336
|
if (!opened) {
|
|
282
337
|
return null;
|
|
@@ -12,6 +12,7 @@ const { getLogger, extractErrorLogData } = require('dbgate-tools');
|
|
|
12
12
|
const pipeForkLogs = require('../utility/pipeForkLogs');
|
|
13
13
|
const config = require('./config');
|
|
14
14
|
const { sendToAuditLog } = require('../utility/auditlog');
|
|
15
|
+
const { testStandardPermission, testDatabaseRolePermission } = require('../utility/hasPermission');
|
|
15
16
|
|
|
16
17
|
const logger = getLogger('sessions');
|
|
17
18
|
|
|
@@ -94,7 +95,7 @@ module.exports = {
|
|
|
94
95
|
socket.emit(`session-initialize-file-${jslid}`);
|
|
95
96
|
},
|
|
96
97
|
|
|
97
|
-
handle_ping() {},
|
|
98
|
+
handle_ping() { },
|
|
98
99
|
|
|
99
100
|
create_meta: true,
|
|
100
101
|
async create({ conid, database }) {
|
|
@@ -148,10 +149,12 @@ module.exports = {
|
|
|
148
149
|
|
|
149
150
|
executeQuery_meta: true,
|
|
150
151
|
async executeQuery({ sesid, sql, autoCommit, autoDetectCharts, limitRows, frontMatter }, req) {
|
|
152
|
+
await testStandardPermission('dbops/query', req);
|
|
151
153
|
const session = this.opened.find(x => x.sesid == sesid);
|
|
152
154
|
if (!session) {
|
|
153
155
|
throw new Error('Invalid session');
|
|
154
156
|
}
|
|
157
|
+
await testDatabaseRolePermission(session.conid, session.database, 'run_script', req);
|
|
155
158
|
|
|
156
159
|
sendToAuditLog(req, {
|
|
157
160
|
category: 'dbop',
|
|
@@ -2,20 +2,20 @@ const fs = require('fs-extra');
|
|
|
2
2
|
const _ = require('lodash');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const { setAuthProviders, getAuthProviderById } = require('../auth/authProvider');
|
|
5
|
-
const { createStorageAuthProvider } = require('../auth/storageAuthProvider');
|
|
5
|
+
const { createStorageAuthProvider, SuperadminAuthProvider } = require('../auth/storageAuthProvider');
|
|
6
6
|
const {
|
|
7
7
|
getStorageConnection,
|
|
8
8
|
getDbConnectionParams,
|
|
9
9
|
storageSelectFmt,
|
|
10
10
|
storageReadUserRolePermissions,
|
|
11
|
-
loadSuperadminPermissions,
|
|
12
11
|
storageReadConfig,
|
|
13
12
|
storageWriteConfig,
|
|
14
13
|
getStorageConnectionError,
|
|
15
14
|
storageSaveRelationDiff,
|
|
16
15
|
selectStorageIdentity,
|
|
16
|
+
storageSaveDetailPermissionsDiff,
|
|
17
17
|
} = require('./storageDb');
|
|
18
|
-
const { hasPermission } = require('../utility/hasPermission');
|
|
18
|
+
const { hasPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
|
19
19
|
const { changeSetToSql, removeSchemaFromChangeSet } = require('dbgate-datalib');
|
|
20
20
|
const storageModel = require('../storageModel');
|
|
21
21
|
const { dumpSqlCommand, dumpSqlSelect, createLogCompoudCondition } = require('dbgate-sqltree');
|
|
@@ -64,6 +64,7 @@ module.exports = {
|
|
|
64
64
|
if (defIndex < 0) {
|
|
65
65
|
defIndex = enabledConfig.findIndex(x => x.type == 'local');
|
|
66
66
|
}
|
|
67
|
+
providers.push(new SuperadminAuthProvider());
|
|
67
68
|
|
|
68
69
|
setAuthProviders(providers, providers[defIndex]);
|
|
69
70
|
|
|
@@ -112,6 +113,7 @@ module.exports = {
|
|
|
112
113
|
|
|
113
114
|
connections_meta: true,
|
|
114
115
|
async connections(req) {
|
|
116
|
+
const loadedPermissions = await loadPermissionsFromRequest(req);
|
|
115
117
|
if (!process.env.STORAGE_DATABASE) {
|
|
116
118
|
return null;
|
|
117
119
|
}
|
|
@@ -121,7 +123,7 @@ module.exports = {
|
|
|
121
123
|
|
|
122
124
|
let resp = null;
|
|
123
125
|
|
|
124
|
-
if (hasPermission('all-connections',
|
|
126
|
+
if (hasPermission('all-connections', loadedPermissions)) {
|
|
125
127
|
resp = await storageSelectFmt(`select ~connections.* from ~connections`);
|
|
126
128
|
} else if (userId) {
|
|
127
129
|
resp = await storageSelectFmt(
|
|
@@ -152,7 +154,7 @@ module.exports = {
|
|
|
152
154
|
return [];
|
|
153
155
|
}
|
|
154
156
|
const res = [];
|
|
155
|
-
if (hasPermission('internal-storage',
|
|
157
|
+
if (hasPermission('internal-storage', loadedPermissions)) {
|
|
156
158
|
res.push(await this.getConnection({ conid: '__storage' }));
|
|
157
159
|
}
|
|
158
160
|
if (resp) {
|
|
@@ -329,10 +331,6 @@ module.exports = {
|
|
|
329
331
|
return storageReadUserRolePermissions(userId);
|
|
330
332
|
},
|
|
331
333
|
|
|
332
|
-
async loadSuperadminPermissions() {
|
|
333
|
-
return loadSuperadminPermissions();
|
|
334
|
-
},
|
|
335
|
-
|
|
336
334
|
getConnectionsForLoginPage_meta: true,
|
|
337
335
|
getConnectionsForLoginPage({ amoid }) {
|
|
338
336
|
return getAuthProviderById(amoid).getLoginPageConnections();
|
|
@@ -487,6 +485,10 @@ module.exports = {
|
|
|
487
485
|
: (await storageSelectFmt('select ~connection_id from ~user_connections where ~user_id = %v', id)).map(
|
|
488
486
|
x => x.connection_id
|
|
489
487
|
);
|
|
488
|
+
const databasePermissions =
|
|
489
|
+
id == 'new' ? [] : await storageSelectFmt('select * from ~user_databases where ~user_id = %v', id);
|
|
490
|
+
const tablePermissions =
|
|
491
|
+
id == 'new' ? [] : await storageSelectFmt('select * from ~user_tables where ~user_id = %v', id);
|
|
490
492
|
|
|
491
493
|
return {
|
|
492
494
|
...resp[0],
|
|
@@ -496,6 +498,8 @@ module.exports = {
|
|
|
496
498
|
usedRoles,
|
|
497
499
|
allConnections,
|
|
498
500
|
usedConnections,
|
|
501
|
+
databasePermissions,
|
|
502
|
+
tablePermissions,
|
|
499
503
|
encryptPassword: !!(resp[0]?.password?.startsWith('crypt:') || id == 'new'),
|
|
500
504
|
};
|
|
501
505
|
},
|
|
@@ -504,7 +508,8 @@ module.exports = {
|
|
|
504
508
|
async saveUserDetail(user) {
|
|
505
509
|
const [conn, driver] = await getStorageConnection();
|
|
506
510
|
|
|
507
|
-
const { login, password, email, usedRoles, usedConnections, permissions } =
|
|
511
|
+
const { login, password, email, usedRoles, usedConnections, permissions, databasePermissions, tablePermissions } =
|
|
512
|
+
encryptUser(user);
|
|
508
513
|
let id = user.id;
|
|
509
514
|
|
|
510
515
|
if (id == null) {
|
|
@@ -533,6 +538,32 @@ module.exports = {
|
|
|
533
538
|
await storageSaveRelationDiff('user_roles', 'user_id', 'role_id', id, usedRoles);
|
|
534
539
|
await storageSaveRelationDiff('user_connections', 'user_id', 'connection_id', id, usedConnections);
|
|
535
540
|
|
|
541
|
+
await storageSaveDetailPermissionsDiff(
|
|
542
|
+
'user_databases',
|
|
543
|
+
'user_id',
|
|
544
|
+
id,
|
|
545
|
+
['connection_id', 'database_names_list', 'database_names_regex', 'database_permission_role_id'],
|
|
546
|
+
databasePermissions
|
|
547
|
+
);
|
|
548
|
+
|
|
549
|
+
await storageSaveDetailPermissionsDiff(
|
|
550
|
+
'user_tables',
|
|
551
|
+
'user_id',
|
|
552
|
+
id,
|
|
553
|
+
[
|
|
554
|
+
'connection_id',
|
|
555
|
+
'database_names_list',
|
|
556
|
+
'database_names_regex',
|
|
557
|
+
'schema_names_list',
|
|
558
|
+
'schema_names_regex',
|
|
559
|
+
'table_names_list',
|
|
560
|
+
'table_names_regex',
|
|
561
|
+
'table_permission_role_id',
|
|
562
|
+
'table_permission_scope_id',
|
|
563
|
+
],
|
|
564
|
+
tablePermissions
|
|
565
|
+
);
|
|
566
|
+
|
|
536
567
|
return true;
|
|
537
568
|
},
|
|
538
569
|
|
|
@@ -677,6 +708,11 @@ module.exports = {
|
|
|
677
708
|
: (await storageSelectFmt('select ~connection_id from ~role_connections where ~role_id = %v', id)).map(
|
|
678
709
|
x => x.connection_id
|
|
679
710
|
);
|
|
711
|
+
const databasePermissions =
|
|
712
|
+
id == 'new' ? [] : await storageSelectFmt('select * from ~role_databases where ~role_id = %v', id);
|
|
713
|
+
const tablePermissions =
|
|
714
|
+
id == 'new' ? [] : await storageSelectFmt('select * from ~role_tables where ~role_id = %v', id);
|
|
715
|
+
|
|
680
716
|
|
|
681
717
|
return {
|
|
682
718
|
...resp[0],
|
|
@@ -686,6 +722,8 @@ module.exports = {
|
|
|
686
722
|
usedUsers,
|
|
687
723
|
allConnections,
|
|
688
724
|
usedConnections,
|
|
725
|
+
databasePermissions,
|
|
726
|
+
tablePermissions,
|
|
689
727
|
};
|
|
690
728
|
},
|
|
691
729
|
|
|
@@ -705,7 +743,7 @@ module.exports = {
|
|
|
705
743
|
async saveRoleDetail(role) {
|
|
706
744
|
const [conn, driver] = await getStorageConnection();
|
|
707
745
|
|
|
708
|
-
const { name, usedConnections, usedUsers, permissions } =
|
|
746
|
+
const { name, usedConnections, usedUsers, permissions, databasePermissions, tablePermissions } = role;
|
|
709
747
|
let id = role.id;
|
|
710
748
|
|
|
711
749
|
if (id == null) {
|
|
@@ -721,6 +759,32 @@ module.exports = {
|
|
|
721
759
|
await storageSaveRelationDiff('user_roles', 'role_id', 'user_id', id, usedUsers);
|
|
722
760
|
await storageSaveRelationDiff('role_connections', 'role_id', 'connection_id', id, usedConnections);
|
|
723
761
|
|
|
762
|
+
await storageSaveDetailPermissionsDiff(
|
|
763
|
+
'role_databases',
|
|
764
|
+
'role_id',
|
|
765
|
+
id,
|
|
766
|
+
['connection_id', 'database_names_list', 'database_names_regex', 'database_permission_role_id'],
|
|
767
|
+
databasePermissions
|
|
768
|
+
);
|
|
769
|
+
|
|
770
|
+
await storageSaveDetailPermissionsDiff(
|
|
771
|
+
'role_tables',
|
|
772
|
+
'role_id',
|
|
773
|
+
id,
|
|
774
|
+
[
|
|
775
|
+
'connection_id',
|
|
776
|
+
'database_names_list',
|
|
777
|
+
'database_names_regex',
|
|
778
|
+
'schema_names_list',
|
|
779
|
+
'schema_names_regex',
|
|
780
|
+
'table_names_list',
|
|
781
|
+
'table_names_regex',
|
|
782
|
+
'table_permission_role_id',
|
|
783
|
+
'table_permission_scope_id',
|
|
784
|
+
],
|
|
785
|
+
tablePermissions
|
|
786
|
+
);
|
|
787
|
+
|
|
724
788
|
return true;
|
|
725
789
|
},
|
|
726
790
|
|
|
@@ -104,7 +104,9 @@ async function getStorageConnectionCore() {
|
|
|
104
104
|
try {
|
|
105
105
|
newConnection = await storageDriver.connect(dbConnectionParams);
|
|
106
106
|
const version = await storageDriver.getVersion(newConnection);
|
|
107
|
-
logger.info(
|
|
107
|
+
logger.info(
|
|
108
|
+
`DBGM-00023 Connected to storage database ${dbConnectionParams.engine}, version ${version?.versionText}`
|
|
109
|
+
);
|
|
108
110
|
storageConnectionError = null;
|
|
109
111
|
} catch (err) {
|
|
110
112
|
storageConnectionError = err;
|
|
@@ -217,6 +219,34 @@ async function storageReadRolePermissions(roleId) {
|
|
|
217
219
|
return resp.map(x => x.permission);
|
|
218
220
|
}
|
|
219
221
|
|
|
222
|
+
async function readComplexUserRolePermissions(userId, userPermissionsTable, rolePermissionsTable) {
|
|
223
|
+
const rolePermissionsResp = await storageSelectFmt(
|
|
224
|
+
'select * from %i where %i.~role_id in (select ~role_id from ~user_roles where ~user_roles.~user_id = %v)',
|
|
225
|
+
rolePermissionsTable,
|
|
226
|
+
rolePermissionsTable,
|
|
227
|
+
userId
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
const userPermissionsResp = await storageSelectFmt(
|
|
231
|
+
'select * from %i where %i.~user_id = %v',
|
|
232
|
+
userPermissionsTable,
|
|
233
|
+
userPermissionsTable,
|
|
234
|
+
userId
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
return [...rolePermissionsResp, ...userPermissionsResp];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async function readComplexRolePermissions(roleId, rolePermissionsTable) {
|
|
241
|
+
const rolePermissionsResp = await storageSelectFmt(
|
|
242
|
+
'select * from %i where %i.~role_id = %v',
|
|
243
|
+
rolePermissionsTable,
|
|
244
|
+
rolePermissionsTable,
|
|
245
|
+
roleId
|
|
246
|
+
);
|
|
247
|
+
return rolePermissionsResp;
|
|
248
|
+
}
|
|
249
|
+
|
|
220
250
|
async function loadSuperadminPermissions() {
|
|
221
251
|
const rolePermissions = await storageReadRolePermissions(-3);
|
|
222
252
|
return [...getPredefinedPermissions('superadmin'), ...rolePermissions];
|
|
@@ -284,6 +314,57 @@ async function storageSaveRelationDiff(table, idColumn, valueColumn, idValue, ne
|
|
|
284
314
|
}
|
|
285
315
|
}
|
|
286
316
|
|
|
317
|
+
function sanitizePermissionCollectionRow(collectionRow, valueColumns) {
|
|
318
|
+
const res = {};
|
|
319
|
+
let hasValue = false;
|
|
320
|
+
for (const col of valueColumns) {
|
|
321
|
+
if (col.endsWith('_list') || col.endsWith('_regex')) {
|
|
322
|
+
res[col] = collectionRow[col]?.trim() ? collectionRow[col]?.trim() : null;
|
|
323
|
+
} else if (col.endsWith('_id')) {
|
|
324
|
+
res[col] = collectionRow[col] ? parseInt(collectionRow[col]) : null;
|
|
325
|
+
} else {
|
|
326
|
+
res[col] = collectionRow[col] || null;
|
|
327
|
+
}
|
|
328
|
+
if (res[col]) {
|
|
329
|
+
hasValue = true;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (!hasValue) {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
return res;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async function storageSaveDetailPermissionsDiff(table, idColumn, idValue, valueColumns, valuesCollection) {
|
|
339
|
+
const [conn, driver] = await getStorageConnection();
|
|
340
|
+
if (!conn) {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (valuesCollection) {
|
|
345
|
+
// Delete existing database permissions for this user
|
|
346
|
+
await runQueryFmt(driver, conn, 'delete from %i where %i = %v', table, idColumn, idValue);
|
|
347
|
+
|
|
348
|
+
// Insert new database permissions
|
|
349
|
+
for (const collectionRow of valuesCollection) {
|
|
350
|
+
const sanitizedRow = sanitizePermissionCollectionRow(collectionRow, valueColumns);
|
|
351
|
+
if (!sanitizedRow) {
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
await runQueryFmt(
|
|
355
|
+
driver,
|
|
356
|
+
conn,
|
|
357
|
+
'insert into %i (%i, %,i) values (%v, %,v)',
|
|
358
|
+
table,
|
|
359
|
+
idColumn,
|
|
360
|
+
valueColumns,
|
|
361
|
+
idValue,
|
|
362
|
+
valueColumns.map(col => sanitizedRow[col])
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
287
368
|
function getStorageConnectionError() {
|
|
288
369
|
return storageConnectionError;
|
|
289
370
|
}
|
|
@@ -301,6 +382,33 @@ async function selectStorageIdentity(tableName) {
|
|
|
301
382
|
return Object.entries(resp.rows[0])[0][1];
|
|
302
383
|
}
|
|
303
384
|
|
|
385
|
+
async function storageCheckRoleConnectionAccess(roleId, conid) {
|
|
386
|
+
const resp = await storageSelectFmt(
|
|
387
|
+
'select 1 from ~role_connections inner join ~connections on ~role_connections.~connection_id = ~connections.~id where ~role_connections.~role_id = %v and ~connections.~conid = %v',
|
|
388
|
+
roleId,
|
|
389
|
+
conid
|
|
390
|
+
);
|
|
391
|
+
return resp.length > 0;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
async function storageCheckUserRoleConnectionAccess(userId, conid) {
|
|
395
|
+
const respByUser = await storageSelectFmt(
|
|
396
|
+
'select 1 from ~user_connections inner join ~connections on ~user_connections.~connection_id = ~connections.~id where ~user_connections.~user_id = %v and ~connections.~conid = %v',
|
|
397
|
+
userId,
|
|
398
|
+
conid
|
|
399
|
+
);
|
|
400
|
+
const respByRole = await storageSelectFmt(
|
|
401
|
+
'select 1 from ~role_connections inner join ~user_roles on ~role_connections.~role_id = ~user_roles.~role_id inner join ~connections on ~role_connections.~connection_id = ~connections.~id where ~user_roles.~user_id = %v and ~connections.~conid = %v',
|
|
402
|
+
userId,
|
|
403
|
+
conid
|
|
404
|
+
);
|
|
405
|
+
const respByLogged = await storageSelectFmt(
|
|
406
|
+
'select 1 from ~role_connections inner join ~connections on ~role_connections.~connection_id = ~connections.~id where ~role_connections.~role_id = -2 and ~connections.~conid = %v',
|
|
407
|
+
conid
|
|
408
|
+
);
|
|
409
|
+
return respByUser.length > 0 || respByRole.length > 0 || respByLogged.length > 0;
|
|
410
|
+
}
|
|
411
|
+
|
|
304
412
|
module.exports = {
|
|
305
413
|
getStorageConnection,
|
|
306
414
|
storageSelectFmt,
|
|
@@ -315,4 +423,9 @@ module.exports = {
|
|
|
315
423
|
storageSqlCommandFmt,
|
|
316
424
|
storageSaveRelationDiff,
|
|
317
425
|
selectStorageIdentity,
|
|
426
|
+
storageSaveDetailPermissionsDiff,
|
|
427
|
+
readComplexUserRolePermissions,
|
|
428
|
+
readComplexRolePermissions,
|
|
429
|
+
storageCheckRoleConnectionAccess,
|
|
430
|
+
storageCheckUserRoleConnectionAccess,
|
|
318
431
|
};
|
package/src/currentVersion.js
CHANGED
package/src/index.js
CHANGED
|
@@ -5,6 +5,7 @@ const moment = require('moment');
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const { logsdir, setLogsFilePath, getLogsFilePath } = require('./utility/directories');
|
|
7
7
|
const currentVersion = require('./currentVersion');
|
|
8
|
+
const _ = require('lodash');
|
|
8
9
|
|
|
9
10
|
const logger = getLogger('apiIndex');
|
|
10
11
|
|
|
@@ -68,7 +69,7 @@ function configureLogger() {
|
|
|
68
69
|
}
|
|
69
70
|
const additionals = {};
|
|
70
71
|
const finalMsg =
|
|
71
|
-
msg.msg && msg.msg.match(/^DBGM-\d\d\d\d\d/)
|
|
72
|
+
_.isString(msg.msg) && msg.msg.match(/^DBGM-\d\d\d\d\d/)
|
|
72
73
|
? {
|
|
73
74
|
...msg,
|
|
74
75
|
msg: msg.msg.substring(10).trimStart(),
|
|
@@ -17,13 +17,14 @@ const requireEngineDriver = require('../utility/requireEngineDriver');
|
|
|
17
17
|
const { connectUtility } = require('../utility/connectUtility');
|
|
18
18
|
const { handleProcessCommunication } = require('../utility/processComm');
|
|
19
19
|
const generateDeploySql = require('../shell/generateDeploySql');
|
|
20
|
-
const { dumpSqlSelect } = require('dbgate-sqltree');
|
|
20
|
+
const { dumpSqlSelect, scriptToSql } = require('dbgate-sqltree');
|
|
21
21
|
const { allowExecuteCustomScript, handleQueryStream } = require('../utility/handleQueryStream');
|
|
22
22
|
const dbgateApi = require('../shell');
|
|
23
23
|
const requirePlugin = require('../shell/requirePlugin');
|
|
24
24
|
const path = require('path');
|
|
25
25
|
const { rundir } = require('../utility/directories');
|
|
26
26
|
const fs = require('fs-extra');
|
|
27
|
+
const { changeSetToSql } = require('dbgate-datalib');
|
|
27
28
|
|
|
28
29
|
const logger = getLogger('dbconnProcess');
|
|
29
30
|
|
|
@@ -348,6 +349,27 @@ async function handleUpdateCollection({ msgid, changeSet }) {
|
|
|
348
349
|
}
|
|
349
350
|
}
|
|
350
351
|
|
|
352
|
+
async function handleSaveTableData({ msgid, changeSet }) {
|
|
353
|
+
await waitStructure();
|
|
354
|
+
try {
|
|
355
|
+
const driver = requireEngineDriver(storedConnection);
|
|
356
|
+
const script = driver.createSaveChangeSetScript(changeSet, analysedStructure, () =>
|
|
357
|
+
changeSetToSql(changeSet, analysedStructure, driver.dialect)
|
|
358
|
+
);
|
|
359
|
+
const sql = scriptToSql(driver, script);
|
|
360
|
+
await driver.script(dbhan, sql, { useTransaction: true });
|
|
361
|
+
process.send({ msgtype: 'response', msgid });
|
|
362
|
+
} catch (err) {
|
|
363
|
+
process.send({
|
|
364
|
+
msgtype: 'response',
|
|
365
|
+
msgid,
|
|
366
|
+
errorMessage: extractErrorMessage(err, 'Error executing SQL script'),
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
}
|
|
372
|
+
|
|
351
373
|
async function handleSqlPreview({ msgid, objects, options }) {
|
|
352
374
|
await waitStructure();
|
|
353
375
|
const driver = requireEngineDriver(storedConnection);
|
|
@@ -464,6 +486,7 @@ const messageHandlers = {
|
|
|
464
486
|
runScript: handleRunScript,
|
|
465
487
|
runOperation: handleRunOperation,
|
|
466
488
|
updateCollection: handleUpdateCollection,
|
|
489
|
+
saveTableData: handleSaveTableData,
|
|
467
490
|
collectionData: handleCollectionData,
|
|
468
491
|
loadKeys: handleLoadKeys,
|
|
469
492
|
scanKeys: handleScanKeys,
|
|
@@ -146,6 +146,30 @@ async function handleServerSummary({ msgid }) {
|
|
|
146
146
|
return handleDriverDataCore(msgid, driver => driver.serverSummary(dbhan));
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
async function handleKillDatabaseProcess({ msgid, pid }) {
|
|
150
|
+
await waitConnected();
|
|
151
|
+
const driver = requireEngineDriver(storedConnection);
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
const result = await driver.killProcess(dbhan, Number(pid));
|
|
155
|
+
process.send({ msgtype: 'response', msgid, result });
|
|
156
|
+
} catch (err) {
|
|
157
|
+
process.send({ msgtype: 'response', msgid, errorMessage: err.message });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function handleListDatabaseProcesses({ msgid }) {
|
|
162
|
+
await waitConnected();
|
|
163
|
+
const driver = requireEngineDriver(storedConnection);
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
const result = await driver.listProcesses(dbhan);
|
|
167
|
+
process.send({ msgtype: 'response', msgid, result });
|
|
168
|
+
} catch (err) {
|
|
169
|
+
process.send({ msgtype: 'response', msgid, errorMessage: err.message });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
149
173
|
async function handleSummaryCommand({ msgid, command, row }) {
|
|
150
174
|
return handleDriverDataCore(msgid, driver => driver.summaryCommand(dbhan, command, row));
|
|
151
175
|
}
|
|
@@ -154,6 +178,8 @@ const messageHandlers = {
|
|
|
154
178
|
connect: handleConnect,
|
|
155
179
|
ping: handlePing,
|
|
156
180
|
serverSummary: handleServerSummary,
|
|
181
|
+
killDatabaseProcess: handleKillDatabaseProcess,
|
|
182
|
+
listDatabaseProcesses: handleListDatabaseProcesses,
|
|
157
183
|
summaryCommand: handleSummaryCommand,
|
|
158
184
|
createDatabase: props => handleDatabaseOp('createDatabase', props),
|
|
159
185
|
dropDatabase: props => handleDatabaseOp('dropDatabase', props),
|