- config.py: add refresh_token_expire_hours=16, jwt_private_key, jwt_public_key fields (D-01, D-09) - services/auth.py: swap all 4 JWT sites to ES256 via base64-decoded PEM keys; remove HS256 (D-02, D-03) - main.py: add _rotate_tokens_on_algorithm_change lifespan hook — bulk-revokes refresh tokens on algorithm change; idempotent on repeat boots (D-04, D-05) - test_auth_es256.py: promote ES256-01..05 + CFG-01 stubs to 6 passing tests; RM-01..03 remain xfail - docker-compose.yml: inject JWT_PRIVATE_KEY + JWT_PUBLIC_KEY into backend + celery-worker (D-07) - README.md: add JWT key env vars + key generation Python one-liner snippet - .env.example: add JWT_PRIVATE_KEY= and JWT_PUBLIC_KEY= lines - Version bump to 0.1.2
83 lines
3.1 KiB
Python
83 lines
3.1 KiB
Python
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
"""Phase 1 Pydantic Settings — reads all Phase 1 env vars from environment or .env file."""
|
|
|
|
model_config = SettingsConfigDict(
|
|
env_file=".env",
|
|
env_file_encoding="utf-8",
|
|
extra="ignore",
|
|
env_list_separator=",",
|
|
)
|
|
|
|
# PostgreSQL
|
|
database_url: str = "postgresql+psycopg://docuvault_app:changeme_app@postgres:5432/docuvault"
|
|
database_migrate_url: str = "postgresql+psycopg://docuvault_migrate:changeme_migrate@postgres:5432/docuvault"
|
|
|
|
# MinIO
|
|
minio_endpoint: str = "minio:9000"
|
|
minio_access_key: str = "docuvault_app"
|
|
minio_secret_key: str = "changeme_minio_app"
|
|
minio_bucket: str = "docuvault"
|
|
# RESEARCH.md Finding 3 — browser-resolvable hostname for presigned URLs.
|
|
# Empty string means fall back to minio_endpoint inside MinIOBackend.
|
|
minio_public_endpoint: str = ""
|
|
|
|
# Redis / Celery
|
|
redis_url: str = "redis://:changeme_redis@redis:6379/0"
|
|
|
|
# Security (Phase 2 — documented now, not read by Phase 1 code paths)
|
|
secret_key: str = "CHANGEME"
|
|
|
|
# Auth / JWT (Phase 2)
|
|
access_token_expire_minutes: int = 15
|
|
refresh_token_expire_days: int = 30
|
|
# ES256 keypair + short-session TTL (Phase 7.3 — D-01, D-09)
|
|
refresh_token_expire_hours: int = 16 # default short session (16h workday)
|
|
jwt_private_key: str = "" # base64-encoded PKCS8 PEM; required at runtime
|
|
jwt_public_key: str = "" # base64-encoded SubjectPublicKeyInfo PEM; required at runtime
|
|
|
|
# SMTP (Phase 2 — D-01)
|
|
smtp_host: str = ""
|
|
smtp_port: int = 587
|
|
smtp_user: str = ""
|
|
smtp_password: str = ""
|
|
smtp_from: str = "noreply@docuvault.local"
|
|
|
|
# Admin bootstrap (Phase 2 — D-04)
|
|
admin_email: str = ""
|
|
admin_password: str = ""
|
|
|
|
# CORS (Phase 2 — D-09)
|
|
cors_origins: list[str] = ["http://localhost:5173"]
|
|
|
|
# Frontend URL — used to build password reset links (D-02, D-03)
|
|
frontend_url: str = "http://localhost:5173"
|
|
|
|
# AI classification defaults (Phase 3 — D-13, D-15)
|
|
system_prompt: str = "" # SYSTEM_PROMPT env var; hardcoded fallback lives in classifier.py
|
|
default_ai_provider: str = "ollama" # DEFAULT_AI_PROVIDER env var
|
|
default_ai_model: str = "llama3.2" # DEFAULT_AI_MODEL env var
|
|
|
|
# Cloud Storage (Phase 5)
|
|
# master key for HKDF per-user credential encryption — must be overridden in production
|
|
cloud_creds_key: str = "CHANGEME-32-bytes-padded!!"
|
|
google_client_id: str = ""
|
|
google_client_secret: str = ""
|
|
onedrive_client_id: str = ""
|
|
onedrive_client_secret: str = ""
|
|
# "common" works for both personal and org accounts
|
|
onedrive_tenant_id: str = "common"
|
|
# used to construct OAuth callback URLs (e.g. {backend_url}/api/cloud/google/callback)
|
|
backend_url: str = "http://localhost:8000"
|
|
# used to construct OAuth success/error redirect to Vue app (per Phase 5 B4 fix)
|
|
# Note: frontend_url already declared above for Phase 2 (password reset links) — shared field
|
|
|
|
# Observability (Phase 6 — D-01)
|
|
log_level: str = "INFO"
|
|
log_json: bool = False
|
|
|
|
|
|
settings = Settings()
|