added community voting and fixed bugs
This commit is contained in:
@@ -23,14 +23,24 @@ In **stealth mode**, offending users **do not realize** they have been moved. Th
|
||||
- **Slash commands only** (modern Discord UX)
|
||||
- `/xcom-setup` – one-time server initialization
|
||||
- `/xcom @user [reason]` – excommunicate a user (manual or via auto-detection)
|
||||
- `/xcom-release @user` – restore full access
|
||||
- `/xcom-release @user` – restore full access (the `[XCOM]` mark remains)
|
||||
- `/xcom-unmark @user` – remove the permanent `[XCOM]` nickname mark
|
||||
- `/xcom-vow <text>` – let an isolated user post a vow of redemption to staff
|
||||
- `/xcom-witness @staff @target` – add a staff member to the shared lounge
|
||||
- `/xcom-absolve @user` – release a user early once they earn enough points
|
||||
- `/xcom-vote @user up|down` – community vote to excommunicate (or defend) a user
|
||||
- `/xcom-votes @user` – staff view of a user's current vote tally
|
||||
- `/xcom-keywords` – admin panel to curate auto-score keywords/phrases
|
||||
- `/xcom-list` – view all currently XCOM users with reasons and timestamps
|
||||
- **Automatic flood protection** – detects ≥5 messages within 8 seconds and auto-excommunicates
|
||||
- **Community voting** – members up/down-vote a user; reaching a net **+10** (with quorum) auto-XCOMs them; tallies reset weekly
|
||||
- **Keyword auto-scoring** – admin-curated phrases (e.g. cracked-software/warez trading) add weighted points to a sender's score and can auto-XCOM critical abuse even when no admin is online
|
||||
- **Absolution Points** – users earn points for good behavior in the xcom-lounge; staff can absolve early
|
||||
- **Shared hidden channel** `xcom-lounge` with 5-second slowmode
|
||||
- **Persistent state** – JSON storage survives bot restarts
|
||||
- **Persistent state** – atomic, corruption-safe JSON storage survives bot restarts
|
||||
- **Mention-safe forwarding** – relocated messages never ping (`@everyone`/`@here`/roles are neutralized)
|
||||
- **Rich embeds + DM notifications** for offenders and staff logs
|
||||
- **Graceful permission handling** and role hierarchy checks
|
||||
- **Graceful permission handling** and role-hierarchy safety checks
|
||||
- Zero bans/kicks – users stay in the server
|
||||
|
||||
## Philosophy & Use Cases
|
||||
@@ -70,7 +80,7 @@ The bot runs as a non-root user with healthchecks and log rotation.
|
||||
|
||||
To view logs:
|
||||
```powershell
|
||||
docker compose logs -f excommunicado-bot
|
||||
docker compose logs -f excommunicado
|
||||
```
|
||||
|
||||
To stop:
|
||||
@@ -149,10 +159,13 @@ The user is stealthily XCOM'd. Their messages are forwarded to the shared room.
|
||||
- `reason` (optional) – default "Flooding the channel"
|
||||
- **Effects**:
|
||||
- Assigns `Excommunicado` role
|
||||
- Applies the permanent `[XCOM]` nickname mark (best-effort; needs Manage Nicknames)
|
||||
- Records in `data/xcom_config.json`
|
||||
- Posts welcome embed in `xcom-lounge`
|
||||
- DMs the user
|
||||
- Logs to staff channel (if set)
|
||||
- **Role-hierarchy safety**: refuses to XCOM the server owner, a member whose top role is equal to or higher than the invoker's, or a member ranked above the bot — each returns a clear ephemeral error instead of failing silently.
|
||||
- **Cooldown**: max 5 uses per 15 seconds per moderator (per guild) to prevent accidental mass-spam.
|
||||
- **Edge cases**: Already under XCOM, bot, self-target, missing hierarchy → clear ephemeral error
|
||||
|
||||
### `/xcom-release <user>`
|
||||
@@ -173,12 +186,35 @@ The user is stealthily XCOM'd. Their messages are forwarded to the shared room.
|
||||
|
||||
### `/xcom-absolve @user`
|
||||
- **Permission**: Manage Roles
|
||||
- **Cooldown**: max 5 uses per 15 seconds per moderator (per guild)
|
||||
- **Effects**: If the user has ≥10 absolution points (earned by positive participation in the lounge), removes the role early. The mark remains.
|
||||
|
||||
### `/xcom-list`
|
||||
- **Permission**: Manage Roles
|
||||
- **Output**: Embed listing up to 15 users with reason + date (truncated if more)
|
||||
|
||||
### `/xcom-vote <user> <up|down>`
|
||||
- **Permission**: None (any member) — light cooldown of 10 uses / 60s per member
|
||||
- **Effects**: Casts a weighted community vote on the target's running score.
|
||||
- `up` = excommunicate, `down` = defend.
|
||||
- Admins/moderators count **±2**; regular members **±1**.
|
||||
- **One vote per voter per target per 24h** (re-voting replaces your previous vote).
|
||||
- When the **net score ≥ 10** *and* at least **5 distinct voters** have participated, the user is automatically XCOM'd and the tally is cleared.
|
||||
- Tallies **reset weekly**.
|
||||
- **Guardrails**: cannot vote on yourself, bots, the server owner, staff/moderators, or anyone ranked above the bot. Confirmations are ephemeral (preserves stealth, avoids public pile-on).
|
||||
|
||||
### `/xcom-votes <user>`
|
||||
- **Permission**: Manage Roles
|
||||
- **Output**: Ephemeral embed showing the target's current score, distinct-voter count, threshold, and quorum, with a breakdown of points from human votes vs. keyword flags.
|
||||
|
||||
### `/xcom-keywords`
|
||||
- **Permission**: Manage Server (admin)
|
||||
- **Effects**: Opens an **interactive ephemeral panel** to curate the auto-score keyword/phrase list:
|
||||
- **Add / Edit** — a modal to enter a phrase and its score weight (1–100). Re-adding an existing phrase updates its weight.
|
||||
- **Remove** — a modal to delete a phrase.
|
||||
- **Refresh** — re-render the current list.
|
||||
- **How it works**: any non-staff message containing a listed phrase (case-insensitive substring match) adds that phrase's weight to the sender's community score. When the score reaches the XCOM threshold, the user is auto-isolated — **no quorum required**, since this path is meant to capture abuse when no admin is online. Staff, the server owner, and members ranked above the bot are immune.
|
||||
|
||||
All commands are ephemeral where possible to keep chat clean.
|
||||
|
||||
## Configuration
|
||||
@@ -192,13 +228,40 @@ All commands are ephemeral where possible to keep chat clean.
|
||||
|
||||
### Tunable Constants (in `bot.py`)
|
||||
```python
|
||||
FLOOD_THRESHOLD = 5
|
||||
FLOOD_WINDOW_SECONDS = 5
|
||||
FLOOD_THRESHOLD = 5 # messages
|
||||
FLOOD_WINDOW_SECONDS = 8 # within this many seconds
|
||||
```
|
||||
Change and restart to adjust sensitivity.
|
||||
A user who sends `FLOOD_THRESHOLD` messages within `FLOOD_WINDOW_SECONDS` is auto-excommunicated. Change and restart to adjust sensitivity.
|
||||
|
||||
### Community Vote Constants (in `cogs/moderation.py`)
|
||||
```python
|
||||
VOTE_XCOM_THRESHOLD = 10 # net score required to auto-XCOM a user
|
||||
VOTE_ADMIN_WEIGHT = 2 # admins / moderators count double
|
||||
VOTE_USER_WEIGHT = 1 # regular members
|
||||
VOTE_COOLDOWN_HOURS = 24 # one vote per voter per target per 24h
|
||||
VOTE_RESET_DAYS = 7 # tallies reset weekly
|
||||
VOTE_MIN_UNIQUE_VOTERS = 5 # quorum: distinct voters required before XCOM fires
|
||||
```
|
||||
|
||||
**Recommended guardrails (already enforced):**
|
||||
- **Quorum** (`VOTE_MIN_UNIQUE_VOTERS`) prevents a handful of admins (±2 each) or a tiny brigade from instantly triggering an XCOM — a genuine community consensus is required.
|
||||
- **Staff immunity** — moderators/admins and the server owner can't be vote-targeted.
|
||||
- **Hierarchy check** — the bot refuses votes it couldn't enforce.
|
||||
- **Ephemeral results** keep the target unaware (stealth) and discourage public harassment campaigns.
|
||||
- **Auto-clear on trigger** stops a target from being re-XCOM'd on the very next vote.
|
||||
|
||||
Tune `VOTE_XCOM_THRESHOLD` and `VOTE_MIN_UNIQUE_VOTERS` together to match your server size — larger servers should raise both.
|
||||
|
||||
### Keyword Auto-Scoring
|
||||
Admins curate the phrase list live via `/xcom-keywords` (no restart needed). Each phrase has an integer **weight**; a matching message adds that weight to the sender's community score (the same score `/xcom-vote` feeds). Notes:
|
||||
- Matching is **case-insensitive substring**, so curate carefully — this is a cybersecurity channel where some terms are legitimate in context. Prefer specific phrases (`"selling cracked"`) over broad single words (`"crack"`).
|
||||
- Multiple distinct phrases matched in one message stack their weights.
|
||||
- A high weight (e.g. `10`) makes a single message enough to XCOM instantly; low weights (`1`–`3`) require repeated abuse.
|
||||
- Keyword points are part of the weekly-resetting score and are shown separately in `/xcom-votes`.
|
||||
- The keyword path **bypasses the human voter quorum** by design, but still respects staff/owner immunity and bot role hierarchy.
|
||||
|
||||
### Data File
|
||||
`data/xcom_config.json` (auto-created):
|
||||
`data/xcom_config.json` (auto-created). Writes are **atomic** (written to a temp file, then `os.replace`d) and the file is **cached in memory**, so the bot does not re-read disk on every message:
|
||||
```json
|
||||
{
|
||||
"123456789": {
|
||||
@@ -207,12 +270,37 @@ Change and restart to adjust sensitivity.
|
||||
"isolated_users": {
|
||||
"333333333": {
|
||||
"reason": "Auto-detected flooding...",
|
||||
"timestamp": "2026-06-08T12:34:56.789012+00:00"
|
||||
"timestamp": "2026-06-08T12:34:56.789012+00:00",
|
||||
"absolution_points": 0,
|
||||
"marked": true
|
||||
}
|
||||
},
|
||||
"votes": {
|
||||
"444444444": {
|
||||
"week_start": "2026-06-08T00:00:00+00:00",
|
||||
"voters": {
|
||||
"555555555": { "direction": 1, "weight": 2, "timestamp": "2026-06-08T12:00:00+00:00" }
|
||||
},
|
||||
"keyword_points": 3
|
||||
}
|
||||
},
|
||||
"keywords": {
|
||||
"selling cracked software": {
|
||||
"weight": 5,
|
||||
"added_by": 555555555,
|
||||
"added_at": "2026-06-08T10:00:00+00:00",
|
||||
"display": "selling cracked software"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
- `absolution_points` – earned by positive participation in the lounge; `/xcom-absolve` needs ≥10.
|
||||
- `marked` – whether the permanent `[XCOM]` nickname mark is applied.
|
||||
- `votes` – per-target community-vote tallies; each voter's `direction` (±1) × `weight` is summed, plus `keyword_points` from auto-scoring, into the net score; the whole record is discarded once `week_start` is older than a week.
|
||||
- `keywords` – admin-curated auto-score phrases (managed via `/xcom-keywords`).
|
||||
|
||||
If the file is ever corrupted, the bot backs it up to `xcom_config.json.corrupt` and starts fresh instead of crashing.
|
||||
|
||||
## How Isolation Works (Technical) — Stealth Mode
|
||||
1. On `/xcom-setup`, the bot creates:
|
||||
@@ -223,7 +311,7 @@ Change and restart to adjust sensitivity.
|
||||
- **No view permissions are removed** from public channels — the user continues to see the full server and does not realize anything changed.
|
||||
3. On every message the isolated user sends outside `xcom-lounge`:
|
||||
- The message is **instantly deleted** (public never sees the spam)
|
||||
- The content is forwarded to the shared `xcom-lounge` room
|
||||
- The content is forwarded to the shared `xcom-lounge` room **with all mentions neutralized** (no `@everyone`/`@here`/role pings) and **truncated** to Discord's 2000-character limit
|
||||
- Staff members who also hold the `Excommunicado` role can see and reply in the same room
|
||||
4. The offender experiences normal server browsing + "their messages just go to the moderated lounge where staff are"
|
||||
5. `/xcom-release` removes the role — full normal behavior is restored instantly
|
||||
@@ -262,15 +350,24 @@ Key flows:
|
||||
- **Commands not appearing** → Restart bot after `GUILD_ID` change; wait 1h for global sync
|
||||
- **Isolated user messages still appear publicly** → The stealth suppression logic in on_message is not triggering (check that the user has the Excommunicado role or is in the isolated_users JSON)
|
||||
- **Auto-detection too sensitive** → Increase `FLOOD_WINDOW_SECONDS` or threshold
|
||||
- **JSON corrupted** → Delete `data/xcom_config.json` (bot will recreate)
|
||||
- **JSON corrupted** → The bot auto-recovers: the bad file is moved to `data/xcom_config.json.corrupt` and a fresh one is created. Restore from the backup if you need the old data.
|
||||
- **`[XCOM]` mark not applied** → Bot is missing `Manage Nicknames`, or the target outranks the bot (role assignment still succeeds; the mark is best-effort)
|
||||
|
||||
## Security Best Practices
|
||||
- Never commit `.env` or the token
|
||||
- Never commit `.env` or the token (the provided `.gitignore` already excludes `.env`, `.env.*`, and `data/`)
|
||||
- Use a dedicated bot account (not your personal account)
|
||||
- Give the bot the minimum permissions required
|
||||
- Regularly audit `data/xcom_config.json` for old entries
|
||||
- Give trusted staff the `Excommunicado` role so they can share the moderated room with XCOM users and respond naturally
|
||||
|
||||
### Built-in hardening
|
||||
- **No mention abuse**: forwarded messages are sent with mentions disabled, so an isolated user cannot make the bot ping `@everyone`, `@here`, or any role.
|
||||
- **Length-safe forwarding**: relocated messages are truncated to Discord's 2000-character limit; image/sticker-only messages forward a placeholder instead of failing.
|
||||
- **Atomic persistence**: config writes can't half-complete and corrupt state; a corrupt file is quarantined automatically.
|
||||
- **Role-hierarchy enforcement**: `/xcom` will not target the owner, equal/higher-ranked members, or members above the bot.
|
||||
- **Command cooldowns**: `/xcom` and `/xcom-absolve` are rate-limited (5 per 15s per moderator) and surface a friendly "slow down" message instead of erroring.
|
||||
- **Runs as non-root** in Docker with healthchecks and log rotation.
|
||||
|
||||
## Extending the Bot
|
||||
Example: add a `/xcom-stats` command counting total excommunications.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user