Skip to content

Commit 17ccb8c

Browse files
committed
Improve token management and add IP rate-limiting
- Implement asynchronous cleanup for expired transfer tokens in `FTransferTokenManager`. - Integrate abuse protection to rate-limit client requests based on IP in the transfer token endpoint. - Add response handling for incorrect tokens in the transfer token endpoint.
1 parent 26e68be commit 17ccb8c

2 files changed

Lines changed: 42 additions & 1 deletion

File tree

ProjectServer/Source/Private/Auth/TransferTokenManager.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,40 @@ void FTransferTokenManager::AsyncWork()
6060

6161
void FTransferTokenManager::AsyncClearOldTransferTokens()
6262
{
63+
std::vector<std::string> ExpiredTokens;
6364

65+
{
66+
std::shared_lock<std::shared_mutex> ReadLock(TransferTokensMapMutex);
67+
const Uint64 CurrentTime = CurrentTimeCached;
68+
69+
for (const auto& [UserId, TokenData] : TransferTokensMap)
70+
{
71+
if (TokenData.ExpirationTime <= CurrentTime)
72+
{
73+
ExpiredTokens.push_back(TokenData.Token);
74+
}
75+
}
76+
}
6477

78+
if (!ExpiredTokens.empty())
79+
{
80+
std::unique_lock<std::shared_mutex> WriteLock(TransferTokensMapMutex);
81+
82+
for (const std::string& Token : ExpiredTokens)
83+
{
84+
// We must double-check if the token still exists in the reverse map.
85+
// Another thread might have overwritten or deleted it between our read and write locks.
86+
auto TokenIt = TransferTokenToIdMap.find(Token);
87+
if (TokenIt != TransferTokenToIdMap.end())
88+
{
89+
const Uint64 UserId = TokenIt->second;
90+
91+
// Safely erase from both maps
92+
TransferTokensMap.erase(UserId);
93+
TransferTokenToIdMap.erase(TokenIt);
94+
}
95+
}
96+
}
6597
}
6698

6799
std::string FTransferTokenManager::CreateTransferToken(const Uint64 UserId)

ProjectServer/Source/Private/Rest/TransferTokenEndpoint.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "PredefinedMessages.h"
88
#include "ProjectEngine.h"
9+
#include "AbuseProtection/AbuseProtection.h"
910
#include "Auth/TransferTokenManager.h"
1011
#include "Auth/UserManager.h"
1112
#include "Misc/Util.h"
@@ -26,7 +27,9 @@ void FTransferTokenEndpoint::RegisterRoutes(crow::App<FCrowAppMiddleware>& App)
2627
{
2728
crow::response OutResponse = FCrowUtils::CreateResponse(crow::status::INTERNAL_SERVER_ERROR, { { FPredefinedMessages::Status::Name, FPredefinedMessages::Status::Error }, { "message", "error."} });
2829

29-
// @TODO: Add limiting of requests per IP address
30+
// @TODO: Add specific limiting of requests per IP address
31+
const std::string& ClientIP = req.remote_ip_address;
32+
ProjectEngine->GetAbuseProtection()->AddRateLimitedAttempt(ClientIP);
3033

3134
const std::string CookieHeader = req.get_header_value("Cookie");
3235
const std::string AuthToken = ProjectEngine->ExtractCookieValue(CookieHeader, "auth_token");
@@ -56,6 +59,12 @@ void FTransferTokenEndpoint::RegisterRoutes(crow::App<FCrowAppMiddleware>& App)
5659
return FCrowUtils::CreateResponse(crow::status::OK,
5760
{ { FPredefinedMessages::Status::Name, FPredefinedMessages::Status::Success }, { "token", Token } });
5861
}
62+
else
63+
{
64+
return FCrowUtils::CreateResponse(crow::status::UNAUTHORIZED,
65+
{ { "status", "error" }, { "message", "Token incorrect."} }
66+
);
67+
}
5968

6069
return OutResponse;
6170
});

0 commit comments

Comments
 (0)