feat: 2FAのバックアップコードの実装 (#121)

This commit is contained in:
まっちゃとーにゅ 2023-07-30 03:35:42 +09:00 committed by GitHub
parent 99232ed417
commit 2b941ae648
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 91 additions and 32 deletions

View file

@ -1255,7 +1255,7 @@ _2fa:
step1: "أولًا ثبّت تطبيق استيثاق على جهازك (مثل {a} و{b})." step1: "أولًا ثبّت تطبيق استيثاق على جهازك (مثل {a} و{b})."
step2: "امسح رمز الاستجابة السريعة الموجد على الشاشة." step2: "امسح رمز الاستجابة السريعة الموجد على الشاشة."
step3: "أدخل الرمز الموجود في تطبيقك لإكمال التثبيت." step3: "أدخل الرمز الموجود في تطبيقك لإكمال التثبيت."
step4: "من هذه اللحظة أثناء ولوجك سيُطلب منك الرمز." step4: "من هذه اللحظة أثناء ولوجك سيُطلب منك الرمز.\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
renewTOTPCancel: "ليس اﻵن" renewTOTPCancel: "ليس اﻵن"
_permissions: _permissions:
"read:account": "اعرض معلومات حسابك" "read:account": "اعرض معلومات حسابك"

View file

@ -1042,7 +1042,7 @@ _2fa:
step2: "এরপরে, অ্যাপের সাহায্যে প্রদর্শিত QR কোডটি স্ক্যান করুন।" step2: "এরপরে, অ্যাপের সাহায্যে প্রদর্শিত QR কোডটি স্ক্যান করুন।"
step2Url: "ডেস্কটপ অ্যাপে, নিম্নলিখিত URL লিখুন:" step2Url: "ডেস্কটপ অ্যাপে, নিম্নলিখিত URL লিখুন:"
step3: "অ্যাপে প্রদর্শিত টোকেনটি লিখুন এবং আপনার কাজ শেষ।" step3: "অ্যাপে প্রদর্শিত টোকেনটি লিখুন এবং আপনার কাজ শেষ।"
step4: "আপনাকে এখন থেকে লগ ইন করার সময়, এইভাবে টোকেন লিখতে হবে।" step4: "আপনাকে এখন থেকে লগ ইন করার সময়, এইভাবে টোকেন লিখতে হবে।\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
securityKeyInfo: "আপনি একটি হার্ডওয়্যার সিকিউরিটি কী ব্যবহার করে লগ ইন করতে পারেন যা FIDO2 বা ডিভাইসের ফিঙ্গারপ্রিন্ট সেন্সর বা পিন সমর্থন করে৷" securityKeyInfo: "আপনি একটি হার্ডওয়্যার সিকিউরিটি কী ব্যবহার করে লগ ইন করতে পারেন যা FIDO2 বা ডিভাইসের ফিঙ্গারপ্রিন্ট সেন্সর বা পিন সমর্থন করে৷"
_permissions: _permissions:
"read:account": "অ্যাকাউন্টের তথ্য দেখুন" "read:account": "অ্যাকাউন্টের তথ্য দেখুন"

View file

@ -1682,7 +1682,7 @@ _2fa:
step2Url: "Nutzt du ein Desktopprogramm kannst du alternativ diese URL eingeben:" step2Url: "Nutzt du ein Desktopprogramm kannst du alternativ diese URL eingeben:"
step3Title: "Authentifizierungsscode eingeben" step3Title: "Authentifizierungsscode eingeben"
step3: "Gib zum Abschluss den Token ein, der von deiner App angezeigt wird." step3: "Gib zum Abschluss den Token ein, der von deiner App angezeigt wird."
step4: "Alle folgenden Anmeldeversuche werden ab sofort die Eingabe eines solchen Tokens benötigen." step4: "Alle folgenden Anmeldeversuche werden ab sofort die Eingabe eines solchen Tokens benötigen.\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
securityKeyNotSupported: "Dein Browser unterstützt keine Security-Tokens." securityKeyNotSupported: "Dein Browser unterstützt keine Security-Tokens."
registerTOTPBeforeKey: "Um einen Security-Token oder einen Passkey zu registrieren, musst du zuerst eine Authentifizierungs-App registrieren." registerTOTPBeforeKey: "Um einen Security-Token oder einen Passkey zu registrieren, musst du zuerst eine Authentifizierungs-App registrieren."
securityKeyInfo: "Du kannst neben Fingerabdruck- oder PIN-Authentifizierung auf deinem Gerät auch Anmeldung mit Hilfe eines FIDO2-kompatiblen Hardware-Sicherheitsschlüssels einrichten." securityKeyInfo: "Du kannst neben Fingerabdruck- oder PIN-Authentifizierung auf deinem Gerät auch Anmeldung mit Hilfe eines FIDO2-kompatiblen Hardware-Sicherheitsschlüssels einrichten."

View file

@ -1686,7 +1686,9 @@ _2fa:
step2Url: "You can also enter this URL if you're using a desktop program:" step2Url: "You can also enter this URL if you're using a desktop program:"
step3Title: "Enter an authentication code" step3Title: "Enter an authentication code"
step3: "Enter the token provided by your app to finish setup." step3: "Enter the token provided by your app to finish setup."
step4: "From now on, any future login attempts will ask for such a login token." step4: "From now on, any future login attempts will ask for such a login token.\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
twoFactorBackupSecretWarning: "You have used some of your backup codes. If your authentication app is no longer available, please reconfigure your authentication app as soon as possible."
twoFactorBackupSecretExhausted: "You have exhausted all your backup codes. If your authentication app is no longer available, you will not be able to access your account anymore. please reconfigure your authentication app as soon as possible."
securityKeyNotSupported: "Your browser does not support security keys." securityKeyNotSupported: "Your browser does not support security keys."
registerTOTPBeforeKey: "Please set up an authenticator app to register a security or pass key." registerTOTPBeforeKey: "Please set up an authenticator app to register a security or pass key."
securityKeyInfo: "Besides fingerprint or PIN authentication, you can also setup authentication via hardware security keys that support FIDO2 to further secure your account." securityKeyInfo: "Besides fingerprint or PIN authentication, you can also setup authentication via hardware security keys that support FIDO2 to further secure your account."
@ -1698,7 +1700,7 @@ _2fa:
removeKeyConfirm: "Really delete the {name} key?" removeKeyConfirm: "Really delete the {name} key?"
whyTOTPOnlyRenew: "The authenticator app cannot be removed as long as a security key is registered." whyTOTPOnlyRenew: "The authenticator app cannot be removed as long as a security key is registered."
renewTOTP: "Reconfigure authenticator app" renewTOTP: "Reconfigure authenticator app"
renewTOTPConfirm: "This will cause verification codes from your previous app to stop working" renewTOTPConfirm: "This will cause verification codes from your previous app and backup codes to stop working"
renewTOTPOk: "Reconfigure" renewTOTPOk: "Reconfigure"
renewTOTPCancel: "Cancel" renewTOTPCancel: "Cancel"
_permissions: _permissions:

View file

@ -1682,7 +1682,7 @@ _2fa:
step2Url: "En una aplicación de escritorio se puede ingresar la siguiente URL:" step2Url: "En una aplicación de escritorio se puede ingresar la siguiente URL:"
step3Title: "Ingresa un código de autenticación" step3Title: "Ingresa un código de autenticación"
step3: "Para terminar, ingrese el token mostrado en la aplicación." step3: "Para terminar, ingrese el token mostrado en la aplicación."
step4: "Ahora cuando inicie sesión, ingrese el mismo token" step4: "Ahora cuando inicie sesión, ingrese el mismo token\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
securityKeyNotSupported: "Tu navegador no soporta claves de autenticación." securityKeyNotSupported: "Tu navegador no soporta claves de autenticación."
registerTOTPBeforeKey: "Please set up an authenticator app to register a security or pass key.\npor favor. configura una aplicación de autenticación para registrar una llave de seguridad." registerTOTPBeforeKey: "Please set up an authenticator app to register a security or pass key.\npor favor. configura una aplicación de autenticación para registrar una llave de seguridad."
securityKeyInfo: "Se puede configurar el inicio de sesión usando una clave de seguridad de hardware que soporte FIDO2 o con un certificado de huella digital o con un PIN" securityKeyInfo: "Se puede configurar el inicio de sesión usando una clave de seguridad de hardware que soporte FIDO2 o con un certificado de huella digital o con un PIN"

View file

@ -1251,7 +1251,7 @@ _2fa:
step2: "Ensuite, scannez le code QR affiché sur lécran." step2: "Ensuite, scannez le code QR affiché sur lécran."
step2Url: "Vous pouvez également saisir cette URL si vous utilisez un programme de bureau :" step2Url: "Vous pouvez également saisir cette URL si vous utilisez un programme de bureau :"
step3: "Entrez le jeton affiché sur votre application pour compléter la configuration." step3: "Entrez le jeton affiché sur votre application pour compléter la configuration."
step4: "À partir de maintenant, ce même jeton vous sera demandé à chacune de vos connexions." step4: "À partir de maintenant, ce même jeton vous sera demandé à chacune de vos connexions.\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
securityKeyInfo: "Vous pouvez configurer l'authentification WebAuthN pour sécuriser davantage le processus de connexion grâce à une clé de sécurité matérielle qui prend en charge FIDO2, ou bien en configurant l'authentification par empreinte digitale ou par code PIN sur votre appareil." securityKeyInfo: "Vous pouvez configurer l'authentification WebAuthN pour sécuriser davantage le processus de connexion grâce à une clé de sécurité matérielle qui prend en charge FIDO2, ou bien en configurant l'authentification par empreinte digitale ou par code PIN sur votre appareil."
removeKeyConfirm: "Voulez-vous supprimer {name} ?" removeKeyConfirm: "Voulez-vous supprimer {name} ?"
renewTOTPCancel: "Pas maintenant" renewTOTPCancel: "Pas maintenant"

View file

@ -1656,7 +1656,7 @@ _2fa:
step2Url: "Di aplikasi desktop, masukkan URL berikut:" step2Url: "Di aplikasi desktop, masukkan URL berikut:"
step3Title: "Masukkan kode autentikasi" step3Title: "Masukkan kode autentikasi"
step3: "Masukkan token yang telah disediakan oleh aplikasimu untuk menyelesaikan pemasangan." step3: "Masukkan token yang telah disediakan oleh aplikasimu untuk menyelesaikan pemasangan."
step4: "Mulai sekarang, upaya login apapun akan meminta token login dari aplikasi otentikasi kamu." step4: "Mulai sekarang, upaya login apapun akan meminta token login dari aplikasi otentikasi kamu.\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
securityKeyNotSupported: "Peramban kamu tidak mendukung security key." securityKeyNotSupported: "Peramban kamu tidak mendukung security key."
registerTOTPBeforeKey: "Mohon atur aplikasi autentikator untuk mendaftarkan security key atau passkey." registerTOTPBeforeKey: "Mohon atur aplikasi autentikator untuk mendaftarkan security key atau passkey."
securityKeyInfo: "Kamu dapat memasang otentikasi WebAuthN untuk mengamankan proses login lebih lanjut dengan tidak hanya perangkat keras kunci keamanan yang mendukung FIDO2, namun juga sidik jari atau otentikasi PIN pada perangkatmu." securityKeyInfo: "Kamu dapat memasang otentikasi WebAuthN untuk mengamankan proses login lebih lanjut dengan tidak hanya perangkat keras kunci keamanan yang mendukung FIDO2, namun juga sidik jari atau otentikasi PIN pada perangkatmu."

2
locales/index.d.ts vendored
View file

@ -1804,6 +1804,8 @@ export interface Locale {
"step3Title": string; "step3Title": string;
"step3": string; "step3": string;
"step4": string; "step4": string;
"twoFactorBackupSecretWarning": string;
"twoFactorBackupSecretExhausted": string;
"securityKeyNotSupported": string; "securityKeyNotSupported": string;
"registerTOTPBeforeKey": string; "registerTOTPBeforeKey": string;
"securityKeyInfo": string; "securityKeyInfo": string;

View file

@ -1682,7 +1682,7 @@ _2fa:
step2Url: "Nell'applicazione desktop inserire il seguente URL: " step2Url: "Nell'applicazione desktop inserire il seguente URL: "
step3Title: "Inserisci il codice di verifica" step3Title: "Inserisci il codice di verifica"
step3: "Inserite il token visualizzato nell'app e il gioco è fatto." step3: "Inserite il token visualizzato nell'app e il gioco è fatto."
step4: "D'ora in poi, quando si accede, si inserisce il token nello stesso modo." step4: "D'ora in poi, quando si accede, si inserisce il token nello stesso modo.\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
securityKeyNotSupported: "Il tuo browser non supporta le chiavi di sicurezza." securityKeyNotSupported: "Il tuo browser non supporta le chiavi di sicurezza."
registerTOTPBeforeKey: "Ti occorre un'app di autenticazione con OTP, prima di registrare la chiave di sicurezza." registerTOTPBeforeKey: "Ti occorre un'app di autenticazione con OTP, prima di registrare la chiave di sicurezza."
securityKeyInfo: "È possibile impostare il dispositivo per accedere utilizzando una chiave di sicurezza hardware che supporta FIDO2 o un'impronta digitale o un PIN sul dispositivo." securityKeyInfo: "È possibile impostare il dispositivo per accedere utilizzando una chiave di sicurezza hardware che supporta FIDO2 o un'impronta digitale o un PIN sul dispositivo."

View file

@ -1721,7 +1721,9 @@ _2fa:
step2Url: "デスクトップアプリでは次のURIを入力します:" step2Url: "デスクトップアプリでは次のURIを入力します:"
step3Title: "確認コードを入力" step3Title: "確認コードを入力"
step3: "アプリに表示されている確認コード(トークン)を入力して完了です。" step3: "アプリに表示されている確認コード(トークン)を入力して完了です。"
step4: "これからログインするときも、同じように確認コードを入力します。" step4: "これからログインするときも、同じように確認コードを入力します。\n\n認証アプリが使えなくなった時、アカウントへの緊急アクセスのためのバックアップコードを作成しました。\n紛失防止のため、必ず安全な場所に保管してください。\nこれらのコードはそれぞれ1回だけ使用することができます。\nもし全てのコードを使い切ってしまうとアカウントにアクセスすることができなくなってしまうので、出来るだけ早く認証アプリを再設定してください。\n\nバックアップコード:\n\n{codes}"
twoFactorBackupSecretWarning: "バックアップコードが使用されました。認証アプリが使えなくなっている場合、なるべく早く認証アプリを再設定してください。"
twoFactorBackupSecretExhausted: "バックアップコードが全て使用されました。認証アプリを利用できない場合、これ以上アカウントにアクセスできなくなります。できるだけ早く認証アプリを再登録してください。"
securityKeyNotSupported: "お使いのブラウザはセキュリティキーに対応していません。" securityKeyNotSupported: "お使いのブラウザはセキュリティキーに対応していません。"
registerTOTPBeforeKey: "セキュリティキー・パスキーを登録するには、まず認証アプリの設定を行なってください。" registerTOTPBeforeKey: "セキュリティキー・パスキーを登録するには、まず認証アプリの設定を行なってください。"
securityKeyInfo: "FIDO2をサポートするハードウェアセキュリティキー、端末の生体認証やPINロック、パスキーといった、WebAuthn由来の鍵を登録します。" securityKeyInfo: "FIDO2をサポートするハードウェアセキュリティキー、端末の生体認証やPINロック、パスキーといった、WebAuthn由来の鍵を登録します。"
@ -1733,7 +1735,7 @@ _2fa:
removeKeyConfirm: "{name}を削除しますか?" removeKeyConfirm: "{name}を削除しますか?"
whyTOTPOnlyRenew: "セキュリティキーが登録されている場合、認証アプリの設定は解除できません。" whyTOTPOnlyRenew: "セキュリティキーが登録されている場合、認証アプリの設定は解除できません。"
renewTOTP: "認証アプリを再設定" renewTOTP: "認証アプリを再設定"
renewTOTPConfirm: "今までの認証アプリの確認コードは使用できなくなります" renewTOTPConfirm: "今までの認証アプリの確認コードとバックアップコードは使用できなくなります"
renewTOTPOk: "再設定する" renewTOTPOk: "再設定する"
renewTOTPCancel: "やめておく" renewTOTPCancel: "やめておく"

View file

@ -1682,7 +1682,7 @@ _2fa:
step2Url: "デスクトップアプリやったら次のURLを入力してや:" step2Url: "デスクトップアプリやったら次のURLを入力してや:"
step3Title: "確認コードを入れてーや" step3Title: "確認コードを入れてーや"
step3: "アプリに表示されているトークンを入力して終わりや。" step3: "アプリに表示されているトークンを入力して終わりや。"
step4: "これからログインするときも、同じようにトークンを入力するんやで" step4: "これからログインするときも、同じようにトークンを入力するんやで\n\n認証アプリが使えなくなった時、アカウントへの緊急アクセスのためのバックアップコードを作成しました。\n紛失防止のため、必ず安全な場所に保管してください。\nこれらのコードはそれぞれ1回だけ使用することができます。\nもし全てのコードを使い切ってしまうとアカウントにアクセスすることができなくなってしまうので、出来るだけ早く認証アプリを再設定してください。\n\nバックアップコード:\n\n{codes}"
securityKeyNotSupported: "今使とるブラウザはセキュリティキーに対応してへんのやってさ。" securityKeyNotSupported: "今使とるブラウザはセキュリティキーに対応してへんのやってさ。"
registerTOTPBeforeKey: "セキュリティキー・パスキーを登録するんやったら、まず認証アプリを設定してーな。" registerTOTPBeforeKey: "セキュリティキー・パスキーを登録するんやったら、まず認証アプリを設定してーな。"
securityKeyInfo: "FIDO2をサポートするハードウェアセキュリティキーか端末の指紋認証やPINを使ってログインするように設定できるで。" securityKeyInfo: "FIDO2をサポートするハードウェアセキュリティキーか端末の指紋認証やPINを使ってログインするように設定できるで。"
@ -1694,7 +1694,7 @@ _2fa:
removeKeyConfirm: "{name}を消すん?" removeKeyConfirm: "{name}を消すん?"
whyTOTPOnlyRenew: "セキュリティキーが登録されとったら、認証アプリの設定は解除できへんで。" whyTOTPOnlyRenew: "セキュリティキーが登録されとったら、認証アプリの設定は解除できへんで。"
renewTOTP: "認証アプリをもっかい設定" renewTOTP: "認証アプリをもっかい設定"
renewTOTPConfirm: "今までの人称アプリの確認コードは使えんくなるけどええか?" renewTOTPConfirm: "今までの人称アプリの確認コードとバックアップコードは使えんくなるけどええか?"
renewTOTPOk: "もっかい設定する" renewTOTPOk: "もっかい設定する"
renewTOTPCancel: "やめとく" renewTOTPCancel: "やめとく"
_permissions: _permissions:

View file

@ -1679,7 +1679,9 @@ _2fa:
step2Url: "데스크톱 앱에서는 다음 URL을 입력하세요:" step2Url: "데스크톱 앱에서는 다음 URL을 입력하세요:"
step3Title: "인증 코드 입력" step3Title: "인증 코드 입력"
step3: "앱에 표시된 토큰을 입력하시면 완료됩니다." step3: "앱에 표시된 토큰을 입력하시면 완료됩니다."
step4: "다음 로그인부터는 토큰을 입력해야 합니다." step4: "다음 로그인부터는 토큰을 입력해야 합니다.\n\n인증 앱이 사용할 수 없게 되었을 때, 계정에 응급 접근할 수 있는 백업 코드를 생성했습니다.\n코드를 잃어버리지 않도록 안전한 곳에 보관해 두세요.\n코드는 각각 1번씩만 사용할 수 있습니다.\n만일 모든 코드를 사용해버렸다면 더이상 계정에 접근할 수 없게 되므로, 가능한 한 빨리 인증 앱을 다시 등록해 주세요.\n\n백업 코드:\n\n{code}"
twoFactorBackupSecretWarning: "백업 코드가 사용되었습니다. 인증 앱을 사용할 수 없는 경우, 가능한 한 빨리 인증 앱을 다시 등록해 주세요."
twoFactorBackupSecretExhausted: "백업 코드가 모두 사용되었습니다. 인증 앱을 사용할 수 없는 경우, 더이상 계정에 접근할 수 없게 됩니다. 가능한 한 빨리 인증 앱을 다시 등록해 주세요."
securityKeyNotSupported: "이 브라우저는 보안 키를 지원하지 않습니다." securityKeyNotSupported: "이 브라우저는 보안 키를 지원하지 않습니다."
registerTOTPBeforeKey: "보안 키 또는 패스키를 등록하려면 인증 앱을 등록하십시오." registerTOTPBeforeKey: "보안 키 또는 패스키를 등록하려면 인증 앱을 등록하십시오."
securityKeyInfo: "FIDO2를 지원하는 하드웨어 보안 키 혹은 디바이스의 지문인식이나 화면잠금 PIN을 이용해서 로그인하도록 설정할 수 있습니다." securityKeyInfo: "FIDO2를 지원하는 하드웨어 보안 키 혹은 디바이스의 지문인식이나 화면잠금 PIN을 이용해서 로그인하도록 설정할 수 있습니다."
@ -1691,7 +1693,7 @@ _2fa:
removeKeyConfirm: "{name} 을(를) 삭제하시겠습니까?" removeKeyConfirm: "{name} 을(를) 삭제하시겠습니까?"
whyTOTPOnlyRenew: "보안 키가 등록되어 있는 경우 인증 앱을 해제할 수 없습니다." whyTOTPOnlyRenew: "보안 키가 등록되어 있는 경우 인증 앱을 해제할 수 없습니다."
renewTOTP: "인증 앱 재설정" renewTOTP: "인증 앱 재설정"
renewTOTPConfirm: "기존에 등록되어 있던 인증 키는 사용하지 못하게 됩니다." renewTOTPConfirm: "기존에 등록되어 있던 인증 키와 백업 코드는 사용하지 못하게 됩니다."
renewTOTPOk: "재설정" renewTOTPOk: "재설정"
renewTOTPCancel: "취소" renewTOTPCancel: "취소"
_permissions: _permissions:

View file

@ -1087,7 +1087,7 @@ _2fa:
step1: "Najpierw, zainstaluj aplikację uwierzytelniającą (taką jak {a} lub {b}) na swoim urządzeniu." step1: "Najpierw, zainstaluj aplikację uwierzytelniającą (taką jak {a} lub {b}) na swoim urządzeniu."
step2: "Następnie, zeskanuje kod QR z ekranu." step2: "Następnie, zeskanuje kod QR z ekranu."
step3: "Wprowadź token podany w aplikacji, aby ukończyć konfigurację." step3: "Wprowadź token podany w aplikacji, aby ukończyć konfigurację."
step4: "Od teraz, przy każdej próbie logowania otrzymasz prośbę o token logowania." step4: "Od teraz, przy każdej próbie logowania otrzymasz prośbę o token logowania.\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
removeKeyConfirm: "Usunąć kopię zapasową {name}?" removeKeyConfirm: "Usunąć kopię zapasową {name}?"
renewTOTPCancel: "Nie teraz" renewTOTPCancel: "Nie teraz"
_permissions: _permissions:

View file

@ -1572,7 +1572,7 @@ _2fa:
step2Url: "Если пользуетесь приложением на компьютере, можете ввести в него эту строку (URL):" step2Url: "Если пользуетесь приложением на компьютере, можете ввести в него эту строку (URL):"
step3Title: "Введите проверочный код" step3Title: "Введите проверочный код"
step3: "И наконец, введите код, который покажет приложение." step3: "И наконец, введите код, который покажет приложение."
step4: "Теперь при каждом входе на сайт вам нужно будет вводить код из приложения аналогичным образом." step4: "Теперь при каждом входе на сайт вам нужно будет вводить код из приложения аналогичным образом.\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
securityKeyNotSupported: "Ваш браузер не поддерживает ключи безопасности." securityKeyNotSupported: "Ваш браузер не поддерживает ключи безопасности."
registerTOTPBeforeKey: "Чтобы зарегистрировать ключ безопасности и пароль, сначала настройте приложение аутентификации." registerTOTPBeforeKey: "Чтобы зарегистрировать ключ безопасности и пароль, сначала настройте приложение аутентификации."
securityKeyInfo: "Вы можете настроить вход с помощью аппаратного ключа безопасности, поддерживающего FIDO2, или отпечатка пальца или PIN-кода на устройстве." securityKeyInfo: "Вы можете настроить вход с помощью аппаратного ключа безопасности, поддерживающего FIDO2, или отпечатка пальца или PIN-кода на устройстве."

View file

@ -1149,7 +1149,7 @@ _2fa:
step2: "Potom, naskenujte QR kód zobrazený na obrazovke." step2: "Potom, naskenujte QR kód zobrazený na obrazovke."
step2Url: "Do aplikácie zadajte nasledujúcu URL adresu:" step2Url: "Do aplikácie zadajte nasledujúcu URL adresu:"
step3: "Nastavenie dokončíte zadaním tokenu z vašej aplikácie." step3: "Nastavenie dokončíte zadaním tokenu z vašej aplikácie."
step4: "Od teraz, všetky ďalšie prihlásenia budú vyžadovať prihlasovací token." step4: "Od teraz, všetky ďalšie prihlásenia budú vyžadovať prihlasovací token.\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
securityKeyInfo: "Okrem odtlačku prsta alebo PIN autentifikácie si môžete nastaviť autentifikáciu cez hardvérový bezpečnostný kľúč podporujúci FIDO2 a tak ešte viac zabezpečiť svoj účet." securityKeyInfo: "Okrem odtlačku prsta alebo PIN autentifikácie si môžete nastaviť autentifikáciu cez hardvérový bezpečnostný kľúč podporujúci FIDO2 a tak ešte viac zabezpečiť svoj účet."
removeKeyConfirm: "Naozaj chcete odstrániť \"{name}\"?" removeKeyConfirm: "Naozaj chcete odstrániť \"{name}\"?"
renewTOTPCancel: "Nie, ďakujem" renewTOTPCancel: "Nie, ďakujem"

View file

@ -1682,7 +1682,7 @@ _2fa:
step2Url: "คุณยังสามารถป้อนบน URL นี้หากคุณใช้โปรแกรมเดสก์ท็อป:" step2Url: "คุณยังสามารถป้อนบน URL นี้หากคุณใช้โปรแกรมเดสก์ท็อป:"
step3Title: "ป้อนรหัสยืนยัน" step3Title: "ป้อนรหัสยืนยัน"
step3: "ป้อนโทเค็นที่แอปของคุณให้มาเพื่อเสร็จสิ้นการตั้งค่า" step3: "ป้อนโทเค็นที่แอปของคุณให้มาเพื่อเสร็จสิ้นการตั้งค่า"
step4: "นับจากนี้เป็นต้นไปการพยายามเข้าสู่ระบบในอนาคตนั้น อาจจะต้องขอโทเค็นในการเข้าสู่ระบบดังกล่าว" step4: "นับจากนี้เป็นต้นไปการพยายามเข้าสู่ระบบในอนาคตนั้น อาจจะต้องขอโทเค็นในการเข้าสู่ระบบดังกล่าว\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
securityKeyNotSupported: "เบราว์เซอร์ของคุณไม่รองรับคีย์ความปลอดภัยนะ" securityKeyNotSupported: "เบราว์เซอร์ของคุณไม่รองรับคีย์ความปลอดภัยนะ"
registerTOTPBeforeKey: "กรุณาตั้งค่าแอปยืนยันตัวตนเพื่อลงทะเบียนรหัสความปลอดภัยหรือรหัสผ่าน" registerTOTPBeforeKey: "กรุณาตั้งค่าแอปยืนยันตัวตนเพื่อลงทะเบียนรหัสความปลอดภัยหรือรหัสผ่าน"
securityKeyInfo: "นอกจากนี้การตรวจสอบความถูกต้องด้วยลายนิ้วมือหรือ PIN แล้ว คุณยังสามารถตั้งค่าการตรวจสอบสิทธิ์ผ่านคีย์ความปลอดภัยของฮาร์ดแวร์ที่รองรับ FIDO2 เพื่อเพิ่มความปลอดภัยให้กับบัญชีของคุณ" securityKeyInfo: "นอกจากนี้การตรวจสอบความถูกต้องด้วยลายนิ้วมือหรือ PIN แล้ว คุณยังสามารถตั้งค่าการตรวจสอบสิทธิ์ผ่านคีย์ความปลอดภัยของฮาร์ดแวร์ที่รองรับ FIDO2 เพื่อเพิ่มความปลอดภัยให้กับบัญชีของคุณ"

View file

@ -1333,7 +1333,7 @@ _2fa:
step2: "Потім відскануйте QR-код, який відображається на цьому екрані." step2: "Потім відскануйте QR-код, який відображається на цьому екрані."
step2Url: "Ви також можете ввести цю URL-адресу, якщо використовуєте програму для ПК:" step2Url: "Ви також можете ввести цю URL-адресу, якщо використовуєте програму для ПК:"
step3: "Щоб завершити налаштування, введіть токен, наданий вашою програмою." step3: "Щоб завершити налаштування, введіть токен, наданий вашою програмою."
step4: "Відтепер будь-які майбутні спроби входу вимагатимуть такого токена." step4: "Відтепер будь-які майбутні спроби входу вимагатимуть такого токена.\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
renewTOTPCancel: "Не зараз" renewTOTPCancel: "Не зараз"
_permissions: _permissions:
"read:account": "Переглядати дані профілю" "read:account": "Переглядати дані профілю"

View file

@ -1353,7 +1353,7 @@ _2fa:
step2: "Sau đó, quét mã QR hiển thị trên màn hình này." step2: "Sau đó, quét mã QR hiển thị trên màn hình này."
step2Url: "Bạn cũng có thể nhập URL này nếu sử dụng một chương trình máy tính:" step2Url: "Bạn cũng có thể nhập URL này nếu sử dụng một chương trình máy tính:"
step3: "Nhập mã token do ứng dụng của bạn cung cấp để hoàn tất thiết lập." step3: "Nhập mã token do ứng dụng của bạn cung cấp để hoàn tất thiết lập."
step4: "Kể từ bây giờ, những lần đăng nhập trong tương lai sẽ yêu cầu mã token đăng nhập đó." step4: "Kể từ bây giờ, những lần đăng nhập trong tương lai sẽ yêu cầu mã token đăng nhập đó.\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
securityKeyInfo: "Bên cạnh xác minh bằng vân tay hoặc mã PIN, bạn cũng có thể thiết lập xác minh thông qua khóa bảo mật phần cứng hỗ trợ FIDO2 để bảo mật hơn nữa cho tài khoản của mình." securityKeyInfo: "Bên cạnh xác minh bằng vân tay hoặc mã PIN, bạn cũng có thể thiết lập xác minh thông qua khóa bảo mật phần cứng hỗ trợ FIDO2 để bảo mật hơn nữa cho tài khoản của mình."
removeKey: "Xóa mã bảo mật" removeKey: "Xóa mã bảo mật"
removeKeyConfirm: "Xóa bản sao lưu {name}?" removeKeyConfirm: "Xóa bản sao lưu {name}?"

View file

@ -1682,7 +1682,7 @@ _2fa:
step2Url: "在桌面应用程序中输入以下 URL" step2Url: "在桌面应用程序中输入以下 URL"
step3Title: "输入验证码" step3Title: "输入验证码"
step3: "输入您的应用提供的动态口令以完成设置。" step3: "输入您的应用提供的动态口令以完成设置。"
step4: "从现在开始,任何登录操作都将要求您提供动态口令。" step4: "从现在开始,任何登录操作都将要求您提供动态口令。\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
securityKeyNotSupported: "您的浏览器不支持安全密钥。" securityKeyNotSupported: "您的浏览器不支持安全密钥。"
registerTOTPBeforeKey: "要注册安全密钥或 Passkey请先设置验证器应用程序。" registerTOTPBeforeKey: "要注册安全密钥或 Passkey请先设置验证器应用程序。"
securityKeyInfo: "注册兼容 WebAuthn 的密钥,例如支持 FIDO2 的硬件安全密钥、设备上的生物识别功能、PIN 码以及 Passkey 等。" securityKeyInfo: "注册兼容 WebAuthn 的密钥,例如支持 FIDO2 的硬件安全密钥、设备上的生物识别功能、PIN 码以及 Passkey 等。"

View file

@ -1682,7 +1682,7 @@ _2fa:
step2Url: "請在桌面版應用程式中輸入以下的 URL" step2Url: "請在桌面版應用程式中輸入以下的 URL"
step3Title: "輸入驗證碼" step3Title: "輸入驗證碼"
step3: "輸入應用程式所提供的權杖以完成設定。" step3: "輸入應用程式所提供的權杖以完成設定。"
step4: "從現在開始,任何登入操作都將要求您提供權杖。" step4: "從現在開始,任何登入操作都將要求您提供權杖。\n\nWe've generated backup codes for emergency access to your account in case your authentication app becomes unavailable.\nPlease ensure these are stored in a safe place to prevent loss.\nEach of these codes can only be used once.\nIf you exhaust all the codes, you will not be able to access your account anymore, so please reconfigure your authentication app as soon as possible.\n\nBackup Codes:\n\n{codes}"
securityKeyNotSupported: "您的瀏覽器不支援安全金鑰。" securityKeyNotSupported: "您的瀏覽器不支援安全金鑰。"
registerTOTPBeforeKey: "如要註冊安全金鑰或 Passkey請先設定驗證應用程式。" registerTOTPBeforeKey: "如要註冊安全金鑰或 Passkey請先設定驗證應用程式。"
securityKeyInfo: "您可以設定使用支援 FIDO2 的硬體安全鎖、終端設備的指紋認證,或者 PIN 碼來登入。" securityKeyInfo: "您可以設定使用支援 FIDO2 的硬體安全鎖、終端設備的指紋認證,或者 PIN 碼來登入。"

View file

@ -0,0 +1,11 @@
export class User2faBackupCodes1690569881926 {
name = 'User2faBackupCodes1690569881926'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "user_profile" ADD "twoFactorBackupSecret" character varying array`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "twoFactorBackupSecret"`);
}
}

