FEATURE: Docker log-based password recovery with KEK-DEK preservation

Breaking Changes:
- Adds compromise mode to zero-trust architecture for UX
- Enables password recovery via physical Docker access

Key Features:
- 6-digit recovery codes output to Docker logs for physical access control
- Recovery DEK layer preserves user encrypted data during password reset
- Zero-trust migration path for future security upgrade
- Critical fix for password reset data loss vulnerability

Security Model:
- Physical access required (Docker logs access)
- 1-minute code expiry with 3-attempt limit
- Recovery keys stored encrypted in database
- Gradual migration path to zero-trust mode

Technical Details:
- Schema: Added recovery_dek, backup_encrypted_dek, zero_trust_mode fields
- API: New /recovery/* endpoints for recovery flow
- UI: Complete password recovery interface redesign
- Crypto: Recovery layer in KEK-DEK architecture
- Migration: ZeroTrustMigration utility for future upgrades

Bug Fixes:
- Fixed critical password reset vulnerability causing permanent data loss
- Fixed JWT token storage inconsistency in recovery login
- Proper KEK-DEK re-encryption during password reset
This commit is contained in:
ZacharyZcR
2025-09-26 15:37:56 +08:00
parent 158e805e04
commit 5c7145ca8e
7 changed files with 1036 additions and 9 deletions

View File

@@ -1552,6 +1552,49 @@ export async function getUserCount(): Promise<UserCount> {
}
}
// ===== New Recovery API functions (UX compromise) =====
export async function requestRecoveryCode(username: string): Promise<any> {
try {
const response = await authApi.post("/users/recovery/request", { username });
return response.data;
} catch (error) {
handleApiError(error, "request recovery code");
}
}
export async function verifyRecoveryCode(
username: string,
code: string,
): Promise<any> {
try {
const response = await authApi.post("/users/recovery/verify", {
username,
code,
});
return response.data;
} catch (error) {
handleApiError(error, "verify recovery code");
}
}
export async function loginWithRecovery(
username: string,
tempToken: string,
): Promise<any> {
try {
const response = await authApi.post("/users/recovery/login", {
username,
tempToken,
});
return response.data;
} catch (error) {
handleApiError(error, "recovery login");
}
}
// ===== Legacy password reset functions (deprecated) =====
export async function initiatePasswordReset(username: string): Promise<any> {
try {
const response = await authApi.post("/users/initiate-reset", { username });