M5: moderation, permissions, channel CRUD, in-app account management
- Server-side moderation & permissions (kick/ban/move/server-mute, channel CRUD). - Database schema v2: channels, bans; BLAKE2b channel passwords, Argon2id accounts. - C ABI additions and client-side handling (vc_kick_user, vc_ban_user, vc_set_permission, vc_set_server_mute, vc_move_user, vc_create/edit/delete_channel, vc_create/reset/delete/list_account). - vccli flags for all M5 operations plus --username/--password auth. - Four new tests covering permissions, kick/ban/move/mute, admin accounts, channel CRUD. - Docs: protocol.md envelope updates, security.md channel-password hashing, PROGRESS.md.
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#define ASIO_STANDALONE 1
|
||||
#include <asio.hpp>
|
||||
|
||||
#include "db.h"
|
||||
#include "proto/voicecat.pb.h"
|
||||
|
||||
namespace voicecat::server {
|
||||
@@ -48,10 +49,10 @@ struct UdpEndpointHash {
|
||||
|
||||
class SessionRegistry {
|
||||
public:
|
||||
SessionRegistry() = default;
|
||||
explicit SessionRegistry(std::shared_ptr<Database> db);
|
||||
|
||||
// Create the default "Lobby" channel (id=1, permanent). Call once at startup.
|
||||
void init_default_channels();
|
||||
// Load channels from the database, seeding defaults on first run.
|
||||
void load_channels();
|
||||
|
||||
// Register a session (before auth). Returns the assigned session_id.
|
||||
uint64_t register_session(std::weak_ptr<ConnSession> session);
|
||||
@@ -71,6 +72,8 @@ class SessionRegistry {
|
||||
// Snapshot for ServerStateSnapshot message.
|
||||
std::vector<voicecat::v1::Channel> channel_snapshot() const;
|
||||
std::vector<voicecat::v1::User> user_snapshot() const;
|
||||
std::optional<voicecat::v1::User> user_snapshot_user(uint32_t user_id) const;
|
||||
std::optional<std::string> user_nickname(uint32_t user_id) const;
|
||||
|
||||
// Resolve target sessions for a text message relay.
|
||||
std::vector<std::shared_ptr<ConnSession>> resolve_text_targets(
|
||||
@@ -79,7 +82,56 @@ class SessionRegistry {
|
||||
// Broadcast an envelope to all sessions except the excluded one.
|
||||
void broadcast(const voicecat::v1::Envelope& env, uint64_t exclude_session_id = 0) const;
|
||||
|
||||
// ── M2: UDP / media ──────────────────────────────────────────────────────
|
||||
private:
|
||||
void broadcast_unlocked(const voicecat::v1::Envelope& env,
|
||||
uint64_t exclude_session_id = 0) const;
|
||||
|
||||
public:
|
||||
// ── Permissions ────────────────────────────────────────────────────────────
|
||||
|
||||
void set_session_permissions(uint64_t session_id,
|
||||
const voicecat::v1::Permissions& perms);
|
||||
std::optional<voicecat::v1::Permissions> get_session_permissions(
|
||||
uint64_t session_id) const;
|
||||
|
||||
// ── Moderation ─────────────────────────────────────────────────────────────
|
||||
|
||||
// Find a live session by its user_id. Returns nullptr if offline.
|
||||
std::shared_ptr<ConnSession> find_session_by_user_id(uint32_t user_id) const;
|
||||
|
||||
// Forcibly disconnect a user with a reason. Broadcasts UserEvent::LEFT.
|
||||
// Returns true if the user was online.
|
||||
bool kick_user(uint32_t user_id, const std::string& reason);
|
||||
|
||||
// Kick a user and insert a persistent ban. Returns true if the user was online.
|
||||
bool ban_user(uint32_t user_id, const std::string& reason, int64_t expires_at);
|
||||
|
||||
// Set server-mute/deafen flags on a user and broadcast the update.
|
||||
bool set_server_mute(uint32_t user_id, bool muted, bool deafened);
|
||||
|
||||
// Move a user to a channel (permission-checked by caller).
|
||||
bool move_user(uint32_t user_id, uint32_t channel_id);
|
||||
|
||||
// ── Channel CRUD ───────────────────────────────────────────────────────────
|
||||
|
||||
// Create a channel. Returns the new channel id, or 0 on error.
|
||||
uint32_t create_channel(const voicecat::v1::Channel& ch, const std::string& password,
|
||||
std::string& error);
|
||||
|
||||
// Update a channel. Returns false on error.
|
||||
bool update_channel(const voicecat::v1::Channel& ch, const std::string& password,
|
||||
std::string& error);
|
||||
|
||||
// Delete a channel. Remaining users are moved to Lobby (id=1). Returns false on error.
|
||||
bool delete_channel(uint32_t channel_id, std::string& error);
|
||||
|
||||
// Return a channel proto by id, or nullopt.
|
||||
std::optional<voicecat::v1::Channel> get_channel(uint32_t channel_id) const;
|
||||
|
||||
// Check a channel password.
|
||||
bool check_channel_password(uint32_t channel_id, const std::string& password) const;
|
||||
|
||||
// ── M2: UDP / media ────────────────────────────────────────────────────────
|
||||
|
||||
// Register a session's UDP token (called at auth success).
|
||||
void register_udp_token(const std::array<uint8_t, 16>& token, uint64_t session_id);
|
||||
@@ -99,7 +151,7 @@ class SessionRegistry {
|
||||
// Add/replace a stream entry on a user (called when StreamAnnounce succeeds).
|
||||
// Returns the updated User proto for broadcasting, or nullopt if user not found.
|
||||
std::optional<voicecat::v1::User> set_user_stream(uint32_t user_id,
|
||||
const voicecat::v1::StreamInfo& info);
|
||||
const voicecat::v1::StreamInfo& info);
|
||||
|
||||
// Remove a stream entry from a user (called on StreamStop). Returns the updated
|
||||
// User proto for broadcasting, or nullopt if user not found.
|
||||
@@ -119,15 +171,20 @@ class SessionRegistry {
|
||||
std::optional<voicecat::v1::AudioConfig> channel_audio_config(uint32_t channel_id) const;
|
||||
|
||||
private:
|
||||
void seed_default_channels();
|
||||
|
||||
mutable std::shared_mutex mu_;
|
||||
|
||||
std::shared_ptr<Database> db_;
|
||||
|
||||
uint64_t next_session_id_{1};
|
||||
uint32_t next_user_id_{1};
|
||||
uint32_t next_channel_id_{2}; // 1 is reserved for Lobby
|
||||
uint32_t next_channel_id_{3}; // 1 and 2 are reserved for Lobby, Music Room
|
||||
|
||||
std::unordered_map<uint64_t, std::weak_ptr<ConnSession>> sessions_;
|
||||
std::unordered_map<uint32_t, UserEntry> users_;
|
||||
std::unordered_map<uint32_t, ChannelEntry> channels_;
|
||||
std::unordered_map<uint64_t, voicecat::v1::Permissions> session_permissions_;
|
||||
|
||||
// M2: token → session_id (populated at auth, cleared on disconnect)
|
||||
struct TokenHash {
|
||||
@@ -150,5 +207,5 @@ class SessionRegistry {
|
||||
|
||||
} // namespace voicecat::server
|
||||
|
||||
#endif // VOICECAT_HAS_NET
|
||||
#endif // VOICECAT_SERVER_SESSION_REGISTRY_H
|
||||
#endif // VOICECAT_SERVER_SESSION_REGISTRY_H
|
||||
|
||||
Reference in New Issue
Block a user