Add support for TOTP through Crotp

This commit is contained in:
syeopite 2021-07-14 23:23:58 -07:00
parent e9d89f2692
commit 71b5874380
No known key found for this signature in database
GPG key ID: 6FA616E5A5294A82
47 changed files with 722 additions and 38 deletions

View file

@ -423,5 +423,15 @@
"Current version: ": "الإصدار الحالي: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Aktuelle Version: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Τρέχουσα έκδοση: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Current version: ",
"next_steps_error_message": "After which you should try to: ",
"next_steps_error_message_refresh": "Refresh",
"next_steps_error_message_go_to_youtube": "Go to Youtube"
"next_steps_error_message_go_to_youtube": "Go to Youtube",
"setup-totp-form-header": "Setup two factor authenticiation (TOTP)",
"setup-totp-instructions-download-auth": "Install an authenticator app (or anything that supports totp) on your device",
"setup-totp-instructions-enter-code": "Enter the following <strong>secret</strong> code:",
"setup-totp-instructions-validate-code": "Enter the 6 digit number on your screen. Be sure to do it under thirty seconds!",
"setup-totp-submit-button": "Setup TOTP",
"general-totp-empty-field": "The TOTP code is a required field",
"general-totp-invalid-code": "The TOTP code entered is invalid",
"general-totp-enter-code-field": "6 digit number",
"general-totp-enter-code-header": "Two-factor authentication",
"general-totp-verify-button": "Verifiy"
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Nuna versio: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Versión actual: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "نسخه فعلی: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Tämänhetkinen versio: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Version actuelle : ",
"next_steps_error_message": "Vous pouvez essayer de : ",
"next_steps_error_message_refresh": "Rafraîchir la page",
"next_steps_error_message_go_to_youtube": "Aller sur Youtube"
"next_steps_error_message_go_to_youtube": "Aller sur Youtube",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "הגרסה הנוכחית: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Trenutačna verzija: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Jelenlegi verzió: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Versi saat ini: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Núverandi útgáfa: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Versione attuale: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "現在のバージョン: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Dabartinė versija: ",
"next_steps_error_message": "Po to turėtumėte pabandyti: ",
"next_steps_error_message_refresh": "Atnaujinti",
"next_steps_error_message_go_to_youtube": "Eiti į Youtube"
"next_steps_error_message_go_to_youtube": "Eiti į Youtube",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Gjeldende versjon: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Huidige versie: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Aktualna wersja: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Versão atual: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Versão atual: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Versiunea actuală: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Текущая версия: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Тренутна верзија: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Nuvarande version: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Şu anki sürüm: ",
"next_steps_error_message": "Bundan sonra şunları denemelisiniz: ",
"next_steps_error_message_refresh": "Yenile",
"next_steps_error_message_go_to_youtube": "Youtube'a git"
"next_steps_error_message_go_to_youtube": "Youtube'a git",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Поточна версія: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "Phiên bản hiện tại: ",
"next_steps_error_message": "",
"next_steps_error_message_refresh": "",
"next_steps_error_message_go_to_youtube": ""
"next_steps_error_message_go_to_youtube": "",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "当前版本: ",
"next_steps_error_message": "在此之后你应尝试: ",
"next_steps_error_message_refresh": "刷新",
"next_steps_error_message_go_to_youtube": "转到 Youtube"
"next_steps_error_message_go_to_youtube": "转到 Youtube",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -423,5 +423,15 @@
"Current version: ": "目前版本: ",
"next_steps_error_message": "之後您應該嘗試: ",
"next_steps_error_message_refresh": "重新整理",
"next_steps_error_message_go_to_youtube": "到 YouTube"
"next_steps_error_message_go_to_youtube": "到 YouTube",
"setup-totp-form-header": "",
"setup-totp-instructions-download-auth": "",
"setup-totp-instructions-enter-code": "",
"setup-totp-instructions-validate-code": "",
"setup-totp-submit-button": "",
"general-totp-empty-field": "",
"general-totp-invalid-code": "",
"general-totp-enter-code-field": "",
"general-totp-enter-code-header": "",
"general-totp-verify-button": ""
}

