mirror of
https://github.com/root-fr/jmap-webmail.git
synced 2026-09-26 00:01:19 +00:00
fix(oauth): fail with a clear message when SSO is loaded over plain HTTP
OAuth2/OIDC with PKCE needs crypto.subtle.digest(), which browsers only expose in secure contexts (HTTPS or localhost). Loading the webmail over http://host without a TLS proxy in front surfaced as "TypeError: can't access property 'digest', crypto.subtle is undefined" when the user clicked "Sign in with SSO" — unhelpful. Guard handleOAuthLogin with window.isSecureContext + a crypto.subtle check and surface a translated message ("SSO requires a secure connection…") in an amber warning banner instead. Key added to all 10 locales. Closes #23.
This commit is contained in:
@@ -40,6 +40,7 @@ export default function LoginPage() {
|
||||
const [oauthDiscoveryDone, setOauthDiscoveryDone] = useState(false);
|
||||
const [oauthLoading, setOauthLoading] = useState(false);
|
||||
const [oauthRetryCount, setOauthRetryCount] = useState(0);
|
||||
const [oauthLocalError, setOauthLocalError] = useState<string | null>(null);
|
||||
|
||||
const suggestionsRef = useRef<HTMLDivElement>(null);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
@@ -256,6 +257,17 @@ export default function LoginPage() {
|
||||
|
||||
const handleOAuthLogin = async () => {
|
||||
if (!oauthMetadata || !oauthClientId) return;
|
||||
|
||||
// PKCE needs Web Crypto (SubtleCrypto.digest). That API is only exposed
|
||||
// in secure contexts — i.e. HTTPS or localhost. Fail loudly before we
|
||||
// try to call it so the user sees a fix-this message instead of a
|
||||
// mystery "crypto.subtle is undefined" TypeError.
|
||||
if (typeof window === "undefined" || !window.isSecureContext || typeof crypto?.subtle?.digest !== "function") {
|
||||
setOauthLocalError(t("oauth_error.requires_https"));
|
||||
return;
|
||||
}
|
||||
|
||||
setOauthLocalError(null);
|
||||
setOauthLoading(true);
|
||||
|
||||
const verifier = generateCodeVerifier();
|
||||
@@ -344,6 +356,13 @@ export default function LoginPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{oauthLocalError && (
|
||||
<div className="mb-6 p-4 bg-amber-500/10 border border-amber-500/20 rounded-lg flex items-start gap-3">
|
||||
<AlertCircle className="w-5 h-5 text-amber-600 dark:text-amber-400 flex-shrink-0 mt-0.5" />
|
||||
<p className="text-sm text-amber-700 dark:text-amber-300">{oauthLocalError}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Login Form */}
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
"missing_params": "Fehlende Autorisierungsdaten. Bitte erneut anmelden.",
|
||||
"token_exchange_failed": "Authentifizierung konnte nicht abgeschlossen werden. Bitte erneut versuchen.",
|
||||
"access_denied": "Zugriff verweigert. Bitte kontaktieren Sie Ihren Administrator.",
|
||||
"back_to_login": "Zurück zur Anmeldung"
|
||||
"back_to_login": "Zurück zur Anmeldung",
|
||||
"requires_https": "Single Sign-On erfordert eine sichere Verbindung. Bitte greifen Sie über HTTPS auf dieses Webmail zu (oder localhost in der Entwicklung)."
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
"missing_params": "Missing authorization data. Please try signing in again.",
|
||||
"token_exchange_failed": "Failed to complete authentication. Please try again.",
|
||||
"access_denied": "Access was denied. Please contact your administrator.",
|
||||
"back_to_login": "Back to login"
|
||||
"back_to_login": "Back to login",
|
||||
"requires_https": "Single Sign-On requires a secure connection. Please access this webmail over HTTPS (or localhost during development)."
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
"missing_params": "Faltan datos de autorización. Intenta iniciar sesión de nuevo.",
|
||||
"token_exchange_failed": "No se pudo completar la autenticación. Inténtalo de nuevo.",
|
||||
"access_denied": "Acceso denegado. Contacta a tu administrador.",
|
||||
"back_to_login": "Volver al inicio de sesión"
|
||||
"back_to_login": "Volver al inicio de sesión",
|
||||
"requires_https": "El inicio de sesión único requiere una conexión segura. Accede a este correo web por HTTPS (o localhost en desarrollo)."
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
"missing_params": "Données d'autorisation manquantes. Veuillez réessayer.",
|
||||
"token_exchange_failed": "Impossible de finaliser l'authentification. Veuillez réessayer.",
|
||||
"access_denied": "L'accès a été refusé. Veuillez contacter votre administrateur.",
|
||||
"back_to_login": "Retour à la connexion"
|
||||
"back_to_login": "Retour à la connexion",
|
||||
"requires_https": "L'authentification SSO nécessite une connexion sécurisée. Accédez à ce webmail via HTTPS (ou localhost en développement)."
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
"missing_params": "Dati di autorizzazione mancanti. Prova ad accedere di nuovo.",
|
||||
"token_exchange_failed": "Impossibile completare l'autenticazione. Riprova.",
|
||||
"access_denied": "Accesso negato. Contatta il tuo amministratore.",
|
||||
"back_to_login": "Torna al login"
|
||||
"back_to_login": "Torna al login",
|
||||
"requires_https": "Il Single Sign-On richiede una connessione sicura. Accedi a questa webmail tramite HTTPS (o localhost in sviluppo)."
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
"missing_params": "認証データが不足しています。再度サインインしてください。",
|
||||
"token_exchange_failed": "認証を完了できませんでした。再度お試しください。",
|
||||
"access_denied": "アクセスが拒否されました。管理者にお問い合わせください。",
|
||||
"back_to_login": "ログインに戻る"
|
||||
"back_to_login": "ログインに戻る",
|
||||
"requires_https": "シングルサインオンには安全な接続が必要です。HTTPS(または開発時は localhost)でこのウェブメールにアクセスしてください。"
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
"missing_params": "Ontbrekende autorisatiegegevens. Probeer opnieuw in te loggen.",
|
||||
"token_exchange_failed": "Authenticatie kon niet worden voltooid. Probeer het opnieuw.",
|
||||
"access_denied": "Toegang geweigerd. Neem contact op met uw beheerder.",
|
||||
"back_to_login": "Terug naar inloggen"
|
||||
"back_to_login": "Terug naar inloggen",
|
||||
"requires_https": "Single Sign-On vereist een beveiligde verbinding. Open deze webmail via HTTPS (of localhost tijdens de ontwikkeling)."
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
"missing_params": "Dados de autorização ausentes. Tente entrar novamente.",
|
||||
"token_exchange_failed": "Não foi possível concluir a autenticação. Tente novamente.",
|
||||
"access_denied": "Acesso negado. Entre em contato com seu administrador.",
|
||||
"back_to_login": "Voltar ao login"
|
||||
"back_to_login": "Voltar ao login",
|
||||
"requires_https": "O Single Sign-On requer uma ligação segura. Aceda a este webmail através de HTTPS (ou localhost em desenvolvimento)."
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
"missing_params": "Отсутствуют данные авторизации. Пожалуйста, попробуйте войти еще раз.",
|
||||
"token_exchange_failed": "Не удалось завершить аутентификацию. Пожалуйста, попробуйте еще раз.",
|
||||
"access_denied": "Доступ был запрещен. Пожалуйста, свяжитесь с вашим администратором.",
|
||||
"back_to_login": "Вернуться к входу"
|
||||
"back_to_login": "Вернуться к входу",
|
||||
"requires_https": "Единый вход требует защищенного соединения. Откройте этот веб-клиент почты по HTTPS (или localhost при разработке)."
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
"missing_params": "Відсутні дані авторизації. Спробуйте ввійти знову.",
|
||||
"token_exchange_failed": "Не вдалося завершити автентифікацію. Спробуйте ще раз.",
|
||||
"access_denied": "У доступі відмовлено. Будь ласка, зверніться до свого адміністратора.",
|
||||
"back_to_login": "Назад до входу"
|
||||
"back_to_login": "Назад до входу",
|
||||
"requires_https": "Єдиний вхід потребує захищеного з'єднання. Відкрийте цей вебклієнт пошти через HTTPS (або localhost під час розробки)."
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
|
||||
Reference in New Issue
Block a user