From 0fd46e184b2178181847fde378ec8b2d3f6d0b49 Mon Sep 17 00:00:00 2001 From: Max Hohlfeld Date: Mon, 19 Aug 2024 20:43:47 +0200 Subject: [PATCH] feat: reset password strength --- src/endpoints/user/post_reset.rs | 58 +++++------------------ src/utils/mod.rs | 1 + src/utils/password_help.rs | 74 ++++++++++++++++++++++++++++++ templates/user/reset_password.html | 51 ++++++++++---------- 4 files changed, 115 insertions(+), 69 deletions(-) create mode 100644 src/utils/password_help.rs diff --git a/src/endpoints/user/post_reset.rs b/src/endpoints/user/post_reset.rs index 97ad987e..6aec20e0 100644 --- a/src/endpoints/user/post_reset.rs +++ b/src/endpoints/user/post_reset.rs @@ -7,14 +7,12 @@ use lettre::{ }; use serde::Deserialize; use sqlx::PgPool; -use zxcvbn::{ - feedback::{Suggestion, Warning}, - zxcvbn, Score, -}; +use zxcvbn::{zxcvbn, Score}; use crate::{ - auth, + auth::{self}, models::{PasswordReset, User}, + utils::password_help, }; #[derive(Deserialize)] @@ -106,53 +104,21 @@ Viele Grüße"##, user.name, reset_url)) let entropy = zxcvbn(form.password.as_ref().unwrap(), &user_inputs); if entropy.score() < Score::Three { - let feedback = entropy.feedback().unwrap(); + let message = password_help::generate_for_entropy(&entropy); - let warning = match feedback.warning() { - Some(Warning::ThisIsATop10Password) => { - "Das Passwort ist eins der 10 meist genutzten." - } - Some(Warning::ThisIsATop100Password) => { - "Das Passwort ist eins der 100 meist genutzten." - } - Some(Warning::ThisIsACommonPassword) => "Das ist ein zu übliches Password.", - Some(Warning::DatesAreOftenEasyToGuess) => { - "Datumsangaben lassen sich meist leicht erraten." - } - Some(Warning::RecentYearsAreEasyToGuess) => { - "Vergangene Jahreszahlen lassen sich leicht erraten." - } - Some(Warning::AWordByItselfIsEasyToGuess) => "abc", - Some(Warning::RepeatsLikeAaaAreEasyToGuess) => "abc", - Some(Warning::SequencesLikeAbcAreEasyToGuess) => "abc", - Some(Warning::StraightRowsOfKeysAreEasyToGuess) => "abc", - Some(Warning::ShortKeyboardPatternsAreEasyToGuess) => "abc", - Some(Warning::ThisIsSimilarToACommonlyUsedPassword) => "abc", - Some(Warning::CommonNamesAndSurnamesAreEasyToGuess) => "abc", - Some(Warning::NamesAndSurnamesByThemselvesAreEasyToGuess) => "abc", - Some(Warning::RepeatsLikeAbcAbcAreOnlySlightlyHarderToGuess) => "abc", - _ => "", - }; - - let suggestion = feedback - .suggestions() - .iter() - .map(|s| match s { - Suggestion::AvoidSequences => "abc", - Suggestion::AvoidRecentYears => "abc", - _ => "abc", - }) - .collect::>() - .join("
"); - - return HttpResponse::BadRequest().body(format!("Passwort zu schwach.
Warnung: {warning}
Vorschlag: {suggestion}")); + return HttpResponse::BadRequest().body(message); } if form.dry.is_some_and(|b| b) { - return HttpResponse::NoContent().finish(); + if entropy.score() == Score::Three { + return HttpResponse::Ok() + .body("
Sicheres Passwort.
"); + } else { + return HttpResponse::Ok() + .body("
Sehr sicheres Passwort.
"); + } } - if form.password.as_ref().unwrap() != form.passwordretyped.as_ref().unwrap() { return HttpResponse::BadRequest().body("Passwörter stimmen nicht überein!"); } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 158bdcdd..8ae39a65 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,2 +1,3 @@ pub mod email; pub mod manage_commands; +pub mod password_help; diff --git a/src/utils/password_help.rs b/src/utils/password_help.rs new file mode 100644 index 00000000..d53a7b81 --- /dev/null +++ b/src/utils/password_help.rs @@ -0,0 +1,74 @@ +use zxcvbn::{feedback::{Suggestion, Warning}, Entropy}; + +pub fn generate_for_entropy(entropy: &Entropy) -> String { + let feedback = entropy.feedback().unwrap(); + + let warning = match feedback.warning() { + Some(Warning::StraightRowsOfKeysAreEasyToGuess) => { + "Gerade Linien von Tasten auf der Tastatur sind leicht zu erraten." + } + Some(Warning::ShortKeyboardPatternsAreEasyToGuess) => { + "Kurze Tastaturmuster sind leicht zu erraten." + } + Some(Warning::RepeatsLikeAaaAreEasyToGuess) => { + "Sich wiederholende Zeichen wie 'aaa' sind leicht zu erraten." + } + Some(Warning::RepeatsLikeAbcAbcAreOnlySlightlyHarderToGuess) => { + "Sich wiederholende Zeichenmuster wie 'abcabcabc' sind leicht zu erraten." + } + Some(Warning::ThisIsATop10Password) => "Dies ist ein sehr häufig verwendetes Passwort.", + Some(Warning::ThisIsATop100Password) => "Dies ist ein häufig verwendetes Passwort.", + Some(Warning::ThisIsACommonPassword) => "Dies ist ein oft verwendetes Passwort.", + Some(Warning::ThisIsSimilarToACommonlyUsedPassword) => { + "Dieses Passwort weist Ähnlichkeit zu anderen, oft verwendeten Passwörtern auf." + } + Some(Warning::SequencesLikeAbcAreEasyToGuess) => { + "Häufige Zeichenfolgen wie 'abc' oder '1234' sind leicht zu erraten." + } + Some(Warning::RecentYearsAreEasyToGuess) => { + "Die jüngsten Jahreszahlen sind leicht zu erraten." + } + Some(Warning::AWordByItselfIsEasyToGuess) => "Einzelne Wörter sind leicht zu erraten.", + Some(Warning::DatesAreOftenEasyToGuess) => "Ein Datum ist leicht zu erraten.", + Some(Warning::NamesAndSurnamesByThemselvesAreEasyToGuess) => { + "Einzelne Namen oder Nachnamen sind leicht zu erraten." + } + Some(Warning::CommonNamesAndSurnamesAreEasyToGuess) => { + "Vornamen und Nachnamen sind leicht zu erraten." + } + _ => "Passwort ist zu schwach.", + }; + + let vorschlag_text = if feedback.suggestions().len() > 1 { + "Vorschläge" + } else { + "Vorschlag" + }; + + let suggestion = feedback + .suggestions() + .iter() + .map(|s| { + let inner = match s { + Suggestion::UseAFewWordsAvoidCommonPhrases => "Mehrere Wörter verwenden, aber allgemeine Phrasen vermeiden.", + Suggestion::NoNeedForSymbolsDigitsOrUppercaseLetters => "Es ist möglich, starke Passwörter zu erstellen, ohne Symbole, Zahlen oder Großbuchstaben zu verwenden.", + Suggestion::AddAnotherWordOrTwo => "Weitere Wörter, die weniger häufig vorkommen, hinzufügen.", + Suggestion::CapitalizationDoesntHelpVeryMuch => "Nicht nur den ersten Buchstaben groß schreiben.", + Suggestion::AllUppercaseIsAlmostAsEasyToGuessAsAllLowercase => "Einige, aber nicht alle Buchstaben groß schreiben.", + Suggestion::ReversedWordsArentMuchHarderToGuess => "Umgekehrte Schreibweise von gebräuchlichen Wörtern vermeiden.", + Suggestion::PredictableSubstitutionsDontHelpVeryMuch => "Vorhersehbare Buchstabenersetzungen wie '@' für 'a' vermeiden.", + Suggestion::UseALongerKeyboardPatternWithMoreTurns => "Längere Tastaturmuster in unterschiedlicher Tipprichtung verwenden.", + Suggestion::AvoidRepeatedWordsAndCharacters => "Wort- und Zeichenwiederholungen vermeiden.", + Suggestion::AvoidSequences => "Häufige Zeichenfolgen vermeiden.", + Suggestion::AvoidRecentYears => "Die jüngsten Jahreszahlen vermeiden.", + Suggestion::AvoidYearsThatAreAssociatedWithYou => "Jahre, die mit persönlichen Daten in Verbindung gebracht werden können, vermeiden.", + Suggestion::AvoidDatesAndYearsThatAreAssociatedWithYou => "Daten, die mit persönlichen Daten in Verbindung gebracht werden können, vermeiden.", + }; + + format!("
  • {inner}
  • ") + }) + .collect::>() + .join(""); + + format!("

    {warning}

    {vorschlag_text}:

      {suggestion}

    ") +} diff --git a/templates/user/reset_password.html b/templates/user/reset_password.html index 78f7aaf6..85018b64 100644 --- a/templates/user/reset_password.html +++ b/templates/user/reset_password.html @@ -2,33 +2,38 @@ {% block body %}
    -
    -

    Brass - Passwort zurücksetzen

    -
    - +
    +

    Brass - Passwort zurücksetzen

    + + - + -
    - -
    - -
    -
    +
    + +
    + +
    +
    -
    - -
    - -
    -
    +
    -
    +
    + +
    + +
    +
    -
    - -
    - -
    +
    + +
    + +
    + +
    {% endblock %}