Publishes the IP ranges and email domains the bot has auto-blocked as JSON: GET /api/blocks, /api/blocks/ip-ranges, /api/blocks/email-domains, each taking an optional ?limit=N. The endpoints are unauthenticated, so BLOCKS_API_ENABLED gates them and defaults to false — with it unset the paths 404 as if they didn't exist. Publishing which ranges are already blocked also tells a spam signup which ones to avoid, so opting in is a per-deployment call; yttrx.com sets it true in the box's .env. Responses assert only that a block exists: the blocked range/domain, a signups count, and first/last seen. No account identifiers, and none of the ipapi.is or check-mail.org classification that drove the decision — republishing a paid reputation feed's verdicts on an open endpoint would be redistributing their data rather than ours. Supporting changes: - signup_ip gains a block_cidr column (migrated in place on open) so the API reports the network actually blocked rather than the signup IP. Rows predating it fall back to that IP's /32 or /128, which is exactly what was registered before range-blocking started 2026-07-15. - register_ip_block / register_email_domain_block now return whether the block landed, and the caller only marks it registered on success, so a failed POST is no longer published as a block that exists.
This commit is contained in:
1 parent
1a3e112946
commit
eb6d7cad46
6 files changed
+422
-22
No files matched your search
@@ -191,6 +191,63 @@ section for the remint procedure.
|
||||
Inspect the watch list: `welcomebot-suspicious` / `welcomebot-suspicious --pending`
|
||||
(see `bin/welcomebot-suspicious`).
|
||||
|
||||
## Blocklist API (`/api/blocks`)
|
||||
|
||||
An optional, **read-only** JSON view of what the bot has auto-blocked. Three
|
||||
endpoints, all `GET`, all accepting an optional `?limit=N`:
|
||||
|
||||
| Path | Returns |
|
||||
|---|---|
|
||||
| `/api/blocks` | both lists in one document |
|
||||
| `/api/blocks/ip-ranges` | networks registered as `Admin::IpBlock` |
|
||||
| `/api/blocks/email-domains` | domains registered as `Admin::EmailDomainBlock` |
|
||||
|
||||
```json
|
||||
{
|
||||
"generated_at": "2026-09-13T00:00:00+00:00",
|
||||
"ip_ranges": {
|
||||
"count": 1,
|
||||
"items": [
|
||||
{"cidr": "198.51.100.0/24", "signups": 3,
|
||||
"first_blocked_at": "2026-07-15 09:12:04",
|
||||
"last_blocked_at": "2026-08-30 22:41:18"}
|
||||
]
|
||||
},
|
||||
"email_domains": {
|
||||
"count": 1,
|
||||
"items": [
|
||||
{"domain": "temp-mail.org", "signups": 2,
|
||||
"first_blocked_at": "2026-07-03 11:02:55",
|
||||
"last_blocked_at": "2026-07-19 16:30:09"}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Off by default.** These paths are served *without authentication*, so they
|
||||
404 unless `BLOCKS_API_ENABLED=true` is set — publishing which ranges and
|
||||
domains are already blocked also tells a would-be spam signup which ones to
|
||||
avoid, and that's a per-deployment call. yttrx.com opts in; the shipped
|
||||
default doesn't. `BLOCKS_API_MAX_ITEMS` (default 5000) caps the response size
|
||||
whatever `?limit` asks for, and `BLOCKS_API_CACHE_SECONDS` (default 300) sets
|
||||
the `Cache-Control: public, max-age=…` on responses.
|
||||
|
||||
What the response deliberately does **not** contain:
|
||||
|
||||
- **No account identifiers** — no handles, account ids, emails or signup IPs.
|
||||
Repeat signups out of one range collapse into a single entry with a
|
||||
`signups` count.
|
||||
- **No classification data.** The ipapi.is verdict (`datacenter`/`proxy`/…),
|
||||
the org name, and check-mail.org's disposable flag and risk score all stay
|
||||
out of the response. They're what *drove* each decision, but republishing a
|
||||
paid reputation feed's verdicts on an open endpoint would be redistributing
|
||||
their data rather than ours. An entry asserts only that the block exists.
|
||||
|
||||
Scope: this is the **bot's own record**, not Mastodon's full blocklist —
|
||||
blocks a moderator added by hand in the admin UI are not in it. Entries appear
|
||||
only once the block actually landed on the Mastodon side (a failed
|
||||
`POST /api/v1/admin/ip_blocks` is logged and *not* recorded as blocked).
|
||||
|
||||
## Layout
|
||||
|
||||
| Path | Purpose |
|
||||
@@ -199,7 +256,7 @@ Inspect the watch list: `welcomebot-suspicious` / `welcomebot-suspicious --pendi
|
||||
| `app/suspicious_sweep.py` | Scheduled sweep: suspends flagged signups with no activity (run via cron, not the webserver) |
|
||||
| `Dockerfile`, `docker-compose.yml` | Container build + run |
|
||||
| `.env.example` | Config template (copy to `.env`, never commit) |
|
||||
| `nginx/hooks.yttrx.com.conf` | nginx site for admin.yttrx.com |
|
||||
| `nginx/hooks.yttrx.com.conf` | nginx site for admin.yttrx.com (webhook, healthz, blocklist API) |
|
||||
| `bin/welcomebot-logs`, `bin/welcomebot-signups`, `bin/welcomebot-suspicious` | Ops CLIs installed to `/root/bin` on admin.yttrx.com |
|
||||
| `test_local.py` | Offline smoke test (no network) |
|
||||
|
||||
|
||||
Reference in new issue
Block a user