Harden 2FA disable and website icon privacy

This commit is contained in:
shuaiplus
2026-07-06 18:45:54 +08:00
parent 5c8f01be59
commit c6438747e3
10 changed files with 52 additions and 18 deletions
+15 -2
View File
@@ -27,6 +27,7 @@ import {
unlockOfflineVaultWithMasterKey,
} from '@/lib/offline-auth';
import { probeNodeWardenService } from '@/lib/network-status';
import { setWebsiteIconsEnabled } from '@/lib/website-icon-settings';
import type { AccountPasskeyPrfOption, AppPhase, Profile, SessionState, TokenSuccess, WebBootstrapResponse } from '@/lib/types';
export interface PendingTotp {
@@ -51,6 +52,7 @@ export type JwtUnsafeReason = 'missing' | 'too_short';
export interface BootstrapAppResult {
defaultKdfIterations: number;
registrationInviteRequired?: boolean;
websiteIconsEnabled: boolean;
jwtWarning: { reason: JwtUnsafeReason; minLength: number } | null;
session: SessionState | null;
profile: Profile | null;
@@ -61,6 +63,7 @@ export interface BootstrapAppResult {
export interface InitialAppBootstrapState {
defaultKdfIterations: number;
registrationInviteRequired?: boolean;
websiteIconsEnabled: boolean;
jwtWarning: { reason: JwtUnsafeReason; minLength: number } | null;
session: SessionState | null;
phase: AppPhase;
@@ -229,10 +232,11 @@ function readWindowBootstrap(): WebBootstrapResponse {
return raw && typeof raw === 'object' ? raw : {};
}
function normalizeBootstrapResponse(boot: WebBootstrapResponse): Pick<InitialAppBootstrapState, 'defaultKdfIterations' | 'registrationInviteRequired' | 'jwtWarning'> {
function normalizeBootstrapResponse(boot: WebBootstrapResponse): Pick<InitialAppBootstrapState, 'defaultKdfIterations' | 'registrationInviteRequired' | 'websiteIconsEnabled' | 'jwtWarning'> {
const defaultKdfIterations = Number(boot.defaultKdfIterations || 600000);
const registrationInviteRequired =
typeof boot.registrationInviteRequired === 'boolean' ? boot.registrationInviteRequired : undefined;
const websiteIconsEnabled = boot.websiteIconsEnabled === true;
const jwtUnsafeReason = boot.jwtUnsafeReason || null;
const jwtWarning = jwtUnsafeReason
? {
@@ -244,6 +248,7 @@ function normalizeBootstrapResponse(boot: WebBootstrapResponse): Pick<InitialApp
return {
defaultKdfIterations,
registrationInviteRequired,
websiteIconsEnabled,
jwtWarning,
};
}
@@ -304,7 +309,8 @@ function resolveUnauthenticatedPhase(registrationInviteRequired: boolean | undef
}
export function readInitialAppBootstrapState(): InitialAppBootstrapState {
const { defaultKdfIterations, registrationInviteRequired, jwtWarning } = normalizeBootstrapResponse(readWindowBootstrap());
const { defaultKdfIterations, registrationInviteRequired, websiteIconsEnabled, jwtWarning } = normalizeBootstrapResponse(readWindowBootstrap());
setWebsiteIconsEnabled(websiteIconsEnabled);
const session = loadSession();
const hasInviteCode = !!readInviteCodeFromUrl();
const unauthenticatedPhase = hasInviteCode ? 'register' : 'login';
@@ -312,6 +318,7 @@ export function readInitialAppBootstrapState(): InitialAppBootstrapState {
return {
defaultKdfIterations,
registrationInviteRequired,
websiteIconsEnabled,
jwtWarning,
session,
phase: jwtWarning ? 'login' : session ? 'locked' : resolveUnauthenticatedPhase(registrationInviteRequired, unauthenticatedPhase),
@@ -323,12 +330,15 @@ export async function bootstrapAppSession(initial: InitialAppBootstrapState = re
const normalizedBoot = normalizeBootstrapResponse(remoteBoot);
const defaultKdfIterations = normalizedBoot.defaultKdfIterations || initial.defaultKdfIterations;
const registrationInviteRequired = normalizedBoot.registrationInviteRequired ?? initial.registrationInviteRequired;
const websiteIconsEnabled = normalizedBoot.websiteIconsEnabled;
setWebsiteIconsEnabled(websiteIconsEnabled);
const jwtWarning = normalizedBoot.jwtWarning ?? initial.jwtWarning;
if (jwtWarning) {
return {
defaultKdfIterations,
registrationInviteRequired,
websiteIconsEnabled,
jwtWarning,
session: null,
profile: null,
@@ -341,6 +351,7 @@ export async function bootstrapAppSession(initial: InitialAppBootstrapState = re
return {
defaultKdfIterations,
registrationInviteRequired,
websiteIconsEnabled,
jwtWarning: null,
session: null,
profile: null,
@@ -353,6 +364,7 @@ export async function bootstrapAppSession(initial: InitialAppBootstrapState = re
return {
defaultKdfIterations,
registrationInviteRequired,
websiteIconsEnabled,
jwtWarning: null,
session: loaded,
profile: cachedProfile,
@@ -364,6 +376,7 @@ export async function bootstrapAppSession(initial: InitialAppBootstrapState = re
return {
defaultKdfIterations,
registrationInviteRequired,
websiteIconsEnabled,
jwtWarning: null,
session: loaded,
profile: null,