Restricting Access to a webpage using python flask stripe payment - python

I have a basic flask app, where I charge customers to view a page
from flask import Flask, render_template, request, redirect, url_for
import stripe
app = Flask(__name__)
pub_key = 'pk_test_999999999'
secret_key = 'sk_test_999999'
stripe.api_key = secret_key
#app.route('/')
def index():
return render_template('index.html', pub_key=pub_key)
#app.route('/thank_you')
def thanks():
return render_template('thanks.html')
#app.route('/pay', methods=['POST'])
def pay():
customer = stripe.Customer.create(
email=request.form['stripeEmail'],
source=request.form['stripeToken']
)
charge = stripe.Charge.create(
customer=customer.id,
amount=19900,
currency='usd',
description='The Product'
)
return redirect(url_for('thanks'))
if __name__ == '__main__':
app.run(debug=True)
What I am trying to do is restrict access to the thank you page I want no one to access the thank_you by typing the whole url in the browser only paying customers get to see the thank you page even if someone type the whole url www.example.com/thank_you it will redirect to you haven't paid please pay
I thought about adding a login page and having a decorator only login customers, I did not like the idea I don't like to create such a barrier I want no customer info to deal with just pay and access page
Any ideas on how to do that?

Try something like this. Remember this is not completely secure. As I don’t know how your ids and tokens are generated. But it’s just for the sake of simplicity.
If you want something more secure check flask sessions or flask login packages.
customers_payed = []
#app.route('/pay', methods=['POST'])
def pay():
customer = stripe.Customer.create(
email=request.form['stripeEmail'],
source=request.form['stripeToken']
)
charge = stripe.Charge.create(
customer=customer.id,
amount=19900,
currency='usd',
description='The Product'
)
# add customer id to list maybe hash it with its email and token you can make this as hard to guess as you want
customers_payed.append(str(customer.id) + request.form['stripeToken'])
return redirect(url_for('thanks', customer_id=customer.id, token= request.form['stripeToken']))
#app.route('/thank_you')
def thanks():
customer_id = requests.args.get(“customer_id”)
token = requests.args.get(“token”)
# check if its in the list, maybe pop it if customer is only allowed once
if (customer_id+token) in customers_payed:
return render_template('thanks.html')
else:
return redirect(url_for(“replace with error page”))

Related

Problem with Flask Blueprints, can´t remove the /home route, or app crashes

Hi there I'm creating a Flask web app and now I have to create more cruds, so I decided to modularize the app using Blueprints.
I have a Login function on main.py that allows me to enter the app interface:
app.route('/', methods=['GET', 'POST'])
def login():
# Output message if something goes wrong...
msg = ''
# Check if "username" and "password" POST requests exist (user submitted form)
if request.method == 'POST' and 'username' in request.form and 'password' in request.form:
# Create variables for easy access
username = request.form['username']
password = request.form['password']
# Check if account exists using MySQL
cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
cursor.execute(
'SELECT * FROM accounts WHERE username = %s AND password = %s', (username, password,))
# Fetch one record and return result
account = cursor.fetchone()
# If account exists in accounts table in out database
if account:
# Create session data, we can access this data in other routes
session['loggedin'] = True
session['id'] = account['id']
session['username'] = account['username']
# Redirect to home page
return redirect(url_for('client.home'))
else:
# Account doesnt exist or username/password incorrect
msg = 'Incorrect username/password!'
# Show the login form with message (if any)
return render_template('index.html', msg=msg)
It redirects to this Blueprint:
from flask import Blueprint, render_template
from flask import render_template, request, redirect, url_for, session, flash
from flask_mysqldb import MySQL
import MySQLdb.cursors
import re
from extension import mysql
client = Blueprint('client', __name__,
static_folder="../static", template_folder="../templates")
#client.route('/')
def home():
if 'loggedin' in session:
cur = mysql.connection.cursor()
cur.execute('SELECT * FROM cliente')
data = cur.fetchall()
# User is loggedin show them the home page
return render_template('home.html', username=session['username'], cliente=data)
# User is not loggedin redirect to login page
return redirect(url_for('login'))
It works just fine, but with a condition. On my main.py I also have this:
#app.route('/home')
def home():
pass
And this is the problem, I don't know why I should keep this route on my main.py because if I delete it my app crashes and throws me this error:
werkzeug.routing.BuildError
werkzeug.routing.BuildError: Could not build url for endpoint 'home'. Did you mean 'client.home' instead?
I have no idea why does this happens.
Why should I keep this route? or What I'm doing wrong?
Could you please give me a hand?
I've trying to change the redirect to using multiple routes, but if I delete that /home route.. my app crashes anyway.
in url_for look for the name of the function ie url_for('function_name', parameters)
so to avoid the crash better to change the name of main.py home function to something else.
Solved: I had one ref to Home on other file: Layout.html.
Just removed the ref and it's solved

