dbgate-api-premium 5.5.7-alpha.60 → 5.5.7-alpha.68

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-premium",
3
3
  "main": "src/index.js",
4
- "version": "5.5.7-alpha.60",
4
+ "version": "5.5.7-alpha.68",
5
5
  "homepage": "https://dbgate.org/",
6
6
  "repository": {
7
7
  "type": "git",
@@ -29,10 +29,10 @@
29
29
  "compare-versions": "^3.6.0",
30
30
  "cors": "^2.8.5",
31
31
  "cross-env": "^6.0.3",
32
- "dbgate-datalib": "^5.5.7-alpha.60",
32
+ "dbgate-datalib": "^5.5.7-alpha.68",
33
33
  "dbgate-query-splitter": "^4.11.2",
34
- "dbgate-sqltree": "^5.5.7-alpha.60",
35
- "dbgate-tools": "^5.5.7-alpha.60",
34
+ "dbgate-sqltree": "^5.5.7-alpha.68",
35
+ "dbgate-tools": "^5.5.7-alpha.68",
36
36
  "debug": "^4.3.4",
37
37
  "diff": "^5.0.0",
38
38
  "diff2html": "^3.4.13",
@@ -81,7 +81,7 @@
81
81
  "devDependencies": {
82
82
  "@types/fs-extra": "^9.0.11",
83
83
  "@types/lodash": "^4.14.149",
84
- "dbgate-types": "^5.5.7-alpha.60",
84
+ "dbgate-types": "^5.5.7-alpha.68",
85
85
  "env-cmd": "^10.1.0",
86
86
  "jsdoc-to-markdown": "^9.0.5",
87
87
  "node-loader": "^1.0.2",
@@ -62,6 +62,8 @@ module.exports = {
62
62
  const logoutUrl = storageConnectionError ? null : await authProvider.getLogoutUrl();
63
63
  const adminConfig = storageConnectionError ? null : await storage.readConfig({ group: 'admin' });
64
64
 
65
+ storage.startRefreshLicense();
66
+
65
67
  const isAdminPasswordMissing = !!(
66
68
  process.env.STORAGE_DATABASE &&
67
69
  !process.env.ADMIN_PASSWORD &&
@@ -81,7 +83,7 @@ module.exports = {
81
83
  isElectron: platformInfo.isElectron,
82
84
  isLicenseValid,
83
85
  isLicenseExpired: checkedLicense?.isExpired,
84
- trialDaysLeft: checkedLicense?.isGeneratedTrial && !checkedLicense?.isExpired ? checkedLicense?.daysLeft : null,
86
+ trialDaysLeft: checkedLicense?.licenseTypeObj?.isTrial && !checkedLicense?.isExpired ? checkedLicense?.daysLeft : null,
85
87
  checkedLicense,
86
88
  configurationError,
87
89
  logoutUrl,
@@ -201,6 +201,7 @@ module.exports = {
201
201
  // @ts-ignore
202
202
  this.datastore = new JsonLinesDatabase(path.join(dir, 'connections.jsonl'));
203
203
  }
204
+ await this.checkUnsavedConnectionsLimit();
204
205
  },
205
206
 
206
207
  list_meta: true,
@@ -300,6 +301,29 @@ module.exports = {
300
301
  return res;
301
302
  },
302
303
 
304
+ async checkUnsavedConnectionsLimit() {
305
+ const MAX_UNSAVED_CONNECTIONS = 5;
306
+ await this.datastore.transformAll(connections => {
307
+ const count = connections.filter(x => x.unsaved).length;
308
+ if (count > MAX_UNSAVED_CONNECTIONS) {
309
+ const res = [];
310
+ let unsavedToSkip = count - MAX_UNSAVED_CONNECTIONS;
311
+ for (const item of connections) {
312
+ if (item.unsaved) {
313
+ if (unsavedToSkip > 0) {
314
+ unsavedToSkip--;
315
+ } else {
316
+ res.push(item);
317
+ }
318
+ } else {
319
+ res.push(item);
320
+ }
321
+ }
322
+ return res;
323
+ }
324
+ });
325
+ },
326
+
303
327
  update_meta: true,
304
328
  async update({ _id, values }, req) {
305
329
  if (portalConnections) return;
@@ -111,7 +111,7 @@ module.exports = {
111
111
  const scriptFile = path.join(uploadsdir(), runid + '.js');
112
112
  fs.writeFileSync(`${scriptFile}`, scriptText);
113
113
  fs.mkdirSync(directory);
114
- const pluginNames = _.union(fs.readdirSync(pluginsdir()), packagedPluginList);
114
+ const pluginNames = extractPlugins(scriptText);
115
115
  logger.info({ scriptFile }, 'Running script');
116
116
  // const subprocess = fork(scriptFile, ['--checkParent', '--max-old-space-size=8192'], {
117
117
  const subprocess = fork(
@@ -52,7 +52,7 @@ module.exports = {
52
52
  if (existing) return existing;
53
53
  const connection = await connections.getCore({ conid });
54
54
  if (!connection) {
55
- throw new Error(`Connection with conid="${conid}" not fund`);
55
+ throw new Error(`Connection with conid="${conid}" not found`);
56
56
  }
57
57
  if (connection.passwordMode == 'askPassword' || connection.passwordMode == 'askUser') {
58
58
  throw new MissingCredentialsError({ conid, passwordMode: connection.passwordMode });
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs-extra');
2
2
  const _ = require('lodash');
3
+ const path = require('path');
3
4
  const { setAuthProviders, getAuthProviderById } = require('../auth/authProvider');
4
5
  const { createStorageAuthProvider } = require('../auth/storageAuthProvider');
5
6
  const {
@@ -16,8 +17,12 @@ const { hasPermission } = require('../utility/hasPermission');
16
17
  const { changeSetToSql, removeSchemaFromChangeSet } = require('dbgate-datalib');
17
18
  const storageModel = require('../storageModel');
18
19
  const { dumpSqlCommand } = require('dbgate-sqltree');
19
- const { runCommandOnDriver } = require('dbgate-tools');
20
+ const { runCommandOnDriver, getLogger } = require('dbgate-tools');
20
21
  const socket = require('../utility/socket');
22
+ const { obtainRefreshedLicense } = require('../utility/authProxy');
23
+ const { datadir } = require('../utility/directories');
24
+
25
+ const logger = getLogger('storage');
21
26
 
22
27
  function mapConnection(connnection) {
23
28
  return {
@@ -32,6 +37,8 @@ async function runQueryFmt(driver, conn, query, ...args) {
32
37
  await driver.query(conn, dmp.s);
33
38
  }
34
39
 
40
+ let refreshLicenseStarted = false;
41
+
35
42
  module.exports = {
36
43
  async _init() {
37
44
  if (!process.env.STORAGE_DATABASE) {
@@ -48,6 +55,32 @@ module.exports = {
48
55
  setAuthProviders(providers, providers[defIndex]);
49
56
  },
50
57
 
58
+ async startRefreshLicense() {
59
+ if (refreshLicenseStarted) {
60
+ return;
61
+ }
62
+ refreshLicenseStarted = true;
63
+ const resp = await obtainRefreshedLicense();
64
+ if (!resp) {
65
+ return;
66
+ }
67
+ if (resp.status == 'error') {
68
+ logger.error(`Error refreshing license: ${resp.message}`);
69
+ return;
70
+ }
71
+ if (resp.status != 'ok') {
72
+ return;
73
+ }
74
+ const { token } = resp;
75
+ logger.info('License succesfully refreshed');
76
+ if (process.env.STORAGE_DATABASE) {
77
+ await this.writeConfig({ group: 'license', config: { licenseKey: token } });
78
+ } else {
79
+ await fs.writeFile(path.join(datadir(), 'license.key'), token);
80
+ }
81
+ socket.emitChanged(`config-changed`);
82
+ },
83
+
51
84
  connections_meta: true,
52
85
  async connections(req) {
53
86
  if (!process.env.STORAGE_DATABASE) {
@@ -81,6 +81,7 @@ async function getStorageConnectionCore() {
81
81
  systemConnection: newConnection,
82
82
  driver: storageDriver,
83
83
  loadedDbModel: storageModel,
84
+ targetSchema: process.env.STORAGE_SCHEMA,
84
85
  });
85
86
 
86
87
  storageConnection = newConnection;
@@ -1,5 +1,5 @@
1
1
 
2
2
  module.exports = {
3
- version: '5.5.7-alpha.60',
4
- buildTime: '2024-11-20T09:21:10.849Z'
3
+ version: '5.5.7-alpha.68',
4
+ buildTime: '2024-12-03T15:39:33.137Z'
5
5
  };
@@ -111,6 +111,15 @@ class JsonLinesDatabase {
111
111
  return removed;
112
112
  }
113
113
 
114
+ async transformAll(transformFunction) {
115
+ await this._ensureLoaded();
116
+ const newData = transformFunction(this.data);
117
+ if (newData) {
118
+ this.data = newData;
119
+ await this._save();
120
+ }
121
+ }
122
+
114
123
  // async _openReader() {
115
124
  // return new Promise((resolve, reject) =>
116
125
  // lineReader.open(this.filename, (err, reader) => {
@@ -1,8 +1,12 @@
1
1
  const axios = require('axios');
2
2
  const { Signer } = require('@aws-sdk/rds-signer');
3
+ const jwt = require('jsonwebtoken');
4
+ const { getLogger, extractErrorLogData } = require('dbgate-tools');
3
5
 
4
- const AUTH_PROXY_URL = process.env.DEVWEB ? 'https://dbgate-auth-proxy.stages.udolni.net' : 'https://auth.dbgate.eu';
5
- // const AUTH_PROXY_URL = 'https://dbgate-auth-proxy.stages.udolni.net';
6
+ const logger = getLogger('authProxy');
7
+
8
+ const AUTH_PROXY_URL = process.env.DEVWEB ? 'https://auth-proxy.dbgate.udolni.net' : 'https://auth.dbgate.eu';
9
+ // const AUTH_PROXY_URL = 'https://auth-proxy.dbgate.udolni.net';
6
10
 
7
11
  let licenseKey = null;
8
12
 
@@ -91,7 +95,7 @@ function startTokenChecking(sid, callback) {
91
95
  callback(resp.data.token);
92
96
  }
93
97
  } catch (err) {
94
- console.error('Error checking token', err);
98
+ logger.error(extractErrorLogData(err), 'Error checking token');
95
99
  }
96
100
  }, 500);
97
101
  }
@@ -121,6 +125,37 @@ async function getAwsIamToken(props) {
121
125
  return token;
122
126
  }
123
127
 
128
+ async function obtainRefreshedLicense() {
129
+ if (!licenseKey) {
130
+ return null;
131
+ }
132
+
133
+ const decoded = jwt.decode(licenseKey);
134
+
135
+ if (Date.now() > decoded.end * 1000) {
136
+ logger.info('License expired, trying to obtain fresh license');
137
+
138
+ try {
139
+ const respToken = await axios.default.post(
140
+ `${AUTH_PROXY_URL}/refresh-license`,
141
+ {},
142
+ {
143
+ headers: {
144
+ 'Content-Type': 'application/json',
145
+ Authorization: `Bearer ${licenseKey}`,
146
+ },
147
+ }
148
+ );
149
+ return respToken.data;
150
+ } catch (err) {
151
+ return {
152
+ status: 'error',
153
+ message: err.message,
154
+ };
155
+ }
156
+ }
157
+ }
158
+
124
159
  module.exports = {
125
160
  isAuthProxySupported,
126
161
  authProxyGetRedirectUrl,
@@ -130,4 +165,5 @@ module.exports = {
130
165
  getAuthProxyUrl,
131
166
  supportsAwsIam,
132
167
  getAwsIamToken,
168
+ obtainRefreshedLicense,
133
169
  };
@@ -23,6 +23,46 @@ mQIDAQAB
23
23
  -----END PUBLIC KEY-----
24
24
  `;
25
25
 
26
+ const licenseTypeById = {
27
+ '1414ede2-dfb3-4539-a93d-24db7e5b59d9': {
28
+ // premium generated by stripe
29
+ name: 'Premium',
30
+ isPremium: true,
31
+ isForWeb: false,
32
+ isForApp: true,
33
+ },
34
+ '9682a88b-909f-48b1-adbf-c03622884421': {
35
+ name: 'Team Premium',
36
+ isPremium: true,
37
+ isForWeb: true,
38
+ isForApp: true,
39
+ },
40
+ '81456363-f167-41e3-9496-b540f4b0c150': {
41
+ name: 'Premium Trial',
42
+ isPremium: true,
43
+ isForWeb: true,
44
+ isForApp: true,
45
+ isTrial: true,
46
+ },
47
+ };
48
+
49
+ function getLicenseByDecoded(decoded) {
50
+ if (!decoded) {
51
+ return null;
52
+ }
53
+ if (decoded.licenseId) {
54
+ return licenseTypeById[decoded.licenseId];
55
+ }
56
+ if (decoded.licenseType == 'premium') {
57
+ if (decoded.isGeneratedTrial) {
58
+ return licenseTypeById['81456363-f167-41e3-9496-b540f4b0c150'];
59
+ } else {
60
+ return licenseTypeById['9682a88b-909f-48b1-adbf-c03622884421'];
61
+ }
62
+ }
63
+ return null;
64
+ }
65
+
26
66
  let awsMetadataLoaded = false;
27
67
  let awsMetadata = null;
28
68
  async function getAwsMetadata() {
@@ -71,20 +111,27 @@ function checkLicenseKey(licenseKey) {
71
111
  const decoded = jwt.verify(licenseKey, publicKey, {
72
112
  algorithms: ['RS256'],
73
113
  });
74
- if (decoded.licenseType != 'premium') {
75
- logger.error(`Incorrect license type, expected premium, found ${decoded.licenseType}`);
114
+
115
+ const licenseTypeObj = getLicenseByDecoded(decoded);
116
+
117
+ if (
118
+ !licenseTypeObj ||
119
+ (platformInfo.isElectron && !licenseTypeObj.isForApp) ||
120
+ (!platformInfo.isElectron && !licenseTypeObj.isForWeb)
121
+ ) {
122
+ logger.error(`Incorrect license type, found ${decoded.licenseType}`);
76
123
  return {
77
124
  status: 'error',
78
- error: `Incorrect license type, expected premium, found ${decoded.licenseType}`,
125
+ error: `Incorrect license type, found ${decoded.licenseType}`,
79
126
  };
80
127
  }
128
+
81
129
  return {
82
130
  status: 'ok',
83
- type: 'premium',
84
131
  validTo: decoded.validTo,
85
132
  expiration: new Date(decoded.exp * 1000).toISOString(),
86
133
  daysLeft: Math.round((decoded.exp * 1000 - Date.now()) / (24 * 60 * 60 * 1000)),
87
- isGeneratedTrial: decoded.isGeneratedTrial,
134
+ licenseTypeObj,
88
135
  };
89
136
  } catch (err) {
90
137
  try {
@@ -187,5 +234,6 @@ function isProApp() {
187
234
  module.exports = {
188
235
  checkLicense,
189
236
  checkLicenseKey,
190
- isProApp
237
+ isProApp,
238
+ licenseTypeById,
191
239
  };