I am trying to follow along with a couple online tutorials for creating a reset password feature in my app. Both these tutorials use itsdangerous TimedJSONWebSignatureSerializer, which has since been deprecated, so I'm working with an older version of itsdangerous. Probably not best practice, I know.
The issue that I'm running into is that when I'm in the reset_token function and use verify_token(), its supposed to return the variable "email" to me, which I then save in "user". The reset_token function runs through the first time to bring up the html page and on this first run through, user = the email address, as it should. However, then when I hit "submit" on my reset password page, the code runs through a second time and then user = None, which therefore makes my query not work.
How do I make "email" not turn to None on the second run through of my code?
from flask import Flask, request, render_template, session, redirect, url_for
import mysql.connector
from flask_mail import Mail, Message
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
def get_token(user, expires_sec=600):
serial = Serializer(app.config['SECRET_KEY'], expires_in=expires_sec)
return serial.dumps({'user_id': user}).decode('utf-8')
def verify_token(token):
serial = Serializer(app.config['SECRET_KEY'])
try:
email = serial.loads(token)['user_id']
except:
return None
return email
def send_mail(email):
token = get_token(email)
msg = Message('Password Reset Request', recipients=[email], sender='censoring this :)')
msg.body = f'''
To reset your password, please follow the link below.
{url_for('reset_token', token=token, _external=True)}
If you did not request a password reset, please ignore this message.
'''
mail.send(msg)
@app.route('/password_reset', methods=['post', 'get'])
def password_reset():
error = None
success = None
def check(s):
email_format = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
if re.match(email_format, s):
return True
else:
return False
if request.method == 'POST':
email = request.form.get('email')
if not check(email):
error = "*Invalid email"
else:
query = "SELECT * FROM users WHERE email = %s"
cursor.execute(query, (email,))
cursor.fetchall()
count_rows = cursor.rowcount
if count_rows < 1:
error = "*We do not have that email address on file."
else:
send_mail(email)
success = "*Reset request sent. Please check your email."
return render_template('password_reset.html', error=error, msg=success)
@app.route('/password_reset/<token>', methods=['get', 'post'])
def reset_token(token):
error = None
success = None
user = verify_token(token)
print(user)
if user is None:
error = "That token is either invalid or expired. Please try again."
return redirect(url_for('password_reset'))
if request.method == 'POST':
password = request.form.get('password')
password_2 = request.form.get('password_2')
if len(password) < 6:
error = "*Your password must have at least 6 characters."
elif password != password_2:
error = "*Passwords do not match."
else:
query = "UPDATE users SET password=%s WHERE email=%s"
cursor.execute(query, (password, user))
mydb.commit()
success = "Your password has been created!"
return render_template('change_password.html')