Select Field in flask forms / flask_wtf is not changing unless I rerun the flask app

So I have a flask form that contains a select field with some options...
what I'm trying to achieve is that when a user chooses an option and submits the form, that option should disappear the next time someone tries to access the form. And it's working only if I stop the app.py and run it again. I want the form to refresh its content every time someone tries to access it without the need to rerun the app.
my flask form:
class ReserveForm(FlaskForm):
rooms = Room.query.filter_by(is_reserved=0, request=None)
roomList = []
for room in rooms:
roomList.append(room)
room = SelectField('Room', choices=roomList)
my code for the user view:
#app.route('/reserve', methods=['GET', 'POST'])
#login_required
def reserve():
form = ReserveForm()
if form.validate_on_submit():
student_id = current_user.id
room_num = int(form.room.data)
newRequest = ReserveRequest(student_id=student_id, room_num=room_num)
db.session.add(newRequest)
db.session.commit()
return '<h1>done<h1>'
return render_template('reserve.html', form=form)

How does Flask-login session works

Forgive me for my lack of knowledge. Am a complete newbie to flask and web technology concept.
I am in the process to build the login part of an app. After searching, I found flask login to be an option to use. After going through SQLAlchemy,Flask-login homepage, some blogs,tutorials,and going through questions on stack-oflow, tried to build a basic login part-code given below. I used SQLAlchemy, and database is POSTGres. This is just a start involving the login through email-password and session handling will involve more functions later.
In the code, I authenticate the user-id and password, and then assign corresponding UUID(primary key in User DB) from the database as a session variable, in order to create a session. Am I right in doing so?. In some 'stack-of' answers, it is mentioned that session-id is to be randomly generated after user authentication, and stored in a separate sessions table in database. Got confused.
I am passing UUID which is my primary key, as an 'id' for 'get_id' method. Is is right??
I tried implementing this code. However in chrome developement console, I see sessions, which dissappear after i logout.
import flask
from flask import Flask,render_template,request,url_for,redirect,session
from flask_sqlalchemy import SQLAlchemy
from flask_login import current_user, UserMixin, LoginManager, login_required, login_user,
logout_user
app = Flask(__name__)
db = SQLAlchemy(app)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:test#localhost/hw'
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
app.config['SECRET_KEY'] = 'thisissecret'
class User(UserMixin,db.Model):
__tablename__ = 'user'
__table_args__ = {'schema': 'logging'}
user_id = db.Column(db.VARCHAR,primary_key = True)
first_name = db.Column(db.VARCHAR)
last_name = db.Column(db.VARCHAR)
email = db.Column(db.VARCHAR)
contact_no = db.Column(db.VARCHAR)
status = db.Column(db.BOOLEAN)
loginpassword = db.Column(db.VARCHAR)
def get_id(self):
return str(self.user_id)
#login_manager.user_loader
def load_user(id):
try:
return User.query.get(id)
except:
return None
#app.route('/logedin',methods=['POST'])
def logedin():
session.pop('id', None)
em = request.form['email']
pwd = request.form['password']
usr = User.query.filter_by(email = em).first()
if usr:
if usr and usr.loginpassword == pwd:
login_user(usr,remember = False)
session['id'] = usr.user_id
return ('you r logged in')
else:
return '<h1>user not found</h1>'
else:
#return render_template('testlogin.html')
return '<h1>user not found</h1>'
#app.before_request
def check_logedin():
if not 'id' in session:
return render_template('testlogin.html')
#app.route('/login')
def login():
if current_user is_authenticated():
return redirect(url_for('home'))
else:
return render_template('testlogin.html')
#app.route('/logout')
#login_required
def logout():
logout_user()
session.pop('id', None)
return 'you are logged out'
#app.route('/home')
#login_required
def home():
return ('The current user is in.')
if __name__ == '__main__':
app.run(debug=True)
Apologies if some silly things. But I am unable to make out this session thing. Appreciate your help. Thanks in advance
You say that you "assign corresponding [user id] as a session variable", but some say "that session-id is to be randomly generated after user authentication, and stored in a separate sessions table in database".
Those two things are not in conflict. A session ID is a value sent to the user. It identifies session data. What is important is that the session data is hidden from the user and that a valid session ID cannot be guessed by a user.
What you are doing with flask.session is fine. You are placing a variable into a session and flask is taking care of the rest (giving only a random session ID to the user).
All you need to do is save user id in the session:
session['id'] = usr.user_id
and later read user id from the session
user_id = session.get('id')
Note that the user_id read this way may be None, meaning the user is not logged in.
This does not keep session data in a database, at least by default, but that probably is not important in your case. A good reason to keep data in a data base would be for example if you have a distributed system in which several servers are serving the same website, so the user might log in in one server, but then access another server.

