How to use recaptcha without Flask-WTF - python

I have been making a file sharing website for quite a while and I want to implement recaptcha when people register to the website. The problem is that I can't use Flask-WTF because I will have to change a lot of my code (I have been programming without it).
I have found this Flask recaptcha that doesn't include the use of Flask-WTF but I can't seem to make it work (it doesn't show the recaptcha itself):
https://github.com/mardix/flask-recaptcha
I have followed step by step and still, it doesn't work. The only thing that I didn't do is the config.
EDIT:
The captcha is not working. Everytime that I enter the right info for the registration and mark the captcha, it says that the username/password is incorrect. If I don't mark it, it does the same.
Here is the captcha code (the others worked before):
recaptcha = ReCaptcha(app=app)
if recaptcha.verify() is False:
flash('Captcha is incorrect')
return redirect(url_for('register'))
<div id="captcha"">
{{ recaptcha }} - HTML PART
</div>
EDIT: After getting help from Nurzhan, I have changed the code and the captcha always returns false, no matter what.

You didn't try the config, but you need to indicate the keys in order to make your recaptcha work. These 2 options are NOT optional in the config:
RECAPTCHA_SITE_KEY : Public key
RECAPTCHA_SECRET_KEY: Private key
Set them with proper values and it see if it works.
EDIT:
It's working now. This is app.py:
import requests
import json
from flask import Flask, render_template, request
from flask_recaptcha import ReCaptcha
app = Flask(__name__)
app.config.update({'RECAPTCHA_ENABLED': True,
'RECAPTCHA_SITE_KEY':
'site_key',
'RECAPTCHA_SECRET_KEY':
'secret_key'})
recaptcha = ReCaptcha(app=app)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/submit', methods=['GET', 'POST'])
def submit():
print('SUBMIT CALLED')
username = ''
password = ''
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
print(request.form)
if username == 'username' and password == 'password':
print('CREDENTIALS ARE OK')
r = requests.post('https://www.google.com/recaptcha/api/siteverify',
data = {'secret' :
'secret_key',
'response' :
request.form['g-recaptcha-response']})
google_response = json.loads(r.text)
print('JSON: ', google_response)
if google_response['success']:
print('SUCCESS')
return render_template('profile.html')
else:
# FAILED
print('FAILED')
return render_template('index.html')
# if recaptcha.verify():
# # SUCCESS
app.run(debug=True)
This is the index.html page:
<!DOCTYPE html>
<html>
<head>
<script src='https://www.google.com/recaptcha/api.js'></script>
</head>
<body>
<h1>Flask Recaptcha</h1>
<p>Flask Recaptcha Test</p>
<form method="post" action="/submit">
Username:<br>
<input type="text" name="username"><br>
Password:<br>
<input type="password" name="password">
{{ recaptcha }}
<input type="submit" value="Submit">
<div class="g-recaptcha" data-sitekey="site_key"></div>
</form>
</body>
</html>
This is the profile.html page if you pass the validation:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>Profile page</h1>
<p>Registration is ok</p>
</body>
</html>
I couldn't make recaptcha.verify() work. In the official docs of Google Recaptcha it is stated that you need to send a post request to google recaptcha api separately after the client submits your form with your secret_key and g-recaptcha-response which you receive when user puts a tick in recaptcha.
Note that this is just an example code. You need to add your own site_key and secret_key to the app.py and index.html and also add a proper checking of user credentials for the registation like double entering password etc.

Related

Struggling to get data from POST request data from a HTML form with flask

I've been working on a website back-end using the python library flask but whenever I try and get the form data from a POST request (as it needs to be sent securely) I always get a 405 - Method not allowed error. After the submission of a user's email and password at the moment its just meant to send them to a very basic html page with their name and email on it (it's easier to explain with the code).
python code:
# reroutes user to login page html file
#app.route("/")
#app.route("/login", methods=["GET", "POST"])
def reroute_login():
return flask.render_template("login.html")
# returns the login page html file
#app.route("/login", methods=["GET", "POST"])
def login():
if flask.request.method == "POST":
print("Reached")
email = flask.request.form["email"]
password = flask.request.form["password"]
print(email, password)
return flask.redirect(flask.url_for("user", usr=email))
else:
return flask.render_template("login.html")
#app.route("/<usr>")
def user(usr):
return f"<h1>{usr}</h1>" # here is that very basic html page I mentioned but it won't reroute to this page
login.html:
<form action="#" method="post">
<h1>Login</h1>
<input type="text" name="email" placeholder="Email">
<input type="password" name="password" placeholder="Password">
Forgot Your Password
<input type="submit" class="button1" value="submit" />
</form>
Please just know I'm very new to Flask and back-end web dev as a whole but any kind of help would be much appreciated :)
Try changing action in login.html from # to /login .
And you have defined multiple routes with same name.
Remove the first route to login.

Basic flask form handling

I am trying to create a basic form in Flask that will take in the input, manipulate it and then return the output. I am running into the issue that when I am running the terminal and trying to make my app work on the http://127.0.0.1:5000/ server, the files are not visible. Not sure where the bug is?
This is how I have my files organized:
/Users/eas/Desktop/grota/templates/index.html
/Users/eas/Desktop/grota/templates/age.html
/Users/eas/Desktop/grota/app.py
This is the app.py file
from flask import Flask, render_template,request
app = Flask(__name__)
#app.route('/send',methods = ['GET','POST'])
def send():
if request.method == 'POST':
age = request.form['age']
return render_template('age.html',age=age)
return render_template('index.html')
if __name__ == '__main__':
app.run()
This is the index.html file
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
</head>
<body>
<h1>How old are you?</h1>
<form method="POST" action = "/send">
<div class = "form-group">
<input type="text" name = "age">
</div>
<input class="btn btn-primary" type="submit" value="submit">
</form>
</body>
</html>
This is the age.html file
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>Your age is{{age}}</h1>
</body>
While looking for a problem, which I try to solve I found your question. For a solution that includes full code (with py and 2 HTML files) you can see my repl.it : https://repl.it/#AlperenAtik/NaturalShortActivecell#main.py
The problems are:
In the first function, you routed your loop to "/send" page. This is why your send page did not appear. The route of the first function needs to be "/"
In the index file, the source route was shown as '/send'. Whenever I changed it to / the script worked without a problem
The other commentators already mentioned your triggering function has an indentation mistake. When host and port added appropriately, your script would work.
for ones who love the harder way- seeing things in stackoverflow- not in action, I am adding the codeblocks. Enjoy.
for main.py
from flask import Flask, render_template,request
app = Flask(__name__)
#app.route('/',methods = ['GET','POST'])
def send():
if request.method == 'POST':
age = request.form['age']
return render_template('age.html',age=age)
return render_template('index.html')
if __name__ == '__main__':
app.run(host = '0.0.0.0', port = 8080
I left the host as '0.0.0.0' and port as 8080. If you are running Python on a terminal, you may try (host = '127.0.0.1', port:5000').
for templates/index.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
</head>
<body>
<h1>How old are you?</h1>
<form method="POST" action = "/">
<div class = "form-group">
<input type="text" name = "age">
</div>
<input class="btn btn-primary" type="submit" value="submit">
</form>
</body>
</html>
for templates/age.html
<html>
<head>
</head>
<body>
<h1>Your age is {{age}}</h1>
</body>
You did not set the root route.
Or you open http://127.0.0.1:5000/send
Or you could use this quick and dirty fix (as you see in decorators now both / and /send are taken into account):
from flask import Flask, render_template,request
app = Flask(__name__)
#app.route('/',methods = ['GET'])
#app.route('/send',methods = ['GET','POST'])
def send():
if request.method == 'POST':
age = request.form['age']
return render_template('age.html',age=age)
return render_template('index.html')
if __name__ == '__main__':
app.run()
If you do not handle the '/' route nothing will happen when you open http://127.0.0.1
If you explain more clearly what is the result that you want to obtain I can help better.
Try going here: http://127.0.0.1:5000/send
If that doesn't work, what error are you getting in either your console or in your browser?
EDIT:
I just tried it, and it worked. Try reloading the page in a new tab in your browser, and see if it still occurs. This error has to do with the naming of your inputs on the webpage and the way you index your form with request.form['age']

Flask: Is it possible to Mask a URL with variables?

I want to pass variables from a site to another.
This is no problem, as there are many ways to do it.
I'm struggling though, in how I can 'hide' these variables in the URL, and yet be able to get the values.
Ex.:
If I use 'request.args.get':
#page.route('/users', methods=['GET', 'POST'])
def users():
user = request.args.get('user')
return render_template('users.html', user=user)
When I click in the link, the URL generated is:
http://localhost:5000/users?user=john
My goal is to access the 'users' page, in the 'John' section, but what the user will see in the URL path is only http://localhost:5000/users
I was able to achieve my goal using:
window.history.pushState({"html":response.html,"pageTitle":response.pageTitle},"", "/users/");
I'm no Web Dev'er, just a Python/Flask enthusiast and know that 'window.history.pushState()' is meant for other purposes. I'm also aware that it a HTML5 Feature and not all browsers are compatible. But hey, it did the trick ;) .
Unless someone point out reasons I shouldn't be using this approach, this is my solution.
Thanks all for your time
If you'd only want to hide the variable name then you could use converters to create a route like 'users/<str:username>'. Your url would be http://localhost:5000/users/john.
Your can find the documentation here: http://exploreflask.com/en/latest/views.html#built-in-converters
Note that hiding the variables completely would mean, that your users would lose the ability to bookmark the page they are on. Additionaly if they bookmark /users anyways, you would have to catch the case that your variable is not sent or run into errors.
Post method can hide data and variables from URL. So you need to integrate it in your project. Here is an example.
app.py:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/users', methods=['GET', 'POST'])
def show_users():
if request.method == 'POST':
username = request.form.get("username", None)
return render_template('post_example.html', username = username)
else:
return render_template('post_example.html')
if __name__ == '__main__':
app.run(debug = True)
post_example.html:
<html>
<head></head>
<body>
{% if username %}
Passed username: {{ username }}
{% endif %}
<form action="/users" method="post">
Username: <input type="text" name="username">
<input type="submit" name="submit" value="Submit">
</form>
</body>
</html>
Output:
You can check the HTTP methods in Flask official documentation here

How to pass your POST to another URL using Flask

I am trying to get some phrase from the user, and when he/she will press "submit" i want to redirect him/her to another page with his/her name, using Flask. Here is my Python code:
from flask import Flask, redirect, render_template, request, session, url_for
app = Flask(__name__)
#app.route("/", methods = ["POST", "GET"])
def login():
if request.method == "POST":
user = request.form["name"]
return redirect(url_for("success", name=user))
else:
return render_template("login.html")
#app.route("/success", methods = ["POST", "GET"])
def success():
user = request.form.get('name')
return render_template("success.html", name=user)
if __name__ == "__main__":
app.run("0.0.0.0", 8080)
So when i go to my site i am going to "else" branch and do: "render_template("login.html")". Then if i press submit i go into "if" where i am trying to redirect the user to "success.html". Here is my login.html:
<html>
<body>
<form action = "http://ide50-zahar-zagrava.cs50.io:8080/" method = "post">
<p>Enter Name:</p>
<p><input type = "text" name = "name" /></p>
<p><input type = "submit" value = "submit" /></p>
</form>
</body>
</html>
And succes.html:
<html>
<body>
<h1>Hello {{ name }}!</h1>
</body>
</html>
But insted of saying: "Hello " it says: "Hello None".
My main question is how to pass data from one page to another?
I am completely new at Flask and Python, so i can't figure out what's going wrong.
your action from form is wrong.you are sending the form to the index page. you could edit it like:
<form action="{{ url_for('success') }}" method="post">
this way, your form will be sent to the success method.

Flask forms not working

I just started learning Flask, and as a practice project I wanted to build a simple site that asks the user for their name, and greets them by their name on a new page. I have been unable to get a user's name through a form, and display it on a new page due to to a 'Bad Request' error. My code is below.
This is my index page with the form on it:
<!DOCTYPE html>
<html>
<head>
<title>Index</title>
</head>
<body>
<h1>Practice index page</h1>
<h2>Welcome to my practice web page.</h2>
<form action = "/firstname">
<p>What's your name?</p>
<input type = "text" name = "yourname"><br>
<input type = "submit" value = "Submit">
</form>
</body>
</html>
This is my application.py file:
from flask import Flask
from flask import render_template, request, redirect
app = Flask(__name__)
#app.route('/')
def hello_world():
return render_template('index.html')
#app.route('/firstname')
def first_name():
yourname = request.form['yourname']
return render_template('firstname.html', name = yourname)
And this is my firstname.html file:
<!DOCTYPE html>
<head>
<title>My name is</title>
</head>
<body>
<h1>Hello</h1>
<h2>Your name is {{name}}.</h2>
</body>
The index page loads fine. The firstname.html template also loads fine when the user's name is hardcoded, it's only when I get it from the form that problems arise.
I have been at this for a few hours, watched YT videos, Googled like crazy, and still can't figure out what's wrong, so I would really appreciate some help!
By default, a Flask route only answers to GET requests. You can tell the first_name view to answer both GET and POST requests like so:
#app.route('/firstname', methods=['GET', 'POST'])
def first_name():
yourname = request.form['yourname']
return render_template('firstname.html', name = yourname)
You also need to set the form method to POST so that yourname is sent as form data (readable in request.form) and not as a URL parameter (readable in request.args).
<form action = "/firstname" method="POST">
<p>What's your name?</p>
<input type = "text" name = "yourname"><br>
<input type = "submit" value = "Submit">
</form>
Use request.args['yourname'] instead of request.form['yourname']
Your index.html form is calling /firstname url with get method and name argument as query string
GET /firstname?yourname=Sunny HTTP/1.1
so you need to access query parameters with request.args['yourname'] & not with request.form['yourname']
You need to pass variables as dict and not directly.
Like this
#app.route('/firstname')
def first_name():
yourname = request.form['yourname']
return render_template('firstname.html', **{"name": "yourname"})

Categories