View file

@ -1,5 +1,13 @@
version: 2.0
shards:
base32:
git: https://github.com/philnash/base32.git
version: 0.1.1+git.commit.0a21c1d90731fdefcb3f0db4913f49d3d25350ac
crotp:
git: https://github.com/philnash/crotp.git
version: 1.0.0
db:
git: https://github.com/crystal-lang/crystal-db.git
version: 0.10.1

View file

@ -25,6 +25,8 @@ dependencies:
lsquic:
github: iv-org/lsquic.cr
version: ~> 2.18.1-2
crotp:
github: philnash/crotp
crystal: 1.0.0

View file

@ -345,6 +345,10 @@ Invidious::Routing.get "/preferences", Invidious::Routes::PreferencesRoute, :sho
Invidious::Routing.post "/preferences", Invidious::Routes::PreferencesRoute, :update
Invidious::Routing.get "/toggle_theme", Invidious::Routes::PreferencesRoute, :toggle_theme
Invidious::Routing.get "/setup_2fa", Invidious::Routes::Accounts, :setup_2fa_page
Invidious::Routing.post "/setup_2fa", Invidious::Routes::Accounts, :setup_2fa
Invidious::Routing.post "/validate_2fa", Invidious::Routes::Accounts, :validate_2fa
# Users
post "/watch_ajax" do |env|

View file

@ -471,3 +471,78 @@ def fetch_random_instance
return filtered_instance_list.sample(1)[0]
end
def totp_validator(env)
locale = LOCALES[env.get("preferences").as(Preferences).locale]?
referer = get_referer(env)
email = env.params.body["email"]?.try &.downcase.byte_slice(0, 254)
password = env.params.body["password"]?
totp_code = env.params.body["totp_code"]?
user = PG_DB.query_one?("SELECT * FROM users WHERE email = $1", email, as: User)
if !totp_code
return error_template(401, translate(locale, "general-totp-empty-field"))
end
# Verify if possible
if token = env.params.body["csrf_token"]?
begin
validate_request(token, sid, env.request, HMAC_KEY, PG_DB, locale)
rescue ex
return error_template(400, ex)
end
end
totp_instance = CrOTP::TOTP.new(user.totp_secret)
if !totp_instance.verify(totp_code)
return error_template(401, translate(locale, "general-totp-invalid-code"))
end
if Kemal.config.ssl || CONFIG.https_only
secure = true
else
secure = false
end
# There are two routes we can go here.
# 1. Where the user is already logged in and is
# confirming an dangerous task.
# 2. The user is logging in.
#
# This can be detected by the hidden email and password parameter
# https://stackoverflow.com/a/574698
if email && password
# The rest of the login code.
if Crypto::Bcrypt::Password.new(user.password.not_nil!).verify(password.byte_slice(0, 55))
sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32))
PG_DB.exec("INSERT INTO session_ids VALUES ($1, $2, $3)", sid, email, Time.utc)
if CONFIG.domain
env.response.cookies["SID"] = HTTP::Cookie.new(name: "SID", domain: "#{CONFIG.domain}", value: sid, expires: Time.utc + 2.years,
secure: secure, http_only: true)
else
env.response.cookies["SID"] = HTTP::Cookie.new(name: "SID", value: sid, expires: Time.utc + 2.years,
secure: secure, http_only: true)
end
else
return error_template(401, "Wrong username or password")
end
# Since this user has already registered, we don't want to overwrite their preferences
if env.request.cookies["PREFS"]?
cookie = env.request.cookies["PREFS"]
cookie.expires = Time.utc(1990, 1, 1)
env.response.cookies << cookie
end
env.redirect referer
else
if CONFIG.domain
env.response.cookies["2faVerified"] = HTTP::Cookie.new(name: "2faVerified", domain: "#{CONFIG.domain}", value: true, expires: Time.utc + 1.hours, secure: secure, http_only: true)
else
env.response.cookies["2faVerified"] = HTTP::Cookie.new(name: "2faVerified", value: true, expires: Time.utc + 1.hours, secure: secure, http_only: true)
end
end
end

