Skip to content

Moderation: queue, actions, appeals, audit log, retention - #23

Merged
AlxcBTW merged 4 commits into
mainfrom
feat/moderation
Oct 24, 2026
Merged

AlxcBTW merged 4 commits into
mainfrom
feat/moderation

Conversation

@AlxcBTW

@AlxcBTW AlxcBTW commented Oct 24, 2026

Copy link
Copy Markdown
Member

Moderation for a public cloud: report queue, actions with a stated reason, an audit log, appeals, protection for new accounts and retention. Needs network PR anyplaynet/network#14 first (the cloud builds against network main). Migration 0005_moderation.sql for SQLite and PostgreSQL; 0004 is left to the other change.

  • Moderators are accounts with a role, granted by the operator (anyplay-cloud admin grant-moderator). They use the /v1/moderation/... routes with their access token. The admin token stays for bootstrap and acts as operator; the old /admin/v1/... routes still work and now go through the same code.
  • Reports have a status, outcome and handler and keep a snapshot of what was reported. They survive deletion of either account (no foreign keys; a deleting reporter is forgotten). One open report per pair, 20 a day and 5 per 10 minutes per account.
  • Actions: warning, mute (no friend requests, later no messages), temporary or permanent ban. Each needs a rule and a reason the player reads. The player gets a statement of reasons on the connection (action event, banned with statement), at GET /v1/me/actions and in the banned error, which also carries an appeal token so a banned person can appeal.
  • Appeals: one per action, within 183 days. A different moderator decides when there is one; reversing lifts the action. The decision is logged and sent to the player.
  • Audit log: append-only (the database refuses an UPDATE) with actor, target, action, reason, rule and reference.
  • Ban e-mail hashes are HMAC-SHA-256 under ban_secret or data_dir/ban.key. Older plain hashes are replaced at start when the account exists, or when the address shows up; they match until then.
  • Retention by the existing sweep, once an hour per node: bans, actions, appeals and decided reports 6 months after their end or decision, open reports 1 year, the log 3 years. A ban for good stays until lifted. Settings in docs/configuration.md.
  • New accounts (24 h by default, new_account_hours, 0 = off) cannot send friend requests: restricted with restriction: new_account and until. The rule is moderation::may_write_to_strangers, ready for messages.
  • Docs: docs/moderation.md; docs/compliance/ updated.

DSA tasks closed: T3, T4 (app and API; the mail is open), T5, T6 (moderation; the log of authority orders is open), T10 (reports, bans, actions, appeals, log; devices and inactive accounts, G3, are open). Gaps G1, G2, G8 closed. T1, T2, T7, T8, T9 stay open.

Tests: crates/cloud/tests/moderation.rs (28 tests, SQLite and PostgreSQL, plus a two-node ban test and a migration test with existing data). Existing tests changed where behaviour changed on purpose: a ban needs a reason, a second open report about one account is refused, and test clouds turn the new-account rule off.

The 24 h rule is on by default, so the launcher must show the restricted error to a new player who tries to add a friend.

…etention

Moderators are accounts with a role (the admin token stays for bootstrap).
Warnings, mutes and bans carry a rule and a reason the player reads, as a
statement of reasons on the connection, at GET /v1/me/actions and in the
banned error. One appeal per action, decided by a different moderator when
there is one. Every step goes to an append-only audit log. Reports keep a
snapshot and survive account deletion. Bans, actions, reports and the log are
swept after configurable periods (default 6 months). Ban e-mail hashes are
keyed. Accounts younger than 24 h cannot send friend requests.
…sts on day one

new_account_hours now covers messages (replacing stranger_min_age_hours) and a
cap on friend requests (new_account_friend_requests_per_day). A muted account
sends no messages either. A report can name a message and keep its text.
@AlxcBTW
AlxcBTW merged commit 8fe460a into main Oct 24, 2026
10 of 15 checks passed
@AlxcBTW
AlxcBTW deleted the feat/moderation branch October 24, 2026 15:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant