AttributeError: 'dict' object has no attribute 'get_reset_password_token' - python

I have been following the guide at https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-x-email-support to implement a password reset feature in my Flask app.
My error is:
Traceback (most recent call last):
File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 2525, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1822, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1820, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1796, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "C:\Users\David PC\Desktop\VS Code Python\Flask Site\app.py", line 691, in passwordreset
EmailSender(form.email.data, "Password reset", {"url": url_for("reset_password", token=user.get_reset_password_token(), _external=True)}, 6)
AttributeError: 'dict' object has no attribute 'get_reset_password_token'
My route view is:
#app.route('/passwordreset', methods=['GET', 'POST'])
def passwordreset():
if current_user.is_authenticated:
return redirect(url_for('profile'))
form = ResetPasswordRequestForm()
if form.validate_on_submit():
user = mycol.find_one({"email": form.email.data})
if user:
EmailSender(form.email.data, "Password reset", {"url": url_for("reset_password", token=user.get_reset_password_token(), _external=True)}, 6)
return redirect(url_for('homepage'))
flash('If an account with this email was registered please check your email.')
return render_template('reset_password_request.html', title='Reset Password', form=form)
And my User class is:
class User(UserMixin):
def __init__(self, user_json):
self.user_json = user_json
def get_id(self):
object_id = self.user_json.get('_id')
return str(object_id)
def get_reset_password_token(self, expires_in=600):
return jwt.encode(
{'reset_password': self.id, 'exp': time() + expires_in},
app.config['SECRET_KEY'], algorithm='HS256')
#staticmethod
def verify_reset_password_token(token):
try:
id = jwt.decode(token, app.config['SECRET_KEY'],
algorithms=['HS256'])['reset_password']
except:
return
return User.query.get(id)
I have a sneaking suspicion I am missing something basic but I cannot seem to figure it out. Any help would be appreciated!

As noted by #Matiss, I had to wrap my pymongo DB query in my User class.
user = User(mycol.find_one({"email": form.email.data}))
This was the fix to the attribute error.

Related

Flask TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement [duplicate]

