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