Issue
I am trying to implement a function to change the user’s password. I am storing only the hash in DB not the password and I want to ask the user to enter the old password first then the new one. I want to check if the old password’s hash is matching the one stored in DB and if so, to update it with the new one. I am doing something wrong as the code is not passing the validation checks and I am having an error: "Invalid password".
Any help, would be appreciated.
@app.route("/change_password", methods=["GET", "POST"])
@login_required
def change_password():
user_id=session["user_id"]
if request.method=="POST":
password = request.form.get("password")
hash = generate_password_hash(password)
new_password = request.form.get("new_password")
confirm_new_password = request.form.get("confirm_new_password")
new_hash = generate_password_hash(new_password)
#Validations:
if not password:
return apology("must provide password", 400)
if not new_password:
return apology("must provide a new password", 400)
#Ensure password confirmation is provided
if not confirm_new_password:
return apology("must confirm new password", 400)
#Check if new password matches
if new_password!= confirm_new_password:
return apology("password does not match", 400)
# Query database for the current password
rows = db.execute("SELECT * FROM users WHERE hash = ?", hash)
# Ensure username exists and password is correct
if len(rows) != 1:
return apology("invalid password", 400)
#Update DB with the new_hash
else:
db.execute ("UPDATE users SET hash=:new_hash WHERE id=:id", new_hash = new_hash, id = user_id)
return redirect("/")
else:
return render_template("change_password.html")
Solution
There are quite some problems with your code…
The biggest problem
rows = db.execute("SELECT * FROM users WHERE hash = ?", hash)
You have to search for the user name, not for the hash!!! Imagine, two users have the same password, or a user enters the wrong password, but that is the password of another user…
I never used direct access to sqlite, only via sqlalchemy, but from a quick look at the docs ( https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.executemany ) db.execute
does not return e.g. rows, but you need to query it.
e.g. after your db.execute
you need to do a db.fetchone
or db.fetchall
, see above linked documentation.
Also, the order of your code could be improved.
e.g. first, you generate the hash of a new password, and then afterwards you check whether there is a password at all – this should be switched.
Speaking of validation, much of it could be done via e.g. flask-wtforms, so you don’t need so much validation code on your own.
Answered By – Jürgen Gmach
This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0