From 1fbfd13f5d7220122b2a127627cc9105013b4893 Mon Sep 17 00:00:00 2001 From: Aotrix <9aotrix@protonmail.com> Date: Wed, 29 Jul 2026 18:31:43 +0200 Subject: Add tests for HearthstoneTokenBuilder --- battleNetApi/src/hearthstoneTokenBuilder.cpp | 122 ++++++++++++++++----------- battleNetApi/src/token.cpp | 24 ++++-- 2 files changed, 89 insertions(+), 57 deletions(-) (limited to 'battleNetApi/src') diff --git a/battleNetApi/src/hearthstoneTokenBuilder.cpp b/battleNetApi/src/hearthstoneTokenBuilder.cpp index 89466a5..668aaa5 100644 --- a/battleNetApi/src/hearthstoneTokenBuilder.cpp +++ b/battleNetApi/src/hearthstoneTokenBuilder.cpp @@ -1,46 +1,69 @@ -#include #include #include #include #include #include +namespace bnet { HearthstoneTokenBuilder::HearthstoneTokenBuilder(const std::span &iJsonPaths) { _credentialJsonPaths.append_range(iJsonPaths); } HearthstoneTokenBuilder &HearthstoneTokenBuilder::buildToken() { - std::ranges::find_if(_credentialJsonPaths, - [](const std::string &iCredentialJsonPath) { return true; }); - if (hasExpired()) { - if (isUpdateSourceFileAllowed()) { + for (const std::string &aCredentialJsonPath : _credentialJsonPaths) { + std::ifstream aCredentialJsonFile{aCredentialJsonPath}; + json aCredentialJson = json::parse(aCredentialJsonFile); + if (isTokenValid(aCredentialJson)) { + _currentToken = std::make_shared(); + _currentToken->setText(aCredentialJson["Token"]["Content"]); + _currentToken->setExpirationTime( + std::chrono::seconds(aCredentialJson["Token"]["ExpirationTime"])); + return *this; } - const std::pair kTokenContent{getTokenWithApi()}; - writeTokenToLocalFile(kTokenContent); } - // return getTokenFromLocalFile(); - if (aTokenContainer.empty()) { - return std::nullopt; + + if (!_allowBattleNetApiCall) { + return *this; + } + + for (const std::string &aCredentialJsonPath : _credentialJsonPaths) { + std::ifstream aCredentialJsonFile{aCredentialJsonPath}; + json aCredentialJson = json::parse(aCredentialJsonFile); + _currentToken = std::make_shared(getTokenWithApi(aCredentialJson)); + if (_currentToken) { + if (_allowUpdateSourceFile) { + writeTokenToLocalFile(_currentToken, aCredentialJsonPath); + } + break; + } } - Token aOutputToken{aTokenContainer.front()}; - aTokenContainer.pop(); - // mCurrentToken = std::make_unique(...); return *this; } -std::shared_ptr HearthstoneTokenBuilder::getToken() { return mCurrentToken; } +std::shared_ptr HearthstoneTokenBuilder::getToken() { return _currentToken; } +HearthstoneTokenBuilder &HearthstoneTokenBuilder::allowBattleNetApiCall() { + _allowBattleNetApiCall = true; + return *this; +} HearthstoneTokenBuilder &HearthstoneTokenBuilder::allowUpdateSourceFile() { - mUpdateSourceFile = true; + _allowUpdateSourceFile = true; + return *this; +} +HearthstoneTokenBuilder &HearthstoneTokenBuilder::allowExpiredToken() { + _allowExpiredToken = true; return *this; } -bool HearthstoneTokenBuilder::isUpdateSourceFileAllowed() const { return mUpdateSourceFile; } +bool HearthstoneTokenBuilder::isUpdateSourceFileAllowed() const { return _allowUpdateSourceFile; } -const bool HearthstoneTokenBuilder::hasExpired(json iTokenJson) const { +bool HearthstoneTokenBuilder::isTokenValid(const json &iTokenJson) const { if (not iTokenJson.contains("Token") or not iTokenJson["Token"].contains("ExpirationTime") or not iTokenJson["Token"].contains("Content")) { - return true; + return false; } if (iTokenJson["Token"]["Content"].dump().length() < kTOKEN_CONTENT_MIN_LENGTH) { + return false; + } + if (_allowExpiredToken) { return true; } const std::uint64_t kExpirationTime{iTokenJson["Token"]["ExpirationTime"]}; @@ -48,7 +71,18 @@ const bool HearthstoneTokenBuilder::hasExpired(json iTokenJson) const { static_cast(std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch()) .count())}; - return kCurrentTime >= kExpirationTime; + return kCurrentTime <= kExpirationTime; +} + +std::chrono::seconds HearthstoneTokenBuilder::getCurrentTime() const { + return std::chrono::duration_cast( + std::chrono::utc_clock::now().time_since_epoch()); +} + +Token HearthstoneTokenBuilder::getTokenWithApi(const std::string &iCredentialsJsonFilePath) const { + std::ifstream aAgentJsonFile{iCredentialsJsonFilePath}; + json aCredentials = json::parse(aAgentJsonFile); + return getTokenWithApi(aCredentials); } size_t HearthstoneTokenBuilder::curlCallbackStringOutput(void *iPtr, size_t iSize, size_t iNmemb, @@ -63,33 +97,25 @@ size_t HearthstoneTokenBuilder::curlCallbackStringOutput(void *iPtr, size_t iSiz return newLength; } -std::chrono::seconds HearthstoneTokenBuilder::getCurrentTime() const { - return std::chrono::duration_cast( - std::chrono::utc_clock::now().time_since_epoch()); -} - -std::pair -HearthstoneTokenBuilder::getTokenWithApi(const std::string &iAgentJsonFilePath) const { - std::ifstream aAgentJsonFile{iAgentJsonFilePath}; - json aCredentials = json::parse(aAgentJsonFile); - if (not aCredentials.contains("Agent") or not aCredentials["Agent"].contains("Username") or - not aCredentials["Agent"].contains("Password")) { +Token HearthstoneTokenBuilder::getTokenWithApi(const json &iCredentials) const { + if (not iCredentials.contains("Agent") or not iCredentials["Agent"].contains("Username") or + not iCredentials["Agent"].contains("Password")) { std::cerr << "Please define Agent/Username and Agent/Password in the " "JSON credentials file\n"; std::exit(EXIT_FAILURE); } - const std::string kAgentUsername{aCredentials["Agent"]["Username"]}; - const std::string kAgentPassword{aCredentials["Agent"]["Password"]}; + const std::string aAgentUsername{iCredentials["Agent"]["Username"]}; + const std::string aAgentPassword{iCredentials["Agent"]["Password"]}; CURL *aCurl{curl_easy_init()}; std::string aTokenInfo; - if (aCurl and not kAgentUsername.empty() and not kAgentPassword.empty()) { + if (aCurl and not aAgentUsername.empty() and not aAgentPassword.empty()) { curl_easy_setopt(aCurl, CURLOPT_URL, "https://oauth.battle.net/token"); curl_easy_setopt(aCurl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(aCurl, CURLOPT_SSL_VERIFYHOST, 0L); curl_easy_setopt(aCurl, CURLOPT_WRITEFUNCTION, curlCallbackStringOutput); curl_easy_setopt(aCurl, CURLOPT_WRITEDATA, &aTokenInfo); curl_easy_setopt(aCurl, CURLOPT_USERPWD, - std::format("{}:{}", kAgentUsername, kAgentPassword).data()); + std::format("{}:{}", aAgentUsername, aAgentPassword).data()); curl_easy_setopt(aCurl, CURLOPT_POSTFIELDS, "grant_type=client_credentials"); CURLcode result_code{curl_easy_perform(aCurl)}; curl_easy_cleanup(aCurl); @@ -99,24 +125,18 @@ HearthstoneTokenBuilder::getTokenWithApi(const std::string &iAgentJsonFilePath) } } json aTokenJson = json::parse(aTokenInfo); - return std::make_pair(aTokenJson["access_token"], aTokenJson["expires_in"]); + return Token{} + .setText(aTokenJson["access_token"]) + .setLifetime(std::chrono::seconds{aTokenJson["expires_in"]}); } -std::string HearthstoneTokenBuilder::getTokenFromLocalFile() const { - std::ifstream aTokenFile{mFilePath}; - return json::parse(aTokenFile)["Token"]["Content"]; -} - -void HearthstoneTokenBuilder::writeTokenToLocalFile( - const std::pair &iToken) const { - std::ifstream aTokenFileInput{mFilePath}; - json aCredentialsFile = json::parse(aTokenFileInput); - aCredentialsFile["Token"]["Content"] = iToken.first; - aCredentialsFile["Token"]["ExpirationTime"] = - std::chrono::duration_cast(getCurrentTime() + - std::chrono::seconds(iToken.second)) - .count(); - - std::ofstream aTokenFileOutput{mFilePath}; +void HearthstoneTokenBuilder::writeTokenToLocalFile(std::shared_ptr &iToken, + const std::string &iTokenFileOutputPath) const { + std::ifstream aTokenFile{iTokenFileOutputPath}; + json aCredentialsFile = json::parse(aTokenFile); + aCredentialsFile["Token"]["Content"] = iToken->text(); + aCredentialsFile["Token"]["ExpirationTime"] = iToken->expirationTime()->count(); + std::ofstream aTokenFileOutput{iTokenFileOutputPath}; aTokenFileOutput << std::setw(4) << aCredentialsFile; } +} // namespace bnet diff --git a/battleNetApi/src/token.cpp b/battleNetApi/src/token.cpp index 276c334..a54136c 100644 --- a/battleNetApi/src/token.cpp +++ b/battleNetApi/src/token.cpp @@ -1,14 +1,26 @@ #include "token.hpp" -Token::Token(const std::string &iTokenText, const std::chrono::seconds &iLifetime) - : _tokenText{iTokenText}, _expirationTime{iLifetime + currentTime()} {} +namespace bnet { +Token::Token() {} -std::string Token::text() const { return _tokenText; } +std::optional Token::text() const { return _tokenText; } -void Token::setText(const std::string &iTokenText) { _tokenText = iTokenText; } +std::optional Token::expirationTime() const { return _expirationTime; } -void Token::setLifetime(const std::chrono::seconds &iExpirationTime) { - _expirationTime = iExpirationTime + currentTime(); +Token &Token::setText(const TokenText &iTokenText) { + _tokenText = iTokenText; + return *this; +} + +Token &Token::setLifetime(const std::chrono::seconds &iLifetime) { + _expirationTime = iLifetime + currentTime(); + return *this; +} + +Token &Token::setExpirationTime(const std::chrono::seconds &iExpirationTime) { + _expirationTime = iExpirationTime; + return *this; } bool Token::isExpired() { return _expirationTime <= currentTime(); } +} // namespace bnet -- cgit v1.2.3