#include #include "auth3_server.hpp" #include "../keys.hpp" #include #include namespace demonware { namespace { #pragma pack(push, 1) struct auth_ticket { unsigned int m_magicNumber; char m_type; unsigned int m_titleID; unsigned int m_timeIssued; unsigned int m_timeExpires; unsigned __int64 m_licenseID; unsigned __int64 m_userID; char m_username[64]; char m_sessionKey[24]; char m_usingHashMagicNumber[3]; char m_hash[4]; }; #pragma pack(pop) } void auth3_server::send_reply(reply* data) { if (!data) return; this->send(data->data()); } void auth3_server::handle(const std::string& packet) { if (packet.starts_with("POST /auth/")) { #ifndef NDEBUG logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [auth]: user requested authentication."); #endif return; } unsigned int title_id = 0; unsigned int iv_seed = 0; std::string identity{}; std::string session_token{}; std::string account_token{}; rapidjson::Document j; j.Parse(packet.data(), packet.size()); if (j.HasMember("title_id") && j["title_id"].IsString()) { title_id = std::stoul(j["title_id"].GetString()); } if (j.HasMember("iv_seed") && j["iv_seed"].IsString()) { iv_seed = std::stoul(j["iv_seed"].GetString()); } if (j.HasMember("identity") && j["identity"].IsString()) { identity = j["identity"].GetString(); } if (j.HasMember("extra_data") && j["extra_data"].IsString()) { rapidjson::Document extra_data; auto& ed = j["extra_data"]; extra_data.Parse(ed.GetString(), ed.GetStringLength()); if (extra_data.HasMember("session_token") && extra_data["session_token"].IsString()) { auto& token_field = extra_data["session_token"]; std::string token_b64(token_field.GetString(), token_field.GetStringLength()); session_token = token_b64; } if (extra_data.HasMember("account_token") && extra_data["account_token"].IsString()) { auto& token_field = extra_data["account_token"]; std::string token_b64(token_field.GetString(), token_field.GetStringLength()); account_token = utilities::cryptography::base64::decode(token_b64); } } std::string session_key( "\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37", 24); // client_ticket auth_ticket ticket{}; std::memset(&ticket, 0x0, sizeof ticket); ticket.m_magicNumber = 0xEFBDADDE; ticket.m_type = 0; ticket.m_titleID = title_id; ticket.m_timeIssued = static_cast(time(nullptr)); ticket.m_timeExpires = ticket.m_timeIssued + 30000; ticket.m_licenseID = 0; ticket.m_userID = 0; strncpy_s(ticket.m_username, sizeof(ticket.m_username), session_token.data(), session_token.length()); std::memcpy(ticket.m_sessionKey, session_key.data(), 24); const auto client_ticket_b64 = utilities::cryptography::base64::encode(reinterpret_cast(&ticket), sizeof(ticket)); // server_ticket uint8_t server_ticket[128]; std::memset(&server_ticket, 0, sizeof server_ticket); std::memcpy(server_ticket, session_key.data(), 24); const auto server_ticket_b64 = utilities::cryptography::base64::encode(server_ticket, 128); demonware::set_session_key(session_key); // header time char date[64]; const auto now = time(nullptr); tm gmtm{}; gmtime_s(&gmtm, &now); strftime(date, 64, "%a, %d %b %G %T", &gmtm); rapidjson::Document extra; extra.SetObject(); std::string username = std::string(ticket.m_username, sizeof(ticket.m_username)).data(); extra.AddMember("username", username, extra.GetAllocator()); extra.AddMember("time_to_live", 9999, extra.GetAllocator()); const auto lul = utilities::cryptography::base64::encode("lul"); extra.AddMember("extended_data", lul, extra.GetAllocator()); rapidjson::StringBuffer extra_buffer{}; rapidjson::Writer> extra_writer(extra_buffer); extra.Accept(extra_writer); std::string extra_data{}; extra_data.append(extra_buffer.GetString(), extra_buffer.GetLength()); // json content rapidjson::Document doc; doc.SetObject(); doc.AddMember("auth_task", "85", doc.GetAllocator()); doc.AddMember("code", "700", doc.GetAllocator()); auto seed = std::to_string(iv_seed); doc.AddMember("iv_seed", seed, doc.GetAllocator()); doc.AddMember("client_ticket", client_ticket_b64, doc.GetAllocator()); doc.AddMember("server_ticket", server_ticket_b64, doc.GetAllocator()); doc.AddMember("client_id", "treyarch-cod-t8-bnet", doc.GetAllocator()); doc.AddMember("account_type", "bnet", doc.GetAllocator()); doc.AddMember("crossplay_enabled", false, doc.GetAllocator()); doc.AddMember("loginqueue_eanbled", false, doc.GetAllocator()); doc.AddMember("identity", identity, doc.GetAllocator()); doc.AddMember("extra_data", extra_data, doc.GetAllocator()); doc.AddMember("service_level", "paid", doc.GetAllocator()); rapidjson::Value value{}; doc.AddMember("lsg_endpoint", value, doc.GetAllocator()); rapidjson::StringBuffer buffer{}; rapidjson::Writer> writer(buffer); doc.Accept(writer); // http stuff std::string result; result.append("HTTP/1.1 200 OK\r\n"); result.append("Server: TornadoServer/4.5.3\r\n"); result.append("Content-Type: application/json\r\n"); result.append(utilities::string::va("Date: %s GMT\r\n", date)); result.append(utilities::string::va("Content-Length: %d\r\n\r\n", buffer.GetLength())); result.append(buffer.GetString(), buffer.GetLength()); raw_reply reply(result); this->send_reply(&reply); #ifndef NDEBUG logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [auth]: user successfully authenticated."); #endif } }