diff --git a/app/(main)/[locale]/layout.tsx b/app/(main)/[locale]/layout.tsx index 76f9396ad..a44a30286 100644 --- a/app/(main)/[locale]/layout.tsx +++ b/app/(main)/[locale]/layout.tsx @@ -11,6 +11,7 @@ import { ProInterfaceRedirect } from "@/components/pro/pro-interface-redirect"; import { ImpersonationReconciler } from "@/components/impersonation/impersonation-reconciler"; import { PluginDialogHost } from "@/components/plugins/plugin-dialog-host"; import { CommandPaletteHost } from "@/components/command-palette/command-palette"; +import { TotpReauthDialog } from "@/components/totp-reauth-dialog"; import { PluginConnectDialog } from "@/components/plugins/plugin-connect-dialog"; import { QuickRuleHost } from "@/components/filters/quick-rule-host"; import { PluginConsentDialog } from "@/components/plugins/plugin-consent-dialog"; @@ -64,6 +65,7 @@ export default async function LocaleLayout({ {children} + diff --git a/components/__tests__/totp-reauth-dialog.test.tsx b/components/__tests__/totp-reauth-dialog.test.tsx new file mode 100644 index 000000000..fb45b3b64 --- /dev/null +++ b/components/__tests__/totp-reauth-dialog.test.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; + +// The 2FA re-auth prompt opens in whichever app made the request (it is +// mounted in the locale layout, not inside mail) and is translated. + +vi.mock('next-intl/server', () => ({ setRequestLocale: vi.fn() })); + +const { TotpReauthDialog } = await import('../totp-reauth-dialog'); +const { useTotpReauthStore } = await import('@/stores/totp-reauth-store'); + +function containsType(node: unknown, type: unknown): boolean { + if (!node || typeof node !== 'object') return false; + if (Array.isArray(node)) return node.some((child) => containsType(child, type)); + const el = node as { type?: unknown; props?: { children?: unknown } }; + if (el.type === type) return true; + return containsType(el.props?.children, type); +} + +describe('TOTP re-auth dialog', () => { + it('is mounted in the locale layout, so every app can show it', async () => { + const { default: LocaleLayout } = await import('@/app/(main)/[locale]/layout'); + const tree = await LocaleLayout({ children: null, params: Promise.resolve({ locale: 'en' }) }); + expect(containsType(tree, TotpReauthDialog)).toBe(true); + }, 120_000); + + it('asks in the user language and hands the code back', async () => { + render(); + let answer: Promise = Promise.resolve(null); + act(() => { answer = useTotpReauthStore.getState().requestTotp(); }); + + expect(screen.getByRole('dialog', { name: 'title' })).toBeInTheDocument(); + const field = screen.getByRole('textbox', { name: 'code_label' }); + expect(field).toHaveFocus(); + fireEvent.change(field, { target: { value: '123456' } }); + act(() => { fireEvent.click(screen.getByRole('button', { name: 'verify' })); }); + await expect(answer).resolves.toBe('123456'); + expect(screen.queryByRole('dialog')).toBeNull(); + }); +}); diff --git a/components/mail/mail-app.tsx b/components/mail/mail-app.tsx index 46bfa3c5a..22682245f 100644 --- a/components/mail/mail-app.tsx +++ b/components/mail/mail-app.tsx @@ -81,7 +81,6 @@ import { } from "@/components/error"; import { ConfirmDialog } from "@/components/ui/confirm-dialog"; import { PromptDialog } from "@/components/ui/prompt-dialog"; -import { TotpReauthDialog } from "@/components/totp-reauth-dialog"; import { DragDropProvider } from "@/contexts/drag-drop-context"; import { jmapErrorType } from "@/lib/jmap/jmap-error"; import { isFilterEmpty, activeFilterCount, DEFAULT_SEARCH_FILTERS } from "@/lib/jmap/search-utils"; @@ -5588,7 +5587,6 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) { )} - {floatingComposer && {composerNode}} diff --git a/components/totp-reauth-dialog.tsx b/components/totp-reauth-dialog.tsx index 51a3958dc..7b4d45e1b 100644 --- a/components/totp-reauth-dialog.tsx +++ b/components/totp-reauth-dialog.tsx @@ -1,107 +1,79 @@ "use client"; import { useState, useEffect, useRef } from "react"; -import { useFocusTrap } from "@/hooks/use-focus-trap"; +import { useTranslations } from "next-intl"; import { useTotpReauthStore } from "@/stores/totp-reauth-store"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; +import { Dialog } from "@/components/ui/dialog"; import { Shield } from "@/components/icons"; /** - * Modal dialog that prompts the user for a fresh TOTP code when their - * 2FA session expires (TOTP rotates every ~30 seconds). + * Asks for a fresh TOTP code when a 2FA session expires (TOTP rotates every + * ~30 seconds). * - * Rendered once at the app root level. The JMAP client triggers it via - * the useTotpReauthStore when a 401 is received on a TOTP-authenticated session. + * Mounted once in the locale layout, so the prompt opens in whichever app + * made the request. The JMAP client opens it through useTotpReauthStore + * when a 401 comes back on a TOTP-authenticated session. */ export function TotpReauthDialog() { + const t = useTranslations("totp_reauth"); + const tCommon = useTranslations("common"); const { isOpen, submit, cancel } = useTotpReauthStore(); const [code, setCode] = useState(""); const inputRef = useRef(null); - const dialogRef = useFocusTrap({ - isActive: isOpen, - onEscape: cancel, - restoreFocus: true, - }); - useEffect(() => { - if (isOpen) { - setCode(""); - setTimeout(() => inputRef.current?.focus(), 50); - } + if (isOpen) setCode(""); }, [isOpen]); - if (!isOpen) return null; - const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - if (code.length >= 6) { - submit(code); - } + if (code.length >= 6) submit(code); }; return ( -
-
-
-
-
- -
-
-

Session Expired

-

Your 2FA code has rotated

-
+ +
- -

- Enter a fresh authentication code from your authenticator app to continue. -

- -

- To avoid being prompted repeatedly, ask your administrator to enable OAuth authentication - (either Stalwart's built-in OAuth or an external identity provider). -

- -
- setCode(e.target.value.replace(/\D/g, ''))} - className="h-12 text-center font-mono tracking-widest text-lg bg-muted/40 border-border/60 rounded-xl focus:bg-background focus:border-primary/50 transition-all duration-200" - placeholder="000000" - autoComplete="one-time-code" - aria-label="Authentication code" - /> -
- - -
-
-
-
+ } + size="sm" + showClose={false} + dirty={code.length > 0} + initialFocus={inputRef} + onSubmit={handleSubmit} + footer={ + <> + + + + } + > +

+ {t("oauth_hint")} +

+ setCode(e.target.value.replace(/\D/g, ""))} + className="h-12 text-center font-mono tracking-widest text-lg" + placeholder="000000" + autoComplete="one-time-code" + aria-label={t("code_label")} + /> + ); } diff --git a/locales/ar/common.json b/locales/ar/common.json index f302c0a3a..691b31dc5 100644 --- a/locales/ar/common.json +++ b/locales/ar/common.json @@ -76,6 +76,13 @@ "back_to_login": "العودة إلى تسجيل الدخول" } }, + "totp_reauth": { + "title": "انتهت الجلسة", + "description": "تغيّر رمز المصادقة الثنائية. أدخل رمزًا جديدًا من تطبيق المصادقة للمتابعة.", + "oauth_hint": "لكي لا تظهر هذه المطالبة مجددًا، اطلب من المسؤول تفعيل تسجيل الدخول عبر OAuth (خدمة OAuth المدمجة في Stalwart أو موفّر هوية خارجي).", + "code_label": "رمز المصادقة", + "verify": "تحقّق" + }, "sidebar": { "close": "إغلاق", "compose": "إنشاء رسالة", diff --git a/locales/ca/common.json b/locales/ca/common.json index c74f3a6e6..3620809c7 100644 --- a/locales/ca/common.json +++ b/locales/ca/common.json @@ -76,6 +76,13 @@ "back_to_login": "Torna a l'inici de sessió" } }, + "totp_reauth": { + "title": "La sessió ha caducat", + "description": "El codi de doble factor ha canviat. Introduïu un codi nou de l'aplicació d'autenticació per continuar.", + "oauth_hint": "Perquè aquest avís no torni a aparèixer, demaneu a l'administrador que activi l'inici de sessió amb OAuth (l'OAuth integrat de Stalwart o un proveïdor d'identitat extern).", + "code_label": "Codi d'autenticació", + "verify": "Verifica" + }, "sidebar": { "close": "Tanca", "compose": "Redacta", diff --git a/locales/cs/common.json b/locales/cs/common.json index 04311030b..2b9719d6b 100644 --- a/locales/cs/common.json +++ b/locales/cs/common.json @@ -76,6 +76,13 @@ "back_to_login": "Zpět na přihlášení" } }, + "totp_reauth": { + "title": "Relace vypršela", + "description": "Váš dvoufázový kód se změnil. Pro pokračování zadejte nový kód z ověřovací aplikace.", + "oauth_hint": "Aby se tato výzva neopakovala, požádejte správce o zapnutí přihlašování přes OAuth (vestavěné OAuth ve Stalwartu nebo externího poskytovatele identity).", + "code_label": "Ověřovací kód", + "verify": "Ověřit" + }, "sidebar": { "close": "Zavřít", "compose": "Napsat", diff --git a/locales/da/common.json b/locales/da/common.json index 517caa46f..2abefd24f 100644 --- a/locales/da/common.json +++ b/locales/da/common.json @@ -76,6 +76,13 @@ "back_to_login": "Tilbage til login" } }, + "totp_reauth": { + "title": "Sessionen er udløbet", + "description": "Din tofaktorkode er ændret. Indtast en ny kode fra din godkendelsesapp for at fortsætte.", + "oauth_hint": "Bed din administrator om at slå login med OAuth til (Stalwarts indbyggede OAuth eller en ekstern identitetsudbyder), så du ikke bliver spurgt igen.", + "code_label": "Godkendelseskode", + "verify": "Bekræft" + }, "sidebar": { "close": "Luk", "compose": "Ny besked", diff --git a/locales/de/common.json b/locales/de/common.json index 141274200..b1c39a1cf 100644 --- a/locales/de/common.json +++ b/locales/de/common.json @@ -76,6 +76,13 @@ "back_to_login": "Zurück zur Anmeldung" } }, + "totp_reauth": { + "title": "Sitzung abgelaufen", + "description": "Ihr Zwei-Faktor-Code hat sich geändert. Geben Sie einen neuen Code aus Ihrer Authenticator-App ein, um fortzufahren.", + "oauth_hint": "Damit diese Abfrage nicht wiederkommt, bitten Sie Ihre Administration, die Anmeldung über OAuth einzuschalten (das integrierte OAuth von Stalwart oder einen externen Identitätsanbieter).", + "code_label": "Authentifizierungscode", + "verify": "Bestätigen" + }, "sidebar": { "close": "Schließen", "compose": "Verfassen", diff --git a/locales/en/common.json b/locales/en/common.json index e25ebab8b..486064e82 100644 --- a/locales/en/common.json +++ b/locales/en/common.json @@ -76,6 +76,13 @@ "back_to_login": "Back to login" } }, + "totp_reauth": { + "title": "Session expired", + "description": "Your two-factor code has changed. Enter a new code from your authenticator app to continue.", + "oauth_hint": "To stop this prompt from coming back, ask your administrator to turn on OAuth sign-in (Stalwart's built-in OAuth or an external identity provider).", + "code_label": "Authentication code", + "verify": "Verify" + }, "sidebar": { "close": "Close", "compose": "Compose", diff --git a/locales/es/common.json b/locales/es/common.json index 5dd4f01d5..36451b967 100644 --- a/locales/es/common.json +++ b/locales/es/common.json @@ -76,6 +76,13 @@ "back_to_login": "Volver al inicio de sesión" } }, + "totp_reauth": { + "title": "La sesión ha caducado", + "description": "Tu código de doble factor ha cambiado. Introduce un código nuevo de tu aplicación de autenticación para continuar.", + "oauth_hint": "Para que este aviso no vuelva a aparecer, pide a tu administrador que active el inicio de sesión con OAuth (el OAuth integrado de Stalwart o un proveedor de identidad externo).", + "code_label": "Código de autenticación", + "verify": "Verificar" + }, "sidebar": { "close": "Cerrar", "compose": "Redactar", diff --git a/locales/et/common.json b/locales/et/common.json index 36cbb878a..a8bd12a62 100644 --- a/locales/et/common.json +++ b/locales/et/common.json @@ -76,6 +76,13 @@ "back_to_login": "Tagasi" } }, + "totp_reauth": { + "title": "Seanss on aegunud", + "description": "Teie kaheastmelise tuvastuse kood on muutunud. Jätkamiseks sisestage autentimisrakendusest uus kood.", + "oauth_hint": "Et see küsimus ei korduks, paluge administraatoril lülitada sisse OAuth-sisselogimine (Stalwarti sisseehitatud OAuth või väline identiteedipakkuja).", + "code_label": "Autentimiskood", + "verify": "Kinnita" + }, "sidebar": { "close": "Sulge", "compose": "Koosta", diff --git a/locales/fa/common.json b/locales/fa/common.json index 09ab7af4f..e5c0151bf 100644 --- a/locales/fa/common.json +++ b/locales/fa/common.json @@ -76,6 +76,13 @@ "back_to_login": "بازگشت به صفحه ورود" } }, + "totp_reauth": { + "title": "نشست منقضی شد", + "description": "کد احراز هویت دومرحله‌ای شما تغییر کرده است. برای ادامه، کد جدیدی از برنامهٔ احراز هویت وارد کنید.", + "oauth_hint": "برای اینکه این درخواست دوباره نمایش داده نشود، از مدیر بخواهید ورود با OAuth را فعال کند (OAuth داخلی Stalwart یا یک ارائه‌دهندهٔ هویت خارجی).", + "code_label": "کد احراز هویت", + "verify": "تأیید" + }, "sidebar": { "close": "بستن", "compose": "ایمیل جدید", diff --git a/locales/fr/common.json b/locales/fr/common.json index 8be4a0523..42fdc729d 100644 --- a/locales/fr/common.json +++ b/locales/fr/common.json @@ -76,6 +76,13 @@ "back_to_login": "Retour à la connexion" } }, + "totp_reauth": { + "title": "Session expirée", + "description": "Votre code à deux facteurs a changé. Saisissez un nouveau code de votre application d'authentification pour continuer.", + "oauth_hint": "Pour ne plus voir cette demande, demandez à votre administrateur d'activer la connexion OAuth (l'OAuth intégré de Stalwart ou un fournisseur d'identité externe).", + "code_label": "Code d'authentification", + "verify": "Vérifier" + }, "sidebar": { "close": "Fermer", "compose": "Composer", diff --git a/locales/he/common.json b/locales/he/common.json index 9ad7d19ef..bc339c75a 100644 --- a/locales/he/common.json +++ b/locales/he/common.json @@ -75,6 +75,13 @@ "jmap_server_label": "שרת", "jmap_server_auto_picked": "שרת שנבחר מדומיין הדוא״ל שלך." }, + "totp_reauth": { + "title": "פג תוקף ההפעלה", + "description": "קוד האימות הדו-שלבי השתנה. כדי להמשיך, הזינו קוד חדש מאפליקציית האימות.", + "oauth_hint": "כדי שהבקשה הזו לא תחזור, בקשו מהמנהל להפעיל כניסה עם OAuth (ה-OAuth המובנה של Stalwart או ספק זהויות חיצוני).", + "code_label": "קוד אימות", + "verify": "אימות" + }, "sidebar": { "unified_mailbox": "תיבת דואר מאוחדת", "close": "סגור", diff --git a/locales/hu/common.json b/locales/hu/common.json index 758e15995..9753edd6e 100644 --- a/locales/hu/common.json +++ b/locales/hu/common.json @@ -76,6 +76,13 @@ "back_to_login": "Vissza a bejelentkezéshez" } }, + "totp_reauth": { + "title": "A munkamenet lejárt", + "description": "A kétlépcsős kód megváltozott. A folytatáshoz adjon meg egy új kódot a hitelesítő alkalmazásból.", + "oauth_hint": "Hogy ez a kérés ne jelenjen meg újra, kérje meg a rendszergazdát, hogy kapcsolja be az OAuth-bejelentkezést (a Stalwart beépített OAuth-ját vagy egy külső identitásszolgáltatót).", + "code_label": "Hitelesítő kód", + "verify": "Ellenőrzés" + }, "sidebar": { "close": "Bezárás", "compose": "Új levél", diff --git a/locales/it/common.json b/locales/it/common.json index cb2f68866..37be7eab2 100644 --- a/locales/it/common.json +++ b/locales/it/common.json @@ -76,6 +76,13 @@ "back_to_login": "Torna al login" } }, + "totp_reauth": { + "title": "Sessione scaduta", + "description": "Il codice a due fattori è cambiato. Inserisci un nuovo codice dall'app di autenticazione per continuare.", + "oauth_hint": "Per non ricevere più questa richiesta, chiedi all'amministratore di attivare l'accesso con OAuth (l'OAuth integrato di Stalwart o un provider di identità esterno).", + "code_label": "Codice di autenticazione", + "verify": "Verifica" + }, "sidebar": { "close": "Chiudi", "compose": "Scrivi", diff --git a/locales/ja/common.json b/locales/ja/common.json index a7a76b7bb..86a57673b 100644 --- a/locales/ja/common.json +++ b/locales/ja/common.json @@ -76,6 +76,13 @@ "back_to_login": "ログインに戻る" } }, + "totp_reauth": { + "title": "セッションの有効期限が切れました", + "description": "2 段階認証コードが変わりました。続けるには、認証アプリの新しいコードを入力してください。", + "oauth_hint": "この確認を繰り返さないようにするには、OAuth によるサインイン(Stalwart の組み込み OAuth または外部の ID プロバイダー)を有効にするよう管理者に依頼してください。", + "code_label": "認証コード", + "verify": "確認" + }, "sidebar": { "close": "閉じる", "compose": "作成", diff --git a/locales/ko/common.json b/locales/ko/common.json index 432de0376..21b3fcf13 100644 --- a/locales/ko/common.json +++ b/locales/ko/common.json @@ -76,6 +76,13 @@ "back_to_login": "로그인 화면으로 돌아가기" } }, + "totp_reauth": { + "title": "세션이 만료되었습니다", + "description": "2단계 인증 코드가 바뀌었습니다. 계속하려면 인증 앱의 새 코드를 입력하세요.", + "oauth_hint": "이 요청이 다시 나타나지 않게 하려면 관리자에게 OAuth 로그인(Stalwart 내장 OAuth 또는 외부 ID 공급자)을 켜 달라고 요청하세요.", + "code_label": "인증 코드", + "verify": "확인" + }, "sidebar": { "close": "닫기", "compose": "메일 쓰기", diff --git a/locales/lv/common.json b/locales/lv/common.json index be3aa7cb9..daf206341 100644 --- a/locales/lv/common.json +++ b/locales/lv/common.json @@ -76,6 +76,13 @@ "back_to_login": "Atgriezties pie pierakstīšanās" } }, + "totp_reauth": { + "title": "Sesija ir beigusies", + "description": "Jūsu divfaktoru kods ir mainījies. Lai turpinātu, ievadiet jaunu kodu no autentifikācijas lietotnes.", + "oauth_hint": "Lai šis pieprasījums vairs neparādītos, lūdziet administratoram ieslēgt pieteikšanos ar OAuth (Stalwart iebūvēto OAuth vai ārēju identitātes nodrošinātāju).", + "code_label": "Autentifikācijas kods", + "verify": "Apstiprināt" + }, "sidebar": { "close": "Aizvērt", "compose": "Rakstīt", diff --git a/locales/mn/common.json b/locales/mn/common.json index 3ac66f6cb..ecca7cdce 100644 --- a/locales/mn/common.json +++ b/locales/mn/common.json @@ -76,6 +76,13 @@ "back_to_login": "Нэвтрэх рүү буцах" } }, + "totp_reauth": { + "title": "Сесс дууссан", + "description": "Таны хоёр шатлалт кодыг сольсон байна. Үргэлжлүүлэхийн тулд баталгаажуулах аппаас шинэ код оруулна уу.", + "oauth_hint": "Энэ хүсэлт дахин гарахгүй байлгахын тулд админаас OAuth нэвтрэлтийг (Stalwart-ын суурилуулсан OAuth эсвэл гадны таних үйлчилгээ) асаахыг хүснэ үү.", + "code_label": "Баталгаажуулах код", + "verify": "Баталгаажуулах" + }, "sidebar": { "close": "Хаах", "compose": "Бичилэх", diff --git a/locales/nb/common.json b/locales/nb/common.json index bce385f8e..224084986 100644 --- a/locales/nb/common.json +++ b/locales/nb/common.json @@ -76,6 +76,13 @@ "back_to_login": "Tilbake til pålogging" } }, + "totp_reauth": { + "title": "Økten er utløpt", + "description": "Tofaktorkoden din er endret. Skriv inn en ny kode fra autentiseringsappen for å fortsette.", + "oauth_hint": "Be administratoren om å slå på pålogging med OAuth (Stalwarts innebygde OAuth eller en ekstern identitetsleverandør), så slipper du denne forespørselen.", + "code_label": "Autentiseringskode", + "verify": "Bekreft" + }, "sidebar": { "close": "Lukk", "compose": "Skriv", diff --git a/locales/nl/common.json b/locales/nl/common.json index 5b111f177..28dea6ba8 100644 --- a/locales/nl/common.json +++ b/locales/nl/common.json @@ -76,6 +76,13 @@ "back_to_login": "Terug naar inloggen" } }, + "totp_reauth": { + "title": "Sessie verlopen", + "description": "Je tweestapscode is veranderd. Voer een nieuwe code uit je authenticator-app in om door te gaan.", + "oauth_hint": "Vraag je beheerder om aanmelden via OAuth aan te zetten (de ingebouwde OAuth van Stalwart of een externe identiteitsprovider), dan krijg je deze vraag niet meer.", + "code_label": "Verificatiecode", + "verify": "Bevestigen" + }, "sidebar": { "close": "Sluiten", "compose": "Nieuw bericht", diff --git a/locales/pl/common.json b/locales/pl/common.json index 079d25f31..40806f3d4 100644 --- a/locales/pl/common.json +++ b/locales/pl/common.json @@ -76,6 +76,13 @@ "back_to_login": "Powrót do logowania" } }, + "totp_reauth": { + "title": "Sesja wygasła", + "description": "Twój kod dwuskładnikowy się zmienił. Aby kontynuować, wpisz nowy kod z aplikacji uwierzytelniającej.", + "oauth_hint": "Aby ta prośba się nie powtarzała, poproś administratora o włączenie logowania przez OAuth (wbudowany OAuth w Stalwart lub zewnętrzny dostawca tożsamości).", + "code_label": "Kod uwierzytelniający", + "verify": "Zweryfikuj" + }, "sidebar": { "close": "Zamknij", "compose": "Napisz", diff --git a/locales/pt/common.json b/locales/pt/common.json index 38fcaf6d8..fe8cab340 100644 --- a/locales/pt/common.json +++ b/locales/pt/common.json @@ -76,6 +76,13 @@ "back_to_login": "Voltar ao login" } }, + "totp_reauth": { + "title": "Sessão expirada", + "description": "O seu código de dois fatores mudou. Introduza um código novo da aplicação de autenticação para continuar.", + "oauth_hint": "Para deixar de ver este pedido, peça ao administrador que ative o início de sessão com OAuth (o OAuth integrado do Stalwart ou um fornecedor de identidade externo).", + "code_label": "Código de autenticação", + "verify": "Verificar" + }, "sidebar": { "close": "Fechar", "compose": "Escrever", diff --git a/locales/ro/common.json b/locales/ro/common.json index 88868221f..9d5783f49 100644 --- a/locales/ro/common.json +++ b/locales/ro/common.json @@ -76,6 +76,13 @@ "back_to_login": "Înapoi la autentificare" } }, + "totp_reauth": { + "title": "Sesiunea a expirat", + "description": "Codul de autentificare în doi pași s-a schimbat. Introduceți un cod nou din aplicația de autentificare pentru a continua.", + "oauth_hint": "Ca această solicitare să nu mai apară, cereți administratorului să activeze conectarea prin OAuth (OAuth-ul integrat în Stalwart sau un furnizor de identitate extern).", + "code_label": "Cod de autentificare", + "verify": "Verifică" + }, "sidebar": { "close": "Închide", "compose": "Compune", diff --git a/locales/ru/common.json b/locales/ru/common.json index 63eafde10..a0a88227b 100644 --- a/locales/ru/common.json +++ b/locales/ru/common.json @@ -76,6 +76,13 @@ "back_to_login": "Вернуться ко входу" } }, + "totp_reauth": { + "title": "Сеанс истёк", + "description": "Код двухфакторной аутентификации сменился. Чтобы продолжить, введите новый код из приложения-аутентификатора.", + "oauth_hint": "Чтобы этот запрос больше не появлялся, попросите администратора включить вход через OAuth (встроенный OAuth Stalwart или внешний поставщик удостоверений).", + "code_label": "Код аутентификации", + "verify": "Подтвердить" + }, "sidebar": { "close": "Закрыть", "compose": "Создать", diff --git a/locales/sk/common.json b/locales/sk/common.json index 29ba9a7e2..e8c76b9b5 100644 --- a/locales/sk/common.json +++ b/locales/sk/common.json @@ -76,6 +76,13 @@ "back_to_login": "Späť na prihlásenie" } }, + "totp_reauth": { + "title": "Relácia vypršala", + "description": "Váš dvojfaktorový kód sa zmenil. Ak chcete pokračovať, zadajte nový kód z overovacej aplikácie.", + "oauth_hint": "Aby sa táto výzva neopakovala, požiadajte správcu o zapnutie prihlasovania cez OAuth (vstavané OAuth v Stalwarte alebo externého poskytovateľa identity).", + "code_label": "Overovací kód", + "verify": "Overiť" + }, "sidebar": { "unified_mailbox": "Zjednotená schránka", "close": "Zavrieť", diff --git a/locales/th/common.json b/locales/th/common.json index 8ed6ed3ef..cf468cab5 100644 --- a/locales/th/common.json +++ b/locales/th/common.json @@ -177,6 +177,13 @@ "back_to_login": "กลับไปหน้าเข้าสู่ระบบ" } }, + "totp_reauth": { + "title": "เซสชันหมดอายุ", + "description": "รหัสยืนยันตัวตนสองขั้นตอนของคุณเปลี่ยนแล้ว ป้อนรหัสใหม่จากแอปยืนยันตัวตนเพื่อดำเนินการต่อ", + "oauth_hint": "หากไม่ต้องการให้ระบบถามอีก โปรดขอให้ผู้ดูแลระบบเปิดการลงชื่อเข้าใช้ด้วย OAuth (OAuth ในตัวของ Stalwart หรือผู้ให้บริการข้อมูลประจำตัวภายนอก)", + "code_label": "รหัสยืนยันตัวตน", + "verify": "ยืนยัน" + }, "sidebar": { "close": "ปิดแถบด้านข้าง", "compose": "เขียนจดหมาย", diff --git a/locales/tr/common.json b/locales/tr/common.json index 6175b06c0..1f1fe35bc 100644 --- a/locales/tr/common.json +++ b/locales/tr/common.json @@ -76,6 +76,13 @@ "back_to_login": "Giriş sayfasına dön" } }, + "totp_reauth": { + "title": "Oturumun süresi doldu", + "description": "İki adımlı doğrulama kodunuz değişti. Devam etmek için kimlik doğrulama uygulamanızdan yeni bir kod girin.", + "oauth_hint": "Bu isteğin tekrar çıkmaması için yöneticinizden OAuth ile oturum açmayı (Stalwart'ın yerleşik OAuth'u veya harici bir kimlik sağlayıcı) açmasını isteyin.", + "code_label": "Doğrulama kodu", + "verify": "Doğrula" + }, "sidebar": { "close": "Kapat", "compose": "Yeni E-posta", diff --git a/locales/uk/common.json b/locales/uk/common.json index b6c42bf7c..f27652d00 100644 --- a/locales/uk/common.json +++ b/locales/uk/common.json @@ -76,6 +76,13 @@ "back_to_login": "Назад до входу" } }, + "totp_reauth": { + "title": "Сеанс завершився", + "description": "Код двофакторної автентифікації змінився. Щоб продовжити, введіть новий код із застосунку автентифікації.", + "oauth_hint": "Щоб цей запит більше не з'являвся, попросіть адміністратора ввімкнути вхід через OAuth (вбудований OAuth Stalwart або зовнішнього постачальника ідентичності).", + "code_label": "Код автентифікації", + "verify": "Підтвердити" + }, "sidebar": { "close": "Закрити", "compose": "Скласти", diff --git a/locales/zh-TW/common.json b/locales/zh-TW/common.json index 3c122fa20..b81169291 100644 --- a/locales/zh-TW/common.json +++ b/locales/zh-TW/common.json @@ -76,6 +76,13 @@ "back_to_login": "返回登入頁面" } }, + "totp_reauth": { + "title": "工作階段已過期", + "description": "您的雙重驗證碼已變更。請輸入驗證器應用程式中的新驗證碼以繼續。", + "oauth_hint": "若不想再看到此提示,請請管理員啟用 OAuth 登入(Stalwart 內建的 OAuth 或外部身分提供者)。", + "code_label": "驗證碼", + "verify": "驗證" + }, "sidebar": { "close": "關閉", "compose": "撰寫郵件", diff --git a/locales/zh/common.json b/locales/zh/common.json index 890c771e7..c1f8ef6ea 100644 --- a/locales/zh/common.json +++ b/locales/zh/common.json @@ -76,6 +76,13 @@ "back_to_login": "返回登录" } }, + "totp_reauth": { + "title": "会话已过期", + "description": "您的两步验证码已更新。请输入身份验证器应用中的新验证码以继续。", + "oauth_hint": "如不想再看到此提示,请让管理员启用 OAuth 登录(Stalwart 内置的 OAuth 或外部身份提供商)。", + "code_label": "验证码", + "verify": "验证" + }, "sidebar": { "close": "关闭", "compose": "撰写邮件",