How can I make this Flask App more DRY (connecting to many oauth APIs)?

I am connecting to several APIs (e.g. Twitter, GitHub, etc.) using Flask-oauthlib. Currently, I have each of these services as a separate blueprint. Within the view files for each of the services, there are the same three views: login, authorized, and get_token. The code right now is not very DRY, but I am struggling to understand how to centralize these views (more conceptually).
How could I make this more DRY? I would like to understand more conceptually rather than someone actually writing the code for me.
Below are a few items that may be helpful. This is the application structure:
- App
- Services
- FourSquare BP
- GitHub BP
- Twitter BP
- ...
- Other BPs
The generic API view would likely go under Services/api_views.py
Here is an example of one of the API Blueprint view files (Twitter).
twitter = Blueprint('twitter', __name__, url_prefix='/twitter')
bp = twitter
bp.api = TwitterAPI()
bp.oauth = bp.api.oauth_app
# Below here is the exact same for each file.
#bp.route('/')
#login_required
def login():
if current_user.get(bp.name, None):
return redirect(url_for('frontend.index'))
return bp.oauth.authorize(callback=url_for('.authorized', _external=True))
#bp.route('/authorized')
#bp.oauth.authorized_handler
def authorized(resp):
if resp is None:
flash(u'You denied the request to sign in.')
return redirect(url_for('frontend.index'))
if bp.oauth_type == 'oauth2':
resp['access_token'] = (resp['access_token'], '')
current_user[bp.name] = resp
current_user.save()
flash('You were signed in to %s' % bp.name.capitalize())
return redirect(url_for('frontend.index'))
#bp.oauth.tokengetter
def get_token(token=None):
if bp.oauth_type == 'oauth2':
return current_user.get(bp.name, None)['access_token']
return current_user.get(bp.name, None)['oauth_token']
I tried just placing the views together in a class then importing those, but was having trouble with the various decorators (the oauth decorators were giving the most trouble).
I figured out something that seems like a good solution to the above issue. Please let me know if this is in fact a good solution.
I decided to use the Flask class-based views. This got me most of the way to just create a class-view for each of the main API functions above:
class APILoginView(View):
decorators = [login_required]
def __init__(self, blueprint):
self.blueprint = blueprint
def dispatch_request(self):
if current_user.get(self.blueprint.name, None):
return redirect(url_for('frontend.index'))
return self.blueprint.oauth.authorize(callback=url_for('.authorized', _external=True))
class APIAuthorizedView(View):
decorators = [login_required]
def __init__(self, blueprint):
self.blueprint = blueprint
def dispatch_request(self, resp):
if resp is None:
flash(u'You denied the request to sign in.')
return redirect(url_for('frontend.index'))
if self.blueprint.api.oauth_type == 'oauth2':
resp['access_token'] = (resp['access_token'], '') #need to make it a tuple for oauth2 requests
current_user[self.blueprint.name] = resp
current_user.save()
flash('You were signed in to %s' % self.blueprint.name.capitalize())
return redirect(url_for('frontend.index'))
That was the easier part. The trickier thing was figuring out how to generalize the tokengetter, required for the Flask-OAuthLib library. Here is what I ended up with:
class APIToken():
def __init__(self, blueprint):
self.blueprint = blueprint
def get_token(self, token=None):
if self.blueprint.api.oauth_type == 'oauth2':
return current_user.get(self.blueprint.name, None)['access_token']
return current_user.get(self.blueprint.name, None)['oauth_token']
And finally, create a function to register those views on a blueprint:
def registerAPIViews(blueprint):
login_view = APILoginView.as_view('login', blueprint=blueprint)
auth_view = blueprint.oauth.authorized_handler(
APIAuthorizedView.as_view('authorized', blueprint=blueprint))
blueprint.add_url_rule('/', view_func=login_view)
blueprint.add_url_rule('/authorized', view_func=auth_view)
apiToken = APIToken(blueprint)
token_getter = blueprint.oauth.tokengetter(apiToken.get_token)
return blueprint

