From 38abbd41d7b80354e040cc3a56a744a4dfe49fa6 Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Mon, 31 Jul 2023 18:01:40 +0200 Subject: [PATCH] Implement more http:c and GetServiceLocator --- src/core/hle/service/frd/frd.cpp | 153 ++++++++++++++++++++++++++- src/core/hle/service/frd/frd.h | 32 ++++++ src/core/hle/service/frd/frd_u.cpp | 4 +- src/core/hle/service/soc/soc_u.cpp | 2 +- src/network/network_clients/nasc.cpp | 71 +++++++++---- src/network/network_clients/nasc.h | 6 ++ 6 files changed, 239 insertions(+), 29 deletions(-) diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp index 924bb30ce6..d291148a5a 100644 --- a/src/core/hle/service/frd/frd.cpp +++ b/src/core/hle/service/frd/frd.cpp @@ -17,7 +17,7 @@ #include "core/hle/service/frd/frd_a.h" #include "core/hle/service/frd/frd_u.h" #include "core/hle/service/fs/fs_user.h" -#include "core/hle/service/http_c.h" +#include "core/hle/service/http/http_c.h" #include "network/network_clients/nasc.h" SERVICE_CONSTRUCT_IMPL(Service::FRD::Module) @@ -667,11 +667,11 @@ void Module::Interface::RequestGameAuthentication(Kernel::HLERequestContext& ctx nasc_client.SetParameter("action", std::string("LOGIN")); nasc_client.SetParameter("ingamesn", std::string("")); - LOG_INFO(Service_FRD, "Performing NASC request to: {}", nasc_url); + LOG_INFO(Service_FRD, "Performing NASC LOGIN request to: {}", nasc_url); NetworkClient::NASC::NASCClient::NASCResult nasc_result = nasc_client.Perform(); frd->last_game_auth_data.Init(); frd->last_game_auth_data.result = nasc_result.result; - if (nasc_result.result != 1) { + if (nasc_result.result >= 100) { LOG_ERROR(Service_FRD, "NASC Error: {}", nasc_result.log_message); if (nasc_result.result != 0) { frd->last_game_auth_data.http_status_code = nasc_result.http_status; @@ -700,6 +700,153 @@ void Module::Interface::GetGameAuthenticationData(Kernel::HLERequestContext& ctx rb.PushStaticBuffer(out_auth_data, 0); } +#pragma optimize("", off) +void Module::Interface::RequestServiceLocator(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + u32 gameID = rp.Pop(); + struct KeyHash { + u8 raw[0xC]; + }; + struct Svc { + u8 raw[0x8]; + }; + KeyHash key_hash = rp.PopRaw(); + Svc svc = rp.PopRaw(); + std::string key_hash_str(reinterpret_cast(&key_hash)); + std::string svc_str(reinterpret_cast(&svc)); + auto sdk_major = rp.Pop(); + auto sdk_minor = rp.Pop(); + auto processID = rp.PopPID(); + auto process = frd->system.Kernel().GetProcessById(processID); + auto event = rp.PopObject(); + + event->Signal(); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + + auto http_c = HTTP::GetService(frd->system); + + if (!http_c) { + LOG_ERROR(Service_FRD, "http:C module not found!"); + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Friends, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + auto clcert = http_c->GetClCertA(); + + if (!clcert.init) { + LOG_ERROR(Service_FRD, "ClCertA missing!"); + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Friends, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + if (frd->my_account_data.password[0] == '\0' || frd->my_account_data.pid_HMAC[0] == '\0') { + LOG_ERROR(Service_FRD, "no account data is present!"); + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Friends, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + auto fs_user = + Core::System::GetInstance().ServiceManager().GetService("fs:USER"); + Service::FS::FS_USER::ProductInfo product_info; + + if (!fs_user->GetProductInfo(processID, product_info)) { + LOG_ERROR(Service_FRD, "no game product info is available!"); + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Friends, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + std::string nasc_url = + std::string(reinterpret_cast(frd->my_account_data.nasc_url.data())); + NetworkClient::NASC::NASCClient nasc_client(nasc_url, clcert.certificate, clcert.private_key); + nasc_client.SetParameter("gameid", fmt::format("{:08X}", gameID)); + nasc_client.SetParameter("sdkver", fmt::format("{:03d}{:03d}", (u8)sdk_major, (u8)sdk_minor)); + nasc_client.SetParameter("titleid", fmt::format("{:016X}", process->codeset->program_id)); + nasc_client.SetParameter( + "gamecd", std::string(reinterpret_cast(product_info.product_code.data() + 6))); + nasc_client.SetParameter("gamever", fmt::format("{:04X}", product_info.remaster_version)); + nasc_client.SetParameter("mediatype", 1); + char makercd[3]; + makercd[0] = (product_info.maker_code >> 8); + makercd[1] = (product_info.maker_code & 0xFF); + makercd[2] = '\0'; + nasc_client.SetParameter("makercd", std::string(makercd)); + nasc_client.SetParameter("unitcd", (int)frd->my_account_data.my_profile.platform); + const u8* mac = frd->my_account_data.mac_address.data(); + nasc_client.SetParameter("macadr", fmt::format("{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}", mac[0], + mac[1], mac[2], mac[3], mac[4], mac[5])); + nasc_client.SetParameter("bssid", std::string("000000000000")); + nasc_client.SetParameter("apinfo", std::string("01:0000000000")); + + { + time_t raw_time; + struct tm* time_info; + char time_buffer[80]; + + time(&raw_time); + time_info = localtime(&raw_time); + + strftime(time_buffer, sizeof(time_buffer), "%y%m%d%H%M%S", time_info); + nasc_client.SetParameter("devtime", std::string(time_buffer)); + } + + std::vector device_cert(sizeof(frd->my_account_data.device_cert)); + memcpy(device_cert.data(), frd->my_account_data.device_cert.data(), device_cert.size()); + nasc_client.SetParameter("fcdcert", device_cert); + auto device_name = Common::UTF16ToUTF8( + reinterpret_cast(frd->my_account_data.device_name.user_name.data())); + nasc_client.SetParameter("devname", device_name); + nasc_client.SetParameter("servertype", std::string("L1")); + nasc_client.SetParameter("fpdver", fmt::format("{:04X}", Module::fpd_version)); + nasc_client.SetParameter("lang", + fmt::format("{:02X}", frd->my_account_data.my_profile.language)); + nasc_client.SetParameter("region", + fmt::format("{:02X}", frd->my_account_data.my_profile.region)); + nasc_client.SetParameter("csnum", std::string(frd->my_account_data.serial_number.data())); + nasc_client.SetParameter("uidhmac", std::string(frd->my_account_data.pid_HMAC.data())); + nasc_client.SetParameter("userid", (int)frd->my_account_data.my_key.friend_id); + nasc_client.SetParameter("action", std::string("SVCLOC")); + nasc_client.SetParameter("keyhash", key_hash_str); + nasc_client.SetParameter("svc", svc_str); + + LOG_INFO(Service_FRD, "Performing NASC SVCLOC request to: {}", nasc_url); + NetworkClient::NASC::NASCClient::NASCResult nasc_result = nasc_client.Perform(); + frd->last_service_locator_data.Init(); + frd->last_service_locator_data.result = nasc_result.result; + if (nasc_result.result >= 100) { + LOG_ERROR(Service_FRD, "NASC Error: {}", nasc_result.log_message); + if (nasc_result.result != 0) { + frd->last_service_locator_data.http_status_code = nasc_result.http_status; + } + } else { + frd->last_service_locator_data.http_status_code = nasc_result.http_status; + strncpy(frd->last_service_locator_data.service_token.data(), + nasc_result.service_token.c_str(), + sizeof(frd->last_service_locator_data.service_token) - 1); + strncpy(frd->last_service_locator_data.service_host.data(), + nasc_result.service_host.c_str(), + sizeof(frd->last_service_locator_data.service_host) - 1); + frd->last_service_locator_data.status = nasc_result.service_status; + frd->last_service_locator_data.server_time = nasc_result.time_stamp; + } + + rb.Push(RESULT_SUCCESS); +} +#pragma optimize("", on) + +void Module::Interface::GetServiceLocatorData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + + std::vector out_service_data(sizeof(ServiceLocatorData)); + memcpy(out_service_data.data(), &frd->last_service_locator_data, sizeof(ServiceLocatorData)); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushStaticBuffer(out_service_data, 0); +} + void Module::Interface::SetClientSdkVersion(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); u32 version = rp.Pop(); diff --git a/src/core/hle/service/frd/frd.h b/src/core/hle/service/frd/frd.h index f485c12f7f..ea89e1095c 100644 --- a/src/core/hle/service/frd/frd.h +++ b/src/core/hle/service/frd/frd.h @@ -149,6 +149,33 @@ private: friend class boost::serialization::access; }; +struct ServiceLocatorData { + s32_le result{}; + s32_le http_status_code{}; + std::array service_token{}; + u8 status; + std::array service_host{}; + std::array padding; + u64_le server_time{}; + + void Init() { + memset(this, 0, sizeof(*this)); + } + +private: + template + void serialize(Archive& ar, const unsigned int) { + ar& result; + ar& http_status_code; + ar& service_token; + ar& status; + ar& service_host; + ar& padding; + ar& server_time; + } + friend class boost::serialization::access; +}; + struct UserNameData { std::array user_name{}; u8 is_bad_word{}; @@ -483,6 +510,10 @@ public: void GetGameAuthenticationData(Kernel::HLERequestContext& ctx); + void RequestServiceLocator(Kernel::HLERequestContext& ctx); + + void GetServiceLocatorData(Kernel::HLERequestContext& ctx); + /** * FRD::SetClientSdkVersion service function * Inputs: @@ -499,6 +530,7 @@ public: private: AccountDataV1 my_account_data; GameAuthenticationData last_game_auth_data{}; + ServiceLocatorData last_service_locator_data{}; MyPresence my_presence{}; Core::System& system; diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp index 9262a1f0b8..7abf96d53e 100644 --- a/src/core/hle/service/frd/frd_u.cpp +++ b/src/core/hle/service/frd/frd_u.cpp @@ -52,8 +52,8 @@ FRD_U::FRD_U(std::shared_ptr frd) : Module::Interface(std::move(frd), "f {0x0027, nullptr, "ResultToErrorCode"}, {0x0028, &FRD_U::RequestGameAuthentication, "RequestGameAuthentication"}, {0x0029, &FRD_U::GetGameAuthenticationData, "GetGameAuthenticationData"}, - {0x002A, nullptr, "RequestServiceLocator"}, - {0x002B, nullptr, "GetServiceLocatorData"}, + {0x002A, &FRD_U::RequestServiceLocator, "RequestServiceLocator"}, + {0x002B, &FRD_U::GetServiceLocatorData, "GetServiceLocatorData"}, {0x002C, nullptr, "DetectNatProperties"}, {0x002D, nullptr, "GetNatProperties"}, {0x002E, nullptr, "GetServerTimeInterval"}, diff --git a/src/core/hle/service/soc/soc_u.cpp b/src/core/hle/service/soc/soc_u.cpp index 05e2bc194e..1b91fdaae9 100644 --- a/src/core/hle/service/soc/soc_u.cpp +++ b/src/core/hle/service/soc/soc_u.cpp @@ -18,7 +18,7 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/result.h" -#include "core/hle/service/soc_u.h" +#include "core/hle/service/soc/soc_u.h" #ifdef _WIN32 #include diff --git a/src/network/network_clients/nasc.cpp b/src/network/network_clients/nasc.cpp index 0129f595ec..72dbeaabbc 100644 --- a/src/network/network_clients/nasc.cpp +++ b/src/network/network_clients/nasc.cpp @@ -62,6 +62,8 @@ NASCClient::NASCResult NASCClient::Perform() { } std::string header_param; + std::string action; + GetParameter(parameters, "action", action); if (GetParameter(parameters, "gameid", header_param)) { request.set_header("X-GameId", header_param); @@ -110,36 +112,59 @@ NASCClient::NASCResult NASCClient::Perform() { } res.result = static_cast(nasc_result); - if (nasc_result != 1) { + if (nasc_result >= 100) { res.log_message = fmt::format("NASC login failed with code 002-{:04d}", nasc_result); return res; } - std::string locator; - if (!GetParameter(out_parameters, "locator", locator)) { - res.log_message = "NASC response missing \"locator\""; - return res; - } + if (action == "LOGIN") { + std::string locator; + if (!GetParameter(out_parameters, "locator", locator)) { + res.log_message = "NASC response missing \"locator\""; + return res; + } - auto delimiter = locator.find(":"); - if (delimiter == locator.npos) { - res.log_message = "NASC response \"locator\" missing port delimiter"; - return res; - } - res.server_address = locator.substr(0, delimiter); - std::string port_str = locator.substr(delimiter + 1); - try { - res.server_port = (u16)std::stoi(port_str); - } catch (std::exception) { - } + auto delimiter = locator.find(":"); + if (delimiter == locator.npos) { + res.log_message = "NASC response \"locator\" missing port delimiter"; + return res; + } + res.server_address = locator.substr(0, delimiter); + std::string port_str = locator.substr(delimiter + 1); + try { + res.server_port = (u16)std::stoi(port_str); + } catch (std::exception) { + } - auto token = out_parameters.find("token"); - if (token == out_parameters.end()) { - res.log_message = "NASC response missing \"locator\""; - return res; - } + auto token = out_parameters.find("token"); + if (token == out_parameters.end()) { + res.log_message = "NASC response missing \"locator\""; + return res; + } - res.auth_token = token->second; + res.auth_token = token->second; + } else if (action == "SVCLOC") { + auto token = out_parameters.find("servicetoken"); + if (token == out_parameters.end()) { + res.log_message = "NASC response missing \"servicetoken\""; + return res; + } + res.service_token = token->second; + + std::string status; + if (!GetParameter(out_parameters, "statusdata", status)) { + res.log_message = "NASC response missing \"statusdata\""; + return res; + } + res.service_status = status[0]; + + std::string svc_host; + if (!GetParameter(out_parameters, "svchost", svc_host)) { + res.log_message = "NASC response missing \"svchost\""; + return res; + } + res.service_host = svc_host; + } long long server_time; if (!GetParameter(out_parameters, "datetime", server_time)) { diff --git a/src/network/network_clients/nasc.h b/src/network/network_clients/nasc.h index c7c84e400a..db853f3a68 100644 --- a/src/network/network_clients/nasc.h +++ b/src/network/network_clients/nasc.h @@ -18,10 +18,16 @@ public: int http_status; std::string log_message; + // LOGIN std::string server_address; u16 server_port; std::string auth_token; u64 time_stamp; + + // SVCLOC + std::string service_token; + std::string service_host; + u8 service_status; }; NASCClient(const std::string& url, const std::vector& cert, const std::vector& key)