Source code for noggin.app

import os
from logging.config import dictConfig

import flask_talisman
import jinja2
from flask import Flask
from flask_healthz import healthz
from flask_mail import Mail
from flask_wtf.csrf import CSRFProtect
from whitenoise import WhiteNoise

from noggin import l10n
from noggin.controller import blueprint
from noggin.middleware import IPAErrorHandler
from noggin.security.ipa_admin import IPAAdmin
from noggin.themes import Theme
from noggin.utility import import_all
from noggin.utility.templates import format_channel, format_nickname


# Forms
csrf = CSRFProtect()

# IPA admin account
ipa_admin = IPAAdmin()

# Theme manager
theme = Theme()

# Flask-Mail
mailer = Mail()

# Catch IPA errors
ipa_error_handler = IPAErrorHandler()

# Security headers
talisman = flask_talisman.Talisman()


[docs] def create_app(config=None): """See https://flask.palletsprojects.com/en/1.1.x/patterns/appfactories/""" app = Flask(__name__) # Load default configuration app.config.from_object("noggin.defaults") # Load the optional configuration file if "NOGGIN_CONFIG_PATH" in os.environ: app.config.from_envvar("NOGGIN_CONFIG_PATH") # Load the config passed as argument app.config.update(config or {}) # Templates reloading if app.config.get("TEMPLATES_AUTO_RELOAD"): app.jinja_env.auto_reload = True # Custom template folders if app.config["TEMPLATES_CUSTOM_DIRECTORIES"]: app.jinja_loader = jinja2.ChoiceLoader( [ jinja2.FileSystemLoader(app.config["TEMPLATES_CUSTOM_DIRECTORIES"]), app.jinja_loader, ] ) # Logging if app.config.get("LOGGING"): dictConfig(app.config["LOGGING"]) # Static files whitenoise = app.wsgi_app = WhiteNoise( app.wsgi_app, root=f"{app.root_path}/static/", prefix="static/" ) # Extensions l10n.babel.init_app(app, locale_selector=l10n.get_locale) app.jinja_env.add_extension("jinja2.ext.i18n") csrf.init_app(app) ipa_admin.init_app(app) mailer.init_app(app) ipa_error_handler.init_app(app) theme.init_app(app, whitenoise=whitenoise) talisman.init_app( app, force_https=app.config.get("SESSION_COOKIE_SECURE", True), frame_options=flask_talisman.DENY, referrer_policy="same-origin", content_security_policy={ "default-src": "'self'", "script-src": [ # https://csp.withgoogle.com/docs/strict-csp.html#example "'strict-dynamic'", ], "img-src": ["'self'", "seccdn.libravatar.org"] + app.config["ACCEPT_IMAGES_FROM"], # The style-src directive needs to be specified (even if it's the same as default-src) # to add the nonce. "style-src": "'self'", }, content_security_policy_nonce_in=['script-src', 'style-src'], ) # Template filters # If there are too many, group them in an extension app.jinja_env.filters["nickname"] = format_nickname app.jinja_env.filters["channel"] = format_channel # Register views import_all("noggin.controller") app.register_blueprint(blueprint) app.register_blueprint(healthz, url_prefix="/healthz") # Don't force the Openshift health views to HTTPS talisman(force_https=False)(app.view_functions["healthz.check"]) return app