Files
flaskpaste/app/config.py
Username 7deba711d4 entropy: exempt small content from check
Small data has unreliable entropy measurement due to sample size.
MIN_ENTROPY_SIZE (default 256 bytes) sets the threshold.
2025-12-20 08:48:13 +01:00

90 lines
3.1 KiB
Python

"""Application configuration."""
import os
from pathlib import Path
# Application version
VERSION = "1.1.0"
class Config:
"""Base configuration."""
BASE_DIR = Path(__file__).parent.parent
DATABASE = os.environ.get("FLASKPASTE_DB", BASE_DIR / "data" / "pastes.db")
PASTE_ID_LENGTH = int(os.environ.get("FLASKPASTE_ID_LENGTH", "12"))
# Paste size limits
MAX_PASTE_SIZE_ANON = int(os.environ.get("FLASKPASTE_MAX_ANON", 3 * 1024 * 1024)) # 3MiB
MAX_PASTE_SIZE_AUTH = int(os.environ.get("FLASKPASTE_MAX_AUTH", 50 * 1024 * 1024)) # 50MiB
MAX_CONTENT_LENGTH = MAX_PASTE_SIZE_AUTH # Flask request limit
# Paste expiry (default 5 days)
PASTE_EXPIRY_SECONDS = int(os.environ.get("FLASKPASTE_EXPIRY", 5 * 24 * 60 * 60))
# Content deduplication / abuse prevention
# Throttle repeated submissions of identical content
CONTENT_DEDUP_WINDOW = int(os.environ.get("FLASKPASTE_DEDUP_WINDOW", 3600)) # 1 hour
CONTENT_DEDUP_MAX = int(os.environ.get("FLASKPASTE_DEDUP_MAX", 3)) # max 3 per window
# Minimum entropy requirement (0 = disabled)
# Encrypted data has ~7.5-8.0 bits/byte, plaintext ~4.0-5.0
# Set to 6.0+ to effectively require encryption
MIN_ENTROPY = float(os.environ.get("FLASKPASTE_MIN_ENTROPY", 0))
# Minimum size for entropy check (small data has unreliable entropy measurement)
MIN_ENTROPY_SIZE = int(os.environ.get("FLASKPASTE_MIN_ENTROPY_SIZE", 256))
# Reverse proxy trust configuration
# SECURITY: The X-SSL-Client-SHA1 header is trusted for authentication.
# This header MUST only come from a trusted reverse proxy that validates
# client certificates. Direct access to this app MUST be blocked.
#
# Set FLASKPASTE_PROXY_SECRET to require the proxy to send a matching
# X-Proxy-Secret header, providing defense-in-depth against header spoofing.
TRUSTED_PROXY_SECRET = os.environ.get("FLASKPASTE_PROXY_SECRET", "")
# Proof-of-work spam prevention
# Clients must solve a computational puzzle before paste creation.
# Difficulty is number of leading zero bits required in hash (0 = disabled).
POW_DIFFICULTY = int(os.environ.get("FLASKPASTE_POW_DIFFICULTY", "20"))
POW_CHALLENGE_TTL = int(os.environ.get("FLASKPASTE_POW_TTL", "300")) # 5 minutes
# Secret key for signing challenges (auto-generated if not set)
POW_SECRET = os.environ.get("FLASKPASTE_POW_SECRET", "")
# URL prefix for reverse proxy deployments (e.g., "/paste" for mymx.me/paste)
URL_PREFIX = os.environ.get("FLASKPASTE_URL_PREFIX", "").rstrip("/")
class DevelopmentConfig(Config):
"""Development configuration."""
DEBUG = True
class ProductionConfig(Config):
"""Production configuration."""
DEBUG = False
class TestingConfig(Config):
"""Testing configuration."""
TESTING = True
DATABASE = ":memory:"
# Relaxed dedup for testing (100 per second window)
CONTENT_DEDUP_WINDOW = 1
CONTENT_DEDUP_MAX = 100
# Disable PoW for most tests (easier testing)
POW_DIFFICULTY = 0
config = {
"development": DevelopmentConfig,
"production": ProductionConfig,
"testing": TestingConfig,
"default": DevelopmentConfig,
}