Add disposable/high-risk email signup scrutiny via check-mail.org

Classifies each signup's email domain (domain-only, GDPR-friendly) alongside
the existing IP scrutiny signal, with matching held-welcome and auto
email_domain_block behavior. A report against an account with a flagged
domain suspends immediately (no reporter-count threshold) and blocks the
domain, classified live from the report payload rather than any signup-time
record so it also covers pre-existing accounts. Ships CHECK_MAIL_DRY_RUN=true
by default, independent of ABUSE_DRY_RUN, so the new report-triggered suspend
path stays inert until watched.
This commit is contained in:
waffle2k
2026-07-03 09:08:30 -07:00
parent 6ad9a93f38
commit 656eec09c0
5 changed files with 452 additions and 40 deletions
+17 -1
View File
@@ -163,12 +163,19 @@ token created in the UI may omit `admin:write:accounts` → silence returns `403
the token with it included, or `IP_SCRUTINY_AUTO_IPBLOCK` writes will 403 (logged
as an error; nothing else in the bot is affected).
**Email-domain scrutiny's `register_email_domain_block` needs another scope,
`admin:write:email_domain_blocks`**, to `POST /api/v1/admin/email_domain_blocks`
— same deal: mint (or re-mint) the token with it included, or
`CHECK_MAIL_AUTO_DOMAIN_BLOCK` writes (both the signup-time path and the
report-triggered suspend override) will 403 (logged as an error; the suspend
itself still goes through since that only needs `admin:write:accounts`).
Mint a correctly-scoped token from the Rails console on mammut:
```bash
ssh mammut 'docker exec $(docker ps -f name=live-web-1 -q) bin/rails runner "
acct = Account.find_local(%q{bot})
scopes = %q{read:statuses write:statuses admin:read:reports admin:write:accounts admin:write:ip_blocks}
scopes = %q{read:statuses write:statuses admin:read:reports admin:write:accounts admin:write:ip_blocks admin:write:email_domain_blocks}
app = Doorkeeper::Application.create!(name: %q{Abuse handler vN}, scopes: scopes, redirect_uri: %q{urn:ietf:wg:oauth:2.0:oob})
tok = Doorkeeper::AccessToken.create!(application_id: app.id, resource_owner_id: acct.user.id, scopes: scopes)
puts tok.token
@@ -197,6 +204,15 @@ curl -s -o /dev/null -w "%{http_code}\n" -X POST \
https://yttrx.com/api/v1/admin/ip_blocks
```
And for `admin:write:email_domain_blocks` (`403` = missing scope; `422` =
authorized, just missing/invalid params):
```bash
curl -s -o /dev/null -w "%{http_code}\n" -X POST \
-H "Authorization: Bearer $ABUSE_BOT_TOKEN" \
https://yttrx.com/api/v1/admin/email_domain_blocks
```
## Mastodon side (mammut)
- The webhook (Administration → Webhooks) is already subscribed to