Add managed channel administration and moderation
.NET port / test (macos-latest) (push) Canceled after 0s
.NET port / test (ubuntu-24.04) (push) Canceled after 0s
.NET port / test (windows-latest) (push) Canceled after 0s
.NET port / cpp-conformance (push) Canceled after 0s

This commit is contained in:
2026-09-15 23:11:09 +02:00
parent 274b85025c
commit 653131b876
15 changed files with 737 additions and 20 deletions
+35 -4
View File
@@ -194,8 +194,38 @@ Authentication starts users in unprotected Lobby (id 1), subject to its capacity
Success returns permissions, then a cloned snapshot; peers receive joined/updated/left
events. Server-authoritative text replaces supplied sender ids/timestamps, limits
bodies to 4096 UTF-8 bytes, and acknowledges valid or rejected routing. Channel text
requires membership; private text echoes to sender and recipient. Protected channel
joins and all admin/moderation handlers are pending.
requires membership; private text echoes to sender and recipient. Protected joins enforce
the supplied password and capacity; `LeaveChannel` returns to Lobby. Passwords use the
native salted, keyed BLAKE2b-256 `salt_hex:hash_hex` format, verified in both directions.
Channel create/edit/delete persist before broadcasting events. Administrators can manage
all channels; `CanCreateTempChannel` permits creation of temporary channels only. Edit with
an empty password preserves the existing hash, matching native behavior; password removal
has no v2 request representation. Lobby cannot be deleted, protected or nested. Missing
parents, tree cycles and deletion of parents with children fail without mutation. Deletion
moves members to Lobby (even if full), clearing their streams. Edits stop existing streams
so clients must negotiate the updated audio configuration. Channel names/topics/passwords
are limited to 128/4096/1024 UTF-8 bytes. Audio requires Opus, 48 kHz, mono/stereo,
500512000 bps, integral 5/10/20/40/60 ms frames and valid application/loss/complexity.
Database v2 has no DRED column; CRUD rejects DRED rather than silently losing it on restart.
Session permissions gate kick/ban/move/mute and account operations. Only administrators
can grant permissions; account-administration permission cannot grant administrator status.
These two permission restrictions are stricter than the C++ oracle. Moves bypass channel
passwords but respect capacity and clear streams. Server mute/deafen immediately updates
encrypted routing. Kick/ban retire routing before closure and emit one LEFT with the reason.
Account bans persist by username; guest bans persist by address because nicknames are not
identities. Ban wire expiry is Unix milliseconds, converted to database seconds rounded up;
zero means permanent. This fixes the native handler's millisecond/second mismatch.
Existing sessions on the same address/account are not swept by a target-user ban.
Create/reset/delete/list accounts require administrator or `CanAdminAccounts`. New accounts
are non-admin. Bounded Argon2 work runs outside the server state lock; authority is checked
when accepting the operation, and cancellation is checked before password writes. Reset
and deletion affect future authentication; existing sessions retain their permissions.
Lists omit password hashes and return millisecond timestamps. Oversized lists fail instead
of truncating or exceeding the 64 KiB frame limit. Privileged responses echo request ids;
generic codes are 6 for permission denied and 3 for invalid/missing/duplicate input.
`VoiceServer.MediaEndPoint` exposes the bound UDP endpoint; UDP uses the same address
and port number as TCP, and `ServerHello.udp_port` advertises it. Successful authentication
@@ -236,8 +266,9 @@ the accept, reaper, control and media loops before disposing credentials/storage
and rejects unknown revisions. Opening an existing channel table does not reseed it.
Account creation/authentication uses parameterized SQL; two password workers bound
per-store Argon2 work. Failed authentication leaves `last_login` unchanged. Dispose
after its operations finish. Account provisioning currently uses this API or the
existing native administration path; there is no automatic bootstrap account.
after its operations finish. `ResetPasswordAsync`, `DeleteAccount` and `ListAccounts`
also expose administration to hosts. Initial administrator provisioning uses this API or
the native administration CLI; there is no automatic bootstrap account.
`PasswordHasher` uses strict UTF-8 without normalization and libsodium-compatible
Argon2id v19 PHC strings: 16-byte salt, 32-byte output, new-hash parameters