dbgate-api-premium 5.5.7-alpha.45

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.
Files changed (125) hide show
  1. package/.env +19 -0
  2. package/.yarnrc +2 -0
  3. package/README.md +1 -0
  4. package/env/dblogin/.env +14 -0
  5. package/env/portal/.env +70 -0
  6. package/env/singledb/.env +17 -0
  7. package/env/storage/.env +43 -0
  8. package/package.json +89 -0
  9. package/src/auth/authCommon.js +16 -0
  10. package/src/auth/authProvider.js +343 -0
  11. package/src/auth/storageAuthProvider.js +393 -0
  12. package/src/controllers/apps.js +280 -0
  13. package/src/controllers/archive.js +217 -0
  14. package/src/controllers/auth.js +136 -0
  15. package/src/controllers/config.js +271 -0
  16. package/src/controllers/connections.js +486 -0
  17. package/src/controllers/databaseConnections.js +561 -0
  18. package/src/controllers/files.js +222 -0
  19. package/src/controllers/jsldata.js +296 -0
  20. package/src/controllers/metadata.js +47 -0
  21. package/src/controllers/plugins.js +216 -0
  22. package/src/controllers/queryHistory.js +54 -0
  23. package/src/controllers/runners.js +234 -0
  24. package/src/controllers/scheduler.js +46 -0
  25. package/src/controllers/serverConnections.js +271 -0
  26. package/src/controllers/sessions.js +243 -0
  27. package/src/controllers/storage.js +380 -0
  28. package/src/controllers/storageDb.js +215 -0
  29. package/src/controllers/uploads.js +133 -0
  30. package/src/currentVersion.js +5 -0
  31. package/src/gistSecret.js +2 -0
  32. package/src/index.js +139 -0
  33. package/src/main.js +202 -0
  34. package/src/packagedPluginsContent.js +1 -0
  35. package/src/proc/connectProcess.js +38 -0
  36. package/src/proc/databaseConnectionProcess.js +431 -0
  37. package/src/proc/index.js +15 -0
  38. package/src/proc/jslDatastoreProcess.js +60 -0
  39. package/src/proc/serverConnectionProcess.js +188 -0
  40. package/src/proc/sessionProcess.js +390 -0
  41. package/src/proc/sshForwardProcess.js +75 -0
  42. package/src/shell/archiveReader.js +11 -0
  43. package/src/shell/archiveWriter.js +22 -0
  44. package/src/shell/autoIndexForeignKeysTransform.js +19 -0
  45. package/src/shell/collectorWriter.js +33 -0
  46. package/src/shell/consoleObjectWriter.js +16 -0
  47. package/src/shell/copyStream.js +48 -0
  48. package/src/shell/dataDuplicator.js +63 -0
  49. package/src/shell/dataTypeMapperTransform.js +21 -0
  50. package/src/shell/dbModelToJson.js +16 -0
  51. package/src/shell/deployDb.js +56 -0
  52. package/src/shell/download.js +15 -0
  53. package/src/shell/dropAllDbObjects.js +42 -0
  54. package/src/shell/dumpDatabase.js +49 -0
  55. package/src/shell/executeQuery.js +39 -0
  56. package/src/shell/fakeObjectReader.js +35 -0
  57. package/src/shell/finalizer.js +12 -0
  58. package/src/shell/generateDeploySql.js +95 -0
  59. package/src/shell/generateModelSql.js +30 -0
  60. package/src/shell/importDatabase.js +85 -0
  61. package/src/shell/index.js +80 -0
  62. package/src/shell/initializeApiEnvironment.js +9 -0
  63. package/src/shell/jslDataReader.js +9 -0
  64. package/src/shell/jsonLinesReader.js +52 -0
  65. package/src/shell/jsonLinesWriter.js +36 -0
  66. package/src/shell/jsonReader.js +84 -0
  67. package/src/shell/jsonToDbModel.js +9 -0
  68. package/src/shell/jsonWriter.js +97 -0
  69. package/src/shell/loadDatabase.js +27 -0
  70. package/src/shell/loadFile.js +10 -0
  71. package/src/shell/modifyJsonLinesReader.js +148 -0
  72. package/src/shell/queryReader.js +30 -0
  73. package/src/shell/registerPlugins.js +9 -0
  74. package/src/shell/requirePlugin.js +43 -0
  75. package/src/shell/runScript.js +19 -0
  76. package/src/shell/sqlDataWriter.js +52 -0
  77. package/src/shell/sqlTextReplacementTransform.js +32 -0
  78. package/src/shell/tableReader.js +39 -0
  79. package/src/shell/tableWriter.js +18 -0
  80. package/src/storageModel.js +819 -0
  81. package/src/utility/ColumnMapTransformStream.js +21 -0
  82. package/src/utility/DatastoreProxy.js +106 -0
  83. package/src/utility/EnsureStreamHeaderStream.js +31 -0
  84. package/src/utility/JsonLinesDatabase.js +148 -0
  85. package/src/utility/JsonLinesDatastore.js +232 -0
  86. package/src/utility/LineReader.js +88 -0
  87. package/src/utility/SSHConnection.js +251 -0
  88. package/src/utility/authProxy.js +133 -0
  89. package/src/utility/checkLicense.js +186 -0
  90. package/src/utility/childProcessChecker.js +21 -0
  91. package/src/utility/cleanDirectory.js +24 -0
  92. package/src/utility/cloudUpgrade.js +61 -0
  93. package/src/utility/connectUtility.js +111 -0
  94. package/src/utility/crypting.js +105 -0
  95. package/src/utility/diff2htmlPage.js +8 -0
  96. package/src/utility/directories.js +179 -0
  97. package/src/utility/downloadPackage.js +51 -0
  98. package/src/utility/downloader.js +25 -0
  99. package/src/utility/exceptions.js +9 -0
  100. package/src/utility/exportDbModel.js +31 -0
  101. package/src/utility/exportDbModelSql.js +80 -0
  102. package/src/utility/getChartExport.js +55 -0
  103. package/src/utility/getDiagramExport.js +25 -0
  104. package/src/utility/getExpressPath.js +10 -0
  105. package/src/utility/getJslFileName.js +16 -0
  106. package/src/utility/getMapExport.js +77 -0
  107. package/src/utility/hardwareFingerprint.js +89 -0
  108. package/src/utility/hasPermission.js +101 -0
  109. package/src/utility/importDbModel.js +9 -0
  110. package/src/utility/loadFilesRecursive.js +20 -0
  111. package/src/utility/loadModelFolder.js +29 -0
  112. package/src/utility/loadModelTransform.js +36 -0
  113. package/src/utility/pipeForkLogs.js +19 -0
  114. package/src/utility/platformInfo.js +62 -0
  115. package/src/utility/processArgs.js +39 -0
  116. package/src/utility/processComm.js +18 -0
  117. package/src/utility/requireEngineDriver.js +26 -0
  118. package/src/utility/requirePluginFunction.js +16 -0
  119. package/src/utility/socket.js +68 -0
  120. package/src/utility/sshTunnel.js +106 -0
  121. package/src/utility/sshTunnelProxy.js +36 -0
  122. package/src/utility/timingSafeCheckToken.js +9 -0
  123. package/src/utility/useController.js +99 -0
  124. package/tsconfig.json +13 -0
  125. package/webpack.config.js +55 -0