View file

@ -0,0 +1,135 @@
require "crotp"
require "./base_route"
# Different routes relating to existing accounts and the control of their data.
class Invidious::Routes::Accounts < Invidious::Routes::BaseRoute
def setup_2fa_page(env)
locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user"
sid = env.get? "sid"
referer = get_referer(env)
user = user.as(User)
sid = sid.as(String)
csrf_token = generate_response(sid, {":setup_2fa"}, HMAC_KEY, PG_DB)
db_secret = Random::Secure.random_bytes(16).hexstring
totp = CrOTP::TOTP.new(db_secret)
user_secret = totp.base32_secret
return templated "account/setup_2fa"
end
# Setup TOTP (post) request.
def setup_2fa(env)
locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user"
sid = env.get? "sid"
referer = get_referer(env)
if !user
return env.redirect referer
end
user = user.as(User)
sid = sid.as(String)
token = env.params.body["csrf_token"]?
begin
validate_request(token, sid, env.request, HMAC_KEY, PG_DB, locale)
rescue ex
return error_template(400, ex)
end
totp_code = env.params.body["totp_code"]?
db_secret = env.params.body["db_secret"] # Must exist
if !totp_code
return error_template(401, translate(locale, "general-totp-empty-field"))
end
totp_instance = CrOTP::TOTP.new(db_secret)
if !totp_instance.verify(totp_code)
return error_template(401, translate(locale, "general-totp-invalid-code"))
end
PG_DB.exec("UPDATE users SET totp_secret = $1 WHERE email = $2", db_secret.to_s, user.email)
end
# Validate 2fa code endpoint
def validate_2fa(env)
locale = LOCALES[env.get("preferences").as(Preferences).locale]?
referer = get_referer(env)
email = env.params.body["email"]?.try &.downcase.byte_slice(0, 254)
password = env.params.body["password"]?
totp_code = env.params.body["totp_code"]?
# This endpoint is only called when the user has a totp_secret.
user = PG_DB.query_one?("SELECT * FROM users WHERE email = $1", email, as: User).not_nil!
if !totp_code
return error_template(401, translate(locale, "general-totp-empty-field"))
end
totp_instance = CrOTP::TOTP.new(user.totp_secret.not_nil!)
if !totp_instance.verify(totp_code)
return error_template(401, translate(locale, "general-totp-invalid-code"))
end
if Kemal.config.ssl || CONFIG.https_only
secure = true
else
secure = false
end
# There are two routes we can go here.
# 1. Where the user is already logged in and is
# confirming an dangerous task.
# 2. The user is logging in.
#
# This can be detected by the hidden email and password parameter
# https://stackoverflow.com/a/574698
if email && password
# The rest of the login code.
if Crypto::Bcrypt::Password.new(user.password.not_nil!).verify(password.byte_slice(0, 55))
sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32))
PG_DB.exec("INSERT INTO session_ids VALUES ($1, $2, $3)", sid, email, Time.utc)
if CONFIG.domain
env.response.cookies["SID"] = HTTP::Cookie.new(name: "SID", domain: "#{CONFIG.domain}", value: sid, expires: Time.utc + 2.years,
secure: secure, http_only: true)
else
env.response.cookies["SID"] = HTTP::Cookie.new(name: "SID", value: sid, expires: Time.utc + 2.years,
secure: secure, http_only: true)
end
else
return error_template(401, "Wrong username or password")
end
# Since this user has already registered, we don't want to overwrite their preferences
if env.request.cookies["PREFS"]?
cookie = env.request.cookies["PREFS"]
cookie.expires = Time.utc(1990, 1, 1)
env.response.cookies << cookie
end
env.redirect referer
else
token = env.params.body["csrf_token"]
begin
validate_request(token, env.get?("sid").as(String), env.request, HMAC_KEY, PG_DB, locale)
rescue ex
return error_template(400, ex)
end
if CONFIG.domain
env.response.cookies["2faVerified"] = HTTP::Cookie.new(name: "2faVerified", domain: "#{CONFIG.domain}", value: "1", expires: Time.utc + 1.hours, secure: secure, http_only: true)
else
env.response.cookies["2faVerified"] = HTTP::Cookie.new(name: "2faVerified", value: "1", expires: Time.utc + 1.hours, secure: secure, http_only: true)
end
end
end
end

