I am implementing a basic web scraping webapp that requires registration and login to use the features. I am now facing an issue in the login [see below the code, please] when trying to decrypt a pwd from the mongodb database. I cannot pass the correct value in the sha512_crypt function, resulting in errors such as: '''ValueError: not a valid sha512_crypt hash'''
I have extensively researched the problem and tried multiple things, but still issues: What can you suggest? Thanks
#route for the signin page
#app.route("/signin", methods = ['GET', "POST"])
def signin():
form = Signin(request.form)
if request.method == 'GET': # make sure the method used is define above
return render_template('signin.html', form = form), print("you are under the signin page now, well done mrbacco")
if request.method == 'POST' and form.validate():
# the following are the data from the init form
email = form.email.data
password_form = form.password.data
print("these are the email and password inserted", email, password_form)
user_db = mycol_u.find_one({'email' : email})
for key, value in user_db.items():
print ("these are the fields in the db ", key, value)
if user_db is None:
flash("No USER FOUND!!, please try again", "danger")
return render_template('signin.html', form = form), print("user not found, flashed a message on the web page")
if sha512_crypt.verify(user_db['password'], password_form):
flash("You are now logged in", "success")
return redirect(url_for("home.html",form = form))
else:
flash("credential not correct, please try again", "danger")
print("redirecting to scraping page")
return render_template('signin.html', form = form)
Related
I'm particularly new to django and still in the learning process.
I have this code where it would have the user input any text into the field and once the user hits the submit button it would grab the text they inputted and look for it in the django database for that item. It's able to do what I want, except when there are no users with that username. I don't know where I would do an if statement, or a work around for that.
views.py
from .forms import RequestPasswordResetForm
from django.contrib.auth.models import User
def request_password(request):
next = request.POST.get('next', '/')
if request.method == "POST":
user = request.POST['passUsername']
users = User.objects.get(username=user)
form = RequestPasswordResetForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Request has been sent! Admin will be with you shortly.')
return HttpResponseRedirect(next)
you can handle it within the try catch block where get method will raise exception (DoesNotExist) if then object is not present in the DB.
def request_password(request):
next = request.POST.get('next', '/')
try:
if request.method == "POST":
username = request.POST['passUsername']
user = User.objects.get(username=username)
form = RequestPasswordResetForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Request has been sent! Admin will be with you shortly.')
return HttpResponseRedirect(next)
except User.DoesNotExist:
messages.error(request, 'Invalid Username')
I would use an if statement alongside the function 'exists()'. It would look something like this:
username = request.POST['passUsername']
if (User.objects.exists(username = username):
user = User.objects.get(username = username)
else:
# Throw error
Also, be careful with your variable naming :)
I am making an app in the flask using firebase authentication with the pyrebase library.
following is the code I use for authentication...
#app.route('/register', methods=['GET', 'POST'])
def register_page():
form = RegisterForm()
if form.validate_on_submit():
data = {
"username": form.username.data,
"email_address": form.email_address.data,
"password_hash": form.password.data
}
db.collection('users').document(form.username.data).set(data)
def register():
email = form.email_address.data
password = form.password.data
confirm_pass = form.confirm_password.data
if password == confirm_pass:
sign_in = auth.create_user_with_email_and_password(email, password)
auth.send_email_verification(sign_in['idToken']) # for email verification
print("email verification sent")
register()
return redirect(url_for('market_page'))
if form.errors != {}: # if no errors occur from validators
for err_msg in form.errors.values():
print(f'there was an error creating the user {err_msg}')
return render_template('register.html', form=form)
I read most of the firebase documentation but I wasn't able to find any answer.
It looks like there is an emailVerified in the result from calling the get_account_info function.
I find it easiest to find this type of information by look at the Pyrebase auth implementation and then finding the Google documentation for the REST API that is invoked, which is getAccountInfo here.
I am pograming a simple web app with flask and am trying to implement a login process. My /register seems to work fine with username and hashed pwd being correctly inserted in my database when registering. However, when it comes to the login part I can't seem to be comparing the username stored in MySQL and the one from resquest.form.get, I get the following error message : TypeError: Object of type Cursor is not JSON serializable.
Here is my code:
#app.route('/login', methods=["GET", "POST"])
def login():
db = sqlite3.connect("users.db")
c = db.cursor()
if request.method== "POST":
username = request.form.get("username")
password = request.form.get("password")
pwd_hash = sha256(password.encode('utf-8')).hexdigest()
# Ensure username was submitted
if not request.form.get("username"):
flash("must provide username", "error")
return redirect("/login")
# Ensure password was submitted
elif not request.form.get("password"):
flash("must provide password", "error")
return redirect("/login")
# Query database for username
if (c.execute("SELECT COUNT(*) FROM users WHERE username=:username", {"username" : username}).fetchall()[0][0] == 0):
flash("invalid username", "error")
return redirect("/login")
if (c.execute("SELECT password FROM users WHERE(username=:username)", {"username": username}).fetchall()[0][0] != pwd_hash):
flash("invalid password", "error")
return redirect("/login")
# Remember which user has logged in
session["user_id"] = c.execute("SELECT username FROM users WHERE(:username=:username)", {"username": username})
# Redirect user to home page
return redirect("/")
# User reached route via GET (as by clicking a link or via redirect)
else:
return render_template("login.html")
Any idea ?
You didn't fetch the row here:
session["user_id"] = c.execute("SELECT username FROM users WHERE(:username=:username)", {"username": username})
c.execute() returns the cursor object, you can't put that into a session variable. It should be
session["user_id"] = c.execute("SELECT username FROM users WHERE(:username=:username)", {"username": username}).fetchone()[0]
But there doesn't seem to be a reason to do another query here. It's just going to return the same username that's in the parameter. So just write
sesion["user_id"] = username
BTW, it's generally considered poor security design to distinguish invalid usernames from invalid passwords. Just do a single query with both the username and password. If it fails, report "Invalid username or password".
if (c.execute("SELECT COUNT(*) FROM users WHERE username=:username AND password=:password", {"username" : username, "password": pwd_hash}).fetchone()[0] == 0):
flash("invalid username or password", "error")
return redirect("/login")
Other issues:
You're assigning variables from the request.form parameters before you check that they were actually filled in.
If you only need one row, use fetchone() instead of fetchall()[0].
#app.route("/login", methods=["GET", "POST"])
def login():
"""Log user in"""
# Forget any user_id
session.clear()
# User reached route via POST (as by submitting a form via POST)
if request.method == "POST":
# Ensure username was submitted
if not request.form.get("username"):
return apology("must provide username", 403)
# Ensure password was submitted
elif not request.form.get("password"):
return apology("must provide password", 403)
# Query database for username
rows = db.execute("SELECT * FROM users WHERE username = :username",
username=request.form.get("username"))
# Ensure username exists and password is correct
if len(rows) != 1 or not check_password_hash(rows[0]["hash"], request.form.get("password")):
return apology("invalid username and/or password", 403)
# Remember which user has logged in
session["user_id"] = rows[0]["id"]
# Redirect user to home page
return redirect("/")
# User reached route via GET (as by clicking a link or via redirect)
else:
return render_template("login.html")
return apology("TODO")
when i run the above code for pset9 finance it is giving this error
TypeError: 'int' object is not subscriptable
As i understand the problem is in line 192:
session["user_id"] = rows[0]["id"]
Can anybody put forward his/her opinion?
From some of the comments, the error is coming from register after this line executes:
results = db.execute("INSERT INTO users (username, hash) VALUES (:username, :password)", username = username, password = hashed)
From the Hints section of the spec:
If str is an INSERT, and the table into which data was inserted
contains an autoincrementing PRIMARY KEY, then execute returns the
value of the newly inserted row’s primary key.
Therefore this line session["user_id"] = results[0]['id'] gives an error because results is an integer.
----ORIGINAL ANSWER -----
Actually, the problem is in index. One can expect login from the distro code to work. login is redirected to "/" (index function).
When you run the code locally, it will produce the same error when logging in a registered user. The traceback in the flask terminal should direct your attention to:
user = db.execute("SELECT * FROM users WHERE id = :id", id = session["user_id"][0]["cash"])
Notice, it is trying to set id to session["user_id"][0]["cash"]. session["user_id"] is an int. Double check the syntax.
I'm writing a web app where you can make a product request through a form before logging in (or signing up). It's kind of a "try it" mode to get the abandon rate lower. When we were putting the signup first -- we were way too many people abandoning the service because they had to make an account first. This way we're drawing people committing some effort before they have to signup.
In any case, I am having trouble getting this pattern working. I'm using the flask-login extension. I have a view that renders my product request form and redirects to the login view if the user is not logged in:
#app.route('/customer/gift_request', methods=['GET', 'POST'])
# Note login is NOT required for this.
def gift_request():
form = GiftRequestForm()
error = None
if form.validate_on_submit():
if current_user.get_id():
new_gift_request = GiftRequest(
current_user.id,
form.giftee_name.data,
form.giftee_age.data,
int(form.giftee_sex.data),
form.event.data,
form.event_date.data,
float(form.budget.data))
try:
db.session.add(new_gift_request)
db.session.commit()
flash("You have successfully submitted a gift request! ",'success')
return redirect(url_for('customer_home'))
except:
error = "Error creating gift request"
else:
return redirect(url_for('login', next=request.url)
return render_template('customer_portal/gift_request.html', form=form, error=error)
My login view is the following:
#app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
error = None
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user:
if bcrypt.hashpw(form.password.data.encode('utf-8'), user.password.encode('utf-8')) == user.password:
login_user(user)
flash('User {} logged in'.format(current_user.email), 'success')
# Handle the next URL
next_url = request.args.get('next')
if next_url is not url_for('gift_request'):
return abort(400)
return redirect(next_url or url_for('customer_home'))
else:
error = "Incorrect password"
else:
error = "User not found"
return render_template("user/landing_page.html",
login_form=form,
register_form=RegisterForm(),
error=error,
show_login_modal=True,
show_register_modal=False)
Note that my login is rendered as a modal window on my landing page. In any case, I have no idea how to keep my gift request form data around after the login. How do I pass that around? I've tried a bunch of stuff -- like putting it in the request -- but that feels hacky (and potentially insecure). Also, upon login submission -- that form data is gone. It's never passed to the login template, so i guess it just disappears. I've searched the internet, but I can't seem to find a pattern to do this.
Also, the login is just a piece of this -- if the person that's filling out the gift request doesn't have a login, then I want to take them to the registration page to make an account. But I figure if I figure this out -- I can take the same pattern and extend it to that.
I think you may need to use a session. It would look something like this:
if form.validate_on_submit():
if current_user.get_id():
session['new_gift_request'] = GiftRequest(
current_user.id,
form.giftee_name.data,
form.giftee_age.data,
int(form.giftee_sex.data),
form.event.data,
form.event_date.data,
float(form.budget.data))
I have used this many times, and I've never had an issue. If you want the form data to hang around without a session, then you have to keep track of it and pass it to every subsequent template.
UPDATE
After re-reading your code it appears that if the current user is not logged in, you aren't saving the form data at all. Here is a slight change (obviously make sure you import session from flask):
#app.route('/customer/gift_request', methods=['GET', 'POST'])
# Note login is NOT required for this.
def gift_request():
form = GiftRequestForm()
error = None
if form.validate_on_submit():
if current_user.get_id():
new_gift_request = GiftRequest(
current_user.id,
form.giftee_name.data,
form.giftee_age.data,
int(form.giftee_sex.data),
form.event.data,
form.event_date.data,
float(form.budget.data))
try:
db.session.add(new_gift_request)
db.session.commit()
flash("You have successfully submitted a gift request! ",'success')
return redirect(url_for('customer_home'))
except:
error = "Error creating gift request"
else:
session['giftee_name'] = form.giftee_name.data
session['giftee_age'] = form.giftee_age.data
session['giftee_age'] = form.giftee_age.data
session['giftee_sex'] = int(form.giftee_sex.data)
session['event'] = form.event.data
session['event_date'] = form.event_date.data
session['budget'] = float(form.budget.data)
return redirect(url_for('login', next=request.url)
return render_template('customer_portal/gift_request.html', form=form, error=error)