mirror of
https://github.com/Xevion/runnerspace.git
synced 2025-12-07 11:16:19 -06:00
Implement CSRF protection & error page
This commit is contained in:
8
app.py
8
app.py
@@ -6,11 +6,14 @@ import click
|
|||||||
import pytz
|
import pytz
|
||||||
from faker import Faker
|
from faker import Faker
|
||||||
from flask import Flask, render_template, request
|
from flask import Flask, render_template, request
|
||||||
|
from flask_wtf.csrf import CSRFProtect, CSRFError
|
||||||
from flask_login import LoginManager, current_user
|
from flask_login import LoginManager, current_user
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
from werkzeug.security import generate_password_hash
|
from werkzeug.security import generate_password_hash
|
||||||
from database import db
|
from database import db
|
||||||
|
|
||||||
|
csrf = CSRFProtect()
|
||||||
|
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
@@ -27,6 +30,7 @@ def create_app():
|
|||||||
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', '').replace('postgres://', 'postgresql://', 1)
|
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', '').replace('postgres://', 'postgresql://', 1)
|
||||||
|
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
|
csrf.init_app(app)
|
||||||
|
|
||||||
login_manager = LoginManager()
|
login_manager = LoginManager()
|
||||||
login_manager.login_view = 'auth.login'
|
login_manager.login_view = 'auth.login'
|
||||||
@@ -52,6 +56,10 @@ def create_app():
|
|||||||
# note that we set the 404 status explicitly
|
# note that we set the 404 status explicitly
|
||||||
return render_template('errors/404.html'), 404
|
return render_template('errors/404.html'), 404
|
||||||
|
|
||||||
|
@app.errorhandler(CSRFError)
|
||||||
|
def handle_csrf_error(e):
|
||||||
|
return render_template('errprs/csrf.html', reason=e.description), 400
|
||||||
|
|
||||||
@app.before_request
|
@app.before_request
|
||||||
def update_last_seen():
|
def update_last_seen():
|
||||||
if current_user.is_authenticated:
|
if current_user.is_authenticated:
|
||||||
|
|||||||
15
forms.py
15
forms.py
@@ -1,9 +1,10 @@
|
|||||||
from wtforms import Form, BooleanField, StringField, PasswordField, TextAreaField, validators
|
from flask_wtf import FlaskForm
|
||||||
|
from wtforms import BooleanField, StringField, PasswordField, TextAreaField, validators
|
||||||
|
|
||||||
from validators import NoProfanity
|
from validators import NoProfanity
|
||||||
|
|
||||||
|
|
||||||
class RegistrationForm(Form):
|
class RegistrationForm(FlaskForm):
|
||||||
username = StringField('Username', [validators.Length(min=4, max=25), NoProfanity()])
|
username = StringField('Username', [validators.Length(min=4, max=25), NoProfanity()])
|
||||||
name = StringField('Name', [validators.Length(min=2, max=35), NoProfanity()])
|
name = StringField('Name', [validators.Length(min=2, max=35), NoProfanity()])
|
||||||
password = PasswordField('New Password', [
|
password = PasswordField('New Password', [
|
||||||
@@ -14,20 +15,20 @@ class RegistrationForm(Form):
|
|||||||
accept_tos = BooleanField('I accept the TOS', [validators.DataRequired()])
|
accept_tos = BooleanField('I accept the TOS', [validators.DataRequired()])
|
||||||
|
|
||||||
|
|
||||||
class LoginForm(Form):
|
class LoginForm(FlaskForm):
|
||||||
username = StringField('Username', [validators.DataRequired()])
|
username = StringField('Username', [validators.DataRequired()])
|
||||||
password = StringField('Password', [validators.DataRequired()])
|
password = StringField('Password', [validators.DataRequired()])
|
||||||
remember_me = BooleanField('Remember Me', [validators.Optional()])
|
remember_me = BooleanField('Remember Me', [validators.Optional()])
|
||||||
|
|
||||||
|
|
||||||
class EditProfileForm(Form):
|
class EditProfileForm(FlaskForm):
|
||||||
name = RegistrationForm.name
|
name = RegistrationForm.name
|
||||||
about_me = StringField('About Me', [validators.Optional(), NoProfanity()], description='Tell us about yourself',)
|
about_me = TextAreaField('About Me', [validators.Optional(), NoProfanity()], description='Tell us about yourself',)
|
||||||
|
|
||||||
|
|
||||||
class NewPostForm(Form):
|
class NewPostForm(FlaskForm):
|
||||||
text = TextAreaField('Text', [validators.Length(min=15, max=1000), NoProfanity()], description='Express yourself.')
|
text = TextAreaField('Text', [validators.Length(min=15, max=1000), NoProfanity()], description='Express yourself.')
|
||||||
|
|
||||||
|
|
||||||
class NewCommentForm(Form):
|
class NewCommentForm(FlaskForm):
|
||||||
text = StringField('Text', [validators.Length(min=5, max=50), NoProfanity()])
|
text = StringField('Text', [validators.Length(min=5, max=50), NoProfanity()])
|
||||||
|
|||||||
19
templates/errors/csrf.html
Normal file
19
templates/errors/csrf.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{% extends 'layouts/index.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="content-inner" style="display: flex">
|
||||||
|
<div style="margin: 0 auto;">
|
||||||
|
<h2>400 - Bad CSRF Token</h2>
|
||||||
|
<p>
|
||||||
|
{% if current_user.is_authenticated %}
|
||||||
|
Sorry <strong>{{ current_user.username }}</strong>, the
|
||||||
|
{% else %}
|
||||||
|
The
|
||||||
|
{% endif %} form you submitted requires a CSRF token to be valid.
|
||||||
|
<br>
|
||||||
|
This may happen if the form was submitted long after the token was generated, and it has thus expired.
|
||||||
|
<span style="text-align: center">Go <a href="{{ url_for('main.index') }}">home?</a></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user