Keep source, config, and deploy files. Leave runtime data, uploads, and logs out of git. Co-authored-by: Cursor <cursoragent@cursor.com>
88 lines
2.8 KiB
Python
88 lines
2.8 KiB
Python
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.testclient import TestClient
|
|
|
|
from kamidso.api.app import cors_origins
|
|
from kamidso.api.deps import KamidsoAuthMiddleware
|
|
from kamidso.api.routes.auth import auth_cookie_kwargs
|
|
|
|
|
|
def _client() -> TestClient:
|
|
app = FastAPI()
|
|
|
|
@app.get("/api/kamidso/v1/auth/session")
|
|
def session():
|
|
return {"ok": True}
|
|
|
|
app.add_middleware(KamidsoAuthMiddleware)
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=cors_origins(),
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
return TestClient(app)
|
|
|
|
|
|
def test_frontend_origins_are_allowed():
|
|
origins = cors_origins()
|
|
assert "https://kamidso.com" in origins
|
|
assert "https://www.kamidso.com" in origins
|
|
assert "*" not in origins
|
|
|
|
|
|
def test_production_cors_is_exactly_the_two_site_origins(monkeypatch):
|
|
monkeypatch.setenv("KAMIDSO_ENV", "production")
|
|
monkeypatch.setenv("KAMIDSO_CORS_ORIGINS", "*,https://evil.example")
|
|
assert cors_origins() == [
|
|
"https://kamidso.com",
|
|
"https://www.kamidso.com",
|
|
]
|
|
|
|
|
|
def test_local_cors_rejects_a_wildcard(monkeypatch):
|
|
monkeypatch.delenv("KAMIDSO_ENV", raising=False)
|
|
monkeypatch.setenv("KAMIDSO_CORS_ORIGINS", "*")
|
|
assert "*" not in cors_origins()
|
|
|
|
|
|
def test_session_preflight_from_frontend_is_allowed():
|
|
response = _client().options(
|
|
"/api/kamidso/v1/auth/session",
|
|
headers={
|
|
"Origin": "https://kamidso.com",
|
|
"Access-Control-Request-Method": "GET",
|
|
"Access-Control-Request-Headers": "content-type",
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
assert response.headers["access-control-allow-origin"] == "https://kamidso.com"
|
|
assert response.headers["access-control-allow-credentials"] == "true"
|
|
|
|
|
|
def test_production_cookie_is_secure_and_host_only(monkeypatch):
|
|
monkeypatch.setenv("KAMIDSO_ENV", "production")
|
|
settings = type("Settings", (), {"jwt_expire_minutes": 10})()
|
|
params = auth_cookie_kwargs(settings)
|
|
assert params["secure"] is True
|
|
assert params["httponly"] is True
|
|
assert params["samesite"] == "lax"
|
|
assert params["path"] == "/"
|
|
assert "domain" not in params
|
|
|
|
|
|
def test_local_cookie_stays_usable_on_http(monkeypatch):
|
|
monkeypatch.delenv("KAMIDSO_ENV", raising=False)
|
|
settings = type("Settings", (), {"jwt_expire_minutes": 10})()
|
|
assert auth_cookie_kwargs(settings)["secure"] is False
|
|
|
|
|
|
def test_session_without_login_is_unauthorized_and_still_cors():
|
|
response = _client().get(
|
|
"/api/kamidso/v1/auth/session",
|
|
headers={"Origin": "https://www.kamidso.com"},
|
|
)
|
|
assert response.status_code == 401
|
|
assert response.headers["access-control-allow-origin"] == "https://www.kamidso.com"
|