gabriel / musehub public
musehub_abuse_models.py python
84 lines 3.0 KB
Raw
sha256:cdfe164af70b640f93370907508ae9066c78c19dfd97f36e14aab34c3d539496 docs: add production-readiness checklist Sonnet 5 34 days ago
1 """ORM models for abuse prevention and security.
2
3 Tables:
4 - musehub_blocked_hashes: Content blocklist — object IDs that must never be indexed or served
5 - musehub_daily_push_bytes: Per-user daily mpack upload byte counter
6 - musehub_push_anomalies: Anomaly detection records for spike pushes
7 """
8
9 from __future__ import annotations
10
11 from datetime import date, datetime, timezone
12
13 import sqlalchemy as sa
14 from sqlalchemy import DateTime, Index, String, Text
15 from sqlalchemy.orm import Mapped, mapped_column
16
17 from musehub.db.database import Base
18
19
20 def _utc_now() -> datetime:
21 return datetime.now(tz=timezone.utc)
22
23
24 class MusehubBlockedHash(Base):
25 """Content blocklist — object IDs that must never be indexed or served.
26
27 Seeded from NCMEC / Project VIC hash lists and DMCA takedown requests.
28 Checked in process_mpack_index_job before any MinIO writes; a match
29 quarantines the entire mpack.
30 """
31
32 __tablename__ = "musehub_blocked_hashes"
33
34 object_id: Mapped[str] = mapped_column(String(128), primary_key=True)
35 reason: Mapped[str | None] = mapped_column(Text, nullable=True)
36 added_by: Mapped[str | None] = mapped_column(String(128), nullable=True)
37 added_at: Mapped[datetime] = mapped_column(
38 DateTime(timezone=True), nullable=False, default=_utc_now
39 )
40
41
42 class MusehubDailyPushBytes(Base):
43 """Per-user daily mpack upload byte counter.
44
45 Upserted at mpack-presign time. Checked before issuing a presigned URL;
46 requests that would push the daily total past mpack_daily_upload_limit_bytes
47 are rejected with 429.
48 """
49
50 __tablename__ = "musehub_daily_push_bytes"
51 __table_args__ = (
52 Index("ix_daily_push_bytes_identity_date", "identity_id", "date"),
53 )
54
55 identity_id: Mapped[str] = mapped_column(String(128), primary_key=True)
56 date: Mapped[date] = mapped_column(sa.Date, primary_key=True)
57 bytes_uploaded: Mapped[int] = mapped_column(sa.BigInteger, nullable=False, default=0)
58 updated_at: Mapped[datetime] = mapped_column(
59 DateTime(timezone=True), nullable=False, default=_utc_now, onupdate=_utc_now
60 )
61
62
63 class MusehubPushAnomaly(Base):
64 """Anomaly detection records for spike pushes.
65
66 Inserted (not rejected) when a user's push volume is >10× their 30-day
67 rolling average. Operators review these records to distinguish legitimate
68 large pushes from abuse.
69 """
70
71 __tablename__ = "musehub_push_anomalies"
72 __table_args__ = (
73 Index("ix_push_anomalies_identity", "identity_id"),
74 )
75
76 anomaly_id: Mapped[str] = mapped_column(String(128), primary_key=True)
77 identity_id: Mapped[str] = mapped_column(String(128), nullable=False, index=True)
78 detected_at: Mapped[datetime] = mapped_column(
79 DateTime(timezone=True), nullable=False, default=_utc_now
80 )
81 bytes_today: Mapped[int] = mapped_column(sa.BigInteger, nullable=False)
82 rolling_avg_bytes: Mapped[float] = mapped_column(sa.Float, nullable=False)
83 ratio: Mapped[float] = mapped_column(sa.Float, nullable=False)
84
File History 1 commit
sha256:cdfe164af70b640f93370907508ae9066c78c19dfd97f36e14aab34c3d539496 docs: add production-readiness checklist Sonnet 5 34 days ago