diff options
| author | George Hazan <george.hazan@gmail.com> | 2023-06-15 19:18:04 +0300 |
|---|---|---|
| committer | George Hazan <george.hazan@gmail.com> | 2023-06-15 19:18:04 +0300 |
| commit | 4a2a1a80bc29ec2dc13e8dd053671431eb36fe2a (patch) | |
| tree | 24a8d499cbbdaa1e998b289eebce7e918fda8fdc /protocols/Steam/src/steam_login.cpp | |
| parent | d85347f1f2028afb685142a776f2af4473de8273 (diff) | |
Steam: complete login sequence (though always gives us "Invalid password" error)
Diffstat (limited to 'protocols/Steam/src/steam_login.cpp')
| -rw-r--r-- | protocols/Steam/src/steam_login.cpp | 422 |
1 files changed, 174 insertions, 248 deletions
diff --git a/protocols/Steam/src/steam_login.cpp b/protocols/Steam/src/steam_login.cpp index 44b419a5f6..6bf3bfb89e 100644 --- a/protocols/Steam/src/steam_login.cpp +++ b/protocols/Steam/src/steam_login.cpp @@ -1,138 +1,6 @@ #include "stdafx.h" -bool CSteamProto::IsOnline() -{ - return m_iStatus > ID_STATUS_OFFLINE && m_hServerConn != nullptr; -} - -bool CSteamProto::IsMe(const char *steamId) -{ - ptrA mySteamId(getStringA("SteamID")); - return mir_strcmp(steamId, mySteamId) == 0; -} - -void CSteamProto::Login() -{ - CMsgClientHello hello; - hello.protocol_version = STEAM_PROTOCOL_VERSION; hello.has_protocol_version = true; - WSSend(EMsg::ClientHello, hello); - - ptrA token(getStringA("TokenSecret")); - ptrA sessionId(getStringA("SessionID")); - if (mir_strlen(token) > 0 && mir_strlen(sessionId) > 0) { - SendRequest(new LogonRequest(token), &CSteamProto::OnLoggedOn); - return; - } - - T2Utf username(getWStringA("Username")); - if (username == NULL) - LoginFailed(); - else { - CAuthenticationGetPasswordRSAPublicKeyRequest request; - request.account_name = username.get(); - WSSendService("Authentication.GetPasswordRSAPublicKey#1", request); - } -} - -void CSteamProto::LoginFailed() -{ - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_FAILED, (HANDLE)m_iStatus, m_iStatus); -} - -void CSteamProto::Logout() -{ - ptrA token(getStringA("TokenSecret")); - if (mir_strlen(token) > 0) { - ptrA umqid(getStringA("UMQID")); - SendRequest(new LogoffRequest(token, umqid)); - } - - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iStatus); -} - -void CSteamProto::OnGotHosts(const JSONNode &root, void*) -{ - db_delete_module(0, STEAM_MODULE); - - int i = 0; - CMStringA szSetting; - for (auto &it : root["response"]["serverlist_websockets"]) { - szSetting.Format("Host%d", i++); - db_set_ws(0, STEAM_MODULE, szSetting, it.as_mstring()); - } - - db_set_dw(0, STEAM_MODULE, DBKEY_HOSTS_COUNT, i); - db_set_dw(0, STEAM_MODULE, DBKEY_HOSTS_DATE, time(0)); -} - -void CSteamProto::OnGotRsaKey(const JSONNode &root, void *) -{ - if (root.isnull()) { - SetStatus(ID_STATUS_OFFLINE); - return; - } - - if (!root["success"].as_bool()) { - SetStatus(ID_STATUS_OFFLINE); - return; - } - - // load rsa key parts - json_string modulus = root["publickey_mod"].as_string(); - json_string exp = root["publickey_exp"].as_string(); - DWORD exponent = strtoul(exp.c_str(), nullptr, 16); // default "010001" = 0x10001 - - json_string timestamp = root["timestamp"].as_string(); - - // encrcrypt password - ptrA base64RsaEncryptedPassword; - ptrA szPassword(getStringA("Password")); - - DWORD error = 0; - DWORD encryptedSize = 0; - if ((error = RsaEncrypt(modulus.c_str(), exponent, szPassword, nullptr, encryptedSize)) != 0) { - debugLogA(__FUNCTION__ ": encryption error (%lu)", error); - SetStatus(ID_STATUS_OFFLINE); - return; - } - - uint8_t *encryptedPassword = (uint8_t *)mir_calloc(encryptedSize); - if ((error = RsaEncrypt(modulus.c_str(), exponent, szPassword, encryptedPassword, encryptedSize)) != 0) { - debugLogA(__FUNCTION__ ": encryption error (%lu)", error); - SetStatus(ID_STATUS_OFFLINE); - return; - } - - base64RsaEncryptedPassword = mir_base64_encode(encryptedPassword, encryptedSize); - mir_free(encryptedPassword); - - // run authorization request - T2Utf username(getWStringA("Username")); - - ptrA twoFactorCode(getStringA("TwoFactorCode")); - if (!twoFactorCode) - twoFactorCode = mir_strdup(""); - - 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(""); - - SendRequest( - new AuthorizationRequest(username, base64RsaEncryptedPassword, timestamp.c_str(), twoFactorCode, guardCode, guardId, captchaId, captchaText), - &CSteamProto::OnAuthorization); -} - +/* void CSteamProto::OnGotCaptcha(const HttpResponse &response, void *arg) { ptrA captchaId((char *)arg); @@ -142,7 +10,7 @@ void CSteamProto::OnGotCaptcha(const HttpResponse &response, void *arg) return; } - CSteamCaptchaDialog captchaDialog(this, (const uint8_t*)response.data(), response.length()); + CSteamCaptchaDialog captchaDialog(this, (const uint8_t *)response.data(), response.length()); if (!captchaDialog.DoModal()) { DeleteAuthSettings(); SetStatus(ID_STATUS_OFFLINE); @@ -152,38 +20,8 @@ void CSteamProto::OnGotCaptcha(const HttpResponse &response, void *arg) setString("CaptchaId", captchaId); setString("CaptchaText", captchaDialog.GetCaptchaText()); - T2Utf username(getWStringA("Username")); - SendRequest(new GetRsaKeyRequest(username), &CSteamProto::OnGotRsaKey); -} - -void CSteamProto::OnAuthorization(const HttpResponse &response, void *) -{ - if (!response) { - SetStatus(ID_STATUS_OFFLINE); - return; - } - - JSONNode root = JSONNode::parse(response.data()); - if (root.isnull()) { - SetStatus(ID_STATUS_OFFLINE); - return; - } - - if (!root["success"].as_bool()) { - OnAuthorizationError(root); - return; - } - - OnAuthorizationSuccess(root); -} - -void CSteamProto::DeleteAuthSettings() -{ - delSetting("TwoFactorCode"); - delSetting("GuardId"); - delSetting("GuardCode"); - delSetting("CaptchaId"); - delSetting("CaptchaText"); + ptrA username(getUStringA("Username")); + // SendRequest(new GetRsaKeyRequest(username), &CSteamProto::OnGotRsaKey); } void CSteamProto::OnAuthorizationError(const JSONNode &root) @@ -222,7 +60,7 @@ void CSteamProto::OnAuthorizationError(const JSONNode &root) setString("TwoFactorCode", twoFactorDialog.GetTwoFactorCode()); - SendRequest(new GetRsaKeyRequest(username), &CSteamProto::OnGotRsaKey); + // SendRequest(new GetRsaKeyRequest(username), &CSteamProto::OnGotRsaKey); } if (root["emailauth_needed"].as_bool()) { @@ -254,7 +92,7 @@ void CSteamProto::OnAuthorizationError(const JSONNode &root) setString("GuardId", guardId.c_str()); setString("GuardCode", guardDialog.GetGuardCode()); - SendRequest(new GetRsaKeyRequest(username), &CSteamProto::OnGotRsaKey); + // SendRequest(new GetRsaKeyRequest(username), &CSteamProto::OnGotRsaKey); return; } @@ -272,134 +110,222 @@ void CSteamProto::OnAuthorizationError(const JSONNode &root) SetStatus(ID_STATUS_OFFLINE); ShowNotification(message); } +*/ -void CSteamProto::OnAuthorizationSuccess(const JSONNode &root) +void CSteamProto::DeleteAuthSettings() { - DeleteAuthSettings(); + delSetting("TwoFactorCode"); + delSetting("GuardId"); + delSetting("GuardCode"); + delSetting("CaptchaId"); + delSetting("CaptchaText"); +} - if (!root["login_complete"].as_bool()) { - SetStatus(ID_STATUS_OFFLINE); +bool CSteamProto::IsOnline() +{ + return m_iStatus > ID_STATUS_OFFLINE && m_hServerConn != nullptr; +} + +bool CSteamProto::IsMe(const char *steamId) +{ + ptrA mySteamId(getStringA(DBKEY_STEAM_ID)); + return mir_strcmp(steamId, mySteamId) == 0; +} + +void CSteamProto::Login() +{ + CMsgClientHello hello; + hello.protocol_version = STEAM_PROTOCOL_VERSION; hello.has_protocol_version = true; + WSSend(EMsg::ClientHello, hello); + + ptrA token(getStringA("TokenSecret")); + ptrA sessionId(getStringA("SessionID")); + if (mir_strlen(token) > 0 && mir_strlen(sessionId) > 0) { + // SendRequest(new LogonRequest(token), &CSteamProto::OnLoggedOn); return; } - json_string oauth = root["oauth"].as_string(); - JSONNode node = JSONNode::parse(oauth.c_str()); - if (node.isnull()) { - SetStatus(ID_STATUS_OFFLINE); - return; + ptrA username(getUStringA("Username")); + if (username == NULL) + LoginFailed(); + else { + CAuthenticationGetPasswordRSAPublicKeyRequest request; + request.account_name = username.get(); + WSSendService("Authentication.GetPasswordRSAPublicKey#1", request, &CSteamProto::OnGotRsaKey); } +} - json_string steamId = node["steamid"].as_string(); - setString("SteamID", steamId.c_str()); +void CSteamProto::LoginFailed() +{ + m_bTerminated = true; - json_string token = node["oauth_token"].as_string(); - setString("TokenSecret", token.c_str()); + m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iStatus); +} - SendRequest(new GetSessionRequest2(token.c_str(), steamId.c_str()), &CSteamProto::OnGotSession); +void CSteamProto::Logout() +{ + m_bTerminated = true; - SendRequest(new LogonRequest(token.c_str()), &CSteamProto::OnLoggedOn); + ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iStatus); } -void CSteamProto::OnGotSession(const HttpResponse &response, void *) +void CSteamProto::OnGotHosts(const JSONNode &root, void*) { - if (!response) { - debugLogA(__FUNCTION__ ": failed to get session id"); - return; - } - - for (auto &header : response.Headers()) { - if (mir_strcmpi(header->szName, "Set-Cookie")) - continue; + db_delete_module(0, STEAM_MODULE); - std::string cookies = header->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; + int i = 0; + CMStringA szSetting; + for (auto &it : root["response"]["serverlist_websockets"]) { + szSetting.Format("Host%d", i++); + db_set_ws(0, STEAM_MODULE, szSetting, it.as_mstring()); } + + db_set_dw(0, STEAM_MODULE, DBKEY_HOSTS_COUNT, i); + db_set_dw(0, STEAM_MODULE, DBKEY_HOSTS_DATE, time(0)); } -void CSteamProto::HandleTokenExpired() +void CSteamProto::OnGotRsaKey(const uint8_t *buf, size_t cbLen) { - // Delete expired token - delSetting("TokenSecret"); - - // Try to relogin automatically (but only once) - if (isLoginAgain) { - // Notify error to user - debugLogA(__FUNCTION__ ": cannot obtain connection token"); - ShowNotification(TranslateT("Cannot obtain connection token.")); - // Just go offline; it also resets the isLoginAgain to false - SetStatus(ID_STATUS_OFFLINE); + proto::AuthenticationGetPasswordRSAPublicKeyResponse reply(buf, cbLen); + if (reply == nullptr || !reply->publickey_exp || !reply->publickey_mod) { + LoginFailed(); return; } - // Remember we are trying to relogin - isLoginAgain = true; + // load rsa key parts + DWORD exponent = strtoul(reply->publickey_exp, nullptr, 16); // default "010001" = 0x10001 - Login(); -} + // encrypt password + ptrA szPassword(getStringA("Password")); -void CSteamProto::OnLoggedOn(const HttpResponse &response, void *) -{ - if (response.GetStatusCode() == HTTP_CODE_UNAUTHORIZED) { - // Probably expired TokenSecret + DWORD error = 0; + DWORD encryptedSize = 0; + if ((error = RsaEncrypt(reply->publickey_mod, exponent, szPassword, nullptr, encryptedSize)) != 0) { + debugLogA(__FUNCTION__ ": encryption error (%lu)", error); SetStatus(ID_STATUS_OFFLINE); - HandleTokenExpired(); return; } - if (!response.IsSuccess()) { - // Probably timeout or no connection, we can do nothing here - debugLogA(__FUNCTION__ ": unknown login error"); + uint8_t *encryptedPassword = (uint8_t *)mir_calloc(encryptedSize); + if ((error = RsaEncrypt(reply->publickey_mod, exponent, szPassword, encryptedPassword, encryptedSize)) != 0) { + debugLogA(__FUNCTION__ ": encryption error (%lu)", error); SetStatus(ID_STATUS_OFFLINE); return; } - JSONNode root = JSONNode::parse(response.data()); - json_string error = root["error"].as_string(); - if (error != "OK") { - // Probably expired TokenSecret - HandleTokenExpired(); + ptrA base64RsaEncryptedPassword(mir_base64_encode(encryptedPassword, encryptedSize)); + mir_free(encryptedPassword); + + // run authorization request + ptrA userName(getUStringA("Username")); + ptrA deviceName(getUStringA("DeviceName")); + + CAuthenticationDeviceDetails details; + details.device_friendly_name = deviceName.get(); + details.os_type = 1; details.has_os_type = true; + details.platform_type = EAUTH_TOKEN_PLATFORM_TYPE__k_EAuthTokenPlatformType_SteamClient; details.has_platform_type = true; + + CAuthenticationBeginAuthSessionViaCredentialsRequest request; + request.account_name = userName.get(); + request.device_friendly_name = deviceName.get(); + request.encrypted_password = base64RsaEncryptedPassword; + request.encryption_timestamp = reply->timestamp; request.has_encryption_timestamp = true; + request.persistence = ESESSION_PERSISTENCE__k_ESessionPersistence_Ephemeral; request.has_persistence = true; + request.platform_type = EAUTH_TOKEN_PLATFORM_TYPE__k_EAuthTokenPlatformType_SteamClient; request.has_platform_type = true; + request.remember_login = 0; request.has_remember_login = true; + request.device_details = &details; + + WSSendService("Authentication.BeginAuthSessionViaCredentials#1", request, &CSteamProto::OnAuthorization); +} + +void CSteamProto::OnAuthorization(const uint8_t *buf, size_t cbLen) +{ + proto::AuthenticationBeginAuthSessionViaCredentialsResponse reply(buf, cbLen); + if (reply == nullptr) { + LoginFailed(); return; } - json_string umqId = root["umqid"].as_string(); - setString("UMQID", umqId.c_str()); + // Success + if (reply->has_client_id && reply->has_steamid) { + DeleteAuthSettings(); + SetId(DBKEY_STEAM_ID, reply->steamid); + SetId(DBKEY_CLIENT_ID, reply->client_id); - long messageId = root["umqid"].as_int(); - setDword("MessageID", messageId); + CAuthenticationPollAuthSessionStatusRequest request; + request.client_id = reply->client_id; request.has_client_id = true; + request.request_id = reply->request_id; request.has_request_id = true; + WSSendService("Authentication.PollAuthSessionStatus#1", request, &CSteamProto::OnPollSession); + } + else { + debugLogA("Something went wrong: %s", reply->extended_error_message); + LoginFailed(); + } +} - // load contact list - ptrA token(getStringA("TokenSecret")); - ptrA steamId(getStringA("SteamID")); +void CSteamProto::OnPollSession(const uint8_t *buf, size_t cbLen) +{ + proto::AuthenticationPollAuthSessionStatusResponse reply(buf, cbLen); + if (reply == nullptr || !reply->access_token || !reply->refresh_token) { + LoginFailed(); + return; + } - SendRequest(new GetSessionRequest2(token, steamId), &CSteamProto::OnGotSession); + m_szAccessToken = reply->access_token; + m_szRefreshToken = reply->refresh_token; - // send this request immediately, so we can start polling thread with already loaded all contacts - SendRequest(new GetFriendListRequest(token, steamId, "friend,ignoredfriend,requestrecipient"), &CSteamProto::OnGotFriendList); + ptrA szAccountName(getUStringA(DBKEY_ACCOUNT_NAME)); + + MBinBuffer machineId(getBlob(DBKEY_MACHINE_ID)); + if (!machineId.length()) { + uint8_t random[100], hashOut[20]; + Utils_GetRandom(random, sizeof(random)); + mir_sha1_hash(random, sizeof(random), hashOut); - // go to online now - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iStatus = m_iDesiredStatus); + db_set_blob(0, m_szModuleName, DBKEY_MACHINE_ID, hashOut, sizeof(hashOut)); + machineId.append(hashOut, sizeof(hashOut)); + } + + CMsgIPAddress privateIp; + privateIp.ip_case = CMSG_IPADDRESS__IP_V4; + privateIp.v4 = 0; + + CMsgClientLogon request; + request.access_token = reply->access_token; + request.account_name = szAccountName.get(); + request.client_language = "english"; + request.client_os_type = 16; request.has_client_os_type = true; + request.should_remember_password = false; request.has_should_remember_password = true; + request.obfuscated_private_ip = &privateIp; + request.protocol_version = STEAM_PROTOCOL_VERSION; request.has_protocol_version = true; + request.supports_rate_limit_response = request.has_supports_rate_limit_response = true; + request.machine_name = ""; + request.steamguard_dont_remember_computer = false; request.has_steamguard_dont_remember_computer = true; + request.chat_mode = 2; request.has_chat_mode = true; + request.cell_id = 7; request.has_cell_id = true; + request.machine_id.data = machineId.data(); + request.machine_id.len = machineId.length(); + WSSend(EMsg::ClientLogon, request); } -void CSteamProto::OnReLogin(const JSONNode &root, void*) +void CSteamProto::OnLoggedOn(const uint8_t *buf, size_t cbLen) { - if (root.isnull()) { - SetStatus(ID_STATUS_OFFLINE); + proto::MsgClientLogonResponse reply(buf, cbLen); + if (reply == nullptr || !reply->has_eresult) { + LoginFailed(); return; } - json_string error = root["error"].as_string(); - if (error != "OK") { - SetStatus(ID_STATUS_OFFLINE); + if (reply->eresult != 1) { + debugLogA("Login failed with error %d", reply->eresult); + LoginFailed(); return; } - json_string umqId = root["umqid"].as_string(); - setString("UMQID", umqId.c_str()); + // go to online now + ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iStatus = m_iDesiredStatus); - long messageId = root["message"].as_int(); - setDword("MessageID", messageId); + // load contact list + // SendRequest(new GetFriendListRequest(token, steamId, "friend,ignoredfriend,requestrecipient"), &CSteamProto::OnGotFriendList); } |
