Dns validation for https (#49)
* Add DNS-01 challenge support for Let's Encrypt Co-authored-by: mathieumoran1 <[email protected]> * Refactor letsencrypt script to use /dev/tty for interactive prompts Co-authored-by: mathieumoran1 <[email protected]> * feat: Add optional DNS hook mode for certonly Co-authored-by: mathieumoran1 <[email protected]> * Refactor: Improve MongoDB connection and add certifi Co-authored-by: mathieumoran1 <[email protected]> * Checkpoint before follow-up message Co-authored-by: mathieumoran1 <[email protected]> --------- Co-authored-by: Cursor Agent <[email protected]>
This commit was merged in pull request #49.
This commit is contained in:
co-authored by
Cursor Agent
parent
812590d262
commit
5325576dc4
@@ -1,6 +1,8 @@
|
||||
import mimetypes
|
||||
import os
|
||||
import posixpath
|
||||
import ssl
|
||||
from functools import lru_cache
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Generator, Optional, Tuple
|
||||
@@ -13,6 +15,7 @@ from fastapi import FastAPI, Header, HTTPException, Request, Response
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import FileResponse, StreamingResponse
|
||||
from pymongo import MongoClient
|
||||
from pymongo.errors import PyMongoError
|
||||
|
||||
|
||||
def _env_str(name: str, default: str = "") -> str:
|
||||
@@ -49,6 +52,12 @@ def _mongo_db_name() -> str:
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
def _env_int(name: str, default: int) -> int:
|
||||
try:
|
||||
return int(_env_str(name, str(default)))
|
||||
except Exception:
|
||||
return default
|
||||
|
||||
|
||||
def _video_files_dir() -> Path:
|
||||
# Read env at runtime (important on Windows/uvicorn worker reloads).
|
||||
@@ -143,7 +152,51 @@ def _mongo_client() -> MongoClient:
|
||||
uri = _mongo_uri()
|
||||
if not uri:
|
||||
raise HTTPException(status_code=500, detail="MONGO_URI is not configured")
|
||||
return MongoClient(uri)
|
||||
kwargs = {
|
||||
# Fail fast instead of hanging for ~30s on each request.
|
||||
"serverSelectionTimeoutMS": _env_int("MONGO_SERVER_SELECTION_TIMEOUT_MS", 8000),
|
||||
"connectTimeoutMS": _env_int("MONGO_CONNECT_TIMEOUT_MS", 8000),
|
||||
"socketTimeoutMS": _env_int("MONGO_SOCKET_TIMEOUT_MS", 20000),
|
||||
}
|
||||
|
||||
# On some hosts, the system CA store is missing/broken or overridden by env vars,
|
||||
# causing TLS handshake failures to MongoDB Atlas. Prefer certifi's CA bundle.
|
||||
ca_file = _env_str("MONGO_TLS_CA_FILE")
|
||||
if ca_file:
|
||||
kwargs["tlsCAFile"] = ca_file
|
||||
else:
|
||||
try:
|
||||
import certifi # type: ignore
|
||||
|
||||
kwargs["tlsCAFile"] = certifi.where()
|
||||
except Exception:
|
||||
# If certifi isn't available, fall back to system trust.
|
||||
pass
|
||||
|
||||
# Some hosts / middleboxes break TLS 1.3 handshakes to Atlas and produce
|
||||
# `TLSV1_ALERT_INTERNAL_ERROR`. Forcing TLS 1.2 can fix it.
|
||||
if _env_str("MONGO_TLS_FORCE_TLS12", "0") in ("1", "true", "yes", "on"):
|
||||
cafile = kwargs.pop("tlsCAFile", None)
|
||||
ctx = ssl.create_default_context(cafile=cafile)
|
||||
try:
|
||||
ctx.minimum_version = ssl.TLSVersion.TLSv1_2
|
||||
ctx.maximum_version = ssl.TLSVersion.TLSv1_2
|
||||
except Exception:
|
||||
# Older Python/OpenSSL may not support TLSVersion fields.
|
||||
pass
|
||||
kwargs["ssl_context"] = ctx
|
||||
|
||||
# Optional escape hatch (NOT recommended): allow invalid certs for debugging only.
|
||||
if _env_str("MONGO_TLS_INSECURE", "0") in ("1", "true", "yes", "on"):
|
||||
kwargs["tlsAllowInvalidCertificates"] = True
|
||||
|
||||
return MongoClient(uri, **kwargs)
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _mongo_client_cached() -> MongoClient:
|
||||
# Reuse one client (connection pool) across requests.
|
||||
return _mongo_client()
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
@@ -211,15 +264,26 @@ def stream_video(
|
||||
except Exception:
|
||||
raise HTTPException(status_code=400, detail="Invalid movie id")
|
||||
|
||||
with _mongo_client() as client:
|
||||
db_name = _mongo_db_name()
|
||||
if not db_name:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Mongo DB name not configured. Add it to MONGO_URI (…/dbname) or set MONGO_DB_NAME.",
|
||||
)
|
||||
db_name = _mongo_db_name()
|
||||
if not db_name:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Mongo DB name not configured. Add it to MONGO_URI (…/dbname) or set MONGO_DB_NAME.",
|
||||
)
|
||||
|
||||
try:
|
||||
client = _mongo_client_cached()
|
||||
db = client[db_name]
|
||||
movie = db["movies"].find_one({"_id": oid}, {"video_file": 1})
|
||||
except PyMongoError as e:
|
||||
raise HTTPException(
|
||||
status_code=502,
|
||||
detail=(
|
||||
"Failed to query MongoDB (TLS/connection issue). "
|
||||
"On some hosts you may need a CA bundle; try installing certifi or set MONGO_TLS_CA_FILE. "
|
||||
f"Original error: {type(e).__name__}: {e}"
|
||||
),
|
||||
)
|
||||
|
||||
video_file = (movie or {}).get("video_file") or ""
|
||||
if not isinstance(video_file, str) or not video_file.strip():
|
||||
@@ -287,5 +351,16 @@ def healthz():
|
||||
"time": datetime.now(timezone.utc).isoformat(),
|
||||
"video_files_dir": str(_video_files_dir()),
|
||||
"mongo_db_name": _mongo_db_name() or None,
|
||||
"openssl": ssl.OPENSSL_VERSION,
|
||||
}
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
def _shutdown():
|
||||
# Close the cached Mongo client cleanly.
|
||||
try:
|
||||
client = _mongo_client_cached()
|
||||
client.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
Reference in New Issue
Block a user