s2-dungeonsandexploits/flask/server.py

163 lines
5.1 KiB
Python
Raw Permalink Normal View History

2022-11-18 09:04:33 +01:00
import os
import secrets
from datetime import timedelta
from flask import Flask, abort
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy
from flask_sslify import SSLify
from flask_talisman import Talisman
from flask_talisman.talisman import ONE_YEAR_IN_SECS
from flask_wtf.csrf import CSRFProtect
domain = None # "127.0.0.1:8000"
# domain = f"dungeonsandexploits.team{team_number}.m0lecon.fans"
app = Flask(__name__)
# init sslify
sslify = SSLify(app)
# init talisman
talisman = Talisman(
app,
content_security_policy_nonce_in=["script-src", "style-src"],
# content_security_policy_nonce_in=["script-src", "style-src"],
content_security_policy_report_only=False,
content_security_policy_report_uri=None,
content_security_policy={ # do not add stuff here, put tags in html template tags: nonce="{{ csp_nonce() }}"
"default-src": "'none'",
# "script-src": "'self'",
"script-src": "'self' 'wasm-unsafe-eval'", # MAYBE THIS SHOULD NOT BE LIKE THIS BUT UNITY NEEDS IT
"style-src": "'self'",
"img-src": "'self'",
"connect-src": "'self'",
"base-uri": "'none'",
"form-action": "'none'",
"frame-ancestors": "'none'",
"strict-dynamic": "",
},
feature_policy={},
force_file_save=True,
force_https_permanent=True,
force_https=True,
frame_options_allow_from=None,
frame_options="DENY",
referrer_policy="strict-origin-when-cross-origin",
session_cookie_http_only=True,
session_cookie_secure=True,
strict_transport_security_include_subdomains=True,
strict_transport_security_max_age=ONE_YEAR_IN_SECS,
strict_transport_security_preload=False, # SOULD BE TRUE, enables HSTS preloading if you register your application with Google's HSTS preload list, Firefox and Chrome will never load your site over a non-secure connection.
strict_transport_security=True,
)
# init session
app.config.update(
APPLICATION_ROOT="/",
JSON_AS_ASCII=True,
JSON_SORT_KEYS=False,
JSONIFY_MIMETYPE="application/json",
JSONIFY_PRETTYPRINT_REGULAR=False,
MAX_CONTENT_LENGTH=16 * 1000 * 1000,
MAX_COOKIE_SIZE=4093,
PERMANENT_SESSION_LIFETIME=timedelta(minutes=30),
PREFERRED_URL_SCHEME="https",
SECRET_KEY=secrets.token_hex(256),
SEND_FILE_MAX_AGE_DEFAULT=timedelta(hours=12),
SERVER_NAME=domain,
SESSION_COOKIE_DOMAIN=domain,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_NAME="session",
SESSION_COOKIE_PATH="/",
SESSION_COOKIE_SAMESITE="Strict",
SESSION_COOKIE_SECURE=True,
SESSION_REFRESH_EACH_REQUEST=True,
USE_X_SENDFILE=False, # disabled: does not work with gunicorn
)
# init flask-wtf
app.config.update(
# RECAPTCHA_API_SERVER=None,
# RECAPTCHA_DATA_ATTRS=None,
# RECAPTCHA_DIV_CLASS="g-recaptcha",
# RECAPTCHA_HTML=None,
# RECAPTCHA_PARAMETERS=None,
# RECAPTCHA_PRIVATE_KEY=None,
# RECAPTCHA_PUBLIC_KEY=None,
# RECAPTCHA_SCRIPT="https://www.google.com/recaptcha/api.js",
# RECAPTCHA_VERIFY_SERVER="https://www.google.com/recaptcha/api/siteverify",
WTF_CSRF_CHECK_DEFAULT=True,
WTF_CSRF_ENABLED=True,
WTF_CSRF_FIELD_NAME="csrf_token",
WTF_CSRF_HEADERS=["X-CSRFToken", "X-CSRF-Token"],
WTF_CSRF_METHODS={"POST", "PUT", "PATCH", "DELETE"},
WTF_CSRF_SECRET_KEY=secrets.token_hex(256),
WTF_CSRF_SSL_STRICT=True,
WTF_CSRF_TIME_LIMIT=1200,
WTF_I18N_ENABLED=True,
)
csrfprotect = CSRFProtect(app)
# init flask-login
app.config.update(
AUTH_HEADER_NAME="Authorization",
COOKIE_DURATION=timedelta(minutes=30),
COOKIE_HTTPONLY=True,
COOKIE_NAME="remember_token",
COOKIE_SAMESITE=True,
COOKIE_SECURE=True,
EXEMPT_METHODS=set(),
LOGIN_MESSAGE_CATEGORY="message",
LOGIN_MESSAGE="Please log in to access this page.",
REFRESH_MESSAGE_CATEGORY="message",
REFRESH_MESSAGE="Please reauthenticate to access this page.",
REMEMBER_COOKIE_DOMAIN=domain,
REMEMBER_COOKIE_DURATION=timedelta(minutes=30),
REMEMBER_COOKIE_HTTPONLY=True,
REMEMBER_COOKIE_NAME="remember_token",
REMEMBER_COOKIE_PATH="/",
REMEMBER_COOKIE_REFRESH_EACH_REQUEST=True,
REMEMBER_COOKIE_SECURE=True,
# SESSION_KEYS=set(["_user_id", "_remember", "_remember_seconds", "_id", "_fresh", "next", ]),
SESSION_PROTECTION="strong",
USE_SESSION_FOR_NEXT=True,
)
login_manager = LoginManager(app)
# init flask-sqlalchemy
app.config.update(
# SQLALCHEMY_DATABASE_URI="sqlite:///:memory:?cache=shared",
SQLALCHEMY_DATABASE_URI="sqlite:////tmp/db.db",
# SQLALCHEMY_BINDS={},
# SQLALCHEMY_ECHO=True,
# SQLALCHEMY_RECORD_QUERIES=True,
SQLALCHEMY_TRACK_MODIFICATIONS=False,
# SQLALCHEMY_ENGINE_OPTIONS={},
)
db = SQLAlchemy(app)
def register_blueprints(app):
from auth import auth
from game import game
from website import website
app.register_blueprint(auth)
app.register_blueprint(website)
app.register_blueprint(game)
register_blueprints(app)
with app.app_context():
# create all missing db tables
db.create_all()
@app.route("/teapot")
async def teapot():
abort(418)
if __name__ == '__main__':
app.run()