def create_app(test_config=None): # Create and configure the app app = Flask(__name__, instance_relative_config=True) app.config.from_mapping( DEBUG=False, SECRET_KEY=os.environ.get("SECRET_KEY", "ppBcUQ5AL7gEmvb0blMDyEOpiBEQUupGmk_a3DMaF34"), TOPIC_STORE_USER=database_username, TOPIC_STORE_PASSWORD=database_password, TOPIC_STORE_DBNAME=database_name, TOPIC_STORE_HOST=database_host, TOPIC_STORE_PORT=database_port, SECURITY_PASSWORD_SALT=os.environ.get("SECURITY_PASSWORD_SALT", "139687009245803364536588051620840970665"), SECURITY_REGISTERABLE=True, SECURITY_RECOVERABLE=True, SECURITY_EMAIL_SENDER=email_sender, SECURITY_URL_PREFIX="/auth", SECURITY_POST_LOGIN_VIEW="/maps/", SECURITY_POST_REGISTER_VIEW="/maps/", MAIL_SERVER=email_server, MAIL_PORT=587, MAIL_USE_SSL=False, MAIL_USERNAME=email_username, MAIL_PASSWORD=email_password, MAX_CONTENT_LENGTH=4 * 1024 * 1024, # 4 megabytes (temporarily - will be 2) ) mail = Mail(app) csrf = SeaSurf(app) if test_config is None: # Load the instance config, if it exists, when not testing app.config.from_pyfile("config.py", silent=True) else: # Load the test config if passed in app.config.from_mapping(test_config) # Ensure the instance folder exists try: os.makedirs(app.instance_path) except OSError: pass @app.route("/") def home(): maps = get_topic_store().get_promoted_topic_maps() # Reset breadcrumbs and (current) scope session["breadcrumbs"] = [] session["current_scope"] = UNIVERSAL_SCOPE session["scope_filter"] = 1 return render_template("index.html", maps=maps) @app.route("/health") def hello(): return "Healthy!" # HTTP error handlers def forbidden(e): return render_template("403.html"), 403 app.register_error_handler(403, forbidden) def page_not_found(e): return render_template("404.html"), 404 app.register_error_handler(404, page_not_found) def internal_server_error(e): return render_template("500.html"), 500 app.register_error_handler(500, internal_server_error) def request_entity_too_large(e): return render_template("413.html"), 413 app.register_error_handler(413, request_entity_too_large) # Setup Flask-Security user_datastore = SQLAlchemySessionUserDatastore(user_store.db_session, user_models.User, user_models.Role) security = Security(app, user_datastore) @user_registered.connect_via(app) def user_registered_handler(app, user, confirm_token, form_data, **extra_args): default_role = user_datastore.find_role("user") user_datastore.add_role_to_user(user, default_role) user_store.db_session.commit() @user_authenticated.connect_via(app) def user_authenticated_handler(app, user, authn_via, **extra_args): app.logger.info(f"User logged in successfully: [{user.email}], authentication method: [{authn_via}]") @app.before_first_request def create_user(): user_store.init_db() # Create roles user_datastore.find_or_create_role(name="admin", description="Administrator") user_datastore.find_or_create_role(name="user", description="End user") # Create users if not user_datastore.get_user("*****@*****.**"): user_datastore.create_user(email="*****@*****.**", password=hash_password("Passw0rd1")) if not user_datastore.get_user("*****@*****.**"): user_datastore.create_user(email="*****@*****.**", password=hash_password("Passw0rd1")) user_store.db_session.commit() # Assign roles user_datastore.add_role_to_user("*****@*****.**", "user") user_datastore.add_role_to_user("*****@*****.**", "admin") user_store.db_session.commit() @app.teardown_request def checkin_db(exc): user_store.db_session.remove() # Register custom filters filters.register_filters(app) # Register Blueprints from contextualise import api app.register_blueprint(api.bp) csrf.exempt(api.create_topic) csrf.exempt(api.create_association) from contextualise import map app.register_blueprint(map.bp) from contextualise import topic app.register_blueprint(topic.bp) from contextualise import image app.register_blueprint(image.bp) from contextualise import file app.register_blueprint(file.bp) from contextualise import link app.register_blueprint(link.bp) from contextualise import video app.register_blueprint(video.bp) from contextualise import association app.register_blueprint(association.bp) from contextualise import note app.register_blueprint(note.bp) from contextualise import three_d app.register_blueprint(three_d.bp) from contextualise import attribute app.register_blueprint(attribute.bp) from contextualise import visualisation app.register_blueprint(visualisation.bp) from contextualise import tag app.register_blueprint(tag.bp) # Add topic store # from contextualise import topic_store # topic_store.init_app(app) # Set up logging if not app.debug: if not os.path.exists("logs"): os.mkdir("logs") file_handler = RotatingFileHandler("logs/contextualise.log", maxBytes=10240, backupCount=10) file_handler.setFormatter( logging.Formatter("%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]") ) file_handler.setLevel(logging.INFO) app.logger.addHandler(file_handler) app.logger.setLevel(logging.INFO) app.logger.info("Contextualise startup") return app
def create_app(config=None): from . import models, routes, services from .assets import assets app = Flask(__name__) # Read log level from environment variable log_level_name = os.environ.get('PDNS_ADMIN_LOG_LEVEL', 'WARNING') log_level = logging.getLevelName(log_level_name.upper()) # Setting logger logging.basicConfig( level=log_level, format= "[%(asctime)s] [%(filename)s:%(lineno)d] %(levelname)s - %(message)s") # If we use Docker + Gunicorn, adjust the # log handler if "GUNICORN_LOGLEVEL" in os.environ: gunicorn_logger = logging.getLogger("gunicorn.error") app.logger.handlers = gunicorn_logger.handlers app.logger.setLevel(gunicorn_logger.level) # Proxy app.wsgi_app = ProxyFix(app.wsgi_app) # CSRF protection csrf = SeaSurf(app) csrf.exempt(routes.index.dyndns_checkip) csrf.exempt(routes.index.dyndns_update) csrf.exempt(routes.index.saml_authorized) csrf.exempt(routes.api.api_login_create_zone) csrf.exempt(routes.api.api_login_delete_zone) csrf.exempt(routes.api.api_generate_apikey) csrf.exempt(routes.api.api_delete_apikey) csrf.exempt(routes.api.api_update_apikey) csrf.exempt(routes.api.api_zone_subpath_forward) csrf.exempt(routes.api.api_zone_forward) csrf.exempt(routes.api.api_create_zone) # Load config from env variables if using docker if os.path.exists(os.path.join(app.root_path, 'docker_config.py')): app.config.from_object('powerdnsadmin.docker_config') else: # Load default configuration app.config.from_object('powerdnsadmin.default_config') # Load config file from FLASK_CONF env variable if 'FLASK_CONF' in os.environ: app.config.from_envvar('FLASK_CONF') # Load app sepecified configuration if config is not None: if isinstance(config, dict): app.config.update(config) elif config.endswith('.py'): app.config.from_pyfile(config) # HSTS if app.config.get('HSTS_ENABLED'): from flask_sslify import SSLify _sslify = SSLify(app) # lgtm [py/unused-local-variable] # SMTP app.mail = Mail(app) # Load app's components assets.init_app(app) models.init_app(app) routes.init_app(app) services.init_app(app) # Register filters app.jinja_env.filters['display_record_name'] = utils.display_record_name app.jinja_env.filters['display_master_name'] = utils.display_master_name app.jinja_env.filters['display_second_to_time'] = utils.display_time app.jinja_env.filters[ 'email_to_gravatar_url'] = utils.email_to_gravatar_url app.jinja_env.filters[ 'display_setting_state'] = utils.display_setting_state # Register context proccessors from .models.setting import Setting @app.context_processor def inject_sitename(): setting = Setting().get('site_name') return dict(SITE_NAME=setting) @app.context_processor def inject_setting(): setting = Setting() return dict(SETTING=setting) return app
@app.before_request def make_session_permanent(): # We use flask sessions for remembering which client is in kiosk mode. # By default, these sessions expire when the browser is closed. Prevent that. session.permanent = True app.permanent_session_lifetime = timedelta(days=2*365) # should be long enough... if app.debug: # allow requests from default broccoli server port from flask_cors import CORS CORS(app, origins=['http://localhost:4200'], supports_credentials=True) import flask_debugtoolbar toolbar = flask_debugtoolbar.DebugToolbarExtension(app) csrf.exempt(flask_debugtoolbar.panels.sqlalchemy.sql_select) else: # production logger to stderr handler = logging.StreamHandler() handler.setLevel(logging.INFO) handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s in %(module)s: %(message)s')) app.logger.setLevel(logging.INFO) app.logger.addHandler(handler) # sqlalchemy treats columns as nullable by default, which we don't want. Column = partial(sqla.Column, nullable=False) from db.fsmi import Cookie # errors that will be reported to the client class ClientError(Exception):
def create_app(test_config=None): # Create app app = Flask(__name__, instance_relative_config=True) app.version = __version__ # Configure app app.config.from_object("contextualise.settings") app.config.from_envvar("CONTEXTUALISE_SETTINGS") app.config.from_mapping( DEBUG=False, DATABASE_PATH=os.path.join(app.instance_path, app.config["DATABASE_FILE"]), SECRET_KEY=os.environ.get( "SECRET_KEY", "ppBcUQ5AL7gEmvb0blMDyEOpiBEQUupGmk_a3DMaF34"), SECURITY_PASSWORD_SALT=os.environ.get( "SECURITY_PASSWORD_SALT", "139687009245803364536588051620840970665"), SECURITY_REGISTERABLE=True, SECURITY_RECOVERABLE=True, SECURITY_URL_PREFIX="/auth", SECURITY_POST_LOGIN_VIEW="/maps/", SECURITY_POST_REGISTER_VIEW="/maps/", MAIL_SERVER=app.config["EMAIL_SERVER"], MAIL_PORT=app.config["EMAIL_PORT"], MAIL_USERNAME=app.config["EMAIL_USERNAME"], MAIL_PASSWORD=app.config["EMAIL_PASSWORD"], MAIL_DEFAULT_SENDER=app.config["EMAIL_SENDER"], MAIL_USE_SSL=False, MAX_CONTENT_LENGTH=4 * 1024 * 1024, # 4 megabytes ) # Set up app mail = Mail(app) csrf = SeaSurf(app) if test_config is None: # Load the instance config, if it exists, when not testing app.config.from_pyfile("config.py", silent=True) else: # Load the test config if passed in app.config.from_mapping(test_config) # Ensure the instance folder exists try: os.makedirs(app.instance_path) except OSError: pass @app.route("/") def home(): maps = get_topic_store().get_promoted_maps() maps = [map for map in maps if map.published] # Reset breadcrumbs and (current) scope session["breadcrumbs"] = [] session["current_scope"] = UNIVERSAL_SCOPE session["scope_filter"] = 1 return render_template("index.html", maps=maps, version=app.version) @app.route("/health") def hello(): return "Healthy!" # HTTP error handlers def forbidden(e): return render_template("403.html"), 403 app.register_error_handler(403, forbidden) def page_not_found(e): return render_template("404.html"), 404 app.register_error_handler(404, page_not_found) def internal_server_error(e): return render_template("500.html"), 500 app.register_error_handler(500, internal_server_error) def request_entity_too_large(e): return render_template("413.html"), 413 app.register_error_handler(413, request_entity_too_large) # Setup Flask-Security engine = create_engine(f"sqlite:///{app.config['DATABASE_PATH']}") db_session = scoped_session( sessionmaker(autocommit=False, autoflush=False, bind=engine)) Base = declarative_base() Base.query = db_session.query_property() class RolesUsers(Base): __tablename__ = "roles_users" id = Column(Integer(), primary_key=True) user_id = Column("user_id", Integer(), ForeignKey("user.id")) role_id = Column("role_id", Integer(), ForeignKey("role.id")) class Role(Base, RoleMixin): __tablename__ = "role" id = Column(Integer(), primary_key=True) name = Column(String(80), unique=True) description = Column(String(255)) class User(Base, UserMixin): __tablename__ = "user" id = Column(Integer, primary_key=True) email = Column(String(255), unique=True) username = Column(String(255), unique=True, nullable=True) password = Column(String(255), nullable=False) last_login_at = Column(DateTime()) current_login_at = Column(DateTime()) last_login_ip = Column(String(100)) current_login_ip = Column(String(100)) login_count = Column(Integer) active = Column(Boolean()) fs_uniquifier = Column(String(255), unique=True, nullable=False) confirmed_at = Column(DateTime()) roles = relationship("Role", secondary="roles_users", backref=backref("users", lazy="dynamic")) user_datastore = SQLAlchemySessionUserDatastore(db_session, User, Role) security = Security(app, user_datastore) @user_registered.connect_via(app) def user_registered_handler(app, user, confirm_token, form_data, **extra_args): default_role = user_datastore.find_role("user") user_datastore.add_role_to_user(user, default_role) db_session.commit() @user_authenticated.connect_via(app) def user_authenticated_handler(app, user, authn_via, **extra_args): app.logger.info( f"User logged in successfully: [{user.email}], authentication method: [{authn_via}]" ) @app.before_first_request def create_user(): Base.metadata.create_all(bind=engine) # Create roles admin_role = user_datastore.find_or_create_role( name="admin", description="Administrator") user_role = user_datastore.find_or_create_role(name="user", description="End user") db_session.commit() # Create users admin_user = user_datastore.find_user(email="*****@*****.**") if not admin_user: admin_user = user_datastore.create_user( email="*****@*****.**", password=hash_password("Passw0rd1")) db_session.commit() user_user = user_datastore.find_user(email="*****@*****.**") if not user_user: user_user = user_datastore.create_user( email="*****@*****.**", password=hash_password("Passw0rd1")) db_session.commit() # Assign roles user_datastore.add_role_to_user(user_user, user_role) user_datastore.add_role_to_user(admin_user, admin_role) db_session.commit() # Create database structure get_topic_store().create_database() @app.teardown_request def checkin_db(exc): db_session.remove() # Register custom filters filters.register_filters(app) # Register Blueprints from contextualise import api app.register_blueprint(api.bp) csrf.exempt(api.create_topic) csrf.exempt(api.create_association) from contextualise import map app.register_blueprint(map.bp) from contextualise import topic app.register_blueprint(topic.bp) from contextualise import image app.register_blueprint(image.bp) from contextualise import file app.register_blueprint(file.bp) from contextualise import link app.register_blueprint(link.bp) from contextualise import video app.register_blueprint(video.bp) from contextualise import association app.register_blueprint(association.bp) from contextualise import note app.register_blueprint(note.bp) from contextualise import three_d app.register_blueprint(three_d.bp) from contextualise import attribute app.register_blueprint(attribute.bp) from contextualise import visualisation app.register_blueprint(visualisation.bp) from contextualise import tag app.register_blueprint(tag.bp) # Set up logging if not app.debug: logs_directory = os.path.join(app.instance_path, "logs") if not os.path.exists(logs_directory): os.mkdir(logs_directory) file_handler = RotatingFileHandler(os.path.join( logs_directory, "contextualise.log"), maxBytes=10240, backupCount=10) file_handler.setFormatter( logging.Formatter( "%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]" )) file_handler.setLevel(logging.INFO) app.logger.addHandler(file_handler) app.logger.setLevel(logging.INFO) app.logger.info("Contextualise startup") return app
from victims.web.handlers.sslify import VSSLify from victims.web.handlers.task import taskman from victims.web.plugin.crosstalk import session_reaper # Custom SSLify sslify = VSSLify(app) # cache cache.init_app(app) # admin setup administration_setup(app) # CSRF exemptions for submit in SUBMISSION_ROUTES: csrf.exempt(submit) # SetUp identity management setup_security(app) @app.after_request def reap_sessions(response): if session.modified: taskman.add_task(session_reaper.reap) return response @app.errorhandler(403) def error_403(e):
from victims.web.handlers.sslify import VSSLify from victims.web.handlers.task import taskman from victims.web.plugin.crosstalk import session_reaper # Custom SSLify sslify = VSSLify(app) # cache cache.init_app(app) # admin setup administration_setup(app) # CSRF exemptions for submit in SUBMISSION_ROUTES: csrf.exempt(submit) # SetUp identity management setup_security(app) @app.after_request def reap_sessions(response): if session.modified: taskman.add_task(session_reaper.reap) return response @app.errorhandler(403) def error_403(e): return render_template(
def make_session_permanent(): # We use flask sessions for remembering which client is in kiosk mode. # By default, these sessions expire when the browser is closed. Prevent that. session.permanent = True app.permanent_session_lifetime = timedelta(days=2 * 365) # should be long enough... if app.debug: # allow requests from default broccoli server port from flask_cors import CORS CORS(app, origins=['http://localhost:4200'], supports_credentials=True) import flask_debugtoolbar toolbar = flask_debugtoolbar.DebugToolbarExtension(app) csrf.exempt(flask_debugtoolbar.panels.sqlalchemy.sql_select) else: # production logger to stderr handler = logging.StreamHandler() handler.setLevel(logging.INFO) handler.setFormatter( logging.Formatter( '[%(asctime)s] %(levelname)s in %(module)s: %(message)s')) app.logger.setLevel(logging.INFO) app.logger.addHandler(handler) # sqlalchemy treats columns as nullable by default, which we don't want. Column = partial(sqla.Column, nullable=False) from db.fsmi import Cookie