Funn fra sikkerhetsgjennomgang: - HØY: post_id ble ikke validert, så en gjest kunne nå andres innlegg via gjest/../../posts/<slug> (lese utkast, laste opp/slette bilder, publisere eierens utkast). Slug og gjestenavn valideres nå mot samme alfabet de lages med, og stien sjekkes etter oppslag. - Bilder: pikselantall sjekkes før dekoding (maks 40 MP), og DecompressionBombError håndteres. - Innlogging: CSRF-token kreves også på login (login-CSRF), og innloggingsbrems etter 5 feil per brukernavn. - Passordbytte ugyldiggjør alle andre sesjoner (stempel i cookien). - Content-Security-Policy og X-Frame-Options på alle sider; admin har ingen inline script lenger (admin.js). - Gjestenavn og eier-slugs kan ikke lenger kollidere på /navn/. - Healthcheck respekterer SOAPBOX_BASE_PATH; login-redirect beholder base path; run.sh dropper capabilities og setter minnegrense; uv pinnet til 0.11. Rettet også en reell feil: existing_slugs() listet feil katalog (Path / er identitet), så slug-unikhet virket ikke. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
50 lines
1.2 KiB
Python
50 lines
1.2 KiB
Python
import io
|
|
|
|
import pytest
|
|
from PIL import Image
|
|
|
|
from soapbox import db
|
|
from soapbox.app import create_app
|
|
from soapbox.config import load_config
|
|
|
|
|
|
@pytest.fixture
|
|
def cfg(tmp_path):
|
|
return load_config(
|
|
{"SOAPBOX_DATA_DIR": str(tmp_path / "data"), "SOAPBOX_SITE_URL": "https://blog.example.no"}
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def app(cfg):
|
|
app = create_app(cfg)
|
|
app.config["TESTING"] = True
|
|
conn = db.connect(cfg.db_path)
|
|
db.create_user(conn, "eier", "hemmelig123", db.ROLE_OWNER, "Ole")
|
|
db.create_user(conn, "gjest1", "hemmelig123", db.ROLE_GUEST, "Gjest En")
|
|
conn.close()
|
|
return app
|
|
|
|
|
|
@pytest.fixture
|
|
def client(app):
|
|
return app.test_client()
|
|
|
|
|
|
def login(client, username="eier", password="hemmelig123", prefix=""):
|
|
client.get(f"{prefix}/admin/login") # gir sesjonen et CSRF-token
|
|
return client.post(
|
|
f"{prefix}/admin/login",
|
|
data={"username": username, "password": password, "csrf": csrf(client, prefix)},
|
|
)
|
|
|
|
|
|
def csrf(client, prefix=""):
|
|
with client.session_transaction(path=f"{prefix}/admin/") as s:
|
|
return s["csrf"]
|
|
|
|
|
|
def png_bytes(size=(3000, 1500)):
|
|
buf = io.BytesIO()
|
|
Image.new("RGB", size, "green").save(buf, "PNG")
|
|
return buf.getvalue()
|