dbgate-api 6.5.4 → 6.5.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dbgate-api",
3
3
  "main": "src/index.js",
4
- "version": "6.5.4",
4
+ "version": "6.5.5",
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.5.4",
33
+ "dbgate-datalib": "^6.5.5",
34
34
  "dbgate-query-splitter": "^4.11.5",
35
- "dbgate-sqltree": "^6.5.4",
36
- "dbgate-tools": "^6.5.4",
35
+ "dbgate-sqltree": "^6.5.5",
36
+ "dbgate-tools": "^6.5.5",
37
37
  "debug": "^4.3.4",
38
38
  "diff": "^5.0.0",
39
39
  "diff2html": "^3.4.13",
@@ -85,7 +85,7 @@
85
85
  "devDependencies": {
86
86
  "@types/fs-extra": "^9.0.11",
87
87
  "@types/lodash": "^4.14.149",
88
- "dbgate-types": "^6.5.4",
88
+ "dbgate-types": "^6.5.5",
89
89
  "env-cmd": "^10.1.0",
90
90
  "jsdoc-to-markdown": "^9.0.5",
91
91
  "node-loader": "^1.0.2",
@@ -11,7 +11,7 @@ const logger = getLogger('authProvider');
11
11
  class AuthProviderBase {
12
12
  amoid = 'none';
13
13
 
14
- async login(login, password, options = undefined) {
14
+ async login(login, password, options = undefined, req = undefined) {
15
15
  return {
16
16
  accessToken: jwt.sign(
17
17
  {
@@ -23,7 +23,7 @@ class AuthProviderBase {
23
23
  };
24
24
  }
25
25
 
26
- oauthToken(params) {
26
+ oauthToken(params, req) {
27
27
  return {};
28
28
  }
29
29
 
@@ -13,8 +13,15 @@ const {
13
13
  } = require('../auth/authProvider');
14
14
  const storage = require('./storage');
15
15
  const { decryptPasswordString } = require('../utility/crypting');
16
- const { createDbGateIdentitySession, startCloudTokenChecking } = require('../utility/cloudIntf');
16
+ const {
17
+ createDbGateIdentitySession,
18
+ startCloudTokenChecking,
19
+ readCloudTokenHolder,
20
+ readCloudTestTokenHolder,
21
+ } = require('../utility/cloudIntf');
17
22
  const socket = require('../utility/socket');
23
+ const { sendToAuditLog } = require('../utility/auditlog');
24
+ const { isLoginLicensed, LOGIN_LIMIT_ERROR } = require('../utility/loginchecker');
18
25
 
19
26
  const logger = getLogger('auth');
20
27
 
@@ -72,6 +79,8 @@ function authMiddleware(req, res, next) {
72
79
  try {
73
80
  const decoded = jwt.verify(token, getTokenSecret());
74
81
  req.user = decoded;
82
+ storage.markUserAsActive(decoded.licenseUid);
83
+
75
84
  return next();
76
85
  } catch (err) {
77
86
  if (skipAuth) {
@@ -87,12 +96,12 @@ function authMiddleware(req, res, next) {
87
96
 
88
97
  module.exports = {
89
98
  oauthToken_meta: true,
90
- async oauthToken(params) {
99
+ async oauthToken(params, req) {
91
100
  const { amoid } = params;
92
- return getAuthProviderById(amoid).oauthToken(params);
101
+ return getAuthProviderById(amoid).oauthToken(params, req);
93
102
  },
94
103
  login_meta: true,
95
- async login(params) {
104
+ async login(params, req) {
96
105
  const { amoid, login, password, isAdminPage } = params;
97
106
 
98
107
  if (isAdminPage) {
@@ -102,12 +111,26 @@ module.exports = {
102
111
  adminPassword = decryptPasswordString(adminConfig?.adminPassword);
103
112
  }
104
113
  if (adminPassword && adminPassword == password) {
114
+ if (!(await isLoginLicensed(req, `superadmin`))) {
115
+ return { error: LOGIN_LIMIT_ERROR };
116
+ }
117
+
118
+ sendToAuditLog(req, {
119
+ category: 'auth',
120
+ component: 'AuthController',
121
+ action: 'login',
122
+ event: 'login.admin',
123
+ severity: 'info',
124
+ message: 'Administration login successful',
125
+ });
126
+
105
127
  return {
106
128
  accessToken: jwt.sign(
107
129
  {
108
130
  login: 'superadmin',
109
131
  permissions: await storage.loadSuperadminPermissions(),
110
132
  roleId: -3,
133
+ licenseUid: `superadmin`,
111
134
  },
112
135
  getTokenSecret(),
113
136
  {
@@ -117,10 +140,19 @@ module.exports = {
117
140
  };
118
141
  }
119
142
 
143
+ sendToAuditLog(req, {
144
+ category: 'auth',
145
+ component: 'AuthController',
146
+ action: 'loginFail',
147
+ event: 'login.adminFailed',
148
+ severity: 'warn',
149
+ message: 'Administraton login failed',
150
+ });
151
+
120
152
  return { error: 'Login failed' };
121
153
  }
122
154
 
123
- return getAuthProviderById(amoid).login(login, password);
155
+ return getAuthProviderById(amoid).login(login, password, undefined, req);
124
156
  },
125
157
 
126
158
  getProviders_meta: true,
@@ -138,8 +170,8 @@ module.exports = {
138
170
  },
139
171
 
140
172
  createCloudLoginSession_meta: true,
141
- async createCloudLoginSession({ client }) {
142
- const res = await createDbGateIdentitySession(client);
173
+ async createCloudLoginSession({ client, redirectUri }) {
174
+ const res = await createDbGateIdentitySession(client, redirectUri);
143
175
  startCloudTokenChecking(res.sid, tokenHolder => {
144
176
  socket.emit('got-cloud-token', tokenHolder);
145
177
  socket.emitChanged('cloud-content-changed');
@@ -148,5 +180,17 @@ module.exports = {
148
180
  return res;
149
181
  },
150
182
 
183
+ cloudLoginRedirected_meta: true,
184
+ async cloudLoginRedirected({ sid }) {
185
+ const tokenHolder = await readCloudTokenHolder(sid);
186
+ return tokenHolder;
187
+ },
188
+
189
+ cloudTestLogin_meta: true,
190
+ async cloudTestLogin({ email }) {
191
+ const tokenHolder = await readCloudTestTokenHolder(email);
192
+ return tokenHolder;
193
+ },
194
+
151
195
  authMiddleware,
152
196
  };
@@ -258,4 +258,22 @@ module.exports = {
258
258
  await fs.writeFile(filePath, content);
259
259
  return true;
260
260
  },
261
+
262
+ folderUsers_meta: true,
263
+ async folderUsers({ folid }) {
264
+ const resp = await callCloudApiGet(`content-folders/users/${folid}`);
265
+ return resp;
266
+ },
267
+
268
+ setFolderUserRole_meta: true,
269
+ async setFolderUserRole({ folid, email, role }) {
270
+ const resp = await callCloudApiPost(`content-folders/set-user-role/${folid}`, { email, role });
271
+ return resp;
272
+ },
273
+
274
+ removeFolderUser_meta: true,
275
+ async removeFolderUser({ folid, email }) {
276
+ const resp = await callCloudApiPost(`content-folders/remove-user/${folid}`, { email });
277
+ return resp;
278
+ },
261
279
  };
@@ -29,6 +29,7 @@ const {
29
29
  } = require('../utility/crypting');
30
30
 
31
31
  const lock = new AsyncLock();
32
+ let cachedSettingsValue = null;
32
33
 
33
34
  module.exports = {
34
35
  // settingsValue: {},
@@ -118,6 +119,7 @@ module.exports = {
118
119
  supportCloudAutoUpgrade: !!process.env.CLOUD_UPGRADE_FILE,
119
120
  allowPrivateCloud: platformInfo.isElectron || !!process.env.ALLOW_DBGATE_PRIVATE_CLOUD,
120
121
  ...currentVersion,
122
+ redirectToDbGateCloudLogin: !!process.env.REDIRECT_TO_DBGATE_CLOUD_LOGIN,
121
123
  };
122
124
 
123
125
  return configResult;
@@ -144,6 +146,13 @@ module.exports = {
144
146
  return res;
145
147
  },
146
148
 
149
+ async getCachedSettings() {
150
+ if (!cachedSettingsValue) {
151
+ cachedSettingsValue = await this.loadSettings();
152
+ }
153
+ return cachedSettingsValue;
154
+ },
155
+
147
156
  deleteSettings_meta: true,
148
157
  async deleteSettings() {
149
158
  await fs.unlink(path.join(datadir(), processArgs.runE2eTests ? 'settings-e2etests.json' : 'settings.json'));
@@ -257,6 +266,7 @@ module.exports = {
257
266
  updateSettings_meta: true,
258
267
  async updateSettings(values, req) {
259
268
  if (!hasPermission(`settings/change`, req)) return false;
269
+ cachedSettingsValue = null;
260
270
 
261
271
  const res = await lock.acquire('settings', async () => {
262
272
  const currentValue = await this.loadSettings();
@@ -265,7 +275,11 @@ module.exports = {
265
275
  if (process.env.STORAGE_DATABASE) {
266
276
  updated = {
267
277
  ...currentValue,
268
- ...values,
278
+ ..._.mapValues(values, v => {
279
+ if (v === true) return 'true';
280
+ if (v === false) return 'false';
281
+ return v;
282
+ }),
269
283
  };
270
284
  await storage.writeConfig({
271
285
  group: 'settings',
@@ -303,7 +317,7 @@ module.exports = {
303
317
  const resp = await axios.default.get('https://raw.githubusercontent.com/dbgate/dbgate/master/CHANGELOG.md');
304
318
  return resp.data;
305
319
  } catch (err) {
306
- return ''
320
+ return '';
307
321
  }
308
322
  },
309
323
 
@@ -536,14 +536,14 @@ module.exports = {
536
536
  },
537
537
 
538
538
  dbloginAuthToken_meta: true,
539
- async dbloginAuthToken({ amoid, code, conid, redirectUri, sid }) {
539
+ async dbloginAuthToken({ amoid, code, conid, redirectUri, sid }, req) {
540
540
  try {
541
541
  const connection = await this.getCore({ conid });
542
542
  const driver = requireEngineDriver(connection);
543
543
  const accessToken = await driver.getAuthTokenFromCode(connection, { code, redirectUri, sid });
544
544
  const volatile = await this.saveVolatile({ conid, accessToken });
545
545
  const authProvider = getAuthProviderById(amoid);
546
- const resp = await authProvider.login(null, null, { conid: volatile._id });
546
+ const resp = await authProvider.login(null, null, { conid: volatile._id }, req);
547
547
  return resp;
548
548
  } catch (err) {
549
549
  logger.error(extractErrorLogData(err), 'Error getting DB token');
@@ -552,18 +552,18 @@ module.exports = {
552
552
  },
553
553
 
554
554
  dbloginAuth_meta: true,
555
- async dbloginAuth({ amoid, conid, user, password }) {
555
+ async dbloginAuth({ amoid, conid, user, password }, req) {
556
556
  if (user || password) {
557
557
  const saveResp = await this.saveVolatile({ conid, user, password, test: true });
558
558
  if (saveResp.msgtype == 'connected') {
559
- const loginResp = await getAuthProviderById(amoid).login(user, password, { conid: saveResp._id });
559
+ const loginResp = await getAuthProviderById(amoid).login(user, password, { conid: saveResp._id }, req);
560
560
  return loginResp;
561
561
  }
562
562
  return saveResp;
563
563
  }
564
564
 
565
565
  // user and password is stored in connection, volatile connection is not needed
566
- const loginResp = await getAuthProviderById(amoid).login(null, null, { conid });
566
+ const loginResp = await getAuthProviderById(amoid).login(null, null, { conid }, req);
567
567
  return loginResp;
568
568
  },
569
569
 
@@ -41,6 +41,7 @@ const { decryptConnection } = require('../utility/crypting');
41
41
  const { getSshTunnel } = require('../utility/sshTunnel');
42
42
  const sessions = require('./sessions');
43
43
  const jsldata = require('./jsldata');
44
+ const { sendToAuditLog } = require('../utility/auditlog');
44
45
 
45
46
  const logger = getLogger('databaseConnections');
46
47
 
@@ -83,8 +84,11 @@ module.exports = {
83
84
  }
84
85
  },
85
86
  handle_response(conid, database, { msgid, ...response }) {
86
- const [resolve, reject] = this.requests[msgid];
87
+ const [resolve, reject, additionalData] = this.requests[msgid];
87
88
  resolve(response);
89
+ if (additionalData?.auditLogger) {
90
+ additionalData?.auditLogger(response);
91
+ }
88
92
  delete this.requests[msgid];
89
93
  },
90
94
  handle_status(conid, database, { status }) {
@@ -215,10 +219,10 @@ module.exports = {
215
219
  },
216
220
 
217
221
  /** @param {import('dbgate-types').OpenedDatabaseConnection} conn */
218
- sendRequest(conn, message) {
222
+ sendRequest(conn, message, additionalData = {}) {
219
223
  const msgid = crypto.randomUUID();
220
224
  const promise = new Promise((resolve, reject) => {
221
- this.requests[msgid] = [resolve, reject];
225
+ this.requests[msgid] = [resolve, reject, additionalData];
222
226
  try {
223
227
  conn.subprocess.send({ msgid, ...message });
224
228
  } catch (err) {
@@ -242,18 +246,57 @@ module.exports = {
242
246
  },
243
247
 
244
248
  sqlSelect_meta: true,
245
- async sqlSelect({ conid, database, select }, req) {
249
+ async sqlSelect({ conid, database, select, auditLogSessionGroup }, req) {
246
250
  testConnectionPermission(conid, req);
247
251
  const opened = await this.ensureOpened(conid, database);
248
- const res = await this.sendRequest(opened, { msgtype: 'sqlSelect', select });
252
+ const res = await this.sendRequest(
253
+ opened,
254
+ { msgtype: 'sqlSelect', select },
255
+ {
256
+ auditLogger:
257
+ auditLogSessionGroup && select?.from?.name?.pureName
258
+ ? response => {
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'}::${
271
+ select?.from?.name?.pureName
272
+ }`,
273
+ sessionGroup: auditLogSessionGroup,
274
+ message: `Loaded table data from ${select?.from?.name?.pureName}`,
275
+ });
276
+ }
277
+ : null,
278
+ }
279
+ );
249
280
  return res;
250
281
  },
251
282
 
252
283
  runScript_meta: true,
253
- async runScript({ conid, database, sql, useTransaction }, req) {
284
+ async runScript({ conid, database, sql, useTransaction, logMessage }, req) {
254
285
  testConnectionPermission(conid, req);
255
286
  logger.info({ conid, database, sql }, 'Processing script');
256
287
  const opened = await this.ensureOpened(conid, database);
288
+ sendToAuditLog(req, {
289
+ category: 'dbop',
290
+ component: 'DatabaseConnectionsController',
291
+ event: 'sql.runscript',
292
+ action: 'runscript',
293
+ severity: 'info',
294
+ conid,
295
+ database,
296
+ detail: sql,
297
+ message: logMessage || `Running SQL script`,
298
+ });
299
+
257
300
  const res = await this.sendRequest(opened, { msgtype: 'runScript', sql, useTransaction });
258
301
  return res;
259
302
  },
@@ -262,16 +305,53 @@ module.exports = {
262
305
  async runOperation({ conid, database, operation, useTransaction }, req) {
263
306
  testConnectionPermission(conid, req);
264
307
  logger.info({ conid, database, operation }, 'Processing operation');
308
+
309
+ sendToAuditLog(req, {
310
+ category: 'dbop',
311
+ component: 'DatabaseConnectionsController',
312
+ event: 'sql.runoperation',
313
+ action: operation.type,
314
+ severity: 'info',
315
+ conid,
316
+ database,
317
+ detail: operation,
318
+ message: `Running DB operation: ${operation.type}`,
319
+ });
320
+
265
321
  const opened = await this.ensureOpened(conid, database);
266
322
  const res = await this.sendRequest(opened, { msgtype: 'runOperation', operation, useTransaction });
267
323
  return res;
268
324
  },
269
325
 
270
326
  collectionData_meta: true,
271
- async collectionData({ conid, database, options }, req) {
327
+ async collectionData({ conid, database, options, auditLogSessionGroup }, req) {
272
328
  testConnectionPermission(conid, req);
273
329
  const opened = await this.ensureOpened(conid, database);
274
- const res = await this.sendRequest(opened, { msgtype: 'collectionData', options });
330
+ const res = await this.sendRequest(
331
+ opened,
332
+ { msgtype: 'collectionData', options },
333
+ {
334
+ auditLogger:
335
+ auditLogSessionGroup && options?.pureName
336
+ ? response => {
337
+ sendToAuditLog(req, {
338
+ category: 'dbop',
339
+ component: 'DatabaseConnectionsController',
340
+ event: 'nosql.collectionData',
341
+ action: 'select',
342
+ severity: 'info',
343
+ conid,
344
+ database,
345
+ pureName: options?.pureName,
346
+ sumint1: response?.result?.rows?.length,
347
+ sessionParam: `${conid}::${database}::${options?.pureName}`,
348
+ sessionGroup: auditLogSessionGroup,
349
+ message: `Loaded collection data ${options?.pureName}`,
350
+ });
351
+ }
352
+ : null,
353
+ }
354
+ );
275
355
  return res.result || null;
276
356
  },
277
357
 
@@ -492,6 +572,20 @@ module.exports = {
492
572
  }
493
573
 
494
574
  const opened = await this.ensureOpened(conid, database);
575
+
576
+ sendToAuditLog(req, {
577
+ category: 'dbop',
578
+ component: 'DatabaseConnectionsController',
579
+ action: 'structure',
580
+ event: 'dbStructure.get',
581
+ severity: 'info',
582
+ conid,
583
+ database,
584
+ sessionParam: `${conid}::${database}`,
585
+ sessionGroup: 'getStructure',
586
+ message: `Loaded database structure for ${database}`,
587
+ });
588
+
495
589
  return opened.structure;
496
590
  // const existing = this.opened.find((x) => x.conid == conid && x.database == database);
497
591
  // if (existing) return existing.status;
@@ -203,10 +203,10 @@ module.exports = {
203
203
  },
204
204
 
205
205
  exportChart_meta: true,
206
- async exportChart({ filePath, title, config, image }) {
206
+ async exportChart({ filePath, title, config, image, plugins }) {
207
207
  const fileName = path.parse(filePath).base;
208
208
  const imageFile = fileName.replace('.html', '-preview.png');
209
- const html = getChartExport(title, config, imageFile);
209
+ const html = getChartExport(title, config, imageFile, plugins);
210
210
  await fs.writeFile(filePath, html);
211
211
  if (image) {
212
212
  const index = image.indexOf('base64,');
@@ -20,6 +20,7 @@ const { handleProcessCommunication } = require('../utility/processComm');
20
20
  const processArgs = require('../utility/processArgs');
21
21
  const platformInfo = require('../utility/platformInfo');
22
22
  const { checkSecureDirectories, checkSecureDirectoriesInScript } = require('../utility/security');
23
+ const { sendToAuditLog, logJsonRunnerScript } = require('../utility/auditlog');
23
24
  const logger = getLogger('runners');
24
25
 
25
26
  function extractPlugins(script) {
@@ -270,7 +271,7 @@ module.exports = {
270
271
  },
271
272
 
272
273
  start_meta: true,
273
- async start({ script }) {
274
+ async start({ script }, req) {
274
275
  const runid = crypto.randomUUID();
275
276
 
276
277
  if (script.type == 'json') {
@@ -280,14 +281,36 @@ module.exports = {
280
281
  }
281
282
  }
282
283
 
284
+ logJsonRunnerScript(req, script);
285
+
283
286
  const js = await jsonScriptToJavascript(script);
284
287
  return this.startCore(runid, scriptTemplate(js, false));
285
288
  }
286
289
 
287
290
  if (!platformInfo.allowShellScripting) {
291
+ sendToAuditLog(req, {
292
+ category: 'shell',
293
+ component: 'RunnersController',
294
+ event: 'script.runFailed',
295
+ action: 'script',
296
+ severity: 'warn',
297
+ detail: script,
298
+ message: 'Scripts are not allowed',
299
+ });
300
+
288
301
  return { errorMessage: 'Shell scripting is not allowed' };
289
302
  }
290
303
 
304
+ sendToAuditLog(req, {
305
+ category: 'shell',
306
+ component: 'RunnersController',
307
+ event: 'script.run.shell',
308
+ action: 'script',
309
+ severity: 'info',
310
+ detail: script,
311
+ message: 'Running JS script',
312
+ });
313
+
291
314
  return this.startCore(runid, scriptTemplate(script, false));
292
315
  },
293
316
 
@@ -12,6 +12,7 @@ const { testConnectionPermission } = require('../utility/hasPermission');
12
12
  const { MissingCredentialsError } = require('../utility/exceptions');
13
13
  const pipeForkLogs = require('../utility/pipeForkLogs');
14
14
  const { getLogger, extractErrorLogData } = require('dbgate-tools');
15
+ const { sendToAuditLog } = require('../utility/auditlog');
15
16
 
16
17
  const logger = getLogger('serverConnection');
17
18
 
@@ -145,6 +146,17 @@ module.exports = {
145
146
  if (conid == '__model') return [];
146
147
  testConnectionPermission(conid, req);
147
148
  const opened = await this.ensureOpened(conid);
149
+ sendToAuditLog(req, {
150
+ category: 'serverop',
151
+ component: 'ServerConnectionsController',
152
+ action: 'listDatabases',
153
+ event: 'databases.list',
154
+ severity: 'info',
155
+ conid,
156
+ sessionParam: `${conid}`,
157
+ sessionGroup: 'listDatabases',
158
+ message: `Loaded databases for connection`,
159
+ });
148
160
  return opened?.databases ?? [];
149
161
  },
150
162
 
@@ -11,6 +11,7 @@ const { appdir } = require('../utility/directories');
11
11
  const { getLogger, extractErrorLogData } = require('dbgate-tools');
12
12
  const pipeForkLogs = require('../utility/pipeForkLogs');
13
13
  const config = require('./config');
14
+ const { sendToAuditLog } = require('../utility/auditlog');
14
15
 
15
16
  const logger = getLogger('sessions');
16
17
 
@@ -146,12 +147,24 @@ module.exports = {
146
147
  },
147
148
 
148
149
  executeQuery_meta: true,
149
- async executeQuery({ sesid, sql, autoCommit, autoDetectCharts, limitRows, frontMatter }) {
150
+ async executeQuery({ sesid, sql, autoCommit, autoDetectCharts, limitRows, frontMatter }, req) {
150
151
  const session = this.opened.find(x => x.sesid == sesid);
151
152
  if (!session) {
152
153
  throw new Error('Invalid session');
153
154
  }
154
155
 
156
+ sendToAuditLog(req, {
157
+ category: 'dbop',
158
+ component: 'SessionController',
159
+ action: 'executeQuery',
160
+ event: 'query.execute',
161
+ severity: 'info',
162
+ detail: sql,
163
+ conid: session.conid,
164
+ database: session.database,
165
+ message: 'Executing query',
166
+ });
167
+
155
168
  logger.info({ sesid, sql }, 'Processing query');
156
169
  this.dispatchMessage(sesid, 'Query execution started');
157
170
  session.subprocess.send({
@@ -31,9 +31,16 @@ module.exports = {
31
31
  return {};
32
32
  },
33
33
 
34
+ sendAuditLog_meta: true,
35
+ async sendAuditLog({}) {
36
+ return null;
37
+ },
38
+
34
39
  startRefreshLicense() {},
35
40
 
36
41
  async getUsedEngines() {
37
42
  return null;
38
43
  },
44
+
45
+ markUserAsActive(licenseUid) {},
39
46
  };
@@ -1,5 +1,5 @@
1
1
 
2
2
  module.exports = {
3
- version: '6.5.4',
4
- buildTime: '2025-06-20T15:05:12.349Z'
3
+ version: '6.5.5',
4
+ buildTime: '2025-07-04T07:10:46.574Z'
5
5
  };
@@ -14,7 +14,7 @@ const crypto = require('crypto');
14
14
  * @param {object} options.driver - driver object. If not provided, it will be loaded from connection
15
15
  * @param {object} options.analysedStructure - analysed structure of the database. If not provided, it will be loaded
16
16
  * @param {string} options.modelFolder - folder with model files (YAML files for tables, SQL files for views, procedures, ...)
17
- * @param {import('dbgate-tools').DatabaseModelFile[]} options.loadedDbModel - loaded database model - collection of yaml and SQL files loaded into array
17
+ * @param {import('dbgate-tools').DatabaseModelFile[] | import('dbgate-types').DatabaseInfo} options.loadedDbModel - loaded database model - collection of yaml and SQL files loaded into array
18
18
  * @param {function[]} options.modelTransforms - array of functions for transforming model
19
19
  * @param {object} options.dbdiffOptionsExtra - extra options for dbdiff
20
20
  * @param {string} options.ignoreNameRegex - regex for ignoring objects by name
@@ -23,7 +23,7 @@ const { connectUtility } = require('../utility/connectUtility');
23
23
  * @param {object} options.driver - driver object. If not provided, it will be loaded from connection
24
24
  * @param {object} options.analysedStructure - analysed structure of the database. If not provided, it will be loaded
25
25
  * @param {string} options.modelFolder - folder with model files (YAML files for tables, SQL files for views, procedures, ...)
26
- * @param {import('dbgate-tools').DatabaseModelFile[]} options.loadedDbModel - loaded database model - collection of yaml and SQL files loaded into array
26
+ * @param {import('dbgate-tools').DatabaseModelFile[] | import('dbgate-types').DatabaseInfo} options.loadedDbModel - loaded database model - collection of yaml and SQL files loaded into array
27
27
  * @param {function[]} options.modelTransforms - array of functions for transforming model
28
28
  * @param {object} options.dbdiffOptionsExtra - extra options for dbdiff
29
29
  * @param {string} options.ignoreNameRegex - regex for ignoring objects by name
@@ -3,7 +3,7 @@ const fs = require('fs-extra');
3
3
  const executeQuery = require('./executeQuery');
4
4
  const { connectUtility } = require('../utility/connectUtility');
5
5
  const requireEngineDriver = require('../utility/requireEngineDriver');
6
- const { getAlterDatabaseScript, DatabaseAnalyser, runCommandOnDriver } = require('dbgate-tools');
6
+ const { getAlterDatabaseScript, DatabaseAnalyser, runCommandOnDriver, adaptDatabaseInfo } = require('dbgate-tools');
7
7
  const importDbModel = require('../utility/importDbModel');
8
8
  const jsonLinesReader = require('./jsonLinesReader');
9
9
  const tableWriter = require('./tableWriter');
@@ -26,10 +26,7 @@ async function importDbFromFolder({ connection, systemConnection, driver, folder
26
26
  if (driver?.databaseEngineTypes?.includes('sql')) {
27
27
  const model = await importDbModel(folder);
28
28
 
29
- let modelAdapted = {
30
- ...model,
31
- tables: model.tables.map(table => driver.adaptTableInfo(table)),
32
- };
29
+ let modelAdapted = adaptDatabaseInfo(model, driver);
33
30
  for (const transform of modelTransforms || []) {
34
31
  modelAdapted = transform(modelAdapted);
35
32
  }
@@ -1,5 +1,192 @@
1
1
  module.exports = {
2
2
  "tables": [
3
+ {
4
+ "pureName": "audit_log",
5
+ "columns": [
6
+ {
7
+ "pureName": "audit_log",
8
+ "columnName": "id",
9
+ "dataType": "int",
10
+ "autoIncrement": true,
11
+ "notNull": true
12
+ },
13
+ {
14
+ "pureName": "audit_log",
15
+ "columnName": "created",
16
+ "dataType": "bigint",
17
+ "notNull": true
18
+ },
19
+ {
20
+ "pureName": "audit_log",
21
+ "columnName": "modified",
22
+ "dataType": "bigint",
23
+ "notNull": false
24
+ },
25
+ {
26
+ "pureName": "audit_log",
27
+ "columnName": "user_id",
28
+ "dataType": "int",
29
+ "notNull": false
30
+ },
31
+ {
32
+ "pureName": "audit_log",
33
+ "columnName": "user_login",
34
+ "dataType": "varchar(250)",
35
+ "notNull": false
36
+ },
37
+ {
38
+ "pureName": "audit_log",
39
+ "columnName": "category",
40
+ "dataType": "varchar(50)",
41
+ "notNull": false
42
+ },
43
+ {
44
+ "pureName": "audit_log",
45
+ "columnName": "component",
46
+ "dataType": "varchar(50)",
47
+ "notNull": false
48
+ },
49
+ {
50
+ "pureName": "audit_log",
51
+ "columnName": "action",
52
+ "dataType": "varchar(50)",
53
+ "notNull": false
54
+ },
55
+ {
56
+ "pureName": "audit_log",
57
+ "columnName": "severity",
58
+ "dataType": "varchar(50)",
59
+ "notNull": false
60
+ },
61
+ {
62
+ "pureName": "audit_log",
63
+ "columnName": "event",
64
+ "dataType": "varchar(100)",
65
+ "notNull": false
66
+ },
67
+ {
68
+ "pureName": "audit_log",
69
+ "columnName": "message",
70
+ "dataType": "varchar(250)",
71
+ "notNull": false
72
+ },
73
+ {
74
+ "pureName": "audit_log",
75
+ "columnName": "detail",
76
+ "dataType": "varchar(1000)",
77
+ "notNull": false
78
+ },
79
+ {
80
+ "pureName": "audit_log",
81
+ "columnName": "detail_full_length",
82
+ "dataType": "int",
83
+ "notNull": false
84
+ },
85
+ {
86
+ "pureName": "audit_log",
87
+ "columnName": "session_id",
88
+ "dataType": "varchar(200)",
89
+ "notNull": false
90
+ },
91
+ {
92
+ "pureName": "audit_log",
93
+ "columnName": "session_group",
94
+ "dataType": "varchar(50)",
95
+ "notNull": false
96
+ },
97
+ {
98
+ "pureName": "audit_log",
99
+ "columnName": "session_param",
100
+ "dataType": "varchar(200)",
101
+ "notNull": false
102
+ },
103
+ {
104
+ "pureName": "audit_log",
105
+ "columnName": "conid",
106
+ "dataType": "varchar(100)",
107
+ "notNull": false
108
+ },
109
+ {
110
+ "pureName": "audit_log",
111
+ "columnName": "connection_data",
112
+ "dataType": "varchar(1000)",
113
+ "notNull": false
114
+ },
115
+ {
116
+ "pureName": "audit_log",
117
+ "columnName": "database",
118
+ "dataType": "varchar(200)",
119
+ "notNull": false
120
+ },
121
+ {
122
+ "pureName": "audit_log",
123
+ "columnName": "schema_name",
124
+ "dataType": "varchar(100)",
125
+ "notNull": false
126
+ },
127
+ {
128
+ "pureName": "audit_log",
129
+ "columnName": "pure_name",
130
+ "dataType": "varchar(100)",
131
+ "notNull": false
132
+ },
133
+ {
134
+ "pureName": "audit_log",
135
+ "columnName": "sumint_1",
136
+ "dataType": "int",
137
+ "notNull": false
138
+ },
139
+ {
140
+ "pureName": "audit_log",
141
+ "columnName": "sumint_2",
142
+ "dataType": "int",
143
+ "notNull": false
144
+ }
145
+ ],
146
+ "foreignKeys": [
147
+ {
148
+ "constraintType": "foreignKey",
149
+ "constraintName": "FK_audit_log_user_id",
150
+ "pureName": "audit_log",
151
+ "refTableName": "users",
152
+ "deleteAction": "SET NULL",
153
+ "columns": [
154
+ {
155
+ "columnName": "user_id",
156
+ "refColumnName": "id"
157
+ }
158
+ ]
159
+ }
160
+ ],
161
+ "indexes": [
162
+ {
163
+ "constraintName": "idx_audit_log_session",
164
+ "pureName": "audit_log",
165
+ "constraintType": "index",
166
+ "columns": [
167
+ {
168
+ "columnName": "session_group"
169
+ },
170
+ {
171
+ "columnName": "session_id"
172
+ },
173
+ {
174
+ "columnName": "session_param"
175
+ }
176
+ ]
177
+ }
178
+ ],
179
+ "primaryKey": {
180
+ "pureName": "audit_log",
181
+ "constraintType": "primaryKey",
182
+ "constraintName": "PK_audit_log",
183
+ "columns": [
184
+ {
185
+ "columnName": "id"
186
+ }
187
+ ]
188
+ }
189
+ },
3
190
  {
4
191
  "pureName": "auth_methods",
5
192
  "columns": [
@@ -50,6 +237,7 @@ module.exports = {
50
237
  "primaryKey": {
51
238
  "pureName": "auth_methods",
52
239
  "constraintType": "primaryKey",
240
+ "constraintName": "PK_auth_methods",
53
241
  "columns": [
54
242
  {
55
243
  "columnName": "id"
@@ -61,7 +249,8 @@ module.exports = {
61
249
  "id": -1,
62
250
  "amoid": "790ca4d2-7f01-4800-955b-d691b890cc50",
63
251
  "name": "Anonymous",
64
- "type": "none"
252
+ "type": "none",
253
+ "is_disabled": 1
65
254
  },
66
255
  {
67
256
  "id": -2,
@@ -69,6 +258,9 @@ module.exports = {
69
258
  "name": "Local",
70
259
  "type": "local"
71
260
  }
261
+ ],
262
+ "preloadedRowsInsertOnly": [
263
+ "is_disabled"
72
264
  ]
73
265
  },
74
266
  {
@@ -103,6 +295,7 @@ module.exports = {
103
295
  "foreignKeys": [
104
296
  {
105
297
  "constraintType": "foreignKey",
298
+ "constraintName": "FK_auth_methods_config_auth_method_id",
106
299
  "pureName": "auth_methods_config",
107
300
  "refTableName": "auth_methods",
108
301
  "deleteAction": "CASCADE",
@@ -114,9 +307,25 @@ module.exports = {
114
307
  ]
115
308
  }
116
309
  ],
310
+ "uniques": [
311
+ {
312
+ "constraintName": "UQ_auth_methods_config_auth_method_id_key",
313
+ "pureName": "auth_methods_config",
314
+ "constraintType": "unique",
315
+ "columns": [
316
+ {
317
+ "columnName": "auth_method_id"
318
+ },
319
+ {
320
+ "columnName": "key"
321
+ }
322
+ ]
323
+ }
324
+ ],
117
325
  "primaryKey": {
118
326
  "pureName": "auth_methods_config",
119
327
  "constraintType": "primaryKey",
328
+ "constraintName": "PK_auth_methods_config",
120
329
  "columns": [
121
330
  {
122
331
  "columnName": "id"
@@ -154,9 +363,25 @@ module.exports = {
154
363
  }
155
364
  ],
156
365
  "foreignKeys": [],
366
+ "uniques": [
367
+ {
368
+ "constraintName": "UQ_config_group_key",
369
+ "pureName": "config",
370
+ "constraintType": "unique",
371
+ "columns": [
372
+ {
373
+ "columnName": "group"
374
+ },
375
+ {
376
+ "columnName": "key"
377
+ }
378
+ ]
379
+ }
380
+ ],
157
381
  "primaryKey": {
158
382
  "pureName": "config",
159
383
  "constraintType": "primaryKey",
384
+ "constraintName": "PK_config",
160
385
  "columns": [
161
386
  {
162
387
  "columnName": "id"
@@ -449,6 +674,7 @@ module.exports = {
449
674
  "primaryKey": {
450
675
  "pureName": "connections",
451
676
  "constraintType": "primaryKey",
677
+ "constraintName": "PK_connections",
452
678
  "columns": [
453
679
  {
454
680
  "columnName": "id"
@@ -456,48 +682,6 @@ module.exports = {
456
682
  ]
457
683
  }
458
684
  },
459
- {
460
- "pureName": "roles",
461
- "columns": [
462
- {
463
- "pureName": "roles",
464
- "columnName": "id",
465
- "dataType": "int",
466
- "autoIncrement": true,
467
- "notNull": true
468
- },
469
- {
470
- "pureName": "roles",
471
- "columnName": "name",
472
- "dataType": "varchar(250)",
473
- "notNull": false
474
- }
475
- ],
476
- "foreignKeys": [],
477
- "primaryKey": {
478
- "pureName": "roles",
479
- "constraintType": "primaryKey",
480
- "columns": [
481
- {
482
- "columnName": "id"
483
- }
484
- ]
485
- },
486
- "preloadedRows": [
487
- {
488
- "id": -1,
489
- "name": "anonymous-user"
490
- },
491
- {
492
- "id": -2,
493
- "name": "logged-user"
494
- },
495
- {
496
- "id": -3,
497
- "name": "superadmin"
498
- }
499
- ]
500
- },
501
685
  {
502
686
  "pureName": "role_connections",
503
687
  "columns": [
@@ -524,6 +708,7 @@ module.exports = {
524
708
  "foreignKeys": [
525
709
  {
526
710
  "constraintType": "foreignKey",
711
+ "constraintName": "FK_role_connections_role_id",
527
712
  "pureName": "role_connections",
528
713
  "refTableName": "roles",
529
714
  "deleteAction": "CASCADE",
@@ -536,6 +721,7 @@ module.exports = {
536
721
  },
537
722
  {
538
723
  "constraintType": "foreignKey",
724
+ "constraintName": "FK_role_connections_connection_id",
539
725
  "pureName": "role_connections",
540
726
  "refTableName": "connections",
541
727
  "deleteAction": "CASCADE",
@@ -550,6 +736,7 @@ module.exports = {
550
736
  "primaryKey": {
551
737
  "pureName": "role_connections",
552
738
  "constraintType": "primaryKey",
739
+ "constraintName": "PK_role_connections",
553
740
  "columns": [
554
741
  {
555
742
  "columnName": "id"
@@ -583,6 +770,7 @@ module.exports = {
583
770
  "foreignKeys": [
584
771
  {
585
772
  "constraintType": "foreignKey",
773
+ "constraintName": "FK_role_permissions_role_id",
586
774
  "pureName": "role_permissions",
587
775
  "refTableName": "roles",
588
776
  "deleteAction": "CASCADE",
@@ -597,6 +785,7 @@ module.exports = {
597
785
  "primaryKey": {
598
786
  "pureName": "role_permissions",
599
787
  "constraintType": "primaryKey",
788
+ "constraintName": "PK_role_permissions",
600
789
  "columns": [
601
790
  {
602
791
  "columnName": "id"
@@ -605,44 +794,47 @@ module.exports = {
605
794
  }
606
795
  },
607
796
  {
608
- "pureName": "users",
797
+ "pureName": "roles",
609
798
  "columns": [
610
799
  {
611
- "pureName": "users",
800
+ "pureName": "roles",
612
801
  "columnName": "id",
613
802
  "dataType": "int",
614
803
  "autoIncrement": true,
615
804
  "notNull": true
616
805
  },
617
806
  {
618
- "pureName": "users",
619
- "columnName": "login",
620
- "dataType": "varchar(250)",
621
- "notNull": false
622
- },
623
- {
624
- "pureName": "users",
625
- "columnName": "password",
626
- "dataType": "varchar(250)",
627
- "notNull": false
628
- },
629
- {
630
- "pureName": "users",
631
- "columnName": "email",
807
+ "pureName": "roles",
808
+ "columnName": "name",
632
809
  "dataType": "varchar(250)",
633
810
  "notNull": false
634
811
  }
635
812
  ],
636
813
  "foreignKeys": [],
637
814
  "primaryKey": {
638
- "pureName": "users",
815
+ "pureName": "roles",
639
816
  "constraintType": "primaryKey",
817
+ "constraintName": "PK_roles",
640
818
  "columns": [
641
819
  {
642
820
  "columnName": "id"
643
821
  }
644
822
  ]
645
- }
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
+ ]
646
838
  },
647
839
  {
648
840
  "pureName": "user_connections",
@@ -670,6 +862,7 @@ module.exports = {
670
862
  "foreignKeys": [
671
863
  {
672
864
  "constraintType": "foreignKey",
865
+ "constraintName": "FK_user_connections_user_id",
673
866
  "pureName": "user_connections",
674
867
  "refTableName": "users",
675
868
  "deleteAction": "CASCADE",
@@ -682,6 +875,7 @@ module.exports = {
682
875
  },
683
876
  {
684
877
  "constraintType": "foreignKey",
878
+ "constraintName": "FK_user_connections_connection_id",
685
879
  "pureName": "user_connections",
686
880
  "refTableName": "connections",
687
881
  "deleteAction": "CASCADE",
@@ -696,6 +890,7 @@ module.exports = {
696
890
  "primaryKey": {
697
891
  "pureName": "user_connections",
698
892
  "constraintType": "primaryKey",
893
+ "constraintName": "PK_user_connections",
699
894
  "columns": [
700
895
  {
701
896
  "columnName": "id"
@@ -729,6 +924,7 @@ module.exports = {
729
924
  "foreignKeys": [
730
925
  {
731
926
  "constraintType": "foreignKey",
927
+ "constraintName": "FK_user_permissions_user_id",
732
928
  "pureName": "user_permissions",
733
929
  "refTableName": "users",
734
930
  "deleteAction": "CASCADE",
@@ -743,6 +939,7 @@ module.exports = {
743
939
  "primaryKey": {
744
940
  "pureName": "user_permissions",
745
941
  "constraintType": "primaryKey",
942
+ "constraintName": "PK_user_permissions",
746
943
  "columns": [
747
944
  {
748
945
  "columnName": "id"
@@ -776,6 +973,7 @@ module.exports = {
776
973
  "foreignKeys": [
777
974
  {
778
975
  "constraintType": "foreignKey",
976
+ "constraintName": "FK_user_roles_user_id",
779
977
  "pureName": "user_roles",
780
978
  "refTableName": "users",
781
979
  "deleteAction": "CASCADE",
@@ -788,6 +986,7 @@ module.exports = {
788
986
  },
789
987
  {
790
988
  "constraintType": "foreignKey",
989
+ "constraintName": "FK_user_roles_role_id",
791
990
  "pureName": "user_roles",
792
991
  "refTableName": "roles",
793
992
  "deleteAction": "CASCADE",
@@ -802,6 +1001,48 @@ module.exports = {
802
1001
  "primaryKey": {
803
1002
  "pureName": "user_roles",
804
1003
  "constraintType": "primaryKey",
1004
+ "constraintName": "PK_user_roles",
1005
+ "columns": [
1006
+ {
1007
+ "columnName": "id"
1008
+ }
1009
+ ]
1010
+ }
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",
805
1046
  "columns": [
806
1047
  {
807
1048
  "columnName": "id"
@@ -815,5 +1056,6 @@ module.exports = {
815
1056
  "matviews": [],
816
1057
  "functions": [],
817
1058
  "procedures": [],
818
- "triggers": []
1059
+ "triggers": [],
1060
+ "schedulerEvents": []
819
1061
  };
@@ -0,0 +1,9 @@
1
+ // only in DbGate Premium
2
+
3
+ async function sendToAuditLog(req, props) {}
4
+ async function logJsonRunnerScript(req, script) {}
5
+
6
+ module.exports = {
7
+ sendToAuditLog,
8
+ logJsonRunnerScript,
9
+ };
@@ -34,11 +34,12 @@ const DBGATE_CLOUD_URL = process.env.LOCAL_DBGATE_CLOUD
34
34
  ? 'https://cloud.dbgate.udolni.net'
35
35
  : 'https://cloud.dbgate.io';
36
36
 
37
- async function createDbGateIdentitySession(client) {
37
+ async function createDbGateIdentitySession(client, redirectUri) {
38
38
  const resp = await axios.default.post(
39
39
  `${DBGATE_IDENTITY_URL}/api/create-session`,
40
40
  {
41
41
  client,
42
+ redirectUri,
42
43
  },
43
44
  {
44
45
  headers: {
@@ -70,7 +71,7 @@ function startCloudTokenChecking(sid, callback) {
70
71
  });
71
72
  // console.log('CHECK RESP:', resp.data);
72
73
 
73
- if (resp.data.email) {
74
+ if (resp.data?.email) {
74
75
  clearInterval(interval);
75
76
  callback(resp.data);
76
77
  }
@@ -80,6 +81,34 @@ function startCloudTokenChecking(sid, callback) {
80
81
  }, 500);
81
82
  }
82
83
 
84
+ async function readCloudTokenHolder(sid) {
85
+ const resp = await axios.default.get(`${DBGATE_IDENTITY_URL}/api/get-token/${sid}`, {
86
+ headers: {
87
+ ...getLicenseHttpHeaders(),
88
+ },
89
+ });
90
+ if (resp.data?.email) {
91
+ return resp.data;
92
+ }
93
+ return null;
94
+ }
95
+
96
+ async function readCloudTestTokenHolder(email) {
97
+ const resp = await axios.default.post(
98
+ `${DBGATE_IDENTITY_URL}/api/test-token`,
99
+ { email },
100
+ {
101
+ headers: {
102
+ ...getLicenseHttpHeaders(),
103
+ },
104
+ }
105
+ );
106
+ if (resp.data?.email) {
107
+ return resp.data;
108
+ }
109
+ return null;
110
+ }
111
+
83
112
  async function loadCloudFiles() {
84
113
  try {
85
114
  const fileContent = await fs.readFile(path.join(datadir(), 'cloud-files.jsonl'), 'utf-8');
@@ -396,4 +425,6 @@ module.exports = {
396
425
  loadCachedCloudConnection,
397
426
  putCloudContent,
398
427
  removeCloudCachedConnection,
428
+ readCloudTokenHolder,
429
+ readCloudTestTokenHolder,
399
430
  };
@@ -1,4 +1,12 @@
1
- const getChartExport = (title, config, imageFile) => {
1
+ const getChartExport = (title, config, imageFile, plugins) => {
2
+ const PLUGIN_TAGS = {
3
+ zoom: '<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/1.2.0/chartjs-plugin-zoom.min.js" integrity="sha512-TT0wAMqqtjXVzpc48sI0G84rBP+oTkBZPgeRYIOVRGUdwJsyS3WPipsNh///ay2LJ+onCM23tipnz6EvEy2/UA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>',
4
+ dataLabels:
5
+ '<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.2.0/chartjs-plugin-datalabels.min.js" integrity="sha512-JPcRR8yFa8mmCsfrw4TNte1ZvF1e3+1SdGMslZvmrzDYxS69J7J49vkFL8u6u8PlPJK+H3voElBtUCzaXj+6ig==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>',
6
+ outlabels:
7
+ '<script src="https://cdn.jsdelivr.net/npm/@energiency/chartjs-plugin-piechart-outlabels@1.3.4/dist/chartjs-plugin-piechart-outlabels.min.js"></script>',
8
+ };
9
+
2
10
  return `<html>
3
11
  <meta charset='utf-8'>
4
12
 
@@ -8,7 +16,7 @@ const getChartExport = (title, config, imageFile) => {
8
16
  <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
9
17
  <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-adapter-moment/1.0.0/chartjs-adapter-moment.min.js" integrity="sha512-oh5t+CdSBsaVVAvxcZKy3XJdP7ZbYUBSRCXDTVn0ODewMDDNnELsrG9eDm8rVZAQg7RsDD/8K3MjPAFB13o6eA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
10
18
  <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js" integrity="sha512-UXumZrZNiOwnTcZSHLOfcTs0aos2MzBWHXOHOuB0J/R44QB0dwY5JgfbvljXcklVf65Gc4El6RjZ+lnwd2az2g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
11
- <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/1.2.0/chartjs-plugin-zoom.min.js" integrity="sha512-TT0wAMqqtjXVzpc48sI0G84rBP+oTkBZPgeRYIOVRGUdwJsyS3WPipsNh///ay2LJ+onCM23tipnz6EvEy2/UA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
19
+ ${plugins.map(plugin => PLUGIN_TAGS[plugin] ?? '')}
12
20
 
13
21
  <style>
14
22
  a { text-decoration: none }
@@ -45,7 +53,7 @@ const getChartExport = (title, config, imageFile) => {
45
53
  </div>
46
54
 
47
55
  <div class="footer">
48
- Exported from <a href='https://dbgate.org/' target='_blank'>DbGate</a>, powered by <a href='https://www.chartjs.org/' target='_blank'>Chart.js</a>
56
+ Exported from <a href='https://dbgate.io/' target='_blank'>DbGate</a>, powered by <a href='https://www.chartjs.org/' target='_blank'>Chart.js</a>
49
57
  </div>
50
58
  </body>
51
59
 
@@ -18,7 +18,7 @@ const getMapExport = (geoJson) => {
18
18
  leaflet
19
19
  .tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
20
20
  maxZoom: 19,
21
- attribution: '<a href="https://dbgate.org" title="Exported from DbGate">DbGate</a> | © OpenStreetMap',
21
+ attribution: '<a href="https://dbgate.io" title="Exported from DbGate">DbGate</a> | © OpenStreetMap',
22
22
  })
23
23
  .addTo(map);
24
24
 
@@ -0,0 +1,15 @@
1
+ // only in DbGate Premium
2
+
3
+ function markUserAsActive(licenseUid) {}
4
+
5
+ async function isLoginLicensed(req, licenseUid) {
6
+ return true;
7
+ }
8
+
9
+ const LOGIN_LIMIT_ERROR = '';
10
+
11
+ module.exports = {
12
+ markUserAsActive,
13
+ isLoginLicensed,
14
+ LOGIN_LIMIT_ERROR,
15
+ };