diff --git a/app/(main)/[locale]/login/page.tsx b/app/(main)/[locale]/login/page.tsx index 77f3cd78..fbddc90e 100644 --- a/app/(main)/[locale]/login/page.tsx +++ b/app/(main)/[locale]/login/page.tsx @@ -133,7 +133,7 @@ export default function LoginPage() { const isMobileHandoff = Boolean(mobileRedirectUri); const { login, loginDemo, isLoading, error, clearError, isAuthenticated } = useAuthStore(); const { theme, setTheme, initializeTheme } = useThemeStore(useShallow((s) => ({ theme: s.theme, setTheme: s.setTheme, initializeTheme: s.initializeTheme }))); - const { appName, jmapServerUrl: configuredServerUrl, oauthEnabled, oauthOnly, oauthClientId: globalOauthClientId, oauthIssuerUrl: globalOauthIssuerUrl, oauthScopes, rememberMeEnabled, devMode, demoMode, loginLogoLightUrl, loginLogoDarkUrl, loginCompanyName, loginImprintUrl, loginPrivacyPolicyUrl, loginWebsiteUrl, loginLogoMaxHeight, loginLogoMaxWidth, loginShowHeading, loginShowSubtitle, isLoading: configLoading, error: configError, autoSsoEnabled, embeddedMode: _embeddedMode, allowCustomJmapEndpoint, jmapServers, jmapServerAutoPickByDomain } = useConfig(); + const { appName, jmapServerUrl: configuredServerUrl, oauthEnabled, oauthOnly, oauthClientId: globalOauthClientId, oauthIssuerUrl: globalOauthIssuerUrl, oauthScopes, rememberMeEnabled, devMode, demoMode, loginLogoLightUrl, loginLogoDarkUrl, loginCompanyName, loginImprintUrl, loginPrivacyPolicyUrl, loginWebsiteUrl, loginLogoMaxHeight, loginLogoMaxWidth, loginShowHeading, loginShowSubtitle, loginShowTotp, loginShowVersion, isLoading: configLoading, error: configError, autoSsoEnabled, embeddedMode: _embeddedMode, allowCustomJmapEndpoint, jmapServers, jmapServerAutoPickByDomain } = useConfig(); const resolvedTheme = useThemeStore((s) => s.resolvedTheme); // Login logo sizing: when a max height/width is configured, drop the fixed @@ -822,7 +822,7 @@ export default function LoginPage() { )} )} - + {loginShowVersion && } @@ -1154,8 +1154,12 @@ export default function LoginPage() { - {/* 2FA toggle / field */} + {/* 2FA toggle / field. The manual toggle can be hidden via + LOGIN_SHOW_TOTP (loginShowTotp) for deployments whose mail + server has no per-account TOTP (auth delegated to an + external directory); server-required TOTP still shows. */} {!showTotpField ? ( + loginShowTotp ? ( + ) : null ) : (
)} - + {loginShowVersion && } diff --git a/app/api/config/route.ts b/app/api/config/route.ts index d9a7efd7..bf86013f 100644 --- a/app/api/config/route.ts +++ b/app/api/config/route.ts @@ -78,6 +78,8 @@ export async function GET(request: NextRequest) { loginLogoMaxWidth: configManager.get('loginLogoMaxWidth', ''), loginShowHeading: configManager.get('loginShowHeading', true), loginShowSubtitle: configManager.get('loginShowSubtitle', true), + loginShowTotp: configManager.get('loginShowTotp', true), + loginShowVersion: configManager.get('loginShowVersion', true), demoMode: configManager.get('demoMode', false), allowCustomJmapEndpoint: configManager.get('allowCustomJmapEndpoint', false), jmapServers: redactJmapServers(parseJmapServers(configManager.get('jmapServers', []))), diff --git a/hooks/use-config.ts b/hooks/use-config.ts index ccb52394..f18c10ee 100644 --- a/hooks/use-config.ts +++ b/hooks/use-config.ts @@ -30,6 +30,8 @@ interface ConfigData { loginLogoMaxWidth: string; loginShowHeading: boolean; loginShowSubtitle: boolean; + loginShowTotp: boolean; + loginShowVersion: boolean; demoMode: boolean; autoSsoEnabled: boolean; allowCustomJmapEndpoint: boolean; @@ -113,6 +115,8 @@ export function useConfig(): AppConfig { loginLogoMaxWidth: configCache?.loginLogoMaxWidth || '', loginShowHeading: configCache?.loginShowHeading ?? true, loginShowSubtitle: configCache?.loginShowSubtitle ?? true, + loginShowTotp: configCache?.loginShowTotp ?? true, + loginShowVersion: configCache?.loginShowVersion ?? true, demoMode: configCache?.demoMode || false, autoSsoEnabled: configCache?.autoSsoEnabled || false, allowCustomJmapEndpoint: configCache?.allowCustomJmapEndpoint || false, @@ -152,6 +156,8 @@ export function useConfig(): AppConfig { loginLogoMaxWidth: configCache.loginLogoMaxWidth, loginShowHeading: configCache.loginShowHeading, loginShowSubtitle: configCache.loginShowSubtitle, + loginShowTotp: configCache.loginShowTotp, + loginShowVersion: configCache.loginShowVersion, demoMode: configCache.demoMode, autoSsoEnabled: configCache.autoSsoEnabled, allowCustomJmapEndpoint: configCache.allowCustomJmapEndpoint, @@ -192,6 +198,8 @@ export function useConfig(): AppConfig { loginLogoMaxWidth: data.loginLogoMaxWidth, loginShowHeading: data.loginShowHeading, loginShowSubtitle: data.loginShowSubtitle, + loginShowTotp: data.loginShowTotp, + loginShowVersion: data.loginShowVersion, demoMode: data.demoMode, autoSsoEnabled: data.autoSsoEnabled, allowCustomJmapEndpoint: data.allowCustomJmapEndpoint, diff --git a/lib/admin/types.ts b/lib/admin/types.ts index fd315d5b..b02a687d 100644 --- a/lib/admin/types.ts +++ b/lib/admin/types.ts @@ -178,6 +178,14 @@ export const CONFIG_ENV_MAP: Record