diff --git a/assets/css/user.css b/assets/css/user.css
index 4ed00a59..7f2cb2b2 100644
--- a/assets/css/user.css
+++ b/assets/css/user.css
@@ -9,6 +9,76 @@
* Licensed under AGPLv3
*/
+
+/*
+ * login/Register pages
+*/
+
+.login-container,
+.register-container {
+ width: max-content;
+ margin: 12vh auto;
+ text-align: end;
+ padding: 2em;
+ border: 1px solid;
+}
+
+.login-container label,
+.register-container label {
+ width: max-content !important;
+ margin-right: 1.5em !important;
+}
+
+.login-container .login-submit-button,
+.register-container .register-submit-button {
+ width: max-content;
+ margin: 1.75em auto 1em auto;
+}
+
+.login-container p,
+.register-container p {
+ margin: 0 auto;
+ text-align: center;
+}
+
+.login-container .username-pass,
+.register-container .username-pass {
+ width: max-content;
+ margin: auto;
+ padding: 0 2em;
+}
+
+.captcha {
+ margin: 2em 0.5em;
+ text-align: center;
+ padding: 1em;
+}
+
+/* Background color accent using transparency */
+/* TODO: handle themes better, ffs */
+.light-theme .captcha { background-color: #0002; }
+.dark-theme .captcha { background-color: #fff2; }
+
+@media (prefers-color-scheme: light) { .no-theme .captcha { background-color: #0002; } }
+@media (prefers-color-scheme: dark) { .no-theme .captcha { background-color: #fff2; } }
+
+
+.captcha div {
+ padding: 0.5em;
+}
+.captcha img {
+ width: 10.5em;
+ height: auto;
+}
+.captcha label {
+ width: auto !important;
+ margin: .4em 0 !important;;
+}
+.captcha a {
+ color: #335d7a;
+}
+
+
/*
* User menu
*/
diff --git a/locales/ar.json b/locales/ar.json
index 24d6cb55..4d15e042 100644
--- a/locales/ar.json
+++ b/locales/ar.json
@@ -162,11 +162,8 @@
"Show replies": "عرض الردود",
"Incorrect password": "كلمة السر غير صحيحة",
"Wrong answer": "إجابة خاطئة",
- "Erroneous CAPTCHA": "الكابتشا CAPTCHA غير صاحلة",
- "CAPTCHA is a required field": "مكان الكابتشا CAPTCHA مطلوب",
"User ID is a required field": "مكان اسم المستخدم مطلوب",
"Password is a required field": "مكان كلمة السر مطلوب",
- "Wrong username or password": "اسم المستخدم او كلمة السر غير صحيح",
"Password cannot be empty": "لا يمكن أن تكون كلمة السر فارغة",
"Password cannot be longer than 55 characters": "يجب أن لا تتعدى كلمة السر 55 حرفًا",
"Please log in": "الرجاء تسجيل الدخول",
@@ -185,7 +182,6 @@
"Could not pull trending pages.": "لم يستطع عرض الصفحات الراجئة.",
"Hidden field \"challenge\" is a required field": "مكان مخفي \"تحدي\" مكان مطلوب",
"Hidden field \"token\" is a required field": "مكان مخفي \"رمز\" مكان مطلوب",
- "Erroneous challenge": "تحدي غير صالح",
"Erroneous token": "رمز مميز خاطئ",
"No such user": "مستخدم غير صالح",
"Token is expired, please try again": "الرمز منتهى الصلاحية، الرجاء المحاولة مرة اخرى",
diff --git a/locales/cs.json b/locales/cs.json
index 843e6739..e22d04fd 100644
--- a/locales/cs.json
+++ b/locales/cs.json
@@ -419,7 +419,6 @@
"Playlist privacy": "Soukromí playlistu",
"Wrong answer": "Špatná odpověď",
"Could not pull trending pages.": "Nepodařilo se získat trendy stránky.",
- "Erroneous CAPTCHA": "Chybná CAPTCHA",
"Password is a required field": "Heslo je vyžadované pole",
"preferences_automatic_instance_redirect_label": "Automatické přesměrování instance (fallback na redirect.invidious.io): ",
"Switch Invidious Instance": "Přepnout instanci Invidious",
@@ -427,7 +426,7 @@
"footer_source_code": "Zdrojový kód",
"View YouTube comments": "Zobrazit YouTube komentáře",
"Blacklisted regions: ": "Oblasti na černé listině: ",
- "Wrong username or password": "Nesprávné uživatelské jméno nebo heslo",
+ "error_invalid_username_or_password": "Nesprávné uživatelské jméno nebo heslo",
"Please sign in using 'Log in with Google'": "Přihlaste se prosím pomocí Googlu",
"Password cannot be empty": "Heslo nemůže být prázné",
"preferences_category_misc": "Různá nastavení",
@@ -457,9 +456,7 @@
"Load more": "Načíst další",
"Not a playlist.": "Není playlist.",
"Playlist does not exist.": "Playlist neexistuje.",
- "Erroneous challenge": "Chybná výzva",
"Premieres `x`": "Premiéra `x`",
- "CAPTCHA is a required field": "CAPTCHA je vyžadované pole",
"`x` ago": "Před `x`",
"search_message_change_filters_or_query": "Zkuste rozšířit vyhledávaný dotaz a/nebo změnit filtry.",
"search_filters_date_option_none": "Jakékoli datum",
diff --git a/locales/da.json b/locales/da.json
index b7915460..2dd02298 100644
--- a/locales/da.json
+++ b/locales/da.json
@@ -157,11 +157,9 @@
"Show replies": "Vis svar",
"Incorrect password": "Forkert adgangskode",
"Wrong answer": "Forkert svar",
- "Erroneous CAPTCHA": "Fejlagtig CAPTCHA",
- "CAPTCHA is a required field": "CAPTCHA er et obligatorisk felt",
"User ID is a required field": "Bruger ID er et krævet felt",
"Password is a required field": "Adgangskode er et obligatorisk felt",
- "Wrong username or password": "Forkert brugernavn eller adgangskode",
+ "error_invalid_username_or_password": "Forkert brugernavn eller adgangskode",
"Please sign in using 'Log in with Google'": "Log ind via 'Log ind med Google'",
"Password cannot be empty": "Adgangskoden må ikke være tom",
"Password cannot be longer than 55 characters": "Adgangskoden må ikke være længere end 55 tegn",
@@ -306,7 +304,6 @@
"Marathi": "Marathi",
"Sindhi": "Sindhi",
"preferences_category_misc": "Diverse indstillinger",
- "Erroneous challenge": "Fejlagtig udfordring",
"Hindi": "Hindi",
"Igbo": "Igbo",
"Javanese": "Javanesisk",
diff --git a/locales/de.json b/locales/de.json
index 4158e83c..eef8467c 100644
--- a/locales/de.json
+++ b/locales/de.json
@@ -162,11 +162,9 @@
"Show replies": "Antworten anzeigen",
"Incorrect password": "Falsches Passwort",
"Wrong answer": "Ungültige Antwort",
- "Erroneous CAPTCHA": "Ungültiges CAPTCHA",
- "CAPTCHA is a required field": "CAPTCHA ist eine erforderliche Eingabe",
"User ID is a required field": "Benutzer ID ist eine erforderliche Eingabe",
"Password is a required field": "Passwort ist eine erforderliche Eingabe",
- "Wrong username or password": "Ungültiger Benutzername oder Passwort",
+ "error_invalid_username_or_password": "Ungültiger Benutzername oder Passwort",
"Password cannot be empty": "Passwort darf nicht leer sein",
"Password cannot be longer than 55 characters": "Passwort darf nicht länger als 55 Zeichen sein",
"Please log in": "Bitte anmelden",
@@ -185,7 +183,6 @@
"Could not pull trending pages.": "Trendenz-Seiten konnten nicht geladen werden.",
"Hidden field \"challenge\" is a required field": "Verstecktes Feld „challenge“ ist eine erforderliche Eingabe",
"Hidden field \"token\" is a required field": "Verstecktes Feld „token“ ist eine erforderliche Eingabe",
- "Erroneous challenge": "Ungültiger Test",
"Erroneous token": "Ungültiger Token",
"No such user": "Ungültiger Benutzer",
"Token is expired, please try again": "Token ist abgelaufen, bitte erneut versuchen",
diff --git a/locales/el.json b/locales/el.json
index a386f17d..3f450570 100644
--- a/locales/el.json
+++ b/locales/el.json
@@ -153,11 +153,9 @@
"Show replies": "Προβολή απαντήσεων",
"Incorrect password": "Λανθασμένος κωδικός πρόσβασης",
"Wrong answer": "Λανθασμένη απάντηση",
- "Erroneous CAPTCHA": "Λανθασμένο CAPTCHA",
- "CAPTCHA is a required field": "Το CAPTCHA είναι απαιτούμενο πεδίο",
"User ID is a required field": "Η ταυτότητα χρήστη είναι απαιτούμενο πεδίο",
"Password is a required field": "Ο κωδικός πρόσβασης είναι απαιτούμενο πεδίο",
- "Wrong username or password": "Λανθασμένο όνομα χρήστη ή κωδικός πρόσβασης",
+ "error_invalid_username_or_password": "Λανθασμένο όνομα χρήστη ή κωδικός πρόσβασης",
"Password cannot be empty": "Ο κωδικός πρόσβασης δεν γίνεται να είναι κενός",
"Password cannot be longer than 55 characters": "Ο κωδικός πρόσβασης δεν γίνεται να υπερβαίνει τους 55 χαρακτήρες",
"Please log in": "Συνδεθείτε",
@@ -176,7 +174,6 @@
"Could not pull trending pages.": "Αδυναμία λήψης σελίδας τάσεων.",
"Hidden field \"challenge\" is a required field": "Το Κρυφό πεδίο \"δοκιμασία\" είναι απαραίτητο",
"Hidden field \"token\" is a required field": "Το κρυφό πεδίο \"αναγνωριστικό διασύνδεσης\" είναι απαραίτητο",
- "Erroneous challenge": "Λανθασμένη δοκιμασία",
"Erroneous token": "Λανθασμένο αναγνωριστικό διασύνδεσης",
"No such user": "Μη υπαρκτός χρήστης",
"Token is expired, please try again": "Το αναγνωριστικό διασύνδεσης έχει λήξει, παρακαλώ ξαναπροσπαθήστε",
diff --git a/locales/en-US.json b/locales/en-US.json
index aa6a71fc..834c26f1 100644
--- a/locales/en-US.json
+++ b/locales/en-US.json
@@ -44,15 +44,6 @@
"An alternative front-end to YouTube": "An alternative front-end to YouTube",
"JavaScript license information": "JavaScript license information",
"source": "source",
- "Log in": "Log in",
- "Log in/register": "Log in/register",
- "User ID": "User ID",
- "Password": "Password",
- "Time (h:mm:ss):": "Time (h:mm:ss):",
- "Text CAPTCHA": "Text CAPTCHA",
- "Image CAPTCHA": "Image CAPTCHA",
- "Sign In": "Sign In",
- "Register": "Register",
"E-mail": "E-mail",
"Preferences": "Preferences",
"preferences_category_player": "Player preferences",
@@ -200,11 +191,6 @@
"Show replies": "Show replies",
"Incorrect password": "Incorrect password",
"Wrong answer": "Wrong answer",
- "Erroneous CAPTCHA": "Erroneous CAPTCHA",
- "CAPTCHA is a required field": "CAPTCHA is a required field",
- "User ID is a required field": "User ID is a required field",
- "Password is a required field": "Password is a required field",
- "Wrong username or password": "Wrong username or password",
"Password cannot be empty": "Password cannot be empty",
"Password cannot be longer than 55 characters": "Password cannot be longer than 55 characters",
"Please log in": "Please log in",
@@ -225,9 +211,7 @@
"Not a playlist.": "Not a playlist.",
"Playlist does not exist.": "Playlist does not exist.",
"Could not pull trending pages.": "Could not pull trending pages.",
- "Hidden field \"challenge\" is a required field": "Hidden field \"challenge\" is a required field",
"Hidden field \"token\" is a required field": "Hidden field \"token\" is a required field",
- "Erroneous challenge": "Erroneous challenge",
"Erroneous token": "Erroneous token",
"No such user": "No such user",
"Token is expired, please try again": "Token is expired, please try again",
@@ -464,5 +448,26 @@
"crash_page_read_the_faq": "read the Frequently Asked Questions (FAQ)",
"crash_page_search_issue": "searched for existing issues on GitHub",
"crash_page_report_issue": "If none of the above helped, please open a new issue on GitHub (preferably in English) and include the following text in your message (do NOT translate that text):",
- "error_video_not_in_playlist": "The requested video doesn't exist in this playlist. Click here for the playlist home page."
+ "error_video_not_in_playlist": "The requested video doesn't exist in this playlist. Click here for the playlist home page.",
+ "error_required_field_username": "Username is a required field",
+ "error_required_field_password": "Password is a required field",
+ "error_login_disabled": "Login has been disabled by the administrator",
+ "error_registration_disabled": "Registration has been disabled by the administrator",
+ "error_invalid_username_or_password": "Invalid username or password",
+ "error_invalid_captcha": "Invalid CAPTCHA",
+ "error_passwords_dont_match": "Passwords don't match",
+ "error_username_already_registered": "Username is already in use. Please try a different one.",
+ "error_database_unavailable": "Database unavailable, please try again later.
\nIf the problem persist, please contact the instance admin.",
+ "login_page_title_login": "Sign in",
+ "login_page_title_register": "Register",
+ "login_page_login_button": "Sign in",
+ "login_page_register_button": "Register",
+ "login_page_username_label": "Username",
+ "login_page_password_label": "Password",
+ "login_page_confirm_label": "Confirm password",
+ "login_page_goto_register_prompt": "Don't have an account yet? Register here!",
+ "login_page_goto_login_prompt": "Already have an account? Log in",
+ "Time (h:mm:ss):": "Time (h:mm:ss):",
+ "login_page_request_text_captcha": "Text CAPTCHA",
+ "login_page_request_image_captcha": "Image CAPTCHA"
}
diff --git a/locales/eo.json b/locales/eo.json
index a7544214..4827b54d 100644
--- a/locales/eo.json
+++ b/locales/eo.json
@@ -162,11 +162,9 @@
"Show replies": "Montri respondojn",
"Incorrect password": "Malbona pasvorto",
"Wrong answer": "Nevalida respondo",
- "Erroneous CAPTCHA": "Nevalida CAPTCHA",
- "CAPTCHA is a required field": "CAPTCHA estas deviga kampo",
"User ID is a required field": "Uzula identigilo estas deviga kampo",
"Password is a required field": "Pasvorto estas deviga kampo",
- "Wrong username or password": "Nevalida uzantnomo aŭ pasvorto",
+ "error_invalid_username_or_password": "Nevalida uzantnomo aŭ pasvorto",
"Please sign in using 'Log in with Google'": "Bonvolu ensaluti per 'Ensaluti per Google'",
"Password cannot be empty": "Pasvorto ne povas esti malplena",
"Password cannot be longer than 55 characters": "Pasvorto ne povas esti pli longa ol 55 signoj",
@@ -186,7 +184,6 @@
"Could not pull trending pages.": "Ne povis venigi tendencajn paĝojn.",
"Hidden field \"challenge\" is a required field": "Kaŝita kampo \"challenge\" estas deviga kampo",
"Hidden field \"token\" is a required field": "Kaŝita kampo \"token\" estas deviga kampo",
- "Erroneous challenge": "Nevalida defio",
"Erroneous token": "Nevalida ĵetono",
"No such user": "Nevalida uzanto",
"Token is expired, please try again": "Ĵetono senvalidiĝis, bonvolu provi denove",
diff --git a/locales/es.json b/locales/es.json
index 317fc853..1ad718ef 100644
--- a/locales/es.json
+++ b/locales/es.json
@@ -162,11 +162,9 @@
"Show replies": "Mostrar las respuestas",
"Incorrect password": "Contraseña incorrecta",
"Wrong answer": "Respuesta no válida",
- "Erroneous CAPTCHA": "CAPTCHA no válido",
- "CAPTCHA is a required field": "El CAPTCHA es un campo obligatorio",
"User ID is a required field": "El nombre es un campo obligatorio",
"Password is a required field": "La contraseña es un campo obligatorio",
- "Wrong username or password": "Nombre o contraseña incorrecto",
+ "error_invalid_username_or_password": "Nombre o contraseña incorrecto",
"Please sign in using 'Log in with Google'": "Inicie sesión con «Iniciar sesión con Google»",
"Password cannot be empty": "La contraseña no puede estar en blanco",
"Password cannot be longer than 55 characters": "La contraseña no puede tener más de 55 caracteres",
@@ -186,7 +184,6 @@
"Could not pull trending pages.": "No se han podido obtener las páginas de tendencias.",
"Hidden field \"challenge\" is a required field": "El campo oculto «desafío» es un campo obligatorio",
"Hidden field \"token\" is a required field": "El campo oculto «símbolo» es un campo obligatorio",
- "Erroneous challenge": "Desafío no válido",
"Erroneous token": "Símbolo no válido",
"No such user": "Usuario no existe",
"Token is expired, please try again": "El símbolo ha caducado, inténtelo de nuevo",
diff --git a/locales/et.json b/locales/et.json
index 1a3e3f27..a74a9145 100644
--- a/locales/et.json
+++ b/locales/et.json
@@ -119,7 +119,7 @@
"Wrong answer": "Vale vastus",
"User ID is a required field": "Kasutaja ID on kohustuslik väli",
"Password is a required field": "Salasõna on kohustuslik väli",
- "Wrong username or password": "Vale kasutajanimi või salasõna",
+ "error_invalid_username_or_password": "Vale kasutajanimi või salasõna",
"Please sign in using 'Log in with Google'": "Palun kasutage 'Logi sisse Google'iga'",
"Password cannot be longer than 55 characters": "Salasõna ei tohi olla pikem kui 55 tähemärki",
"Password cannot be empty": "Salasõna ei tohi olla tühi",
@@ -293,7 +293,6 @@
"Lithuanian": "Leedu",
"Videos": "Videod",
"Community": "Kogukond",
- "CAPTCHA is a required field": "CAPTCHA on kohustuslik väli",
"comments_points_count": "{{count}} punkt",
"comments_points_count_plural": "{{count}} punkti",
"Chinese": "Hiina",
diff --git a/locales/eu.json b/locales/eu.json
index 928a7757..eede0af6 100644
--- a/locales/eu.json
+++ b/locales/eu.json
@@ -164,7 +164,7 @@
"Premieres `x`": "'x' estrenaldiak",
"Wrong answer": "Erantzun ez zuzena",
"Password is a required field": "Pasahitza beharrezkoa da",
- "Wrong username or password": "Pasahitza edo ezizena gaizki",
+ "error_invalid_username_or_password": "Pasahitza edo ezizena gaizki",
"Password cannot be longer than 55 characters": "Pasahitza 55 karaktere baino luzeagoa ezin da izan",
"This channel does not exist.": "Kanal hau ez dago.",
"`x` ago": "duela 'x'",
@@ -191,12 +191,10 @@
"Danish": "Daniera",
"Dutch": "Alemaniera",
"Esperanto": "Esperanto",
- "Erroneous challenge": "Erronka okerra",
"View all playlists": "Zerrenda guztiak ikusi",
"Show annotations": "Oharrak erakutsi",
"Empty playlist": "Zerrenda hutsik",
"Please log in": "Sartu, mesedez",
- "CAPTCHA is a required field": "CAPTCHA beharrezko eremua da",
"preferences_category_data": "Dataren lehentasunak",
"preferences_default_home_label": "Homepage lehenetsia: ",
"preferences_automatic_instance_redirect_label": "berbideratze adibide automatikoa (atzera egin berbideratzeko: invidious.io) ",
@@ -246,7 +244,6 @@
"revoke": "ukatu",
"preferences_continue_label": "Hurrengo lehenetsia jo: ",
"Whitelisted regions: ": "Zuri zerrendaren zonaldeak: ",
- "Erroneous CAPTCHA": "CAPTCHA gaizki",
"Deleted or invalid channel": "Ezgai edota ezabatutako kanala",
"Could not create mix.": "Nahastea ezin sortu.",
"Not a playlist.": "Ez da zerrenda.",
diff --git a/locales/fa.json b/locales/fa.json
index 086e5fe0..de826b6f 100644
--- a/locales/fa.json
+++ b/locales/fa.json
@@ -169,11 +169,9 @@
"Show replies": "نمایش پاسخ ها",
"Incorrect password": "گذرواژه نا درست",
"Wrong answer": "پاسخ غلط",
- "Erroneous CAPTCHA": "CAPTCHA نا درست",
- "CAPTCHA is a required field": "CAPTCHA یک فیلد ضروری است",
"User ID is a required field": "شناسه کاربری یک فیلد ضروری است",
"Password is a required field": "گذرواژه یک فیلد ضروری است",
- "Wrong username or password": "نام کاربری یا گذرواژه غلط است",
+ "error_invalid_username_or_password": "نام کاربری یا گذرواژه غلط است",
"Please sign in using 'Log in with Google'": "لطفا با استفاده از 'ورود توسط گوگل' وارد شوید",
"Password cannot be empty": "گذرواژه نمیتواند خالی باشد",
"Password cannot be longer than 55 characters": "گذر واژه نمیتواند از ۵۵ کاراکتر بیشتر باشد",
@@ -195,7 +193,6 @@
"Could not pull trending pages.": "نمیتوان صفحه های پر طرفدار را بکشد.",
"Hidden field \"challenge\" is a required field": "فیلد مخفی \"چالش\" یک فیلد ضروری است",
"Hidden field \"token\" is a required field": "فیلد مخفی \"توکن\" یک فیلد ضروری است",
- "Erroneous challenge": "چالش غلط",
"Erroneous token": "توکن غلط",
"No such user": "چنین کاربری وجود ندارد",
"Token is expired, please try again": "توکن ضروری است، لطفا دوباره تلاش کنید",
diff --git a/locales/fi.json b/locales/fi.json
index 20448d2f..f9c68694 100644
--- a/locales/fi.json
+++ b/locales/fi.json
@@ -161,11 +161,9 @@
"Show replies": "Näytä vastaukset",
"Incorrect password": "Väärä salasana",
"Wrong answer": "Väärä vastaus",
- "Erroneous CAPTCHA": "Virheellinen CAPTCHA",
- "CAPTCHA is a required field": "CAPTCHA-kenttä vaaditaan",
"User ID is a required field": "Käyttäjätunnus vaaditaan",
"Password is a required field": "Salasana vaaditaan",
- "Wrong username or password": "Väärä käyttäjänimi tai salasana",
+ "error_invalid_username_or_password": "Väärä käyttäjänimi tai salasana",
"Password cannot be empty": "Salasana ei voi olla tyhjä",
"Password cannot be longer than 55 characters": "Salasana ei voi olla yli 55 merkkiä pitkä",
"Please log in": "Kirjaudu sisään, ole hyvä",
@@ -184,7 +182,6 @@
"Could not pull trending pages.": "Nousussa olevien sivujen lataus epäonnistui.",
"Hidden field \"challenge\" is a required field": "Piilotettu kenttä \"challenge\" vaaditaan",
"Hidden field \"token\" is a required field": "Piilotettu kenttä \"tunnus\" vaaditaan",
- "Erroneous challenge": "Virheellinen haaste",
"Erroneous token": "Virheellinen tunnus",
"No such user": "Käyttäjää ei ole olemassa",
"Token is expired, please try again": "Tunnus on vanhentunut, yritä uudestaan",
diff --git a/locales/fr.json b/locales/fr.json
index 23d1806b..163b234d 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -44,15 +44,6 @@
"An alternative front-end to YouTube": "Un front-end alternatif à YouTube",
"JavaScript license information": "Informations sur les licences JavaScript",
"source": "source",
- "Log in": "Se connecter",
- "Log in/register": "Se connecter/S'inscrire",
- "User ID": "Identifiant utilisateur",
- "Password": "Mot de passe",
- "Time (h:mm:ss):": "Heure (h:mm:ss) :",
- "Text CAPTCHA": "CAPTCHA textuel",
- "Image CAPTCHA": "CAPTCHA graphique",
- "Sign In": "Se connecter",
- "Register": "S'inscrire",
"E-mail": "E-mail",
"Preferences": "Préférences",
"preferences_category_player": "Préférences du lecteur",
@@ -177,11 +168,9 @@
"Show replies": "Afficher les réponses",
"Incorrect password": "Mot de passe incorrect",
"Wrong answer": "Réponse invalide",
- "Erroneous CAPTCHA": "CAPTCHA invalide",
- "CAPTCHA is a required field": "Veuillez entrer un CAPTCHA",
"User ID is a required field": "Veuillez entrer un Identifiant Utilisateur",
"Password is a required field": "Veuillez entrer un Mot de passe",
- "Wrong username or password": "Nom d'utilisateur ou mot de passe invalide",
+ "error_invalid_username_or_password": "Nom d'utilisateur ou mot de passe invalide",
"Password cannot be empty": "Le mot de passe ne peut pas être vide",
"Password cannot be longer than 55 characters": "Le mot de passe ne doit pas comporter plus de 55 caractères",
"Please log in": "Veuillez vous connecter",
@@ -204,7 +193,6 @@
"Could not pull trending pages.": "Impossible de charger les pages de tendances.",
"Hidden field \"challenge\" is a required field": "Le champ masqué \"challenge\" est un champ obligatoire",
"Hidden field \"token\" is a required field": "Le champ caché « token » est requis",
- "Erroneous challenge": "Challenge invalide",
"Erroneous token": "Token invalide",
"No such user": "Cet utilisateur n'existe pas",
"Token is expired, please try again": "Le token est expiré, veuillez réessayer",
@@ -464,5 +452,26 @@
"search_filters_date_label": "Date d'ajout",
"search_filters_features_option_vr180": "VR180",
"search_filters_duration_option_none": "Toutes les durées",
- "error_video_not_in_playlist": "La vidéo demandée n'existe pas dans cette liste de lecture. Cliquez ici pour retourner à la liste de lecture."
+ "error_video_not_in_playlist": "La vidéo demandée n'existe pas dans cette liste de lecture. Cliquez ici pour retourner à la liste de lecture.",
+ "error_required_field_username": "Le champ \"nom d'utilisateur\" est requis",
+ "error_required_field_password": "Le champ \"mot de passe\" est requis",
+ "error_login_disabled": "L'administrateur a interdit l'utilisation des comptes utilisateur",
+ "error_registration_disabled": "L'administrateur a interdit la création de comptes utilisateur",
+ "error_invalid_username_or_password": "Mot de passe ou nom d'utilisateur invalide",
+ "error_invalid_captcha": "CAPTCHA invalide",
+ "error_passwords_dont_match": "Les mots de passe ne correspondent pas",
+ "error_username_already_registered": "Ce nom d'utilisateur n'est pas disponible. Merci d'en utiliser un autre.",
+ "error_database_unavailable": "Base de données indisponible, merci de réessayer plus tard.
\nSi le problèm persiste, merci de contacter l'administrateur de cette instance.",
+ "login_page_title_login": "Connexion",
+ "login_page_title_register": "Créer un compte",
+ "login_page_login_button": "Connexion",
+ "login_page_register_button": "Créer un compte",
+ "login_page_username_label": "Nom d'utilisateur",
+ "login_page_password_label": "Mot de passe",
+ "login_page_confirm_label": "Confirmer le mot de passe",
+ "login_page_goto_register_prompt": "Pas encore de compte? S'enregistrer",
+ "login_page_goto_login_prompt": "Déjà un compte? Se connecter",
+ "Time (h:mm:ss):": "Time (h:mm:ss):",
+ "login_page_request_text_captcha": "Changer pour un CAPTCHA textuel",
+ "login_page_request_image_captcha": "Changer pour un CAPTCHA visuel"
}
diff --git a/locales/he.json b/locales/he.json
index c19ba31d..f4a5093e 100644
--- a/locales/he.json
+++ b/locales/he.json
@@ -130,10 +130,9 @@
"Show replies": "הצגת תגובות",
"Incorrect password": "סיסמה שגויה",
"Wrong answer": "תשובה שגויה",
- "CAPTCHA is a required field": "שדה CAPTCHA הוא שדה חובה",
"User ID is a required field": "חובה למלא את שדה שם המשתמש",
"Password is a required field": "חובה למלא את שדה הסיסמה",
- "Wrong username or password": "שם משתמש שגוי או סיסמה שגויה",
+ "error_invalid_username_or_password": "שם משתמש שגוי או סיסמה שגויה",
"Please sign in using 'Log in with Google'": "נא להתחבר בעזרת \"התחברות עם Google\"",
"Password cannot be longer than 55 characters": "על אורך הסיסמה להיות 55 תווים לכל היותר",
"Please log in": "נא להתחבר",
diff --git a/locales/hi.json b/locales/hi.json
index 82cbd703..f7f656bf 100644
--- a/locales/hi.json
+++ b/locales/hi.json
@@ -14,7 +14,6 @@
"License: ": "लाइसेंस: ",
"Wilson score: ": "Wilson स्कोर: ",
"Wrong answer": "गलत जवाब",
- "Erroneous CAPTCHA": "गलत CAPTCHA",
"Please log in": "कृपया लॉग-इन करें",
"Bosnian": "बोस्नियाई",
"Bulgarian": "बुल्गारियाई",
@@ -221,10 +220,9 @@
"Hide replies": "जवाब छिपाएँ",
"Show replies": "जवाब दिखाएँ",
"Incorrect password": "गलत पासवर्ड",
- "CAPTCHA is a required field": "CAPTCHA एक ज़रूरी फ़ील्ड है",
"User ID is a required field": "सदस्य ID एक ज़रूरी फ़ील्ड है",
"Password is a required field": "पासवर्ड एक ज़रूरी फ़ील्ड है",
- "Wrong username or password": "गलत सदस्यनाम या पासवर्ड",
+ "error_invalid_username_or_password": "गलत सदस्यनाम या पासवर्ड",
"Please sign in using 'Log in with Google'": "कृपया 'Google के साथ लॉग-इन करें' के साथ साइन-इन करें",
"Password cannot be empty": "पासवर्ड खाली नहीं हो सकता",
"Password cannot be longer than 55 characters": "पासवर्ड में अधिकतम 55 अक्षर हो सकते हैं",
@@ -244,7 +242,6 @@
"Could not pull trending pages.": "रुझान के पृष्ठ प्राप्त न किए जा सके।",
"Hidden field \"challenge\" is a required field": "छिपाया गया फ़ील्ड \"चुनौती\" एक आवश्यक फ़ील्ड है",
"Hidden field \"token\" is a required field": "छिपाया गया फ़ील्ड \"टोकन\" एक आवश्यक फ़ील्ड है",
- "Erroneous challenge": "त्रुटिपूर्ण चुनौती",
"Erroneous token": "त्रुटिपूर्ण टोकन",
"No such user": "यह सदस्य मौजूद नहीं हैं",
"Token is expired, please try again": "टोकन की समय-सीमा समाप्त हो चुकी है, कृपया दोबारा कोशिश करें",
diff --git a/locales/hr.json b/locales/hr.json
index 501e709d..d6e833aa 100644
--- a/locales/hr.json
+++ b/locales/hr.json
@@ -162,11 +162,9 @@
"Show replies": "Prikaži odgovore",
"Incorrect password": "Neispravna lozinka",
"Wrong answer": "Krivi odgovor",
- "Erroneous CAPTCHA": "Neispravan CAPTCHA",
- "CAPTCHA is a required field": "CAPTCHA je obavezno polje",
"User ID is a required field": "Korisnički ID je obavezno polje",
"Password is a required field": "Polje lozinke je obavezno polje",
- "Wrong username or password": "Krivo korisničko ime ili lozinka",
+ "error_invalid_username_or_password": "Krivo korisničko ime ili lozinka",
"Password cannot be empty": "Polje lozinke ne smije ostati prazno",
"Password cannot be longer than 55 characters": "Lozinka ne može biti duža od 55 znakova",
"Please log in": "Prijavi se",
@@ -185,7 +183,6 @@
"Could not pull trending pages.": "Neuspjelo preuzimanje stranica u trendu.",
"Hidden field \"challenge\" is a required field": "Skriveno polje „izazov” je obavezno polje",
"Hidden field \"token\" is a required field": "Skriveno polje „token” je obavezno polje",
- "Erroneous challenge": "Neispravan izazov",
"Erroneous token": "Neispravan token",
"No such user": "Takav korisnik ne postoji",
"Token is expired, please try again": "Token je istekao, pokušaj ponovo",
diff --git a/locales/hu-HU.json b/locales/hu-HU.json
index 7cc79ebb..b9a5b4ec 100644
--- a/locales/hu-HU.json
+++ b/locales/hu-HU.json
@@ -171,11 +171,9 @@
"Show replies": "Válaszok mutatása",
"Incorrect password": "A jelszó nem megfelelő",
"Wrong answer": "Nem jól válaszoltál.",
- "Erroneous CAPTCHA": "A CAPTCHA hibás.",
- "CAPTCHA is a required field": "A CAPTCHA-mezőt ki kell tölteni.",
"User ID is a required field": "A felhasználói azonosítót meg kell adni.",
"Password is a required field": "Meg kell adni egy jelszót.",
- "Wrong username or password": "Vagy a felhasználói név, vagy pedig a jelszó nem megfelelő.",
+ "error_invalid_username_or_password": "Vagy a felhasználói név, vagy pedig a jelszó nem megfelelő.",
"Password cannot be empty": "A jelszót nem lehet kihagyni.",
"Password cannot be longer than 55 characters": "A jelszó nem lehet hosszabb 55 karakternél.",
"Please log in": "Kérjük, jelentkezz be.",
@@ -198,7 +196,6 @@
"Could not pull trending pages.": "Nem lehetett betölteni a felkapott videók oldalát.",
"Hidden field \"challenge\" is a required field": "A rejtett „challenge” mezőt ki kell tölteni.",
"Hidden field \"token\" is a required field": "A rejtett „token” mezőt ki kell tölteni.",
- "Erroneous challenge": "Hibás challenge",
"Erroneous token": "Hibás token",
"No such user": "Nincs ilyen felhasználó",
"Token is expired, please try again": "A token lejárt. Kérjük, próbáld meg újból.",
diff --git a/locales/id.json b/locales/id.json
index 5c9e5511..33ed00b5 100644
--- a/locales/id.json
+++ b/locales/id.json
@@ -169,11 +169,9 @@
"Show replies": "Lihat balasan",
"Incorrect password": "Kata sandi salah",
"Wrong answer": "Jawaban salah",
- "Erroneous CAPTCHA": "CAPTCHA salah",
- "CAPTCHA is a required field": "CAPTCHA perlu diisi",
"User ID is a required field": "ID pengguna perlu diisi",
"Password is a required field": "Kata sandi perlu diisi",
- "Wrong username or password": "Nama pengguna atau kata sandi salah",
+ "error_invalid_username_or_password": "Nama pengguna atau kata sandi salah",
"Password cannot be empty": "Kata sandi tidak boleh kosong",
"Password cannot be longer than 55 characters": "Kata sandi tidak boleh lebih dari 55 karakter",
"Please log in": "Harap masuk",
@@ -194,7 +192,6 @@
"Could not pull trending pages.": "Tidak bisa mendapatkan laman tren.",
"Hidden field \"challenge\" is a required field": "Bidang \"tantangan\" tersembunyi wajib diisi",
"Hidden field \"token\" is a required field": "Bidang \"token\" tersembunyi wajib diisi",
- "Erroneous challenge": "Tantangan salah",
"Erroneous token": "Token salah",
"No such user": "Tidak ada pengguna demikian",
"Token is expired, please try again": "Token kadaluwarsa, harap coba lagi",
diff --git a/locales/is.json b/locales/is.json
index e578332d..b24d6626 100644
--- a/locales/is.json
+++ b/locales/is.json
@@ -153,11 +153,9 @@
"Show replies": "Sýna svör",
"Incorrect password": "Rangt lykilorð",
"Wrong answer": "Rangt svar",
- "Erroneous CAPTCHA": "Rangt CAPTCHA",
- "CAPTCHA is a required field": "CAPTCHA er nauðsynlegur reitur",
"User ID is a required field": "Notandakenni er nauðsynlegur reitur",
"Password is a required field": "Lykilorð er nauðsynlegur reitur",
- "Wrong username or password": "Rangt notandanafn eða lykilorð",
+ "error_invalid_username_or_password": "Rangt notandanafn eða lykilorð",
"Password cannot be empty": "Lykilorð má ekki vera autt",
"Password cannot be longer than 55 characters": "Lykilorð má ekki vera lengra en 55 stafir",
"Please log in": "Vinsamlegast skráðu þig inn",
@@ -176,7 +174,6 @@
"Could not pull trending pages.": "Ekki tókst að draga vinsælar síður.",
"Hidden field \"challenge\" is a required field": "Falinn reitur \"áskorun\" er nauðsynlegur reitur",
"Hidden field \"token\" is a required field": "Falinn reitur \"tákn\" er nauðsynlegur reitur",
- "Erroneous challenge": "Röng áskorun",
"Erroneous token": "Rangt tákn",
"No such user": "Enginn slíkur notandi",
"Token is expired, please try again": "Tákn er útrunnið, vinsamlegast reyndu aftur",
diff --git a/locales/it.json b/locales/it.json
index 80b7f72f..e369260d 100644
--- a/locales/it.json
+++ b/locales/it.json
@@ -167,11 +167,9 @@
"Show replies": "Mostra le risposte",
"Incorrect password": "Password sbagliata",
"Wrong answer": "Risposta errata",
- "Erroneous CAPTCHA": "CAPTCHA errato",
- "CAPTCHA is a required field": "Il CAPTCHA è un campo obbligatorio",
"User ID is a required field": "L'ID utente è obbligatorio",
"Password is a required field": "La password è un campo obbligatorio",
- "Wrong username or password": "Nome utente o password errati",
+ "error_invalid_username_or_password": "Nome utente o password errati",
"Password cannot be empty": "La password non può essere vuota",
"Password cannot be longer than 55 characters": "La password non può contenere più di 55 caratteri",
"Please log in": "Per favore, accedi",
@@ -190,7 +188,6 @@
"Could not pull trending pages.": "Impossibile recuperare le tendenze.",
"Hidden field \"challenge\" is a required field": "Il campo nascosto \"challenge\" è obbligatorio",
"Hidden field \"token\" is a required field": "Il campo nascosto «token» è obbligatorio",
- "Erroneous challenge": "Campo «challenge» non valido",
"Erroneous token": "Campo \"token\" non valido",
"No such user": "Utente non valido",
"Token is expired, please try again": "Gettone scaduto, riprova",
diff --git a/locales/ja.json b/locales/ja.json
index 8df1c096..53f57dad 100644
--- a/locales/ja.json
+++ b/locales/ja.json
@@ -169,11 +169,9 @@
"Show replies": "返信を表示",
"Incorrect password": "パスワードが間違っています",
"Wrong answer": "回答が間違っています",
- "Erroneous CAPTCHA": "CAPTCHA が間違っています",
- "CAPTCHA is a required field": "CAPTCHA は必須項目です",
"User ID is a required field": "ユーザー ID は必須項目です",
"Password is a required field": "パスワードは必須項目です",
- "Wrong username or password": "ユーザー名またはパスワードが間違っています",
+ "error_invalid_username_or_password": "ユーザー名またはパスワードが間違っています",
"Password cannot be empty": "パスワードを空にすることはできません",
"Password cannot be longer than 55 characters": "パスワードは55文字より長くできません",
"Please log in": "ログインをしてください",
@@ -194,7 +192,6 @@
"Could not pull trending pages.": "急上昇ページを取得できませんでした。",
"Hidden field \"challenge\" is a required field": "非表示項目 \"challenge\" は必須項目です",
"Hidden field \"token\" is a required field": "非表示項目 \"token\" は必須項目です",
- "Erroneous challenge": "チャレンジが間違っています",
"Erroneous token": "トークンが間違っています",
"No such user": "ユーザーが存在しません",
"Token is expired, please try again": "トークンが期限切れです。再度試してください",
diff --git a/locales/ko.json b/locales/ko.json
index 32e073b5..544f9397 100644
--- a/locales/ko.json
+++ b/locales/ko.json
@@ -234,7 +234,6 @@
"Hausa": "하우사어",
"No such user": "해당 사용자 없음",
"Erroneous token": "잘못된 token",
- "Erroneous challenge": "잘못된 challenge",
"Hidden field \"token\" is a required field": "숨겨진 필드 \"token\"은 필수 필드입니다",
"Hidden field \"challenge\" is a required field": "숨겨진 필드 \"challenge\"는 필수 필드입니다",
"Could not pull trending pages.": "인기 급상승 페이지를 가져올 수 없습니다.",
@@ -276,11 +275,9 @@
"Please log in": "로그인하세요",
"Password cannot be longer than 55 characters": "비밀번호는 55자 이하여야 합니다",
"Password cannot be empty": "비밀번호는 비워둘 수 없습니다",
- "Wrong username or password": "잘못된 사용자 이름 또는 비밀번호",
+ "error_invalid_username_or_password": "잘못된 사용자 이름 또는 비밀번호",
"Password is a required field": "비밀번호는 필수 필드입니다",
"User ID is a required field": "사용자 ID는 필수 필드입니다",
- "CAPTCHA is a required field": "CAPTCHA는 필수 필드입니다",
- "Erroneous CAPTCHA": "잘못된 CAPTCHA",
"Blacklisted regions: ": "차단된 지역: ",
"Playlists": "재생목록",
"View as playlist": "재생목록으로 보기",
diff --git a/locales/lt.json b/locales/lt.json
index 812072b2..50e99951 100644
--- a/locales/lt.json
+++ b/locales/lt.json
@@ -162,11 +162,9 @@
"Show replies": "Rodyti atsakymus",
"Incorrect password": "Slaptažodis neteisingas",
"Wrong answer": "Atsakymas neteisingas",
- "Erroneous CAPTCHA": "Klaidinga CAPTCHA",
- "CAPTCHA is a required field": "CAPTCHA yra reikalinga šiam laukeliui",
"User ID is a required field": "Vartotojo ID yra reikalingas šiam laukeliui",
"Password is a required field": "Slaptažodis yra reikalingas šiam laukeliui",
- "Wrong username or password": "Neteisingas vartotojo vardas arba slaptažodis",
+ "error_invalid_username_or_password": "Neteisingas vartotojo vardas arba slaptažodis",
"Password cannot be empty": "Slaptažodžio laukelis negali būti tuščias",
"Password cannot be longer than 55 characters": "Slaptažodis negali būti ilgesnis nei 55 simboliai",
"Please log in": "Prašome prisijungti",
@@ -185,7 +183,6 @@
"Could not pull trending pages.": "Nepavyko ištraukti tendencijų puslapių.",
"Hidden field \"challenge\" is a required field": "Paslėptas laukas „iššūkis“ yra privalomas laukas",
"Hidden field \"token\" is a required field": "Paslėptas laukas „žetonas“ yra privalomas laukas",
- "Erroneous challenge": "Klaidingas iššūkis",
"Erroneous token": "Klaidingas žetonas",
"No such user": "Nėra tokio vartotojo",
"Token is expired, please try again": "Žetonas pasibaigęs, prašome bandyti dar kartą",
diff --git a/locales/nb-NO.json b/locales/nb-NO.json
index 1bcf6cc0..678823da 100644
--- a/locales/nb-NO.json
+++ b/locales/nb-NO.json
@@ -162,11 +162,9 @@
"Show replies": "Vis svar",
"Incorrect password": "Feil passord",
"Wrong answer": "Ugyldig svar",
- "Erroneous CAPTCHA": "Ugyldig CAPTCHA",
- "CAPTCHA is a required field": "CAPTCHA er et påkrevd felt",
"User ID is a required field": "Bruker-ID er et påkrevd felt",
"Password is a required field": "Passord er et påkrevd felt",
- "Wrong username or password": "Ugyldig brukernavn eller passord",
+ "error_invalid_username_or_password": "Ugyldig brukernavn eller passord",
"Password cannot be empty": "Passordet kan ikke være tomt",
"Password cannot be longer than 55 characters": "Passordet kan ikke være lengre enn 55 tegn",
"Please log in": "Logg inn",
@@ -185,7 +183,6 @@
"Could not pull trending pages.": "Kunne ikke hente trendsettende sider.",
"Hidden field \"challenge\" is a required field": "Skjult felt \"utfordring\" er et påkrevd felt",
"Hidden field \"token\" is a required field": "Skjult felt \"symbol\" er et påkrevd felt",
- "Erroneous challenge": "Ugyldig utfordring",
"Erroneous token": "Ugyldig symbol",
"No such user": "Ugyldig bruker",
"Token is expired, please try again": "Symbol utløpt, prøv igjen",
diff --git a/locales/nl.json b/locales/nl.json
index 5d2de3a8..8b6354aa 100644
--- a/locales/nl.json
+++ b/locales/nl.json
@@ -157,11 +157,9 @@
"Show replies": "Antwoorden tonen",
"Incorrect password": "Wachtwoord is onjuist",
"Wrong answer": "Onjuist antwoord",
- "Erroneous CAPTCHA": "Onjuiste CAPTCHA",
- "CAPTCHA is a required field": "CAPTCHA is vereist",
"User ID is a required field": "Gebruikers-id is vereist",
"Password is a required field": "Wachtwoord is vereist",
- "Wrong username or password": "Onjuiste gebruikersnaam of wachtwoord",
+ "error_invalid_username_or_password": "Onjuiste gebruikersnaam of wachtwoord",
"Please sign in using 'Log in with Google'": "Log in via 'Inloggen met Google'",
"Password cannot be empty": "Het wachtwoordveld mag niet leeg zijn",
"Password cannot be longer than 55 characters": "Het wachtwoord mag niet langer dan 55 tekens zijn",
@@ -181,7 +179,6 @@
"Could not pull trending pages.": "Kan uitgelichte pagina's niet ophalen.",
"Hidden field \"challenge\" is a required field": "Verborgen veld \"uitdaging\" is vereist",
"Hidden field \"token\" is a required field": "Verborgen veld \"toegangssleutel\" is vereist",
- "Erroneous challenge": "Ongeldige uitdaging",
"Erroneous token": "Ongeldige toegangssleutel",
"No such user": "Gebruiker bestaat niet",
"Token is expired, please try again": "Toegangssleutel verlopen; probeer het opnieuw",
diff --git a/locales/pl.json b/locales/pl.json
index f6720ca2..a35425bd 100644
--- a/locales/pl.json
+++ b/locales/pl.json
@@ -161,11 +161,9 @@
"Show replies": "Pokaż odpowiedzi",
"Incorrect password": "Niepoprawne hasło",
"Wrong answer": "Niepoprawna odpowiedź",
- "Erroneous CAPTCHA": "CAPTCHA wykonane błędnie",
- "CAPTCHA is a required field": "CAPTCHA jest polem wymaganym",
"User ID is a required field": "ID użytkownika jest polem wymaganym",
"Password is a required field": "Hasło jest polem wymaganym",
- "Wrong username or password": "Niepoprawny login lub hasło",
+ "error_invalid_username_or_password": "Niepoprawny login lub hasło",
"Please sign in using 'Log in with Google'": "Zaloguj się używając \"Zaloguj się przez Google\"",
"Password cannot be empty": "Hasło nie może być puste",
"Password cannot be longer than 55 characters": "Hasło nie może być dłuższe niż 55 znaków",
@@ -185,7 +183,6 @@
"Could not pull trending pages.": "Nie udało się pobrać strony na czasie.",
"Hidden field \"challenge\" is a required field": "Ukryte pole \"wyzwanie\" jest polem wymaganym",
"Hidden field \"token\" is a required field": "Ukryte pole \"token\" jest polem wymaganym",
- "Erroneous challenge": "Niepoprawne wyzwanie",
"Erroneous token": "Niepoprawny token",
"No such user": "Niepoprawny użytkownik",
"Token is expired, please try again": "Token wygasł, spróbuj ponownie",
diff --git a/locales/pt-BR.json b/locales/pt-BR.json
index 1719050d..d5422fda 100644
--- a/locales/pt-BR.json
+++ b/locales/pt-BR.json
@@ -164,11 +164,9 @@
"Show replies": "Mostrar respostas",
"Incorrect password": "Senha incorreta",
"Wrong answer": "Resposta incorreta",
- "Erroneous CAPTCHA": "CAPTCHA inválido",
- "CAPTCHA is a required field": "O CAPTCHA é um campo obrigatório",
"User ID is a required field": "O nome de usuário é um campo obrigatório",
"Password is a required field": "A senha é um campo obrigatório",
- "Wrong username or password": "Nome de usuário ou senha inválidos",
+ "error_invalid_username_or_password": "Nome de usuário ou senha inválidos",
"Please sign in using 'Log in with Google'": "Por favor, entre usando 'Entrar com conta Google'",
"Password cannot be empty": "A senha não pode ficar em branco",
"Password cannot be longer than 55 characters": "A senha não pode ter mais que 55 caracteres",
@@ -188,7 +186,6 @@
"Could not pull trending pages.": "Não foi possível obter as páginas dos vídeos em alta.",
"Hidden field \"challenge\" is a required field": "O campo oculto \"desafio\" é obrigatório",
"Hidden field \"token\" is a required field": "O campo oculto \"token\" é obrigatório",
- "Erroneous challenge": "Desafio inválido",
"Erroneous token": "Token inválido",
"No such user": "Usuário inválido",
"Token is expired, please try again": "Token expirou, tente novamente",
diff --git a/locales/pt-PT.json b/locales/pt-PT.json
index 27f2cdf1..75cca317 100644
--- a/locales/pt-PT.json
+++ b/locales/pt-PT.json
@@ -164,11 +164,9 @@
"Show replies": "Mostrar respostas",
"Incorrect password": "Palavra-chave incorreta",
"Wrong answer": "Resposta errada",
- "Erroneous CAPTCHA": "CAPTCHA inválido",
- "CAPTCHA is a required field": "CAPTCHA é um campo obrigatório",
"User ID is a required field": "O nome de utilizador é um campo obrigatório",
"Password is a required field": "Palavra-chave é um campo obrigatório",
- "Wrong username or password": "Nome de utilizador ou palavra-chave incorreto",
+ "error_invalid_username_or_password": "Nome de utilizador ou palavra-chave incorreto",
"Please sign in using 'Log in with Google'": "Por favor, inicie sessão usando 'Iniciar sessão com o Google'",
"Password cannot be empty": "A palavra-chave não pode estar vazia",
"Password cannot be longer than 55 characters": "A palavra-chave não pode ser superior a 55 caracteres",
@@ -188,7 +186,6 @@
"Could not pull trending pages.": "Não foi possível obter as páginas de tendências.",
"Hidden field \"challenge\" is a required field": "O campo oculto \"desafio\" é obrigatório",
"Hidden field \"token\" is a required field": "O campo oculto \"token\" é um campo obrigatório",
- "Erroneous challenge": "Desafio inválido",
"Erroneous token": "Token inválido",
"No such user": "Utilizador inválido",
"Token is expired, please try again": "Token expirou, tente novamente",
diff --git a/locales/pt.json b/locales/pt.json
index 25611860..e90ca528 100644
--- a/locales/pt.json
+++ b/locales/pt.json
@@ -106,7 +106,6 @@
"Token is expired, please try again": "Token expirou, tente novamente",
"No such user": "Utilizador inválido",
"Erroneous token": "Token inválido",
- "Erroneous challenge": "Desafio inválido",
"Hidden field \"token\" is a required field": "O campo oculto \"token\" é um campo obrigatório",
"Hidden field \"challenge\" is a required field": "O campo oculto \"desafio\" é obrigatório",
"Playlist does not exist.": "A lista de reprodução não existe.",
@@ -123,11 +122,9 @@
"Password cannot be longer than 55 characters": "A palavra-chave não pode ser superior a 55 caracteres",
"Password cannot be empty": "A palavra-chave não pode estar vazia",
"Please sign in using 'Log in with Google'": "Por favor, inicie sessão usando 'Iniciar sessão com o Google'",
- "Wrong username or password": "Nome de utilizador ou palavra-chave incorreto",
+ "error_invalid_username_or_password": "Nome de utilizador ou palavra-chave incorreto",
"Password is a required field": "Palavra-chave é um campo obrigatório",
"User ID is a required field": "O nome de utilizador é um campo obrigatório",
- "CAPTCHA is a required field": "CAPTCHA é um campo obrigatório",
- "Erroneous CAPTCHA": "CAPTCHA inválido",
"Wrong answer": "Resposta errada",
"Incorrect password": "Palavra-chave incorreta",
"Show replies": "Mostrar respostas",
diff --git a/locales/ro.json b/locales/ro.json
index 958efd4b..050ec11c 100644
--- a/locales/ro.json
+++ b/locales/ro.json
@@ -153,11 +153,9 @@
"Show replies": "Afișați replicile",
"Incorrect password": "Parolă incorectă",
"Wrong answer": "Răspuns invalid",
- "Erroneous CAPTCHA": "CAPTCHA invalid",
- "CAPTCHA is a required field": "Câmpul CAPTCHA este obligatoriu",
"User ID is a required field": "Câmpul ID Utilizator este obligatoriu",
"Password is a required field": "Câmpul Parolă este obligatoriu",
- "Wrong username or password": "Nume de utilizator sau parolă invalidă",
+ "error_invalid_username_or_password": "Nume de utilizator sau parolă invalidă",
"Please sign in using 'Log in with Google'": "Vă rog conectați-vă folosind \"Conectați-vă cu Google\"",
"Password cannot be empty": "Parola nu poate fi goală",
"Password cannot be longer than 55 characters": "Parola nu poate să conțină mai mult de 55 de caractere",
@@ -177,7 +175,6 @@
"Could not pull trending pages.": "Încărcarea paginilor de tendințe a eșuat.",
"Hidden field \"challenge\" is a required field": "Câmpul ascuns \"challenge\" este un câmp obligatoriu",
"Hidden field \"token\" is a required field": "Câmpul ascuns \"token\" este un câmp obligatoriu",
- "Erroneous challenge": "Challenge invalid",
"Erroneous token": "Token invalid",
"No such user": "Acest utilizator nu există",
"Token is expired, please try again": "Jetonul a expirat, vă rugăm să încercați din nou",
diff --git a/locales/ru.json b/locales/ru.json
index 04b3430c..a493ad2b 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -162,11 +162,9 @@
"Show replies": "Показать ответы",
"Incorrect password": "Неправильный пароль",
"Wrong answer": "Неправильный ответ",
- "Erroneous CAPTCHA": "Неправильная капча",
- "CAPTCHA is a required field": "Необходимо решить капчу",
"User ID is a required field": "Необходимо ввести ID пользователя",
"Password is a required field": "Необходимо ввести пароль",
- "Wrong username or password": "Неправильный логин или пароль",
+ "error_invalid_username_or_password": "Неправильный логин или пароль",
"Please sign in using 'Log in with Google'": "Пожалуйста, нажмите «Войти через Google»",
"Password cannot be empty": "Пароль не может быть пустым",
"Password cannot be longer than 55 characters": "Пароль не может быть длиннее 55 символов",
@@ -186,7 +184,6 @@
"Could not pull trending pages.": "Не удаётся загрузить страницы «в тренде».",
"Hidden field \"challenge\" is a required field": "Необходимо заполнить скрытое поле «challenge»",
"Hidden field \"token\" is a required field": "Необходимо заполнить скрытое поле «токен»",
- "Erroneous challenge": "Неправильный ответ в «challenge»",
"Erroneous token": "Неправильный токен",
"No such user": "Пользователь не найден",
"Token is expired, please try again": "Срок действия токена истёк, попробуйте позже",
diff --git a/locales/sl.json b/locales/sl.json
index a9838fd3..d80d9afb 100644
--- a/locales/sl.json
+++ b/locales/sl.json
@@ -126,7 +126,6 @@
"comments_points_count_2": "{{count}} točke",
"comments_points_count_3": "{{count}} točk",
"Hidden field \"token\" is a required field": "Skrito polje »žeton« je zahtevano polje",
- "Erroneous challenge": "Napačen izziv",
"English": "angleščina",
"English (United States)": "angleščina (Združene države)",
"Albanian": "albanščina",
@@ -329,10 +328,9 @@
"Premieres in `x`": "Premiere v `x`",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Živjo! Izgleda, da imaš izklopljene JavaScripte . Klikni tukaj, če si želiš ogledati komentarje, vendar vedi, da bo lahko nalaganje trajajo nekoliko dlje.",
"Show replies": "Pokaži odgovore",
- "Erroneous CAPTCHA": "Napačna CAPTCHA",
"User ID is a required field": "ID uporabnika je obvezno polje",
"Password is a required field": "Geslo je obvezno polje",
- "Wrong username or password": "Napačno uporabniško ime ali geslo",
+ "error_invalid_username_or_password": "Napačno uporabniško ime ali geslo",
"Password cannot be longer than 55 characters": "Geslo ne sme biti daljše od 55 znakov",
"channel:`x`": "kanal: `x`",
"Could not fetch comments": "Ni bilo mogoče pridobiti komentarjev",
@@ -350,7 +348,6 @@
"Token is expired, please try again": "Žeton je potekel, poskusi znova",
"English (United Kingdom)": "angleščina (Združeno kraljestvo)",
"Wrong answer": "Napačen odgovor",
- "CAPTCHA is a required field": "CAPTCHA je obvezno polje",
"Could not get channel info.": "Ni bilo mogoče dobiti informacij o kanalu.",
"comments_view_x_replies_0": "Poglej {{count}} odgovor",
"comments_view_x_replies_1": "Poglej {{count}} odgovora",
diff --git a/locales/sq.json b/locales/sq.json
index cc890abd..0041cb54 100644
--- a/locales/sq.json
+++ b/locales/sq.json
@@ -157,11 +157,9 @@
"Blacklisted regions: ": "Rajone të palejuara: ",
"Premieres in `x`": "Premiera në `x`",
"Wrong answer": "Përgjigje e gabuar",
- "Erroneous CAPTCHA": "CAPTCHA e gabuar",
- "CAPTCHA is a required field": "CAPTCHA është fushë e domosdoshme",
"User ID is a required field": "ID-ja e përdoruesit është fushë e domosdoshme",
"Password is a required field": "Fusha e fjalëkalimit është e domosdoshme",
- "Wrong username or password": "Emër përdoruesi ose fjalëkalim i gabuar",
+ "error_invalid_username_or_password": "Emër përdoruesi ose fjalëkalim i gabuar",
"Please sign in using 'Log in with Google'": "Ju lutemi, bëni hyrjen duke përdorur “Bëni hyrjen me Google”",
"Password cannot be empty": "Fjalëkalimi s’mund të jetë i zbrazët",
"Password cannot be longer than 55 characters": "Fjalëkalimi s’mund të jetë më i gjatë se 55 shenja",
diff --git a/locales/sr.json b/locales/sr.json
index 89adf231..230c9d14 100644
--- a/locales/sr.json
+++ b/locales/sr.json
@@ -56,7 +56,6 @@
"Editing playlist `x`": "Izmena plej liste `x`",
"Please sign in using 'Log in with Google'": "Molimo Vas da se prijavite pomoću 'Log in with Google'",
"Playlist does not exist.": "Nepostojeća plej lista.",
- "Erroneous challenge": "Pogrešan izazov",
"Maltese": "Malteški",
"Download": "Preuzmi",
"Download as: ": "Preuzmi kao: ",
@@ -77,7 +76,7 @@
"Switch Invidious Instance": "Promeni Invidious instancu",
"Hide annotations": "Sakrij napomene",
"User ID is a required field": "Korisnički ID je obavezno polje",
- "Wrong username or password": "Pogrešno korisničko ime ili lozinka",
+ "error_invalid_username_or_password": "Pogrešno korisničko ime ili lozinka",
"Please log in": "Molimo vas da se prijavite",
"channel:`x`": "kanal:`x`",
"Could not fetch comments": "Uzimanje komentara nije uspelo",
@@ -178,7 +177,6 @@
"": "Prikaži `x` komentara"
},
"View Reddit comments": "Prikaži Reddit komentare",
- "CAPTCHA is a required field": "CAPTCHA je obavezno polje",
"Croatian": "Hrvatski",
"Estonian": "Estonski",
"Filipino": "Filipino",
@@ -278,7 +276,6 @@
"Wrong answer": "Pogrešan odgovor",
"preferences_quality_label": "Preferirani video kvalitet: ",
"Hide replies": "Sakrij odgovore",
- "Erroneous CAPTCHA": "Pogrešna CAPTCHA",
"Erroneous token": "Pogrešan žeton",
"Czech": "Češki",
"Latin": "Latinski",
diff --git a/locales/sr_Cyrl.json b/locales/sr_Cyrl.json
index ebe61bb3..92af5fda 100644
--- a/locales/sr_Cyrl.json
+++ b/locales/sr_Cyrl.json
@@ -147,7 +147,6 @@
"Burmese": "Бурмански",
"preferences_quality_dash_label": "Преферирани квалитет DASH видео формата: ",
"Erroneous token": "Погрешан жетон",
- "CAPTCHA is a required field": "CAPTCHA је обавезно поље",
"No such user": "Непостојећи корисник",
"Chinese (Traditional)": "Кинески (Традиционални)",
"adminprefs_modified_source_code_url_label": "УРЛ веза до складишта са Измењеном Изворном Кодом",
@@ -191,7 +190,7 @@
"preferences_category_misc": "Остала подешавања",
"User ID is a required field": "Кориснички ИД је обавезно поље",
"Password is a required field": "Лозинка је обавезно поље",
- "Wrong username or password": "Погрешно корисничко име или лозинка",
+ "error_invalid_username_or_password": "Погрешно корисничко име или лозинка",
"Please sign in using 'Log in with Google'": "Молимо Вас да се пријавите помоћу 'Log in with Google'",
"Password cannot be empty": "Лозинка не може бити празна",
"Password cannot be longer than 55 characters": "Лозинка не може бити дужа од 55 карактера",
@@ -267,7 +266,6 @@
"Shared `x`": "Подељено `x`",
"Playlists": "Плеј листе",
"Yoruba": "Јоруба",
- "Erroneous challenge": "Погрешан изазов",
"Danish": "Дански",
"Could not get channel info.": "Узимање података о каналу није успело.",
"search_filters_features_option_hd": "HD",
@@ -352,7 +350,6 @@
"footer_source_code": "Изворна Кода",
"search_filters_features_option_three_d": "3D",
"search_filters_features_option_four_k": "4K",
- "Erroneous CAPTCHA": "Погрешна CAPTCHA",
"`x` ago": "пре `x`",
"Arabic": "Арапски",
"Bulgarian": "Бугарски",
diff --git a/locales/sv-SE.json b/locales/sv-SE.json
index af8b868a..1619363b 100644
--- a/locales/sv-SE.json
+++ b/locales/sv-SE.json
@@ -160,11 +160,9 @@
"Show replies": "Visa svar",
"Incorrect password": "Fel lösenord",
"Wrong answer": "Fel svar",
- "Erroneous CAPTCHA": "Ogiltig CAPTCHA",
- "CAPTCHA is a required field": "CAPTCHA är ett obligatoriskt fält",
"User ID is a required field": "Användar-ID är ett obligatoriskt fält",
"Password is a required field": "Lösenord är ett obligatoriskt fält",
- "Wrong username or password": "Ogiltigt användarnamn eller lösenord",
+ "error_invalid_username_or_password": "Ogiltigt användarnamn eller lösenord",
"Please sign in using 'Log in with Google'": "Logga in genom \"Google-inloggning\"",
"Password cannot be empty": "Lösenordet kan inte vara tomt",
"Password cannot be longer than 55 characters": "Lösenordet kan inte vara längre än 55 tecken",
@@ -184,7 +182,6 @@
"Could not pull trending pages.": "Kunde inte hämta trendande sidor.",
"Hidden field \"challenge\" is a required field": "Dolt fält \"challenge\" är ett obligatoriskt fält",
"Hidden field \"token\" is a required field": "Dolt fält \"token\" är ett obligatoriskt fält",
- "Erroneous challenge": "Felaktig challenge",
"Erroneous token": "Felaktig token",
"No such user": "Ogiltig användare",
"Token is expired, please try again": "Token föråldrad, försök igen",
diff --git a/locales/tr.json b/locales/tr.json
index e18dfbd1..15f7a0d3 100644
--- a/locales/tr.json
+++ b/locales/tr.json
@@ -162,11 +162,9 @@
"Show replies": "Cevapları göster",
"Incorrect password": "Yanlış parola",
"Wrong answer": "Yanlış cevap",
- "Erroneous CAPTCHA": "Hatalı CAPTCHA",
- "CAPTCHA is a required field": "CAPTCHA zorunlu bir alandır",
"User ID is a required field": "Kullanıcı kimliği zorunlu bir alandır",
"Password is a required field": "Parola zorunlu bir alandır",
- "Wrong username or password": "Yanlış kullanıcı adı ya da parola",
+ "error_invalid_username_or_password": "Yanlış kullanıcı adı ya da parola",
"Please sign in using 'Log in with Google'": "Lütfen 'Google ile giriş yap' seçeneğini kullanarak oturum açın",
"Password cannot be empty": "Parola boş olamaz",
"Password cannot be longer than 55 characters": "Parola 55 karakterden uzun olamaz",
@@ -186,7 +184,6 @@
"Could not pull trending pages.": "Trend sayfaları alınamıyor.",
"Hidden field \"challenge\" is a required field": "Gizli alan \"challenge\" zorunlu bir alandır",
"Hidden field \"token\" is a required field": "\"belirteç\" gizli alanı zorunlu bir alandır",
- "Erroneous challenge": "Hatalı challenge",
"Erroneous token": "Hatalı belirteç",
"No such user": "Böyle bir kullanıcı yok",
"Token is expired, please try again": "Belirtecin süresi doldu, lütfen tekrar deneyin",
diff --git a/locales/uk.json b/locales/uk.json
index ef2591f7..9e7cc88e 100644
--- a/locales/uk.json
+++ b/locales/uk.json
@@ -153,11 +153,9 @@
"Show replies": "Показати відповіді",
"Incorrect password": "Неправильний пароль",
"Wrong answer": "Неправильна відповідь",
- "Erroneous CAPTCHA": "Неправильна капча",
- "CAPTCHA is a required field": "Необхідно пройти CAPTCHA",
"User ID is a required field": "Необхідно ввести ID користувача",
"Password is a required field": "Необхідно ввести пароль",
- "Wrong username or password": "Неправильний логін чи пароль",
+ "error_invalid_username_or_password": "Неправильний логін чи пароль",
"Please sign in using 'Log in with Google'": "Будь ласка, натисніть «Увійти через Google»",
"Password cannot be empty": "Пароль не може бути порожнім",
"Password cannot be longer than 55 characters": "Пароль не може бути довшим за 55 знаків",
@@ -177,7 +175,6 @@
"Could not pull trending pages.": "Не вдається завантажити сторінки «у тренді».",
"Hidden field \"challenge\" is a required field": "Необхідно заповнити приховане поле «challenge»",
"Hidden field \"token\" is a required field": "Необхідно заповнити приховане поле «token»",
- "Erroneous challenge": "Неправильна відповідь у «challenge»",
"Erroneous token": "Недійсний токен",
"No such user": "Недопустиме ім’я користувача",
"Token is expired, please try again": "Термін дії токена закінчився, спробуйте пізніше",
diff --git a/locales/vi.json b/locales/vi.json
index d781a6e5..2a6110d3 100644
--- a/locales/vi.json
+++ b/locales/vi.json
@@ -150,11 +150,9 @@
"Show replies": "Hiển thị câu trả lời",
"Incorrect password": "Mật khẩu không đúng",
"Wrong answer": "Câu trả lời sai",
- "Erroneous CAPTCHA": "CAPTCHA bị lỗi",
- "CAPTCHA is a required field": "CAPTCHA là trường bắt buộc",
"User ID is a required field": "User ID là trường bắt buộc",
"Password is a required field": "Mật khẩu là trường bắt buộc",
- "Wrong username or password": "Tên người dùng hoặc mật khẩu sai",
+ "error_invalid_username_or_password": "Tên người dùng hoặc mật khẩu sai",
"Password cannot be empty": "Mật khẩu không được để trống",
"Password cannot be longer than 55 characters": "Mật khẩu không được dài hơn 55 ký tự",
"Please log in": "Xin vui lòng đăng nhập",
@@ -171,7 +169,6 @@
"Could not pull trending pages.": "Không thể kéo các trang thịnh hành.",
"Hidden field \"challenge\" is a required field": "Trường ẩn \"challenge\" là trường bắt buộc",
"Hidden field \"token\" is a required field": "Trường ẩn \"token\" là trường bắt buộc",
- "Erroneous challenge": "Thử thách sai",
"Erroneous token": "Mã thông báo bị lỗi",
"No such user": "Không có người dùng như vậy",
"Token is expired, please try again": "Token đã hết hạn, vui lòng thử lại",
diff --git a/locales/zh-CN.json b/locales/zh-CN.json
index b8fd84ad..abde4841 100644
--- a/locales/zh-CN.json
+++ b/locales/zh-CN.json
@@ -169,11 +169,9 @@
"Show replies": "显示回复",
"Incorrect password": "密码错误",
"Wrong answer": "错误的回复",
- "Erroneous CAPTCHA": "验证码错误",
- "CAPTCHA is a required field": "验证码必填",
"User ID is a required field": "用户名必填",
"Password is a required field": "密码必填",
- "Wrong username or password": "用户名或密码错误",
+ "error_invalid_username_or_password": "用户名或密码错误",
"Password cannot be empty": "密码不能为空",
"Password cannot be longer than 55 characters": "密码长度不能大于 55",
"Please log in": "请登录",
@@ -194,7 +192,6 @@
"Could not pull trending pages.": "无法获取“时下流行”页面。",
"Hidden field \"challenge\" is a required field": "隐藏表单项 \"challenge\" 为必填",
"Hidden field \"token\" is a required field": "隐藏表单项 \"token\" 为必填",
- "Erroneous challenge": "错误的验证回复(challenge)",
"Erroneous token": "错误的令牌",
"No such user": "用户不存在",
"Token is expired, please try again": "令牌过期,请重试",
diff --git a/locales/zh-TW.json b/locales/zh-TW.json
index c847fcda..27c8238c 100644
--- a/locales/zh-TW.json
+++ b/locales/zh-TW.json
@@ -169,11 +169,9 @@
"Show replies": "顯示回覆",
"Incorrect password": "不正確的密碼",
"Wrong answer": "錯誤的答案",
- "Erroneous CAPTCHA": "錯誤的 CAPTCHA",
- "CAPTCHA is a required field": "CAPTCHA 為必填欄位",
"User ID is a required field": "使用者 ID 為必填欄位",
"Password is a required field": "密碼為必填欄位",
- "Wrong username or password": "錯誤的使用者名稱或密碼",
+ "error_invalid_username_or_password": "錯誤的使用者名稱或密碼",
"Password cannot be empty": "密碼不能為空",
"Password cannot be longer than 55 characters": "密碼不能長於55個字元",
"Please log in": "請登入",
@@ -194,7 +192,6 @@
"Could not pull trending pages.": "無法拉取趨勢頁面。",
"Hidden field \"challenge\" is a required field": "隱藏的欄位 \"challenge\" 是必填欄位",
"Hidden field \"token\" is a required field": "隱藏的欄位 \"token\" 是必填欄位",
- "Erroneous challenge": "錯誤的 challenge",
"Erroneous token": "錯誤的 token",
"No such user": "無此使用者",
"Token is expired, please try again": "Token 已過期,請再試一次",
diff --git a/src/invidious/frontend/login_register.cr b/src/invidious/frontend/login_register.cr
new file mode 100644
index 00000000..cebf07b1
--- /dev/null
+++ b/src/invidious/frontend/login_register.cr
@@ -0,0 +1,135 @@
+module Invidious::Frontend::LoginRegister
+ extend self
+
+ # HTML form input template
+ #
+ # `id` defines the CSS `id` attribute, as well as the localized label text.
+ # `type` defines the type of input (text, password, etc...)
+ private macro text_input(id, type)
+ str << %(\t\t\t
" + str << translate(locale, "login_page_goto_register_prompt", url.to_s) + str << "
\n" + end + end + + # Generate the registration form's HTML + def gen_register_form( + env : HTTP::Server::Context, + captcha : User::Captcha? + ) : String + locale = env.get("preferences").as(Preferences).locale + + # Create the parameters for the form URL + params = HTTP::Params.new + if referer = env.get?("referer").try &.as(String) + params["referer"] = referer + end + + url = URI.new(path: "/register", query: params) + + return String.build(1200) do |str| + # Begin registration form + str << %(\t\n" + + submit_button(register) + + # Prompt for the login page (we reuse the form's + # uri object for simplicity sake) + url.path = "/login" + + str << "\t" + str << translate(locale, "login_page_goto_login_prompt", url.to_s) + str << "
\n" + + str << "" + end + end +end diff --git a/src/invidious/routes/account.cr b/src/invidious/routes/account.cr index d3030fc0..378b34fd 100644 --- a/src/invidious/routes/account.cr +++ b/src/invidious/routes/account.cr @@ -48,9 +48,9 @@ module Invidious::Routes::Account return error_template(400, ex) end - password = env.params.body["password"]? - if !password - return error_template(401, "Password is a required field") + old_password = env.params.body["password"]? + if old_password.nil? || old_password.empty? + return error_template(401, "error_required_field_password") end new_passwords = env.params.body.select { |k, v| k.match(/^new_password\[\d+\]$/) }.map { |k, v| v } @@ -68,7 +68,7 @@ module Invidious::Routes::Account return error_template(400, "Password cannot be longer than 55 characters") end - if !Crypto::Bcrypt::Password.new(user.password.not_nil!).verify(password.byte_slice(0, 55)) + if !user.validate_password(old_password) return error_template(401, "Incorrect password") end diff --git a/src/invidious/routes/login.cr b/src/invidious/routes/login.cr index c9351630..fb658962 100644 --- a/src/invidious/routes/login.cr +++ b/src/invidious/routes/login.cr @@ -3,187 +3,160 @@ module Invidious::Routes::Login def self.login_page(env) locale = env.get("preferences").as(Preferences).locale - - user = env.get? "user" - - return env.redirect "/feed/subscriptions" if user - - if !CONFIG.login_enabled - return error_template(400, "Login has been disabled by administrator.") - end - referer = get_referer(env, "/feed/subscriptions") - email = nil - password = nil - captcha = nil + return env.redirect referer if env.get? "user" - account_type = env.params.query["type"]? - account_type ||= "invidious" + if !CONFIG.login_enabled + return error_template(403, "error_login_disabled") + end - captcha_type = env.params.query["captcha"]? - captcha_type ||= "image" + account_type = env.params.query["type"]? || "invidious" - tfa = env.params.query["tfa"]? - prompt = nil + captcha_type = User::Captcha.parse_type(env.params.query) + captcha = User::Captcha.generate(captcha_type) - templated "user/login" + return templated "user/login" end def self.login(env) locale = env.get("preferences").as(Preferences).locale - referer = get_referer(env, "/feed/subscriptions") if !CONFIG.login_enabled - return error_template(403, "Login has been disabled by administrator.") + return error_template(403, "error_login_disabled") end - # https://stackoverflow.com/a/574698 - email = env.params.body["email"]?.try &.downcase.byte_slice(0, 254) - password = env.params.body["password"]? + # Verify captcha + if CONFIG.captcha_enabled + begin + captcha_verified = User::Captcha.verify(env) + raise InfoException.new("error_invalid_captcha") if !captcha_verified + rescue ex + return error_template(400, ex) + end + end - account_type = env.params.query["type"]? - account_type ||= "invidious" + account_type = env.params.query["type"]? || "invidious" case account_type when "invidious" - if !email - return error_template(401, "User ID is a required field") + # https://stackoverflow.com/a/574698 + username = env.params.body["username"]?.try &.downcase.byte_slice(0, 254) + password = env.params.body["password"]? + + if username.nil? || username.empty? || password.nil? || password.empty? + return error_template(403, "error_invalid_username_or_password") end - if !password - return error_template(401, "Password is a required field") - end - - user = Invidious::Database::Users.select(email: email) - - if user - if Crypto::Bcrypt::Password.new(user.password.not_nil!).verify(password.byte_slice(0, 55)) - sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) - Invidious::Database::SessionIDs.insert(sid, email) - - env.response.cookies["SID"] = Invidious::User::Cookies.sid(CONFIG.domain, sid) - 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 - else - if !CONFIG.registration_enabled - return error_template(400, "Registration has been disabled by administrator.") - end - - if password.empty? - return error_template(401, "Password cannot be empty") - end - - # See https://security.stackexchange.com/a/39851 - if password.bytesize > 55 - return error_template(400, "Password cannot be longer than 55 characters") - end - - password = password.byte_slice(0, 55) - - if CONFIG.captcha_enabled - captcha_type = env.params.body["captcha_type"]? - answer = env.params.body["answer"]? - change_type = env.params.body["change_type"]? - - if !captcha_type || change_type - if change_type - captcha_type = change_type - end - captcha_type ||= "image" - - account_type = "invidious" - tfa = false - prompt = "" - - if captcha_type == "image" - captcha = Invidious::User::Captcha.generate_image(HMAC_KEY) - else - captcha = Invidious::User::Captcha.generate_text(HMAC_KEY) - end - - return templated "user/login" - end - - tokens = env.params.body.select { |k, _| k.match(/^token\[\d+\]$/) }.map { |_, v| v } - - answer ||= "" - captcha_type ||= "image" - - case captcha_type - when "image" - answer = answer.lstrip('0') - answer = OpenSSL::HMAC.hexdigest(:sha256, HMAC_KEY, answer) - - begin - validate_request(tokens[0], answer, env.request, HMAC_KEY, locale) - rescue ex - return error_template(400, ex) - end - else # "text" - answer = Digest::MD5.hexdigest(answer.downcase.strip) - - if tokens.empty? - return error_template(500, "Erroneous CAPTCHA") - end - - found_valid_captcha = false - error_exception = Exception.new - tokens.each do |tok| - begin - validate_request(tok, answer, env.request, HMAC_KEY, locale) - found_valid_captcha = true - rescue ex - error_exception = ex - end - end - - if !found_valid_captcha - return error_template(500, error_exception) - end - end - end + user = Database::Users.select(email: username) + if !user.nil? && user.validate_password(password) + # Generate session ID and store it. sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) - user, sid = create_user(sid, email, password) - - if language_header = env.request.headers["Accept-Language"]? - if language = ANG.language_negotiator.best(language_header, LOCALES.keys) - user.preferences.locale = language.header - end + begin + Database::SessionIDs.insert(sid, username) + rescue ex + return error_template(500, "error_database_unavailable") end - Invidious::Database::Users.insert(user) - Invidious::Database::SessionIDs.insert(sid, email) - - view_name = "subscriptions_#{sha256(user.email)}" - PG_DB.exec("CREATE MATERIALIZED VIEW #{view_name} AS #{MATERIALIZED_VIEW_SQL.call(user.email)}") - - env.response.cookies["SID"] = Invidious::User::Cookies.sid(CONFIG.domain, sid) - - if env.request.cookies["PREFS"]? - user.preferences = env.get("preferences").as(Preferences) - Invidious::Database::Users.update_preferences(user) - - cookie = env.request.cookies["PREFS"] - cookie.expires = Time.utc(1990, 1, 1) - env.response.cookies << cookie - end + # Generate cookies + env.response.cookies["SID"] = User::Cookies.sid(CONFIG.domain, sid) + env.response.cookies["PREFS"] = User::Cookies.prefs(CONFIG.domain, user.preferences) + else + return error_template(403, "error_invalid_username_or_password") end - - env.redirect referer - else - env.redirect referer end + + return env.redirect referer + end + + def self.register_page(env) + locale = env.get("preferences").as(Preferences).locale + referer = get_referer(env, "/feed/subscriptions") + + return env.redirect referer if env.get? "user" + + if !CONFIG.registration_enabled + return error_template(403, "error_registration_disabled") + end + + captcha_type = User::Captcha.parse_type(env.params.query) + captcha = User::Captcha.generate(captcha_type) + + return templated "user/register" + end + + def self.register(env) + locale = env.get("preferences").as(Preferences).locale + referer = get_referer(env, "/feed/subscriptions") + + if !CONFIG.registration_enabled + return error_template(403, "error_registration_disabled") + end + + # https://stackoverflow.com/a/574698 + username = env.params.body["username"]?.try &.downcase.byte_slice(0, 254) + password = env.params.body["password"]? + confirm = env.params.body["confirm"]? + + if username.nil? || username.empty? + return error_template(400, "error_required_field_username") + end + + if password.nil? || password.empty? || confirm.nil? || confirm.empty? + return error_template(400, "error_required_field_password") + end + + if password != confirm + return error_template(400, "error_passwords_dont_match") + end + + # TODO: find a way to allow longer passwords + # See https://security.stackexchange.com/a/39851 + if password.bytesize > 55 + return error_template(400, "Password cannot be longer than 55 characters") + end + + # Verify captcha + if CONFIG.captcha_enabled + begin + captcha_verified = User::Captcha.verify(env) + raise InfoException.new("error_invalid_captcha") if !captcha_verified + rescue ex + return error_template(400, ex) + end + end + + # Make sure that user doesn't exist!! + user_check = Database::Users.select(email: username) + if !user_check.nil? + return error_template(400, "error_username_already_registered") + end + + # Generate session ID + sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) + user = User.create(sid, username, password) + + # Use the preferences from user cookie (pre-registration) + # and save them into the account. Otherwise, make a new one. + if env.request.cookies["PREFS"]? + user.preferences = env.get("preferences").as(Preferences) + end + + # Create the proper DN + # TODO: use DB transaction here to avoid corrupted states + Database::Users.insert(user) + Database::SessionIDs.insert(sid, username) + + view_name = "subscriptions_#{sha256(user.email)}" + PG_DB.exec("CREATE MATERIALIZED VIEW #{view_name} AS #{MATERIALIZED_VIEW_SQL.call(user.email)}") + + # Generate cookies + env.response.cookies["SID"] = User::Cookies.sid(CONFIG.domain, sid) + env.response.cookies["PREFS"] = User::Cookies.prefs(CONFIG.domain, user.preferences) + + return env.redirect referer end def self.signout(env) @@ -214,6 +187,6 @@ module Invidious::Routes::Login env.response.cookies << cookie end - env.redirect referer + return env.redirect referer end end diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index b854d537..dfd5d9e6 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -51,9 +51,11 @@ module Invidious::Routing # ------------------- def register_user_routes - # User login/out + # User login/out and registration get "/login", Routes::Login, :login_page post "/login", Routes::Login, :login + get "/register", Routes::Login, :register_page + post "/register", Routes::Login, :register post "/signout", Routes::Login, :signout # User preferences diff --git a/src/invidious/user/captcha.cr b/src/invidious/user/captcha.cr index 8a0f67e5..3dee409b 100644 --- a/src/invidious/user/captcha.cr +++ b/src/invidious/user/captcha.cr @@ -1,12 +1,57 @@ require "openssl/hmac" struct Invidious::User - module Captcha - extend self - + struct Captcha private TEXTCAPTCHA_URL = URI.parse("https://textcaptcha.com") - def generate_image(key) + # Structure that holds the type, the question string and the + # cryptographically signed response(s). + getter type : Type + getter question : String + getter tokens : Array(String) + + def initialize(@type, @question, @tokens) + end + + # ------------------- + # Type parsing + # ------------------- + + enum Type + None + Text + Image + end + + def self.parse_type(params : HTTP::Params) : Type + if CONFIG.captcha_enabled + type_text = params["captcha"]? || "image" + type = Type.parse?(type_text) || Type::Image + + # You opened the dev tools, didn't you? :P + type = Type::Image if type.none? + else + type = Type::None + end + + return type + end + + # ------------------- + # Generators + # ------------------- + + # High-level method that calls the captcha generator for the given type. + def self.generate(type : Type) : Captcha? + case type + when .image? then return gen_image_captcha(HMAC_KEY) + when .text? then return gen_text_captcha(HMAC_KEY) + else + return nil + end + end + + private def self.gen_image_captcha(key) : Captcha second = Random::Secure.rand(12) second_angle = second * 30 second = second * 5 @@ -17,9 +62,6 @@ struct Invidious::User hour = Random::Secure.rand(12) hour_angle = hour * 30 + minute_angle.to_f / 12 - if hour == 0 - hour = 12 - end clock_svg = <<-END_SVG