1
0
Fork 0

cAuthenticator: Added GetUUIDsFromPlayerNames().

This commit is contained in:
madmaxoft 2014-07-28 12:37:48 +02:00
parent 003f0e69a9
commit f5f9656917
2 changed files with 116 additions and 3 deletions

View File

@ -17,6 +17,8 @@
#define DEFAULT_AUTH_SERVER "sessionserver.mojang.com"
#define DEFAULT_AUTH_ADDRESS "/session/minecraft/hasJoined?username=%USERNAME%&serverId=%SERVERID%"
#define DEFAULT_NAME_TO_UUID_SERVER "api.mojang.com"
#define DEFAULT_NAME_TO_UUID_ADDRESS "/profiles/minecraft"
/** This is the data of the root certs for Starfield Technologies, the CA that signed sessionserver.mojang.com's cert:
Downloaded from http://certs.starfieldtech.com/repository/ */
@ -83,6 +85,8 @@ cAuthenticator::cAuthenticator(void) :
super("cAuthenticator"),
m_Server(DEFAULT_AUTH_SERVER),
m_Address(DEFAULT_AUTH_ADDRESS),
m_NameToUUIDServer(DEFAULT_NAME_TO_UUID_SERVER),
m_NameToUUIDAddress(DEFAULT_NAME_TO_UUID_ADDRESS),
m_ShouldAuthenticate(true)
{
}
@ -102,9 +106,11 @@ cAuthenticator::~cAuthenticator()
void cAuthenticator::ReadINI(cIniFile & IniFile)
{
m_Server = IniFile.GetValueSet("Authentication", "Server", DEFAULT_AUTH_SERVER);
m_Address = IniFile.GetValueSet("Authentication", "Address", DEFAULT_AUTH_ADDRESS);
m_Server = IniFile.GetValueSet ("Authentication", "Server", DEFAULT_AUTH_SERVER);
m_Address = IniFile.GetValueSet ("Authentication", "Address", DEFAULT_AUTH_ADDRESS);
m_ShouldAuthenticate = IniFile.GetValueSetB("Authentication", "Authenticate", true);
m_NameToUUIDServer = IniFile.GetValueSet ("Authentication", "NameToUUIDServer", DEFAULT_NAME_TO_UUID_SERVER);
m_NameToUUIDAddress = IniFile.GetValueSet ("Authentication", "NameToUUIDAddress", DEFAULT_NAME_TO_UUID_ADDRESS);
}
@ -151,6 +157,93 @@ void cAuthenticator::Stop(void)
AStringVector cAuthenticator::GetUUIDsFromPlayerNames(const AStringVector & a_PlayerNames)
{
AStringVector res;
// Create the request body - a JSON containing all the playernames:
Json::Value root;
for (AStringVector::const_iterator itr = a_PlayerNames.begin(), end = a_PlayerNames.end(); itr != end; ++itr)
{
Json::Value req(*itr);
root.append(req);
} // for itr - a_PlayerNames[]
Json::FastWriter Writer;
AString RequestBody = Writer.write(root);
// Create the HTTP request:
AString Request;
Request += "POST " + m_NameToUUIDAddress + " HTTP/1.1\r\n";
Request += "Host: " + m_NameToUUIDServer + "\r\n";
Request += "User-Agent: MCServer\r\n";
Request += "Connection: close\r\n";
Request += "Content-Type: application/json\r\n";
Request += Printf("Content-Length: %u\r\n", (unsigned)RequestBody.length());
Request += "\r\n";
Request += RequestBody;
// Get the response from the server:
AString Response;
if (!SecureGetFromAddress(StarfieldCACert(), m_NameToUUIDServer, Request, Response))
{
return res;
}
// Check the HTTP status line:
const AString Prefix("HTTP/1.1 200 OK");
AString HexDump;
if (Response.compare(0, Prefix.size(), Prefix))
{
LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__);
LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return res;
}
// Erase the HTTP headers from the response:
size_t idxHeadersEnd = Response.find("\r\n\r\n");
if (idxHeadersEnd == AString::npos)
{
LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__);
LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return res;
}
Response.erase(0, idxHeadersEnd + 4);
// Parse the returned string into Json:
Json::Reader reader;
if (!reader.parse(Response, root, false) || !root.isArray())
{
LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__);
LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return res;
}
// Fill in the resulting array; do not expect to get the UUIDs in the same order as the inputs:
size_t len = a_PlayerNames.size();
size_t JsonCount = root.size();
res.resize(len);
for (size_t idx = 0; idx < len; idx++) // For each input username...
{
const AString & InputName = a_PlayerNames[idx];
for (size_t IdxJson = 0; IdxJson < JsonCount; ++IdxJson)
{
Json::Value & Val = root[IdxJson];
AString JsonName = Val.get("name", "").asString();
if (NoCaseCompare(JsonName, InputName) == 0)
{
res[idx] = Val.get("id", "").asString();
break;
}
} // for IdxJson - root[]
} // for idx - a_PlayerNames[] / res[]
return res;
}
void cAuthenticator::Execute(void)
{
for (;;)
@ -307,7 +400,7 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
a_UUID = root.get("id", "").asString();
a_Properties = root["properties"];
// If the UUID doesn't contain the hashes, insert them at the proper places:
// If the UUID doesn't contain the dashes, insert them at the proper places:
if (a_UUID.size() == 32)
{
a_UUID.insert(8, "-");

View File

@ -52,6 +52,12 @@ public:
/** Stops the authenticator thread. The thread may be started and stopped repeatedly */
void Stop(void);
/** Converts the player names into UUIDs.
a_PlayerName[idx] will be converted to UUID and returned as idx-th value
The UUID will be empty on error.
Blocking operation, do not use in world-tick thread! */
AStringVector GetUUIDsFromPlayerNames(const AStringVector & a_PlayerName);
private:
@ -76,8 +82,22 @@ private:
cUserList m_Queue;
cEvent m_QueueNonempty;
/** The server that is to be contacted for auth / UUID conversions */
AString m_Server;
/** The URL to use for auth, without server part.
%USERNAME% will be replaced with actual user name.
%SERVERID% will be replaced with server's ID.
For example "/session/minecraft/hasJoined?username=%USERNAME%&serverId=%SERVERID%". */
AString m_Address;
/** The server to connect to when converting player names to UUIDs. For example "api.mojang.com". */
AString m_NameToUUIDServer;
/** The URL to use for converting player names to UUIDs, without server part.
For example "/profiles/page/1". */
AString m_NameToUUIDAddress;
AString m_PropertiesAddress;
bool m_ShouldAuthenticate;