#include "stdafx.h" bool CSteamProto::IsOnline() { return m_iStatus > ID_STATUS_OFFLINE && m_hPollingThread; } bool CSteamProto::IsMe(const char *steamId) { ptrA mySteamId(getStringA("SteamID")); if (!lstrcmpA(steamId, mySteamId)) return true; return false; } void CSteamProto::OnGotRsaKey(const NETLIBHTTPREQUEST *response) { if (response == NULL) return; // load rsa key parts JSONNode root = JSONNode::parse(response->pData); if (!root) return; if (!root["success"].as_bool()) return; std::string modulus = root["publickey_mod"].as_string(); // exponent "010001" is used as constant in CSteamProto::RsaEncrypt //std::string exponent = root["publickey_exp"].as_string(); std::string timestamp = root["timestamp"].as_string(); // encrcrypt password ptrA base64RsaEncryptedPassword; ptrA password(getStringA("Password")); DWORD error = 0; DWORD encryptedSize = 0; if ((error = RsaEncrypt(modulus.c_str(), password, NULL, encryptedSize)) != 0) { debugLogA("CSteamProto::OnGotRsaKey: encryption error (%lu)", error); return; } BYTE *encryptedPassword = (BYTE*)mir_calloc(encryptedSize); if ((error = RsaEncrypt(modulus.c_str(), password, encryptedPassword, encryptedSize)) != 0) { debugLogA("CSteamProto::OnGotRsaKey: encryption error (%lu)", error); return; } base64RsaEncryptedPassword = mir_base64_encode(encryptedPassword, encryptedSize); mir_free(encryptedPassword); // run authorization request T2Utf username(getTStringA("Username")); ptrA guardId(getStringA("GuardId")); if (!guardId) guardId = mir_strdup(""); ptrA guardCode(getStringA("GuardCode")); if (!guardCode) guardCode = mir_strdup(""); ptrA captchaId(getStringA("CaptchaId")); if (!captchaId) captchaId = mir_strdup("-1"); ptrA captchaText(getStringA("CaptchaText")); if (!captchaText) captchaText = mir_strdup(""); PushRequest( new AuthorizationRequest(username, base64RsaEncryptedPassword, timestamp.c_str(), "", guardCode, guardId, captchaId, captchaText), &CSteamProto::OnAuthorization); } void CSteamProto::OnAuthorization(const NETLIBHTTPREQUEST *response) { if (response == NULL) { SetStatus(ID_STATUS_OFFLINE); return; } JSONNode root = JSONNode::parse(response->pData); if (!root) { SetStatus(ID_STATUS_OFFLINE); return; } if (!root["success"].as_bool()) { OnAuthorizationError(root); return; } OnAuthorizationSuccess(root); } void CSteamProto::OnAuthorizationError(const JSONNode &node) { std::string message = node["message"].as_string(); ptrT messageT(mir_utf8decodeT(message.c_str())); if (!mir_tstrcmpi(messageT, _T("Incorrect login."))) { // We can't continue with incorrect login/password delSetting("GuardId"); delSetting("GuardCode"); delSetting("CaptchaId"); delSetting("CaptchaText"); SetStatus(ID_STATUS_OFFLINE); return; } T2Utf username(getTStringA("Username")); if (node["requires_twofactor"].as_bool()) { return; } if (node["emailauth_needed"].as_bool()) { std::string guardId = node["emailsteamid"].as_string(); ptrA oldGuardId(getStringA("GuardId")); if (mir_strcmp(guardId.c_str(), oldGuardId) == 0) { delSetting("GuardId"); delSetting("GuardCode"); PushRequest( new GetRsaKeyRequest(username), &CSteamProto::OnGotRsaKey); return; } std::string domain = node["emaildomain"].as_string(); CSteamGuardDialog guardDialog(this, domain.c_str()); if (!guardDialog.DoModal()) { delSetting("GuardId"); delSetting("GuardCode"); delSetting("CaptchaId"); delSetting("CaptchaText"); SetStatus(ID_STATUS_OFFLINE); return; } setString("GuardId", guardId.c_str()); setString("GuardCode", guardDialog.GetGuardCode()); PushRequest( new GetRsaKeyRequest(username), &CSteamProto::OnGotRsaKey); return; } if (node["captcha_needed"].as_bool()) { std::string captchaId = node["captcha_gid"].as_string(); GetCaptchaRequest *request = new GetCaptchaRequest(captchaId.c_str()); NETLIBHTTPREQUEST *response = request->Send(m_hNetlibUser); delete request; CSteamCaptchaDialog captchaDialog(this, (BYTE*)response->pData, response->dataLength); CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)response); if (!captchaDialog.DoModal()) { delSetting("CaptchaId"); delSetting("CaptchaText"); SetStatus(ID_STATUS_OFFLINE); return; } setString("CaptchaId", captchaId.c_str()); setString("CaptchaText", captchaDialog.GetCaptchaText()); PushRequest( new GetRsaKeyRequest(username), &CSteamProto::OnGotRsaKey); return; } delSetting("GuardId"); delSetting("GuardCode"); delSetting("CaptchaId"); delSetting("CaptchaText"); SetStatus(ID_STATUS_OFFLINE); } void CSteamProto::OnAuthorizationSuccess(const JSONNode &node) { delSetting("GuardId"); delSetting("GuardCode"); delSetting("CaptchaId"); delSetting("CaptchaText"); if (!node["login_complete"].as_bool()) { SetStatus(ID_STATUS_OFFLINE); return; } std::string oauth = node["oauth"].as_string(); JSONNode root = JSONNode::parse(oauth.c_str()); if (!root) { SetStatus(ID_STATUS_OFFLINE); return; } std::string steamId = root["steamid"].as_string(); setString("SteamID", steamId.c_str()); std::string token = root["oauth_token"].as_string(); setString("TokenSecret", token.c_str()); std::string cookie = root["webcookie"].as_string(); PushRequest( new GetSessionRequest(token.c_str(), steamId.c_str(), cookie.c_str()), &CSteamProto::OnGotSession); PushRequest( new LogonRequest(token.c_str()), &CSteamProto::OnLoggedOn); } void CSteamProto::OnGotSession(const NETLIBHTTPREQUEST *response) { if(response == NULL) return; for (int i = 0; i < response->headersCount; i++) { if (lstrcmpiA(response->headers[i].szName, "Set-Cookie")) continue; std::string cookies = response->headers[i].szValue; size_t start = cookies.find("sessionid=") + 10; size_t end = cookies.substr(start).find(';'); std::string sessionId = cookies.substr(start, end - start + 10); setString("SessionID", sessionId.c_str()); break; } } void CSteamProto::HandleTokenExpired() { // Notify error to user ShowNotification(_T("Steam"), TranslateT("Connection token expired. Please login again.")); // Delete expired token delSetting("TokenSecret"); // Set status to offline SetStatus(ID_STATUS_OFFLINE); } void CSteamProto::OnLoggedOn(const NETLIBHTTPREQUEST *response) { if (response == NULL) { // Probably timeout or no connection, we can do nothing here SetStatus(ID_STATUS_OFFLINE); return; } JSONROOT root(response->pData); JSONNODE *node = json_get(root, "error"); ptrT error(json_as_string(node)); if (mir_tstrcmpi(error, _T("OK")) || response->resultCode == HTTP_STATUS_UNAUTHORIZED) { // Probably expired TokenSecret HandleTokenExpired(); return; } node = json_get(root, "umqid"); setString("UMQID", ptrA(mir_u2a(ptrT(json_as_string(node))))); node = json_get(root, "message"); setDword("MessageID", json_as_int(node)); // load contact list ptrA token(getStringA("TokenSecret")); ptrA steamId(getStringA("SteamID")); PushRequest( new GetFriendListRequest(token, steamId), &CSteamProto::OnGotFriendList); // start polling thread m_hPollingThread = ForkThreadEx(&CSteamProto::PollingThread, 0, NULL); // go to online now ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iStatus = m_iDesiredStatus); }