feat: add master password hint functionality

- Updated user model to include masterPasswordHint.
- Modified sync handler to return masterPasswordHint.
- Implemented password hint retrieval in public API.
- Enhanced user profile management to allow updating of password hint.
- Added UI components for displaying and editing password hint.
- Updated localization files for new password hint strings.
- Improved rate limiting for sensitive public requests.
- Adjusted database schema to accommodate master password hint.
This commit is contained in:
shuaiplus
2026-03-19 00:38:56 +08:00
parent 8bc43b8f0c
commit facd0ea5f7
26 changed files with 460 additions and 26 deletions
@@ -9,6 +9,7 @@ import {
revokeAuthorizedDeviceTrust,
revokeAllAuthorizedDeviceTrust,
setTotp,
updateProfile,
} from '@/lib/api/auth';
import { t } from '@/lib/i18n';
import type { AppConfirmState } from '@/components/AppGlobalOverlays';
@@ -25,6 +26,7 @@ interface UseAccountSecurityActionsOptions {
clearDisableTotpDialog: () => void;
onLogoutNow: () => void;
onNotify: Notify;
onProfileUpdated: (profile: Profile) => void;
onSetConfirm: (next: AppConfirmState | null) => void;
refetchTotpStatus: () => Promise<unknown>;
refetchAuthorizedDevices: () => Promise<unknown>;
@@ -39,6 +41,7 @@ export default function useAccountSecurityActions(options: UseAccountSecurityAct
clearDisableTotpDialog,
onLogoutNow,
onNotify,
onProfileUpdated,
onSetConfirm,
refetchTotpStatus,
refetchAuthorizedDevices,
@@ -85,6 +88,22 @@ export default function useAccountSecurityActions(options: UseAccountSecurityAct
});
},
async savePasswordHint(masterPasswordHint: string) {
if (!profile) return;
const normalized = String(masterPasswordHint || '').trim();
if (normalized.length > 120) {
onNotify('error', t('txt_password_hint_too_long'));
return;
}
try {
const nextProfile = await updateProfile(authedFetch, { masterPasswordHint: normalized });
onProfileUpdated(nextProfile);
onNotify('success', t('txt_profile_updated'));
} catch (error) {
onNotify('error', error instanceof Error ? error.message : t('txt_save_profile_failed'));
}
},
async enableTotp(secret: string, token: string) {
if (!secret.trim() || !token.trim()) {
const error = new Error(t('txt_secret_and_code_are_required'));
@@ -208,6 +227,7 @@ export default function useAccountSecurityActions(options: UseAccountSecurityAct
disableTotpPassword,
onLogoutNow,
onNotify,
onProfileUpdated,
onSetConfirm,
profile,
refetchAuthorizedDevices,