-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.py
134 lines (107 loc) · 4 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# IMPORTS
import logging
import os
from functools import wraps
from dotenv import load_dotenv
from flask import Flask, render_template, request
from flask_login import LoginManager, current_user
from flask_qrcode import QRcode
from flask_sqlalchemy import SQLAlchemy
from flask_talisman import Talisman
csp = { # Content Security Policy
'default-src': [ # Whitelist content sources
'\'self\'',
'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css'
],
'frame-src': [ # Whitelist iframe content
'\'self\'',
'https://www.google.com/recaptcha/',
'https://recaptcha.google.com/recaptcha/'
],
'script-src': [ # Allow inline scripts
'\'self\'',
'\'unsafe-inline\'',
'https://www.google.com/recaptcha/',
'https://www.gstatic.com/recaptcha/',
],
'img-src': [ # Allow images
'data:',
],
'style-src': [ # Allow styles
'\'self\'',
'\'unsafe-inline\'',
'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css'
],
}
class SecurityFilter(logging.Filter):
def filter(self, record):
return 'SECURITY' in record.getMessage()
logger = logging.getLogger()
file_handler = logging.FileHandler('lottery.log', 'a')
file_handler.setLevel(logging.WARNING)
file_handler.addFilter(SecurityFilter())
formatter = logging.Formatter('%(asctime)s : %(message)s', '%m/%d/%Y %I:%M:%S %p')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
# CONFIG
load_dotenv()
app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('SQLALCHEMY_DATABASE_URI')
app.config['SQLALCHEMY_ECHO'] = os.getenv('SQLALCHEMY_ECHO') == 'True'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = os.getenv('SQLALCHEMY_TRACK_MODIFICATIONS') == 'True'
app.config['RECAPTCHA_PUBLIC_KEY'] = os.getenv('RECAPTCHA_PUBLIC_KEY')
app.config['RECAPTCHA_PRIVATE_KEY'] = os.getenv('RECAPTCHA_PRIVATE_KEY')
# initialise database
db = SQLAlchemy(app)
talisman = Talisman(app, content_security_policy=csp)
QRcode(app)
# HOME PAGE VIEW
@app.route('/')
def index():
return render_template('main/index.html')
def requires_roles(*roles): # Create custom wrapper for roles
def wrapper(f):
@wraps(f)
def wrapped(*args, **kwargs):
if current_user.role not in roles:
logging.warning('SECURITY - User attempted attempted to access page with invalid role[%s, %s, %s, %s]',
current_user.id,
current_user.email, current_user.role, request.remote_addr)
return render_template('errors/403.html'), 403
return f(*args, **kwargs)
return wrapped
return wrapper
def anonymous_required(f):
@wraps(f)
def wrapped(*args, **kwargs):
if current_user.is_authenticated:
logging.warning('SECURITY - User attempted to access page with invalid role[%s, %s, %s, %s]',
current_user.id,
current_user.email, current_user.role, request.remote_addr)
return render_template('errors/403.html'), 403
return f(*args, **kwargs)
return wrapped
# BLUEPRINTS
# import blueprints
from users.views import users_blueprint
from admin.views import admin_blueprint
from lottery.views import lottery_blueprint
from errors.views import errors_blueprint
# register blueprints with app
app.register_blueprint(users_blueprint)
app.register_blueprint(admin_blueprint)
app.register_blueprint(lottery_blueprint)
app.register_blueprint(errors_blueprint)
# initialise login manager
login_manager = LoginManager()
login_manager.login_view = 'users.login'
login_manager.init_app(app)
from models import User
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
if __name__ == "__main__":
# app.run(ssl_context=('cert.pem', 'key.pem')) # Run with SSL
# Run with additional options: --cert=cert.pem --key=key.pem
app.run()