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,217 @@
1
+ const fs = require('fs-extra');
2
+ const readline = require('readline');
3
+ const crypto = require('crypto');
4
+ const path = require('path');
5
+ const { archivedir, clearArchiveLinksCache, resolveArchiveFolder } = require('../utility/directories');
6
+ const socket = require('../utility/socket');
7
+ const loadFilesRecursive = require('../utility/loadFilesRecursive');
8
+ const getJslFileName = require('../utility/getJslFileName');
9
+ const { getLogger, extractErrorLogData } = require('dbgate-tools');
10
+ const dbgateApi = require('../shell');
11
+ const jsldata = require('./jsldata');
12
+ const platformInfo = require('../utility/platformInfo');
13
+
14
+ const logger = getLogger('archive');
15
+
16
+ module.exports = {
17
+ folders_meta: true,
18
+ async folders() {
19
+ const folders = await fs.readdir(archivedir());
20
+ return [
21
+ {
22
+ name: 'default',
23
+ type: 'jsonl',
24
+ },
25
+ ...folders
26
+ .filter(x => x != 'default')
27
+ .map(name => ({
28
+ name,
29
+ type: 'jsonl',
30
+ })),
31
+ ];
32
+ },
33
+
34
+ createFolder_meta: true,
35
+ async createFolder({ folder }) {
36
+ await fs.mkdir(path.join(archivedir(), folder));
37
+ socket.emitChanged('archive-folders-changed');
38
+ return true;
39
+ },
40
+
41
+ createLink_meta: true,
42
+ async createLink({ linkedFolder }) {
43
+ const folder = await this.getNewArchiveFolder({ database: path.parse(linkedFolder).name + '.link' });
44
+ fs.writeFile(path.join(archivedir(), folder), linkedFolder);
45
+ clearArchiveLinksCache();
46
+ socket.emitChanged('archive-folders-changed');
47
+ return folder;
48
+ },
49
+
50
+ files_meta: true,
51
+ async files({ folder }) {
52
+ try {
53
+ const dir = resolveArchiveFolder(folder);
54
+ if (!(await fs.exists(dir))) return [];
55
+ const files = await loadFilesRecursive(dir); // fs.readdir(dir);
56
+
57
+ function fileType(ext, type) {
58
+ return files
59
+ .filter(name => name.endsWith(ext))
60
+ .map(name => ({
61
+ name: name.slice(0, -ext.length),
62
+ label: path.parse(name.slice(0, -ext.length)).base,
63
+ type,
64
+ }));
65
+ }
66
+
67
+ return [
68
+ ...fileType('.jsonl', 'jsonl'),
69
+ ...fileType('.table.yaml', 'table.yaml'),
70
+ ...fileType('.view.sql', 'view.sql'),
71
+ ...fileType('.proc.sql', 'proc.sql'),
72
+ ...fileType('.func.sql', 'func.sql'),
73
+ ...fileType('.trigger.sql', 'trigger.sql'),
74
+ ...fileType('.matview.sql', 'matview.sql'),
75
+ ];
76
+ } catch (err) {
77
+ logger.error(extractErrorLogData(err), 'Error reading archive files');
78
+ return [];
79
+ }
80
+ },
81
+
82
+ refreshFiles_meta: true,
83
+ async refreshFiles({ folder }) {
84
+ socket.emitChanged('archive-files-changed', { folder });
85
+ return true;
86
+ },
87
+
88
+ refreshFolders_meta: true,
89
+ async refreshFolders() {
90
+ socket.emitChanged(`archive-folders-changed`);
91
+ return true;
92
+ },
93
+
94
+ deleteFile_meta: true,
95
+ async deleteFile({ folder, file, fileType }) {
96
+ await fs.unlink(path.join(resolveArchiveFolder(folder), `${file}.${fileType}`));
97
+ socket.emitChanged(`archive-files-changed`, { folder });
98
+ return true;
99
+ },
100
+
101
+ renameFile_meta: true,
102
+ async renameFile({ folder, file, newFile, fileType }) {
103
+ await fs.rename(
104
+ path.join(resolveArchiveFolder(folder), `${file}.${fileType}`),
105
+ path.join(resolveArchiveFolder(folder), `${newFile}.${fileType}`)
106
+ );
107
+ socket.emitChanged(`archive-files-changed`, { folder });
108
+ return true;
109
+ },
110
+
111
+ modifyFile_meta: true,
112
+ async modifyFile({ folder, file, changeSet, mergedRows, mergeKey, mergeMode }) {
113
+ await jsldata.closeDataStore(`archive://${folder}/${file}`);
114
+ const changedFilePath = path.join(resolveArchiveFolder(folder), `${file}.jsonl`);
115
+
116
+ if (!fs.existsSync(changedFilePath)) {
117
+ if (!mergedRows) {
118
+ return false;
119
+ }
120
+ const fileStream = fs.createWriteStream(changedFilePath);
121
+ for (const row of mergedRows) {
122
+ await fileStream.write(JSON.stringify(row) + '\n');
123
+ }
124
+ await fileStream.close();
125
+
126
+ socket.emitChanged(`archive-files-changed`, { folder });
127
+ return true;
128
+ }
129
+
130
+ const tmpchangedFilePath = path.join(resolveArchiveFolder(folder), `${file}-${crypto.randomUUID()}.jsonl`);
131
+ const reader = await dbgateApi.modifyJsonLinesReader({
132
+ fileName: changedFilePath,
133
+ changeSet,
134
+ mergedRows,
135
+ mergeKey,
136
+ mergeMode,
137
+ });
138
+ const writer = await dbgateApi.jsonLinesWriter({ fileName: tmpchangedFilePath });
139
+ await dbgateApi.copyStream(reader, writer);
140
+ if (platformInfo.isWindows) {
141
+ await fs.copyFile(tmpchangedFilePath, changedFilePath);
142
+ await fs.unlink(tmpchangedFilePath);
143
+ } else {
144
+ await fs.unlink(changedFilePath);
145
+ await fs.rename(tmpchangedFilePath, changedFilePath);
146
+ }
147
+ return true;
148
+ },
149
+
150
+ renameFolder_meta: true,
151
+ async renameFolder({ folder, newFolder }) {
152
+ const uniqueName = await this.getNewArchiveFolder({ database: newFolder });
153
+ await fs.rename(path.join(archivedir(), folder), path.join(archivedir(), uniqueName));
154
+ socket.emitChanged(`archive-folders-changed`);
155
+ return true;
156
+ },
157
+
158
+ deleteFolder_meta: true,
159
+ async deleteFolder({ folder }) {
160
+ if (!folder) throw new Error('Missing folder parameter');
161
+ if (folder.endsWith('.link')) {
162
+ await fs.unlink(path.join(archivedir(), folder));
163
+ } else {
164
+ await fs.rmdir(path.join(archivedir(), folder), { recursive: true });
165
+ }
166
+ socket.emitChanged(`archive-folders-changed`);
167
+ return true;
168
+ },
169
+
170
+ saveText_meta: true,
171
+ async saveText({ folder, file, text }) {
172
+ await fs.writeFile(path.join(resolveArchiveFolder(folder), `${file}.jsonl`), text);
173
+ socket.emitChanged(`archive-files-changed`, { folder });
174
+ return true;
175
+ },
176
+
177
+ saveJslData_meta: true,
178
+ async saveJslData({ folder, file, jslid, changeSet }) {
179
+ const source = getJslFileName(jslid);
180
+ const target = path.join(resolveArchiveFolder(folder), `${file}.jsonl`);
181
+ if (changeSet) {
182
+ const reader = await dbgateApi.modifyJsonLinesReader({
183
+ fileName: source,
184
+ changeSet,
185
+ });
186
+ const writer = await dbgateApi.jsonLinesWriter({ fileName: target });
187
+ await dbgateApi.copyStream(reader, writer);
188
+ } else {
189
+ await fs.copyFile(source, target);
190
+ socket.emitChanged(`archive-files-changed`, { folder });
191
+ }
192
+ return true;
193
+ },
194
+
195
+ saveRows_meta: true,
196
+ async saveRows({ folder, file, rows }) {
197
+ const fileStream = fs.createWriteStream(path.join(resolveArchiveFolder(folder), `${file}.jsonl`));
198
+ for (const row of rows) {
199
+ await fileStream.write(JSON.stringify(row) + '\n');
200
+ }
201
+ await fileStream.close();
202
+ socket.emitChanged(`archive-files-changed`, { folder });
203
+ return true;
204
+ },
205
+
206
+ async getNewArchiveFolder({ database }) {
207
+ const isLink = database.endsWith(database);
208
+ const name = isLink ? database.slice(0, -5) : database;
209
+ const suffix = isLink ? '.link' : '';
210
+ if (!(await fs.exists(path.join(archivedir(), database)))) return database;
211
+ let index = 2;
212
+ while (await fs.exists(path.join(archivedir(), `${name}${index}${suffix}`))) {
213
+ index += 1;
214
+ }
215
+ return `${name}${index}${suffix}`;
216
+ },
217
+ };
@@ -0,0 +1,136 @@
1
+ const axios = require('axios');
2
+ const jwt = require('jsonwebtoken');
3
+ const getExpressPath = require('../utility/getExpressPath');
4
+ const { getLogger, extractErrorLogData } = require('dbgate-tools');
5
+ const AD = require('activedirectory2').promiseWrapper;
6
+ const crypto = require('crypto');
7
+ const { getTokenSecret, getTokenLifetime } = require('../auth/authCommon');
8
+ const {
9
+ getAuthProviderFromReq,
10
+ getAuthProviders,
11
+ getDefaultAuthProvider,
12
+ getAuthProviderById,
13
+ } = require('../auth/authProvider');
14
+ const storage = require('./storage');
15
+
16
+ const logger = getLogger('auth');
17
+
18
+ function unauthorizedResponse(req, res, text) {
19
+ // if (req.path == getExpressPath('/config/get-settings')) {
20
+ // return res.json({});
21
+ // }
22
+ // if (req.path == getExpressPath('/connections/list')) {
23
+ // return res.json([]);
24
+ // }
25
+
26
+ return res.status(401).send(text);
27
+ }
28
+
29
+ function authMiddleware(req, res, next) {
30
+ const SKIP_AUTH_PATHS = [
31
+ '/config/get',
32
+ '/config/logout',
33
+ '/config/get-settings',
34
+ '/config/save-license-key',
35
+ '/auth/oauth-token',
36
+ '/auth/login',
37
+ '/auth/redirect',
38
+ '/stream',
39
+ '/storage/get-connections-for-login-page',
40
+ '/storage/set-admin-password',
41
+ '/auth/get-providers',
42
+ '/connections/dblogin-web',
43
+ '/connections/dblogin-app',
44
+ '/connections/dblogin-auth',
45
+ '/connections/dblogin-auth-token',
46
+ ];
47
+
48
+ // console.log('********************* getAuthProvider()', getAuthProvider());
49
+
50
+ // const isAdminPage = req.headers['x-is-admin-page'] == 'true';
51
+
52
+ if (process.env.BASIC_AUTH) {
53
+ // API is not authorized for basic auth
54
+ return next();
55
+ }
56
+
57
+ let skipAuth = !!SKIP_AUTH_PATHS.find(x => req.path == getExpressPath(x));
58
+
59
+ const authHeader = req.headers.authorization;
60
+ if (!authHeader) {
61
+ if (skipAuth) {
62
+ return next();
63
+ }
64
+ return unauthorizedResponse(req, res, 'missing authorization header');
65
+ }
66
+ const token = authHeader.split(' ')[1];
67
+ try {
68
+ const decoded = jwt.verify(token, getTokenSecret());
69
+ req.user = decoded;
70
+ return next();
71
+ } catch (err) {
72
+ if (skipAuth) {
73
+ req.isInvalidToken = true;
74
+ return next();
75
+ }
76
+
77
+ logger.error(extractErrorLogData(err), 'Sending invalid token error');
78
+
79
+ return unauthorizedResponse(req, res, 'invalid token');
80
+ }
81
+ }
82
+
83
+ module.exports = {
84
+ oauthToken_meta: true,
85
+ async oauthToken(params) {
86
+ const { amoid } = params;
87
+ return getAuthProviderById(amoid).oauthToken(params);
88
+ },
89
+ login_meta: true,
90
+ async login(params) {
91
+ const { amoid, login, password, isAdminPage } = params;
92
+
93
+ if (isAdminPage) {
94
+ let adminPassword = process.env.ADMIN_PASSWORD;
95
+ if (!adminPassword) {
96
+ const adminConfig = await storage.readConfig({ group: 'admin' });
97
+ adminPassword = adminConfig?.adminPassword;
98
+ }
99
+ if (adminPassword && adminPassword == password) {
100
+ return {
101
+ accessToken: jwt.sign(
102
+ {
103
+ login: 'superadmin',
104
+ permissions: await storage.loadSuperadminPermissions(),
105
+ roleId: -3,
106
+ },
107
+ getTokenSecret(),
108
+ {
109
+ expiresIn: getTokenLifetime(),
110
+ }
111
+ ),
112
+ };
113
+ }
114
+
115
+ return { error: 'Login failed' };
116
+ }
117
+
118
+ return getAuthProviderById(amoid).login(login, password);
119
+ },
120
+
121
+ getProviders_meta: true,
122
+ getProviders() {
123
+ return {
124
+ providers: getAuthProviders().map(x => x.toJson()),
125
+ default: getDefaultAuthProvider()?.amoid,
126
+ };
127
+ },
128
+
129
+ redirect_meta: true,
130
+ async redirect(params) {
131
+ const { amoid } = params;
132
+ return getAuthProviderById(amoid).redirect(params);
133
+ },
134
+
135
+ authMiddleware,
136
+ };
@@ -0,0 +1,271 @@
1
+ const fs = require('fs-extra');
2
+ const os = require('os');
3
+ const path = require('path');
4
+ const axios = require('axios');
5
+ const { datadir, getLogsFilePath } = require('../utility/directories');
6
+ const { hasPermission } = require('../utility/hasPermission');
7
+ const socket = require('../utility/socket');
8
+ const _ = require('lodash');
9
+ const AsyncLock = require('async-lock');
10
+ const jwt = require('jsonwebtoken');
11
+
12
+ const currentVersion = require('../currentVersion');
13
+ const platformInfo = require('../utility/platformInfo');
14
+ const connections = require('../controllers/connections');
15
+ const { getAuthProviderFromReq } = require('../auth/authProvider');
16
+ const { checkLicense, checkLicenseKey } = require('../utility/checkLicense');
17
+ const storage = require('./storage');
18
+ const { getAuthProxyUrl } = require('../utility/authProxy');
19
+ const { getPublicHardwareFingerprint } = require('../utility/hardwareFingerprint');
20
+ const { extractErrorMessage } = require('dbgate-tools');
21
+
22
+ const lock = new AsyncLock();
23
+
24
+ module.exports = {
25
+ // settingsValue: {},
26
+
27
+ // async _init() {
28
+ // try {
29
+ // this.settingsValue = JSON.parse(await fs.readFile(path.join(datadir(), 'settings.json'), { encoding: 'utf-8' }));
30
+ // } catch (err) {
31
+ // this.settingsValue = {};
32
+ // }
33
+ // },
34
+
35
+ get_meta: true,
36
+ async get(_params, req) {
37
+ const authProvider = getAuthProviderFromReq(req);
38
+ const login = authProvider.getCurrentLogin(req);
39
+ const permissions = authProvider.getCurrentPermissions(req);
40
+ const isUserLoggedIn = authProvider.isUserLoggedIn(req);
41
+
42
+ const singleConid = authProvider.getSingleConnectionId(req);
43
+ const storageConnectionError = storage.getStorageConnectionError();
44
+
45
+ const singleConnection =
46
+ singleConid && !storageConnectionError
47
+ ? await connections.getCore({ conid: singleConid })
48
+ : connections.singleConnection;
49
+
50
+ let configurationError = null;
51
+ if (process.env.STORAGE_DATABASE && process.env.BASIC_AUTH) {
52
+ configurationError =
53
+ 'Basic authentization is not allowed, when using storage. Cannot use both STORAGE_DATABASE and BASIC_AUTH';
54
+ }
55
+
56
+ if (storageConnectionError && !configurationError) {
57
+ configurationError = extractErrorMessage(storageConnectionError);
58
+ }
59
+
60
+ const checkedLicense = storageConnectionError ? null : await checkLicense();
61
+ const isLicenseValid = checkedLicense?.status == 'ok';
62
+ const logoutUrl = storageConnectionError ? null : await authProvider.getLogoutUrl();
63
+ const adminConfig = storageConnectionError ? null : await storage.readConfig({ group: 'admin' });
64
+
65
+ const isAdminPasswordMissing = !!(
66
+ process.env.STORAGE_DATABASE &&
67
+ !process.env.ADMIN_PASSWORD &&
68
+ !process.env.BASIC_AUTH &&
69
+ !adminConfig?.adminPasswordState
70
+ );
71
+
72
+ const configResult = {
73
+ runAsPortal: !!connections.portalConnections,
74
+ singleDbConnection: connections.singleDbConnection,
75
+ singleConnection: singleConnection,
76
+ isUserLoggedIn,
77
+ // hideAppEditor: !!process.env.HIDE_APP_EDITOR,
78
+ allowShellConnection: platformInfo.allowShellConnection,
79
+ allowShellScripting: platformInfo.allowShellScripting,
80
+ isDocker: platformInfo.isDocker,
81
+ isElectron: platformInfo.isElectron,
82
+ isLicenseValid,
83
+ isLicenseExpired: checkedLicense?.isExpired,
84
+ trialDaysLeft: checkedLicense?.isGeneratedTrial && !checkedLicense?.isExpired ? checkedLicense?.daysLeft : null,
85
+ checkedLicense,
86
+ configurationError,
87
+ logoutUrl,
88
+ permissions,
89
+ login,
90
+ // ...additionalConfigProps,
91
+ isBasicAuth: !!process.env.BASIC_AUTH,
92
+ isAdminLoginForm: !!(
93
+ process.env.STORAGE_DATABASE &&
94
+ (process.env.ADMIN_PASSWORD || adminConfig?.adminPasswordState == 'set') &&
95
+ !process.env.BASIC_AUTH
96
+ ),
97
+ isAdminPasswordMissing,
98
+ isInvalidToken: req?.isInvalidToken,
99
+ adminPasswordState: adminConfig?.adminPasswordState,
100
+ storageDatabase: process.env.STORAGE_DATABASE,
101
+ logsFilePath: getLogsFilePath(),
102
+ connectionsFilePath: path.join(datadir(), 'connections.jsonl'),
103
+ ...currentVersion,
104
+ };
105
+
106
+ return configResult;
107
+ },
108
+
109
+ logout_meta: {
110
+ method: 'get',
111
+ raw: true,
112
+ },
113
+ logout(req, res) {
114
+ res.status(401).send('Logged out<br><a href="../..">Back to DbGate</a>');
115
+ },
116
+
117
+ platformInfo_meta: true,
118
+ async platformInfo() {
119
+ return platformInfo;
120
+ },
121
+
122
+ getSettings_meta: true,
123
+ async getSettings() {
124
+ const res = await lock.acquire('settings', async () => {
125
+ return await this.loadSettings();
126
+ });
127
+ return res;
128
+ },
129
+
130
+ deleteSettings_meta: true,
131
+ async deleteSettings() {
132
+ await fs.unlink(path.join(datadir(), 'settings.json'));
133
+ return true;
134
+ },
135
+
136
+ fillMissingSettings(value) {
137
+ const res = {
138
+ ...value,
139
+ };
140
+ if (value['app.useNativeMenu'] !== true && value['app.useNativeMenu'] !== false) {
141
+ // res['app.useNativeMenu'] = os.platform() == 'darwin' ? true : false;
142
+ res['app.useNativeMenu'] = false;
143
+ }
144
+ for (const envVar in process.env) {
145
+ if (envVar.startsWith('SETTINGS_')) {
146
+ const key = envVar.substring('SETTINGS_'.length);
147
+ if (!res[key]) {
148
+ res[key] = process.env[envVar];
149
+ }
150
+ }
151
+ }
152
+ return res;
153
+ },
154
+
155
+ async loadSettings() {
156
+ try {
157
+ const settingsText = await fs.readFile(path.join(datadir(), 'settings.json'), { encoding: 'utf-8' });
158
+ return {
159
+ ...this.fillMissingSettings(JSON.parse(settingsText)),
160
+ 'other.licenseKey': platformInfo.isElectron ? await this.loadLicenseKey() : undefined,
161
+ };
162
+ } catch (err) {
163
+ return this.fillMissingSettings({});
164
+ }
165
+ },
166
+
167
+ async loadLicenseKey() {
168
+ try {
169
+ const licenseKey = await fs.readFile(path.join(datadir(), 'license.key'), { encoding: 'utf-8' });
170
+ return licenseKey;
171
+ } catch (err) {
172
+ return null;
173
+ }
174
+ },
175
+
176
+ saveLicenseKey_meta: true,
177
+ async saveLicenseKey({ licenseKey }) {
178
+ const decoded = jwt.decode(licenseKey);
179
+ if (!decoded) {
180
+ return {
181
+ status: 'error',
182
+ errorMessage: 'Invalid license key',
183
+ };
184
+ }
185
+
186
+ const { exp } = decoded;
187
+ if (exp * 1000 < Date.now()) {
188
+ return {
189
+ status: 'error',
190
+ errorMessage: 'License key is expired',
191
+ };
192
+ }
193
+
194
+ try {
195
+ if (process.env.STORAGE_DATABASE) {
196
+ await storage.writeConfig({ group: 'license', config: { licenseKey } });
197
+ // await storageWriteConfig('license', { licenseKey });
198
+ } else {
199
+ await fs.writeFile(path.join(datadir(), 'license.key'), licenseKey);
200
+ }
201
+ socket.emitChanged(`config-changed`);
202
+ return { status: 'ok' };
203
+ } catch (err) {
204
+ return {
205
+ status: 'error',
206
+ errorMessage: err.message,
207
+ };
208
+ }
209
+ },
210
+
211
+ startTrial_meta: true,
212
+ async startTrial() {
213
+ try {
214
+ const fingerprint = await getPublicHardwareFingerprint();
215
+
216
+ const resp = await axios.default.post(`${getAuthProxyUrl()}/trial-license`, {
217
+ type: 'premium-trial',
218
+ days: 30,
219
+ fingerprint,
220
+ });
221
+ const { token } = resp.data;
222
+
223
+ return await this.saveLicenseKey({ licenseKey: token });
224
+ } catch (err) {
225
+ return {
226
+ status: 'error',
227
+ errorMessage: err.message,
228
+ };
229
+ }
230
+ },
231
+
232
+ updateSettings_meta: true,
233
+ async updateSettings(values, req) {
234
+ if (!hasPermission(`settings/change`, req)) return false;
235
+
236
+ const res = await lock.acquire('settings', async () => {
237
+ const currentValue = await this.loadSettings();
238
+ try {
239
+ const updated = {
240
+ ...currentValue,
241
+ ..._.omit(values, ['other.licenseKey']),
242
+ };
243
+ await fs.writeFile(path.join(datadir(), 'settings.json'), JSON.stringify(updated, undefined, 2));
244
+ // this.settingsValue = updated;
245
+
246
+ if (currentValue['other.licenseKey'] != values['other.licenseKey']) {
247
+ await this.saveLicenseKey({ licenseKey: values['other.licenseKey'] });
248
+ socket.emitChanged(`config-changed`);
249
+ }
250
+
251
+ socket.emitChanged(`settings-changed`);
252
+ return updated;
253
+ } catch (err) {
254
+ return false;
255
+ }
256
+ });
257
+ return res;
258
+ },
259
+
260
+ changelog_meta: true,
261
+ async changelog() {
262
+ const resp = await axios.default.get('https://raw.githubusercontent.com/dbgate/dbgate/master/CHANGELOG.md');
263
+ return resp.data;
264
+ },
265
+
266
+ checkLicense_meta: true,
267
+ async checkLicense({ licenseKey }) {
268
+ const resp = await checkLicenseKey(licenseKey);
269
+ return resp;
270
+ },
271
+ };