diff --git a/src/Cafe/IOSU/legacy/iosu_boss.cpp b/src/Cafe/IOSU/legacy/iosu_boss.cpp index c2c1eb51f..760e5b666 100644 --- a/src/Cafe/IOSU/legacy/iosu_boss.cpp +++ b/src/Cafe/IOSU/legacy/iosu_boss.cpp @@ -498,7 +498,7 @@ namespace iosu curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, task_header_callback); curl_easy_setopt(curl, CURLOPT_HEADERDATA, &(*it)); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 0x3C); - if (GetNetworkConfig().disablesslver.GetValue() && ActiveSettings::GetNetworkService() == NetworkService::Custom || ActiveSettings::GetNetworkService() == NetworkService::Pretendo) // remove Pretendo Function once SSL is in the Service + if (IsNetworkServiceSSLDisabled(ActiveSettings::GetNetworkService())) { curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,0L); } diff --git a/src/Cafe/IOSU/legacy/iosu_crypto.cpp b/src/Cafe/IOSU/legacy/iosu_crypto.cpp index 80eb2f017..a4f75430e 100644 --- a/src/Cafe/IOSU/legacy/iosu_crypto.cpp +++ b/src/Cafe/IOSU/legacy/iosu_crypto.cpp @@ -292,16 +292,6 @@ void iosuCrypto_generateDeviceCertificate() BN_CTX_free(context); } -bool iosuCrypto_hasAllDataForLogin() -{ - if (hasOtpMem == false) - return false; - if (hasSeepromMem == false) - return false; - // todo - check if certificates are available - return true; -} - sint32 iosuCrypto_getDeviceCertificateBase64Encoded(char* output) { iosuCrypto_base64Encode((uint8*)&g_wiiuDeviceCert, sizeof(g_wiiuDeviceCert), output); diff --git a/src/Cafe/IOSU/legacy/iosu_crypto.h b/src/Cafe/IOSU/legacy/iosu_crypto.h index 9f1429c76..d4fc49b92 100644 --- a/src/Cafe/IOSU/legacy/iosu_crypto.h +++ b/src/Cafe/IOSU/legacy/iosu_crypto.h @@ -2,7 +2,6 @@ void iosuCrypto_init(); -bool iosuCrypto_hasAllDataForLogin(); bool iosuCrypto_getDeviceId(uint32* deviceId); void iosuCrypto_getDeviceSerialString(char* serialString); diff --git a/src/Cafe/IOSU/legacy/iosu_nim.cpp b/src/Cafe/IOSU/legacy/iosu_nim.cpp index e7cf97ef0..b529640d7 100644 --- a/src/Cafe/IOSU/legacy/iosu_nim.cpp +++ b/src/Cafe/IOSU/legacy/iosu_nim.cpp @@ -228,7 +228,7 @@ namespace iosu } } - auto result = NAPI::IDBE_Request(titleId); + auto result = NAPI::IDBE_Request(ActiveSettings::GetNetworkService(), titleId); if (!result) { memset(idbeIconOutput, 0, sizeof(NAPI::IDBEIconDataV0)); diff --git a/src/Cafe/OS/libs/nn_idbe/nn_idbe.cpp b/src/Cafe/OS/libs/nn_idbe/nn_idbe.cpp index a78494cf1..a69f32a3d 100644 --- a/src/Cafe/OS/libs/nn_idbe/nn_idbe.cpp +++ b/src/Cafe/OS/libs/nn_idbe/nn_idbe.cpp @@ -42,7 +42,7 @@ namespace nn void asyncDownloadIconFile(uint64 titleId, nnIdbeEncryptedIcon_t* iconOut, OSThread_t* thread) { - std::vector idbeData = NAPI::IDBE_RequestRawEncrypted(titleId); + std::vector idbeData = NAPI::IDBE_RequestRawEncrypted(ActiveSettings::GetNetworkService(), titleId); if (idbeData.size() != sizeof(nnIdbeEncryptedIcon_t)) { // icon does not exist or has the wrong size diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.cpp b/src/Cafe/OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.cpp index 1bf2b37db..db1885af2 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.cpp +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.cpp @@ -43,7 +43,7 @@ namespace nn return res; CurlRequestHelper req; - req.initate(reqUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE); + req.initate(ActiveSettings::GetNetworkService(), reqUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE); InitializeOliveRequest(req); StackAllocator requestDoneEvent; diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_InitializeTypes.cpp b/src/Cafe/OS/libs/nn_olv/nn_olv_InitializeTypes.cpp index 5e6dba7ef..ba657ff74 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_InitializeTypes.cpp +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_InitializeTypes.cpp @@ -195,7 +195,7 @@ namespace nn break; } - req.initate(requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE); + req.initate(ActiveSettings::GetNetworkService(), requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE); InitializeOliveRequest(req); StackAllocator requestDoneEvent; diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp index 179d66bd8..6f3c43b9d 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp @@ -50,7 +50,7 @@ namespace nn CurlRequestHelper req; - req.initate(requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE); + req.initate(ActiveSettings::GetNetworkService(), requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE); InitializeOliveRequest(req); StackAllocator requestDoneEvent; diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp index 307004b9b..1e2d40ab7 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp @@ -40,7 +40,7 @@ namespace nn snprintf(requestUrl, sizeof(requestUrl), "%s/v1/communities/%lu.favorite", g_DiscoveryResults.apiEndpoint, pParam->communityId.value()); CurlRequestHelper req; - req.initate(requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE); + req.initate(ActiveSettings::GetNetworkService(), requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE); InitializeOliveRequest(req); StackAllocator requestDoneEvent; diff --git a/src/Cemu/Tools/DownloadManager/DownloadManager.cpp b/src/Cemu/Tools/DownloadManager/DownloadManager.cpp index 807a4e724..9e683ed1a 100644 --- a/src/Cemu/Tools/DownloadManager/DownloadManager.cpp +++ b/src/Cemu/Tools/DownloadManager/DownloadManager.cpp @@ -33,14 +33,7 @@ void DownloadManager::downloadTitleVersionList() { if (m_hasTitleVersionList) return; - NAPI::AuthInfo authInfo; - authInfo.accountId = m_authInfo.nnidAccountName; - authInfo.passwordHash = m_authInfo.passwordHash; - authInfo.deviceId = m_authInfo.deviceId; - authInfo.serial = m_authInfo.serial; - authInfo.country = m_authInfo.country; - authInfo.region = m_authInfo.region; - authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64; + NAPI::AuthInfo authInfo = GetAuthInfo(false); auto versionListVersionResult = NAPI::TAG_GetVersionListVersion(authInfo); if (!versionListVersionResult.isValid) return; @@ -195,15 +188,7 @@ struct StoredTokenInfo : public SerializerHelper bool DownloadManager::_connect_refreshIASAccountIdAndDeviceToken() { - NAPI::AuthInfo authInfo; - authInfo.accountId = m_authInfo.nnidAccountName; - authInfo.passwordHash = m_authInfo.passwordHash; - authInfo.deviceId = m_authInfo.deviceId; - authInfo.serial = m_authInfo.serial; - authInfo.country = m_authInfo.country; - authInfo.region = m_authInfo.region; - authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64; - + NAPI::AuthInfo authInfo = GetAuthInfo(false); // query IAS/ECS account id and device token (if not cached) auto rChallenge = NAPI::IAS_GetChallenge(authInfo); if (rChallenge.apiError != NAPI_RESULT::SUCCESS) @@ -211,7 +196,6 @@ bool DownloadManager::_connect_refreshIASAccountIdAndDeviceToken() auto rRegistrationInfo = NAPI::IAS_GetRegistrationInfo_QueryInfo(authInfo, rChallenge.challenge); if (rRegistrationInfo.apiError != NAPI_RESULT::SUCCESS) return false; - m_iasToken.serviceAccountId = rRegistrationInfo.accountId; m_iasToken.deviceToken = rRegistrationInfo.deviceToken; // store to cache @@ -221,24 +205,13 @@ bool DownloadManager::_connect_refreshIASAccountIdAndDeviceToken() std::vector serializedData; if (!storedTokenInfo.serialize(serializedData)) return false; - s_nupFileCache->AddFileAsync({ fmt::format("{}/token_info", m_authInfo.nnidAccountName) }, serializedData.data(), serializedData.size()); + s_nupFileCache->AddFileAsync({ fmt::format("{}/token_info", m_authInfo.cachefileName) }, serializedData.data(), serializedData.size()); return true; } bool DownloadManager::_connect_queryAccountStatusAndServiceURLs() { - NAPI::AuthInfo authInfo; - authInfo.accountId = m_authInfo.nnidAccountName; - authInfo.passwordHash = m_authInfo.passwordHash; - authInfo.deviceId = m_authInfo.deviceId; - authInfo.serial = m_authInfo.serial; - authInfo.country = m_authInfo.country; - authInfo.region = m_authInfo.region; - authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64; - - authInfo.IASToken.accountId = m_iasToken.serviceAccountId; - authInfo.IASToken.deviceToken = m_iasToken.deviceToken; - + NAPI::AuthInfo authInfo = GetAuthInfo(true); NAPI::NAPI_ECSGetAccountStatus_Result accountStatusResult = NAPI::ECS_GetAccountStatus(authInfo); if (accountStatusResult.apiError != NAPI_RESULT::SUCCESS) { @@ -291,7 +264,7 @@ void DownloadManager::loadTicketCache() m_ticketCache.clear(); cemu_assert_debug(m_ticketCache.empty()); std::vector ticketCacheBlob; - if (!s_nupFileCache->GetFile({ fmt::format("{}/eticket_cache", m_authInfo.nnidAccountName) }, ticketCacheBlob)) + if (!s_nupFileCache->GetFile({ fmt::format("{}/eticket_cache", m_authInfo.cachefileName) }, ticketCacheBlob)) return; MemStreamReader memReader(ticketCacheBlob.data(), ticketCacheBlob.size()); uint8 version = memReader.readBE(); @@ -343,23 +316,12 @@ void DownloadManager::storeTicketCache() memWriter.writePODVector(cert); } auto serializedBlob = memWriter.getResult(); - s_nupFileCache->AddFileAsync({ fmt::format("{}/eticket_cache", m_authInfo.nnidAccountName) }, serializedBlob.data(), serializedBlob.size()); + s_nupFileCache->AddFileAsync({ fmt::format("{}/eticket_cache", m_authInfo.cachefileName) }, serializedBlob.data(), serializedBlob.size()); } bool DownloadManager::syncAccountTickets() { - NAPI::AuthInfo authInfo; - authInfo.accountId = m_authInfo.nnidAccountName; - authInfo.passwordHash = m_authInfo.passwordHash; - authInfo.deviceId = m_authInfo.deviceId; - authInfo.serial = m_authInfo.serial; - authInfo.country = m_authInfo.country; - authInfo.region = m_authInfo.region; - authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64; - - authInfo.IASToken.accountId = m_iasToken.serviceAccountId; - authInfo.IASToken.deviceToken = m_iasToken.deviceToken; - + NAPI::AuthInfo authInfo = GetAuthInfo(true); // query TIV list from server NAPI::NAPI_ECSAccountListETicketIds_Result resultTicketIds = NAPI::ECS_AccountListETicketIds(authInfo); if (!resultTicketIds.isValid()) @@ -425,19 +387,7 @@ bool DownloadManager::syncAccountTickets() bool DownloadManager::syncSystemTitleTickets() { setStatusMessage(_("Downloading system tickets...").utf8_string(), DLMGR_STATUS_CODE::CONNECTING); - // todo - add GetAuth() function - NAPI::AuthInfo authInfo; - authInfo.accountId = m_authInfo.nnidAccountName; - authInfo.passwordHash = m_authInfo.passwordHash; - authInfo.deviceId = m_authInfo.deviceId; - authInfo.serial = m_authInfo.serial; - authInfo.country = m_authInfo.country; - authInfo.region = m_authInfo.region; - authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64; - - authInfo.IASToken.accountId = m_iasToken.serviceAccountId; - authInfo.IASToken.deviceToken = m_iasToken.deviceToken; - + NAPI::AuthInfo authInfo = GetAuthInfo(true); auto querySystemTitleTicket = [&](uint64 titleId) -> void { // check if cached already @@ -520,8 +470,7 @@ bool DownloadManager::syncUpdateTickets() if (findTicketByTitleIdAndVersion(itr.titleId, itr.availableTitleVersion)) continue; - NAPI::AuthInfo dummyAuth; - auto cetkResult = NAPI::CCS_GetCETK(dummyAuth, itr.titleId, itr.availableTitleVersion); + auto cetkResult = NAPI::CCS_GetCETK(GetDownloadMgrNetworkService(), itr.titleId, itr.availableTitleVersion); if (!cetkResult.isValid) continue; NCrypto::ETicketParser ticketParser; @@ -657,7 +606,7 @@ void DownloadManager::_handle_connect() if (s_nupFileCache) { std::vector serializationBlob; - if (s_nupFileCache->GetFile({ fmt::format("{}/token_info", m_authInfo.nnidAccountName) }, serializationBlob)) + if (s_nupFileCache->GetFile({ fmt::format("{}/token_info", m_authInfo.cachefileName) }, serializationBlob)) { StoredTokenInfo storedTokenInfo; if (storedTokenInfo.deserialize(serializationBlob)) @@ -683,7 +632,7 @@ void DownloadManager::_handle_connect() if (!_connect_queryAccountStatusAndServiceURLs()) { m_connectState.store(CONNECT_STATE::FAILED); - setStatusMessage(_("Failed to query account status. Invalid account information?").utf8_string(), DLMGR_STATUS_CODE::FAILED); + setStatusMessage(_("Failed to query account status").utf8_string(), DLMGR_STATUS_CODE::FAILED); return; } // load ticket cache and sync @@ -692,7 +641,7 @@ void DownloadManager::_handle_connect() if (!syncTicketCache()) { m_connectState.store(CONNECT_STATE::FAILED); - setStatusMessage(_("Failed to request tickets (invalid NNID?)").utf8_string(), DLMGR_STATUS_CODE::FAILED); + setStatusMessage(_("Failed to request tickets").utf8_string(), DLMGR_STATUS_CODE::FAILED); return; } searchForIncompleteDownloads(); @@ -713,22 +662,10 @@ void DownloadManager::connect( std::string_view serial, std::string_view deviceCertBase64) { - if (nnidAccountName.empty()) - { - m_connectState.store(CONNECT_STATE::FAILED); - setStatusMessage(_("This account is not linked with an NNID").utf8_string(), DLMGR_STATUS_CODE::FAILED); - return; - } runManager(); m_authInfo.nnidAccountName = nnidAccountName; m_authInfo.passwordHash = passwordHash; - if (std::all_of(m_authInfo.passwordHash.begin(), m_authInfo.passwordHash.end(), [](uint8 v) { return v == 0; })) - { - cemuLog_log(LogType::Force, "DLMgr: Invalid password hash"); - m_connectState.store(CONNECT_STATE::FAILED); - setStatusMessage(_("Failed. Account does not have password set").utf8_string(), DLMGR_STATUS_CODE::FAILED); - return; - } + m_authInfo.cachefileName = nnidAccountName.empty() ? "DefaultName" : nnidAccountName; m_authInfo.region = region; m_authInfo.country = country; m_authInfo.deviceCertBase64 = deviceCertBase64; @@ -744,6 +681,31 @@ bool DownloadManager::IsConnected() const return m_connectState.load() != CONNECT_STATE::UNINITIALIZED; } +NetworkService DownloadManager::GetDownloadMgrNetworkService() +{ + return NetworkService::Nintendo; +} + +NAPI::AuthInfo DownloadManager::GetAuthInfo(bool withIasToken) +{ + NAPI::AuthInfo authInfo; + authInfo.serviceOverwrite = GetDownloadMgrNetworkService(); + authInfo.accountId = m_authInfo.nnidAccountName; + authInfo.passwordHash = m_authInfo.passwordHash; + authInfo.deviceId = m_authInfo.deviceId; + authInfo.serial = m_authInfo.serial; + authInfo.country = m_authInfo.country; + authInfo.region = m_authInfo.region; + authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64; + if(withIasToken) + { + cemu_assert_debug(!m_iasToken.serviceAccountId.empty()); + authInfo.IASToken.accountId = m_iasToken.serviceAccountId; + authInfo.IASToken.deviceToken = m_iasToken.deviceToken; + } + return authInfo; +} + /* package / downloading */ // start/resume/retry download @@ -1022,17 +984,7 @@ void DownloadManager::reportPackageProgress(Package* package, uint32 currentProg void DownloadManager::asyncPackageDownloadTMD(Package* package) { - NAPI::AuthInfo authInfo; - authInfo.accountId = m_authInfo.nnidAccountName; - authInfo.passwordHash = m_authInfo.passwordHash; - authInfo.deviceId = m_authInfo.deviceId; - authInfo.serial = m_authInfo.serial; - authInfo.country = m_authInfo.country; - authInfo.region = m_authInfo.region; - authInfo.deviceCertBase64 = m_authInfo.deviceCertBase64; - authInfo.IASToken.accountId = m_iasToken.serviceAccountId; - authInfo.IASToken.deviceToken = m_iasToken.deviceToken; - + NAPI::AuthInfo authInfo = GetAuthInfo(true); TitleIdParser titleIdParser(package->titleId); NAPI::NAPI_CCSGetTMD_Result tmdResult; if (titleIdParser.GetType() == TitleIdParser::TITLE_TYPE::AOC) @@ -1196,7 +1148,7 @@ void DownloadManager::asyncPackageDownloadContentFile(Package* package, uint16 i setPackageError(package, _("Cannot create file").utf8_string()); return; } - if (!NAPI::CCS_GetContentFile(titleId, contentId, CallbackInfo::writeCallback, &callbackInfoData)) + if (!NAPI::CCS_GetContentFile(GetDownloadMgrNetworkService(), titleId, contentId, CallbackInfo::writeCallback, &callbackInfoData)) { setPackageError(package, _("Download failed").utf8_string()); delete callbackInfoData.fileOutput; @@ -1490,7 +1442,7 @@ void DownloadManager::prepareIDBE(uint64 titleId) if (s_nupFileCache->GetFile({ fmt::format("idbe/{0:016x}", titleId) }, idbeFile) && idbeFile.size() == sizeof(NAPI::IDBEIconDataV0)) return addToCache(titleId, (NAPI::IDBEIconDataV0*)(idbeFile.data())); // not cached, query from server - std::optional iconData = NAPI::IDBE_Request(titleId); + std::optional iconData = NAPI::IDBE_Request(GetDownloadMgrNetworkService(), titleId); if (!iconData) return; s_nupFileCache->AddFileAsync({ fmt::format("idbe/{0:016x}", titleId) }, (uint8*)&(*iconData), sizeof(NAPI::IDBEIconDataV0)); diff --git a/src/Cemu/Tools/DownloadManager/DownloadManager.h b/src/Cemu/Tools/DownloadManager/DownloadManager.h index 1693318c8..8f693a3e6 100644 --- a/src/Cemu/Tools/DownloadManager/DownloadManager.h +++ b/src/Cemu/Tools/DownloadManager/DownloadManager.h @@ -2,17 +2,14 @@ #include "util/helpers/Semaphore.h" #include "Cemu/ncrypto/ncrypto.h" #include "Cafe/TitleList/TitleId.h" - #include "util/helpers/ConcurrentQueue.h" +#include "config/NetworkSettings.h" -#include -#include - -#include - +// forward declarations namespace NAPI { struct IDBEIconDataV0; + struct AuthInfo; } namespace NCrypto @@ -86,7 +83,6 @@ class DownloadManager bool IsConnected() const; - private: /* connect / login */ @@ -101,6 +97,7 @@ class DownloadManager struct { + std::string cachefileName; std::string nnidAccountName; std::array passwordHash; std::string deviceCertBase64; @@ -122,7 +119,10 @@ class DownloadManager void _handle_connect(); bool _connect_refreshIASAccountIdAndDeviceToken(); bool _connect_queryAccountStatusAndServiceURLs(); - + + NetworkService GetDownloadMgrNetworkService(); + NAPI::AuthInfo GetAuthInfo(bool withIasToken); + /* idbe cache */ public: void prepareIDBE(uint64 titleId); diff --git a/src/Cemu/napi/napi.h b/src/Cemu/napi/napi.h index ab17a7b30..e1397d629 100644 --- a/src/Cemu/napi/napi.h +++ b/src/Cemu/napi/napi.h @@ -1,6 +1,7 @@ #pragma once -#include #include "config/CemuConfig.h" // for ConsoleLanguage +#include "config/NetworkSettings.h" // for NetworkService +#include "config/ActiveSettings.h" // for GetNetworkService() enum class NAPI_RESULT { @@ -16,8 +17,6 @@ namespace NAPI // common auth info structure shared by ACT, ECS and IAS service struct AuthInfo { - // todo - constructor for account name + raw password - // nnid std::string accountId; std::array passwordHash; @@ -41,9 +40,13 @@ namespace NAPI std::string deviceToken; }IASToken; - // ACT token (for account.nintendo.net requests) - + // service selection, if not set fall back to global setting + std::optional serviceOverwrite; + NetworkService GetService() const + { + return serviceOverwrite.value_or(ActiveSettings::GetNetworkService()); + } }; bool NAPI_MakeAuthInfoFromCurrentAccount(AuthInfo& authInfo); // helper function. Returns false if online credentials/dumped files are not available @@ -232,9 +235,9 @@ namespace NAPI NAPI_CCSGetTMD_Result CCS_GetTMD(AuthInfo& authInfo, uint64 titleId, uint16 titleVersion); NAPI_CCSGetTMD_Result CCS_GetTMD(AuthInfo& authInfo, uint64 titleId); - NAPI_CCSGetETicket_Result CCS_GetCETK(AuthInfo& authInfo, uint64 titleId, uint16 titleVersion); - bool CCS_GetContentFile(uint64 titleId, uint32 contentId, bool(*cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast), void* userData); - NAPI_CCSGetContentH3_Result CCS_GetContentH3File(uint64 titleId, uint32 contentId); + NAPI_CCSGetETicket_Result CCS_GetCETK(NetworkService service, uint64 titleId, uint16 titleVersion); + bool CCS_GetContentFile(NetworkService service, uint64 titleId, uint32 contentId, bool(*cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast), void* userData); + NAPI_CCSGetContentH3_Result CCS_GetContentH3File(NetworkService service, uint64 titleId, uint32 contentId); /* IDBE */ @@ -286,8 +289,8 @@ namespace NAPI static_assert(sizeof(IDBEHeader) == 2+32); - std::optional IDBE_Request(uint64 titleId); - std::vector IDBE_RequestRawEncrypted(uint64 titleId); // same as IDBE_Request but doesn't strip the header and decrypt the IDBE + std::optional IDBE_Request(NetworkService networkService, uint64 titleId); + std::vector IDBE_RequestRawEncrypted(NetworkService networkService, uint64 titleId); // same as IDBE_Request but doesn't strip the header and decrypt the IDBE /* Version list */ diff --git a/src/Cemu/napi/napi_act.cpp b/src/Cemu/napi/napi_act.cpp index 9716c41ee..c72d9f476 100644 --- a/src/Cemu/napi/napi_act.cpp +++ b/src/Cemu/napi/napi_act.cpp @@ -14,6 +14,21 @@ namespace NAPI { + std::string _getACTUrl(NetworkService service) + { + switch (service) + { + case NetworkService::Nintendo: + return NintendoURLs::ACTURL; + case NetworkService::Pretendo: + return PretendoURLs::ACTURL; + case NetworkService::Custom: + return GetNetworkConfig().urls.ACT.GetValue(); + default: + return NintendoURLs::ACTURL; + } + } + struct ACTOauthToken : public _NAPI_CommonResultACT { std::string token; @@ -91,7 +106,7 @@ namespace NAPI struct OAuthTokenCacheEntry { - OAuthTokenCacheEntry(std::string_view accountId, std::array& passwordHash, std::string_view token, std::string_view refreshToken, uint64 expiresIn) : accountId(accountId), passwordHash(passwordHash), token(token), refreshToken(refreshToken) + OAuthTokenCacheEntry(std::string_view accountId, std::array& passwordHash, std::string_view token, std::string_view refreshToken, uint64 expiresIn, NetworkService service) : accountId(accountId), passwordHash(passwordHash), token(token), refreshToken(refreshToken), service(service) { expires = HighResolutionTimer::now().getTickInSeconds() + expiresIn; }; @@ -107,10 +122,10 @@ namespace NAPI } std::string accountId; std::array passwordHash; - std::string token; std::string refreshToken; uint64 expires; + NetworkService service; }; std::vector g_oauthTokenCache; @@ -122,11 +137,12 @@ namespace NAPI ACTOauthToken result{}; // check cache first + NetworkService service = authInfo.GetService(); g_oauthTokenCacheMtx.lock(); auto cacheItr = g_oauthTokenCache.begin(); while (cacheItr != g_oauthTokenCache.end()) { - if (cacheItr->CheckIfSameAccount(authInfo)) + if (cacheItr->CheckIfSameAccount(authInfo) && cacheItr->service == service) { if (cacheItr->CheckIfExpired()) { @@ -145,7 +161,7 @@ namespace NAPI // token not cached, request from server via oauth2 CurlRequestHelper req; - req.initate(fmt::format("{}/v1/api/oauth20/access_token/generate", LaunchSettings::GetActURLPrefix()), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT); + req.initate(authInfo.GetService(), fmt::format("{}/v1/api/oauth20/access_token/generate", _getACTUrl(authInfo.GetService())), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT); _ACTSetCommonHeaderParameters(req, authInfo); _ACTSetDeviceParameters(req, authInfo); _ACTSetRegionAndCountryParameters(req, authInfo); @@ -220,7 +236,7 @@ namespace NAPI if (expiration > 0) { g_oauthTokenCacheMtx.lock(); - g_oauthTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, result.token, result.refreshToken, expiration); + g_oauthTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, result.token, result.refreshToken, expiration, service); g_oauthTokenCacheMtx.unlock(); } return result; @@ -230,14 +246,13 @@ namespace NAPI { CurlRequestHelper req; - req.initate(fmt::format("{}/v1/api/people/@me/profile", LaunchSettings::GetActURLPrefix()), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT); + req.initate(authInfo.GetService(), fmt::format("{}/v1/api/people/@me/profile", _getACTUrl(authInfo.GetService())), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT); _ACTSetCommonHeaderParameters(req, authInfo); _ACTSetDeviceParameters(req, authInfo); // get oauth2 token ACTOauthToken oauthToken = ACT_GetOauthToken_WithCache(authInfo, 0x0005001010001C00, 0x0001C); - cemu_assert_unimplemented(); return true; @@ -245,15 +260,16 @@ namespace NAPI struct NexTokenCacheEntry { - NexTokenCacheEntry(std::string_view accountId, std::array& passwordHash, uint32 gameServerId, ACTNexToken& nexToken) : accountId(accountId), passwordHash(passwordHash), nexToken(nexToken), gameServerId(gameServerId) {}; + NexTokenCacheEntry(std::string_view accountId, std::array& passwordHash, NetworkService networkService, uint32 gameServerId, ACTNexToken& nexToken) : accountId(accountId), passwordHash(passwordHash), networkService(networkService), nexToken(nexToken), gameServerId(gameServerId) {}; bool IsMatch(const AuthInfo& authInfo, const uint32 gameServerId) const { - return authInfo.accountId == accountId && authInfo.passwordHash == passwordHash && this->gameServerId == gameServerId; + return authInfo.accountId == accountId && authInfo.passwordHash == passwordHash && authInfo.GetService() == networkService && this->gameServerId == gameServerId; } std::string accountId; std::array passwordHash; + NetworkService networkService; uint32 gameServerId; ACTNexToken nexToken; @@ -297,7 +313,7 @@ namespace NAPI } // do request CurlRequestHelper req; - req.initate(fmt::format("{}/v1/api/provider/nex_token/@me?game_server_id={:08X}", LaunchSettings::GetActURLPrefix(), serverId), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT); + req.initate(authInfo.GetService(), fmt::format("{}/v1/api/provider/nex_token/@me?game_server_id={:08X}", _getACTUrl(authInfo.GetService()), serverId), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT); _ACTSetCommonHeaderParameters(req, authInfo); _ACTSetDeviceParameters(req, authInfo); _ACTSetRegionAndCountryParameters(req, authInfo); @@ -374,21 +390,21 @@ namespace NAPI result.nexToken.port = (uint16)StringHelpers::ToInt(port); result.apiError = NAPI_RESULT::SUCCESS; g_nexTokenCacheMtx.lock(); - g_nexTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, serverId, result.nexToken); + g_nexTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, authInfo.GetService(), serverId, result.nexToken); g_nexTokenCacheMtx.unlock(); return result; } struct IndependentTokenCacheEntry { - IndependentTokenCacheEntry(std::string_view accountId, std::array& passwordHash, std::string_view clientId, std::string_view independentToken, sint64 expiresIn) : accountId(accountId), passwordHash(passwordHash), clientId(clientId), independentToken(independentToken) + IndependentTokenCacheEntry(std::string_view accountId, std::array& passwordHash, NetworkService networkService, std::string_view clientId, std::string_view independentToken, sint64 expiresIn) : accountId(accountId), passwordHash(passwordHash), networkService(networkService), clientId(clientId), independentToken(independentToken) { expires = HighResolutionTimer::now().getTickInSeconds() + expiresIn; }; bool IsMatch(const AuthInfo& authInfo, const std::string_view clientId) const { - return authInfo.accountId == accountId && authInfo.passwordHash == passwordHash && this->clientId == clientId; + return authInfo.accountId == accountId && authInfo.passwordHash == passwordHash && authInfo.GetService() == networkService && this->clientId == clientId; } bool CheckIfExpired() const @@ -398,6 +414,7 @@ namespace NAPI std::string accountId; std::array passwordHash; + NetworkService networkService; std::string clientId; sint64 expires; @@ -449,7 +466,7 @@ namespace NAPI } // do request CurlRequestHelper req; - req.initate(fmt::format("{}/v1/api/provider/service_token/@me?client_id={}", LaunchSettings::GetActURLPrefix(), clientId), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT); + req.initate(authInfo.GetService(), fmt::format("{}/v1/api/provider/service_token/@me?client_id={}", _getACTUrl(authInfo.GetService()), clientId), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT); _ACTSetCommonHeaderParameters(req, authInfo); _ACTSetDeviceParameters(req, authInfo); _ACTSetRegionAndCountryParameters(req, authInfo); @@ -494,7 +511,7 @@ namespace NAPI result.apiError = NAPI_RESULT::SUCCESS; g_IndependentTokenCacheMtx.lock(); - g_IndependentTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, clientId, result.token, 3600); + g_IndependentTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, authInfo.GetService(), clientId, result.token, 3600); g_IndependentTokenCacheMtx.unlock(); return result; } @@ -520,7 +537,7 @@ namespace NAPI } // do request CurlRequestHelper req; - req.initate(fmt::format("{}/v1/api/admin/mapped_ids?input_type=user_id&output_type=pid&input={}", LaunchSettings::GetActURLPrefix(), nnid), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT); + req.initate(authInfo.GetService(), fmt::format("{}/v1/api/admin/mapped_ids?input_type=user_id&output_type=pid&input={}", _getACTUrl(authInfo.GetService()), nnid), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT); _ACTSetCommonHeaderParameters(req, authInfo); _ACTSetDeviceParameters(req, authInfo); _ACTSetRegionAndCountryParameters(req, authInfo); diff --git a/src/Cemu/napi/napi_ec.cpp b/src/Cemu/napi/napi_ec.cpp index 9bc4bfbfb..2c0812e42 100644 --- a/src/Cemu/napi/napi_ec.cpp +++ b/src/Cemu/napi/napi_ec.cpp @@ -16,103 +16,112 @@ namespace NAPI { /* Service URL manager */ - std::string s_serviceURL_ContentPrefixURL; - std::string s_serviceURL_UncachedContentPrefixURL; - std::string s_serviceURL_EcsURL; - std::string s_serviceURL_IasURL; - std::string s_serviceURL_CasURL; - std::string s_serviceURL_NusURL; - - std::string _getNUSUrl() + struct CachedServiceUrls { - if (!s_serviceURL_NusURL.empty()) - return s_serviceURL_NusURL; - switch (ActiveSettings::GetNetworkService()) - { - case NetworkService::Nintendo: - return NintendoURLs::NUSURL; - break; - case NetworkService::Pretendo: - return PretendoURLs::NUSURL; - break; - case NetworkService::Custom: - return GetNetworkConfig().urls.NUS; - break; - default: - return NintendoURLs::NUSURL; - break; - } + std::string s_serviceURL_ContentPrefixURL; + std::string s_serviceURL_UncachedContentPrefixURL; + std::string s_serviceURL_EcsURL; + std::string s_serviceURL_IasURL; + std::string s_serviceURL_CasURL; + std::string s_serviceURL_NusURL; + }; + + std::unordered_map s_cachedServiceUrlsMap; + + CachedServiceUrls& GetCachedServiceUrls(NetworkService service) + { + return s_cachedServiceUrlsMap[service]; } - std::string _getIASUrl() + std::string _getNUSUrl(NetworkService service) { - if (!s_serviceURL_IasURL.empty()) - return s_serviceURL_IasURL; - switch (ActiveSettings::GetNetworkService()) - { - case NetworkService::Nintendo: - return NintendoURLs::IASURL; - break; - case NetworkService::Pretendo: - return PretendoURLs::IASURL; - break; - case NetworkService::Custom: - return GetNetworkConfig().urls.IAS; - break; - default: - return NintendoURLs::IASURL; - break; - } + auto& cachedServiceUrls = GetCachedServiceUrls(service); + if (!cachedServiceUrls.s_serviceURL_NusURL.empty()) + return cachedServiceUrls.s_serviceURL_NusURL; + switch (service) + { + case NetworkService::Nintendo: + return NintendoURLs::NUSURL; + case NetworkService::Pretendo: + return PretendoURLs::NUSURL; + case NetworkService::Custom: + return GetNetworkConfig().urls.NUS; + default: + return NintendoURLs::NUSURL; + } } - std::string _getECSUrl() + std::string _getIASUrl(NetworkService service) + { + auto& cachedServiceUrls = GetCachedServiceUrls(service); + if (!cachedServiceUrls.s_serviceURL_IasURL.empty()) + return cachedServiceUrls.s_serviceURL_IasURL; + switch (service) + { + case NetworkService::Nintendo: + return NintendoURLs::IASURL; + case NetworkService::Pretendo: + return PretendoURLs::IASURL; + case NetworkService::Custom: + return GetNetworkConfig().urls.IAS; + default: + return NintendoURLs::IASURL; + } + } + + std::string _getECSUrl(NetworkService service) { // this is the first url queried (GetAccountStatus). The others are dynamically set if provided by the server but will fallback to hardcoded defaults otherwise - if (!s_serviceURL_EcsURL.empty()) - return s_serviceURL_EcsURL; - return LaunchSettings::GetServiceURL_ecs(); // by default this is "https://ecs.wup.shop.nintendo.net/ecs/services/ECommerceSOAP" + auto& cachedServiceUrls = GetCachedServiceUrls(service); + if (!cachedServiceUrls.s_serviceURL_EcsURL.empty()) + return cachedServiceUrls.s_serviceURL_EcsURL; + switch (service) + { + case NetworkService::Nintendo: + return NintendoURLs::ECSURL; + case NetworkService::Pretendo: + return PretendoURLs::ECSURL; + case NetworkService::Custom: + return GetNetworkConfig().urls.ECS; + default: + return NintendoURLs::ECSURL; + } } - std::string _getCCSUncachedUrl() // used for TMD requests + std::string _getCCSUncachedUrl(NetworkService service) // used for TMD requests { - if (!s_serviceURL_UncachedContentPrefixURL.empty()) - return s_serviceURL_UncachedContentPrefixURL; - switch (ActiveSettings::GetNetworkService()) - { - case NetworkService::Nintendo: - return NintendoURLs::CCSUURL; - break; - case NetworkService::Pretendo: - return PretendoURLs::CCSUURL; - break; - case NetworkService::Custom: - return GetNetworkConfig().urls.CCSU; - break; - default: - return NintendoURLs::CCSUURL; - break; - } + auto& cachedServiceUrls = GetCachedServiceUrls(service); + if (!cachedServiceUrls.s_serviceURL_UncachedContentPrefixURL.empty()) + return cachedServiceUrls.s_serviceURL_UncachedContentPrefixURL; + switch (service) + { + case NetworkService::Nintendo: + return NintendoURLs::CCSUURL; + case NetworkService::Pretendo: + return PretendoURLs::CCSUURL; + case NetworkService::Custom: + return GetNetworkConfig().urls.CCSU; + default: + return NintendoURLs::CCSUURL; + } } - std::string _getCCSUrl() // used for game data downloads + std::string _getCCSUrl(NetworkService service) // used for game data downloads { - if (!s_serviceURL_ContentPrefixURL.empty()) - return s_serviceURL_ContentPrefixURL; - switch (ActiveSettings::GetNetworkService()) - { - case NetworkService::Nintendo: - return NintendoURLs::CCSURL; - break; - case NetworkService::Pretendo: - return PretendoURLs::CCSURL; - break; - case NetworkService::Custom: - return GetNetworkConfig().urls.CCS; - break; - default: - return NintendoURLs::CCSURL; - break; - } + auto& cachedServiceUrls = GetCachedServiceUrls(service); + if (!cachedServiceUrls.s_serviceURL_ContentPrefixURL.empty()) + return cachedServiceUrls.s_serviceURL_ContentPrefixURL; + switch (service) + { + case NetworkService::Nintendo: + return NintendoURLs::CCSURL; + case NetworkService::Pretendo: + return PretendoURLs::CCSURL; + case NetworkService::Custom: + return GetNetworkConfig().urls.CCS; + default: + return NintendoURLs::CCSURL; + } } /* NUS */ @@ -122,8 +131,8 @@ namespace NAPI { NAPI_NUSGetSystemCommonETicket_Result result{}; - CurlSOAPHelper soapHelper; - soapHelper.SOAP_initate("nus", _getNUSUrl(), "GetSystemCommonETicket", "1.0"); + CurlSOAPHelper soapHelper(authInfo.GetService()); + soapHelper.SOAP_initate("nus", _getNUSUrl(authInfo.GetService()), "GetSystemCommonETicket", "1.0"); soapHelper.SOAP_addRequestField("DeviceId", fmt::format("{}", authInfo.getDeviceIdWithPlatform())); soapHelper.SOAP_addRequestField("RegionId", NCrypto::GetRegionAsString(authInfo.region)); @@ -175,8 +184,8 @@ namespace NAPI { NAPI_IASGetChallenge_Result result{}; - CurlSOAPHelper soapHelper; - soapHelper.SOAP_initate("ias", _getIASUrl(), "GetChallenge", "2.0"); + CurlSOAPHelper soapHelper(authInfo.GetService()); + soapHelper.SOAP_initate("ias", _getIASUrl(authInfo.GetService()), "GetChallenge", "2.0"); soapHelper.SOAP_addRequestField("DeviceId", fmt::format("{}", authInfo.getDeviceIdWithPlatform())); // not validated but the generated Challenge is bound to this DeviceId soapHelper.SOAP_addRequestField("Region", NCrypto::GetRegionAsString(authInfo.region)); @@ -200,8 +209,8 @@ namespace NAPI NAPI_IASGetRegistrationInfo_Result IAS_GetRegistrationInfo_QueryInfo(AuthInfo& authInfo, std::string challenge) { NAPI_IASGetRegistrationInfo_Result result; - CurlSOAPHelper soapHelper; - soapHelper.SOAP_initate("ias", _getIASUrl(), "GetRegistrationInfo", "2.0"); + CurlSOAPHelper soapHelper(authInfo.GetService()); + soapHelper.SOAP_initate("ias", _getIASUrl(authInfo.GetService()), "GetRegistrationInfo", "2.0"); soapHelper.SOAP_addRequestField("DeviceId", fmt::format("{}", authInfo.getDeviceIdWithPlatform())); // this must match the DeviceId used to generate Challenge soapHelper.SOAP_addRequestField("Region", NCrypto::GetRegionAsString(authInfo.region)); @@ -301,8 +310,8 @@ namespace NAPI { NAPI_ECSGetAccountStatus_Result result{}; - CurlSOAPHelper soapHelper; - soapHelper.SOAP_initate("ecs", _getECSUrl(), "GetAccountStatus", "2.0"); + CurlSOAPHelper soapHelper(authInfo.GetService()); + soapHelper.SOAP_initate("ecs", _getECSUrl(authInfo.GetService()), "GetAccountStatus", "2.0"); soapHelper.SOAP_addRequestField("DeviceId", fmt::format("{}", authInfo.getDeviceIdWithPlatform())); soapHelper.SOAP_addRequestField("Region", NCrypto::GetRegionAsString(authInfo.region)); @@ -367,19 +376,19 @@ namespace NAPI } // assign service URLs + auto& cachedServiceUrls = GetCachedServiceUrls(authInfo.GetService()); if (!result.serviceURLs.ContentPrefixURL.empty()) - s_serviceURL_ContentPrefixURL = result.serviceURLs.ContentPrefixURL; + cachedServiceUrls.s_serviceURL_ContentPrefixURL = result.serviceURLs.ContentPrefixURL; if (!result.serviceURLs.UncachedContentPrefixURL.empty()) - s_serviceURL_UncachedContentPrefixURL = result.serviceURLs.UncachedContentPrefixURL; + cachedServiceUrls.s_serviceURL_UncachedContentPrefixURL = result.serviceURLs.UncachedContentPrefixURL; if (!result.serviceURLs.IasURL.empty()) - s_serviceURL_IasURL = result.serviceURLs.IasURL; + cachedServiceUrls.s_serviceURL_IasURL = result.serviceURLs.IasURL; if (!result.serviceURLs.CasURL.empty()) - s_serviceURL_CasURL = result.serviceURLs.CasURL; + cachedServiceUrls.s_serviceURL_CasURL = result.serviceURLs.CasURL; if (!result.serviceURLs.NusURL.empty()) - s_serviceURL_NusURL = result.serviceURLs.NusURL; + cachedServiceUrls.s_serviceURL_NusURL = result.serviceURLs.NusURL; if (!result.serviceURLs.EcsURL.empty()) - s_serviceURL_EcsURL = result.serviceURLs.EcsURL; - + cachedServiceUrls.s_serviceURL_EcsURL = result.serviceURLs.EcsURL; return result; } @@ -387,8 +396,8 @@ namespace NAPI { NAPI_ECSAccountListETicketIds_Result result{}; - CurlSOAPHelper soapHelper; - soapHelper.SOAP_initate("ecs", _getECSUrl(), "AccountListETicketIds", "2.0"); + CurlSOAPHelper soapHelper(authInfo.GetService()); + soapHelper.SOAP_initate("ecs", _getECSUrl(authInfo.GetService()), "AccountListETicketIds", "2.0"); soapHelper.SOAP_addRequestField("DeviceId", fmt::format("{}", authInfo.getDeviceIdWithPlatform())); soapHelper.SOAP_addRequestField("Region", NCrypto::GetRegionAsString(authInfo.region)); @@ -446,8 +455,8 @@ namespace NAPI { NAPI_ECSAccountGetETickets_Result result{}; - CurlSOAPHelper soapHelper; - soapHelper.SOAP_initate("ecs", _getECSUrl(), "AccountGetETickets", "2.0"); + CurlSOAPHelper soapHelper(authInfo.GetService()); + soapHelper.SOAP_initate("ecs", _getECSUrl(authInfo.GetService()), "AccountGetETickets", "2.0"); soapHelper.SOAP_addRequestField("DeviceId", fmt::format("{}", authInfo.getDeviceIdWithPlatform())); soapHelper.SOAP_addRequestField("Region", NCrypto::GetRegionAsString(authInfo.region)); @@ -512,7 +521,7 @@ namespace NAPI { NAPI_CCSGetTMD_Result result{}; CurlRequestHelper req; - req.initate(fmt::format("{}/{:016x}/tmd.{}?deviceId={}&accountId={}", _getCCSUncachedUrl(), titleId, titleVersion, authInfo.getDeviceIdWithPlatform(), authInfo.IASToken.accountId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS); + req.initate(authInfo.GetService(), fmt::format("{}/{:016x}/tmd.{}?deviceId={}&accountId={}", _getCCSUncachedUrl(authInfo.GetService()), titleId, titleVersion, authInfo.getDeviceIdWithPlatform(), authInfo.IASToken.accountId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS); req.setTimeout(180); if (!req.submitRequest(false)) { @@ -528,7 +537,7 @@ namespace NAPI { NAPI_CCSGetTMD_Result result{}; CurlRequestHelper req; - req.initate(fmt::format("{}/{:016x}/tmd?deviceId={}&accountId={}", _getCCSUncachedUrl(), titleId, authInfo.getDeviceIdWithPlatform(), authInfo.IASToken.accountId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS); + req.initate(authInfo.GetService(), fmt::format("{}/{:016x}/tmd?deviceId={}&accountId={}", _getCCSUncachedUrl(authInfo.GetService()), titleId, authInfo.getDeviceIdWithPlatform(), authInfo.IASToken.accountId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS); req.setTimeout(180); if (!req.submitRequest(false)) { @@ -540,11 +549,11 @@ namespace NAPI return result; } - NAPI_CCSGetETicket_Result CCS_GetCETK(AuthInfo& authInfo, uint64 titleId, uint16 titleVersion) + NAPI_CCSGetETicket_Result CCS_GetCETK(NetworkService service, uint64 titleId, uint16 titleVersion) { NAPI_CCSGetETicket_Result result{}; CurlRequestHelper req; - req.initate(fmt::format("{}/{:016x}/cetk", _getCCSUncachedUrl(), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS); + req.initate(service, fmt::format("{}/{:016x}/cetk", _getCCSUncachedUrl(service), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS); req.setTimeout(180); if (!req.submitRequest(false)) { @@ -556,10 +565,10 @@ namespace NAPI return result; } - bool CCS_GetContentFile(uint64 titleId, uint32 contentId, bool(*cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast), void* userData) + bool CCS_GetContentFile(NetworkService service, uint64 titleId, uint32 contentId, bool(*cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast), void* userData) { CurlRequestHelper req; - req.initate(fmt::format("{}/{:016x}/{:08x}", _getCCSUrl(), titleId, contentId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS); + req.initate(service, fmt::format("{}/{:016x}/{:08x}", _getCCSUrl(service), titleId, contentId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS); req.setWriteCallback(cbWriteCallback, userData); req.setTimeout(0); if (!req.submitRequest(false)) @@ -570,11 +579,11 @@ namespace NAPI return true; } - NAPI_CCSGetContentH3_Result CCS_GetContentH3File(uint64 titleId, uint32 contentId) + NAPI_CCSGetContentH3_Result CCS_GetContentH3File(NetworkService service, uint64 titleId, uint32 contentId) { NAPI_CCSGetContentH3_Result result{}; CurlRequestHelper req; - req.initate(fmt::format("{}/{:016x}/{:08x}.h3", _getCCSUrl(), titleId, contentId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS); + req.initate(service, fmt::format("{}/{:016x}/{:08x}.h3", _getCCSUrl(service), titleId, contentId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS); if (!req.submitRequest(false)) { cemuLog_log(LogType::Force, fmt::format("Failed to request content hash file {:08x}.h3 for title {:016X}", contentId, titleId)); diff --git a/src/Cemu/napi/napi_helper.cpp b/src/Cemu/napi/napi_helper.cpp index 776baf339..e498d07ff 100644 --- a/src/Cemu/napi/napi_helper.cpp +++ b/src/Cemu/napi/napi_helper.cpp @@ -119,7 +119,7 @@ CurlRequestHelper::~CurlRequestHelper() curl_easy_cleanup(m_curl); } -void CurlRequestHelper::initate(std::string url, SERVER_SSL_CONTEXT sslContext) +void CurlRequestHelper::initate(NetworkService service, std::string url, SERVER_SSL_CONTEXT sslContext) { // reset parameters m_headerExtraFields.clear(); @@ -131,8 +131,10 @@ void CurlRequestHelper::initate(std::string url, SERVER_SSL_CONTEXT sslContext) curl_easy_setopt(m_curl, CURLOPT_TIMEOUT, 60); // SSL - if (GetNetworkConfig().disablesslver.GetValue() && ActiveSettings::GetNetworkService() == NetworkService::Custom || ActiveSettings::GetNetworkService() == NetworkService::Pretendo){ //Remove once Pretendo has SSL - curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 1L); + if (IsNetworkServiceSSLDisabled(service)) + { + curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L); } else if (sslContext == SERVER_SSL_CONTEXT::ACT || sslContext == SERVER_SSL_CONTEXT::TAGAYA) { @@ -256,18 +258,24 @@ bool CurlRequestHelper::submitRequest(bool isPost) return true; } -CurlSOAPHelper::CurlSOAPHelper() +CurlSOAPHelper::CurlSOAPHelper(NetworkService service) { m_curl = curl_easy_init(); curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, __curlWriteCallback); curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, this); // SSL - if (!GetNetworkConfig().disablesslver.GetValue() && ActiveSettings::GetNetworkService() != NetworkService::Pretendo && ActiveSettings::GetNetworkService() != NetworkService::Custom) { //Remove once Pretendo has SSL - curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_SOAP); - curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, NULL); + if (!IsNetworkServiceSSLDisabled(service)) + { + curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_SOAP); + curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, NULL); + curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 1L); } - if(GetConfig().proxy_server.GetValue() != "") + else + { + curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L); + } + if (GetConfig().proxy_server.GetValue() != "") { curl_easy_setopt(m_curl, CURLOPT_PROXY, GetConfig().proxy_server.GetValue().c_str()); } diff --git a/src/Cemu/napi/napi_helper.h b/src/Cemu/napi/napi_helper.h index 6403f074d..adfe73939 100644 --- a/src/Cemu/napi/napi_helper.h +++ b/src/Cemu/napi/napi_helper.h @@ -38,7 +38,7 @@ class CurlRequestHelper return m_curl; } - void initate(std::string url, SERVER_SSL_CONTEXT sslContext); + void initate(NetworkService service, std::string url, SERVER_SSL_CONTEXT sslContext); void addHeaderField(const char* fieldName, std::string_view value); void addPostField(const char* fieldName, std::string_view value); void setWriteCallback(bool(*cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast), void* userData); @@ -74,7 +74,7 @@ class CurlRequestHelper class CurlSOAPHelper // todo - make this use CurlRequestHelper { public: - CurlSOAPHelper(); + CurlSOAPHelper(NetworkService service); ~CurlSOAPHelper(); CURL* getCURL() diff --git a/src/Cemu/napi/napi_idbe.cpp b/src/Cemu/napi/napi_idbe.cpp index acf7799c0..db7fda20c 100644 --- a/src/Cemu/napi/napi_idbe.cpp +++ b/src/Cemu/napi/napi_idbe.cpp @@ -54,11 +54,11 @@ namespace NAPI AES128_CBC_decrypt((uint8*)iconData, (uint8*)iconData, sizeof(IDBEIconDataV0), aesKey, iv); } - std::vector IDBE_RequestRawEncrypted(uint64 titleId) + std::vector IDBE_RequestRawEncrypted(NetworkService networkService, uint64 titleId) { CurlRequestHelper req; std::string requestUrl; - switch (ActiveSettings::GetNetworkService()) + switch (networkService) { case NetworkService::Pretendo: requestUrl = PretendoURLs::IDBEURL; @@ -72,7 +72,7 @@ namespace NAPI break; } requestUrl.append(fmt::format(fmt::runtime("/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId)); - req.initate(requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); + req.initate(networkService, requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); if (!req.submitRequest(false)) { @@ -90,7 +90,7 @@ namespace NAPI return receivedData; } - std::optional IDBE_Request(uint64 titleId) + std::optional IDBE_Request(NetworkService networkService, uint64 titleId) { if (titleId == 0x000500301001500A || titleId == 0x000500301001510A || @@ -101,7 +101,7 @@ namespace NAPI return std::nullopt; } - std::vector idbeData = IDBE_RequestRawEncrypted(titleId); + std::vector idbeData = IDBE_RequestRawEncrypted(networkService, titleId); if (idbeData.size() < 0x22) return std::nullopt; if (idbeData[0] != 0) diff --git a/src/Cemu/napi/napi_version.cpp b/src/Cemu/napi/napi_version.cpp index 9fc71556a..a1f5879c4 100644 --- a/src/Cemu/napi/napi_version.cpp +++ b/src/Cemu/napi/napi_version.cpp @@ -18,7 +18,7 @@ namespace NAPI CurlRequestHelper req; std::string requestUrl; - switch (ActiveSettings::GetNetworkService()) + switch (authInfo.GetService()) { case NetworkService::Pretendo: requestUrl = PretendoURLs::TAGAYAURL; @@ -32,7 +32,7 @@ namespace NAPI break; } requestUrl.append(fmt::format(fmt::runtime("/{}/{}/latest_version"), NCrypto::GetRegionAsString(authInfo.region), authInfo.country)); - req.initate(requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); + req.initate(authInfo.GetService(), requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); if (!req.submitRequest(false)) { @@ -63,7 +63,7 @@ namespace NAPI { NAPI_VersionList_Result result; CurlRequestHelper req; - req.initate(fmt::format("https://{}/tagaya/versionlist/{}/{}/list/{}.versionlist", fqdnURL, NCrypto::GetRegionAsString(authInfo.region), authInfo.country, versionListVersion), CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); + req.initate(authInfo.GetService(), fmt::format("https://{}/tagaya/versionlist/{}/{}/list/{}.versionlist", fqdnURL, NCrypto::GetRegionAsString(authInfo.region), authInfo.country, versionListVersion), CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); if (!req.submitRequest(false)) { cemuLog_log(LogType::Force, fmt::format("Failed to request update list")); diff --git a/src/Cemu/ncrypto/ncrypto.cpp b/src/Cemu/ncrypto/ncrypto.cpp index 8a989d2cf..bbda681ff 100644 --- a/src/Cemu/ncrypto/ncrypto.cpp +++ b/src/Cemu/ncrypto/ncrypto.cpp @@ -20,7 +20,8 @@ void iosuCrypto_readOtpData(void* output, sint32 wordIndex, sint32 size); void iosuCrypto_readSeepromData(void* output, sint32 wordIndex, sint32 size); -extern bool hasSeepromMem; // remove later +extern bool hasSeepromMem; // remove later (migrate otp/seeprom loading & parsing to this class) +extern bool hasOtpMem; // remove later namespace NCrypto { @@ -792,6 +793,16 @@ namespace NCrypto return (CafeConsoleRegion)seepromRegionU32[3]; } + bool OTP_IsPresent() + { + return hasOtpMem; + } + + bool HasDataForConsoleCert() + { + return SEEPROM_IsPresent() && OTP_IsPresent(); + } + std::string GetRegionAsString(CafeConsoleRegion regionCode) { if (regionCode == CafeConsoleRegion::EUR) @@ -957,6 +968,11 @@ namespace NCrypto return it->second; } + size_t GetCountryCount() + { + return g_countryTable.size(); + } + void unitTests() { base64Tests(); diff --git a/src/Cemu/ncrypto/ncrypto.h b/src/Cemu/ncrypto/ncrypto.h index 51f3d9cb4..5f399ad78 100644 --- a/src/Cemu/ncrypto/ncrypto.h +++ b/src/Cemu/ncrypto/ncrypto.h @@ -205,7 +205,11 @@ namespace NCrypto CafeConsoleRegion SEEPROM_GetRegion(); std::string GetRegionAsString(CafeConsoleRegion regionCode); const char* GetCountryAsString(sint32 index); // returns NN if index is not valid or known + size_t GetCountryCount(); bool SEEPROM_IsPresent(); + bool OTP_IsPresent(); + + bool HasDataForConsoleCert(); void unitTests(); } \ No newline at end of file diff --git a/src/config/ActiveSettings.cpp b/src/config/ActiveSettings.cpp index 2049bd650..81662ab5a 100644 --- a/src/config/ActiveSettings.cpp +++ b/src/config/ActiveSettings.cpp @@ -39,7 +39,6 @@ ActiveSettings::LoadOnce( g_config.SetFilename(GetConfigPath("settings.xml").generic_wstring()); g_config.Load(); - LaunchSettings::ChangeNetworkServiceURL(GetConfig().account.active_service); std::string additionalErrorInfo; s_has_required_online_files = iosuCrypt_checkRequirementsForOnlineMode(additionalErrorInfo) == IOS_CRYPTO_ONLINE_REQ_OK; return failed_write_access; diff --git a/src/config/LaunchSettings.cpp b/src/config/LaunchSettings.cpp index b7a79a11f..1731f5004 100644 --- a/src/config/LaunchSettings.cpp +++ b/src/config/LaunchSettings.cpp @@ -69,11 +69,7 @@ bool LaunchSettings::HandleCommandline(const std::vector& args) ("account,a", po::value(), "Persistent id of account") ("force-interpreter", po::value()->implicit_value(true), "Force interpreter CPU emulation, disables recompiler") - ("enable-gdbstub", po::value()->implicit_value(true), "Enable GDB stub to debug executables inside Cemu using an external debugger") - - ("act-url", po::value(), "URL prefix for account server") - ("ecs-url", po::value(), "URL for ECS service"); - + ("enable-gdbstub", po::value()->implicit_value(true), "Enable GDB stub to debug executables inside Cemu using an external debugger"); po::options_description hidden{ "Hidden options" }; hidden.add_options() @@ -190,16 +186,6 @@ bool LaunchSettings::HandleCommandline(const std::vector& args) if (vm.count("output")) log_path = vm["output"].as(); - // urls - if (vm.count("act-url")) - { - serviceURL_ACT = vm["act-url"].as(); - if (serviceURL_ACT.size() > 0 && serviceURL_ACT.back() == '/') - serviceURL_ACT.pop_back(); - } - if (vm.count("ecs-url")) - serviceURL_ECS = vm["ecs-url"].as(); - if(!extract_path.empty()) { ExtractorTool(extract_path, output_path, log_path); @@ -280,24 +266,3 @@ bool LaunchSettings::ExtractorTool(std::wstring_view wud_path, std::string_view return true; } - - -void LaunchSettings::ChangeNetworkServiceURL(int ID){ - NetworkService Network = static_cast(ID); - switch (Network) - { - case NetworkService::Pretendo: - serviceURL_ACT = PretendoURLs::ACTURL; - serviceURL_ECS = PretendoURLs::ECSURL; - break; - case NetworkService::Custom: - serviceURL_ACT = GetNetworkConfig().urls.ACT.GetValue(); - serviceURL_ECS = GetNetworkConfig().urls.ECS.GetValue(); - break; - case NetworkService::Nintendo: - default: - serviceURL_ACT = NintendoURLs::ACTURL; - serviceURL_ECS = NintendoURLs::ECSURL; - break; - } -} diff --git a/src/config/LaunchSettings.h b/src/config/LaunchSettings.h index be989e6a5..b0f673a13 100644 --- a/src/config/LaunchSettings.h +++ b/src/config/LaunchSettings.h @@ -29,10 +29,6 @@ class LaunchSettings static std::optional GetPersistentId() { return s_persistent_id; } - static std::string GetActURLPrefix() { return serviceURL_ACT; } - static std::string GetServiceURL_ecs() { return serviceURL_ECS; } - static void ChangeNetworkServiceURL(int ID); - private: inline static std::optional s_load_game_file{}; inline static std::optional s_load_title_id{}; @@ -48,12 +44,6 @@ class LaunchSettings inline static std::optional s_persistent_id{}; - // service URLS - inline static std::string serviceURL_ACT; - inline static std::string serviceURL_ECS; - // todo - npts and other boss urls - - static bool ExtractorTool(std::wstring_view wud_path, std::string_view output_path, std::wstring_view log_path); }; diff --git a/src/config/NetworkSettings.cpp b/src/config/NetworkSettings.cpp index 5cc66a915..b086d0aec 100644 --- a/src/config/NetworkSettings.cpp +++ b/src/config/NetworkSettings.cpp @@ -30,8 +30,6 @@ void NetworkConfig::Load(XMLConfigParser& parser) urls.BOSS = u.get("boss", NintendoURLs::BOSSURL); urls.TAGAYA = u.get("tagaya", NintendoURLs::TAGAYAURL); urls.OLV = u.get("olv", NintendoURLs::OLVURL); - if (static_cast(GetConfig().account.active_service.GetValue()) == NetworkService::Custom) - LaunchSettings::ChangeNetworkServiceURL(2); } bool NetworkConfig::XMLExists() @@ -41,7 +39,6 @@ bool NetworkConfig::XMLExists() { if (static_cast(GetConfig().account.active_service.GetValue()) == NetworkService::Custom) { - LaunchSettings::ChangeNetworkServiceURL(0); GetConfig().account.active_service = 0; } return false; diff --git a/src/config/NetworkSettings.h b/src/config/NetworkSettings.h index 26137cdde..be311182b 100644 --- a/src/config/NetworkSettings.h +++ b/src/config/NetworkSettings.h @@ -3,13 +3,15 @@ #include "ConfigValue.h" #include "XMLConfig.h" - -enum class NetworkService { -Nintendo, -Pretendo, -Custom, +enum class NetworkService +{ + Nintendo, + Pretendo, + Custom }; -struct NetworkConfig { + +struct NetworkConfig +{ NetworkConfig() { @@ -69,4 +71,15 @@ struct PretendoURLs { typedef XMLDataConfig XMLNetworkConfig_t; extern XMLNetworkConfig_t n_config; -inline NetworkConfig& GetNetworkConfig() { return n_config.data();}; \ No newline at end of file +inline NetworkConfig& GetNetworkConfig() { return n_config.data();}; + +inline bool IsNetworkServiceSSLDisabled(NetworkService service) +{ + if(service == NetworkService::Nintendo) + return false; + else if(service == NetworkService::Pretendo) + return true; + else if(service == NetworkService::Custom) + return GetNetworkConfig().disablesslver.GetValue(); + return false; +} \ No newline at end of file diff --git a/src/gui/CemuApp.cpp b/src/gui/CemuApp.cpp index 7f11d4c68..505a09c69 100644 --- a/src/gui/CemuApp.cpp +++ b/src/gui/CemuApp.cpp @@ -332,7 +332,7 @@ void CemuApp::CreateDefaultFiles(bool first_start) if (!fs::exists(countryFile)) { std::ofstream file(countryFile); - for (sint32 i = 0; i < 201; i++) + for (sint32 i = 0; i < NCrypto::GetCountryCount(); i++) { const char* countryCode = NCrypto::GetCountryAsString(i); if (boost::iequals(countryCode, "NN")) diff --git a/src/gui/GeneralSettings2.cpp b/src/gui/GeneralSettings2.cpp index e33cfbf68..27ce37fa5 100644 --- a/src/gui/GeneralSettings2.cpp +++ b/src/gui/GeneralSettings2.cpp @@ -686,8 +686,10 @@ wxPanel* GeneralSettings2::AddAccountPage(wxNotebook* notebook) if (!NetworkConfig::XMLExists()) m_active_service->Enable(2, false); + m_active_service->SetItemToolTip(0, _("Connect to the official Nintendo Network Service")); + m_active_service->SetItemToolTip(1, _("Connect to the Pretendo Network Service")); + m_active_service->SetItemToolTip(2, _("Connect to a custom Network Service (configured via network_services.xml)")); - m_active_service->SetToolTip(_("Connect to which Network Service")); m_active_service->Bind(wxEVT_RADIOBOX, &GeneralSettings2::OnAccountServiceChanged,this); content->Add(m_active_service, 0, wxEXPAND | wxALL, 5); @@ -762,7 +764,7 @@ wxPanel* GeneralSettings2::AddAccountPage(wxNotebook* notebook) m_account_grid->Append(new wxStringProperty(_("Email"), kPropertyEmail)); wxPGChoices countries; - for (int i = 0; i < 195; ++i) + for (int i = 0; i < NCrypto::GetCountryCount(); ++i) { const auto country = NCrypto::GetCountryAsString(i); if (country && (i == 0 || !boost::equals(country, "NN"))) @@ -1948,8 +1950,6 @@ void GeneralSettings2::OnActiveAccountChanged(wxCommandEvent& event) void GeneralSettings2::OnAccountServiceChanged(wxCommandEvent& event) { - LaunchSettings::ChangeNetworkServiceURL(m_active_service->GetSelection()); - UpdateAccountInformation(); } diff --git a/src/gui/TitleManager.cpp b/src/gui/TitleManager.cpp index 669a1aaf9..00e7992f0 100644 --- a/src/gui/TitleManager.cpp +++ b/src/gui/TitleManager.cpp @@ -31,17 +31,15 @@ #include #include +#include "Cafe/IOSU/legacy/iosu_crypto.h" #include "config/ActiveSettings.h" #include "gui/dialogs/SaveImport/SaveImportWindow.h" #include "Cafe/Account/Account.h" #include "Cemu/Tools/DownloadManager/DownloadManager.h" #include "gui/CemuApp.h" - #include "Cafe/TitleList/TitleList.h" - -#include "resource/embedded/resources.h" - #include "Cafe/TitleList/SaveList.h" +#include "resource/embedded/resources.h" wxDEFINE_EVENT(wxEVT_TITLE_FOUND, wxCommandEvent); wxDEFINE_EVENT(wxEVT_TITLE_SEARCH_COMPLETE, wxCommandEvent); @@ -155,6 +153,7 @@ wxPanel* TitleManager::CreateDownloadManagerPage() { auto* row = new wxBoxSizer(wxHORIZONTAL); +#if DOWNLOADMGR_HAS_ACCOUNT_DROPDOWN m_account = new wxChoice(panel, wxID_ANY); m_account->SetMinSize({ 250,-1 }); auto accounts = Account::GetAccounts(); @@ -172,6 +171,7 @@ wxPanel* TitleManager::CreateDownloadManagerPage() } row->Add(m_account, 0, wxALL, 5); +#endif m_connect = new wxButton(panel, wxID_ANY, _("Connect")); m_connect->Bind(wxEVT_BUTTON, &TitleManager::OnConnect, this); @@ -180,7 +180,17 @@ wxPanel* TitleManager::CreateDownloadManagerPage() sizer->Add(row, 0, wxEXPAND, 5); } +#if DOWNLOADMGR_HAS_ACCOUNT_DROPDOWN m_status_text = new wxStaticText(panel, wxID_ANY, _("Select an account and press Connect")); +#else + if(!NCrypto::HasDataForConsoleCert()) + { + m_status_text = new wxStaticText(panel, wxID_ANY, _("Valid online files are required to download eShop titles. For more information, go to the Account tab in the General Settings.")); + m_connect->Enable(false); + } + else + m_status_text = new wxStaticText(panel, wxID_ANY, _("Click on Connect to load the list of downloadable titles")); +#endif this->Bind(wxEVT_SET_TEXT, &TitleManager::OnSetStatusText, this); sizer->Add(m_status_text, 0, wxALL, 5); @@ -720,9 +730,10 @@ void TitleManager::OnSaveImport(wxCommandEvent& event) void TitleManager::InitiateConnect() { // init connection to download manager if queued +#if DOWNLOADMGR_HAS_ACCOUNT_DROPDOWN uint32 persistentId = (uint32)(uintptr_t)m_account->GetClientData(m_account->GetSelection()); auto& account = Account::GetAccount(persistentId); - +#endif DownloadManager* dlMgr = DownloadManager::GetInstance(); dlMgr->reset(); m_download_list->SetCurrentDownloadMgr(dlMgr); @@ -742,7 +753,15 @@ void TitleManager::InitiateConnect() TitleManager::Callback_ConnectStatusUpdate, TitleManager::Callback_AddDownloadableTitle, TitleManager::Callback_RemoveDownloadableTitle); - dlMgr->connect(account.GetAccountId(), account.GetAccountPasswordCache(), NCrypto::SEEPROM_GetRegion(), NCrypto::GetCountryAsString(account.GetCountry()), NCrypto::GetDeviceId(), NCrypto::GetSerial(), deviceCertBase64); + std::string accountName; + std::array accountPassword; + std::string accountCountry; +#if DOWNLOADMGR_HAS_ACCOUNT_DROPDOWN + accountName = account.GetAccountId(); + accountPassword = account.GetAccountPasswordCache(); + accountCountry.assign(NCrypto::GetCountryAsString(account.GetCountry())); +#endif + dlMgr->connect(accountName, accountPassword, NCrypto::SEEPROM_GetRegion(), accountCountry, NCrypto::GetDeviceId(), NCrypto::GetSerial(), deviceCertBase64); } void TitleManager::OnConnect(wxCommandEvent& event) @@ -787,7 +806,9 @@ void TitleManager::OnDisconnect(wxCommandEvent& event) void TitleManager::SetConnected(bool state) { +#if DOWNLOADMGR_HAS_ACCOUNT_DROPDOWN m_account->Enable(!state); +#endif m_connect->Enable(!state); m_show_titles->Enable(state); diff --git a/src/gui/TitleManager.h b/src/gui/TitleManager.h index 2973618f8..ae284040d 100644 --- a/src/gui/TitleManager.h +++ b/src/gui/TitleManager.h @@ -8,6 +8,8 @@ #include "Cemu/Tools/DownloadManager/DownloadManager.h" +#define DOWNLOADMGR_HAS_ACCOUNT_DROPDOWN 0 + class wxCheckBox; class wxStaticText; class wxListEvent;