#pragma once #include #include #include #include #include #include struct UserInfo { int64_t id = 0; std::string username; bool isAdmin = false; bool isModerator = false; // Site-wide moderator role bool isStreamer = false; bool isRestreamer = false; bool isBot = false; bool isTexter = false; bool isPgpOnly = false; bool isDisabled = false; // SECURITY FIX #26: Track disabled status std::string bio; std::string avatarUrl; std::string bannerUrl; int bannerPosition = 50; // Y position percentage (0-100) for object-position int bannerZoom = 100; // Zoom percentage (100-200) int bannerPositionX = 50; // X position percentage (0-100) for object-position std::string graffitiUrl; std::string pgpOnlyEnabledAt; std::string colorCode; double ubercoinBalance = 0.0; // Übercoin balance (3 decimal places) std::string createdAt; // Account creation date (for burn rate calculation) int tokenVersion = 1; // SECURITY FIX #10: Token version for revocation }; // Result structure for refresh token operations struct RefreshTokenResult { bool success = false; std::string error; std::string accessToken; std::string refreshToken; std::string familyId; UserInfo user; }; // Chat service compatibility struct struct UserClaims { std::string userId; std::string username; std::string userColor; bool isAdmin; bool isModerator; // Site-wide moderator role bool isStreamer; bool isRestreamer; UserClaims() : isAdmin(false), isModerator(false), isStreamer(false), isRestreamer(false) {} }; class AuthService { public: static AuthService& getInstance() { static AuthService instance; return instance; } void registerUser(const std::string& username, const std::string& password, const std::string& publicKey, const std::string& fingerprint, std::function callback); void loginUser(const std::string& username, const std::string& password, std::function callback); void initiatePgpLogin(const std::string& username, std::function callback); void verifyPgpLogin(const std::string& username, const std::string& signature, const std::string& challenge, std::function callback); std::string generateToken(const UserInfo& user); bool validateToken(const std::string& token, UserInfo& userInfo); // Chat service compatibility method std::optional verifyToken(const std::string& token); // Refresh token methods void createRefreshTokenFamily(int64_t userId, std::function callback); void validateAndRotateRefreshToken(const std::string& refreshToken, std::function callback); void revokeTokenFamily(const std::string& familyId, std::function callback); void revokeAllUserTokenFamilies(int64_t userId, std::function callback); // New method to fetch complete user info including color void fetchUserInfo(int64_t userId, std::function callback); void updatePassword(int64_t userId, const std::string& oldPassword, const std::string& newPassword, std::function callback); void updateUserColor(int64_t userId, const std::string& newColor, std::function callback); void generateUniqueColor(std::function callback); private: AuthService() = default; std::string jwtSecret_; bool validatePassword(const std::string& password, std::string& error); void validateAndLoadJwtSecret(); // SECURITY FIX #5 // Refresh token helpers std::string generateRefreshToken(); // Generates random 256-bit token std::string hashToken(const std::string& token); // SHA256 hash for storage std::string generateUUID(); // Generate UUID for family_id static constexpr int ACCESS_TOKEN_EXPIRY_MINUTES = 150; // 2.5 hours (gives buffer for 2-hour refresh) static constexpr int REFRESH_TOKEN_EXPIRY_DAYS = 90; };