Full-stack self-hosted finance app with FastAPI backend and React frontend. Features: - Accounts, transactions, budgets, investments with GBP base currency - CSV import with auto-detection for 10 UK bank formats - ML predictions: spending forecast, net worth projection, Monte Carlo - 7 selectable themes (Obsidian, Arctic, Midnight, Vault, Terminal, Synthwave, Ledger) - Receipt/document attachments on transactions (JPEG, PNG, WebP, PDF) - AES-256-GCM field encryption, RS256 JWT, TOTP 2FA, RLS, audit log - Encrypted nightly backups + key rotation script - Mobile-responsive layout with bottom nav Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
28 lines
714 B
Python
28 lines
714 B
Python
"""
|
|
Redis sliding window rate limiter.
|
|
"""
|
|
import time
|
|
from redis.asyncio import Redis
|
|
|
|
|
|
async def is_rate_limited(
|
|
redis: Redis,
|
|
key: str,
|
|
limit: int,
|
|
window_seconds: int = 60,
|
|
) -> tuple[bool, int]:
|
|
"""
|
|
Returns (is_limited, requests_remaining).
|
|
Uses a sorted set with timestamps as scores for sliding window.
|
|
"""
|
|
now = time.time()
|
|
window_start = now - window_seconds
|
|
pipe = redis.pipeline()
|
|
pipe.zremrangebyscore(key, 0, window_start)
|
|
pipe.zadd(key, {str(now): now})
|
|
pipe.zcard(key)
|
|
pipe.expire(key, window_seconds + 1)
|
|
results = await pipe.execute()
|
|
count = results[2]
|
|
remaining = max(0, limit - count)
|
|
return count > limit, remaining
|