diff --git a/src/backend/database/routes/users.ts b/src/backend/database/routes/users.ts index 7ad84061..11d600f6 100644 --- a/src/backend/database/routes/users.ts +++ b/src/backend/database/routes/users.ts @@ -1317,19 +1317,15 @@ router.post("/complete-reset", async (req, res) => { .where(eq(users.username, username)); try { - // Check if user has an active session with DEK (logged in while resetting) const hasActiveSession = authManager.isUserUnlocked(userId); if (hasActiveSession) { - // User is logged in - preserve their data by keeping the same DEK - // This happens when user resets password from settings page const success = await authManager.resetUserPasswordWithPreservedDEK( userId, newPassword, ); if (!success) { - // If preservation fails, fall back to new DEK (will lose data) authLogger.warn( `Failed to preserve DEK during password reset for ${username}. Creating new DEK - data will be lost.`, { @@ -1351,7 +1347,6 @@ router.post("/complete-reset", async (req, res) => { ); } } else { - // User is NOT logged in - create new DEK (data will be inaccessible) await authManager.registerUser(userId, newPassword); authManager.logoutUser(userId); @@ -2049,7 +2044,6 @@ router.post("/change-password", authenticateJWT, async (req, res) => { .set({ password_hash: newPasswordHash }) .where(eq(users.id, userId)); - // Trigger database save to persist password hash const { saveMemoryDatabaseToFile } = await import("../db/index.js"); await saveMemoryDatabaseToFile(); diff --git a/src/backend/utils/user-crypto.ts b/src/backend/utils/user-crypto.ts index 0d4393b2..8e12778d 100644 --- a/src/backend/utils/user-crypto.ts +++ b/src/backend/utils/user-crypto.ts @@ -249,7 +249,6 @@ class UserCrypto { newPassword: string, ): Promise { try { - // Validate current password const isValid = await this.validatePassword(userId, oldPassword); if (!isValid) return false; @@ -260,35 +259,24 @@ class UserCrypto { const encryptedDEK = await this.getEncryptedDEK(userId); if (!encryptedDEK) return false; - // Decrypt DEK with old password's KEK const DEK = this.decryptDEK(encryptedDEK, oldKEK); - // The DEK stays the same - only the KEK changes with the new password - // This preserves all encrypted user data - - // Generate new KEK from new password const newKekSalt = await this.generateKEKSalt(); const newKEK = this.deriveKEK(newPassword, newKekSalt); - // Re-encrypt the same DEK with new KEK const newEncryptedDEK = this.encryptDEK(DEK, newKEK); - // Store new KEK salt and new encrypted DEK await this.storeKEKSalt(userId, newKekSalt); await this.storeEncryptedDEK(userId, newEncryptedDEK); - // Trigger database save to persist the encryption key changes const { saveMemoryDatabaseToFile } = await import("../database/db/index.js"); await saveMemoryDatabaseToFile(); - // Clean up sensitive data from memory oldKEK.fill(0); newKEK.fill(0); - // Create a copy of DEK for the session before zeroing it out const dekCopy = Buffer.from(DEK); - // Keep user session active with the same DEK const now = Date.now(); const oldSession = this.userSessions.get(userId); if (oldSession) { @@ -301,7 +289,6 @@ class UserCrypto { expiresAt: now + UserCrypto.SESSION_DURATION, }); - // Zero out the original DEK from memory DEK.fill(0); return true; @@ -320,36 +307,26 @@ class UserCrypto { newPassword: string, ): Promise { try { - // This method preserves the existing DEK by re-encrypting it with the new password - // Used for password reset when user is logged in - - // Check if user has an active session with DEK const existingDEK = this.getUserDataKey(userId); if (!existingDEK) { return false; } - // Generate new KEK from new password const newKekSalt = await this.generateKEKSalt(); const newKEK = this.deriveKEK(newPassword, newKekSalt); - // Re-encrypt the existing DEK with new KEK const newEncryptedDEK = this.encryptDEK(existingDEK, newKEK); - // Store new KEK salt and new encrypted DEK await this.storeKEKSalt(userId, newKekSalt); await this.storeEncryptedDEK(userId, newEncryptedDEK); - // Trigger database save to persist the encryption key changes const { saveMemoryDatabaseToFile } = await import( "../database/db/index.js" ); await saveMemoryDatabaseToFile(); - // Clean up sensitive data newKEK.fill(0); - // Update session activity timestamp const session = this.userSessions.get(userId); if (session) { session.lastActivity = Date.now();