diff --git a/status/js/auth-gate.js b/status/js/auth-gate.js index b1ddd47..4f1c84e 100644 --- a/status/js/auth-gate.js +++ b/status/js/auth-gate.js @@ -189,20 +189,57 @@ const providers = await fetchMethods(); if (providers.length === 0) { - // Either the endpoint isn't reachable OR only TOTP is enabled (which - // isEnabled() returns false until set up). Either way, fall back to - // the legacy TOTP overlay — existing totp-auth.js handles it. + // Either the endpoint isn't reachable OR no provider reports enabled. + // Fall back to the legacy TOTP overlay — existing totp-auth.js handles it. if (typeof window._showTotpOverlay === 'function') window._showTotpOverlay(); return; } if (providers.length === 1 && providers[0].name === 'totp') { - // Single TOTP provider → show the original TOTP overlay unchanged - if (typeof window._showTotpOverlay === 'function') window._showTotpOverlay(); + // Single TOTP provider → show the original TOTP overlay unchanged, + // but with an "Or sign in with email" link below so the email path + // is reachable as the recovery / phone-friendly alternative. Most + // users still want their primary method (TOTP) front-and-center. + showTotpWithEmailFallback(providers[0]); return; } showProviderSelector(providers); } + function showTotpWithEmailFallback(totpProvider) { + const emailEnabled = methodsCache && methodsCache.find(p => p.name === 'email'); + if (!emailEnabled) { + // Truly single-provider path: legacy TOTP overlay, no alt link. + if (typeof window._showTotpOverlay === 'function') window._showTotpOverlay(); + return; + } + const overlay = document.getElementById('totp-overlay'); + const card = overlay.querySelector('.totp-card'); + if (!card) return; + + // Save the original TOTP markup so we can restore on alt-link click off. + if (!card.dataset.originalBody) card.dataset.originalBody = card.innerHTML; + + // Add a small "or" link at the bottom of the existing card WITHOUT + // touching the TOTP input markup — keeps totp-auth.js's submitTotpCode + // binding intact. + let alt = card.querySelector('#auth-gate-email-alt'); + if (!alt) { + const div = document.createElement('div'); + div.id = 'auth-gate-email-alt'; + div.style.cssText = 'margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border); font-size: 0.85rem;'; + div.innerHTML = ` + Or sign in with email instead → + `; + card.appendChild(div); + div.querySelector('#auth-gate-email-alt-link').addEventListener('click', e => { + e.preventDefault(); + renderProviderChallenge(emailEnabled); + }); + } + overlay.classList.add('show'); + } + // ---- Trigger points ---- // 1. SSO redirect from Caddy: ?auth=required // We claim ownership here (set window.__dc_049_handled = true)