dbgate-api 4.7.4-alpha.3 → 4.7.4-alpha.7

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": "4.7.4-alpha.3",
4
+ "version": "4.7.4-alpha.7",
5
5
  "homepage": "https://dbgate.org/",
6
6
  "repository": {
7
7
  "type": "git",
@@ -25,9 +25,9 @@
25
25
  "compare-versions": "^3.6.0",
26
26
  "cors": "^2.8.5",
27
27
  "cross-env": "^6.0.3",
28
- "dbgate-query-splitter": "^4.7.4-alpha.3",
29
- "dbgate-sqltree": "^4.7.4-alpha.3",
30
- "dbgate-tools": "^4.7.4-alpha.3",
28
+ "dbgate-query-splitter": "^4.7.4-alpha.7",
29
+ "dbgate-sqltree": "^4.7.4-alpha.7",
30
+ "dbgate-tools": "^4.7.4-alpha.7",
31
31
  "diff": "^5.0.0",
32
32
  "diff2html": "^3.4.13",
33
33
  "eslint": "^6.8.0",
@@ -63,7 +63,7 @@
63
63
  "devDependencies": {
64
64
  "@types/fs-extra": "^9.0.11",
65
65
  "@types/lodash": "^4.14.149",
66
- "dbgate-types": "^4.7.4-alpha.3",
66
+ "dbgate-types": "^4.7.4-alpha.7",
67
67
  "env-cmd": "^10.1.0",
68
68
  "node-loader": "^1.0.2",
69
69
  "nodemon": "^2.0.2",
@@ -33,6 +33,8 @@ module.exports = {
33
33
  runAsPortal: !!connections.portalConnections,
34
34
  singleDatabase: connections.singleDatabase,
35
35
  hideAppEditor: !!process.env.HIDE_APP_EDITOR,
36
+ allowShellConnection: platformInfo.allowShellConnection,
37
+ allowShellScripting: platformInfo.allowShellConnection,
36
38
  permissions,
37
39
  ...currentVersion,
38
40
  };
@@ -5,13 +5,14 @@ const fs = require('fs-extra');
5
5
 
6
6
  const { datadir, filesdir } = require('../utility/directories');
7
7
  const socket = require('../utility/socket');
8
- const { encryptConnection } = require('../utility/crypting');
8
+ const { encryptConnection, maskConnection } = require('../utility/crypting');
9
9
  const { handleProcessCommunication } = require('../utility/processComm');
10
10
  const { pickSafeConnectionInfo } = require('../utility/crypting');
11
11
  const JsonLinesDatabase = require('../utility/JsonLinesDatabase');
12
12
 
13
13
  const processArgs = require('../utility/processArgs');
14
14
  const { safeJsonParse } = require('dbgate-tools');
15
+ const platformInfo = require('../utility/platformInfo');
15
16
 
16
17
  function getNamedArgs() {
17
18
  const res = {};
@@ -165,7 +166,9 @@ module.exports = {
165
166
 
166
167
  list_meta: true,
167
168
  async list() {
168
- return portalConnections || this.datastore.find();
169
+ return portalConnections && !platformInfo.allowShellConnection
170
+ ? portalConnections.map(maskConnection)
171
+ : this.datastore.find();
169
172
  },
170
173
 
171
174
  test_meta: true,
@@ -244,14 +247,21 @@ module.exports = {
244
247
  return res;
245
248
  },
246
249
 
247
- get_meta: true,
248
- async get({ conid }) {
250
+ async getCore({ conid, mask = false }) {
249
251
  if (!conid) return null;
250
- if (portalConnections) return portalConnections.find(x => x._id == conid) || null;
252
+ if (portalConnections) {
253
+ const res = portalConnections.find(x => x._id == conid) || null;
254
+ return mask && !platformInfo.allowShellConnection ? maskConnection(res) : res;
255
+ }
251
256
  const res = await this.datastore.get(conid);
252
257
  return res || null;
253
258
  },
254
259
 
260
+ get_meta: true,
261
+ async get({ conid }) {
262
+ return this.getCore({ conid, mask: true });
263
+ },
264
+
255
265
  newSqliteDatabase_meta: true,
256
266
  async newSqliteDatabase({ file }) {
257
267
  const sqliteDir = path.join(filesdir(), 'sqlite');
@@ -79,7 +79,7 @@ module.exports = {
79
79
  async ensureOpened(conid, database) {
80
80
  const existing = this.opened.find(x => x.conid == conid && x.database == database);
81
81
  if (existing) return existing;
82
- const connection = await connections.get({ conid });
82
+ const connection = await connections.getCore({ conid });
83
83
  const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
84
84
  '--is-forked-api',
85
85
  '--start-process',
@@ -392,8 +392,8 @@ module.exports = {
392
392
  const targetDb = generateDbPairingId(
393
393
  extendDatabaseInfo(await this.structure({ conid: targetConid, database: targetDatabase }))
394
394
  );
395
- // const sourceConnection = await connections.get({conid:sourceConid})
396
- const connection = await connections.get({ conid: targetConid });
395
+ // const sourceConnection = await connections.getCore({conid:sourceConid})
396
+ const connection = await connections.getCore({ conid: targetConid });
397
397
  const driver = requireEngineDriver(connection);
398
398
  const targetDbPaired = matchPairedObjects(sourceDb, targetDb, dbDiffOptions);
399
399
  const diffRows = computeDbDiffRows(sourceDb, targetDbPaired, dbDiffOptions, driver);
@@ -73,7 +73,7 @@ module.exports = {
73
73
  const res = [];
74
74
  for (const packageName of _.union(files1, files2)) {
75
75
  if (packageName == 'dist') continue;
76
- // if (!/^dbgate-plugin-.*$/.test(packageName)) continue;
76
+ if (!/^dbgate-plugin-.*$/.test(packageName)) continue;
77
77
  try {
78
78
  if (packagedContent && packagedContent[packageName]) {
79
79
  const manifest = {
@@ -6,9 +6,10 @@ const byline = require('byline');
6
6
  const socket = require('../utility/socket');
7
7
  const { fork } = require('child_process');
8
8
  const { rundir, uploadsdir, pluginsdir, getPluginBackendPath, packagedPluginList } = require('../utility/directories');
9
- const { extractShellApiPlugins, extractShellApiFunctionName } = require('dbgate-tools');
9
+ const { extractShellApiPlugins, extractShellApiFunctionName, jsonScriptToJavascript } = require('dbgate-tools');
10
10
  const { handleProcessCommunication } = require('../utility/processComm');
11
11
  const processArgs = require('../utility/processArgs');
12
+ const platformInfo = require('../utility/platformInfo');
12
13
 
13
14
  function extractPlugins(script) {
14
15
  const requireRegex = /\s*\/\/\s*@require\s+([^\s]+)\s*\n/g;
@@ -148,12 +149,18 @@ module.exports = {
148
149
  },
149
150
 
150
151
  start_meta: true,
151
- async start({ script, isGeneratedScript }) {
152
- if (!isGeneratedScript && process.env.DISABLE_SHELL) {
153
- return { errorMessage: 'Shell is disabled' };
152
+ async start({ script }) {
153
+ const runid = uuidv1();
154
+
155
+ if (script.type == 'json') {
156
+ const js = jsonScriptToJavascript(script);
157
+ return this.startCore(runid, scriptTemplate(js, false));
158
+ }
159
+
160
+ if (!platformInfo.allowShellScripting) {
161
+ return { errorMessage: 'Shell scripting is not allowed' };
154
162
  }
155
163
 
156
- const runid = uuidv1();
157
164
  return this.startCore(runid, scriptTemplate(script, false));
158
165
  },
159
166
 
@@ -37,7 +37,7 @@ module.exports = {
37
37
  const res = await lock.acquire(conid, async () => {
38
38
  const existing = this.opened.find(x => x.conid == conid);
39
39
  if (existing) return existing;
40
- const connection = await connections.get({ conid });
40
+ const connection = await connections.getCore({ conid });
41
41
  const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
42
42
  '--is-forked-api',
43
43
  '--start-process',
@@ -54,6 +54,9 @@ module.exports = {
54
54
  this.dispatchMessage(sesid, 'Query execution finished');
55
55
  }
56
56
  const session = this.opened.find(x => x.sesid == sesid);
57
+ if (session.loadingReader_jslid) {
58
+ socket.emit(`session-jslid-done-${session.loadingReader_jslid}`);
59
+ }
57
60
  if (session.killOnDone) {
58
61
  this.kill({ sesid });
59
62
  }
@@ -78,7 +81,7 @@ module.exports = {
78
81
  create_meta: true,
79
82
  async create({ conid, database }) {
80
83
  const sesid = uuidv1();
81
- const connection = await connections.get({ conid });
84
+ const connection = await connections.getCore({ conid });
82
85
  const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
83
86
  '--is-forked-api',
84
87
  '--start-process',
@@ -124,6 +127,7 @@ module.exports = {
124
127
  const session = this.opened.find(x => x.sesid == sesid);
125
128
  session.killOnDone = true;
126
129
  const jslid = uuidv1();
130
+ session.loadingReader_jslid = jslid;
127
131
  const fileName = queryName && appFolder ? path.join(appdir(), appFolder, `${queryName}.query.sql`) : null;
128
132
 
129
133
  session.subprocess.send({ msgtype: 'executeReader', sql, fileName, jslid });
@@ -131,6 +135,15 @@ module.exports = {
131
135
  return { jslid };
132
136
  },
133
137
 
138
+ stopLoadingReader_meta: true,
139
+ async stopLoadingReader({ jslid }) {
140
+ const session = this.opened.find(x => x.loadingReader_jslid == jslid);
141
+ if (session) {
142
+ this.kill({ sesid: session.sesid });
143
+ }
144
+ return true;
145
+ },
146
+
134
147
  // cancel_meta: true,
135
148
  // async cancel({ sesid }) {
136
149
  // const session = this.opened.find((x) => x.sesid == sesid);
@@ -1,5 +1,5 @@
1
1
 
2
2
  module.exports = {
3
- version: '4.7.4-alpha.3',
4
- buildTime: '2022-03-17T19:22:21.077Z'
3
+ version: '4.7.4-alpha.7',
4
+ buildTime: '2022-03-20T12:32:18.367Z'
5
5
  };
@@ -20,7 +20,7 @@ function start() {
20
20
  if (handleProcessCommunication(connection)) return;
21
21
  try {
22
22
  const driver = requireEngineDriver(connection);
23
- const conn = await connectUtility(driver, connection);
23
+ const conn = await connectUtility(driver, connection, 'app');
24
24
  const res = await driver.getVersion(conn);
25
25
  process.send({ msgtype: 'connected', ...res });
26
26
  } catch (e) {
@@ -108,7 +108,7 @@ async function handleConnect({ connection, structure, globalSettings }) {
108
108
 
109
109
  if (!structure) setStatusName('pending');
110
110
  const driver = requireEngineDriver(storedConnection);
111
- systemConnection = await checkedAsyncCall(connectUtility(driver, storedConnection));
111
+ systemConnection = await checkedAsyncCall(connectUtility(driver, storedConnection, 'app'));
112
112
  await checkedAsyncCall(readVersion());
113
113
  if (structure) {
114
114
  analysedStructure = structure;
@@ -58,11 +58,14 @@ async function handleConnect(connection) {
58
58
 
59
59
  const driver = requireEngineDriver(storedConnection);
60
60
  try {
61
- systemConnection = await connectUtility(driver, storedConnection);
61
+ systemConnection = await connectUtility(driver, storedConnection, 'app');
62
62
  readVersion();
63
63
  handleRefresh();
64
64
  if (extractBoolSettingsValue(globalSettings, 'connection.autoRefresh', false)) {
65
- setInterval(handleRefresh, extractIntSettingsValue(globalSettings, 'connection.autoRefreshInterval', 30, 5, 3600) * 1000);
65
+ setInterval(
66
+ handleRefresh,
67
+ extractIntSettingsValue(globalSettings, 'connection.autoRefreshInterval', 30, 5, 3600) * 1000
68
+ );
66
69
  }
67
70
  } catch (err) {
68
71
  setStatus({
@@ -80,7 +83,7 @@ function handlePing() {
80
83
 
81
84
  async function handleCreateDatabase({ name }) {
82
85
  const driver = requireEngineDriver(storedConnection);
83
- systemConnection = await connectUtility(driver, storedConnection);
86
+ systemConnection = await connectUtility(driver, storedConnection, 'app');
84
87
  console.log(`RUNNING SCRIPT: CREATE DATABASE ${driver.dialect.quoteIdentifier(name)}`);
85
88
  if (driver.createDatabase) {
86
89
  await driver.createDatabase(systemConnection, name);
@@ -181,7 +181,7 @@ async function handleConnect(connection) {
181
181
  storedConnection = connection;
182
182
 
183
183
  const driver = requireEngineDriver(storedConnection);
184
- systemConnection = await connectUtility(driver, storedConnection);
184
+ systemConnection = await connectUtility(driver, storedConnection, 'app');
185
185
  for (const [resolve] of afterConnectCallbacks) {
186
186
  resolve();
187
187
  }
@@ -5,7 +5,7 @@ async function executeQuery({ connection = undefined, systemConnection = undefin
5
5
  console.log(`Execute query ${sql}`);
6
6
 
7
7
  if (!driver) driver = requireEngineDriver(connection);
8
- const pool = systemConnection || (await connectUtility(driver, connection));
8
+ const pool = systemConnection || (await connectUtility(driver, connection, 'script'));
9
9
  console.log(`Connected.`);
10
10
 
11
11
  await driver.script(pool, sql);
@@ -21,7 +21,7 @@ async function generateDeploySql({
21
21
  }) {
22
22
  if (!driver) driver = requireEngineDriver(connection);
23
23
 
24
- const pool = systemConnection || (await connectUtility(driver, connection));
24
+ const pool = systemConnection || (await connectUtility(driver, connection, 'read'));
25
25
  if (!analysedStructure) {
26
26
  analysedStructure = await driver.analyseFull(pool);
27
27
  }
@@ -1,14 +1,26 @@
1
1
  const requireEngineDriver = require('../utility/requireEngineDriver');
2
- const { decryptConnection } = require('../utility/crypting');
3
2
  const connectUtility = require('../utility/connectUtility');
4
3
 
5
- async function queryReader({ connection, sql }) {
6
- console.log(`Reading query ${sql}`);
4
+ async function queryReader({
5
+ connection,
6
+ query,
7
+ queryType,
8
+ // obsolete; use query instead
9
+ sql,
10
+ }) {
11
+ // if (sql && json) {
12
+ // throw new Error('Only one of sql or json could be set');
13
+ // }
14
+ // if (!sql && !json) {
15
+ // throw new Error('One of sql or json must be set');
16
+ // }
17
+ console.log(`Reading query ${query || sql}`);
18
+ // else console.log(`Reading query ${JSON.stringify(json)}`);
7
19
 
8
20
  const driver = requireEngineDriver(connection);
9
- const pool = await connectUtility(driver, connection);
21
+ const pool = await connectUtility(driver, connection, queryType == 'json' ? 'read' : 'script');
10
22
  console.log(`Connected.`);
11
- return await driver.readQuery(pool, sql);
23
+ return queryType == 'json' ? await driver.readJsonQuery(pool, query) : await driver.readQuery(pool, query || sql);
12
24
  }
13
25
 
14
26
  module.exports = queryReader;
@@ -4,7 +4,7 @@ const connectUtility = require('../utility/connectUtility');
4
4
 
5
5
  async function tableReader({ connection, pureName, schemaName }) {
6
6
  const driver = requireEngineDriver(connection);
7
- const pool = await connectUtility(driver, connection);
7
+ const pool = await connectUtility(driver, connection, 'read');
8
8
  console.log(`Connected.`);
9
9
 
10
10
  const fullName = { pureName, schemaName };
@@ -8,7 +8,7 @@ async function tableWriter({ connection, schemaName, pureName, driver, systemCon
8
8
  if (!driver) {
9
9
  driver = requireEngineDriver(connection);
10
10
  }
11
- const pool = systemConnection || (await connectUtility(driver, connection));
11
+ const pool = systemConnection || (await connectUtility(driver, connection, 'write'));
12
12
 
13
13
  console.log(`Connected.`);
14
14
  return await driver.writeTable(pool, { schemaName, pureName }, options);
@@ -4,11 +4,47 @@ const fs = require('fs-extra');
4
4
  const { decryptConnection } = require('./crypting');
5
5
  const { getSshTunnel } = require('./sshTunnel');
6
6
  const { getSshTunnelProxy } = require('./sshTunnelProxy');
7
+ const platformInfo = require('../utility/platformInfo');
8
+ const connections = require('../controllers/connections');
9
+
10
+ async function loadConnection(driver, storedConnection, connectionMode) {
11
+ const { allowShellConnection } = platformInfo;
12
+
13
+ if (connectionMode == 'app') {
14
+ return storedConnection;
15
+ }
16
+
17
+ if (storedConnection._id || !allowShellConnection) {
18
+ if (!storedConnection._id) {
19
+ throw new Error('Missing connection _id');
20
+ }
21
+
22
+ await connections._init();
23
+ const loaded = await connections.getCore({ conid: storedConnection._id });
24
+ const loadedWithDb = {
25
+ ...loaded,
26
+ database: storedConnection.database,
27
+ };
28
+
29
+ if (loaded.isReadOnly) {
30
+ if (connectionMode == 'read') return loadedWithDb;
31
+ if (connectionMode == 'write') throw new Error('Cannot write readonly connection');
32
+ if (connectionMode == 'script') {
33
+ if (driver.readOnlySessions) return loadedWithDb;
34
+ throw new Error('Cannot write readonly connection');
35
+ }
36
+ }
37
+ return loadedWithDb;
38
+ }
39
+ return storedConnection;
40
+ }
41
+
42
+ async function connectUtility(driver, storedConnection, connectionMode) {
43
+ const connectionLoaded = await loadConnection(driver, storedConnection, connectionMode);
7
44
 
8
- async function connectUtility(driver, storedConnection) {
9
45
  const connection = {
10
- database: storedConnection.defaultDatabase,
11
- ...decryptConnection(storedConnection),
46
+ database: connectionLoaded.defaultDatabase,
47
+ ...decryptConnection(connectionLoaded),
12
48
  };
13
49
 
14
50
  if (!connection.port && driver.defaultPort) connection.port = driver.defaultPort.toString();
@@ -55,7 +55,7 @@ function encryptPasswordField(connection, field) {
55
55
  [field]: 'crypt:' + getEncryptor().encrypt(connection[field]),
56
56
  };
57
57
  }
58
- return connection;
58
+ return connection;
59
59
  }
60
60
 
61
61
  function decryptPasswordField(connection, field) {
@@ -75,6 +75,11 @@ function encryptConnection(connection) {
75
75
  return connection;
76
76
  }
77
77
 
78
+ function maskConnection(connection) {
79
+ if (!connection) return connection;
80
+ return _.omit(connection, ['password', 'sshPassword', 'sshKeyfilePassword']);
81
+ }
82
+
78
83
  function decryptConnection(connection) {
79
84
  connection = decryptPasswordField(connection, 'password');
80
85
  connection = decryptPasswordField(connection, 'sshPassword');
@@ -95,5 +100,6 @@ module.exports = {
95
100
  loadEncryptionKey,
96
101
  encryptConnection,
97
102
  decryptConnection,
103
+ maskConnection,
98
104
  pickSafeConnectionInfo,
99
105
  };
@@ -39,6 +39,8 @@ const platformInfo = {
39
39
  environment: process.env.NODE_ENV,
40
40
  platform,
41
41
  runningInWebpack: !!process.env.WEBPACK_DEV_SERVER_URL,
42
+ allowShellConnection: !!process.env.SHELL_CONNECTION || !!isElectron(),
43
+ allowShellScripting: !!process.env.SHELL_SCRIPTING || !!isElectron(),
42
44
  defaultKeyfile: path.join(os.homedir(), '.ssh/id_rsa'),
43
45
  };
44
46