#pragma once #include #include #include #include #include #include "../models/ChatMessage.h" namespace services { class RedisMessageStore { public: static RedisMessageStore& getInstance(); void initialize(const std::string& host, int port, int db = 1, const std::string& password = ""); bool isInitialized() const { return redis_ != nullptr; } // Track active realms for cleanup void trackActiveRealm(const std::string& realmId); std::vector getActiveRealms(); // Message operations bool addMessage(const models::ChatMessage& message); std::vector getMessages(const std::string& realmId, int limit = 100, int64_t beforeTimestamp = 0); // Get messages from ALL active realms (for global chat history) std::vector getGlobalMessages(int limit = 100); bool deleteMessage(const std::string& realmId, const std::string& messageId); void cleanupOldMessages(const std::string& realmId, int retentionHours); void cleanupExpiredSelfDestruct(const std::string& realmId); // Settings operations void setGlobalSettings(const models::GlobalChatSettings& settings); models::GlobalChatSettings getGlobalSettings(); void setRealmSettings(const std::string& realmId, const models::ChatSettings& settings); models::ChatSettings getRealmSettings(const std::string& realmId); // Moderation operations (per-realm) bool addBan(const std::string& realmId, const std::string& userId); bool removeBan(const std::string& realmId, const std::string& userId); bool isBanned(const std::string& realmId, const std::string& userId); std::vector getBannedUsers(const std::string& realmId); // durationSeconds: 0 = permanent, >0 = temporary with TTL bool addMute(const std::string& realmId, const std::string& userId, int durationSeconds = 0); bool removeMute(const std::string& realmId, const std::string& userId); bool isMuted(const std::string& realmId, const std::string& userId); // Fingerprint bans - site-wide "uberban" (for guests and registered users) bool addFingerprintBan(const std::string& fingerprint); bool removeFingerprintBan(const std::string& fingerprint); bool isFingerprintBanned(const std::string& fingerprint); std::vector getBannedFingerprints(); // Realm-specific bans (supports both user IDs and fingerprints) // identifier format: "user:{userId}" or "fp:{fingerprint}" bool addRealmBan(const std::string& realmId, const std::string& identifier); bool removeRealmBan(const std::string& realmId, const std::string& identifier); bool isRealmBanned(const std::string& realmId, const std::string& userId, const std::string& fingerprint = ""); std::vector getRealmBannedIdentifiers(const std::string& realmId); // Kicks (temporary disconnect + rejoin block with TTL) bool addKick(const std::string& realmId, const std::string& userId, int durationSeconds = 60); bool isKicked(const std::string& realmId, const std::string& userId); // Slow mode bool canSendMessage(const std::string& realmId, const std::string& userId, int slowModeSeconds); void recordMessageSent(const std::string& realmId, const std::string& userId); // Guest ID generation std::string generateGuestId(const std::string& pattern); // SECURITY FIX #31: Server-side guest name persistence (by fingerprint) // Stores guest's chosen name server-side so it persists across sessions // More secure than localStorage which is accessible to same-origin XSS bool setGuestName(const std::string& fingerprint, const std::string& name); std::optional getGuestName(const std::string& fingerprint); bool clearGuestName(const std::string& fingerprint); // Active users void recordUserActivity(const std::string& realmId, const std::string& userId); int getActiveUserCount(const std::string& realmId); // Pending uberban check (set by backend or chat-service, checked on connect) bool setPendingUberban(const std::string& userId); bool hasPendingUberban(const std::string& userId); bool clearPendingUberban(const std::string& userId); private: RedisMessageStore() = default; ~RedisMessageStore() = default; RedisMessageStore(const RedisMessageStore&) = delete; RedisMessageStore& operator=(const RedisMessageStore&) = delete; std::unique_ptr redis_; std::string getMessagesKey(const std::string& realmId) const { return "chat:messages:" + realmId; } std::string getBanKey(const std::string& realmId) const { return "chat:banned:" + realmId; } std::string getMuteKey(const std::string& realmId, const std::string& userId) const { return "chat:muted:" + realmId + ":" + userId; } std::string getSlowModeKey(const std::string& realmId, const std::string& userId) const { return "chat:slowmode:" + realmId + ":" + userId; } std::string getActiveUsersKey(const std::string& realmId) const { return "chat:active:" + realmId; } std::string getRealmBanKey(const std::string& realmId) const { return "chat:realm_banned:" + realmId; } std::string getKickKey(const std::string& realmId, const std::string& userId) const { return "chat:kicked:" + realmId + ":" + userId; } std::string getMessageIndexKey(const std::string& realmId) const { return "chat:msg_index:" + realmId; } }; } // namespace services