r9k-bot#
An encrypted Matrix Robot9000-style moderation bot. Each room gets a permanent set of previously posted text. While R9K mode is enabled, a message whose content is already in that set is redacted.
Behavior#
- Text, notices, and emotes share one room-local uniqueness set.
- Repeats by the original sender are duplicates too.
- Unicode is normalized to NFC, so canonically equivalent text collides.
- Emoji in message bodies participates in duplicate detection.
- Reactions, media, state events, and bot commands are ignored.
- Reply fallback quotations are removed before comparison.
- Edits claim their new content without releasing the original content.
- Disabling enforcement does not stop collection.
The bot stores keyed BLAKE3 digests, not message plaintext. A one-time forward history pass seeds each room with all decryptable text visible to the bot. Historical duplicates are not retroactively redacted.
Matrix setup#
Use a dedicated Matrix account with password login enabled:
- Start the bot and invite its account to a room.
- Give the account enough room power to redact other users' events.
- As a room moderator, send
!r9k on.
The bot accepts invitations from users on its own homeserver by default.
R9K_TRUSTED_INVITERS can replace that behavior with an explicit
comma-separated user-ID allowlist.
Room commands:
!r9k on
!r9k off
!r9k status
Commands are acknowledged with reactions, which do not enter the uniqueness set. Only users with power level 50 or higher can control the mode.
Configuration#
Required environment variables:
| Variable | Purpose |
|---|---|
MATRIX_USERNAME |
Full bot user ID, such as @r9k:example.org |
MATRIX_PASSWORD |
Bot account password |
R9K_STORE_PASSPHRASE |
Encrypts the Matrix SDK's persistent store |
R9K_HASH_KEY |
Exactly 32 random bytes encoded as 64 hexadecimal characters |
Optional variables:
| Variable | Default | Purpose |
|---|---|---|
MATRIX_HOMESERVER |
http://tuwunel:6167 |
Client API base URL |
MATRIX_DEVICE_ID |
R9KBOT |
Stable Matrix device ID |
MATRIX_RECOVERY_KEY |
unset | Recovers secret storage and room-key backups |
R9K_DATA_DIR |
/data |
Persistent SDK and ledger directory |
R9K_TRUSTED_INVITERS |
local users | Comma-separated invitation allowlist |
RUST_LOG |
info |
Standard tracing filter |
Generate the independent storage secrets with:
openssl rand -hex 32
openssl rand -hex 32
Do not reuse either value as the Matrix password or recovery key.
Run locally#
The project requires Rust 1.93 or newer:
cargo test
cargo run
The data directory must be persistent. SQLite and the Matrix SDK crypto store should use a local filesystem rather than NFS.
Container#
docker build -t git.dragonfruit.dev/ryphon/r9k-bot:latest .
docker run --rm \
--env-file .env \
--volume r9k-data:/data \
git.dragonfruit.dev/ryphon/r9k-bot:latest
The image runs as UID/GID 10001 and requires write access to /data.