View file

@ -455,6 +455,7 @@ export class UserEntityService implements OnModuleInit {
preventAiLearning: profile!.preventAiLearning, preventAiLearning: profile!.preventAiLearning,
isExplorable: user.isExplorable, isExplorable: user.isExplorable,
isDeleted: user.isDeleted, isDeleted: user.isDeleted,
twoFactorBackupCodes: profile?.twoFactorBackupSecret?.length === 20 ? 'full' : (profile?.twoFactorBackupSecret?.length ?? 0) > 0 ? 'partial' : 'none',
hideOnlineStatus: user.hideOnlineStatus, hideOnlineStatus: user.hideOnlineStatus,
hasUnreadSpecifiedNotes: this.noteUnreadsRepository.count({ hasUnreadSpecifiedNotes: this.noteUnreadsRepository.count({
where: { userId: user.id, isSpecified: true }, where: { userId: user.id, isSpecified: true },

View file

@ -91,6 +91,11 @@ export class UserProfile {
}) })
public twoFactorTempSecret: string | null; public twoFactorTempSecret: string | null;
@Column('varchar', {
nullable: true, array: true,
})
public twoFactorBackupSecret: string[] | null;
@Column('varchar', { @Column('varchar', {
length: 128, nullable: true, length: 128, nullable: true,
}) })

View file

@ -320,6 +320,11 @@ export const packedMeDetailedOnlySchema = {
type: 'boolean', type: 'boolean',
nullable: false, optional: false, nullable: false, optional: false,
}, },
twoFactorBackupCodes: {
type: 'string',
enum: ['full', 'partial', 'none'],
nullable: false, optional: false,
},
hideOnlineStatus: { hideOnlineStatus: {
type: 'boolean', type: 'boolean',
nullable: false, optional: false, nullable: false, optional: false,

View file

@ -155,6 +155,13 @@ export class SigninApiService {
}); });
} }
if (profile.twoFactorBackupSecret?.includes(token)) {
await this.userProfilesRepository.update({ userId: profile.userId }, {
twoFactorBackupSecret: profile.twoFactorBackupSecret.filter((secret) => secret !== token),
});
return this.signinService.signin(request, reply, user);
}
const delta = OTPAuth.TOTP.validate({ const delta = OTPAuth.TOTP.validate({
secret: OTPAuth.Secret.fromBase32(profile.twoFactorSecret!), secret: OTPAuth.Secret.fromBase32(profile.twoFactorSecret!),
digits: 6, digits: 6,

View file

@ -54,8 +54,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw new Error('not verified'); throw new Error('not verified');
} }
const backupCodes = Array.from({ length: 20 }, () => {
return new OTPAuth.Secret().base32;
});
await this.userProfilesRepository.update(me.id, { await this.userProfilesRepository.update(me.id, {
twoFactorSecret: profile.twoFactorTempSecret, twoFactorSecret: profile.twoFactorTempSecret,
twoFactorBackupSecret: backupCodes,
twoFactorEnabled: true, twoFactorEnabled: true,
}); });
@ -64,6 +69,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
detail: true, detail: true,
includeSecrets: true, includeSecrets: true,
})); }));
return {
backupCodes: backupCodes,
};
}); });
} }
} }