Adding usernames to the path of the url

I am building an application using webapp2 in Google App Engine. How do I pass the username into the url so that when the profile button is clicked, it takes the user to "/profile/username" where "username" is specific to the user?
My current handlers:
app = webapp2.WSGIApplication([('/', MainPage),
('/signup', Register),
('/login', Login),
('/logout', Logout),
('/profile', Profile)
],
debug=True)
the Profile class:
class Profile(BlogHandler):
def get(self):
email = self.request.get('email')
product = self.request.get('product')
product_list = db.GqlQuery("SELECT * FROM Post ORDER BY created DESC LIMIT 10")
self.render('profile.html', email = email, product = product, product_list = product_list)
I am trying to send each user to a Profile page that contains information in my database specific to them. Thanks
One possible solution would be to simply have one URL, i.e., /profile. The corresponding handler would render the response with data coming from the logged-in user.
If you really want to have URLs like /profile/username, you could define a route:
app = webapp2.WSGIApplication([('/', MainPage),
('/signup', Register),
('/login', Login),
('/logout', Logout),
('r/profile/(\w+)', Profile)
],
debug=True)
and access the username in your handler:
class Profile(BlogHandler):
def get(self, username):
But depending on your application, you might want to make sure only the logged-in user has access to its /profile/username by adding a check somewhere in the handler.
See http://webapp-improved.appspot.com/guide/routing.html
You could have something like
class Profile(BlogHandler):
def get(self, username):
...
app = webapp2.WSGIApplication([('/profile/(\w+)', Profile), ...])
Start by adding a capture group to /profile:
(r'/profile/(\w+)', Profile)
The r before the beginning of the string is important, as it will correctly handle regular expression characters. Otherwise, you'd have to escape the blackslash manually.
\w+ will match one or more alphanumeric characters and the underscore. That should suffice for your usernames, yes?
Then set up your RequestHandler like this:
class Profile(webapp2.RequestHandler):
def get(self, username):
# The value captured in the (\w+) part of the URL will automatically
# be passed in to the username parameter.
# Do the rest of my coding to get and render the data.

Categories