diff --git a/Minecraft.Client/AuthScreen.cpp b/Minecraft.Client/AuthScreen.cpp index c640f0da..0f0d3330 100644 --- a/Minecraft.Client/AuthScreen.cpp +++ b/Minecraft.Client/AuthScreen.cpp @@ -346,6 +346,7 @@ void AuthFlow::microsoftFlowThread() state = AuthFlowState::POLLING; string msAccessToken; string msRefreshToken; + const string pollBody = "client_id=" + string(MS_CLIENT_ID) + "&device_code=" + deviceCode + "&grant_type=urn:ietf:params:oauth:grant-type:device_code"; for (int attempt = 0; attempt < 180; attempt++) { @@ -357,7 +358,7 @@ void AuthFlow::microsoftFlowThread() auto pollResp = HttpClient::post( "https://login.live.com/oauth20_token.srf", - "client_id=" + string(MS_CLIENT_ID) + "&device_code=" + deviceCode + "&grant_type=urn:ietf:params:oauth:grant-type:device_code", + pollBody, "application/x-www-form-urlencoded" ); diff --git a/Minecraft.Client/ClientConnection.cpp b/Minecraft.Client/ClientConnection.cpp index c85e61b2..2765e921 100644 --- a/Minecraft.Client/ClientConnection.cpp +++ b/Minecraft.Client/ClientConnection.cpp @@ -55,7 +55,8 @@ #endif #include "DLCTexturePack.h" #include "..\Minecraft.World\HandshakeManager.h" -#include "..\Minecraft.World\AuthModule.h" +#include "..\Minecraft.World\SessionAuthModule.h" +#include "..\Minecraft.World\OfflineAuthModule.h" #include "AuthScreen.h" #ifdef _WINDOWS64 diff --git a/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp b/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp index 139f6b77..3d1febc3 100644 --- a/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp @@ -524,7 +524,7 @@ void UIScene_MainMenu::ShowAuthMenu(int iPad, void *pClass) s_authPad = iPad; s_authParam = pClass; - static const wchar_t *authOptions[] = { L"Next", L"Use", L"Add", L"Back" }; + static const wchar_t *authOptions[] = { L"Next", L"Use", L"Add", L"Remove" }; ShowAuthMessageBox(iPad, L"Authentication", BuildAuthProfileText(), authOptions, 4, &UIScene_MainMenu::AuthMenuReturned, pClass, true); } @@ -565,6 +565,16 @@ int UIScene_MainMenu::AuthMenuReturned(LPVOID lpParam, int iPad, const C4JStorag ShowAuthAddMenu(iPad, lpParam); break; } + case C4JStorage::EMessage_ResultFourthOption: + { + if (!profiles.empty()) + { + AuthProfileManager::removeSelectedProfile(); + if (auto *scene = ui.FindScene(eUIScene_MessageBox)) + static_cast(scene)->updateContent(BuildAuthProfileText()); + } + return 0; + } default: { ui.NavigateBack(iPad); diff --git a/Minecraft.Client/PendingConnection.cpp b/Minecraft.Client/PendingConnection.cpp index 090decd3..a85e3378 100644 --- a/Minecraft.Client/PendingConnection.cpp +++ b/Minecraft.Client/PendingConnection.cpp @@ -15,7 +15,8 @@ #include "..\Minecraft.World\SharedConstants.h" #include "Settings.h" #include "..\Minecraft.World\HandshakeManager.h" -#include "..\Minecraft.World\AuthModule.h" +#include "..\Minecraft.World\SessionAuthModule.h" +#include "..\Minecraft.World\OfflineAuthModule.h" #if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) #include "..\Minecraft.Server\ServerLogManager.h" #include "..\Minecraft.Server\Access\Access.h" diff --git a/Minecraft.World/AuthModule.cpp b/Minecraft.World/AuthModule.cpp index 45b11734..091a14db 100644 --- a/Minecraft.World/AuthModule.cpp +++ b/Minecraft.World/AuthModule.cpp @@ -1,18 +1,5 @@ #include "stdafx.h" #include "AuthModule.h" -#include "HttpClient.h" -#include "StringHelpers.h" -#include "Common/vendor/nlohmann/json.hpp" -#include - -static wstring generateServerId() -{ - static constexpr wchar_t hex[] = L"0123456789abcdef"; - static std::mt19937 rng(std::random_device{}()); - wstring id(16, L'0'); - for (auto &c : id) c = hex[rng() & 0xF]; - return id; -} bool AuthModule::validate(const wstring &uid, const wstring &username) { @@ -28,100 +15,3 @@ bool AuthModule::extractIdentity(const vector> &fields, w } return validate(outUid, outUsername); } - -SessionAuthModule::SessionAuthModule() -{ - endpoints[L"mojang"] = {L"https://authserver.mojang.com", L"https://sessionserver.mojang.com"}; - endpoints[L"elyby"] = {L"https://authserver.ely.by", L"https://authserver.ely.by"}; -} - -const wchar_t *SessionAuthModule::schemeName() { return L"mcconsoles:session"; } - -vector SessionAuthModule::supportedVariations() -{ - return {L"mojang", L"elyby"}; -} - -vector> SessionAuthModule::getSettings(const wstring &variation) -{ - auto it = endpoints.find(variation); - if (it == endpoints.end()) return {}; - - activeSessionEndpoint = it->second.sessionEndpoint; - activeServerId = generateServerId(); - - return { - {L"authEndpoint", it->second.authEndpoint}, - {L"sessionEndpoint", it->second.sessionEndpoint}, - {L"serverId", activeServerId} - }; -} - -bool SessionAuthModule::onAuthData(const vector> &fields, wstring &outUid, wstring &outUsername) -{ - wstring username; - for (const auto &[k, v] : fields) - { - if (k == L"username") username = v; - } - - if (username.empty() || activeServerId.empty() || activeSessionEndpoint.empty()) - return false; - - string url = narrowStr(activeSessionEndpoint) - + "/session/minecraft/hasJoined?username=" + narrowStr(username) - + "&serverId=" + narrowStr(activeServerId); - - auto response = HttpClient::get(url); - if (response.statusCode != 200) - return false; - - auto json = nlohmann::json::parse(response.body, nullptr, false); - if (json.is_discarded()) - return false; - - string id = json.value("id", ""); - string name = json.value("name", ""); - - if (id.empty() || name.empty()) - return false; - - outUid = convStringToWstring(id); - outUsername = convStringToWstring(name); - - return validate(outUid, outUsername); -} - -const wchar_t *KeypairOfflineAuthModule::schemeName() { return L"mcconsoles:keypair_offline"; } - -vector KeypairOfflineAuthModule::supportedVariations() -{ - return {L"rsa2048", L"ed25519"}; -} - -vector> KeypairOfflineAuthModule::getSettings(const wstring &variation) -{ - return {{L"key_type", variation}}; -} - -bool KeypairOfflineAuthModule::onAuthData(const vector> &fields, wstring &outUid, wstring &outUsername) -{ - return extractIdentity(fields, outUid, outUsername); -} - -const wchar_t *OfflineAuthModule::schemeName() { return L"mcconsoles:offline"; } - -vector OfflineAuthModule::supportedVariations() -{ - return {}; -} - -vector> OfflineAuthModule::getSettings(const wstring &variation) -{ - return {}; -} - -bool OfflineAuthModule::onAuthData(const vector> &fields, wstring &outUid, wstring &outUsername) -{ - return extractIdentity(fields, outUid, outUsername); -} diff --git a/Minecraft.World/AuthModule.h b/Minecraft.World/AuthModule.h index e5f4a6fa..ae5875b4 100644 --- a/Minecraft.World/AuthModule.h +++ b/Minecraft.World/AuthModule.h @@ -4,7 +4,6 @@ using namespace std; #include #include #include -#include inline string narrowStr(const wstring &w) { @@ -26,43 +25,3 @@ public: protected: bool extractIdentity(const vector> &fields, wstring &outUid, wstring &outUsername); }; - -class SessionAuthModule : public AuthModule -{ -public: - struct EndpointPair { - wstring authEndpoint; - wstring sessionEndpoint; - }; - -private: - unordered_map endpoints; - wstring activeSessionEndpoint; - wstring activeServerId; - -public: - SessionAuthModule(); - - const wchar_t *schemeName() override; - vector supportedVariations() override; - vector> getSettings(const wstring &variation) override; - bool onAuthData(const vector> &fields, wstring &outUid, wstring &outUsername) override; -}; - -class KeypairOfflineAuthModule : public AuthModule -{ -public: - const wchar_t *schemeName() override; - vector supportedVariations() override; - vector> getSettings(const wstring &variation) override; - bool onAuthData(const vector> &fields, wstring &outUid, wstring &outUsername) override; -}; - -class OfflineAuthModule : public AuthModule -{ -public: - const wchar_t *schemeName() override; - vector supportedVariations() override; - vector> getSettings(const wstring &variation) override; - bool onAuthData(const vector> &fields, wstring &outUid, wstring &outUsername) override; -}; diff --git a/Minecraft.World/HandshakeManager.cpp b/Minecraft.World/HandshakeManager.cpp index 931a0116..96d83b26 100644 --- a/Minecraft.World/HandshakeManager.cpp +++ b/Minecraft.World/HandshakeManager.cpp @@ -35,8 +35,8 @@ void HandshakeManager::setCredentials(const wstring &token, const wstring &uid, vector> HandshakeManager::drainPendingPackets() { - vector> out; - out.swap(pendingPackets); + auto out = std::move(pendingPackets); + pendingPackets.clear(); return out; } diff --git a/Minecraft.World/OfflineAuthModule.cpp b/Minecraft.World/OfflineAuthModule.cpp new file mode 100644 index 00000000..5369ceac --- /dev/null +++ b/Minecraft.World/OfflineAuthModule.cpp @@ -0,0 +1,36 @@ +#include "stdafx.h" +#include "OfflineAuthModule.h" + +const wchar_t *KeypairOfflineAuthModule::schemeName() { return L"mcconsoles:keypair_offline"; } + +vector KeypairOfflineAuthModule::supportedVariations() +{ + return {L"rsa2048", L"ed25519"}; +} + +vector> KeypairOfflineAuthModule::getSettings(const wstring &variation) +{ + return {{L"key_type", variation}}; +} + +bool KeypairOfflineAuthModule::onAuthData(const vector> &fields, wstring &outUid, wstring &outUsername) +{ + return extractIdentity(fields, outUid, outUsername); +} + +const wchar_t *OfflineAuthModule::schemeName() { return L"mcconsoles:offline"; } + +vector OfflineAuthModule::supportedVariations() +{ + return {}; +} + +vector> OfflineAuthModule::getSettings(const wstring &variation) +{ + return {}; +} + +bool OfflineAuthModule::onAuthData(const vector> &fields, wstring &outUid, wstring &outUsername) +{ + return extractIdentity(fields, outUid, outUsername); +} diff --git a/Minecraft.World/OfflineAuthModule.h b/Minecraft.World/OfflineAuthModule.h new file mode 100644 index 00000000..b2b4454d --- /dev/null +++ b/Minecraft.World/OfflineAuthModule.h @@ -0,0 +1,22 @@ +#pragma once +using namespace std; + +#include "AuthModule.h" + +class KeypairOfflineAuthModule : public AuthModule +{ +public: + const wchar_t *schemeName() override; + vector supportedVariations() override; + vector> getSettings(const wstring &variation) override; + bool onAuthData(const vector> &fields, wstring &outUid, wstring &outUsername) override; +}; + +class OfflineAuthModule : public AuthModule +{ +public: + const wchar_t *schemeName() override; + vector supportedVariations() override; + vector> getSettings(const wstring &variation) override; + bool onAuthData(const vector> &fields, wstring &outUid, wstring &outUsername) override; +}; diff --git a/Minecraft.World/SessionAuthModule.cpp b/Minecraft.World/SessionAuthModule.cpp new file mode 100644 index 00000000..50844b39 --- /dev/null +++ b/Minecraft.World/SessionAuthModule.cpp @@ -0,0 +1,78 @@ +#include "stdafx.h" +#include "SessionAuthModule.h" +#include "HttpClient.h" +#include "StringHelpers.h" +#include "Common/vendor/nlohmann/json.hpp" +#include + +static wstring generateServerId() +{ + static constexpr wchar_t hex[] = L"0123456789abcdef"; + static std::mt19937 rng(std::random_device{}()); + wstring id(16, L'0'); + for (auto &c : id) c = hex[rng() & 0xF]; + return id; +} + +SessionAuthModule::SessionAuthModule() +{ + endpoints[L"mojang"] = {L"https://authserver.mojang.com", L"https://sessionserver.mojang.com"}; + endpoints[L"elyby"] = {L"https://authserver.ely.by", L"https://authserver.ely.by"}; +} + +const wchar_t *SessionAuthModule::schemeName() { return L"mcconsoles:session"; } + +vector SessionAuthModule::supportedVariations() +{ + return {L"mojang", L"elyby"}; +} + +vector> SessionAuthModule::getSettings(const wstring &variation) +{ + auto it = endpoints.find(variation); + if (it == endpoints.end()) return {}; + + activeSessionEndpoint = it->second.sessionEndpoint; + activeServerId = generateServerId(); + + return { + {L"authEndpoint", it->second.authEndpoint}, + {L"sessionEndpoint", it->second.sessionEndpoint}, + {L"serverId", activeServerId} + }; +} + +bool SessionAuthModule::onAuthData(const vector> &fields, wstring &outUid, wstring &outUsername) +{ + wstring username; + for (const auto &[k, v] : fields) + { + if (k == L"username") username = v; + } + + if (username.empty() || activeServerId.empty() || activeSessionEndpoint.empty()) + return false; + + string url = narrowStr(activeSessionEndpoint) + + "/session/minecraft/hasJoined?username=" + narrowStr(username) + + "&serverId=" + narrowStr(activeServerId); + + auto response = HttpClient::get(url); + if (response.statusCode != 200) + return false; + + auto json = nlohmann::json::parse(response.body, nullptr, false); + if (json.is_discarded()) + return false; + + string id = json.value("id", ""); + string name = json.value("name", ""); + + if (id.empty() || name.empty()) + return false; + + outUid = convStringToWstring(id); + outUsername = convStringToWstring(name); + + return validate(outUid, outUsername); +} diff --git a/Minecraft.World/SessionAuthModule.h b/Minecraft.World/SessionAuthModule.h new file mode 100644 index 00000000..ecb60c06 --- /dev/null +++ b/Minecraft.World/SessionAuthModule.h @@ -0,0 +1,27 @@ +#pragma once +using namespace std; + +#include "AuthModule.h" +#include + +class SessionAuthModule : public AuthModule +{ +public: + struct EndpointPair { + wstring authEndpoint; + wstring sessionEndpoint; + }; + +private: + unordered_map endpoints; + wstring activeSessionEndpoint; + wstring activeServerId; + +public: + SessionAuthModule(); + + const wchar_t *schemeName() override; + vector supportedVariations() override; + vector> getSettings(const wstring &variation) override; + bool onAuthData(const vector> &fields, wstring &outUid, wstring &outUsername) override; +}; diff --git a/Minecraft.World/cmake/sources/Common.cmake b/Minecraft.World/cmake/sources/Common.cmake index ae1fad9d..8bf351e9 100644 --- a/Minecraft.World/cmake/sources/Common.cmake +++ b/Minecraft.World/cmake/sources/Common.cmake @@ -261,6 +261,10 @@ set(_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_NETWORK_PACKET "${CMAKE_CURRENT_SOURCE_DIR}/AnimatePacket.h" "${CMAKE_CURRENT_SOURCE_DIR}/AuthModule.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/AuthModule.h" + "${CMAKE_CURRENT_SOURCE_DIR}/SessionAuthModule.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/SessionAuthModule.h" + "${CMAKE_CURRENT_SOURCE_DIR}/OfflineAuthModule.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/OfflineAuthModule.h" "${CMAKE_CURRENT_SOURCE_DIR}/AuthPackets.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/AuthPackets.h" "${CMAKE_CURRENT_SOURCE_DIR}/UUID.cpp"