View file

@ -42,6 +42,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
await this.userProfilesRepository.update(me.id, { await this.userProfilesRepository.update(me.id, {
twoFactorSecret: null, twoFactorSecret: null,
twoFactorBackupSecret: null,
twoFactorEnabled: false, twoFactorEnabled: false,
usePasswordLessLogin: false, usePasswordLessLogin: false,
}); });

View file

@ -186,7 +186,7 @@ describe('2要素認証', () => {
const doneResponse = await api('/i/2fa/done', { const doneResponse = await api('/i/2fa/done', {
token: otpToken(registerResponse.body.secret), token: otpToken(registerResponse.body.secret),
}, alice); }, alice);
assert.strictEqual(doneResponse.status, 204); assert.strictEqual(doneResponse.status, 200);
const usersShowResponse = await api('/users/show', { const usersShowResponse = await api('/users/show', {
username, username,
@ -211,7 +211,7 @@ describe('2要素認証', () => {
const doneResponse = await api('/i/2fa/done', { const doneResponse = await api('/i/2fa/done', {
token: otpToken(registerResponse.body.secret), token: otpToken(registerResponse.body.secret),
}, alice); }, alice);
assert.strictEqual(doneResponse.status, 204); assert.strictEqual(doneResponse.status, 200);
const registerKeyResponse = await api('/i/2fa/register-key', { const registerKeyResponse = await api('/i/2fa/register-key', {
password, password,
@ -267,7 +267,7 @@ describe('2要素認証', () => {
const doneResponse = await api('/i/2fa/done', { const doneResponse = await api('/i/2fa/done', {
token: otpToken(registerResponse.body.secret), token: otpToken(registerResponse.body.secret),
}, alice); }, alice);
assert.strictEqual(doneResponse.status, 204); assert.strictEqual(doneResponse.status, 200);
const registerKeyResponse = await api('/i/2fa/register-key', { const registerKeyResponse = await api('/i/2fa/register-key', {
password, password,
@ -324,7 +324,7 @@ describe('2要素認証', () => {
const doneResponse = await api('/i/2fa/done', { const doneResponse = await api('/i/2fa/done', {
token: otpToken(registerResponse.body.secret), token: otpToken(registerResponse.body.secret),
}, alice); }, alice);
assert.strictEqual(doneResponse.status, 204); assert.strictEqual(doneResponse.status, 200);
const registerKeyResponse = await api('/i/2fa/register-key', { const registerKeyResponse = await api('/i/2fa/register-key', {
password, password,
@ -366,7 +366,7 @@ describe('2要素認証', () => {
const doneResponse = await api('/i/2fa/done', { const doneResponse = await api('/i/2fa/done', {
token: otpToken(registerResponse.body.secret), token: otpToken(registerResponse.body.secret),
}, alice); }, alice);
assert.strictEqual(doneResponse.status, 204); assert.strictEqual(doneResponse.status, 200);
const registerKeyResponse = await api('/i/2fa/register-key', { const registerKeyResponse = await api('/i/2fa/register-key', {
password, password,
@ -418,7 +418,7 @@ describe('2要素認証', () => {
const doneResponse = await api('/i/2fa/done', { const doneResponse = await api('/i/2fa/done', {
token: otpToken(registerResponse.body.secret), token: otpToken(registerResponse.body.secret),
}, alice); }, alice);
assert.strictEqual(doneResponse.status, 204); assert.strictEqual(doneResponse.status, 200);
const usersShowResponse = await api('/users/show', { const usersShowResponse = await api('/users/show', {
username, username,

View file

@ -148,6 +148,7 @@ describe('ユーザー', () => {
preventAiLearning: user.preventAiLearning, preventAiLearning: user.preventAiLearning,
isExplorable: user.isExplorable, isExplorable: user.isExplorable,
isDeleted: user.isDeleted, isDeleted: user.isDeleted,
twoFactorBackupCodes: user.twoFactorBackupCodes,
hideOnlineStatus: user.hideOnlineStatus, hideOnlineStatus: user.hideOnlineStatus,
hasUnreadSpecifiedNotes: user.hasUnreadSpecifiedNotes, hasUnreadSpecifiedNotes: user.hasUnreadSpecifiedNotes,
hasUnreadMentions: user.hasUnreadMentions, hasUnreadMentions: user.hasUnreadMentions,
@ -394,6 +395,7 @@ describe('ユーザー', () => {
assert.strictEqual(response.preventAiLearning, true); assert.strictEqual(response.preventAiLearning, true);
assert.strictEqual(response.isExplorable, true); assert.strictEqual(response.isExplorable, true);
assert.strictEqual(response.isDeleted, false); assert.strictEqual(response.isDeleted, false);
assert.strictEqual(response.twoFactorBackupCodes, 'none');
assert.strictEqual(response.hideOnlineStatus, false); assert.strictEqual(response.hideOnlineStatus, false);
assert.strictEqual(response.hasUnreadSpecifiedNotes, false); assert.strictEqual(response.hasUnreadSpecifiedNotes, false);
assert.strictEqual(response.hasUnreadMentions, false); assert.strictEqual(response.hasUnreadMentions, false);

View file

@ -111,6 +111,7 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host = 'mi
publicReactions: false, publicReactions: false,
securityKeys: false, securityKeys: false,
twoFactorEnabled: false, twoFactorEnabled: false,
twoFactorBackupCodes: 'none',
updatedAt: null, updatedAt: null,
uri: null, uri: null,
url: null, url: null,

View file

@ -32,7 +32,7 @@
<template #label>{{ i18n.ts.password }}</template> <template #label>{{ i18n.ts.password }}</template>
<template #prefix><i class="ti ti-lock"></i></template> <template #prefix><i class="ti ti-lock"></i></template>
</MkInput> </MkInput>
<MkInput v-model="token" type="text" pattern="^[0-9]{6}$" autocomplete="one-time-code" :spellcheck="false" required> <MkInput v-model="token" type="text" pattern="^([0-9]{6}|[A-Z0-9]{32})$" autocomplete="one-time-code" :spellcheck="false" required>
<template #label>{{ i18n.ts.token }}</template> <template #label>{{ i18n.ts.token }}</template>
<template #prefix><i class="ti ti-123"></i></template> <template #prefix><i class="ti ti-123"></i></template>
</MkInput> </MkInput>

View file

@ -3,6 +3,13 @@
<template #label>{{ i18n.ts['2fa'] }}</template> <template #label>{{ i18n.ts['2fa'] }}</template>
<div v-if="$i" class="_gaps_s"> <div v-if="$i" class="_gaps_s">
<MkInfo v-if="$i.twoFactorEnabled && $i.twoFactorBackupCodes === 'partial'" warn class="info">
{{ i18n.ts._2fa.twoFactorBackupSecretWarning }}
</MkInfo>
<MkInfo v-if="$i.twoFactorEnabled && $i.twoFactorBackupCodes === 'none'" warn class="info">
{{ i18n.ts._2fa.twoFactorBackupSecretExhausted }}
</MkInfo>
<MkFolder> <MkFolder>
<template #icon><i class="ti ti-shield-lock"></i></template> <template #icon><i class="ti ti-shield-lock"></i></template>
<template #label>{{ i18n.ts.totp }}</template> <template #label>{{ i18n.ts.totp }}</template>
@ -114,13 +121,13 @@ async function registerTOTP() {
}); });
if (token.canceled) return; if (token.canceled) return;
await os.apiWithDialog('i/2fa/done', { const { backupCodes } = await os.apiWithDialog('i/2fa/done', {
token: token.result.toString(), token: token.result.toString(),
}); });
await os.alert({ await os.alert({
type: 'success', type: 'success',
text: i18n.ts._2fa.step4, text: i18n.t('_2fa.step4', { codes: backupCodes.join('\n') }),
}); });
} }

View file

@ -2455,6 +2455,7 @@ type MeDetailed = UserDetailed & {
hasUnreadMessagingMessage: boolean; hasUnreadMessagingMessage: boolean;
hasUnreadNotification: boolean; hasUnreadNotification: boolean;
hasUnreadSpecifiedNotes: boolean; hasUnreadSpecifiedNotes: boolean;
twoFactorBackupCodes: 'full' | 'partial' | 'none';
hideOnlineStatus: boolean; hideOnlineStatus: boolean;
injectFeaturedNote: boolean; injectFeaturedNote: boolean;
integrations: Record<string, any>; integrations: Record<string, any>;

View file

@ -95,6 +95,7 @@ export type MeDetailed = UserDetailed & {
hasUnreadMessagingMessage: boolean; hasUnreadMessagingMessage: boolean;
hasUnreadNotification: boolean; hasUnreadNotification: boolean;
hasUnreadSpecifiedNotes: boolean; hasUnreadSpecifiedNotes: boolean;
twoFactorBackupCodes: 'full' | 'partial' | 'none';
hideOnlineStatus: boolean; hideOnlineStatus: boolean;
injectFeaturedNote: boolean; injectFeaturedNote: boolean;
integrations: Record<string, any>; integrations: Record<string, any>;