29 lines
1.1 KiB
Python
29 lines
1.1 KiB
Python
"""Singleton Flask extension instances — initialized, not configured, here.
|
|
|
|
Configuration happens in create_app() via .init_app(), so nothing here
|
|
holds app- or request-scoped state that must survive a process restart
|
|
(factor 6: stateless processes).
|
|
"""
|
|
from flask_caching import Cache
|
|
from flask_limiter import Limiter
|
|
from flask_limiter.util import get_remote_address
|
|
from flask_login import LoginManager
|
|
from flask_migrate import Migrate
|
|
from flask_sqlalchemy import SQLAlchemy
|
|
from flask_wtf import CSRFProtect
|
|
|
|
db = SQLAlchemy()
|
|
cache = Cache()
|
|
csrf = CSRFProtect()
|
|
login_manager = LoginManager()
|
|
login_manager.login_view = "auth.login"
|
|
migrate = Migrate()
|
|
|
|
# In-memory storage (Chapter 12: "in-memory or DB-backed... do not require
|
|
# Redis"). CAVEAT (flagged): each of up to 60 entry processes (Ch03) keeps
|
|
# its own counters, so the effective ceiling across the whole app is up to
|
|
# (per-process limit x concurrent processes hit), not one hard global cap.
|
|
# Acceptable for this app's threat model (slowing down /login and /uploads
|
|
# brute-forcing), but not a strict global rate guarantee.
|
|
limiter = Limiter(key_func=get_remote_address, storage_uri="memory://")
|