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:
@@ -9,7 +9,9 @@ A small FastAPI webhook server that receives Mastodon **admin webhooks** for
|
||||
- **`report.created`** — evaluates the reported account and, when enough
|
||||
**distinct** reporters have open reports against a *young* or *dormant*
|
||||
account, auto-**silences** it (reversible) and DMs a moderator for review
|
||||
(the abuse bot).
|
||||
(the abuse bot). Special case: a report against an account whose email
|
||||
domain is flagged high-risk (see below) auto-**suspends** it immediately
|
||||
(no reporter-count threshold) and blocks the domain.
|
||||
|
||||
- **Runs on:** `admin.yttrx.com` (Docker container, nginx-proxied at
|
||||
`https://hooks.yttrx.com`)
|
||||
@@ -85,6 +87,43 @@ regexes for a while. Registering ip_blocks requires the `ABUSE_BOT_TOKEN` to
|
||||
carry the `admin:write:ip_blocks` scope in addition to its existing scopes
|
||||
(see `CLAUDE.md`).
|
||||
|
||||
## Disposable/high-risk email signup scrutiny
|
||||
|
||||
Every `account.created` delivery already carries the signup email for free
|
||||
(`Admin::Account.email`). On each new local signup, the bot:
|
||||
|
||||
1. **Classifies the domain only** (never the full email address — GDPR-
|
||||
friendly) via [check-mail.org](https://check-mail.org/), cached in sqlite.
|
||||
Flagged if the API marks it `is_disposable` or its `risk` score (0-100) is
|
||||
at or above `CHECK_MAIL_RISK_THRESHOLD` (default 80).
|
||||
2. If flagged, same scrutiny shape as the IP signal:
|
||||
- **Moderator DM** with the domain and risk score.
|
||||
- **Held welcome** (`CHECK_MAIL_HOLD_WELCOME`) — same semantics as
|
||||
`IP_SCRUTINY_HOLD_WELCOME`.
|
||||
- **Auto-registered email domain block** (`CHECK_MAIL_AUTO_DOMAIN_BLOCK`)
|
||||
— the domain is added to Mastodon's native `Admin::EmailDomainBlock`,
|
||||
blocking future signups from it.
|
||||
|
||||
A **report** against an account whose email domain is flagged is a special,
|
||||
stronger case (not merely a lowered threshold like the IP signal): it
|
||||
auto-**suspends** the account on the very first report — no distinct-reporter
|
||||
threshold — and (re-)registers the email domain block. This is classified
|
||||
**live** from the report payload's `target_account.email` (a full
|
||||
`Admin::Account`, always present), not from any record made at signup time —
|
||||
so it also catches accounts that signed up before this feature existed or
|
||||
while `CHECK_MAIL_ENABLED`/`CHECK_MAIL_API_KEY` was off. Gated by
|
||||
`ABUSE_DRY_RUN` **or** `CHECK_MAIL_DRY_RUN` (either one holds it) —
|
||||
deliberately independent of `ABUSE_DRY_RUN` alone, so this brand-new action
|
||||
ships inert by `CHECK_MAIL_DRY_RUN`'s own default even once the general
|
||||
abuse-bot is live.
|
||||
|
||||
`CHECK_MAIL_DRY_RUN=true` (the shipped default) classifies and DMs a
|
||||
moderator without holding any welcome or writing any email_domain_block —
|
||||
keep it on until you've watched the false-positive rate for a while.
|
||||
Registering email_domain_blocks requires the `ABUSE_BOT_TOKEN` to carry the
|
||||
`admin:write:email_domain_blocks` scope in addition to its existing scopes
|
||||
(see `CLAUDE.md`).
|
||||
|
||||
## Layout
|
||||
|
||||
| Path | Purpose |
|
||||
@@ -127,6 +166,12 @@ Copy `.env.example` to `.env` and fill in:
|
||||
| `IP_SCRUTINY_AUTO_IPBLOCK` | Auto-register a flagged IP into Mastodon's `Admin::IpBlock` |
|
||||
| `IP_SCRUTINY_IPBLOCK_SEVERITY` | `sign_up_requires_approval` (default), `sign_up_block`, or `no_access` |
|
||||
| `IP_SCRUTINY_HOSTING_RE` / `IP_SCRUTINY_MOBILE_RE` | Keyword regexes matched against the RDAP org/ASN description |
|
||||
| `CHECK_MAIL_ENABLED` | Master switch for disposable/high-risk email signup scrutiny |
|
||||
| `CHECK_MAIL_API_KEY` | check-mail.org API key; blank disables the check |
|
||||
| `CHECK_MAIL_DRY_RUN` | `true` — classify + DM only, no held welcome, no email_domain_block write, no report-triggered suspend |
|
||||
| `CHECK_MAIL_RISK_THRESHOLD` | Flag if `is_disposable` or `risk` ≥ this (default 80) |
|
||||
| `CHECK_MAIL_HOLD_WELCOME` | `true` — hold the welcome for a flagged signup until `account.approved` |
|
||||
| `CHECK_MAIL_AUTO_DOMAIN_BLOCK` | Auto-register a flagged domain into Mastodon's `Admin::EmailDomainBlock`; also gates the report-triggered override |
|
||||
|
||||
## Local test
|
||||
|
||||
|
||||
Reference in New Issue
Block a user