config.py.example# Configuration file. Each variable can be overridden by a # corresponding environment variable import os import sys import copy import logging import pathlib from slowapi import Limiter from slowapi.util import get_remote_address from fastapi_login import LoginManager # Authentication configuration LOGIN_SECRET_KEY = ( os.getenv("LOGIN_SECRET_KEY") or "login-secret" ) # Recommended value: os.urandom(24).hex() USE_BEARER_HEADER = True USE_COOKIE = True # Logging configuration LOG_LEVEL = int(os.getenv("LOG_LEVEL") or 0) or 20 LOG_FILE = os.getenv("LOG_FILE") or "" # Empty to disable LOG_FORMAT = os.getenv("LOG_FORMAT") or "[%(levelname)s - %(asctime)s] %(message)s" LOG_DATE_FORMAT = os.getenv("LOG_DATE_FORMAT") or "%d/%m/%Y %p" # Bcrypt configuration BCRYPT_ROUNDS = ( os.getenv("BCRYPT_ROUNDS") or 10 ) # How many rounds are used when salting # Rate limit configuration REDIS_URL = "" # Used for rate limits. Empty to fall back to memory REDIS_OPTIONS = {} # Options for redis RATELIMIT_ENABLED = False # False to disable rate limiting RATELIMIT_STRATEGY = "moving-window" # Refer to https://flask-limiter.readthedocs.io/en/stable/strategies.html # Session configuration SESSION_EXPIRE_LIMIT = 3600 # Unit is in seconds SESSION_COOKIE_NAME = "_social_media_session" COOKIE_SAMESITE_POLICY = "none" # Options are "lax", "none", "strict" COOKIE_DOMAIN = "localhost" # Empty to disable this COOKIE_PATH = "/" COOKIE_HTTPONLY = True SECURE_COOKIE = False # Set to true in production, False during development (unless your local server has HTTPS) # SMTP configuration SMTP_HOST = "smtp.nocturn9x.space" SMTP_USER = "info@example.com" SMTP_PASSWORD = "password" SMTP_PORT = 587 SMTP_USE_TLS = True SMTP_FROM_USER = "info@example.com" SMTP_TEMPLATES_DIRECTORY = pathlib.Path(__file__) / "templates" / "email" SMTP_TIMEOUT = 10 # Miscellaneous # Usernames containing these characters are not valid INVALID_USERNAME_CHARACTERS = ["@", "\\", "/"] # Empty this to allow any character # Empty this to disable username validation VALIDATE_USERNAME_REGEX = ( rf"^([^{''.join(INVALID_USERNAME_CHARACTERS)}]|[a-z0-9A-Z]){{5,32}}$" ) # Criteria: # - Between 10 and 72 characters long # - At least 2 uppercase letters # - At least 3 lowercase letters # - At least one special character (!, @, #, $, %, &, *, _, +, /, \, (, ), £, ", ?, ^ # - At least 2 numbers # You can change the repetitions to enforce stricter/laxer rules or empty # this field to disable weakness validation VALIDATE_PASSWORD_REGEX = r"^(?=.*[A-Z]){2,}(?=.*[\"!@%#$&*_^\?\\\/(\)\+\-])+(?=.*[0-9]){2,}(?=.*[a-z]){3,}.{10,72}$" FORCE_EMAIL_VERIFICATION = False EMAIL_VERIFICATION_EXPIRATION = 3600 # In seconds PLATFORM_NAME = "PySimpleSocial" # Used in emails HAS_HTTPS = False class NotAuthenticated(Exception): pass class AdminNotAuthenticated(Exception): pass if __name__ != "__main__": LOGGER: logging.Logger = logging.getLogger("socialMedia") LOGGER.setLevel(LOG_LEVEL) handler = logging.StreamHandler(sys.stderr) formatter = logging.Formatter(fmt=LOG_FORMAT, datefmt=LOG_DATE_FORMAT) handler.setFormatter(formatter) LOGGER.addHandler(handler) handler.setLevel(LOG_LEVEL) if LOG_FILE: file_handler = logging.FileHandler(LOG_FILE, "a", "utf8") file_handler.setFormatter(formatter) LOGGER.addHandler(handler) file_handler.setLevel(LOG_LEVEL) logging.getLogger("uvicorn").addHandler(file_handler) LIMITER = Limiter( key_func=get_remote_address, strategy=RATELIMIT_STRATEGY, storage_uri=REDIS_URL or None, in_memory_fallback_enabled=bool(REDIS_URL), storage_options=REDIS_OPTIONS, enabled=RATELIMIT_ENABLED, ) MANAGER = LoginManager( LOGIN_SECRET_KEY, "/user", use_cookie=True, cookie_name=SESSION_COOKIE_NAME, use_header=USE_BEARER_HEADER, custom_exception=NotAuthenticated, ) UNVERIFIED_MANAGER = copy.deepcopy(MANAGE) ADMIN_MANAGER = LoginManager( LOGIN_SECRET_KEY, "/admin", use_cookie=True, cookie_name=f"{SESSION_COOKIE_NAME}_admin", use_header=USE_BEARER_HEADER, custom_exception=AdminNotAuthenticated ) # Uvicorn config HOST = os.getenv("HOST") or "localhost" PORT = int(os.getenv("PORT") or 0) or 8000 WORKERS = int(os.getenv("PORT") or 0) or 1 # Storage configuration STORAGE_ENGINE = "database" # Stores media inside the database. Other options are "local" to use a local/remote folder # or "url" for uploading to a CDN STORAGE_FOLDER = "" # Only needed when STORAGE_ENGINE is set to local MAX_MEDIA_SIZE = 5242880 # Max length of media allowed. Anything bigger raises a 415 HTTP Exception ALLOWED_MEDIA_TYPES = ["gif", "png", "jpeg", "tiff"] ZLIB_COMPRESSION_LEVEL = 9