This commit is contained in:
parent
c2bfa06faa
commit
a56ca40204
16 changed files with 816 additions and 234 deletions
|
|
@ -2684,4 +2684,43 @@ void UserController::getReferralSettings(const HttpRequestPtr &req,
|
|||
callback(jsonResp(resp));
|
||||
}
|
||||
>> DB_ERROR_MSG(callback, "get settings", "Failed to get settings");
|
||||
}
|
||||
|
||||
void UserController::updateScreensaver(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
try {
|
||||
UserInfo user = getUserFromRequest(req);
|
||||
if (user.id == 0) {
|
||||
callback(jsonError("Unauthorized", k401Unauthorized));
|
||||
return;
|
||||
}
|
||||
|
||||
auto json = req->getJsonObject();
|
||||
if (!json) {
|
||||
callback(jsonError("Invalid JSON"));
|
||||
return;
|
||||
}
|
||||
|
||||
bool enabled = (*json).isMember("enabled") ? (*json)["enabled"].asBool() : false;
|
||||
int timeoutMinutes = (*json).isMember("timeout_minutes") ? (*json)["timeout_minutes"].asInt() : 5;
|
||||
|
||||
// Validate timeout range (1-30 minutes)
|
||||
if (timeoutMinutes < 1) timeoutMinutes = 1;
|
||||
if (timeoutMinutes > 30) timeoutMinutes = 30;
|
||||
|
||||
auto dbClient = app().getDbClient();
|
||||
*dbClient << "UPDATE users SET screensaver_enabled = $1, screensaver_timeout_minutes = $2 WHERE id = $3"
|
||||
<< enabled << timeoutMinutes << user.id
|
||||
>> [callback, enabled, timeoutMinutes](const Result&) {
|
||||
Json::Value resp;
|
||||
resp["success"] = true;
|
||||
resp["screensaver"]["enabled"] = enabled;
|
||||
resp["screensaver"]["timeout_minutes"] = timeoutMinutes;
|
||||
callback(jsonResp(resp));
|
||||
}
|
||||
>> DB_ERROR_MSG(callback, "update screensaver settings", "Failed to update screensaver settings");
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR << "Exception in updateScreensaver: " << e.what();
|
||||
callback(jsonError("Internal server error"));
|
||||
}
|
||||
}
|
||||
|
|
@ -48,6 +48,8 @@ public:
|
|||
ADD_METHOD_TO(UserController::validateReferralCode, "/api/auth/validate-referral", Post);
|
||||
ADD_METHOD_TO(UserController::registerWithReferral, "/api/auth/register-referral", Post);
|
||||
ADD_METHOD_TO(UserController::getReferralSettings, "/api/settings/referral", Get);
|
||||
// Screensaver settings
|
||||
ADD_METHOD_TO(UserController::updateScreensaver, "/api/user/screensaver", Put);
|
||||
METHOD_LIST_END
|
||||
|
||||
void register_(const HttpRequestPtr &req,
|
||||
|
|
@ -171,6 +173,10 @@ public:
|
|||
void getReferralSettings(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
|
||||
// Screensaver settings
|
||||
void updateScreensaver(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
|
||||
private:
|
||||
// Übercoin helper: Calculate burn rate based on account age
|
||||
// Formula: max(1, 99 * e^(-account_age_days / 180))
|
||||
|
|
|
|||
|
|
@ -443,7 +443,7 @@ void AuthService::loginUser(const std::string& username, const std::string& pass
|
|||
return;
|
||||
}
|
||||
|
||||
*dbClient << "SELECT id, username, password_hash, is_admin, is_moderator, is_streamer, is_restreamer, is_bot, is_texter, is_pgp_only, is_disabled, bio, avatar_url, banner_url, banner_position, banner_zoom, banner_position_x, graffiti_url, pgp_only_enabled_at, user_color "
|
||||
*dbClient << "SELECT id, username, password_hash, is_admin, is_moderator, is_streamer, is_restreamer, is_bot, is_texter, is_pgp_only, is_disabled, bio, avatar_url, banner_url, banner_position, banner_zoom, banner_position_x, graffiti_url, pgp_only_enabled_at, user_color, screensaver_enabled, screensaver_timeout_minutes "
|
||||
"FROM users WHERE username = $1 LIMIT 1"
|
||||
<< username
|
||||
>> [password, callback, this](const Result& r) {
|
||||
|
|
@ -504,6 +504,8 @@ void AuthService::loginUser(const std::string& username, const std::string& pass
|
|||
user.graffitiUrl = r[0]["graffiti_url"].isNull() ? "" : r[0]["graffiti_url"].as<std::string>();
|
||||
user.pgpOnlyEnabledAt = r[0]["pgp_only_enabled_at"].isNull() ? "" : r[0]["pgp_only_enabled_at"].as<std::string>();
|
||||
user.colorCode = r[0]["user_color"].isNull() ? "#561D5E" : r[0]["user_color"].as<std::string>();
|
||||
user.screensaverEnabled = r[0]["screensaver_enabled"].isNull() ? false : r[0]["screensaver_enabled"].as<bool>();
|
||||
user.screensaverTimeoutMinutes = r[0]["screensaver_timeout_minutes"].isNull() ? 5 : r[0]["screensaver_timeout_minutes"].as<int>();
|
||||
|
||||
std::string token = generateToken(user);
|
||||
callback(true, token, user);
|
||||
|
|
@ -599,7 +601,7 @@ void AuthService::verifyPgpLogin(const std::string& username, const std::string&
|
|||
}
|
||||
|
||||
*dbClient << "SELECT pk.public_key, u.id, u.username, u.is_admin, u.is_moderator, u.is_streamer, u.is_restreamer, u.is_bot, u.is_texter, "
|
||||
"u.is_pgp_only, u.is_disabled, u.bio, u.avatar_url, u.banner_url, u.banner_position, u.banner_zoom, u.banner_position_x, u.graffiti_url, u.pgp_only_enabled_at, u.user_color "
|
||||
"u.is_pgp_only, u.is_disabled, u.bio, u.avatar_url, u.banner_url, u.banner_position, u.banner_zoom, u.banner_position_x, u.graffiti_url, u.pgp_only_enabled_at, u.user_color, u.screensaver_enabled, u.screensaver_timeout_minutes "
|
||||
"FROM pgp_keys pk JOIN users u ON pk.user_id = u.id "
|
||||
"WHERE u.username = $1 ORDER BY pk.created_at DESC LIMIT 1"
|
||||
<< username
|
||||
|
|
@ -650,6 +652,8 @@ void AuthService::verifyPgpLogin(const std::string& username, const std::string&
|
|||
user.graffitiUrl = r[0]["graffiti_url"].isNull() ? "" : r[0]["graffiti_url"].as<std::string>();
|
||||
user.pgpOnlyEnabledAt = r[0]["pgp_only_enabled_at"].isNull() ? "" : r[0]["pgp_only_enabled_at"].as<std::string>();
|
||||
user.colorCode = r[0]["user_color"].isNull() ? "#561D5E" : r[0]["user_color"].as<std::string>();
|
||||
user.screensaverEnabled = r[0]["screensaver_enabled"].isNull() ? false : r[0]["screensaver_enabled"].as<bool>();
|
||||
user.screensaverTimeoutMinutes = r[0]["screensaver_timeout_minutes"].isNull() ? 5 : r[0]["screensaver_timeout_minutes"].as<int>();
|
||||
|
||||
std::string token = generateToken(user);
|
||||
callback(true, token, user);
|
||||
|
|
@ -917,7 +921,7 @@ void AuthService::fetchUserInfo(int64_t userId, std::function<void(bool, const U
|
|||
return;
|
||||
}
|
||||
|
||||
*dbClient << "SELECT id, username, is_admin, is_moderator, is_streamer, is_restreamer, is_bot, is_texter, is_pgp_only, bio, avatar_url, banner_url, banner_position, banner_zoom, banner_position_x, graffiti_url, pgp_only_enabled_at, user_color "
|
||||
*dbClient << "SELECT id, username, is_admin, is_moderator, is_streamer, is_restreamer, is_bot, is_texter, is_pgp_only, bio, avatar_url, banner_url, banner_position, banner_zoom, banner_position_x, graffiti_url, pgp_only_enabled_at, user_color, screensaver_enabled, screensaver_timeout_minutes "
|
||||
"FROM users WHERE id = $1 LIMIT 1"
|
||||
<< userId
|
||||
>> [callback](const Result& r) {
|
||||
|
|
@ -946,6 +950,8 @@ void AuthService::fetchUserInfo(int64_t userId, std::function<void(bool, const U
|
|||
user.graffitiUrl = r[0]["graffiti_url"].isNull() ? "" : r[0]["graffiti_url"].as<std::string>();
|
||||
user.pgpOnlyEnabledAt = r[0]["pgp_only_enabled_at"].isNull() ? "" : r[0]["pgp_only_enabled_at"].as<std::string>();
|
||||
user.colorCode = r[0]["user_color"].isNull() ? "#561D5E" : r[0]["user_color"].as<std::string>();
|
||||
user.screensaverEnabled = r[0]["screensaver_enabled"].isNull() ? false : r[0]["screensaver_enabled"].as<bool>();
|
||||
user.screensaverTimeoutMinutes = r[0]["screensaver_timeout_minutes"].isNull() ? 5 : r[0]["screensaver_timeout_minutes"].as<int>();
|
||||
|
||||
callback(true, user);
|
||||
} catch (const std::exception& e) {
|
||||
|
|
@ -1069,7 +1075,7 @@ void AuthService::validateAndRotateRefreshToken(const std::string& refreshToken,
|
|||
*dbClient << "SELECT rtf.id, rtf.user_id, rtf.family_id, rtf.expires_at, rtf.revoked, "
|
||||
"u.username, u.is_admin, u.is_moderator, u.is_streamer, u.is_restreamer, "
|
||||
"u.is_bot, u.is_texter, u.is_pgp_only, u.is_disabled, u.user_color, u.avatar_url, "
|
||||
"u.token_version "
|
||||
"u.token_version, u.screensaver_enabled, u.screensaver_timeout_minutes "
|
||||
"FROM refresh_token_families rtf "
|
||||
"JOIN users u ON rtf.user_id = u.id "
|
||||
"WHERE rtf.current_token_hash = $1"
|
||||
|
|
@ -1130,6 +1136,8 @@ void AuthService::validateAndRotateRefreshToken(const std::string& refreshToken,
|
|||
user.colorCode = row["user_color"].isNull() ? "#561D5E" : row["user_color"].as<std::string>();
|
||||
user.avatarUrl = row["avatar_url"].isNull() ? "" : row["avatar_url"].as<std::string>();
|
||||
user.tokenVersion = row["token_version"].isNull() ? 1 : row["token_version"].as<int>();
|
||||
user.screensaverEnabled = row["screensaver_enabled"].isNull() ? false : row["screensaver_enabled"].as<bool>();
|
||||
user.screensaverTimeoutMinutes = row["screensaver_timeout_minutes"].isNull() ? 5 : row["screensaver_timeout_minutes"].as<int>();
|
||||
|
||||
// Generate new tokens (rotation)
|
||||
std::string newRefreshToken = generateRefreshToken();
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ struct UserInfo {
|
|||
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
|
||||
bool screensaverEnabled = false; // Screensaver feature enabled
|
||||
int screensaverTimeoutMinutes = 5; // Idle timeout before screensaver activates (1-30)
|
||||
};
|
||||
|
||||
// Result structure for refresh token operations
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue