mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-08-20 09:57:09 +00:00
add: implement authentication system ui and handshake.
This commit is contained in:
parent
7a24494d3c
commit
d42da07721
101
Minecraft.Client/AuthScreen.cpp
Normal file
101
Minecraft.Client/AuthScreen.cpp
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
#include "stdafx.h"
|
||||
#include "AuthScreen.h"
|
||||
#include "Minecraft.h"
|
||||
#include "User.h"
|
||||
#include <fstream>
|
||||
|
||||
static constexpr auto PROFILES_FILE = L"auth_profiles.dat";
|
||||
|
||||
vector<AuthProfile> AuthProfileManager::profiles;
|
||||
int AuthProfileManager::selectedProfile = -1;
|
||||
|
||||
void AuthProfileManager::load()
|
||||
{
|
||||
profiles.clear();
|
||||
std::ifstream file(PROFILES_FILE, std::ios::binary);
|
||||
if (!file) return;
|
||||
|
||||
uint32_t count = 0;
|
||||
file.read(reinterpret_cast<char *>(&count), sizeof(count));
|
||||
|
||||
for (uint32_t i = 0; i < count && file.good(); i++)
|
||||
{
|
||||
AuthProfile p;
|
||||
uint8_t type;
|
||||
file.read(reinterpret_cast<char *>(&type), sizeof(type));
|
||||
p.type = static_cast<AuthProfile::Type>(type);
|
||||
|
||||
auto readWstr = [&file]() -> wstring {
|
||||
uint16_t len = 0;
|
||||
file.read(reinterpret_cast<char *>(&len), sizeof(len));
|
||||
wstring s(len, L'\0');
|
||||
file.read(reinterpret_cast<char *>(s.data()), len * sizeof(wchar_t));
|
||||
return s;
|
||||
};
|
||||
|
||||
p.uid = readWstr();
|
||||
p.username = readWstr();
|
||||
p.token = readWstr();
|
||||
profiles.push_back(std::move(p));
|
||||
}
|
||||
|
||||
if (!profiles.empty())
|
||||
selectedProfile = 0;
|
||||
}
|
||||
|
||||
void AuthProfileManager::save()
|
||||
{
|
||||
std::ofstream file(PROFILES_FILE, std::ios::binary | std::ios::trunc);
|
||||
if (!file) return;
|
||||
|
||||
uint32_t count = static_cast<uint32_t>(profiles.size());
|
||||
file.write(reinterpret_cast<const char *>(&count), sizeof(count));
|
||||
|
||||
auto writeWstr = [&file](const wstring &s) {
|
||||
uint16_t len = static_cast<uint16_t>(s.length());
|
||||
file.write(reinterpret_cast<const char *>(&len), sizeof(len));
|
||||
file.write(reinterpret_cast<const char *>(s.data()), len * sizeof(wchar_t));
|
||||
};
|
||||
|
||||
for (const auto &p : profiles)
|
||||
{
|
||||
uint8_t type = static_cast<uint8_t>(p.type);
|
||||
file.write(reinterpret_cast<const char *>(&type), sizeof(type));
|
||||
writeWstr(p.uid);
|
||||
writeWstr(p.username);
|
||||
writeWstr(p.token);
|
||||
}
|
||||
}
|
||||
|
||||
void AuthProfileManager::addProfile(AuthProfile::Type type, const wstring &username)
|
||||
{
|
||||
profiles.push_back({type, L"offline_" + username, username, {}});
|
||||
selectedProfile = static_cast<int>(profiles.size()) - 1;
|
||||
save();
|
||||
}
|
||||
|
||||
void AuthProfileManager::removeSelectedProfile()
|
||||
{
|
||||
if (selectedProfile < 0 || selectedProfile >= static_cast<int>(profiles.size()))
|
||||
return;
|
||||
|
||||
profiles.erase(profiles.begin() + selectedProfile);
|
||||
if (selectedProfile >= static_cast<int>(profiles.size()))
|
||||
selectedProfile = static_cast<int>(profiles.size()) - 1;
|
||||
save();
|
||||
}
|
||||
|
||||
bool AuthProfileManager::applySelectedProfile()
|
||||
{
|
||||
if (selectedProfile < 0 || selectedProfile >= static_cast<int>(profiles.size()))
|
||||
return false;
|
||||
|
||||
const auto &p = profiles[selectedProfile];
|
||||
auto *mc = Minecraft::GetInstance();
|
||||
|
||||
if (mc->user)
|
||||
delete mc->user;
|
||||
|
||||
mc->user = new User(p.username, p.token);
|
||||
return true;
|
||||
}
|
||||
30
Minecraft.Client/AuthScreen.h
Normal file
30
Minecraft.Client/AuthScreen.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
struct AuthProfile
|
||||
{
|
||||
enum Type : uint8_t { MICROSOFT, ELYBY, OFFLINE };
|
||||
|
||||
Type type;
|
||||
wstring uid;
|
||||
wstring username;
|
||||
wstring token;
|
||||
};
|
||||
|
||||
class AuthProfileManager
|
||||
{
|
||||
private:
|
||||
static vector<AuthProfile> profiles;
|
||||
static int selectedProfile;
|
||||
|
||||
public:
|
||||
static void load();
|
||||
static void save();
|
||||
static void addProfile(AuthProfile::Type type, const wstring &username);
|
||||
static void removeSelectedProfile();
|
||||
static bool applySelectedProfile();
|
||||
|
||||
static const vector<AuthProfile> &getProfiles() { return profiles; }
|
||||
static int getSelectedIndex() { return selectedProfile; }
|
||||
static void setSelectedIndex(int idx) { selectedProfile = idx; }
|
||||
};
|
||||
|
|
@ -54,6 +54,8 @@
|
|||
#include "PS3/Network/SonyVoiceChat.h"
|
||||
#endif
|
||||
#include "DLCTexturePack.h"
|
||||
#include "..\Minecraft.World\HandshakeManager.h"
|
||||
#include "..\Minecraft.World\AuthModule.h"
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
#include "Xbox\Network\NetworkPlayerXbox.h"
|
||||
|
|
@ -140,6 +142,9 @@ ClientConnection::ClientConnection(Minecraft *minecraft, Socket *socket, int iUs
|
|||
}
|
||||
|
||||
deferredEntityLinkPackets = vector<DeferredEntityLinkPacket>();
|
||||
|
||||
handshakeManager = nullptr;
|
||||
authComplete = false;
|
||||
}
|
||||
|
||||
bool ClientConnection::isPrimaryConnection() const
|
||||
|
|
@ -202,6 +207,7 @@ ClientConnection::~ClientConnection()
|
|||
delete connection;
|
||||
delete random;
|
||||
delete savedDataStorage;
|
||||
delete handshakeManager;
|
||||
}
|
||||
|
||||
void ClientConnection::tick()
|
||||
|
|
@ -4129,3 +4135,34 @@ ClientConnection::DeferredEntityLinkPacket::DeferredEntityLinkPacket(shared_ptr<
|
|||
m_recievedTick = GetTickCount();
|
||||
m_packet = packet;
|
||||
}
|
||||
|
||||
void ClientConnection::beginAuth()
|
||||
{
|
||||
handshakeManager = new HandshakeManager(false);
|
||||
handshakeManager->registerModule(new MojangAuthModule());
|
||||
handshakeManager->registerModule(new ElyByAuthModule());
|
||||
handshakeManager->registerModule(new KeypairOfflineAuthModule());
|
||||
handshakeManager->registerModule(new OfflineAuthModule());
|
||||
|
||||
auto initial = handshakeManager->createInitialPacket();
|
||||
if (initial) send(initial);
|
||||
}
|
||||
|
||||
void ClientConnection::handleAuth(const shared_ptr<AuthPacket> &packet)
|
||||
{
|
||||
if (done || authComplete) return;
|
||||
if (!handshakeManager) return;
|
||||
|
||||
auto response = handshakeManager->handlePacket(packet);
|
||||
if (response) send(response);
|
||||
|
||||
if (handshakeManager->isComplete())
|
||||
{
|
||||
authComplete = true;
|
||||
}
|
||||
else if (handshakeManager->isFailed())
|
||||
{
|
||||
done = true;
|
||||
message = L"Auth handshake failed";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ class MultiPlayerLevel;
|
|||
class SavedDataStorage;
|
||||
class Socket;
|
||||
class MultiplayerLocalPlayer;
|
||||
class HandshakeManager;
|
||||
|
||||
class ClientConnection : public PacketListener
|
||||
{
|
||||
|
|
@ -179,4 +180,10 @@ private:
|
|||
static const int MAX_ENTITY_LINK_DEFERRAL_INTERVAL = 1000;
|
||||
|
||||
void checkDeferredEntityLinkPackets(int newEntityId);
|
||||
|
||||
public:
|
||||
HandshakeManager *handshakeManager;
|
||||
bool authComplete;
|
||||
void beginAuth();
|
||||
virtual void handleAuth(const shared_ptr<AuthPacket> &packet);
|
||||
};
|
||||
|
|
@ -2948,7 +2948,7 @@ C4JStorage::EMessageResult UIController::RequestMessageBox(UINT uiTitle, UINT ui
|
|||
int( *Func)(LPVOID,int,const C4JStorage::EMessageResult),LPVOID lpParam, WCHAR *pwchFormatString,DWORD dwFocusButton, bool bIsError)
|
||||
|
||||
{
|
||||
MessageBoxInfo param;
|
||||
MessageBoxInfo param = {};
|
||||
param.uiTitle = uiTitle;
|
||||
param.uiText = uiText;
|
||||
param.uiOptionA = uiOptionA;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "..\..\..\Minecraft.World\Random.h"
|
||||
#include "..\..\User.h"
|
||||
#include "..\..\MinecraftServer.h"
|
||||
#include "..\..\AuthScreen.h"
|
||||
#include "UI.h"
|
||||
#include "UIScene_MainMenu.h"
|
||||
#ifdef __ORBIS__
|
||||
|
|
@ -46,12 +47,12 @@ UIScene_MainMenu::UIScene_MainMenu(int iPad, void *initData, UILayer *parentLaye
|
|||
if(ProfileManager.IsFullVersion())
|
||||
{
|
||||
m_bTrialVersion=false;
|
||||
m_buttons[static_cast<int>(eControl_UnlockOrDLC)].init(IDS_DOWNLOADABLECONTENT,eControl_UnlockOrDLC);
|
||||
m_buttons[static_cast<int>(eControl_UnlockOrDLC)].init(L"Auth",eControl_UnlockOrDLC);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bTrialVersion=true;
|
||||
m_buttons[static_cast<int>(eControl_UnlockOrDLC)].init(IDS_UNLOCK_FULL_GAME,eControl_UnlockOrDLC);
|
||||
m_buttons[static_cast<int>(eControl_UnlockOrDLC)].init(L"Auth",eControl_UnlockOrDLC);
|
||||
}
|
||||
|
||||
#ifndef _DURANGO
|
||||
|
|
@ -181,8 +182,8 @@ void UIScene_MainMenu::handleGainFocus(bool navBack)
|
|||
|
||||
if(navBack && ProfileManager.IsFullVersion())
|
||||
{
|
||||
// Replace the Unlock Full Game with Downloadable Content
|
||||
m_buttons[static_cast<int>(eControl_UnlockOrDLC)].setLabel(IDS_DOWNLOADABLECONTENT);
|
||||
// once again replacing the shop with auth. not a bad thing.
|
||||
m_buttons[static_cast<int>(eControl_UnlockOrDLC)].setLabel(L"Auth");
|
||||
}
|
||||
|
||||
#if TO_BE_IMPLEMENTED
|
||||
|
|
@ -357,7 +358,7 @@ void UIScene_MainMenu::handlePress(F64 controlId, F64 childId)
|
|||
ui.PlayUISFX(eSFX_Press);
|
||||
|
||||
m_eAction=eAction_RunUnlockOrDLC;
|
||||
signInReturnedFunc = &UIScene_MainMenu::UnlockFullGame_SignInReturned;
|
||||
RunAction(primaryPad);
|
||||
break;
|
||||
case eControl_Exit:
|
||||
//CD - Added for audio
|
||||
|
|
@ -438,8 +439,11 @@ void UIScene_MainMenu::RunAction(int iPad)
|
|||
RunHelpAndOptions(iPad);
|
||||
break;
|
||||
case eAction_RunUnlockOrDLC:
|
||||
RunUnlockOrDLC(iPad);
|
||||
{
|
||||
AuthProfileManager::load();
|
||||
ShowAuthMenu(iPad, this);
|
||||
break;
|
||||
}
|
||||
#ifdef _DURANGO
|
||||
case eAction_RunXboxHelp:
|
||||
// 4J: Launch the dummy xbox help application.
|
||||
|
|
@ -450,6 +454,161 @@ void UIScene_MainMenu::RunAction(int iPad)
|
|||
}
|
||||
}
|
||||
|
||||
static int s_authPad = 0;
|
||||
|
||||
static const wchar_t *BuildAuthProfileText()
|
||||
{
|
||||
static wstring text;
|
||||
const auto &profiles = AuthProfileManager::getProfiles();
|
||||
int sel = AuthProfileManager::getSelectedIndex();
|
||||
if (profiles.empty())
|
||||
{
|
||||
text = L"No profiles - press Add to create one";
|
||||
}
|
||||
else
|
||||
{
|
||||
text.clear();
|
||||
for (int i = 0; i < static_cast<int>(profiles.size()); i++)
|
||||
{
|
||||
const auto &p = profiles[i];
|
||||
const wchar_t *type = (p.type == AuthProfile::MICROSOFT) ? L"[MS]"
|
||||
: (p.type == AuthProfile::ELYBY) ? L"[Ely]" : L"[Off]";
|
||||
if (i > 0) text += L"\n";
|
||||
text += (i == sel) ? L"> " : L" ";
|
||||
text += wstring(type) + L" " + p.username;
|
||||
}
|
||||
}
|
||||
return text.c_str();
|
||||
}
|
||||
|
||||
void UIScene_MainMenu::ShowAuthMenu(int iPad, void *pClass)
|
||||
{
|
||||
s_authPad = iPad;
|
||||
|
||||
static const wchar_t *authOptions[] = { L"Next", L"Use", L"Add", L"Back" };
|
||||
MessageBoxInfo param = {};
|
||||
param.uiOptionC = 4;
|
||||
param.dwPad = iPad;
|
||||
param.Func = &UIScene_MainMenu::AuthMenuReturned;
|
||||
param.lpParam = pClass;
|
||||
param.rawTitle = L"Authentication";
|
||||
param.rawText = BuildAuthProfileText();
|
||||
param.rawOptions = authOptions;
|
||||
ui.NavigateToScene(iPad, eUIScene_MessageBox, ¶m, eUILayer_Alert, eUIGroup_Fullscreen);
|
||||
UIScene *scene = ui.FindScene(eUIScene_MessageBox);
|
||||
if (scene)
|
||||
static_cast<UIScene_MessageBox *>(scene)->setKeepOpen(true);
|
||||
}
|
||||
|
||||
void UIScene_MainMenu::ShowAuthAddMenu(int iPad, void *pClass)
|
||||
{
|
||||
static const wchar_t *addOptions[] = { L"Microsoft Auth", L"Ely.by Auth", L"Add Offline User", L"Back" };
|
||||
MessageBoxInfo param = {};
|
||||
param.uiOptionC = 4;
|
||||
param.dwPad = iPad;
|
||||
param.Func = &UIScene_MainMenu::AuthAddMenuReturned;
|
||||
param.lpParam = pClass;
|
||||
param.rawTitle = L"Add Profile";
|
||||
param.rawText = L"Select an auth type";
|
||||
param.rawOptions = addOptions;
|
||||
ui.NavigateToScene(iPad, eUIScene_MessageBox, ¶m, eUILayer_Alert, eUIGroup_Fullscreen);
|
||||
}
|
||||
|
||||
int UIScene_MainMenu::AuthMenuReturned(LPVOID lpParam, int iPad, const C4JStorage::EMessageResult result)
|
||||
{
|
||||
const auto &profiles = AuthProfileManager::getProfiles();
|
||||
switch (result)
|
||||
{
|
||||
case C4JStorage::EMessage_ResultAccept:
|
||||
{
|
||||
if (!profiles.empty())
|
||||
{
|
||||
int next = (AuthProfileManager::getSelectedIndex() + 1) % static_cast<int>(profiles.size());
|
||||
AuthProfileManager::setSelectedIndex(next);
|
||||
}
|
||||
if (auto *scene = ui.FindScene(eUIScene_MessageBox))
|
||||
static_cast<UIScene_MessageBox *>(scene)->updateContent(BuildAuthProfileText());
|
||||
return 0;
|
||||
}
|
||||
case C4JStorage::EMessage_ResultDecline:
|
||||
{
|
||||
ui.NavigateBack(iPad);
|
||||
AuthProfileManager::applySelectedProfile();
|
||||
break;
|
||||
}
|
||||
case C4JStorage::EMessage_ResultThirdOption:
|
||||
{
|
||||
ui.NavigateBack(iPad);
|
||||
ShowAuthAddMenu(iPad, lpParam);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ui.NavigateBack(iPad);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UIScene_MainMenu::AuthAddMenuReturned(LPVOID lpParam, int iPad, const C4JStorage::EMessageResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case C4JStorage::EMessage_ResultAccept:
|
||||
AuthProfileManager::addProfile(AuthProfile::MICROSOFT, L"Player");
|
||||
ShowAuthMenu(iPad, lpParam);
|
||||
break;
|
||||
case C4JStorage::EMessage_ResultDecline:
|
||||
AuthProfileManager::addProfile(AuthProfile::ELYBY, L"Player");
|
||||
ShowAuthMenu(iPad, lpParam);
|
||||
break;
|
||||
case C4JStorage::EMessage_ResultThirdOption:
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
UIKeyboardInitData kbData;
|
||||
kbData.title = L"Enter Username";
|
||||
kbData.defaultText = L"Player";
|
||||
kbData.maxChars = 16;
|
||||
kbData.callback = &UIScene_MainMenu::AuthKeyboardReturned;
|
||||
kbData.lpParam = lpParam;
|
||||
kbData.pcMode = g_KBMInput.IsKBMActive();
|
||||
ui.NavigateToScene(iPad, eUIScene_Keyboard, &kbData);
|
||||
#else
|
||||
InputManager.RequestKeyboard(L"Enter Username", L"Player", (DWORD)0, 16, &UIScene_MainMenu::AuthKeyboardReturned, lpParam, C_4JInput::EKeyboardMode_Default);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ShowAuthMenu(iPad, lpParam);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UIScene_MainMenu::AuthKeyboardReturned(LPVOID lpParam, const bool bRes)
|
||||
{
|
||||
if (bRes)
|
||||
{
|
||||
uint16_t ui16Text[128];
|
||||
ZeroMemory(ui16Text, 128 * sizeof(uint16_t));
|
||||
#ifdef _WINDOWS64
|
||||
Win64_GetKeyboardText(ui16Text, 128);
|
||||
#else
|
||||
InputManager.GetText(ui16Text);
|
||||
#endif
|
||||
if (ui16Text[0] != 0)
|
||||
{
|
||||
wchar_t wName[128] = {};
|
||||
for (int k = 0; k < 127 && ui16Text[k]; k++)
|
||||
wName[k] = static_cast<wchar_t>(ui16Text[k]);
|
||||
AuthProfileManager::addProfile(AuthProfile::OFFLINE, wName);
|
||||
}
|
||||
}
|
||||
ShowAuthMenu(s_authPad, lpParam);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UIScene_MainMenu::customDraw(IggyCustomDrawCallbackRegion *region)
|
||||
{
|
||||
if(wcscmp((wchar_t *)region->name,L"Splash")==0)
|
||||
|
|
@ -1946,7 +2105,7 @@ void UIScene_MainMenu::tick()
|
|||
if(ProfileManager.IsFullVersion())
|
||||
{
|
||||
m_bTrialVersion=false;
|
||||
m_buttons[(int)eControl_UnlockOrDLC].init(app.GetString(IDS_DOWNLOADABLECONTENT),eControl_UnlockOrDLC);
|
||||
m_buttons[(int)eControl_UnlockOrDLC].init(L"Auth",eControl_UnlockOrDLC);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -144,7 +144,13 @@ private:
|
|||
void RunHelpAndOptions(int iPad);
|
||||
|
||||
void RunAction(int iPad);
|
||||
|
||||
|
||||
static void ShowAuthMenu(int iPad, void *pClass);
|
||||
static void ShowAuthAddMenu(int iPad, void *pClass);
|
||||
static int AuthMenuReturned(void *pParam, int iPad, C4JStorage::EMessageResult result);
|
||||
static int AuthAddMenuReturned(void *pParam, int iPad, C4JStorage::EMessageResult result);
|
||||
static int AuthKeyboardReturned(LPVOID lpParam, const bool bRes);
|
||||
|
||||
static void LoadTrial();
|
||||
|
||||
#ifdef _XBOX_ONE
|
||||
|
|
|
|||
|
|
@ -23,28 +23,29 @@ UIScene_MessageBox::UIScene_MessageBox(int iPad, void *initData, UILayer *parent
|
|||
int buttonIndex = 0;
|
||||
if(param->uiOptionC > 3)
|
||||
{
|
||||
m_buttonButtons[eControl_Button0].init(app.GetString(param->uiOptionA[buttonIndex]),buttonIndex);
|
||||
m_buttonButtons[eControl_Button0].init(param->rawOptions ? param->rawOptions[buttonIndex] : app.GetString(param->uiOptionA[buttonIndex]),buttonIndex);
|
||||
++buttonIndex;
|
||||
}
|
||||
if(param->uiOptionC > 2)
|
||||
{
|
||||
m_buttonButtons[eControl_Button1].init(app.GetString(param->uiOptionA[buttonIndex]),buttonIndex);
|
||||
m_buttonButtons[eControl_Button1].init(param->rawOptions ? param->rawOptions[buttonIndex] : app.GetString(param->uiOptionA[buttonIndex]),buttonIndex);
|
||||
++buttonIndex;
|
||||
}
|
||||
if(param->uiOptionC > 1)
|
||||
{
|
||||
m_buttonButtons[eControl_Button2].init(app.GetString(param->uiOptionA[buttonIndex]),buttonIndex);
|
||||
m_buttonButtons[eControl_Button2].init(param->rawOptions ? param->rawOptions[buttonIndex] : app.GetString(param->uiOptionA[buttonIndex]),buttonIndex);
|
||||
++buttonIndex;
|
||||
}
|
||||
m_buttonButtons[eControl_Button3].init(app.GetString(param->uiOptionA[buttonIndex]),buttonIndex);
|
||||
m_buttonButtons[eControl_Button3].init(param->rawOptions ? param->rawOptions[buttonIndex] : app.GetString(param->uiOptionA[buttonIndex]),buttonIndex);
|
||||
|
||||
m_labelTitle.init(app.GetString(param->uiTitle));
|
||||
m_labelContent.init(app.GetString(param->uiText));
|
||||
m_labelTitle.init(param->rawTitle ? param->rawTitle : app.GetString(param->uiTitle));
|
||||
m_labelContent.init(param->rawText ? param->rawText : app.GetString(param->uiText));
|
||||
|
||||
out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcAutoResize , 0 , nullptr );
|
||||
|
||||
m_Func = param->Func;
|
||||
m_lpParam = param->lpParam;
|
||||
m_keepOpen = false;
|
||||
|
||||
parentLayer->addComponent(iPad,eUIComponent_MenuBackground);
|
||||
|
||||
|
|
@ -99,7 +100,7 @@ void UIScene_MessageBox::handleInput(int iPad, int key, bool repeat, bool presse
|
|||
case ACTION_MENU_CANCEL:
|
||||
if(pressed)
|
||||
{
|
||||
navigateBack();
|
||||
if(!m_keepOpen) navigateBack();
|
||||
if(m_Func) m_Func(m_lpParam, iPad, C4JStorage::EMessage_Cancelled);
|
||||
}
|
||||
break;
|
||||
|
|
@ -136,10 +137,15 @@ void UIScene_MessageBox::handlePress(F64 controlId, F64 childId)
|
|||
break;
|
||||
}
|
||||
|
||||
navigateBack();
|
||||
if(!m_keepOpen) navigateBack();
|
||||
if(m_Func) m_Func(m_lpParam, m_iPad, result);
|
||||
}
|
||||
|
||||
void UIScene_MessageBox::updateContent(const wchar_t *text)
|
||||
{
|
||||
m_labelContent.init(text);
|
||||
}
|
||||
|
||||
bool UIScene_MessageBox::hasFocus(int iPad)
|
||||
{
|
||||
// 4J-JEV: Fix for PS4 #5204 - [TRC][R4033] The application can be locked up by second user logging out of the system.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ private:
|
|||
int( *m_Func)(LPVOID,int,const C4JStorage::EMessageResult);
|
||||
LPVOID m_lpParam;
|
||||
int m_buttonCount;
|
||||
bool m_keepOpen;
|
||||
|
||||
UIControl_Button m_buttonButtons[eControl_COUNT];
|
||||
UIControl_Label m_labelTitle, m_labelContent;
|
||||
|
|
@ -57,4 +58,8 @@ public:
|
|||
|
||||
protected:
|
||||
void handlePress(F64 controlId, F64 childId);
|
||||
|
||||
public:
|
||||
void updateContent(const wchar_t *text);
|
||||
void setKeepOpen(bool keep) { m_keepOpen = keep; }
|
||||
};
|
||||
|
|
@ -485,6 +485,9 @@ typedef struct _MessageBoxInfo
|
|||
//C4JStringTable *pStringTable; // 4J Stu - We don't need this for our internal message boxes
|
||||
WCHAR *pwchFormatString;
|
||||
DWORD dwFocusButton;
|
||||
const wchar_t *rawTitle;
|
||||
const wchar_t *rawText;
|
||||
const wchar_t **rawOptions;
|
||||
} MessageBoxInfo;
|
||||
|
||||
typedef struct _DLCOffersParam
|
||||
|
|
|
|||
|
|
@ -11,13 +11,14 @@
|
|||
ConnectScreen::ConnectScreen(Minecraft *minecraft, const wstring& ip, int port)
|
||||
{
|
||||
aborted = false;
|
||||
preLoginSent = false;
|
||||
// System.out.println("Connecting to " + ip + ", " + port);
|
||||
minecraft->setLevel(nullptr);
|
||||
#if 1
|
||||
// 4J - removed from separate thread, but need to investigate what we actually need here
|
||||
connection = new ClientConnection(minecraft, ip, port);
|
||||
if (aborted) return;
|
||||
connection->send(std::make_shared<PreLoginPacket>(minecraft->user->name));
|
||||
connection->beginAuth();
|
||||
#else
|
||||
|
||||
new Thread() {
|
||||
|
|
@ -47,6 +48,11 @@ void ConnectScreen::tick()
|
|||
{
|
||||
if (connection != nullptr)
|
||||
{
|
||||
if (!preLoginSent && connection->authComplete)
|
||||
{
|
||||
preLoginSent = true;
|
||||
connection->send(std::make_shared<PreLoginPacket>(minecraft->user->name));
|
||||
}
|
||||
connection->tick();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ class ConnectScreen : public Screen
|
|||
private:
|
||||
ClientConnection *connection;
|
||||
bool aborted;
|
||||
bool preLoginSent;
|
||||
public:
|
||||
ConnectScreen(Minecraft *minecraft, const wstring& ip, int port);
|
||||
virtual void tick();
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
#include "..\Minecraft.World\net.minecraft.world.item.h"
|
||||
#include "..\Minecraft.World\SharedConstants.h"
|
||||
#include "Settings.h"
|
||||
#include "..\Minecraft.World\HandshakeManager.h"
|
||||
#include "..\Minecraft.World\AuthModule.h"
|
||||
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
|
||||
#include "..\Minecraft.Server\ServerLogManager.h"
|
||||
#include "..\Minecraft.Server\Access\Access.h"
|
||||
|
|
@ -59,10 +61,14 @@ PendingConnection::PendingConnection(MinecraftServer *server, Socket *socket, co
|
|||
this->server = server;
|
||||
connection = new Connection(socket, id, this);
|
||||
connection->fakeLag = FAKE_LAG;
|
||||
|
||||
handshakeManager = nullptr;
|
||||
authComplete = false;
|
||||
}
|
||||
|
||||
PendingConnection::~PendingConnection()
|
||||
{
|
||||
delete handshakeManager;
|
||||
delete connection;
|
||||
}
|
||||
|
||||
|
|
@ -98,6 +104,13 @@ void PendingConnection::disconnect(DisconnectPacket::eDisconnectReason reason)
|
|||
|
||||
void PendingConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
|
||||
{
|
||||
if (handshakeManager && !authComplete)
|
||||
{
|
||||
app.DebugPrintf("PendingConnection: PreLogin received before auth complete, disconnecting\n");
|
||||
disconnect(DisconnectPacket::eDisconnect_Closed);
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet->m_netcodeVersion != MINECRAFT_NET_VERSION)
|
||||
{
|
||||
app.DebugPrintf("Netcode version is %d not equal to %d\n", packet->m_netcodeVersion, MINECRAFT_NET_VERSION);
|
||||
|
|
@ -394,3 +407,33 @@ bool PendingConnection::isDisconnected()
|
|||
{
|
||||
return done;
|
||||
}
|
||||
|
||||
void PendingConnection::initAuth()
|
||||
{
|
||||
handshakeManager = new HandshakeManager(true);
|
||||
handshakeManager->registerModule(new MojangAuthModule());
|
||||
handshakeManager->registerModule(new ElyByAuthModule());
|
||||
handshakeManager->registerModule(new KeypairOfflineAuthModule());
|
||||
handshakeManager->registerModule(new OfflineAuthModule());
|
||||
}
|
||||
|
||||
void PendingConnection::handleAuth(const shared_ptr<AuthPacket> &packet)
|
||||
{
|
||||
if (done || authComplete) return;
|
||||
|
||||
if (!handshakeManager)
|
||||
initAuth();
|
||||
|
||||
auto response = handshakeManager->handlePacket(packet);
|
||||
if (response) send(response);
|
||||
|
||||
if (handshakeManager->isComplete())
|
||||
{
|
||||
authComplete = true;
|
||||
name = std::move(handshakeManager->finalUsername);
|
||||
}
|
||||
else if (handshakeManager->isFailed())
|
||||
{
|
||||
disconnect(DisconnectPacket::eDisconnect_Closed);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ class Socket;
|
|||
class LoginPacket;
|
||||
class Connection;
|
||||
class Random;
|
||||
class HandshakeManager;
|
||||
using namespace std;
|
||||
|
||||
class PendingConnection : public PacketListener
|
||||
|
|
@ -43,6 +44,10 @@ public:
|
|||
wstring getName();
|
||||
virtual bool isServerPacketListener();
|
||||
virtual bool isDisconnected();
|
||||
HandshakeManager *handshakeManager;
|
||||
bool authComplete;
|
||||
void initAuth();
|
||||
virtual void handleAuth(const shared_ptr<AuthPacket> &packet);
|
||||
|
||||
private:
|
||||
void sendPreLoginResponse();
|
||||
|
|
|
|||
|
|
@ -969,6 +969,8 @@ set(_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_SKINS
|
|||
source_group("net/minecraft/client/skins" FILES ${_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_SKINS})
|
||||
|
||||
set(_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_TITLE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/AuthScreen.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/AuthScreen.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/TitleScreen.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/TitleScreen.h"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ set(_MINECRAFT_SERVER_COMMON_ROOT
|
|||
"${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/AllowAllCuller.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/ArchiveFile.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/ArrowRenderer.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/AuthScreen.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/BatModel.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/BatRenderer.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/BeaconRenderer.cpp"
|
||||
|
|
|
|||
|
|
@ -50,8 +50,6 @@ vector<wstring> MojangAuthModule::supportedVariations()
|
|||
return {L"java", L"bedrock"};
|
||||
}
|
||||
|
||||
// --- KeypairOfflineAuthModule ---
|
||||
|
||||
const wchar_t *KeypairOfflineAuthModule::schemeName() { return L"mcconsoles:keypair_offline"; }
|
||||
|
||||
vector<wstring> KeypairOfflineAuthModule::supportedVariations()
|
||||
|
|
|
|||
|
|
@ -26,10 +26,10 @@ void AuthPacket::write(DataOutputStream *dos)
|
|||
{
|
||||
dos->writeByte(static_cast<byte>(stage));
|
||||
dos->writeShort(static_cast<short>(fields.size()));
|
||||
for (const auto &field : fields)
|
||||
for (const auto &[key, value] : fields)
|
||||
{
|
||||
writeUtf(field.first, dos);
|
||||
writeUtf(field.second, dos);
|
||||
writeUtf(key, dos);
|
||||
writeUtf(value, dos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ void AuthPacket::handle(PacketListener *listener)
|
|||
int AuthPacket::getEstimatedSize()
|
||||
{
|
||||
int size = 1 + 2;
|
||||
for (const auto &field : fields)
|
||||
size += 4 + static_cast<int>((field.first.length() + field.second.length()) * sizeof(wchar_t));
|
||||
for (const auto &[key, value] : fields)
|
||||
size += 4 + static_cast<int>((key.length() + value.length()) * sizeof(wchar_t));
|
||||
return size;
|
||||
}
|
||||
|
|
|
|||
205
Minecraft.World/HandshakeManager.cpp
Normal file
205
Minecraft.World/HandshakeManager.cpp
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
#include "stdafx.h"
|
||||
#include "HandshakeManager.h"
|
||||
#include "AuthModule.h"
|
||||
|
||||
static constexpr auto PROTOCOL_VERSION = L"1.0";
|
||||
|
||||
HandshakeManager::HandshakeManager(bool isServer)
|
||||
: isServer(isServer), state(HandshakeState::IDLE), activeModule(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
HandshakeManager::~HandshakeManager()
|
||||
{
|
||||
for (auto &[name, module] : modules)
|
||||
delete module;
|
||||
}
|
||||
|
||||
void HandshakeManager::registerModule(AuthModule *module)
|
||||
{
|
||||
modules[module->schemeName()] = module;
|
||||
}
|
||||
|
||||
shared_ptr<AuthPacket> HandshakeManager::handlePacket(const shared_ptr<AuthPacket> &packet)
|
||||
{
|
||||
return isServer ? handleServer(packet) : handleClient(packet);
|
||||
}
|
||||
|
||||
shared_ptr<AuthPacket> HandshakeManager::createInitialPacket()
|
||||
{
|
||||
state = HandshakeState::VERSION_SENT;
|
||||
return makePacket(AuthStage::ANNOUNCE_VERSION, {{L"version", PROTOCOL_VERSION}});
|
||||
}
|
||||
|
||||
shared_ptr<AuthPacket> HandshakeManager::handleServer(const shared_ptr<AuthPacket> &packet)
|
||||
{
|
||||
switch (packet->stage)
|
||||
{
|
||||
case AuthStage::ANNOUNCE_VERSION:
|
||||
{
|
||||
protocolVersion = L"";
|
||||
for (const auto &[k, v] : packet->fields)
|
||||
if (k == L"version") protocolVersion = v;
|
||||
|
||||
if (protocolVersion != PROTOCOL_VERSION)
|
||||
return fail();
|
||||
|
||||
// Pick first registered module as the scheme
|
||||
if (modules.empty())
|
||||
return fail();
|
||||
|
||||
activeModule = modules.begin()->second;
|
||||
state = HandshakeState::SCHEME_DECLARED;
|
||||
return makePacket(AuthStage::DECLARE_SCHEME, {
|
||||
{L"version", PROTOCOL_VERSION},
|
||||
{L"scheme", activeModule->schemeName()}
|
||||
});
|
||||
}
|
||||
|
||||
case AuthStage::ACCEPT_SCHEME:
|
||||
{
|
||||
wstring variation;
|
||||
for (const auto &[k, v] : packet->fields)
|
||||
if (k == L"variation") variation = v;
|
||||
|
||||
activeVariation = variation;
|
||||
state = HandshakeState::SETTINGS_SENT;
|
||||
auto settings = activeModule->getSettings(activeVariation);
|
||||
return makePacket(AuthStage::SCHEME_SETTINGS, std::move(settings));
|
||||
}
|
||||
|
||||
case AuthStage::BEGIN_AUTH:
|
||||
{
|
||||
state = HandshakeState::AUTH_IN_PROGRESS;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
case AuthStage::AUTH_DATA:
|
||||
{
|
||||
wstring uid, username;
|
||||
if (!activeModule->onAuthData(packet->fields, uid, username))
|
||||
return fail();
|
||||
|
||||
state = HandshakeState::AUTH_DATA_EXCHANGED;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
case AuthStage::AUTH_DONE:
|
||||
{
|
||||
wstring uid, username;
|
||||
for (const auto &[k, v] : packet->fields)
|
||||
{
|
||||
if (k == L"uid") uid = v;
|
||||
else if (k == L"username") username = v;
|
||||
}
|
||||
|
||||
if (!activeModule->validate(uid, username))
|
||||
return fail();
|
||||
|
||||
finalUid = uid;
|
||||
finalUsername = username;
|
||||
state = HandshakeState::IDENTITY_ASSIGNED;
|
||||
return makePacket(AuthStage::ASSIGN_IDENTITY, {
|
||||
{L"uid", finalUid},
|
||||
{L"username", finalUsername}
|
||||
});
|
||||
}
|
||||
|
||||
case AuthStage::CONFIRM_IDENTITY:
|
||||
{
|
||||
wstring uid, username;
|
||||
for (const auto &[k, v] : packet->fields)
|
||||
{
|
||||
if (k == L"uid") uid = v;
|
||||
else if (k == L"username") username = v;
|
||||
}
|
||||
|
||||
if (uid != finalUid || username != finalUsername)
|
||||
return fail();
|
||||
|
||||
state = HandshakeState::COMPLETE;
|
||||
return makePacket(AuthStage::AUTH_SUCCESS);
|
||||
}
|
||||
|
||||
default:
|
||||
return fail();
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<AuthPacket> HandshakeManager::handleClient(const shared_ptr<AuthPacket> &packet)
|
||||
{
|
||||
switch (packet->stage)
|
||||
{
|
||||
case AuthStage::DECLARE_SCHEME:
|
||||
{
|
||||
wstring scheme;
|
||||
for (const auto &[k, v] : packet->fields)
|
||||
{
|
||||
if (k == L"version") protocolVersion = v;
|
||||
else if (k == L"scheme") scheme = v;
|
||||
}
|
||||
|
||||
if (protocolVersion != PROTOCOL_VERSION)
|
||||
return fail();
|
||||
|
||||
auto it = modules.find(scheme);
|
||||
if (it == modules.end())
|
||||
return fail();
|
||||
|
||||
activeModule = it->second;
|
||||
|
||||
auto variations = activeModule->supportedVariations();
|
||||
activeVariation = variations.empty() ? L"" : variations[0];
|
||||
|
||||
state = HandshakeState::SCHEME_ACCEPTED;
|
||||
return makePacket(AuthStage::ACCEPT_SCHEME, {{L"variation", activeVariation}});
|
||||
}
|
||||
|
||||
case AuthStage::SCHEME_SETTINGS:
|
||||
{
|
||||
state = HandshakeState::AUTH_IN_PROGRESS;
|
||||
return makePacket(AuthStage::BEGIN_AUTH);
|
||||
}
|
||||
|
||||
case AuthStage::ASSIGN_IDENTITY:
|
||||
{
|
||||
for (const auto &[k, v] : packet->fields)
|
||||
{
|
||||
if (k == L"uid") finalUid = v;
|
||||
else if (k == L"username") finalUsername = v;
|
||||
}
|
||||
|
||||
state = HandshakeState::IDENTITY_CONFIRMED;
|
||||
return makePacket(AuthStage::CONFIRM_IDENTITY, {
|
||||
{L"uid", finalUid},
|
||||
{L"username", finalUsername}
|
||||
});
|
||||
}
|
||||
|
||||
case AuthStage::AUTH_SUCCESS:
|
||||
{
|
||||
state = HandshakeState::COMPLETE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
case AuthStage::AUTH_FAILURE:
|
||||
{
|
||||
state = HandshakeState::FAILED;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
default:
|
||||
return fail();
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<AuthPacket> HandshakeManager::makePacket(AuthStage stage, vector<pair<wstring, wstring>> fields)
|
||||
{
|
||||
return std::make_shared<AuthPacket>(stage, std::move(fields));
|
||||
}
|
||||
|
||||
shared_ptr<AuthPacket> HandshakeManager::fail()
|
||||
{
|
||||
state = HandshakeState::FAILED;
|
||||
return makePacket(AuthStage::AUTH_FAILURE);
|
||||
}
|
||||
57
Minecraft.World/HandshakeManager.h
Normal file
57
Minecraft.World/HandshakeManager.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#pragma once
|
||||
using namespace std;
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include "AuthPackets.h"
|
||||
|
||||
class AuthModule;
|
||||
|
||||
enum class HandshakeState : uint8_t
|
||||
{
|
||||
IDLE,
|
||||
VERSION_SENT,
|
||||
SCHEME_DECLARED,
|
||||
SCHEME_ACCEPTED,
|
||||
SETTINGS_SENT,
|
||||
AUTH_IN_PROGRESS,
|
||||
AUTH_DATA_EXCHANGED,
|
||||
IDENTITY_ASSIGNED,
|
||||
IDENTITY_CONFIRMED,
|
||||
COMPLETE,
|
||||
FAILED
|
||||
};
|
||||
|
||||
class HandshakeManager
|
||||
{
|
||||
private:
|
||||
bool isServer;
|
||||
HandshakeState state;
|
||||
unordered_map<wstring, AuthModule *> modules;
|
||||
AuthModule *activeModule;
|
||||
wstring activeVariation;
|
||||
wstring protocolVersion;
|
||||
|
||||
public:
|
||||
wstring finalUid;
|
||||
wstring finalUsername;
|
||||
|
||||
HandshakeManager(bool isServer);
|
||||
~HandshakeManager();
|
||||
|
||||
void registerModule(AuthModule *module);
|
||||
shared_ptr<AuthPacket> handlePacket(const shared_ptr<AuthPacket> &packet);
|
||||
shared_ptr<AuthPacket> createInitialPacket();
|
||||
|
||||
bool isComplete() const { return state == HandshakeState::COMPLETE; }
|
||||
bool isFailed() const { return state == HandshakeState::FAILED; }
|
||||
HandshakeState getState() const { return state; }
|
||||
|
||||
private:
|
||||
shared_ptr<AuthPacket> handleServer(const shared_ptr<AuthPacket> &packet);
|
||||
shared_ptr<AuthPacket> handleClient(const shared_ptr<AuthPacket> &packet);
|
||||
|
||||
shared_ptr<AuthPacket> makePacket(AuthStage stage, vector<pair<wstring, wstring>> fields = {});
|
||||
shared_ptr<AuthPacket> fail();
|
||||
};
|
||||
|
|
@ -492,7 +492,7 @@ void PacketListener::handleGameCommand(shared_ptr<GameCommandPacket> packet)
|
|||
onUnhandledPacket( (shared_ptr<Packet> ) packet);
|
||||
}
|
||||
|
||||
void PacketListener::handleAuth(shared_ptr<AuthPacket> packet)
|
||||
void PacketListener::handleAuth(const shared_ptr<AuthPacket> &packet)
|
||||
{
|
||||
onUnhandledPacket( (shared_ptr<Packet> ) packet);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,6 +229,5 @@ public:
|
|||
virtual void handleXZ(shared_ptr<XZPacket> packet);
|
||||
virtual void handleGameCommand(shared_ptr<GameCommandPacket> packet);
|
||||
|
||||
// MCConsoles Auth
|
||||
virtual void handleAuth(shared_ptr<AuthPacket> packet);
|
||||
virtual void handleAuth(const shared_ptr<AuthPacket> &packet);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -318,6 +318,8 @@ set(_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_NETWORK_PACKET
|
|||
"${CMAKE_CURRENT_SOURCE_DIR}/GameEventPacket.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/GetInfoPacket.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/GetInfoPacket.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/HandshakeManager.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/HandshakeManager.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/InteractPacket.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/InteractPacket.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/KeepAlivePacket.cpp"
|
||||
|
|
|
|||
Loading…
Reference in a new issue