Add text format, CORS, and an importer so other instances can use the list
docker-build-push / build-push (push) Successful in 4s
docker-build-push / build-push (push) Successful in 4s
Mastodon has no RBL/DNSBL support — nothing in it consults an outside list when deciding whether to accept a signup, confirmed against v4.7.1 (the only outbound lookup in that path is EmailMxValidator's MX resolution, which feeds the local email_domain_blocks table). So a shared blocklist has to be imported rather than queried live, the same way Garden Fence and other community lists propagate. These are the pieces that make ours importable. - ?format=txt on both per-list endpoints: one entry per line under a '#' comment header, the form blocklists are traded in and the form a cron job can consume without a JSON parser. The combined /api/blocks stays JSON-only — a text rendering would mix CIDRs with domains in one file, defeating the point. An unrecognised ?format is a 400 rather than a silent fallback to JSON, and the enabled-gate still runs first so a disabled deployment 404s either way. - Access-Control-Allow-Origin: * on blocklist responses, so browser-side admin tooling can read them. The data is already public. - bin/yttrx-blocklist-import: standard-library-only importer another admin can run against their own instance. Dry run unless --apply; 422 from Mastodon counts as "already blocked", not an error. The importer defaults IP entries to sign_up_requires_approval rather than the sign_up_block yttrx uses itself. The entries are whole ASN routes, which suits yttrx because a flagged signup here is nearly always datacenter/VPN/proxy space — that calibration isn't transferable, so an importer gets the reviewable severity by default and has to opt into the hard one.
This commit is contained in:
1 parent
af49aab79c
commit
8966de2a1d
5 files changed
+331
-9
No files matched your search
@@ -224,6 +224,54 @@ endpoints, all `GET`, all accepting an optional `?limit=N`:
|
||||
}
|
||||
```
|
||||
|
||||
### Plain-text format
|
||||
|
||||
Both per-list endpoints also take `?format=txt`, which renders one entry per
|
||||
line under a `#` comment header — the form blocklists are normally traded in,
|
||||
and the form another admin's cron job can consume without a JSON parser:
|
||||
|
||||
```bash
|
||||
curl -s 'https://hooks.yttrx.com/api/blocks/ip-ranges?format=txt' | grep -v '^#'
|
||||
curl -s 'https://hooks.yttrx.com/api/blocks/email-domains?format=txt' | grep -v '^#'
|
||||
```
|
||||
|
||||
The combined `/api/blocks` is JSON-only: a text rendering would put CIDRs and
|
||||
domains in one file, and the point of the text form is that it pipes straight
|
||||
into something expecting one kind of entry. Responses carry
|
||||
`Access-Control-Allow-Origin: *` so browser-side tooling can read them.
|
||||
|
||||
### Importing it elsewhere (`bin/yttrx-blocklist-import`)
|
||||
|
||||
Mastodon has **no RBL/DNSBL support** — nothing in it consults an outside list
|
||||
when deciding whether to accept a signup. (The only outbound lookup in that
|
||||
path is `EmailMxValidator`'s MX resolution, and that feeds the *local*
|
||||
`email_domain_blocks` table.) So another instance can't point at this feed
|
||||
live; it has to import, the same way [Garden Fence](https://gardenfence.github.io)
|
||||
and other community lists propagate.
|
||||
|
||||
`bin/yttrx-blocklist-import` does that — standard library only, no install:
|
||||
|
||||
```bash
|
||||
# dry run (the default — nothing is written)
|
||||
./bin/yttrx-blocklist-import --instance https://your.instance --token "$TOKEN"
|
||||
# actually write the blocks
|
||||
./bin/yttrx-blocklist-import --instance https://your.instance --token "$TOKEN" --apply
|
||||
```
|
||||
|
||||
The token needs `admin:write:ip_blocks` and `admin:write:email_domain_blocks`
|
||||
(the script's `--help` has a Rails-console snippet that mints one). Entries
|
||||
already present come back `422` and are counted as "already blocked", not as
|
||||
errors. `--min-signups N` skips one-off entries, `--ips-only`/`--domains-only`
|
||||
take one list, `--limit` caps each.
|
||||
|
||||
**On severity:** the IP entries are whole networks, because on yttrx a flagged
|
||||
signup is almost always datacenter/VPN/proxy space where the next attempt comes
|
||||
from a neighbouring address. That's calibrated to yttrx's traffic, not someone
|
||||
else's, so the importer defaults to `sign_up_requires_approval` — a flagged
|
||||
signup lands in the importer's moderation queue rather than being rejected —
|
||||
even though yttrx runs these at `sign_up_block` itself. `--ip-severity
|
||||
sign_up_block` opts into the harder behaviour.
|
||||
|
||||
**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
|
||||
@@ -268,6 +316,7 @@ only once the block actually landed on the Mastodon side (a failed
|
||||
| `.env.example` | Config template (copy to `.env`, never commit) |
|
||||
| `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 |
|
||||
| `bin/yttrx-blocklist-import` | Importer other admins can run to pull this list into their own instance |
|
||||
| `bin/backfill-block-cidr.py` | One-shot: reconstruct `block_cidr` for rows predating it (run 2026-09-13) |
|
||||
| `test_local.py` | Offline smoke test (no network) |
|
||||
|
||||
|
||||
Reference in new issue
Block a user