dbgate-api-premium 6.5.5 → 6.6.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 +6 -5
- package/src/auth/storageAuthProvider.js +90 -67
- package/src/controllers/auth.js +41 -14
- package/src/controllers/cloud.js +14 -0
- package/src/controllers/config.js +41 -16
- package/src/controllers/storage.js +0 -5
- package/src/currentVersion.js +2 -2
- package/src/storageModel.js +74 -62
- package/src/utility/authProxy.js +50 -0
- package/src/utility/checkLicense.js +1 -0
- package/src/utility/cloudIntf.js +13 -1
- package/src/utility/crypting.js +13 -11
- package/src/utility/loginchecker.js +27 -2
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.
|
|
4
|
+
"version": "6.6.0",
|
|
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.
|
|
33
|
+
"dbgate-datalib": "^6.6.0",
|
|
34
34
|
"dbgate-query-splitter": "^4.11.5",
|
|
35
|
-
"dbgate-sqltree": "^6.
|
|
36
|
-
"dbgate-tools": "^6.
|
|
35
|
+
"dbgate-sqltree": "^6.6.0",
|
|
36
|
+
"dbgate-tools": "^6.6.0",
|
|
37
37
|
"debug": "^4.3.4",
|
|
38
38
|
"diff": "^5.0.0",
|
|
39
39
|
"diff2html": "^3.4.13",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"start": "env-cmd -f .env node src/index.js --listen-api",
|
|
71
|
+
"start:debug": "env-cmd -f .env node --inspect src/index.js --listen-api",
|
|
71
72
|
"start:portal": "env-cmd -f env/portal/.env node src/index.js --listen-api",
|
|
72
73
|
"start:singledb": "env-cmd -f env/singledb/.env node src/index.js --listen-api",
|
|
73
74
|
"start:auth": "env-cmd -f env/auth/.env node src/index.js --listen-api",
|
|
@@ -85,7 +86,7 @@
|
|
|
85
86
|
"devDependencies": {
|
|
86
87
|
"@types/fs-extra": "^9.0.11",
|
|
87
88
|
"@types/lodash": "^4.14.149",
|
|
88
|
-
"dbgate-types": "^6.
|
|
89
|
+
"dbgate-types": "^6.6.0",
|
|
89
90
|
"env-cmd": "^10.1.0",
|
|
90
91
|
"jsdoc-to-markdown": "^9.0.5",
|
|
91
92
|
"node-loader": "^1.0.2",
|
|
@@ -22,7 +22,7 @@ const _ = require('lodash');
|
|
|
22
22
|
const { authProxyGetTokenFromCode, authProxyGetRedirectUrl } = require('../utility/authProxy');
|
|
23
23
|
const { decryptUser } = require('../utility/crypting');
|
|
24
24
|
const { sendToAuditLog } = require('../utility/auditlog');
|
|
25
|
-
const { isLoginLicensed, LOGIN_LIMIT_ERROR } = require('../utility/loginchecker');
|
|
25
|
+
const { isLoginLicensed, LOGIN_LIMIT_ERROR, markTokenAsLoggedIn } = require('../utility/loginchecker');
|
|
26
26
|
|
|
27
27
|
async function loadPermissionsForUserId(userId) {
|
|
28
28
|
const rolePermissions = sortPermissionsFromTheSameLevel(await storageReadUserRolePermissions(userId));
|
|
@@ -31,7 +31,6 @@ async function loadPermissionsForUserId(userId) {
|
|
|
31
31
|
return [...getPredefinedPermissions('logged-user'), ...loggedUserPermissions, ...rolePermissions, ...userPermissions];
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
35
34
|
class StorageProviderBase extends AuthProviderBase {
|
|
36
35
|
constructor(config) {
|
|
37
36
|
super();
|
|
@@ -72,16 +71,20 @@ class AnonymousProvider extends StorageProviderBase {
|
|
|
72
71
|
message: 'Anonymous login',
|
|
73
72
|
});
|
|
74
73
|
|
|
74
|
+
const licenseUid = 'anonymous';
|
|
75
|
+
const accessToken = jwt.sign(
|
|
76
|
+
{
|
|
77
|
+
amoid: this.amoid,
|
|
78
|
+
permissions,
|
|
79
|
+
licenseUid,
|
|
80
|
+
},
|
|
81
|
+
getTokenSecret(),
|
|
82
|
+
{ expiresIn: getTokenLifetime() }
|
|
83
|
+
);
|
|
84
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
85
|
+
|
|
75
86
|
return {
|
|
76
|
-
accessToken
|
|
77
|
-
{
|
|
78
|
-
amoid: this.amoid,
|
|
79
|
-
permissions,
|
|
80
|
-
licenseUid: 'anonymous',
|
|
81
|
-
},
|
|
82
|
-
getTokenSecret(),
|
|
83
|
-
{ expiresIn: getTokenLifetime() }
|
|
84
|
-
),
|
|
87
|
+
accessToken,
|
|
85
88
|
};
|
|
86
89
|
}
|
|
87
90
|
}
|
|
@@ -114,18 +117,22 @@ class LocalAuthProvider extends StorageProviderBase {
|
|
|
114
117
|
message: 'Local login successful',
|
|
115
118
|
});
|
|
116
119
|
|
|
120
|
+
const licenseUid = `local:${login}`;
|
|
121
|
+
const accessToken = jwt.sign(
|
|
122
|
+
{
|
|
123
|
+
amoid: this.amoid,
|
|
124
|
+
login,
|
|
125
|
+
permissions,
|
|
126
|
+
userId,
|
|
127
|
+
licenseUid,
|
|
128
|
+
},
|
|
129
|
+
getTokenSecret(),
|
|
130
|
+
{ expiresIn: getTokenLifetime() }
|
|
131
|
+
);
|
|
132
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
133
|
+
|
|
117
134
|
return {
|
|
118
|
-
accessToken
|
|
119
|
-
{
|
|
120
|
-
amoid: this.amoid,
|
|
121
|
-
login,
|
|
122
|
-
permissions,
|
|
123
|
-
userId,
|
|
124
|
-
licenseUid: `local:${login}`,
|
|
125
|
-
},
|
|
126
|
-
getTokenSecret(),
|
|
127
|
-
{ expiresIn: getTokenLifetime() }
|
|
128
|
-
),
|
|
135
|
+
accessToken,
|
|
129
136
|
};
|
|
130
137
|
}
|
|
131
138
|
|
|
@@ -252,18 +259,22 @@ class OauthProvider extends StorageProviderBase {
|
|
|
252
259
|
message: `User ${login} logged in via OAUTH`,
|
|
253
260
|
});
|
|
254
261
|
|
|
262
|
+
const licenseUid = `oauth:${login}`;
|
|
263
|
+
const accessToken = jwt.sign(
|
|
264
|
+
{
|
|
265
|
+
amoid: this.amoid,
|
|
266
|
+
login,
|
|
267
|
+
permissions,
|
|
268
|
+
userId: loginRows[0]?.id,
|
|
269
|
+
licenseUid,
|
|
270
|
+
},
|
|
271
|
+
getTokenSecret(),
|
|
272
|
+
{ expiresIn: getTokenLifetime() }
|
|
273
|
+
);
|
|
274
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
275
|
+
|
|
255
276
|
return {
|
|
256
|
-
accessToken
|
|
257
|
-
{
|
|
258
|
-
amoid: this.amoid,
|
|
259
|
-
login,
|
|
260
|
-
permissions,
|
|
261
|
-
userId: loginRows[0]?.id,
|
|
262
|
-
licenseUid: `oauth:${login}`,
|
|
263
|
-
},
|
|
264
|
-
getTokenSecret(),
|
|
265
|
-
{ expiresIn: getTokenLifetime() }
|
|
266
|
-
),
|
|
277
|
+
accessToken,
|
|
267
278
|
};
|
|
268
279
|
}
|
|
269
280
|
|
|
@@ -339,17 +350,21 @@ class ADProvider extends StorageProviderBase {
|
|
|
339
350
|
message: `User ${login} logged in via AD`,
|
|
340
351
|
});
|
|
341
352
|
|
|
353
|
+
const licenseUid = `ad:${login}`;
|
|
354
|
+
const accessToken = jwt.sign(
|
|
355
|
+
{
|
|
356
|
+
amoid: this.amoid,
|
|
357
|
+
login,
|
|
358
|
+
permissions,
|
|
359
|
+
licenseUid,
|
|
360
|
+
},
|
|
361
|
+
getTokenSecret(),
|
|
362
|
+
{ expiresIn: getTokenLifetime() }
|
|
363
|
+
);
|
|
364
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
365
|
+
|
|
342
366
|
return {
|
|
343
|
-
accessToken
|
|
344
|
-
{
|
|
345
|
-
amoid: this.amoid,
|
|
346
|
-
login,
|
|
347
|
-
permissions,
|
|
348
|
-
licenseUid: `ad:${login}`,
|
|
349
|
-
},
|
|
350
|
-
getTokenSecret(),
|
|
351
|
-
{ expiresIn: getTokenLifetime() }
|
|
352
|
-
),
|
|
367
|
+
accessToken,
|
|
353
368
|
};
|
|
354
369
|
} catch (e) {
|
|
355
370
|
sendToAuditLog(req, {
|
|
@@ -422,19 +437,23 @@ class DatabaseProvider extends StorageProviderBase {
|
|
|
422
437
|
message: `User ${login} logged in via database`,
|
|
423
438
|
});
|
|
424
439
|
|
|
440
|
+
const licenseUid = `db:${login}`;
|
|
441
|
+
const accessToken = jwt.sign(
|
|
442
|
+
{
|
|
443
|
+
amoid: this.amoid,
|
|
444
|
+
login,
|
|
445
|
+
permissions,
|
|
446
|
+
userId,
|
|
447
|
+
conid,
|
|
448
|
+
licenseUid,
|
|
449
|
+
},
|
|
450
|
+
getTokenSecret(),
|
|
451
|
+
{ expiresIn: getTokenLifetime() }
|
|
452
|
+
);
|
|
453
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
454
|
+
|
|
425
455
|
return {
|
|
426
|
-
accessToken
|
|
427
|
-
{
|
|
428
|
-
amoid: this.amoid,
|
|
429
|
-
login,
|
|
430
|
-
permissions,
|
|
431
|
-
userId,
|
|
432
|
-
conid,
|
|
433
|
-
licenseUid: `db:${login}`,
|
|
434
|
-
},
|
|
435
|
-
getTokenSecret(),
|
|
436
|
-
{ expiresIn: getTokenLifetime() }
|
|
437
|
-
),
|
|
456
|
+
accessToken,
|
|
438
457
|
};
|
|
439
458
|
}
|
|
440
459
|
|
|
@@ -504,19 +523,23 @@ class MsEntraProvider extends StorageProviderBase {
|
|
|
504
523
|
message: `User ${payload.unique_name} logged in via MS Entra`,
|
|
505
524
|
});
|
|
506
525
|
|
|
526
|
+
const licenseUid = `msentra:${payload.unique_name}`;
|
|
527
|
+
const accessToken = jwt.sign(
|
|
528
|
+
{
|
|
529
|
+
amoid: this.amoid,
|
|
530
|
+
permissions,
|
|
531
|
+
msentraToken: token,
|
|
532
|
+
userId: loginRows[0]?.id,
|
|
533
|
+
login: payload.unique_name,
|
|
534
|
+
licenseUid,
|
|
535
|
+
},
|
|
536
|
+
getTokenSecret(),
|
|
537
|
+
{ expiresIn: getTokenLifetime() }
|
|
538
|
+
);
|
|
539
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
540
|
+
|
|
507
541
|
return {
|
|
508
|
-
accessToken
|
|
509
|
-
{
|
|
510
|
-
amoid: this.amoid,
|
|
511
|
-
permissions,
|
|
512
|
-
msentraToken: token,
|
|
513
|
-
userId: loginRows[0]?.id,
|
|
514
|
-
login: payload.unique_name,
|
|
515
|
-
licenseUid: `msentra:${payload.unique_name}`,
|
|
516
|
-
},
|
|
517
|
-
getTokenSecret(),
|
|
518
|
-
{ expiresIn: getTokenLifetime() }
|
|
519
|
-
),
|
|
542
|
+
accessToken,
|
|
520
543
|
};
|
|
521
544
|
}
|
|
522
545
|
|
package/src/controllers/auth.js
CHANGED
|
@@ -21,7 +21,13 @@ const {
|
|
|
21
21
|
} = require('../utility/cloudIntf');
|
|
22
22
|
const socket = require('../utility/socket');
|
|
23
23
|
const { sendToAuditLog } = require('../utility/auditlog');
|
|
24
|
-
const {
|
|
24
|
+
const {
|
|
25
|
+
isLoginLicensed,
|
|
26
|
+
LOGIN_LIMIT_ERROR,
|
|
27
|
+
markTokenAsLoggedIn,
|
|
28
|
+
markUserAsActive,
|
|
29
|
+
markLoginAsLoggedOut,
|
|
30
|
+
} = require('../utility/loginchecker');
|
|
25
31
|
|
|
26
32
|
const logger = getLogger('auth');
|
|
27
33
|
|
|
@@ -61,6 +67,11 @@ function authMiddleware(req, res, next) {
|
|
|
61
67
|
|
|
62
68
|
// const isAdminPage = req.headers['x-is-admin-page'] == 'true';
|
|
63
69
|
|
|
70
|
+
if (process.env.SKIP_ALL_AUTH) {
|
|
71
|
+
// API is not authorized for basic auth
|
|
72
|
+
return next();
|
|
73
|
+
}
|
|
74
|
+
|
|
64
75
|
if (process.env.BASIC_AUTH) {
|
|
65
76
|
// API is not authorized for basic auth
|
|
66
77
|
return next();
|
|
@@ -79,7 +90,7 @@ function authMiddleware(req, res, next) {
|
|
|
79
90
|
try {
|
|
80
91
|
const decoded = jwt.verify(token, getTokenSecret());
|
|
81
92
|
req.user = decoded;
|
|
82
|
-
|
|
93
|
+
markUserAsActive(decoded.licenseUid, token);
|
|
83
94
|
|
|
84
95
|
return next();
|
|
85
96
|
} catch (err) {
|
|
@@ -124,19 +135,23 @@ module.exports = {
|
|
|
124
135
|
message: 'Administration login successful',
|
|
125
136
|
});
|
|
126
137
|
|
|
138
|
+
const licenseUid = `superadmin`;
|
|
139
|
+
const accessToken = jwt.sign(
|
|
140
|
+
{
|
|
141
|
+
login: 'superadmin',
|
|
142
|
+
permissions: await storage.loadSuperadminPermissions(),
|
|
143
|
+
roleId: -3,
|
|
144
|
+
licenseUid,
|
|
145
|
+
},
|
|
146
|
+
getTokenSecret(),
|
|
147
|
+
{
|
|
148
|
+
expiresIn: getTokenLifetime(),
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
152
|
+
|
|
127
153
|
return {
|
|
128
|
-
accessToken
|
|
129
|
-
{
|
|
130
|
-
login: 'superadmin',
|
|
131
|
-
permissions: await storage.loadSuperadminPermissions(),
|
|
132
|
-
roleId: -3,
|
|
133
|
-
licenseUid: `superadmin`,
|
|
134
|
-
},
|
|
135
|
-
getTokenSecret(),
|
|
136
|
-
{
|
|
137
|
-
expiresIn: getTokenLifetime(),
|
|
138
|
-
}
|
|
139
|
-
),
|
|
154
|
+
accessToken,
|
|
140
155
|
};
|
|
141
156
|
}
|
|
142
157
|
|
|
@@ -192,5 +207,17 @@ module.exports = {
|
|
|
192
207
|
return tokenHolder;
|
|
193
208
|
},
|
|
194
209
|
|
|
210
|
+
logoutAdmin_meta: true,
|
|
211
|
+
async logoutAdmin() {
|
|
212
|
+
await markLoginAsLoggedOut('superadmin');
|
|
213
|
+
return true;
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
logoutUser_meta: true,
|
|
217
|
+
async logoutUser({}, req) {
|
|
218
|
+
await markLoginAsLoggedOut(req?.user?.licenseUid);
|
|
219
|
+
return true;
|
|
220
|
+
},
|
|
221
|
+
|
|
195
222
|
authMiddleware,
|
|
196
223
|
};
|
package/src/controllers/cloud.js
CHANGED
|
@@ -16,6 +16,7 @@ const { getConnectionLabel, getLogger, extractErrorLogData } = require('dbgate-t
|
|
|
16
16
|
const logger = getLogger('cloud');
|
|
17
17
|
const _ = require('lodash');
|
|
18
18
|
const fs = require('fs-extra');
|
|
19
|
+
const { getAiGatewayServer } = require('../utility/authProxy');
|
|
19
20
|
|
|
20
21
|
module.exports = {
|
|
21
22
|
publicFiles_meta: true,
|
|
@@ -276,4 +277,17 @@ module.exports = {
|
|
|
276
277
|
const resp = await callCloudApiPost(`content-folders/remove-user/${folid}`, { email });
|
|
277
278
|
return resp;
|
|
278
279
|
},
|
|
280
|
+
|
|
281
|
+
getAiGateway_meta: true,
|
|
282
|
+
async getAiGateway() {
|
|
283
|
+
return getAiGatewayServer();
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
// chatStream_meta: {
|
|
287
|
+
// raw: true,
|
|
288
|
+
// method: 'post',
|
|
289
|
+
// },
|
|
290
|
+
// chatStream(req, res) {
|
|
291
|
+
// callChatStream(req.body, res);
|
|
292
|
+
// },
|
|
279
293
|
};
|
|
@@ -16,7 +16,7 @@ const connections = require('../controllers/connections');
|
|
|
16
16
|
const { getAuthProviderFromReq } = require('../auth/authProvider');
|
|
17
17
|
const { checkLicense, checkLicenseKey } = require('../utility/checkLicense');
|
|
18
18
|
const storage = require('./storage');
|
|
19
|
-
const { getAuthProxyUrl } = require('../utility/authProxy');
|
|
19
|
+
const { getAuthProxyUrl, tryToGetRefreshedLicense } = require('../utility/authProxy');
|
|
20
20
|
const { getPublicHardwareFingerprint } = require('../utility/hardwareFingerprint');
|
|
21
21
|
const { extractErrorMessage } = require('dbgate-tools');
|
|
22
22
|
const {
|
|
@@ -109,6 +109,7 @@ module.exports = {
|
|
|
109
109
|
),
|
|
110
110
|
isAdminPasswordMissing,
|
|
111
111
|
isInvalidToken: req?.isInvalidToken,
|
|
112
|
+
skipAllAuth: !!process.env.SKIP_ALL_AUTH,
|
|
112
113
|
adminPasswordState: adminConfig?.adminPasswordState,
|
|
113
114
|
storageDatabase: process.env.STORAGE_DATABASE,
|
|
114
115
|
logsFilePath: getLogsFilePath(),
|
|
@@ -191,6 +192,7 @@ module.exports = {
|
|
|
191
192
|
return {
|
|
192
193
|
...this.fillMissingSettings(JSON.parse(settingsText)),
|
|
193
194
|
'other.licenseKey': platformInfo.isElectron ? await this.loadLicenseKey() : undefined,
|
|
195
|
+
// 'other.licenseKey': await this.loadLicenseKey(),
|
|
194
196
|
};
|
|
195
197
|
}
|
|
196
198
|
} catch (err) {
|
|
@@ -208,21 +210,34 @@ module.exports = {
|
|
|
208
210
|
},
|
|
209
211
|
|
|
210
212
|
saveLicenseKey_meta: true,
|
|
211
|
-
async saveLicenseKey({ licenseKey }) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
213
|
+
async saveLicenseKey({ licenseKey, forceSave = false, tryToRenew = false }) {
|
|
214
|
+
if (!forceSave) {
|
|
215
|
+
const decoded = jwt.decode(licenseKey?.trim());
|
|
216
|
+
if (!decoded) {
|
|
217
|
+
return {
|
|
218
|
+
status: 'error',
|
|
219
|
+
errorMessage: 'Invalid license key',
|
|
220
|
+
};
|
|
221
|
+
}
|
|
219
222
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
223
|
+
const { exp } = decoded;
|
|
224
|
+
if (exp * 1000 < Date.now()) {
|
|
225
|
+
let renewed = false;
|
|
226
|
+
if (tryToRenew) {
|
|
227
|
+
const newLicenseKey = await tryToGetRefreshedLicense(licenseKey);
|
|
228
|
+
if (newLicenseKey.status == 'ok') {
|
|
229
|
+
licenseKey = newLicenseKey.token;
|
|
230
|
+
renewed = true;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (!renewed) {
|
|
235
|
+
return {
|
|
236
|
+
status: 'error',
|
|
237
|
+
errorMessage: 'License key is expired',
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
}
|
|
226
241
|
}
|
|
227
242
|
|
|
228
243
|
try {
|
|
@@ -297,7 +312,7 @@ module.exports = {
|
|
|
297
312
|
// this.settingsValue = updated;
|
|
298
313
|
|
|
299
314
|
if (currentValue['other.licenseKey'] != values['other.licenseKey']) {
|
|
300
|
-
await this.saveLicenseKey({ licenseKey: values['other.licenseKey'] });
|
|
315
|
+
await this.saveLicenseKey({ licenseKey: values['other.licenseKey'], forceSave: true });
|
|
301
316
|
socket.emitChanged(`config-changed`);
|
|
302
317
|
}
|
|
303
318
|
}
|
|
@@ -327,6 +342,16 @@ module.exports = {
|
|
|
327
342
|
return resp;
|
|
328
343
|
},
|
|
329
344
|
|
|
345
|
+
getNewLicense_meta: true,
|
|
346
|
+
async getNewLicense({ oldLicenseKey }) {
|
|
347
|
+
const newLicenseKey = await tryToGetRefreshedLicense(oldLicenseKey);
|
|
348
|
+
const res = await checkLicenseKey(newLicenseKey.token);
|
|
349
|
+
if (res.status == 'ok') {
|
|
350
|
+
res.licenseKey = newLicenseKey.token;
|
|
351
|
+
}
|
|
352
|
+
return res;
|
|
353
|
+
},
|
|
354
|
+
|
|
330
355
|
recryptDatabaseForExport(db) {
|
|
331
356
|
const encryptionKey = generateTransportEncryptionKey();
|
|
332
357
|
const transportEncryptor = createTransportEncryptor(encryptionKey);
|
|
@@ -40,7 +40,6 @@ const crypto = require('crypto');
|
|
|
40
40
|
const dataReplicator = require('../shell/dataReplicator');
|
|
41
41
|
const storageReplicatorItems = require('../utility/storageReplicatorItems');
|
|
42
42
|
const { sendToAuditLog } = require('../utility/auditlog');
|
|
43
|
-
const { markUserAsActive } = require('../utility/loginchecker');
|
|
44
43
|
|
|
45
44
|
const logger = getLogger('storage');
|
|
46
45
|
|
|
@@ -881,8 +880,4 @@ module.exports = {
|
|
|
881
880
|
sendToAuditLog(req, props);
|
|
882
881
|
return null;
|
|
883
882
|
},
|
|
884
|
-
|
|
885
|
-
markUserAsActive(licenseUid) {
|
|
886
|
-
markUserAsActive(licenseUid);
|
|
887
|
-
},
|
|
888
883
|
};
|
package/src/currentVersion.js
CHANGED
package/src/storageModel.js
CHANGED
|
@@ -519,6 +519,12 @@ module.exports = {
|
|
|
519
519
|
"dataType": "int",
|
|
520
520
|
"notNull": false
|
|
521
521
|
},
|
|
522
|
+
{
|
|
523
|
+
"pureName": "connections",
|
|
524
|
+
"columnName": "useSeparateSchemas",
|
|
525
|
+
"dataType": "int",
|
|
526
|
+
"notNull": false
|
|
527
|
+
},
|
|
522
528
|
{
|
|
523
529
|
"pureName": "connections",
|
|
524
530
|
"columnName": "defaultDatabase",
|
|
@@ -668,6 +674,12 @@ module.exports = {
|
|
|
668
674
|
"columnName": "awsRegion",
|
|
669
675
|
"dataType": "varchar(250)",
|
|
670
676
|
"notNull": false
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
"pureName": "connections",
|
|
680
|
+
"columnName": "connectionDefinition",
|
|
681
|
+
"dataType": "text",
|
|
682
|
+
"notNull": false
|
|
671
683
|
}
|
|
672
684
|
],
|
|
673
685
|
"foreignKeys": [],
|
|
@@ -682,6 +694,49 @@ module.exports = {
|
|
|
682
694
|
]
|
|
683
695
|
}
|
|
684
696
|
},
|
|
697
|
+
{
|
|
698
|
+
"pureName": "roles",
|
|
699
|
+
"columns": [
|
|
700
|
+
{
|
|
701
|
+
"pureName": "roles",
|
|
702
|
+
"columnName": "id",
|
|
703
|
+
"dataType": "int",
|
|
704
|
+
"autoIncrement": true,
|
|
705
|
+
"notNull": true
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
"pureName": "roles",
|
|
709
|
+
"columnName": "name",
|
|
710
|
+
"dataType": "varchar(250)",
|
|
711
|
+
"notNull": false
|
|
712
|
+
}
|
|
713
|
+
],
|
|
714
|
+
"foreignKeys": [],
|
|
715
|
+
"primaryKey": {
|
|
716
|
+
"pureName": "roles",
|
|
717
|
+
"constraintType": "primaryKey",
|
|
718
|
+
"constraintName": "PK_roles",
|
|
719
|
+
"columns": [
|
|
720
|
+
{
|
|
721
|
+
"columnName": "id"
|
|
722
|
+
}
|
|
723
|
+
]
|
|
724
|
+
},
|
|
725
|
+
"preloadedRows": [
|
|
726
|
+
{
|
|
727
|
+
"id": -1,
|
|
728
|
+
"name": "anonymous-user"
|
|
729
|
+
},
|
|
730
|
+
{
|
|
731
|
+
"id": -2,
|
|
732
|
+
"name": "logged-user"
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
"id": -3,
|
|
736
|
+
"name": "superadmin"
|
|
737
|
+
}
|
|
738
|
+
]
|
|
739
|
+
},
|
|
685
740
|
{
|
|
686
741
|
"pureName": "role_connections",
|
|
687
742
|
"columns": [
|
|
@@ -794,47 +849,45 @@ module.exports = {
|
|
|
794
849
|
}
|
|
795
850
|
},
|
|
796
851
|
{
|
|
797
|
-
"pureName": "
|
|
852
|
+
"pureName": "users",
|
|
798
853
|
"columns": [
|
|
799
854
|
{
|
|
800
|
-
"pureName": "
|
|
855
|
+
"pureName": "users",
|
|
801
856
|
"columnName": "id",
|
|
802
857
|
"dataType": "int",
|
|
803
858
|
"autoIncrement": true,
|
|
804
859
|
"notNull": true
|
|
805
860
|
},
|
|
806
861
|
{
|
|
807
|
-
"pureName": "
|
|
808
|
-
"columnName": "
|
|
862
|
+
"pureName": "users",
|
|
863
|
+
"columnName": "login",
|
|
864
|
+
"dataType": "varchar(250)",
|
|
865
|
+
"notNull": false
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
"pureName": "users",
|
|
869
|
+
"columnName": "password",
|
|
870
|
+
"dataType": "varchar(250)",
|
|
871
|
+
"notNull": false
|
|
872
|
+
},
|
|
873
|
+
{
|
|
874
|
+
"pureName": "users",
|
|
875
|
+
"columnName": "email",
|
|
809
876
|
"dataType": "varchar(250)",
|
|
810
877
|
"notNull": false
|
|
811
878
|
}
|
|
812
879
|
],
|
|
813
880
|
"foreignKeys": [],
|
|
814
881
|
"primaryKey": {
|
|
815
|
-
"pureName": "
|
|
882
|
+
"pureName": "users",
|
|
816
883
|
"constraintType": "primaryKey",
|
|
817
|
-
"constraintName": "
|
|
884
|
+
"constraintName": "PK_users",
|
|
818
885
|
"columns": [
|
|
819
886
|
{
|
|
820
887
|
"columnName": "id"
|
|
821
888
|
}
|
|
822
889
|
]
|
|
823
|
-
}
|
|
824
|
-
"preloadedRows": [
|
|
825
|
-
{
|
|
826
|
-
"id": -1,
|
|
827
|
-
"name": "anonymous-user"
|
|
828
|
-
},
|
|
829
|
-
{
|
|
830
|
-
"id": -2,
|
|
831
|
-
"name": "logged-user"
|
|
832
|
-
},
|
|
833
|
-
{
|
|
834
|
-
"id": -3,
|
|
835
|
-
"name": "superadmin"
|
|
836
|
-
}
|
|
837
|
-
]
|
|
890
|
+
}
|
|
838
891
|
},
|
|
839
892
|
{
|
|
840
893
|
"pureName": "user_connections",
|
|
@@ -1008,47 +1061,6 @@ module.exports = {
|
|
|
1008
1061
|
}
|
|
1009
1062
|
]
|
|
1010
1063
|
}
|
|
1011
|
-
},
|
|
1012
|
-
{
|
|
1013
|
-
"pureName": "users",
|
|
1014
|
-
"columns": [
|
|
1015
|
-
{
|
|
1016
|
-
"pureName": "users",
|
|
1017
|
-
"columnName": "id",
|
|
1018
|
-
"dataType": "int",
|
|
1019
|
-
"autoIncrement": true,
|
|
1020
|
-
"notNull": true
|
|
1021
|
-
},
|
|
1022
|
-
{
|
|
1023
|
-
"pureName": "users",
|
|
1024
|
-
"columnName": "login",
|
|
1025
|
-
"dataType": "varchar(250)",
|
|
1026
|
-
"notNull": false
|
|
1027
|
-
},
|
|
1028
|
-
{
|
|
1029
|
-
"pureName": "users",
|
|
1030
|
-
"columnName": "password",
|
|
1031
|
-
"dataType": "varchar(250)",
|
|
1032
|
-
"notNull": false
|
|
1033
|
-
},
|
|
1034
|
-
{
|
|
1035
|
-
"pureName": "users",
|
|
1036
|
-
"columnName": "email",
|
|
1037
|
-
"dataType": "varchar(250)",
|
|
1038
|
-
"notNull": false
|
|
1039
|
-
}
|
|
1040
|
-
],
|
|
1041
|
-
"foreignKeys": [],
|
|
1042
|
-
"primaryKey": {
|
|
1043
|
-
"pureName": "users",
|
|
1044
|
-
"constraintType": "primaryKey",
|
|
1045
|
-
"constraintName": "PK_users",
|
|
1046
|
-
"columns": [
|
|
1047
|
-
{
|
|
1048
|
-
"columnName": "id"
|
|
1049
|
-
}
|
|
1050
|
-
]
|
|
1051
|
-
}
|
|
1052
1064
|
}
|
|
1053
1065
|
],
|
|
1054
1066
|
"collections": [],
|
package/src/utility/authProxy.js
CHANGED
|
@@ -185,6 +185,27 @@ async function obtainRefreshedLicense() {
|
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
async function tryToGetRefreshedLicense(oldLicenseKey) {
|
|
189
|
+
try {
|
|
190
|
+
const respToken = await axios.default.post(
|
|
191
|
+
`${AUTH_PROXY_URL}/refresh-license`,
|
|
192
|
+
{},
|
|
193
|
+
{
|
|
194
|
+
headers: {
|
|
195
|
+
'Content-Type': 'application/json',
|
|
196
|
+
Authorization: `Bearer ${oldLicenseKey}`,
|
|
197
|
+
},
|
|
198
|
+
}
|
|
199
|
+
);
|
|
200
|
+
return respToken.data;
|
|
201
|
+
} catch (err) {
|
|
202
|
+
return {
|
|
203
|
+
status: 'error',
|
|
204
|
+
message: err.message,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
188
209
|
/**
|
|
189
210
|
* @param {import('dbgate-types').DatabaseInfo} structure
|
|
190
211
|
* @returns {import('dbgate-types').DatabaseInfoTiny}
|
|
@@ -289,6 +310,32 @@ async function callRefactorSqlQueryApi(query, task, structure, dialect) {
|
|
|
289
310
|
return resp.data;
|
|
290
311
|
}
|
|
291
312
|
|
|
313
|
+
// async function callChatStream({ input, tools }, res) {
|
|
314
|
+
// const resp = await axios.default.post(
|
|
315
|
+
// `${AI_GATEWAY_URL}/chat-stream`,
|
|
316
|
+
// {
|
|
317
|
+
// input,
|
|
318
|
+
// tools,
|
|
319
|
+
// },
|
|
320
|
+
// getAxiosParamsWithLicense()
|
|
321
|
+
// );
|
|
322
|
+
|
|
323
|
+
// res.set(resp.headers);
|
|
324
|
+
// res.status(resp.status);
|
|
325
|
+
// resp.data.pipe(res);
|
|
326
|
+
// }
|
|
327
|
+
|
|
328
|
+
function getAiGatewayServer() {
|
|
329
|
+
return {
|
|
330
|
+
url: AI_GATEWAY_URL,
|
|
331
|
+
headers: {
|
|
332
|
+
Authorization:
|
|
333
|
+
licenseKey ?? process.env.DBGATE_LICENSE ? `Bearer ${licenseKey ?? process.env.DBGATE_LICENSE}` : undefined,
|
|
334
|
+
...getE2ETestHeaders(),
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
292
339
|
module.exports = {
|
|
293
340
|
isAuthProxySupported,
|
|
294
341
|
authProxyGetRedirectUrl,
|
|
@@ -303,4 +350,7 @@ module.exports = {
|
|
|
303
350
|
callCompleteOnCursorApi,
|
|
304
351
|
callRefactorSqlQueryApi,
|
|
305
352
|
getLicenseHttpHeaders,
|
|
353
|
+
tryToGetRefreshedLicense,
|
|
354
|
+
getAiGatewayServer,
|
|
355
|
+
// callChatStream,
|
|
306
356
|
};
|
package/src/utility/cloudIntf.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
2
3
|
const fs = require('fs-extra');
|
|
3
4
|
const _ = require('lodash');
|
|
4
5
|
const path = require('path');
|
|
@@ -216,7 +217,7 @@ async function updateCloudFiles(isRefresh) {
|
|
|
216
217
|
{
|
|
217
218
|
headers: {
|
|
218
219
|
...getLicenseHttpHeaders(),
|
|
219
|
-
...(await
|
|
220
|
+
...(await getCloudInstanceHeaders()),
|
|
220
221
|
'x-app-version': currentVersion.version,
|
|
221
222
|
},
|
|
222
223
|
}
|
|
@@ -300,6 +301,17 @@ async function callCloudApiGet(endpoint, signinHolder = null, additionalHeaders
|
|
|
300
301
|
return resp.data;
|
|
301
302
|
}
|
|
302
303
|
|
|
304
|
+
async function getCloudInstanceHeaders() {
|
|
305
|
+
if (!(await fs.exists(path.join(datadir(), 'cloud-instance.txt')))) {
|
|
306
|
+
const newInstanceId = crypto.randomUUID();
|
|
307
|
+
await fs.writeFile(path.join(datadir(), 'cloud-instance.txt'), newInstanceId);
|
|
308
|
+
}
|
|
309
|
+
const instanceId = await fs.readFile(path.join(datadir(), 'cloud-instance.txt'), 'utf-8');
|
|
310
|
+
return {
|
|
311
|
+
'x-cloud-instance': instanceId,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
303
315
|
async function callCloudApiPost(endpoint, body, signinHolder = null) {
|
|
304
316
|
if (!signinHolder) {
|
|
305
317
|
signinHolder = await getCloudSigninHolder();
|
package/src/utility/crypting.js
CHANGED
|
@@ -101,24 +101,26 @@ function decryptObjectPasswordField(obj, field, encryptor = null) {
|
|
|
101
101
|
return obj;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
const fieldsToEncrypt = ['password', 'sshPassword', 'sshKeyfilePassword', 'connectionDefinition'];
|
|
105
|
+
|
|
104
106
|
function encryptConnection(connection, encryptor = null) {
|
|
105
107
|
if (connection.passwordMode != 'saveRaw') {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
for (const field of fieldsToEncrypt) {
|
|
109
|
+
connection = encryptObjectPasswordField(connection, field, encryptor);
|
|
110
|
+
}
|
|
109
111
|
}
|
|
110
112
|
return connection;
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
function maskConnection(connection) {
|
|
114
116
|
if (!connection) return connection;
|
|
115
|
-
return _.omit(connection,
|
|
117
|
+
return _.omit(connection, fieldsToEncrypt);
|
|
116
118
|
}
|
|
117
119
|
|
|
118
|
-
function decryptConnection(connection
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
function decryptConnection(connection) {
|
|
121
|
+
for (const field of fieldsToEncrypt) {
|
|
122
|
+
connection = decryptObjectPasswordField(connection, field);
|
|
123
|
+
}
|
|
122
124
|
return connection;
|
|
123
125
|
}
|
|
124
126
|
|
|
@@ -188,9 +190,9 @@ function recryptObjectPasswordFieldInPlace(obj, field, decryptEncryptor, encrypt
|
|
|
188
190
|
}
|
|
189
191
|
|
|
190
192
|
function recryptConnection(connection, decryptEncryptor, encryptEncryptor) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
193
|
+
for (const field of fieldsToEncrypt) {
|
|
194
|
+
connection = recryptObjectPasswordField(connection, field, decryptEncryptor, encryptEncryptor);
|
|
195
|
+
}
|
|
194
196
|
return connection;
|
|
195
197
|
}
|
|
196
198
|
|
|
@@ -4,22 +4,32 @@ const _ = require('lodash');
|
|
|
4
4
|
const { sendToAuditLog } = require('./auditlog');
|
|
5
5
|
const { checkLicense } = require('./checkLicense');
|
|
6
6
|
const LOGIN_LIMIT_ERROR = 'Your limit of concurrent logins has been reached';
|
|
7
|
+
const jwt = require('jsonwebtoken');
|
|
7
8
|
|
|
8
9
|
// map string (user key) => time to expiration
|
|
9
10
|
let activeLoggedUsers = {};
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
// map string (user key) => token expiration time
|
|
13
|
+
let activeLoggedTokens = {};
|
|
14
|
+
|
|
15
|
+
function markUserAsActive(licenseUid, accessToken) {
|
|
12
16
|
activeLoggedUsers[licenseUid] = Date.now() + 60 * 1000; // mark user as active for 1 minute
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
async function isLoginLicensed(req, licenseUid) {
|
|
16
20
|
const license = await checkLicense();
|
|
17
21
|
activeLoggedUsers = _.pickBy(activeLoggedUsers, value => value > Date.now());
|
|
22
|
+
activeLoggedTokens = _.pickBy(activeLoggedTokens, value => value > Date.now());
|
|
18
23
|
if (licenseUid in activeLoggedUsers) {
|
|
19
24
|
return true;
|
|
20
25
|
}
|
|
26
|
+
if (licenseUid in activeLoggedTokens) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
21
29
|
if (license.licenseId == 'f0346efe-ebc2-4822-9a83-4b4668a897e5' && license?.users != null) {
|
|
22
|
-
const
|
|
30
|
+
const uniqUsers = _.uniq([...Object.keys(activeLoggedUsers), ...Object.keys(activeLoggedTokens)]);
|
|
31
|
+
const currentUserCount = uniqUsers.length;
|
|
32
|
+
|
|
23
33
|
if (currentUserCount >= license?.users) {
|
|
24
34
|
sendToAuditLog(req, {
|
|
25
35
|
category: 'auth',
|
|
@@ -37,8 +47,23 @@ async function isLoginLicensed(req, licenseUid) {
|
|
|
37
47
|
return true;
|
|
38
48
|
}
|
|
39
49
|
|
|
50
|
+
function markTokenAsLoggedIn(licenseUid, token) {
|
|
51
|
+
if (licenseUid != 'anonymous') {
|
|
52
|
+
const decoded = jwt.decode(token);
|
|
53
|
+
activeLoggedTokens[licenseUid] = decoded.exp * 1000;
|
|
54
|
+
}
|
|
55
|
+
activeLoggedUsers[licenseUid] = Date.now() + 60 * 1000; // mark user as active for 1 minute
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function markLoginAsLoggedOut(licenseUid) {
|
|
59
|
+
delete activeLoggedUsers[licenseUid];
|
|
60
|
+
delete activeLoggedTokens[licenseUid];
|
|
61
|
+
}
|
|
62
|
+
|
|
40
63
|
module.exports = {
|
|
41
64
|
markUserAsActive,
|
|
65
|
+
markTokenAsLoggedIn,
|
|
42
66
|
isLoginLicensed,
|
|
43
67
|
LOGIN_LIMIT_ERROR,
|
|
68
|
+
markLoginAsLoggedOut,
|
|
44
69
|
};
|