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
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dbgate-api-premium",
|
|
3
3
|
"main": "src/index.js",
|
|
4
|
-
"version": "6.6.
|
|
4
|
+
"version": "6.6.3",
|
|
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.3",
|
|
34
34
|
"dbgate-query-splitter": "^4.11.5",
|
|
35
|
-
"dbgate-sqltree": "^6.6.
|
|
36
|
-
"dbgate-tools": "^6.6.
|
|
35
|
+
"dbgate-sqltree": "^6.6.3",
|
|
36
|
+
"dbgate-tools": "^6.6.3",
|
|
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.3",
|
|
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
|
}
|
|
@@ -11,6 +11,11 @@ const {
|
|
|
11
11
|
storageReadUserPermissions,
|
|
12
12
|
storageReadRolePermissions,
|
|
13
13
|
storageSqlCommandFmt,
|
|
14
|
+
loadSuperadminPermissions,
|
|
15
|
+
readComplexUserRolePermissions,
|
|
16
|
+
readComplexRolePermissions,
|
|
17
|
+
storageCheckRoleConnectionAccess,
|
|
18
|
+
storageCheckUserRoleConnectionAccess,
|
|
14
19
|
} = require('../controllers/storageDb');
|
|
15
20
|
const { getTokenSecret, getTokenLifetime } = require('./authCommon');
|
|
16
21
|
const { AuthProviderBase } = require('./authProvider');
|
|
@@ -31,6 +36,34 @@ async function loadPermissionsForUserId(userId) {
|
|
|
31
36
|
return [...getPredefinedPermissions('logged-user'), ...loggedUserPermissions, ...rolePermissions, ...userPermissions];
|
|
32
37
|
}
|
|
33
38
|
|
|
39
|
+
class SuperadminAuthProvider extends AuthProviderBase {
|
|
40
|
+
constructor() {
|
|
41
|
+
super();
|
|
42
|
+
this.amoid = 'superadmin';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// @ts-ignore
|
|
46
|
+
async getCurrentPermissions(req) {
|
|
47
|
+
const permissions = await loadSuperadminPermissions();
|
|
48
|
+
return permissions;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async getCurrentDatabasePermissions(req) {
|
|
52
|
+
const databasePermissions = await readComplexRolePermissions(-3, 'role_databases');
|
|
53
|
+
return databasePermissions;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async getCurrentTablePermissions(req) {
|
|
57
|
+
const tablePermissions = await readComplexRolePermissions(-3, 'role_tables');
|
|
58
|
+
return tablePermissions;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async checkCurrentConnectionPermission(req, conid) {
|
|
62
|
+
const res = await storageCheckRoleConnectionAccess(-3, conid);
|
|
63
|
+
return res;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
34
67
|
class StorageProviderBase extends AuthProviderBase {
|
|
35
68
|
constructor(config) {
|
|
36
69
|
super();
|
|
@@ -38,10 +71,6 @@ class StorageProviderBase extends AuthProviderBase {
|
|
|
38
71
|
this.amoid = config.amoid;
|
|
39
72
|
}
|
|
40
73
|
|
|
41
|
-
getCurrentPermissions(req) {
|
|
42
|
-
return req?.user?.permissions || process.env.PERMISSIONS;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
74
|
toJson() {
|
|
46
75
|
return {
|
|
47
76
|
...super.toJson(),
|
|
@@ -49,15 +78,38 @@ class StorageProviderBase extends AuthProviderBase {
|
|
|
49
78
|
type: this.config.type,
|
|
50
79
|
};
|
|
51
80
|
}
|
|
81
|
+
|
|
82
|
+
async getCurrentPermissions(req) {
|
|
83
|
+
const userId = this.getUserIdFromRequest(req);
|
|
84
|
+
const permissions = await loadPermissionsForUserId(userId);
|
|
85
|
+
return permissions;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async getCurrentDatabasePermissions(req) {
|
|
89
|
+
const userId = this.getUserIdFromRequest(req);
|
|
90
|
+
const databasePermissions = await readComplexUserRolePermissions(userId, 'user_databases', 'role_databases');
|
|
91
|
+
return databasePermissions;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async getCurrentTablePermissions(req) {
|
|
95
|
+
const userId = this.getUserIdFromRequest(req);
|
|
96
|
+
const tablePermissions = await readComplexUserRolePermissions(userId, 'user_tables', 'role_tables');
|
|
97
|
+
return tablePermissions;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async checkCurrentConnectionPermission(req, conid) {
|
|
101
|
+
const userId = this.getUserIdFromRequest(req);
|
|
102
|
+
const res = await storageCheckUserRoleConnectionAccess(userId, conid);
|
|
103
|
+
return res;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
getUserIdFromRequest(req) {
|
|
107
|
+
return req?.user?.userId ?? -1;
|
|
108
|
+
}
|
|
52
109
|
}
|
|
53
110
|
|
|
54
111
|
class AnonymousProvider extends StorageProviderBase {
|
|
55
112
|
async login(login, password, options = undefined, req = undefined) {
|
|
56
|
-
const permissions = await [
|
|
57
|
-
...getPredefinedPermissions('anonymous-user'),
|
|
58
|
-
...(await storageReadRolePermissions(-1)),
|
|
59
|
-
];
|
|
60
|
-
|
|
61
113
|
if (!(await isLoginLicensed(req, `anonymous`))) {
|
|
62
114
|
return { error: LOGIN_LIMIT_ERROR };
|
|
63
115
|
}
|
|
@@ -75,7 +127,6 @@ class AnonymousProvider extends StorageProviderBase {
|
|
|
75
127
|
const accessToken = jwt.sign(
|
|
76
128
|
{
|
|
77
129
|
amoid: this.amoid,
|
|
78
|
-
permissions,
|
|
79
130
|
licenseUid,
|
|
80
131
|
},
|
|
81
132
|
getTokenSecret(),
|
|
@@ -87,6 +138,30 @@ class AnonymousProvider extends StorageProviderBase {
|
|
|
87
138
|
accessToken,
|
|
88
139
|
};
|
|
89
140
|
}
|
|
141
|
+
|
|
142
|
+
// @ts-ignore
|
|
143
|
+
async getCurrentPermissions(req) {
|
|
144
|
+
const permissions = await [
|
|
145
|
+
...getPredefinedPermissions('anonymous-user'),
|
|
146
|
+
...(await storageReadRolePermissions(-1)),
|
|
147
|
+
];
|
|
148
|
+
return permissions;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async getCurrentDatabasePermissions(req) {
|
|
152
|
+
const databasePermissions = await readComplexRolePermissions(-1, 'role_databases');
|
|
153
|
+
return databasePermissions;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async getCurrentTablePermissions(req) {
|
|
157
|
+
const tablePermissions = await readComplexRolePermissions(-1, 'role_tables');
|
|
158
|
+
return tablePermissions;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async checkCurrentConnectionPermission(req, conid) {
|
|
162
|
+
const res = await storageCheckRoleConnectionAccess(-1, conid);
|
|
163
|
+
return res;
|
|
164
|
+
}
|
|
90
165
|
}
|
|
91
166
|
|
|
92
167
|
class LocalAuthProvider extends StorageProviderBase {
|
|
@@ -101,7 +176,6 @@ class LocalAuthProvider extends StorageProviderBase {
|
|
|
101
176
|
const row = decryptUser(rows[0]);
|
|
102
177
|
if (row.password == password) {
|
|
103
178
|
const userId = row.id;
|
|
104
|
-
const permissions = await loadPermissionsForUserId(userId);
|
|
105
179
|
|
|
106
180
|
if (!(await isLoginLicensed(req, `local:${login}`))) {
|
|
107
181
|
return { error: LOGIN_LIMIT_ERROR };
|
|
@@ -122,7 +196,6 @@ class LocalAuthProvider extends StorageProviderBase {
|
|
|
122
196
|
{
|
|
123
197
|
amoid: this.amoid,
|
|
124
198
|
login,
|
|
125
|
-
permissions,
|
|
126
199
|
userId,
|
|
127
200
|
licenseUid,
|
|
128
201
|
},
|
|
@@ -198,7 +271,6 @@ class OauthProvider extends StorageProviderBase {
|
|
|
198
271
|
: 'oauth';
|
|
199
272
|
|
|
200
273
|
const loginRows = await storageSelectFmt('select * from ~users where ~login = %v', login);
|
|
201
|
-
const permissions = await loadPermissionsForUserId(loginRows[0]?.id ?? -1);
|
|
202
274
|
|
|
203
275
|
if (this.config.oauthOnlyDefinedLogins == 1 && loginRows.length == 0) {
|
|
204
276
|
sendToAuditLog(req, {
|
|
@@ -264,7 +336,6 @@ class OauthProvider extends StorageProviderBase {
|
|
|
264
336
|
{
|
|
265
337
|
amoid: this.amoid,
|
|
266
338
|
login,
|
|
267
|
-
permissions,
|
|
268
339
|
userId: loginRows[0]?.id,
|
|
269
340
|
licenseUid,
|
|
270
341
|
},
|
|
@@ -328,7 +399,6 @@ class ADProvider extends StorageProviderBase {
|
|
|
328
399
|
}
|
|
329
400
|
|
|
330
401
|
const loginRows = await storageSelectFmt('select * from ~users where ~login = %v', login);
|
|
331
|
-
const permissions = await loadPermissionsForUserId(loginRows[0]?.id ?? -1);
|
|
332
402
|
|
|
333
403
|
if (this.config.adOnlyDefinedLogins == 1) {
|
|
334
404
|
if (loginRows.length == 0) {
|
|
@@ -355,8 +425,8 @@ class ADProvider extends StorageProviderBase {
|
|
|
355
425
|
{
|
|
356
426
|
amoid: this.amoid,
|
|
357
427
|
login,
|
|
358
|
-
permissions,
|
|
359
428
|
licenseUid,
|
|
429
|
+
userId: loginRows[0]?.id ?? -1,
|
|
360
430
|
},
|
|
361
431
|
getTokenSecret(),
|
|
362
432
|
{ expiresIn: getTokenLifetime() }
|
|
@@ -421,7 +491,6 @@ class DatabaseProvider extends StorageProviderBase {
|
|
|
421
491
|
return { error: 'Login not allowed', login };
|
|
422
492
|
}
|
|
423
493
|
const userId = rows[0]?.id;
|
|
424
|
-
const permissions = await loadPermissionsForUserId(userId ?? -1);
|
|
425
494
|
|
|
426
495
|
if (!(await isLoginLicensed(req, `db:${login}`))) {
|
|
427
496
|
return { error: LOGIN_LIMIT_ERROR };
|
|
@@ -442,7 +511,6 @@ class DatabaseProvider extends StorageProviderBase {
|
|
|
442
511
|
{
|
|
443
512
|
amoid: this.amoid,
|
|
444
513
|
login,
|
|
445
|
-
permissions,
|
|
446
514
|
userId,
|
|
447
515
|
conid,
|
|
448
516
|
licenseUid,
|
|
@@ -490,7 +558,6 @@ class MsEntraProvider extends StorageProviderBase {
|
|
|
490
558
|
const { email } = payload;
|
|
491
559
|
|
|
492
560
|
const loginRows = await storageSelectFmt('select * from ~users where ~email = %v', email);
|
|
493
|
-
const permissions = await loadPermissionsForUserId(loginRows[0]?.id ?? -1);
|
|
494
561
|
|
|
495
562
|
if (this.config.msentraOnlyDefinedLogins == 1) {
|
|
496
563
|
if (loginRows.length == 0) {
|
|
@@ -527,7 +594,6 @@ class MsEntraProvider extends StorageProviderBase {
|
|
|
527
594
|
const accessToken = jwt.sign(
|
|
528
595
|
{
|
|
529
596
|
amoid: this.amoid,
|
|
530
|
-
permissions,
|
|
531
597
|
msentraToken: token,
|
|
532
598
|
userId: loginRows[0]?.id,
|
|
533
599
|
login: payload.unique_name,
|
|
@@ -593,4 +659,5 @@ function createStorageAuthProvider(config) {
|
|
|
593
659
|
|
|
594
660
|
module.exports = {
|
|
595
661
|
createStorageAuthProvider,
|
|
662
|
+
SuperadminAuthProvider,
|
|
596
663
|
};
|
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
|
|