beeta/chat-service/src/services/RedisMessageStore.h
doomtube 33624d3b02
All checks were successful
Build and Push / build-all (push) Successful in 9m28s
fixes lol
2026-01-10 01:50:20 -05:00

131 lines
5.6 KiB
C++

#pragma once
#include <memory>
#include <string>
#include <vector>
#include <optional>
#include <sw/redis++/redis++.h>
#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<std::string> getActiveRealms();
// Message operations
bool addMessage(const models::ChatMessage& message);
std::vector<models::ChatMessage> getMessages(const std::string& realmId,
int limit = 100,
int64_t beforeTimestamp = 0);
// Get messages from ALL active realms (for global chat history)
std::vector<models::ChatMessage> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<sw::redis::Redis> 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