This question already has answers here:
Flask view return error "View function did not return a response"
(3 answers)
Closed 1 year ago.
#app.route('/login',methods=["GET","POST"])
def login():
if request.method == "POST":
email = request.form['email']
password = request.form['password'].encode('utf-8')
cur = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
cur.execute("SELECT * FROM users WHERE email=%s",(email,))
user = cur.fetchone()
cur.close()
if len(user) > 0:
if bcrypt.hashpw(password, user['password'].encode('utf-8')) == user['password'].encode('utf-8'):
session['name'] = user['name']
session['email'] = user['email']
return render_template("home.html")
else:
return "Error password or user not match"
else:
return render_template("login.html")
this is my login part in flask program. but when I try to log in, this error pops out.
TypeError
TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.
Traceback (most recent call last)
File "C:\ProgramData\Anaconda3\Lib\site-packages\flask\app.py", line 2464, in __call__
return self.wsgi_app(environ, start_response)
File "C:\ProgramData\Anaconda3\Lib\site-packages\flask\app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "C:\ProgramData\Anaconda3\Lib\site-packages\flask\app.py", line 1867, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\ProgramData\Anaconda3\Lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "C:\ProgramData\Anaconda3\Lib\site-packages\flask\app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "C:\ProgramData\Anaconda3\Lib\site-packages\flask\app.py", line 1953, in full_dispatch_request
return self.finalize_request(rv)
File "C:\ProgramData\Anaconda3\Lib\site-packages\flask\app.py", line 1968, in finalize_request
response = self.make_response(rv)
File "C:\ProgramData\Anaconda3\Lib\site-packages\flask\app.py", line 2097, in make_response
raise TypeError(
TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.
TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.
What does it means? other solutions are said it is because there's no return but I have returns
and even on a same indentation.
HELP ME!
You have to add response for each else condition in your code.
check below code :
from flask import jsonify
if len(user) > 0:
if bcrypt.hashpw(password, user['password'].encode('utf-8')) == user['password'].encode('utf-8'):
session['name'] = user['name']
session['email'] = user['email']
return render_template("home.html")
else:
return jsonify({"message":"Error password or user not match"})
else:
return jsonify({"message":"user not available"})
if len(user) > 0:
if bcrypt.hashpw(password, user['password'].encode('utf-8')) == user['password'].encode('utf-8'):
session['name'] = user['name']
session['email'] = user['email']
return render_template("home.html")
else:
return "Error password or user not match"
You need to return something in case the password does not match. Your if-block will only catch the case where no users are found.

Trying to hash a username and store it in DB using hashlib and flask

I am trying to hash a username, using hashlib, that I am getting from a form before committing it to a DB.
Code:
#auth.route('/sign-up', methods=['GET', 'POST']) #enabling POST request method on this page
def signup(): #create function to handle route
if request.method == 'POST': #if POSTING to server get data from form
username = request.form.get('username')
password1 = request.form.get('password1')
password2 = request.form.get('password2')
email = request.form.get('email')
#checks database for already existing account name and email
account = Account.query.filter_by(username=username).first()
if account:
flash('User already exists', category='error')
emailCheck = Account.query.filter_by(email=email).first()
if emailCheck:
flash('User already exists', category='error')
#perform some data checks
if len(email) < 4:
flash('Email is too short', category='error')
elif password1 != password2:
flash('Passwords do not match', category='error')
elif len(username) < 5:
flash('Username too short', category='error')
else:
#hash the username
username = hashlib.sha256(username.encode('utf-8'))
#create new user using User schema
new_account = Account(email=email, username=username, password=generate_password_hash(password1, method='sha256')) #user name and password are created and hashed before being stored.
db.session.add(new_account)
db.session.commit()
login_user(new_account, remember=True)
flash('Account Created', category='success')
return redirect(url_for('views.getuserinfo'))
return render_template("signup.html", user=current_user)
I am able to get the username and commit without hashing it. However once I use this line:
username = hashlib.sha256(username.encode('utf-8'))
It gives me the error: Error binding parameter 2 - probably unsupported type. Hashing and storing a value should be relatively easy so I am really not sure where I am going wrong. I followed the documentation on hashlib as well.
Any help would be appreciated.
EDIT: After playing around with it for a bit I managed to come up with a different error. I changed my hashing code to look like this:
hashedusername = hashlib.sha256(str('username'))
#create new user using User schema
new_account = Account(email=email, username=hashedusername, password=generate_password_hash(password1, method='sha256'))
Traceback:
Traceback (most recent call last):
File "/home/nicholas/.local/lib/python3.7/site-packages/flask/app.py", line 2464, in __call__
return self.wsgi_app(environ, start_response)
File "/home/nicholas/.local/lib/python3.7/site-packages/flask/app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "/home/nicholas/.local/lib/python3.7/site-packages/flask/app.py", line 1867, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/nicholas/.local/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/home/nicholas/.local/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/home/nicholas/.local/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/nicholas/.local/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/nicholas/.local/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/home/nicholas/.local/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/home/nicholas/.local/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/nicholas/Documents/CY 324 Web App/website/auth.py", line 71, in signup
hashedusername = hashlib.sha256(str('username'))
TypeError: Unicode-objects must be encoded before hashing

anyone know how to solve this ? " TypeError: a bytes-like object is required, not 'int' "

i wanted to fetch the data(blob) to download it from my database. I'm facing some error with bytes TypeError: a bytes-like object is required, not 'int'. I had been working on this for so long.
#app.route("/search", methods=['GET','POST'])
def search():
if request.method == "POST":
if not request.form.get("search"):
return error("error")
conn= sqlite3.connect("YTD2.db")
cursor = conn.cursor()
c = cursor.execute("SELECT * FROM my_table")
id = db.execute("SELECT id FROM my_table WHERE name=:name", \
name=request.form.get("search"))
# print(data)
for sub in id:
for key in sub:
sub[key] = int(sub[key])
for x in c.fetchall():
data_v=x[1][sub[key]]
break
conn.commit()
cursor.close()
conn.close()
# print(c)
return send_file(BytesIO(data_v), attachment_filename='download.pdf', as_attachment=True)
return redirect("home.html")
here is the error
DEBUG:cs50:SELECT id FROM my_table WHERE name='网格.pdf'
ERROR:app:Exception on /search [POST]
Traceback (most recent call last):
File "e:\programme\python\lib\site-packages\flask\app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "e:\programme\python\lib\site-packages\flask\app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "e:\programme\python\lib\site-packages\flask\app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "e:\programme\python\lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "e:\programme\python\lib\site-packages\flask\app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "e:\programme\python\lib\site-packages\flask\app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\Win X\Desktop\CS50 FP\TRY\Download Prob\app.py", line 176, in search
return send_file(BytesIO(data_v), attachment_filename='download.jpg', as_attachment=True)
TypeError: a bytes-like object is required, not 'int'
INFO:werkzeug:127.0.0.1 - - [27/Jun/2020 23:44:12] "POST /search HTTP/1.1" 500 -
anyone else have some good algorithm to flask blob from database and store as PDF, i had been working on this using flask_wtf
here this is the new update that how i store my blob file
#app.route('/upload', methods=["GET", "POST"])
#login_required
def upload():
form = UploadForm()
if request.method == "POST":
if form.validate_on_submit():
file_name = form.file.data
database(name=file_name.filename, data=file_name.read())
return render_template("upload.html", form=form)
return render_template("upload.html", form=form)
class UploadForm(Form):
file = FileField()
submit = SubmitField("submit")
download = SubmitField("download")
def database(name, data):
db.execute("INSERT INTO my_table(name, data) VALUES (?,?)",(name,data))

How to make Flask unit test to test login

main.py
#app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
verify(username, password)
def verify(name, psw):
data = User.query.filter_by(username=name, password=psw).first()
if data is not None:
session['logged_in'] = True
else:
session['logged_in'] = False
return redirect(url_for('home', num=None))
test.py
class UnitTest(unittest.TestCase):
def setUp(self):
self.app = Flask(__name__)
app.config['SECRET_KEY'] = '123'
self.client = self.app.test_client()
self.app = app.test_client()
def test_login(self):
with app.test_client() as client:
client.post('/login', data=dict(username='s', password='s'))
with client.session_transaction() as sess:
assert sess['logged_in']
It passes test but there is some error.
[2020-05-25 05:48:58,606] ERROR in app: Exception on /login [POST]
Traceback (most recent call last):
File "C:\Users\queen\AppData\Local\Programs\Python\Python38-32\lib\site-packages\flask\app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\queen\AppData\Local\Programs\Python\Python38-32\lib\site-packages\flask\app.py", line 1953, in full_dispatch_request
return self.finalize_request(rv)
File "C:\Users\queen\AppData\Local\Programs\Python\Python38-32\lib\site-packages\flask\app.py", line 1968, in finalize_request
response = self.make_response(rv)
File "C:\Users\queen\AppData\Local\Programs\Python\Python38-32\lib\site-packages\flask\app.py", line 2097, in make_response
raise TypeError(
TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.
How can I fix this?

TypeError: Expecting a string- or bytes-formatted key when using Flask-JWT

I have a question about flask python.
I tried learning how to build a web using flask, and there is some error. In this case I am using mongoengine as database and JWT(Json Web Token) and the alert error is like this: "TypeError: Expecting a string- or bytes-formatted key"
192.168.100.26 - - [22/Nov/2016 22:50:08] "POST /auth HTTP/1.1" 500 -
Traceback (most recent call last):
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 2000, in __call__
return self.wsgi_app(environ, start_response)
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1991, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1567, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1988, in wsgi_app
response = self.full_dispatch_request()
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1641, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1544, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1639, in full_dispatch_request
rv = self.dispatch_request()
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1625, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/def/pr/flask/flask_deeper/test/routes/auth.py", line 26, in auth
access_token = _jwt.jwt_encode_callback(identity)
File "/usr/local/lib/python2.7/dist-packages/flask_jwt/__init__.py", line 70, in _default_jwt_encode_handler
return jwt.encode(payload, secret, algorithm=algorithm, headers=headers)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 56, in encode
json_payload, key, algorithm, headers, json_encoder
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jws.py", line 98, in encode
key = alg_obj.prepare_key(key)
File "/usr/local/lib/python2.7/dist-packages/jwt/algorithms.py", line 116, in prepare_key
raise TypeError('Expecting a string- or bytes-formatted key.')
TypeError: Expecting a string- or bytes-formatted key.
I thought the error was at this.
models/user.py
#staticmethod
def jwt_handler(token):
if not User.objects(token=token):
raise JWTError("Bad bad bad bad")
secret = str(current_app.config["JWT_SECRET_KEY"])
algorithm = str(current_app.config["JWT_ALGORITHM"])
options = {
'verify_' + claim: True
for claim in verify_claims
}
options.update({
'require_' + claim: True
for claim in required_claims
})
decode = jwt.decode(token, secret, options=options, algorithms=[algorithm])
return decode
#staticmethod
def authenticate(username, password):
user = User.objects(username=username)
if len(user) == 0:
return None
user = user[0]
user["id"] = str(user["id"])
if crypt.verify(password, user.password):
return user
return user
routes/user.py
def auth():
username = request.form.get("username")
password = request.form.get("password")
if not username:
raise BadRequest("Userna doesn't exists")
user = user_ctrl.read(username)
identity = _jwt.authentication_callback(username, password)
if identity:
access_token = _jwt.jwt_encode_callback(identity)
identity.update(push__token=access.decode("utf8"))
return _jwt.auth_response_callback(access_token, identity)
else:
raise JWTError("Bad bad bad very bad")
config.py
import os
from test.models import db
class Config(object):
db_name = os.getenv('MONGODB_NAME', 'third')
db_host = os.getenv('MONGODB_HOST', '127.0.0.1')
db_port = os.getenv('MONGODB_PORT', '5000')
JWT_SECRET_KEY = 'test123'
JWT_ALGORITHM = 'SH256'
JWT_AUTH_ENDPOINT = 'jwt'
JWT_AUTH_USERNAME_KEY = 'username'
JWT_AUTH_PASSWORD_KEY = 'password'
http.py
import logging.config
import jwt
from flask_jwt import JWT
from flask import Flask
from test import routes
from test.models import db, User
_jwt = JWT(authentication_handler=User.authenticate, identity_handler=User.identity)
_jwt.jwt_decode_callback=User.jwt_handler
def create_app(config):
app = Flask(__name__.split(',')[0])
app.register_blueprint(routes.user.bp)
app.register_blueprint(routes.auth.bp)
db.init_app(app)
_jwt.init_app(app)
return app
You have defined the configuration is config.py but have not added the configuration object to your flask app. Therefore, keys such as JWT_SECRET_KEY are not in your app config.
Flask-JWT's default_handler expects those values (Copied in case source changes)
def _default_jwt_decode_handler(token):
secret = current_app.config['JWT_SECRET_KEY']
algorithm = current_app.config['JWT_ALGORITHM']
leeway = current_app.config['JWT_LEEWAY']
In your case as that is not set, it returns None and trips the algorithms.py (which expects a string key).
Therefore, during your app initialization in http.py, you must add a call to app.config.from_object. Maybe something like this
def create_app(config):
app = Flask(__name__.split(',')[0])
# Edit the following to point it to your Config class
app.config.from_object(config.Config)
app.register_blueprint(routes.user.bp)
app.register_blueprint(routes.auth.bp)
db.init_app(app)
_jwt.init_app(app)
return app
On a side note, the name of JWT_ALGORITHM should be HS256 rather than SH256 (Although it doesn't matter as HS256 is the default and will be chosen since SH256 is not a valid algorithm)

Categories