When a user submits the registration form to Flask, I want to check the password they chose against a file with 10000 common passwords. If their password matches a common value, I want to flash a message instead of create the user.
I wrote the code below, but it always creates the user even if they enter one of the common passwords. What is wrong with the check I wrote?
@bp.route("/register", methods=["GET", "POST"])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data)
with open("VanligePassord.txt") as f:
for line in f:
if form.password.data == line[:-1]:
flash("Passordet ditt er for svakt")
else:
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
return redirect(url_for("auth.login"))
return render_template("auth/register.html", form=form)
The check you wrote doesn't stop when it encounters a bad password, it only flashes a message, then continues on to the next value. And if the password doesn't match the bad value, it goes to the else branch and gets committed immediately, regardless of if some other value were to match later.
Use any() to check if any value matches the password, then flash an error or commit based on that.
password = form.password.data
with current_app.open_resource("common_passwords.txt") as f:
common_values = [line.rstrip("\n") for line in f]
if any(value == password for value in common_values):
flash("Don't use a common password.")
else:
user.set_password(password)
db.session.add(user)
db.session.commit()
Since you're using WTForms, you could also write this as part of the form validation instead of part of the view.
class RegistrationForm(FlaskForm):
...
def validate_password(self, field, data):
with current_app.open_resource("common_passwords.txt") as f:
common_values = [line.rstrip("\n") for line in f]
if any(value == data for value in common_values):
raise ValidationError("Don't use a common password.")