fix: address security issue

This commit is contained in:
shuaiplus
2026-06-24 01:44:50 +08:00
committed by Shuai
parent 5048cc0720
commit 7279668955
24 changed files with 613 additions and 114 deletions
+20 -7
View File
@@ -66,6 +66,12 @@ export interface CompletedLogin {
session: SessionState;
profile: Profile;
profilePromise: Promise<Profile>;
freshMasterPasswordHash?: string | null;
freshUserVerificationToken?: string | null;
}
function readTokenUserVerificationToken(token: TokenSuccess): string | null {
return String(token.UserVerificationToken || token.userVerificationToken || '').trim() || null;
}
export type PasswordLoginResult =
@@ -319,7 +325,8 @@ export async function completeLogin(
token: TokenSuccess,
email: string,
masterKey: Uint8Array,
fallbackKdfIterations: number
fallbackKdfIterations: number,
freshMasterPasswordHash?: string | null
): Promise<CompletedLogin> {
const normalizedEmail = email.trim().toLowerCase();
const fallbackProfile = loadProfileSnapshot(normalizedEmail);
@@ -348,6 +355,8 @@ export async function completeLogin(
session: { ...baseSession, ...keys },
profile,
profilePromise: getProfile(tempFetch),
freshMasterPasswordHash: freshMasterPasswordHash || null,
freshUserVerificationToken: readTokenUserVerificationToken(token),
};
}
@@ -360,7 +369,8 @@ async function completeLoginWithVaultKeys(
token: TokenSuccess,
email: string,
keys: { symEncKey: string; symMacKey: string },
fallbackKdfIterations: number
fallbackKdfIterations: number,
freshMasterPasswordHash?: string | null
): Promise<CompletedLogin> {
const normalizedEmail = email.trim().toLowerCase();
const fallbackProfile = loadProfileSnapshot(normalizedEmail);
@@ -385,6 +395,8 @@ async function completeLoginWithVaultKeys(
session: { ...baseSession, ...keys },
profile,
profilePromise: getProfile(tempFetch),
freshMasterPasswordHash: freshMasterPasswordHash || null,
freshUserVerificationToken: readTokenUserVerificationToken(token),
};
}
@@ -400,7 +412,7 @@ export async function performPasswordLogin(
if ('access_token' in token && token.access_token) {
return {
kind: 'success',
login: await completeLogin(token, normalizedEmail, derived.masterKey, derived.kdfIterations),
login: await completeLogin(token, normalizedEmail, derived.masterKey, derived.kdfIterations, derived.hash),
};
}
@@ -476,7 +488,7 @@ export async function completePasskeyPasswordLogin(
password: string
): Promise<CompletedLogin> {
const derived = await deriveLoginHashLocally(pending.email, password, pending.kdfIterations);
return completeLogin(pending.token, pending.email, derived.masterKey, pending.kdfIterations);
return completeLogin(pending.token, pending.email, derived.masterKey, pending.kdfIterations, derived.hash);
}
export async function performTotpLogin(
@@ -489,7 +501,7 @@ export async function performTotpLogin(
rememberDevice,
});
if ('access_token' in token && token.access_token) {
return completeLogin(token, pendingTotp.email, pendingTotp.masterKey, pendingTotp.kdfIterations);
return completeLogin(token, pendingTotp.email, pendingTotp.masterKey, pendingTotp.kdfIterations, pendingTotp.passwordHash);
}
const tokenError = token as { error_description?: string; error?: string };
throw new Error(translateServerError(tokenError.error_description || tokenError.error, t('txt_totp_verify_failed')));
@@ -508,7 +520,7 @@ export async function performRecoverTwoFactorLogin(
if ('access_token' in token && token.access_token) {
return {
login: await completeLogin(token, normalizedEmail, derived.masterKey, derived.kdfIterations),
login: await completeLogin(token, normalizedEmail, derived.masterKey, derived.kdfIterations, derived.hash),
newRecoveryCode: recovered.newRecoveryCode || null,
};
}
@@ -557,6 +569,7 @@ export async function performUnlock(
session: offline.session,
profile: offline.profile,
profilePromise: Promise.resolve(offline.profile),
freshMasterPasswordHash: null,
},
};
} catch {
@@ -589,7 +602,7 @@ export async function performUnlock(
if ('access_token' in token && token.access_token) {
return {
kind: 'success',
login: await completeLogin(token, normalizedEmail, derived.masterKey, derived.kdfIterations),
login: await completeLogin(token, normalizedEmail, derived.masterKey, derived.kdfIterations, derived.hash),
};
}