View file

@ -324,6 +324,9 @@ class Invidious::Routes::Login < Invidious::Routes::BaseRoute
if user
if !user.password
return error_template(400, "Please sign in using 'Log in with Google'")
elsif user.totp_secret
csrf_token = nil # setting this to false for compatibility reasons.
return templated "account/validate_2fa"
end
if Crypto::Bcrypt::Password.new(user.password.not_nil!).verify(password.byte_slice(0, 55))

View file

@ -0,0 +1,36 @@
<% content_for "header" do %>
<title><%= translate(locale, "setup-totp-form-header") %> - Invidious</title>
<% end %>
<div class="pure-g">
<div class="pure-u-1 pure-u-lg-1-5"></div>
<div class="pure-u-1 pure-u-lg-3-5">
<div class="h-box">
<form class="pure-form pure-form-aligned" action="/setup_2fa?referer=<%= URI.encode_www_form(referer) %>" method="post">
<legend><%= translate(locale, "setup-totp-form-header") %></legend>
<fieldset>
<input name="db_secret" type="hidden" value="<%= HTML.escape(db_secret) %>">
<ol style="word-wrap: anywhere; white-space: break-space;">
<li> <%= translate(locale, "setup-totp-instructions-download-auth") %> </li>
<li> <%= translate(locale, "setup-totp-instructions-enter-code") %>
<code> <%=user_secret%> </code>
</li>
<li> <%= translate(locale, "setup-totp-instructions-validate-code") %> </li>
</ol>
<input required class="pure-input-1" name="totp_code" placeholder="<%= translate(locale, "general-totp-enter-code-field") %>">
<input type="hidden" name="csrf_token" value="<%= URI.encode_www_form(csrf_token) %>">
<button type="submit" name="action" value="setup-totp-form-header" class="pure-button pure-button-primary">
<%= translate(locale, "setup-totp-submit-button") %>
</button>
</fieldset>
</form>
</div>
</div>
<div class="pure-u-1 pure-u-lg-1-5"></div>
</div>

View file

@ -0,0 +1,37 @@
<% content_for "header" do %>
<title><%= translate(locale, "setup-totp-form-header") %> - Invidious</title>
<% end %>
<div class="pure-g">
<div class="pure-u-1 pure-u-lg-1-5"></div>
<div class="pure-u-1 pure-u-lg-3-5">
<div class="h-box">
<form class="pure-form pure-form-aligned" action="/validate_2fa?referer=<%= URI.encode_www_form(referer) %>" method="post">
<legend><%= translate(locale, "general-totp-enter-code-header") %></legend>
<fieldset>
<!-- Hidden fields used for sign-in authentication-->
<% if email %>
<input name="email" type="hidden" value="<%= email %>">
<% end %>
<% if password %>
<input name="password" type="hidden" value="<%= HTML.escape(password) %>">
<% end %>
<input required class="pure-input-1" name="totp_code" placeholder="<%= translate(locale, "general-totp-enter-code-field") %>">
<% if csrf_token %>
<input type="hidden" name="csrf_token" value="<%= URI.encode_www_form(csrf_token) %>">
<% end %>
<button type="submit" name="action" class="pure-button pure-button-primary">
<%= translate(locale, "general-totp-verify-button") %>
</button>
</fieldset>
</form>
</div>
</div>
<div class="pure-u-1 pure-u-lg-1-5"></div>
</div>

View file

@ -319,6 +319,10 @@
<a href="/feed/history"><%= translate(locale, "Watch history") %></a>
</div>
<div class="pure-control-group">
<a href="/setup_2fa?referer=<%= URI.encode_www_form(referer) %>"><%= translate(locale, "setup-totp-form-header") %></a>
</div>
<div class="pure-control-group">
<a href="/delete_account?referer=<%= URI.encode_www_form(referer) %>"><%= translate(locale, "Delete account") %></a>
</div>