@@ -0,0 +1,111 @@
1
+ const fs = require('fs-extra');
2
+ const { decryptConnection } = require('./crypting');
3
+ const { getSshTunnelProxy } = require('./sshTunnelProxy');
4
+ const platformInfo = require('../utility/platformInfo');
5
+ const connections = require('../controllers/connections');
6
+ const _ = require('lodash');
7
+
8
+ async function loadConnection(driver, storedConnection, connectionMode) {
9
+ const { allowShellConnection, allowConnectionFromEnvVariables } = platformInfo;
10
+
11
+ if (connectionMode == 'app') {
12
+ return storedConnection;
13
+ }
14
+
15
+ if (storedConnection._id || !allowShellConnection) {
16
+ if (!storedConnection._id) {
17
+ throw new Error('Missing connection _id');
18
+ }
19
+
20
+ await connections._init();
21
+ const loaded = await connections.getCore({ conid: storedConnection._id });
22
+ const loadedWithDb = {
23
+ ...loaded,
24
+ database: storedConnection.database,
25
+ };
26
+
27
+ if (loaded.isReadOnly) {
28
+ if (connectionMode == 'read') return loadedWithDb;
29
+ if (connectionMode == 'write') throw new Error('Cannot write readonly connection');
30
+ if (connectionMode == 'script') {
31
+ if (driver.readOnlySessions) return loadedWithDb;
32
+ throw new Error('Cannot write readonly connection');
33
+ }
34
+ }
35
+ return loadedWithDb;
36
+ }
37
+
38
+ if (allowConnectionFromEnvVariables) {
39
+ return _.mapValues(storedConnection, (value, key) => {
40
+ if (_.isString(value) && value.startsWith('${') && value.endsWith('}')) {
41
+ return process.env[value.slice(2, -1)];
42
+ }
43
+ return value;
44
+ });
45
+ }
46
+
47
+ return storedConnection;
48
+ }
49
+
50
+ async function connectUtility(driver, storedConnection, connectionMode, additionalOptions = null) {
51
+ const connectionLoaded = await loadConnection(driver, storedConnection, connectionMode);
52
+
53
+ const connection = {
54
+ database: connectionLoaded.defaultDatabase,
55
+ ...decryptConnection(connectionLoaded),
56
+ };
57
+
58
+ if (!connection.port && driver.defaultPort) connection.port = driver.defaultPort.toString();
59
+
60
+ if (connection.useSshTunnel) {
61
+ const tunnel = await getSshTunnelProxy(connection);
62
+ if (tunnel.state == 'error') {
63
+ throw new Error(tunnel.message);
64
+ }
65
+
66
+ connection.server = 'localhost';
67
+ connection.port = tunnel.localPort;
68
+ }
69
+
70
+ // SSL functionality - copied from https://github.com/beekeeper-studio/beekeeper-studio
71
+ if (connection.useSsl) {
72
+ connection.ssl = {};
73
+
74
+ if (connection.sslCaFile) {
75
+ connection.ssl.ca = await fs.readFile(connection.sslCaFile);
76
+ connection.ssl.sslCaFile = connection.sslCaFile;
77
+ }
78
+
79
+ if (connection.sslCertFile) {
80
+ connection.ssl.cert = await fs.readFile(connection.sslCertFile);
81
+ connection.ssl.sslCertFile = connection.sslCertFile;
82
+ }
83
+
84
+ if (connection.sslKeyFile) {
85
+ connection.ssl.key = await fs.readFile(connection.sslKeyFile);
86
+ connection.ssl.sslKeyFile = connection.sslKeyFile;
87
+ }
88
+
89
+ if (connection.sslCertFilePassword) {
90
+ connection.ssl.password = connection.sslCertFilePassword;
91
+ }
92
+
93
+ if (!connection.ssl.key && !connection.ssl.ca && !connection.ssl.cert) {
94
+ // TODO: provide this as an option in settings
95
+ // or per-connection as 'reject self-signed certs'
96
+ // How it works:
97
+ // if false, cert can be self-signed
98
+ // if true, has to be from a public CA
99
+ // Heroku certs are self-signed.
100
+ // if you provide ca/cert/key files, it overrides this
101
+ connection.ssl.rejectUnauthorized = false;
102
+ } else {
103
+ connection.ssl.rejectUnauthorized = connection.sslRejectUnauthorized;
104
+ }
105
+ }
106
+
107
+ const conn = await driver.connect({ ...connection, ...additionalOptions });
108
+ return conn;
109
+ }
110
+
111
+ module.exports = connectUtility;
@@ -0,0 +1,105 @@
1
+ const crypto = require('crypto');
2
+ const simpleEncryptor = require('simple-encryptor');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const _ = require('lodash');
6
+
7
+ const { datadir } = require('./directories');
8
+
9
+ const defaultEncryptionKey = 'mQAUaXhavRGJDxDTXSCg7Ej0xMmGCrx6OKA07DIMBiDcYYkvkaXjTAzPUEHEHEf9';
10
+
11
+ let _encryptionKey = null;
12
+
13
+ function loadEncryptionKey() {
14
+ if (_encryptionKey) {
15
+ return _encryptionKey;
16
+ }
17
+ const encryptor = simpleEncryptor.createEncryptor(defaultEncryptionKey);
18
+
19
+ const keyFile = path.join(datadir(), '.key');
20
+
21
+ if (!fs.existsSync(keyFile)) {
22
+ const generatedKey = crypto.randomBytes(32);
23
+ const newKey = generatedKey.toString('hex');
24
+ const result = {
25
+ encryptionKey: newKey,
26
+ };
27
+ fs.writeFileSync(keyFile, encryptor.encrypt(result), 'utf-8');
28
+ }
29
+
30
+ const encryptedData = fs.readFileSync(keyFile, 'utf-8');
31
+ const data = encryptor.decrypt(encryptedData);
32
+ _encryptionKey = data['encryptionKey'];
33
+ return _encryptionKey;
34
+ }
35
+
36
+ let _encryptor = null;
37
+
38
+ function getEncryptor() {
39
+ if (_encryptor) {
40
+ return _encryptor;
41
+ }
42
+ _encryptor = simpleEncryptor.createEncryptor(loadEncryptionKey());
43
+ return _encryptor;
44
+ }
45
+
46
+ function encryptPasswordField(connection, field) {
47
+ if (
48
+ connection &&
49
+ connection[field] &&
50
+ !connection[field].startsWith('crypt:') &&
51
+ connection.passwordMode != 'saveRaw'
52
+ ) {
53
+ return {
54
+ ...connection,
55
+ [field]: 'crypt:' + getEncryptor().encrypt(connection[field]),
56
+ };
57
+ }
58
+ return connection;
59
+ }
60
+
61
+ function decryptPasswordField(connection, field) {
62
+ if (connection && connection[field] && connection[field].startsWith('crypt:')) {
63
+ return {
64
+ ...connection,
65
+ [field]: getEncryptor().decrypt(connection[field].substring('crypt:'.length)),
66
+ };
67
+ }
68
+ return connection;
69
+ }
70
+
71
+ function encryptConnection(connection) {
72
+ connection = encryptPasswordField(connection, 'password');
73
+ connection = encryptPasswordField(connection, 'sshPassword');
74
+ connection = encryptPasswordField(connection, 'sshKeyfilePassword');
75
+ return connection;
76
+ }
77
+
78
+ function maskConnection(connection) {
79
+ if (!connection) return connection;
80
+ return _.omit(connection, ['password', 'sshPassword', 'sshKeyfilePassword']);
81
+ }
82
+
83
+ function decryptConnection(connection) {
84
+ connection = decryptPasswordField(connection, 'password');
85
+ connection = decryptPasswordField(connection, 'sshPassword');
86
+ connection = decryptPasswordField(connection, 'sshKeyfilePassword');
87
+ return connection;
88
+ }
89
+
90
+ function pickSafeConnectionInfo(connection) {
91
+ return _.mapValues(connection, (v, k) => {
92
+ if (k == 'engine' || k == 'port' || k == 'authType' || k == 'sshMode' || k == 'passwordMode') return v;
93
+ if (v === null || v === true || v === false) return v;
94
+ if (v) return '***';
95
+ return undefined;
96
+ });
97
+ }
98
+
99
+ module.exports = {
100
+ loadEncryptionKey,
101
+ encryptConnection,
102
+ decryptConnection,
103
+ maskConnection,
104
+ pickSafeConnectionInfo,
105
+ };
@@ -0,0 +1,8 @@
1
+ const diff2htmlCss =
2
+ '.d2h-d-none{display:none}.d2h-wrapper{text-align:left}.d2h-file-header{background-color:#f7f7f7;border-bottom:1px solid #d8d8d8;font-family:Source Sans Pro,Helvetica Neue,Helvetica,Arial,sans-serif;height:35px;padding:5px 10px}.d2h-file-header,.d2h-file-stats{display:-webkit-box;display:-ms-flexbox;display:flex}.d2h-file-stats{font-size:14px;margin-left:auto}.d2h-lines-added{border:1px solid #b4e2b4;border-radius:5px 0 0 5px;color:#399839;padding:2px;text-align:right;vertical-align:middle}.d2h-lines-deleted{border:1px solid #e9aeae;border-radius:0 5px 5px 0;color:#c33;margin-left:1px;padding:2px;text-align:left;vertical-align:middle}.d2h-file-name-wrapper{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:15px;width:100%}.d2h-file-name{overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}.d2h-file-wrapper{border:1px solid #ddd;border-radius:3px;margin-bottom:1em}.d2h-file-collapse{-webkit-box-pack:end;-ms-flex-pack:end;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border:1px solid #ddd;border-radius:3px;cursor:pointer;display:none;font-size:12px;justify-content:flex-end;padding:4px 8px}.d2h-file-collapse.d2h-selected{background-color:#c8e1ff}.d2h-file-collapse-input{margin:0 4px 0 0}.d2h-diff-table{border-collapse:collapse;font-family:Menlo,Consolas,monospace;font-size:13px;width:100%}.d2h-files-diff{width:100%}.d2h-file-diff{overflow-y:hidden}.d2h-file-side-diff{display:inline-block;margin-bottom:-8px;margin-right:-4px;overflow-x:scroll;overflow-y:hidden;width:50%}.d2h-code-line{padding:0 8em}.d2h-code-line,.d2h-code-side-line{display:inline-block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;white-space:nowrap;width:100%}.d2h-code-side-line{padding:0 4.5em}.d2h-code-line-ctn{word-wrap:normal;background:none;display:inline-block;padding:0;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;vertical-align:middle;white-space:pre;width:100%}.d2h-code-line del,.d2h-code-side-line del{background-color:#ffb6ba}.d2h-code-line del,.d2h-code-line ins,.d2h-code-side-line del,.d2h-code-side-line ins{border-radius:.2em;display:inline-block;margin-top:-1px;text-decoration:none;vertical-align:middle}.d2h-code-line ins,.d2h-code-side-line ins{background-color:#97f295;text-align:left}.d2h-code-line-prefix{word-wrap:normal;background:none;display:inline;padding:0;white-space:pre}.line-num1{float:left}.line-num1,.line-num2{-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;padding:0 .5em;text-overflow:ellipsis;width:3.5em}.line-num2{float:right}.d2h-code-linenumber{background-color:#fff;border:solid #eee;border-width:0 1px;-webkit-box-sizing:border-box;box-sizing:border-box;color:rgba(0,0,0,.3);cursor:pointer;display:inline-block;position:absolute;text-align:right;width:7.5em}.d2h-code-linenumber:after{content:"\200b"}.d2h-code-side-linenumber{background-color:#fff;border:solid #eee;border-width:0 1px;-webkit-box-sizing:border-box;box-sizing:border-box;color:rgba(0,0,0,.3);cursor:pointer;display:inline-block;overflow:hidden;padding:0 .5em;position:absolute;text-align:right;text-overflow:ellipsis;width:4em}.d2h-code-side-linenumber:after{content:"\200b"}.d2h-code-side-emptyplaceholder,.d2h-emptyplaceholder{background-color:#f1f1f1;border-color:#e1e1e1}.d2h-code-line-prefix,.d2h-code-linenumber,.d2h-code-side-linenumber,.d2h-emptyplaceholder{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.d2h-code-linenumber,.d2h-code-side-linenumber{direction:rtl}.d2h-del{background-color:#fee8e9;border-color:#e9aeae}.d2h-ins{background-color:#dfd;border-color:#b4e2b4}.d2h-info{background-color:#f8fafd;border-color:#d5e4f2;color:rgba(0,0,0,.3)}.d2h-file-diff .d2h-del.d2h-change{background-color:#fdf2d0}.d2h-file-diff .d2h-ins.d2h-change{background-color:#ded}.d2h-file-list-wrapper{margin-bottom:10px}.d2h-file-list-wrapper a{color:#3572b0;text-decoration:none}.d2h-file-list-wrapper a:visited{color:#3572b0}.d2h-file-list-header{text-align:left}.d2h-file-list-title{font-weight:700}.d2h-file-list-line{display:-webkit-box;display:-ms-flexbox;display:flex;text-align:left}.d2h-file-list{display:block;list-style:none;margin:0;padding:0}.d2h-file-list>li{border-bottom:1px solid #ddd;margin:0;padding:5px 10px}.d2h-file-list>li:last-child{border-bottom:none}.d2h-file-switch{cursor:pointer;display:none;font-size:10px}.d2h-icon{fill:currentColor;margin-right:10px;vertical-align:middle}.d2h-deleted{color:#c33}.d2h-added{color:#399839}.d2h-changed{color:#d0b44c}.d2h-moved{color:#3572b0}.d2h-tag{background-color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:10px;margin-left:5px;padding:0 2px}.d2h-deleted-tag{border:1px solid #c33}.d2h-added-tag{border:1px solid #399839}.d2h-changed-tag{border:1px solid #d0b44c}.d2h-moved-tag{border:1px solid #3572b0}';
3
+
4
+ function diff2htmlPage(content) {
5
+ return `<html><head><style>${diff2htmlCss}</style><body>${content}</body></html>`;
6
+ }
7
+
8
+ module.exports = diff2htmlPage;
@@ -0,0 +1,179 @@
1
+ const os = require('os');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+ const _ = require('lodash');
5
+ const cleanDirectory = require('./cleanDirectory');
6
+ const platformInfo = require('./platformInfo');
7
+ const processArgs = require('./processArgs');
8
+ const consoleObjectWriter = require('../shell/consoleObjectWriter');
9
+ const { getLogger } = require('dbgate-tools');
10
+
11
+ let logsFilePath;
12
+
13
+ const createDirectories = {};
14
+ const ensureDirectory = (dir, clean) => {
15
+ if (!createDirectories[dir]) {
16
+ if (clean && fs.existsSync(dir) && !platformInfo.isForkedApi) {
17
+ getLogger('directories').info(`Cleaning directory ${dir}`);
18
+ cleanDirectory(dir, _.isNumber(clean) ? clean : null);
19
+ }
20
+ if (!fs.existsSync(dir)) {
21
+ getLogger('directories').info(`Creating directory ${dir}`);
22
+ fs.mkdirSync(dir);
23
+ }
24
+ createDirectories[dir] = true;
25
+ }
26
+ };
27
+
28
+ function datadirCore() {
29
+ if (process.env.WORKSPACE_DIR) {
30
+ return process.env.WORKSPACE_DIR;
31
+ }
32
+ if (processArgs.workspaceDir) {
33
+ return processArgs.workspaceDir;
34
+ }
35
+ return path.join(os.homedir(), '.dbgate');
36
+ }
37
+
38
+ function datadir() {
39
+ const dir = datadirCore();
40
+ ensureDirectory(dir);
41
+
42
+ return dir;
43
+ }
44
+
45
+ const dirFunc =
46
+ (dirname, clean, subdirs = []) =>
47
+ () => {
48
+ const dir = path.join(datadir(), dirname);
49
+ ensureDirectory(dir, clean);
50
+ for (const subdir of subdirs) {
51
+ ensureDirectory(path.join(dir, subdir), false);
52
+ }
53
+
54
+ return dir;
55
+ };
56
+
57
+ const jsldir = dirFunc('jsl', true);
58
+ const rundir = dirFunc('run', true);
59
+ const uploadsdir = dirFunc('uploads', true);
60
+ const pluginsdir = dirFunc('plugins');
61
+ const archivedir = dirFunc('archive', false, ['default']);
62
+ const appdir = dirFunc('apps');
63
+ const filesdir = dirFunc('files');
64
+ const logsdir = dirFunc('logs', 3600 * 24 * 7);
65
+
66
+ function packagedPluginsDir() {
67
+ // console.log('CALL DIR FROM', new Error('xxx').stack);
68
+ // console.log('__dirname', __dirname);
69
+ // console.log('platformInfo.isElectronBundle', platformInfo.isElectronBundle);
70
+ // console.log('platformInfo.isForkedApi', platformInfo.isForkedApi);
71
+ if (platformInfo.isDevMode) {
72
+ return path.resolve(__dirname, '../../../../plugins');
73
+ }
74
+ if (platformInfo.isBuiltWebMode) {
75
+ return path.resolve(__dirname, '../../plugins');
76
+ }
77
+ if (platformInfo.isDocker) {
78
+ return '/home/dbgate-docker/plugins';
79
+ }
80
+ if (platformInfo.isAwsUbuntuLayout) {
81
+ return '/home/ubuntu/build/plugins';
82
+ }
83
+ if (platformInfo.isNpmDist) {
84
+ // node_modules
85
+ return global['PLUGINS_DIR'];
86
+ }
87
+ if (processArgs.pluginsDir) {
88
+ return processArgs.pluginsDir;
89
+ }
90
+ if (platformInfo.isElectronBundle) {
91
+ return path.resolve(__dirname, '../../plugins');
92
+
93
+ // if (platformInfo.isForkedApi) {
94
+ // return path.resolve(__dirname, '../plugins');
95
+ // } else {
96
+ // return path.resolve(__dirname, '../../plugins');
97
+ // }
98
+ }
99
+ return null;
100
+ }
101
+
102
+ const packagedPluginList =
103
+ packagedPluginsDir() != null ? fs.readdirSync(packagedPluginsDir()).filter(x => x.startsWith('dbgate-plugin-')) : [];
104
+
105
+ function getPluginBackendPath(packageName) {
106
+ if (packagedPluginList.includes(packageName)) {
107
+ if (platformInfo.isDevMode) {
108
+ return path.join(packagedPluginsDir(), packageName, 'src', 'backend', 'index.js');
109
+ }
110
+ return path.join(packagedPluginsDir(), packageName, 'dist', 'backend.js');
111
+ }
112
+
113
+ return path.join(pluginsdir(), packageName, 'dist', 'backend.js');
114
+ }
115
+
116
+ let archiveLinksCache = {};
117
+
118
+ function resolveArchiveFolder(folder) {
119
+ if (folder.endsWith('.link')) {
120
+ if (!archiveLinksCache[folder]) {
121
+ archiveLinksCache[folder] = fs.readFileSync(path.join(archivedir(), folder), 'utf-8');
122
+ }
123
+ return archiveLinksCache[folder];
124
+ }
125
+ return path.join(archivedir(), folder);
126
+ }
127
+
128
+ function clearArchiveLinksCache() {
129
+ archiveLinksCache = {};
130
+ }
131
+
132
+ function migrateDataDir() {
133
+ if (process.env.WORKSPACE_DIR) {
134
+ return;
135
+ }
136
+ if (processArgs.workspaceDir) {
137
+ return;
138
+ }
139
+
140
+ try {
141
+ const oldDir = path.join(os.homedir(), 'dbgate-data');
142
+ const newDir = path.join(os.homedir(), '.dbgate');
143
+ if (fs.existsSync(oldDir) && !fs.existsSync(newDir)) {
144
+ fs.renameSync(oldDir, newDir);
145
+ }
146
+ } catch (err) {
147
+ getLogger('directories').error({ err }, 'Error migrating data dir');
148
+ }
149
+ }
150
+
151
+ function setLogsFilePath(value) {
152
+ logsFilePath = value;
153
+ }
154
+
155
+ function getLogsFilePath() {
156
+ return logsFilePath;
157
+ }
158
+
159
+ migrateDataDir();
160
+
161
+ module.exports = {
162
+ datadir,
163
+ jsldir,
164
+ rundir,
165
+ uploadsdir,
166
+ archivedir,
167
+ appdir,
168
+ ensureDirectory,
169
+ pluginsdir,
170
+ filesdir,
171
+ logsdir,
172
+ packagedPluginsDir,
173
+ packagedPluginList,
174
+ getPluginBackendPath,
175
+ resolveArchiveFolder,
176
+ clearArchiveLinksCache,
177
+ getLogsFilePath,
178
+ setLogsFilePath,
179
+ };
@@ -0,0 +1,51 @@
1
+ const crypto = require('crypto');
2
+ // const pacote = require('pacote');
3
+ const axios = require('axios');
4
+ // const tarballExtract = require('tarball-extract');
5
+ const path = require('path');
6
+ const fs = require('fs');
7
+ const zlib = require('zlib');
8
+ const tar = require('tar');
9
+ const ncp = require('ncp').ncp;
10
+ const { uploadsdir } = require('./directories');
11
+ const { downloadFile } = require('./downloader');
12
+
13
+ function extractTarball(tmpFile, destination) {
14
+ return new Promise((resolve, reject) => {
15
+ fs.createReadStream(tmpFile)
16
+ .pipe(zlib.createGunzip())
17
+ .pipe(tar.extract({ cwd: destination }))
18
+ .on('error', err => reject(err))
19
+ .on('end', () => resolve());
20
+ });
21
+ }
22
+
23
+ function copyDirectory(source, target) {
24
+ return new Promise((resolve, reject) => {
25
+ ncp(source, target, err => {
26
+ if (err) reject(err);
27
+ resolve();
28
+ });
29
+ });
30
+ }
31
+
32
+ async function downloadPackage(packageName, directory) {
33
+ // await pacote.extract(packageName, directory);
34
+ const infoResp = await axios.default.get(`https://registry.npmjs.org/${packageName}`);
35
+
36
+ const { latest } = infoResp.data['dist-tags'] || {};
37
+ if (!latest) return false;
38
+
39
+ const tarball = infoResp.data.versions[latest].dist.tarball;
40
+
41
+ const tmpFile = path.join(uploadsdir(), crypto.randomUUID() + '.tgz');
42
+ await downloadFile(tarball, tmpFile);
43
+ const tmpDir = path.join(uploadsdir(), crypto.randomUUID());
44
+ fs.mkdirSync(tmpDir);
45
+ await extractTarball(tmpFile, tmpDir);
46
+ await copyDirectory(path.join(tmpDir, 'package'), directory);
47
+
48
+ return true;
49
+ }
50
+
51
+ module.exports = downloadPackage;
@@ -0,0 +1,25 @@
1
+ const axios = require('axios');
2
+ const fs = require('fs');
3
+
4
+ function saveStreamToFile(pipedStream, fileName) {
5
+ return new Promise((resolve, reject) => {
6
+ const fileStream = fs.createWriteStream(fileName);
7
+ fileStream.on('close', () => resolve());
8
+ pipedStream.pipe(fileStream);
9
+ });
10
+ }
11
+
12
+ async function downloadFile(url, file) {
13
+ console.log(`Downloading ${url} into ${file}`);
14
+ const tarballResp = await axios.default({
15
+ method: 'get',
16
+ url,
17
+ responseType: 'stream',
18
+ });
19
+ await saveStreamToFile(tarballResp.data, file);
20
+ }
21
+
22
+ module.exports = {
23
+ saveStreamToFile,
24
+ downloadFile,
25
+ };
@@ -0,0 +1,9 @@
1
+ class MissingCredentialsError {
2
+ constructor(detail) {
3
+ this.detail = detail;
4
+ }
5
+ }
6
+
7
+ module.exports = {
8
+ MissingCredentialsError,
9
+ };
@@ -0,0 +1,31 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const yaml = require('js-yaml');
4
+ const { tableInfoToYaml } = require('dbgate-tools');
5
+
6
+ async function exportDbModel(dbModel, outputDir) {
7
+ const { tables, views, procedures, functions, triggers, matviews } = dbModel;
8
+
9
+ if (!fs.existsSync(outputDir)) {
10
+ await fs.mkdir(outputDir);
11
+ }
12
+
13
+ for (const table of tables || []) {
14
+ const content = yaml.dump(tableInfoToYaml(table));
15
+ await fs.writeFile(path.join(outputDir, `${table.pureName}.table.yaml`), content);
16
+ }
17
+
18
+ async function writeList(list, ext) {
19
+ for (const obj of list || []) {
20
+ await fs.writeFile(path.join(outputDir, `${obj.pureName}.${ext}.sql`), obj.createSql);
21
+ }
22
+ }
23
+
24
+ await writeList(views, 'view');
25
+ await writeList(procedures, 'proc');
26
+ await writeList(functions, 'func');
27
+ await writeList(triggers, 'trigger');
28
+ await writeList(matviews, 'matview');
29
+ }
30
+
31
+ module.exports = exportDbModel;
@@ -0,0 +1,80 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const { getSchemasUsedByStructure } = require('dbgate-tools');
4
+
5
+ async function exportDbModelSql(dbModel, driver, outputDir, outputFile) {
6
+ const { tables, views, procedures, functions, triggers, matviews } = dbModel;
7
+
8
+ const usedSchemas = getSchemasUsedByStructure(dbModel);
9
+ const useSchemaDir = usedSchemas.length > 1;
10
+
11
+ const createdDirs = new Set();
12
+ async function ensureDir(dir) {
13
+ if (!createdDirs.has(dir)) {
14
+ await fs.mkdir(dir, { recursive: true });
15
+ createdDirs.add(dir);
16
+ }
17
+ }
18
+
19
+ async function writeLists(writeList) {
20
+ await writeList(views, 'views');
21
+ await writeList(procedures, 'procedures');
22
+ await writeList(functions, 'functions');
23
+ await writeList(triggers, 'triggers');
24
+ await writeList(matviews, 'matviews');
25
+ }
26
+
27
+ if (outputFile) {
28
+ const dmp = driver.createDumper();
29
+ for (const table of tables || []) {
30
+ dmp.createTable({
31
+ ...table,
32
+ foreignKeys: [],
33
+ dependencies: [],
34
+ });
35
+ }
36
+ for (const table of tables || []) {
37
+ for (const fk of table.foreignKeys || []) {
38
+ dmp.createForeignKey(fk);
39
+ }
40
+ }
41
+ writeLists((list, folder) => {
42
+ for (const obj of list || []) {
43
+ dmp.createSqlObject(obj);
44
+ }
45
+ });
46
+
47
+ const script = dmp.s;
48
+ await fs.writeFile(outputFile, script);
49
+ }
50
+
51
+ if (outputDir) {
52
+ for (const table of tables || []) {
53
+ const tablesDir = useSchemaDir
54
+ ? path.join(outputDir, table.schemaName ?? 'default', 'tables')
55
+ : path.join(outputDir, 'tables');
56
+ await ensureDir(tablesDir);
57
+ const dmp = driver.createDumper();
58
+ dmp.createTable({
59
+ ...table,
60
+ foreignKeys: [],
61
+ dependencies: [],
62
+ });
63
+ await fs.writeFile(path.join(tablesDir, `${table.pureName}.sql`), dmp.s);
64
+ }
65
+
66
+ await writeLists(async (list, folder) => {
67
+ for (const obj of list || []) {
68
+ const objdir = useSchemaDir
69
+ ? path.join(outputDir, obj.schemaName ?? 'default', folder)
70
+ : path.join(outputDir, folder);
71
+ await ensureDir(objdir);
72
+ const dmp = driver.createDumper();
73
+ dmp.createSqlObject(obj);
74
+ await fs.writeFile(path.join(objdir, `${obj.pureName}.sql`), dmp.s);
75
+ }
76
+ });
77
+ }
78
+ }
79
+
80
+ module.exports = exportDbModelSql;
@@ -0,0 +1,55 @@
1
+ const getChartExport = (title, config, imageFile) => {
2
+ return `<html>
3
+ <meta charset='utf-8'>
4
+
5
+ <head>
6
+ ${title ? `<title>${title}</title>` : ''}
7
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.6.0/chart.min.js" integrity="sha512-GMGzUEevhWh8Tc/njS0bDpwgxdCJLQBWG3Z2Ct+JGOpVnEmjvNx6ts4v6A2XJf1HOrtOsfhv3hBKpK9kE5z8AQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
8
+ <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
+ <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
+ <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>
12
+
13
+ <style>
14
+ a { text-decoration: none }
15
+
16
+ .footer {
17
+ float: right;
18
+ font-family: Arial;
19
+ color: #888;
20
+ margin-top: 10px;
21
+ margin-right: 10px;
22
+ font-size: 10pt;
23
+ }
24
+ </style>
25
+
26
+ <script>
27
+ const config = ${JSON.stringify(config)};
28
+
29
+ function showChart() {
30
+ document.getElementById('myImage').style.display = "none";
31
+
32
+ const myChart = new Chart(
33
+ document.getElementById('myChart'),
34
+ config
35
+ );
36
+ }
37
+ </script>
38
+ </head>
39
+
40
+ <body onload="showChart()">
41
+ <img src="${imageFile}" id="myImage" />
42
+
43
+ <div>
44
+ <canvas id="myChart"></canvas>
45
+ </div>
46
+
47
+ <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>
49
+ </div>
50
+ </body>
51
+
52
+ </html>`;
53
+ };
54
+
55
+ module.exports = getChartExport;