dbgate-api-premium 7.0.4 → 7.1.0
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 +7 -6
- package/src/controllers/auth.js +2 -0
- package/src/controllers/connections.js +13 -13
- package/src/controllers/databaseConnections.js +5 -0
- package/src/controllers/restConnections.js +316 -0
- package/src/controllers/runners.js +10 -10
- package/src/controllers/storage.js +133 -1
- package/src/currentVersion.js +2 -2
- package/src/main.js +2 -0
- package/src/proc/connectProcess.js +4 -1
- package/src/proc/index.js +2 -0
- package/src/proc/restConnectionProcess.js +771 -0
- package/src/shell/requirePlugin.js +9 -3
- package/src/storageModel.js +78 -0
- package/src/utility/authProxy.js +25 -0
- package/src/utility/connectUtility.js +29 -1
- package/src/utility/crypting.js +21 -1
- package/src/utility/envtools.js +13 -2
|
@@ -16,6 +16,7 @@ const {
|
|
|
16
16
|
storageSaveDetailPermissionsDiff,
|
|
17
17
|
saveStorageTeamFilesPermissions,
|
|
18
18
|
saveStorageTeamFoldersPermissions,
|
|
19
|
+
storageSqlCommandFmt,
|
|
19
20
|
} = require('./storageDb');
|
|
20
21
|
const { hasPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
|
21
22
|
const { changeSetToSql, removeSchemaFromChangeSet } = require('dbgate-datalib');
|
|
@@ -28,9 +29,10 @@ const {
|
|
|
28
29
|
getPredefinedPermissions,
|
|
29
30
|
runQueryOnDriver,
|
|
30
31
|
safeJsonParse,
|
|
32
|
+
extractErrorLogData,
|
|
31
33
|
} = require('dbgate-tools');
|
|
32
34
|
const socket = require('../utility/socket');
|
|
33
|
-
const { obtainRefreshedLicense } = require('../utility/authProxy');
|
|
35
|
+
const { obtainRefreshedLicense, sendEmailViaApi } = require('../utility/authProxy');
|
|
34
36
|
const { datadir } = require('../utility/directories');
|
|
35
37
|
const {
|
|
36
38
|
loadEncryptionKeyFromExternal,
|
|
@@ -43,6 +45,7 @@ const dataReplicator = require('../shell/dataReplicator');
|
|
|
43
45
|
const storageReplicatorItems = require('../utility/storageReplicatorItems');
|
|
44
46
|
const { sendToAuditLog } = require('../utility/auditlog');
|
|
45
47
|
const { extractImportEntitiesFromEnv, createStorageFromEnvReplicatorItems } = require('../utility/envtools');
|
|
48
|
+
const { format } = require('date-fns');
|
|
46
49
|
|
|
47
50
|
const logger = getLogger('storage');
|
|
48
51
|
|
|
@@ -1150,4 +1153,133 @@ module.exports = {
|
|
|
1150
1153
|
});
|
|
1151
1154
|
socket.emitChanged('connection-list-changed');
|
|
1152
1155
|
},
|
|
1156
|
+
|
|
1157
|
+
requestPasswordReset_meta: true,
|
|
1158
|
+
async requestPasswordReset({ email }, req) {
|
|
1159
|
+
// Check if user exists with this email
|
|
1160
|
+
const users = await storageSelectFmt('select * from ~users where ~email = %v', email);
|
|
1161
|
+
|
|
1162
|
+
if (users.length === 0) {
|
|
1163
|
+
// Don't reveal whether user exists or not for security reasons
|
|
1164
|
+
return { success: true };
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
const user = users[0];
|
|
1168
|
+
|
|
1169
|
+
// Generate a secure random token
|
|
1170
|
+
const token = crypto.randomBytes(32).toString('hex');
|
|
1171
|
+
const now = new Date();
|
|
1172
|
+
const expiresAt = new Date(now.getTime() + 60 * 60 * 1000); // 1 hour expiry
|
|
1173
|
+
|
|
1174
|
+
// Store token in database
|
|
1175
|
+
await storageSqlCommandFmt(
|
|
1176
|
+
'insert into ~user_password_reset_tokens (~user_id, ~token, ~created_at, ~expires_at) values (%v, %v, %v, %v)',
|
|
1177
|
+
user.id,
|
|
1178
|
+
token,
|
|
1179
|
+
format(now, "yyyy-MM-dd'T'HH:mm:ss"),
|
|
1180
|
+
format(expiresAt, "yyyy-MM-dd'T'HH:mm:ss")
|
|
1181
|
+
);
|
|
1182
|
+
|
|
1183
|
+
// Generate reset link
|
|
1184
|
+
const resetUrl = `${req.headers.origin || 'http://localhost:3000'}/reset-password.html?token=${token}`;
|
|
1185
|
+
|
|
1186
|
+
// Send email via api.dbgate.io
|
|
1187
|
+
try {
|
|
1188
|
+
await sendEmailViaApi({
|
|
1189
|
+
receiver: email,
|
|
1190
|
+
subject: 'DbGate Password Reset',
|
|
1191
|
+
body: `
|
|
1192
|
+
Hello,
|
|
1193
|
+
|
|
1194
|
+
You requested a password reset for your DbGate account.
|
|
1195
|
+
|
|
1196
|
+
Click the following link to reset your password:
|
|
1197
|
+
${resetUrl}
|
|
1198
|
+
|
|
1199
|
+
This link will expire in 1 hour.
|
|
1200
|
+
|
|
1201
|
+
If you did not request this password reset, please ignore this email.
|
|
1202
|
+
|
|
1203
|
+
Best regards,
|
|
1204
|
+
DbGate Team
|
|
1205
|
+
`.trim(),
|
|
1206
|
+
});
|
|
1207
|
+
|
|
1208
|
+
sendToAuditLog(req, {
|
|
1209
|
+
category: 'auth',
|
|
1210
|
+
component: 'StorageController',
|
|
1211
|
+
action: 'requestPasswordReset',
|
|
1212
|
+
event: 'password.resetRequested',
|
|
1213
|
+
severity: 'info',
|
|
1214
|
+
detail: { email },
|
|
1215
|
+
message: 'Password reset requested',
|
|
1216
|
+
});
|
|
1217
|
+
} catch (err) {
|
|
1218
|
+
logger.error(extractErrorLogData(err), 'DBGM-00270 Failed to send password reset email');
|
|
1219
|
+
// Cleanup: delete the password reset token that was inserted before sending the email
|
|
1220
|
+
try {
|
|
1221
|
+
await storageSqlCommandFmt(
|
|
1222
|
+
'delete from ~user_password_reset_tokens where ~token = %v and ~used_at is null',
|
|
1223
|
+
token
|
|
1224
|
+
);
|
|
1225
|
+
} catch (cleanupErr) {
|
|
1226
|
+
logger.error(
|
|
1227
|
+
extractErrorLogData(cleanupErr),
|
|
1228
|
+
'DBGM-00274 Failed to clean up password reset token after email failure'
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
return { error: 'Failed to send email' };
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
return { success: true };
|
|
1235
|
+
},
|
|
1236
|
+
|
|
1237
|
+
resetPassword_meta: true,
|
|
1238
|
+
async resetPassword({ token, newPassword }, req) {
|
|
1239
|
+
// Find valid token
|
|
1240
|
+
const tokens = await storageSelectFmt(
|
|
1241
|
+
'select * from ~user_password_reset_tokens where ~token = %v and ~used_at is null and ~expires_at > %v',
|
|
1242
|
+
token,
|
|
1243
|
+
format(new Date(), "yyyy-MM-dd'T'HH:mm:ss")
|
|
1244
|
+
);
|
|
1245
|
+
|
|
1246
|
+
if (tokens.length === 0) {
|
|
1247
|
+
return { error: 'Invalid or expired token' };
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
const resetToken = tokens[0];
|
|
1251
|
+
|
|
1252
|
+
// Get user
|
|
1253
|
+
const users = await storageSelectFmt('select * from ~users where ~id = %v', resetToken.user_id);
|
|
1254
|
+
if (users.length === 0) {
|
|
1255
|
+
return { error: 'User not found' };
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
const user = users[0];
|
|
1259
|
+
|
|
1260
|
+
await storageSqlCommandFmt(
|
|
1261
|
+
'update ~users set ~password = %v where ~id = %v',
|
|
1262
|
+
encryptPasswordString(newPassword),
|
|
1263
|
+
user.id
|
|
1264
|
+
);
|
|
1265
|
+
|
|
1266
|
+
// Mark token as used
|
|
1267
|
+
await storageSqlCommandFmt(
|
|
1268
|
+
'update ~user_password_reset_tokens set ~used_at = %v where ~id = %v',
|
|
1269
|
+
format(new Date(), "yyyy-MM-dd'T'HH:mm:ss"),
|
|
1270
|
+
resetToken.id
|
|
1271
|
+
);
|
|
1272
|
+
|
|
1273
|
+
sendToAuditLog(req, {
|
|
1274
|
+
category: 'auth',
|
|
1275
|
+
component: 'StorageController',
|
|
1276
|
+
action: 'resetPassword',
|
|
1277
|
+
event: 'password.resetCompleted',
|
|
1278
|
+
severity: 'info',
|
|
1279
|
+
detail: { userId: user.id, login: user.login },
|
|
1280
|
+
message: 'Password reset completed',
|
|
1281
|
+
});
|
|
1282
|
+
|
|
1283
|
+
return { success: true };
|
|
1284
|
+
},
|
|
1153
1285
|
};
|
package/src/currentVersion.js
CHANGED
package/src/main.js
CHANGED
|
@@ -14,6 +14,7 @@ const socket = require('./utility/socket');
|
|
|
14
14
|
const connections = require('./controllers/connections');
|
|
15
15
|
const serverConnections = require('./controllers/serverConnections');
|
|
16
16
|
const databaseConnections = require('./controllers/databaseConnections');
|
|
17
|
+
const restConnections = require('./controllers/restConnections');
|
|
17
18
|
const metadata = require('./controllers/metadata');
|
|
18
19
|
const sessions = require('./controllers/sessions');
|
|
19
20
|
const runners = require('./controllers/runners');
|
|
@@ -267,6 +268,7 @@ function useAllControllers(app, electron) {
|
|
|
267
268
|
useController(app, electron, '/auth', auth);
|
|
268
269
|
useController(app, electron, '/cloud', cloud);
|
|
269
270
|
useController(app, electron, '/team-files', teamFiles);
|
|
271
|
+
useController(app, electron, '/rest-connections', restConnections);
|
|
270
272
|
}
|
|
271
273
|
|
|
272
274
|
function setElectronSender(electronSender) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const childProcessChecker = require('../utility/childProcessChecker');
|
|
2
2
|
const requireEngineDriver = require('../utility/requireEngineDriver');
|
|
3
|
-
const { connectUtility } = require('../utility/connectUtility');
|
|
3
|
+
const { connectUtility, getRestAuthFromConnection } = require('../utility/connectUtility');
|
|
4
4
|
const { handleProcessCommunication } = require('../utility/processComm');
|
|
5
5
|
const { pickSafeConnectionInfo } = require('../utility/crypting');
|
|
6
6
|
const _ = require('lodash');
|
|
@@ -29,6 +29,9 @@ function start() {
|
|
|
29
29
|
try {
|
|
30
30
|
const driver = requireEngineDriver(connection);
|
|
31
31
|
const connectionChanged = driver?.beforeConnectionSave ? driver.beforeConnectionSave(connection) : connection;
|
|
32
|
+
if (driver?.databaseEngineTypes?.includes('rest')) {
|
|
33
|
+
connectionChanged.restAuth = getRestAuthFromConnection(connection);
|
|
34
|
+
}
|
|
32
35
|
|
|
33
36
|
if (!connection.isVolatileResolved) {
|
|
34
37
|
if (connectionChanged.useRedirectDbLogin) {
|
package/src/proc/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const connectProcess = require('./connectProcess');
|
|
2
2
|
const databaseConnectionProcess = require('./databaseConnectionProcess');
|
|
3
3
|
const serverConnectionProcess = require('./serverConnectionProcess');
|
|
4
|
+
const restConnectionProcess = require('./restConnectionProcess');
|
|
4
5
|
const sessionProcess = require('./sessionProcess');
|
|
5
6
|
const jslDatastoreProcess = require('./jslDatastoreProcess');
|
|
6
7
|
const sshForwardProcess = require('./sshForwardProcess');
|
|
@@ -9,6 +10,7 @@ module.exports = {
|
|
|
9
10
|
connectProcess,
|
|
10
11
|
databaseConnectionProcess,
|
|
11
12
|
serverConnectionProcess,
|
|
13
|
+
restConnectionProcess,
|
|
12
14
|
sessionProcess,
|
|
13
15
|
jslDatastoreProcess,
|
|
14
16
|
sshForwardProcess,
|