dbgate-api 4.7.3 → 4.7.4-alpha.12
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/.env +13 -0
- package/env/singledb/.env +2 -0
- package/package.json +5 -5
- package/src/controllers/config.js +19 -5
- package/src/controllers/connections.js +22 -5
- package/src/controllers/databaseConnections.js +72 -5
- package/src/controllers/files.js +22 -17
- package/src/controllers/jsldata.js +14 -10
- package/src/controllers/plugins.js +8 -8
- package/src/controllers/runners.js +13 -2
- package/src/controllers/scheduler.js +3 -3
- package/src/controllers/serverConnections.js +1 -1
- package/src/controllers/sessions.js +42 -3
- package/src/currentVersion.js +2 -2
- package/src/index.js +1 -1
- package/src/main.js +21 -12
- package/src/proc/connectProcess.js +1 -1
- package/src/proc/databaseConnectionProcess.js +58 -3
- package/src/proc/serverConnectionProcess.js +6 -3
- package/src/proc/sessionProcess.js +92 -7
- package/src/shell/executeQuery.js +1 -1
- package/src/shell/generateDeploySql.js +1 -1
- package/src/shell/queryReader.js +17 -5
- package/src/shell/tableReader.js +2 -2
- package/src/shell/tableWriter.js +1 -1
- package/src/utility/connectUtility.js +39 -3
- package/src/utility/crypting.js +7 -1
- package/src/utility/directories.js +1 -1
- package/src/utility/hasPermission.js +50 -6
- package/src/utility/platformInfo.js +3 -1
- package/src/utility/useController.js +1 -1
package/.env
CHANGED
|
@@ -1 +1,14 @@
|
|
|
1
1
|
DEVMODE=1
|
|
2
|
+
# PERMISSIONS=~widgets/app,~widgets/plugins
|
|
3
|
+
# DISABLE_SHELL=1
|
|
4
|
+
# HIDE_APP_EDITOR=1
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
DEVWEB=1
|
|
8
|
+
LOGINS=admin,test
|
|
9
|
+
|
|
10
|
+
LOGIN_PASSWORD_admin=admin
|
|
11
|
+
LOGIN_PERMISSIONS_admin=*
|
|
12
|
+
|
|
13
|
+
LOGIN_PASSWORD_test=test
|
|
14
|
+
LOGIN_PERMISSIONS_test=~*, widgets/database
|
package/env/singledb/.env
CHANGED
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
|
+
"version": "4.7.4-alpha.12",
|
|
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.
|
|
29
|
-
"dbgate-sqltree": "^4.7.
|
|
30
|
-
"dbgate-tools": "^4.7.
|
|
28
|
+
"dbgate-query-splitter": "^4.7.4-alpha.12",
|
|
29
|
+
"dbgate-sqltree": "^4.7.4-alpha.12",
|
|
30
|
+
"dbgate-tools": "^4.7.4-alpha.12",
|
|
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.
|
|
66
|
+
"dbgate-types": "^4.7.4-alpha.12",
|
|
67
67
|
"env-cmd": "^10.1.0",
|
|
68
68
|
"node-loader": "^1.0.2",
|
|
69
69
|
"nodemon": "^2.0.2",
|
|
@@ -3,7 +3,7 @@ const os = require('os');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const axios = require('axios');
|
|
5
5
|
const { datadir } = require('../utility/directories');
|
|
6
|
-
const hasPermission = require('../utility/hasPermission');
|
|
6
|
+
const { hasPermission, getLogins } = require('../utility/hasPermission');
|
|
7
7
|
const socket = require('../utility/socket');
|
|
8
8
|
const _ = require('lodash');
|
|
9
9
|
const AsyncLock = require('async-lock');
|
|
@@ -26,17 +26,31 @@ module.exports = {
|
|
|
26
26
|
// },
|
|
27
27
|
|
|
28
28
|
get_meta: true,
|
|
29
|
-
async get() {
|
|
30
|
-
const
|
|
29
|
+
async get(_params, req) {
|
|
30
|
+
const logins = getLogins();
|
|
31
|
+
const login = logins ? logins.find(x => x.login == (req.auth && req.auth.user)) : null;
|
|
32
|
+
const permissions = login ? login.permissions : null;
|
|
31
33
|
|
|
32
34
|
return {
|
|
33
35
|
runAsPortal: !!connections.portalConnections,
|
|
34
36
|
singleDatabase: connections.singleDatabase,
|
|
37
|
+
// hideAppEditor: !!process.env.HIDE_APP_EDITOR,
|
|
38
|
+
allowShellConnection: platformInfo.allowShellConnection,
|
|
39
|
+
allowShellScripting: platformInfo.allowShellConnection,
|
|
35
40
|
permissions,
|
|
41
|
+
login,
|
|
36
42
|
...currentVersion,
|
|
37
43
|
};
|
|
38
44
|
},
|
|
39
45
|
|
|
46
|
+
logout_meta: {
|
|
47
|
+
method: 'get',
|
|
48
|
+
raw: true,
|
|
49
|
+
},
|
|
50
|
+
logout(req, res) {
|
|
51
|
+
res.status(401).send('Logged out<br><a href="../..">Back to DbGate</a>');
|
|
52
|
+
},
|
|
53
|
+
|
|
40
54
|
platformInfo_meta: true,
|
|
41
55
|
async platformInfo() {
|
|
42
56
|
return platformInfo;
|
|
@@ -64,8 +78,8 @@ module.exports = {
|
|
|
64
78
|
},
|
|
65
79
|
|
|
66
80
|
updateSettings_meta: true,
|
|
67
|
-
async updateSettings(values) {
|
|
68
|
-
if (!hasPermission(`settings/change
|
|
81
|
+
async updateSettings(values, req) {
|
|
82
|
+
if (!hasPermission(`settings/change`, req)) return false;
|
|
69
83
|
|
|
70
84
|
const res = await lock.acquire('update', async () => {
|
|
71
85
|
const currentValue = await this.getSettings();
|
|
@@ -5,12 +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
|
+
const { safeJsonParse } = require('dbgate-tools');
|
|
15
|
+
const platformInfo = require('../utility/platformInfo');
|
|
14
16
|
|
|
15
17
|
function getNamedArgs() {
|
|
16
18
|
const res = {};
|
|
@@ -55,6 +57,8 @@ function getPortalCollections() {
|
|
|
55
57
|
(process.env[`FILE_${id}`] ? getDatabaseFileLabel(process.env[`FILE_${id}`]) : null),
|
|
56
58
|
singleDatabase: !!process.env[`DATABASE_${id}`] || !!process.env[`FILE_${id}`],
|
|
57
59
|
displayName: process.env[`LABEL_${id}`],
|
|
60
|
+
isReadOnly: process.env[`READONLY_${id}`],
|
|
61
|
+
databases: process.env[`DBCONFIG_${id}`] ? safeJsonParse(process.env[`DBCONFIG_${id}`]) : null,
|
|
58
62
|
|
|
59
63
|
// SSH tunnel
|
|
60
64
|
useSshTunnel: process.env[`USE_SSH_${id}`],
|
|
@@ -162,7 +166,9 @@ module.exports = {
|
|
|
162
166
|
|
|
163
167
|
list_meta: true,
|
|
164
168
|
async list() {
|
|
165
|
-
return portalConnections
|
|
169
|
+
return portalConnections && !platformInfo.allowShellConnection
|
|
170
|
+
? portalConnections.map(maskConnection)
|
|
171
|
+
: this.datastore.find();
|
|
166
172
|
},
|
|
167
173
|
|
|
168
174
|
test_meta: true,
|
|
@@ -199,6 +205,9 @@ module.exports = {
|
|
|
199
205
|
}
|
|
200
206
|
socket.emitChanged('connection-list-changed');
|
|
201
207
|
socket.emitChanged('used-apps-changed');
|
|
208
|
+
if (this._closeAll) {
|
|
209
|
+
this._closeAll(connection._id);
|
|
210
|
+
}
|
|
202
211
|
// for (const db of connection.databases || []) {
|
|
203
212
|
// socket.emitChanged(`db-apps-changed-${connection._id}-${db.name}`);
|
|
204
213
|
// }
|
|
@@ -238,13 +247,21 @@ module.exports = {
|
|
|
238
247
|
return res;
|
|
239
248
|
},
|
|
240
249
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
if (portalConnections)
|
|
250
|
+
async getCore({ conid, mask = false }) {
|
|
251
|
+
if (!conid) return null;
|
|
252
|
+
if (portalConnections) {
|
|
253
|
+
const res = portalConnections.find(x => x._id == conid) || null;
|
|
254
|
+
return mask && !platformInfo.allowShellConnection ? maskConnection(res) : res;
|
|
255
|
+
}
|
|
244
256
|
const res = await this.datastore.get(conid);
|
|
245
257
|
return res || null;
|
|
246
258
|
},
|
|
247
259
|
|
|
260
|
+
get_meta: true,
|
|
261
|
+
async get({ conid }) {
|
|
262
|
+
return this.getCore({ conid, mask: true });
|
|
263
|
+
},
|
|
264
|
+
|
|
248
265
|
newSqliteDatabase_meta: true,
|
|
249
266
|
async newSqliteDatabase({ file }) {
|
|
250
267
|
const sqliteDir = path.join(filesdir(), 'sqlite');
|
|
@@ -33,6 +33,10 @@ module.exports = {
|
|
|
33
33
|
closed: {},
|
|
34
34
|
requests: {},
|
|
35
35
|
|
|
36
|
+
async _init() {
|
|
37
|
+
connections._closeAll = conid => this.closeAll(conid);
|
|
38
|
+
},
|
|
39
|
+
|
|
36
40
|
handle_structure(conid, database, { structure }) {
|
|
37
41
|
const existing = this.opened.find(x => x.conid == conid && x.database == database);
|
|
38
42
|
if (!existing) return;
|
|
@@ -75,7 +79,7 @@ module.exports = {
|
|
|
75
79
|
async ensureOpened(conid, database) {
|
|
76
80
|
const existing = this.opened.find(x => x.conid == conid && x.database == database);
|
|
77
81
|
if (existing) return existing;
|
|
78
|
-
const connection = await connections.
|
|
82
|
+
const connection = await connections.getCore({ conid });
|
|
79
83
|
const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
|
|
80
84
|
'--is-forked-api',
|
|
81
85
|
'--start-process',
|
|
@@ -136,6 +140,13 @@ module.exports = {
|
|
|
136
140
|
return res;
|
|
137
141
|
},
|
|
138
142
|
|
|
143
|
+
sqlSelect_meta: true,
|
|
144
|
+
async sqlSelect({ conid, database, select }) {
|
|
145
|
+
const opened = await this.ensureOpened(conid, database);
|
|
146
|
+
const res = await this.sendRequest(opened, { msgtype: 'sqlSelect', select });
|
|
147
|
+
return res;
|
|
148
|
+
},
|
|
149
|
+
|
|
139
150
|
runScript_meta: true,
|
|
140
151
|
async runScript({ conid, database, sql }) {
|
|
141
152
|
console.log(`Processing script, conid=${conid}, database=${database}, sql=${sql}`);
|
|
@@ -148,14 +159,64 @@ module.exports = {
|
|
|
148
159
|
async collectionData({ conid, database, options }) {
|
|
149
160
|
const opened = await this.ensureOpened(conid, database);
|
|
150
161
|
const res = await this.sendRequest(opened, { msgtype: 'collectionData', options });
|
|
151
|
-
return res.result;
|
|
162
|
+
return res.result || null;
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
async loadDataCore(msgtype, { conid, database, ...args }) {
|
|
166
|
+
const opened = await this.ensureOpened(conid, database);
|
|
167
|
+
const res = await this.sendRequest(opened, { msgtype, ...args });
|
|
168
|
+
if (res.errorMessage) {
|
|
169
|
+
console.error(res.errorMessage);
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
errorMessage: res.errorMessage,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
return res.result || null;
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
loadKeys_meta: true,
|
|
179
|
+
async loadKeys({ conid, database, root }) {
|
|
180
|
+
return this.loadDataCore('loadKeys', { conid, database, root });
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
loadKeyInfo_meta: true,
|
|
184
|
+
async loadKeyInfo({ conid, database, key }) {
|
|
185
|
+
return this.loadDataCore('loadKeyInfo', { conid, database, key });
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
loadKeyTableRange_meta: true,
|
|
189
|
+
async loadKeyTableRange({ conid, database, key, cursor, count }) {
|
|
190
|
+
return this.loadDataCore('loadKeyTableRange', { conid, database, key, cursor, count });
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
loadFieldValues_meta: true,
|
|
194
|
+
async loadFieldValues({ conid, database, schemaName, pureName, field, search }) {
|
|
195
|
+
return this.loadDataCore('loadFieldValues', { conid, database, schemaName, pureName, field, search });
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
callMethod_meta: true,
|
|
199
|
+
async callMethod({ conid, database, method, args }) {
|
|
200
|
+
return this.loadDataCore('callMethod', { conid, database, method, args });
|
|
201
|
+
|
|
202
|
+
// const opened = await this.ensureOpened(conid, database);
|
|
203
|
+
// const res = await this.sendRequest(opened, { msgtype: 'callMethod', method, args });
|
|
204
|
+
// if (res.errorMessage) {
|
|
205
|
+
// console.error(res.errorMessage);
|
|
206
|
+
// }
|
|
207
|
+
// return res.result || null;
|
|
152
208
|
},
|
|
153
209
|
|
|
154
210
|
updateCollection_meta: true,
|
|
155
211
|
async updateCollection({ conid, database, changeSet }) {
|
|
156
212
|
const opened = await this.ensureOpened(conid, database);
|
|
157
213
|
const res = await this.sendRequest(opened, { msgtype: 'updateCollection', changeSet });
|
|
158
|
-
|
|
214
|
+
if (res.errorMessage) {
|
|
215
|
+
return {
|
|
216
|
+
errorMessage: res.errorMessage,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
return res.result || null;
|
|
159
220
|
},
|
|
160
221
|
|
|
161
222
|
status_meta: true,
|
|
@@ -228,6 +289,12 @@ module.exports = {
|
|
|
228
289
|
}
|
|
229
290
|
},
|
|
230
291
|
|
|
292
|
+
closeAll(conid, kill = true) {
|
|
293
|
+
for (const existing of this.opened.filter(x => x.conid == conid)) {
|
|
294
|
+
this.close(conid, existing.database, kill);
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
|
|
231
298
|
disconnect_meta: true,
|
|
232
299
|
async disconnect({ conid, database }) {
|
|
233
300
|
await this.close(conid, database, true);
|
|
@@ -325,8 +392,8 @@ module.exports = {
|
|
|
325
392
|
const targetDb = generateDbPairingId(
|
|
326
393
|
extendDatabaseInfo(await this.structure({ conid: targetConid, database: targetDatabase }))
|
|
327
394
|
);
|
|
328
|
-
// const sourceConnection = await connections.
|
|
329
|
-
const connection = await connections.
|
|
395
|
+
// const sourceConnection = await connections.getCore({conid:sourceConid})
|
|
396
|
+
const connection = await connections.getCore({ conid: targetConid });
|
|
330
397
|
const driver = requireEngineDriver(connection);
|
|
331
398
|
const targetDbPaired = matchPairedObjects(sourceDb, targetDb, dbDiffOptions);
|
|
332
399
|
const diffRows = computeDbDiffRows(sourceDb, targetDbPaired, dbDiffOptions, driver);
|
package/src/controllers/files.js
CHANGED
|
@@ -3,7 +3,7 @@ const fs = require('fs-extra');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const { filesdir, archivedir, resolveArchiveFolder, uploadsdir, appdir } = require('../utility/directories');
|
|
5
5
|
const getChartExport = require('../utility/getChartExport');
|
|
6
|
-
const hasPermission = require('../utility/hasPermission');
|
|
6
|
+
const { hasPermission } = require('../utility/hasPermission');
|
|
7
7
|
const socket = require('../utility/socket');
|
|
8
8
|
const scheduler = require('./scheduler');
|
|
9
9
|
const getDiagramExport = require('../utility/getDiagramExport');
|
|
@@ -23,8 +23,8 @@ function deserialize(format, text) {
|
|
|
23
23
|
|
|
24
24
|
module.exports = {
|
|
25
25
|
list_meta: true,
|
|
26
|
-
async list({ folder }) {
|
|
27
|
-
if (!hasPermission(`files/${folder}/read
|
|
26
|
+
async list({ folder }, req) {
|
|
27
|
+
if (!hasPermission(`files/${folder}/read`, req)) return [];
|
|
28
28
|
const dir = path.join(filesdir(), folder);
|
|
29
29
|
if (!(await fs.exists(dir))) return [];
|
|
30
30
|
const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
|
|
@@ -32,11 +32,11 @@ module.exports = {
|
|
|
32
32
|
},
|
|
33
33
|
|
|
34
34
|
listAll_meta: true,
|
|
35
|
-
async listAll() {
|
|
35
|
+
async listAll(_params, req) {
|
|
36
36
|
const folders = await fs.readdir(filesdir());
|
|
37
37
|
const res = [];
|
|
38
38
|
for (const folder of folders) {
|
|
39
|
-
if (!hasPermission(`files/${folder}/read
|
|
39
|
+
if (!hasPermission(`files/${folder}/read`, req)) continue;
|
|
40
40
|
const dir = path.join(filesdir(), folder);
|
|
41
41
|
const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
|
|
42
42
|
res.push(...files);
|
|
@@ -45,31 +45,34 @@ module.exports = {
|
|
|
45
45
|
},
|
|
46
46
|
|
|
47
47
|
delete_meta: true,
|
|
48
|
-
async delete({ folder, file }) {
|
|
49
|
-
if (!hasPermission(`files/${folder}/write
|
|
48
|
+
async delete({ folder, file }, req) {
|
|
49
|
+
if (!hasPermission(`files/${folder}/write`, req)) return false;
|
|
50
50
|
await fs.unlink(path.join(filesdir(), folder, file));
|
|
51
51
|
socket.emitChanged(`files-changed-${folder}`);
|
|
52
52
|
socket.emitChanged(`all-files-changed`);
|
|
53
|
+
return true;
|
|
53
54
|
},
|
|
54
55
|
|
|
55
56
|
rename_meta: true,
|
|
56
|
-
async rename({ folder, file, newFile }) {
|
|
57
|
-
if (!hasPermission(`files/${folder}/write
|
|
57
|
+
async rename({ folder, file, newFile }, req) {
|
|
58
|
+
if (!hasPermission(`files/${folder}/write`, req)) return false;
|
|
58
59
|
await fs.rename(path.join(filesdir(), folder, file), path.join(filesdir(), folder, newFile));
|
|
59
60
|
socket.emitChanged(`files-changed-${folder}`);
|
|
60
61
|
socket.emitChanged(`all-files-changed`);
|
|
62
|
+
return true;
|
|
61
63
|
},
|
|
62
64
|
|
|
63
65
|
copy_meta: true,
|
|
64
|
-
async copy({ folder, file, newFile }) {
|
|
65
|
-
if (!hasPermission(`files/${folder}/write
|
|
66
|
+
async copy({ folder, file, newFile }, req) {
|
|
67
|
+
if (!hasPermission(`files/${folder}/write`, req)) return false;
|
|
66
68
|
await fs.copyFile(path.join(filesdir(), folder, file), path.join(filesdir(), folder, newFile));
|
|
67
69
|
socket.emitChanged(`files-changed-${folder}`);
|
|
68
70
|
socket.emitChanged(`all-files-changed`);
|
|
71
|
+
return true;
|
|
69
72
|
},
|
|
70
73
|
|
|
71
74
|
load_meta: true,
|
|
72
|
-
async load({ folder, file, format }) {
|
|
75
|
+
async load({ folder, file, format }, req) {
|
|
73
76
|
if (folder.startsWith('archive:')) {
|
|
74
77
|
const text = await fs.readFile(path.join(resolveArchiveFolder(folder.substring('archive:'.length)), file), {
|
|
75
78
|
encoding: 'utf-8',
|
|
@@ -81,20 +84,22 @@ module.exports = {
|
|
|
81
84
|
});
|
|
82
85
|
return deserialize(format, text);
|
|
83
86
|
} else {
|
|
84
|
-
if (!hasPermission(`files/${folder}/read
|
|
87
|
+
if (!hasPermission(`files/${folder}/read`, req)) return null;
|
|
85
88
|
const text = await fs.readFile(path.join(filesdir(), folder, file), { encoding: 'utf-8' });
|
|
86
89
|
return deserialize(format, text);
|
|
87
90
|
}
|
|
88
91
|
},
|
|
89
92
|
|
|
90
93
|
save_meta: true,
|
|
91
|
-
async save({ folder, file, data, format }) {
|
|
94
|
+
async save({ folder, file, data, format }, req) {
|
|
92
95
|
if (folder.startsWith('archive:')) {
|
|
96
|
+
if (!hasPermission(`archive/write`, req)) return false;
|
|
93
97
|
const dir = resolveArchiveFolder(folder.substring('archive:'.length));
|
|
94
98
|
await fs.writeFile(path.join(dir, file), serialize(format, data));
|
|
95
99
|
socket.emitChanged(`archive-files-changed-${folder.substring('archive:'.length)}`);
|
|
96
100
|
return true;
|
|
97
101
|
} else if (folder.startsWith('app:')) {
|
|
102
|
+
if (!hasPermission(`apps/write`, req)) return false;
|
|
98
103
|
const app = folder.substring('app:'.length);
|
|
99
104
|
await fs.writeFile(path.join(appdir(), app, file), serialize(format, data));
|
|
100
105
|
socket.emitChanged(`app-files-changed-${app}`);
|
|
@@ -102,7 +107,7 @@ module.exports = {
|
|
|
102
107
|
apps.emitChangedDbApp(folder);
|
|
103
108
|
return true;
|
|
104
109
|
} else {
|
|
105
|
-
if (!hasPermission(`files/${folder}/write
|
|
110
|
+
if (!hasPermission(`files/${folder}/write`, req)) return false;
|
|
106
111
|
const dir = path.join(filesdir(), folder);
|
|
107
112
|
if (!(await fs.exists(dir))) {
|
|
108
113
|
await fs.mkdir(dir);
|
|
@@ -123,8 +128,8 @@ module.exports = {
|
|
|
123
128
|
},
|
|
124
129
|
|
|
125
130
|
favorites_meta: true,
|
|
126
|
-
async favorites() {
|
|
127
|
-
if (!hasPermission(`files/favorites/read
|
|
131
|
+
async favorites(_params, req) {
|
|
132
|
+
if (!hasPermission(`files/favorites/read`, req)) return [];
|
|
128
133
|
const dir = path.join(filesdir(), 'favorites');
|
|
129
134
|
if (!(await fs.exists(dir))) return [];
|
|
130
135
|
const files = await fs.readdir(dir);
|
|
@@ -111,18 +111,22 @@ module.exports = {
|
|
|
111
111
|
getInfo_meta: true,
|
|
112
112
|
async getInfo({ jslid }) {
|
|
113
113
|
const file = getJslFileName(jslid);
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
try {
|
|
115
|
+
const firstLine = await readFirstLine(file);
|
|
116
|
+
if (firstLine) {
|
|
117
|
+
const parsed = JSON.parse(firstLine);
|
|
118
|
+
if (parsed.__isStreamHeader) {
|
|
119
|
+
return parsed;
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
__isStreamHeader: true,
|
|
123
|
+
__isDynamicStructure: true,
|
|
124
|
+
};
|
|
119
125
|
}
|
|
120
|
-
return
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
};
|
|
126
|
+
return null;
|
|
127
|
+
} catch (err) {
|
|
128
|
+
return null;
|
|
124
129
|
}
|
|
125
|
-
return null;
|
|
126
130
|
},
|
|
127
131
|
|
|
128
132
|
getRows_meta: true,
|
|
@@ -7,7 +7,7 @@ const socket = require('../utility/socket');
|
|
|
7
7
|
const compareVersions = require('compare-versions');
|
|
8
8
|
const requirePlugin = require('../shell/requirePlugin');
|
|
9
9
|
const downloadPackage = require('../utility/downloadPackage');
|
|
10
|
-
const hasPermission = require('../utility/hasPermission');
|
|
10
|
+
const { hasPermission } = require('../utility/hasPermission');
|
|
11
11
|
const _ = require('lodash');
|
|
12
12
|
const packagedPluginsContent = require('../packagedPluginsContent');
|
|
13
13
|
|
|
@@ -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
|
-
|
|
76
|
+
if (!/^dbgate-plugin-.*$/.test(packageName)) continue;
|
|
77
77
|
try {
|
|
78
78
|
if (packagedContent && packagedContent[packageName]) {
|
|
79
79
|
const manifest = {
|
|
@@ -115,8 +115,8 @@ module.exports = {
|
|
|
115
115
|
// },
|
|
116
116
|
|
|
117
117
|
install_meta: true,
|
|
118
|
-
async install({ packageName }) {
|
|
119
|
-
if (!hasPermission(`plugins/install
|
|
118
|
+
async install({ packageName }, req) {
|
|
119
|
+
if (!hasPermission(`plugins/install`, req)) return;
|
|
120
120
|
const dir = path.join(pluginsdir(), packageName);
|
|
121
121
|
// @ts-ignore
|
|
122
122
|
if (!(await fs.exists(dir))) {
|
|
@@ -128,8 +128,8 @@ module.exports = {
|
|
|
128
128
|
},
|
|
129
129
|
|
|
130
130
|
uninstall_meta: true,
|
|
131
|
-
async uninstall({ packageName }) {
|
|
132
|
-
if (!hasPermission(`plugins/install
|
|
131
|
+
async uninstall({ packageName }, req) {
|
|
132
|
+
if (!hasPermission(`plugins/install`, req)) return;
|
|
133
133
|
const dir = path.join(pluginsdir(), packageName);
|
|
134
134
|
await fs.rmdir(dir, { recursive: true });
|
|
135
135
|
socket.emitChanged(`installed-plugins-changed`);
|
|
@@ -138,8 +138,8 @@ module.exports = {
|
|
|
138
138
|
},
|
|
139
139
|
|
|
140
140
|
upgrade_meta: true,
|
|
141
|
-
async upgrade({ packageName }) {
|
|
142
|
-
if (!hasPermission(`plugins/install
|
|
141
|
+
async upgrade({ packageName }, req) {
|
|
142
|
+
if (!hasPermission(`plugins/install`, req)) return;
|
|
143
143
|
const dir = path.join(pluginsdir(), packageName);
|
|
144
144
|
// @ts-ignore
|
|
145
145
|
if (await fs.exists(dir)) {
|
|
@@ -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;
|
|
@@ -110,7 +111,7 @@ module.exports = {
|
|
|
110
111
|
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
111
112
|
env: {
|
|
112
113
|
...process.env,
|
|
113
|
-
DBGATE_API: global['API_PACKAGE'] ||
|
|
114
|
+
DBGATE_API: global['API_PACKAGE'] || process.argv[1],
|
|
114
115
|
..._.fromPairs(pluginNames.map(name => [`PLUGIN_${_.camelCase(name)}`, getPluginBackendPath(name)])),
|
|
115
116
|
},
|
|
116
117
|
}
|
|
@@ -150,6 +151,16 @@ module.exports = {
|
|
|
150
151
|
start_meta: true,
|
|
151
152
|
async start({ script }) {
|
|
152
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' };
|
|
162
|
+
}
|
|
163
|
+
|
|
153
164
|
return this.startCore(runid, scriptTemplate(script, false));
|
|
154
165
|
},
|
|
155
166
|
|
|
@@ -3,7 +3,7 @@ const fs = require('fs-extra');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const cron = require('node-cron');
|
|
5
5
|
const runners = require('./runners');
|
|
6
|
-
const hasPermission = require('../utility/hasPermission');
|
|
6
|
+
const { hasPermission } = require('../utility/hasPermission');
|
|
7
7
|
|
|
8
8
|
const scheduleRegex = /\s*\/\/\s*@schedule\s+([^\n]+)\n/;
|
|
9
9
|
|
|
@@ -26,8 +26,8 @@ module.exports = {
|
|
|
26
26
|
this.tasks.push(task);
|
|
27
27
|
},
|
|
28
28
|
|
|
29
|
-
async reload() {
|
|
30
|
-
if (!hasPermission('files/shell/read')) return;
|
|
29
|
+
async reload(_params, req) {
|
|
30
|
+
if (!hasPermission('files/shell/read', req)) return;
|
|
31
31
|
const shellDir = path.join(filesdir(), 'shell');
|
|
32
32
|
await this.unload();
|
|
33
33
|
if (!(await fs.exists(shellDir))) return;
|
|
@@ -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.
|
|
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',
|
|
@@ -4,8 +4,10 @@ const connections = require('./connections');
|
|
|
4
4
|
const socket = require('../utility/socket');
|
|
5
5
|
const { fork } = require('child_process');
|
|
6
6
|
const jsldata = require('./jsldata');
|
|
7
|
+
const path = require('path');
|
|
7
8
|
const { handleProcessCommunication } = require('../utility/processComm');
|
|
8
9
|
const processArgs = require('../utility/processArgs');
|
|
10
|
+
const { appdir } = require('../utility/directories');
|
|
9
11
|
|
|
10
12
|
module.exports = {
|
|
11
13
|
/** @type {import('dbgate-types').OpenedSession[]} */
|
|
@@ -46,9 +48,18 @@ module.exports = {
|
|
|
46
48
|
this.dispatchMessage(sesid, info);
|
|
47
49
|
},
|
|
48
50
|
|
|
49
|
-
handle_done(sesid) {
|
|
51
|
+
handle_done(sesid, props) {
|
|
50
52
|
socket.emit(`session-done-${sesid}`);
|
|
51
|
-
|
|
53
|
+
if (!props.skipFinishedMessage) {
|
|
54
|
+
this.dispatchMessage(sesid, 'Query execution finished');
|
|
55
|
+
}
|
|
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
|
+
}
|
|
60
|
+
if (session.killOnDone) {
|
|
61
|
+
this.kill({ sesid });
|
|
62
|
+
}
|
|
52
63
|
},
|
|
53
64
|
|
|
54
65
|
handle_recordset(sesid, props) {
|
|
@@ -60,12 +71,17 @@ module.exports = {
|
|
|
60
71
|
jsldata.notifyChangedStats(stats);
|
|
61
72
|
},
|
|
62
73
|
|
|
74
|
+
handle_initializeFile(sesid, props) {
|
|
75
|
+
const { jslid } = props;
|
|
76
|
+
socket.emit(`session-initialize-file-${jslid}`);
|
|
77
|
+
},
|
|
78
|
+
|
|
63
79
|
handle_ping() {},
|
|
64
80
|
|
|
65
81
|
create_meta: true,
|
|
66
82
|
async create({ conid, database }) {
|
|
67
83
|
const sesid = uuidv1();
|
|
68
|
-
const connection = await connections.
|
|
84
|
+
const connection = await connections.getCore({ conid });
|
|
69
85
|
const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
|
|
70
86
|
'--is-forked-api',
|
|
71
87
|
'--start-process',
|
|
@@ -105,6 +121,29 @@ module.exports = {
|
|
|
105
121
|
return { state: 'ok' };
|
|
106
122
|
},
|
|
107
123
|
|
|
124
|
+
executeReader_meta: true,
|
|
125
|
+
async executeReader({ conid, database, sql, queryName, appFolder }) {
|
|
126
|
+
const { sesid } = await this.create({ conid, database });
|
|
127
|
+
const session = this.opened.find(x => x.sesid == sesid);
|
|
128
|
+
session.killOnDone = true;
|
|
129
|
+
const jslid = uuidv1();
|
|
130
|
+
session.loadingReader_jslid = jslid;
|
|
131
|
+
const fileName = queryName && appFolder ? path.join(appdir(), appFolder, `${queryName}.query.sql`) : null;
|
|
132
|
+
|
|
133
|
+
session.subprocess.send({ msgtype: 'executeReader', sql, fileName, jslid });
|
|
134
|
+
|
|
135
|
+
return { jslid };
|
|
136
|
+
},
|
|
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
|
+
|
|
108
147
|
// cancel_meta: true,
|
|
109
148
|
// async cancel({ sesid }) {
|
|
110
149
|
// const session = this.opened.find((x) => x.sesid == sesid);
|
package/src/currentVersion.js
CHANGED
package/src/index.js
CHANGED
|
@@ -8,7 +8,7 @@ if (processArgs.startProcess) {
|
|
|
8
8
|
const proc = require('./proc');
|
|
9
9
|
const module = proc[processArgs.startProcess];
|
|
10
10
|
module.start();
|
|
11
|
-
} else if (!processArgs.checkParent && !global['API_PACKAGE']
|
|
11
|
+
} else if (!processArgs.checkParent && !global['API_PACKAGE']) {
|
|
12
12
|
const main = require('./main');
|
|
13
13
|
|
|
14
14
|
main.start();
|