diff options
author | George Hazan <george.hazan@gmail.com> | 2024-12-15 15:50:25 +0300 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2024-12-15 15:50:25 +0300 |
commit | 4bbe001b15dec9cacd882ee55fe54f85c56a147f (patch) | |
tree | f181de7f9180492ac67a4a724697aad48eb6edb7 | |
parent | d2c72c9bf3492fd40960c2f0935c9c675795d28a (diff) |
Steam: service calls switched to static handlers
-rw-r--r-- | protocols/Steam/src/main.cpp | 31 | ||||
-rw-r--r-- | protocols/Steam/src/proto.h | 5 | ||||
-rw-r--r-- | protocols/Steam/src/protobuf-c/protobuf-c-text.cpp | 20 | ||||
-rw-r--r-- | protocols/Steam/src/stdafx.h | 1 | ||||
-rw-r--r-- | protocols/Steam/src/steam_login.cpp | 211 | ||||
-rw-r--r-- | protocols/Steam/src/steam_messages.cpp | 60 | ||||
-rw-r--r-- | protocols/Steam/src/steam_proto.cpp | 33 | ||||
-rw-r--r-- | protocols/Steam/src/steam_proto.h | 47 | ||||
-rw-r--r-- | protocols/Steam/src/steam_server.cpp | 33 | ||||
-rw-r--r-- | protocols/Steam/src/steam_utils.cpp | 39 | ||||
-rw-r--r-- | protocols/Steam/src/steam_ws.cpp | 115 |
11 files changed, 305 insertions, 290 deletions
diff --git a/protocols/Steam/src/main.cpp b/protocols/Steam/src/main.cpp index be3991d116..a39ce0aef5 100644 --- a/protocols/Steam/src/main.cpp +++ b/protocols/Steam/src/main.cpp @@ -32,15 +32,42 @@ extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOC /////////////////////////////////////////////////////////////////////////////////////////
+void CMPlugin::InitSteamServices()
+{
+ // services from steammessages_auth.steamclient.proto
+ services["Authentication"] = &authentication__descriptor;
+ services["AuthenticationSupport"] = &authentication_support__descriptor;
+
+ // services from steammessages_chat.steamclient.proto
+ services["Chat"] = &chat__descriptor;
+ services["ChatRoom"] = &chat_room__descriptor;
+ services["ChatRoomClient"] = &chat_room_client__descriptor;
+
+ // services from steammessages_friendmessages.steamclient.proto
+ services["FriendMessages"] = &friend_messages__descriptor;
+ services["FriendMessagesClient"] = &friend_messages_client__descriptor;
+
+ // static service handlers
+ serviceHandlers[PollAuthSessionStatus] = ServiceResponseHandler(&CSteamProto::OnPollSession);
+ serviceHandlers[GetPasswordRSAPublicKey] = ServiceResponseHandler(&CSteamProto::OnGotRsaKey);
+ serviceHandlers[BeginAuthSessionViaCredentials] = ServiceResponseHandler(&CSteamProto::OnBeginSession);
+ serviceHandlers[UpdateAuthSessionWithSteamGuardCode] = ServiceResponseHandler(&CSteamProto::OnGotConfirmationCode);
+
+ serviceHandlers[FriendSendMessage] = ServiceResponseHandler(&CSteamProto::OnMessageSent);
+}
+
int CMPlugin::Load()
{
+ InitSteamServices();
+
+ // extra statuses
char iconName[100];
mir_snprintf(iconName, "%s_%s", MODULE, "gaming");
+ hExtraXStatus = ExtraIcon_RegisterIcolib("steam_game", LPGEN("Steam game"), iconName);
- // extra statuses
HookEvent(ME_SKIN_ICONSCHANGED, OnReloadIcons);
- hExtraXStatus = ExtraIcon_RegisterIcolib("steam_game", LPGEN("Steam game"), iconName);
+ // menus
CSteamProto::InitMenus();
return 0;
}
diff --git a/protocols/Steam/src/proto.h b/protocols/Steam/src/proto.h index 2998d34d0f..fdb120452d 100644 --- a/protocols/Steam/src/proto.h +++ b/protocols/Steam/src/proto.h @@ -2143,9 +2143,4 @@ namespace proto PROTOBUF_PTR(MsgMulti, cmsg_multi__descriptor); PROTOBUF_PTR(MsgProtoBufHeader, cmsg_proto_buf_header__descriptor); PROTOBUF_PTR(MsgClientLogonResponse, cmsg_client_logon_response__descriptor); - PROTOBUF_PTR(FriendMessagesSendMessageResponse, cfriend_messages__send_message__response__descriptor); - PROTOBUF_PTR(AuthenticationGetPasswordRSAPublicKeyResponse, cauthentication__get_password_rsapublic_key__response__descriptor); - PROTOBUF_PTR(AuthenticationBeginAuthSessionViaCredentialsResponse, cauthentication__begin_auth_session_via_credentials__response__descriptor); - PROTOBUF_PTR(AuthenticationPollAuthSessionStatusResponse, cauthentication__poll_auth_session_status__response__descriptor); - PROTOBUF_PTR(AuthenticationUpdateAuthSessionWithSteamGuardCodeResponse, cauthentication__update_auth_session_with_steam_guard_code__response__descriptor); }; diff --git a/protocols/Steam/src/protobuf-c/protobuf-c-text.cpp b/protocols/Steam/src/protobuf-c/protobuf-c-text.cpp index c0438b6ac8..68e54f143e 100644 --- a/protocols/Steam/src/protobuf-c/protobuf-c-text.cpp +++ b/protocols/Steam/src/protobuf-c/protobuf-c-text.cpp @@ -330,18 +330,22 @@ static void protobuf_c_text_to_string_internal( if (f[i].label == PROTOBUF_C_LABEL_REPEATED) { for (j = 0; j < quantifier_offset; j++) { auto *member = STRUCT_MEMBER(ProtobufCBinaryData *, m, f[i].offset); - char *p = (char *)malloc(member->len * 2 + 1); - bin2hex(member->data, member->len, p); - str.AppendFormat("%*s%s: \"%s\"\n", level, "", f[i].name, p); - free(p); + if (member->len && member->data) { + char *p = (char *)malloc(member->len * 2 + 1); + bin2hex(member->data, member->len, p); + str.AppendFormat("%*s%s: \"%s\"\n", level, "", f[i].name, p); + free(p); + } } } else { auto member = STRUCT_MEMBER(ProtobufCBinaryData, m, f[i].offset); - char *p = (char *)malloc(member.len * 2 + 1); - bin2hex(member.data, member.len, p); - str.AppendFormat("%*s%s: \"%s\"\n", level, "", f[i].name, p); - free(p); + if (member.len && member.data) { + char *p = (char *)malloc(member.len * 2 + 1); + bin2hex(member.data, member.len, p); + str.AppendFormat("%*s%s: \"%s\"\n", level, "", f[i].name, p); + free(p); + } } break; diff --git a/protocols/Steam/src/stdafx.h b/protocols/Steam/src/stdafx.h index d14388ef70..8311086c3b 100644 --- a/protocols/Steam/src/stdafx.h +++ b/protocols/Steam/src/stdafx.h @@ -40,6 +40,7 @@ #include "version.h"
#include "protobuf-c/steammessages_auth.steamclient.pb-c.h"
+#include "protobuf-c/steammessages_chat.steamclient.pb-c.h"
#include "protobuf-c/steammessages_clientserver_login.pb-c.h"
#include "protobuf-c/steammessages_friendmessages.steamclient.pb-c.h"
#include "proto.h"
diff --git a/protocols/Steam/src/steam_login.cpp b/protocols/Steam/src/steam_login.cpp index e5476bb99c..33a8548554 100644 --- a/protocols/Steam/src/steam_login.cpp +++ b/protocols/Steam/src/steam_login.cpp @@ -62,21 +62,15 @@ void CSteamProto::Login() CAuthenticationGetPasswordRSAPublicKeyRequest request; request.account_name = username.get(); - WSSendService("Authentication.GetPasswordRSAPublicKey#1", request, &CSteamProto::OnGotRsaKey); + WSSendService(GetPasswordRSAPublicKey, request, true); } -void CSteamProto::OnGotRsaKey(const uint8_t *buf, size_t cbLen) +void CSteamProto::OnGotRsaKey(const CAuthenticationGetPasswordRSAPublicKeyResponse *pResponse) { - proto::AuthenticationGetPasswordRSAPublicKeyResponse reply(buf, cbLen); - if (reply == nullptr || !reply->publickey_exp || !reply->publickey_mod) { - Logout(); - return; - } - // encrypt password ptrA szPassword(getStringA("Password")); - MBinBuffer encPassword(RsaEncrypt(reply->publickey_mod, reply->publickey_exp, szPassword)); + MBinBuffer encPassword(RsaEncrypt(pResponse->publickey_mod, pResponse->publickey_exp, szPassword)); ptrA base64RsaEncryptedPassword(mir_base64_encode(encPassword.data(), encPassword.length())); // run authorization request @@ -93,7 +87,7 @@ void CSteamProto::OnGotRsaKey(const uint8_t *buf, size_t cbLen) request.account_name = userName.get(); request.website_id = "Client"; request.encrypted_password = base64RsaEncryptedPassword; - request.encryption_timestamp = reply->timestamp; request.has_encryption_timestamp = true; + request.encryption_timestamp = pResponse->timestamp; request.has_encryption_timestamp = true; request.persistence = ESESSION_PERSISTENCE__k_ESessionPersistence_Persistent; request.has_persistence = true; request.remember_login = request.has_remember_login = true; request.language = 1; request.has_language = true; @@ -104,7 +98,47 @@ void CSteamProto::OnGotRsaKey(const uint8_t *buf, size_t cbLen) request.platform_type = details.platform_type; request.has_platform_type = true; request.guard_data = machineId; - WSSendService("Authentication.BeginAuthSessionViaCredentials#1", request, &CSteamProto::OnBeginSession); + WSSendService(BeginAuthSessionViaCredentials, request, true); +} + +void CSteamProto::OnBeginSession(const CAuthenticationBeginAuthSessionViaCredentialsResponse *pResponse) +{ + if (pResponse->has_client_id && pResponse->has_steamid) { + DeleteAuthSettings(); + SetId(DBKEY_STEAM_ID, m_iSteamId = pResponse->steamid); + SetId(DBKEY_CLIENT_ID, m_iClientId = pResponse->client_id); + + if (pResponse->has_request_id) + m_requestId.append(pResponse->request_id.data, pResponse->request_id.len); + + for (int i = 0; i < pResponse->n_allowed_confirmations; i++) { + auto &conf = pResponse->allowed_confirmations[i]; + debugLogA("Confirmation required %d (%s)", conf->confirmation_type, conf->associated_message); + switch (conf->confirmation_type) { + case EAUTH_SESSION_GUARD_TYPE__k_EAuthSessionGuardType_None: // nothing to do + SendPollRequest(); + return; + + case EAUTH_SESSION_GUARD_TYPE__k_EAuthSessionGuardType_EmailCode: // email confirmation + CallFunctionSync(EnterEmailCode, this); + return; + + case EAUTH_SESSION_GUARD_TYPE__k_EAuthSessionGuardType_DeviceCode: // totp confirmation + CallFunctionSync(EnterTotpCode, this); + return; + } + + debugLogA("Unsupported confirmation code: %i", conf->confirmation_type); + Logout(); + } + + // no confirmation needed - we've done + SendPollRequest(); + } + else { + debugLogA("Something went wrong: %s", pResponse->extended_error_message); + Logout(); + } } ///////////////////////////////////////////////////////////////////////////////////////// @@ -139,14 +173,7 @@ INT_PTR CALLBACK CSteamProto::EnterTotpCode(void *param) return 0; } -void CSteamProto::OnGotConfirmationCode(const uint8_t *buf, size_t cbLen) -{ - proto::AuthenticationUpdateAuthSessionWithSteamGuardCodeResponse reply(buf, cbLen); - if (reply == nullptr) - Logout(); - else - SendPollRequest(); -} +///////////////////////////////////////////////////////////////////////////////////////// void CSteamProto::SendConfirmationCode(bool isEmail, const char *pszCode) { @@ -159,152 +186,34 @@ void CSteamProto::SendConfirmationCode(bool isEmail, const char *pszCode) request.code_type = EAUTH_SESSION_GUARD_TYPE__k_EAuthSessionGuardType_DeviceCode; request.has_code_type = true; request.code = (char*)pszCode; - WSSendService("Authentication.UpdateAuthSessionWithSteamGuardCode#1", request, &CSteamProto::OnGotConfirmationCode); + WSSendService(UpdateAuthSessionWithSteamGuardCode, request, true); } -///////////////////////////////////////////////////////////////////////////////////////// - -void CSteamProto::OnBeginSession(const uint8_t *buf, size_t cbLen) +void CSteamProto::OnGotConfirmationCode(const CAuthenticationUpdateAuthSessionWithSteamGuardCodeResponse*) { - proto::AuthenticationBeginAuthSessionViaCredentialsResponse reply(buf, cbLen); - if (reply == nullptr) { - Logout(); - return; - } - - // Success - m_bPollCanceled = false; - m_iPollingInterval = (reply->has_interval) ? reply->interval : 5; - - if (reply->has_client_id && reply->has_steamid) { - DeleteAuthSettings(); - SetId(DBKEY_STEAM_ID, m_iSteamId = reply->steamid); - SetId(DBKEY_CLIENT_ID, m_iClientId = reply->client_id); - - if (reply->has_request_id) - m_requestId.append(reply->request_id.data, reply->request_id.len); - - for (int i = 0; i < reply->n_allowed_confirmations; i++) { - auto &conf = reply->allowed_confirmations[i]; - debugLogA("Confirmation required %d (%s)", conf->confirmation_type, conf->associated_message); - switch (conf->confirmation_type) { - case EAUTH_SESSION_GUARD_TYPE__k_EAuthSessionGuardType_None: // nothing to do - SendPollRequest(); - return; - - case EAUTH_SESSION_GUARD_TYPE__k_EAuthSessionGuardType_EmailCode: // email confirmation - CallFunctionSync(EnterEmailCode, this); - return; - - case EAUTH_SESSION_GUARD_TYPE__k_EAuthSessionGuardType_DeviceCode: // totp confirmation - CallFunctionSync(EnterTotpCode, this); - return; - } - - debugLogA("Unsupported confirmation code: %i", conf->confirmation_type); - Logout(); - } - - // no confirmation needed - we've done - SendPollRequest(); - } - else { - debugLogA("Something went wrong: %s", reply->extended_error_message); - Logout(); - } + SendPollRequest(); } -void CSteamProto::CancelLoginAttempt() -{ - m_bPollCanceled = true; - m_impl.m_poll.Stop(); -} +///////////////////////////////////////////////////////////////////////////////////////// void CSteamProto::SendPollRequest() { - if (m_bPollCanceled) - return; - - m_impl.m_poll.Stop(); - - if (!m_iPollingStartTime) - m_iPollingStartTime = time(0); - - if (time(0) - m_iPollingStartTime >= 30) { - CancelLoginAttempt(); - return; - } - CAuthenticationPollAuthSessionStatusRequest request; request.client_id = GetId(DBKEY_CLIENT_ID); request.has_client_id = true; request.request_id.data = m_requestId.data(); request.request_id.len = m_requestId.length(); request.has_request_id = true; - WSSendService("Authentication.PollAuthSessionStatus#1", request, &CSteamProto::OnPollSession); + WSSendService(PollAuthSessionStatus, request, true); } -///////////////////////////////////////////////////////////////////////////////////////// - -static MBinBuffer createMachineID(const char *accName) +void CSteamProto::OnPollSession(const CAuthenticationPollAuthSessionStatusResponse *pResponse) { - uint8_t hashOut[MIR_SHA1_HASH_SIZE]; - char hashHex[MIR_SHA1_HASH_SIZE*2 + 1]; - - CMStringA _bb3 = CMStringA("SteamUser Hash BB3 ") + accName; - CMStringA _ff2 = CMStringA("SteamUser Hash FF2 ") + accName; - CMStringA _3b3 = CMStringA("SteamUser Hash 3B3 ") + accName; - - MBinBuffer ret; - uint8_t c = 0; - ret.append(&c, 1); - ret.append("MessageObject", 14); - - c = 1; - ret.append(&c, 1); - ret.append("BB3", 4); - mir_sha1_hash((uint8_t *)_bb3.c_str(), _bb3.GetLength(), hashOut); - bin2hex(hashOut, sizeof(hashOut), hashHex); - ret.append(hashHex, 41); - - ret.append(&c, 1); - ret.append("FF2", 4); - mir_sha1_hash((uint8_t *)_ff2.c_str(), _ff2.GetLength(), hashOut); - bin2hex(hashOut, sizeof(hashOut), hashHex); - ret.append(hashHex, 41); - - ret.append(&c, 1); - ret.append("3B3", 4); - mir_sha1_hash((uint8_t *)_3b3.c_str(), _3b3.GetLength(), hashOut); - bin2hex(hashOut, sizeof(hashOut), hashHex); - ret.append(hashHex, 41); - - ret.append("\x08\x08", 2); - return ret; -} - -void CSteamProto::OnPollSession(const uint8_t *buf, size_t cbLen) -{ - proto::AuthenticationPollAuthSessionStatusResponse reply(buf, cbLen); - if (reply == nullptr) { - Logout(); - return; - } + if (pResponse->has_new_client_id) + m_iClientId = pResponse->new_client_id; - if (reply->has_new_client_id) - m_iClientId = reply->new_client_id; + if (pResponse->new_guard_data) + setString("MachineId", pResponse->new_guard_data); - if (!reply->refresh_token) { - if (!m_bPollCanceled) - m_impl.m_poll.Start(m_iPollingInterval * 1000); - return; - } - - // stop polling - CancelLoginAttempt(); - - if (reply->new_guard_data) - setString("MachineId", reply->new_guard_data); - - m_szAccessToken = reply->access_token; - m_szRefreshToken = reply->refresh_token; + m_szAccessToken = pResponse->access_token; + m_szRefreshToken = pResponse->refresh_token; // sending logon packet ptrA szAccountName(getUStringA(DBKEY_ACCOUNT_NAME)), szPassword(getUStringA("Password")); @@ -316,7 +225,7 @@ void CSteamProto::OnPollSession(const uint8_t *buf, size_t cbLen) privateIp.v4 = 0; CMsgClientLogon request; - request.access_token = reply->refresh_token; + request.access_token = pResponse->refresh_token; request.machine_name = szMachineName; request.client_language = "english"; request.client_os_type = 16; request.has_client_os_type = true; @@ -339,6 +248,8 @@ void CSteamProto::OnClientLogon(const uint8_t *buf, size_t cbLen) return; } + debugLogA("client logged in\n%s", protobuf_c_text_to_string(*reply).c_str()); + if (reply->has_heartbeat_seconds) m_impl.m_heartBeat.Start(reply->heartbeat_seconds * 1000); diff --git a/protocols/Steam/src/steam_messages.cpp b/protocols/Steam/src/steam_messages.cpp index b5a89e3c8c..17da66fbb7 100644 --- a/protocols/Steam/src/steam_messages.cpp +++ b/protocols/Steam/src/steam_messages.cpp @@ -1,65 +1,5 @@ #include "stdafx.h"
-int CSteamProto::SendMsg(MCONTACT hContact, MEVENT, const char *message)
-{
- if (!IsOnline())
- return -1;
-
- UINT hMessage = InterlockedIncrement(&hMessageProcess);
- CMStringA szId(FORMAT, "%d", hMessage);
- {
- mir_cslock lck(m_csOwnMessages);
- m_arOwnMessages.insert(new COwnMessage(hContact, hMessage));
- }
-
- CFriendMessagesSendMessageRequest request;
- request.chat_entry_type = (int)EChatEntryType::ChatMsg; request.has_chat_entry_type = true;
- request.client_message_id = szId.GetBuffer();
- request.contains_bbcode = request.has_contains_bbcode = true;
- request.steamid = GetId(hContact, DBKEY_STEAM_ID); request.has_steamid = true;
- request.message = (char *)message;
- WSSendClient("FriendMessages.SendMessage#1", request, &CSteamProto::OnMessageSent);
-
- return hMessage;
-}
-
-void CSteamProto::OnMessageSent(const uint8_t *buf, size_t cbLen)
-{
- proto::FriendMessagesSendMessageResponse reply(buf, cbLen);
- if (!reply)
- return;
-
- COwnMessage *pOwn;
- {
- mir_cslock lck(m_csOwnMessages);
- pOwn = m_arOwnMessages.find((COwnMessage *)&reply->ordinal);
- }
-
- if (pOwn) {
- uint32_t timestamp = (reply->has_server_timestamp) ? reply->server_timestamp : 0;
- if (timestamp > getDword(pOwn->hContact, DB_KEY_LASTMSGTS))
- setDword(pOwn->hContact, DB_KEY_LASTMSGTS, timestamp);
-
- pOwn->timestamp = timestamp;
- ProtoBroadcastAck(pOwn->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)pOwn->iMessageId, 0);
- }
-}
-
-int CSteamProto::OnPreCreateMessage(WPARAM, LPARAM lParam)
-{
- MessageWindowEvent *evt = (MessageWindowEvent *)lParam;
- if (mir_strcmp(Proto_GetBaseAccountName(evt->hContact), m_szModuleName))
- return 0;
-
- mir_cslock lck(m_csOwnMessages);
- if (auto *pOwn = m_arOwnMessages.find((COwnMessage *)&evt->seq)) {
- evt->dbei->timestamp = pOwn->timestamp;
- m_arOwnMessages.remove(pOwn);
- }
-
- return 0;
-}
-
int CSteamProto::UserIsTyping(MCONTACT hContact, int type)
{
// NOTE: Steam doesn't support sending "user stopped typing" so we're sending only positive info
diff --git a/protocols/Steam/src/steam_proto.cpp b/protocols/Steam/src/steam_proto.cpp index c93951749f..14d79c8beb 100644 --- a/protocols/Steam/src/steam_proto.cpp +++ b/protocols/Steam/src/steam_proto.cpp @@ -224,6 +224,21 @@ HANDLE CSteamProto::SearchByName(const wchar_t *nick, const wchar_t *firstName, return (HANDLE)STEAM_SEARCH_BYNAME;
}
+int CSteamProto::SendMsg(MCONTACT hContact, MEVENT, const char *message)
+{
+ if (!IsOnline())
+ return -1;
+
+ UINT hMessage = InterlockedIncrement(&hMessageProcess);
+ {
+ mir_cslock lck(m_csOwnMessages);
+ m_arOwnMessages.insert(new COwnMessage(hContact, hMessage));
+ }
+
+ SendFriendMessage(hMessage, GetId(hContact, DBKEY_STEAM_ID), message);
+ return hMessage;
+}
+
int CSteamProto::SetStatus(int new_status)
{
// Routing statuses not supported by Steam
@@ -277,6 +292,8 @@ int CSteamProto::SetStatus(int new_status) return 0;
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
void CSteamProto::GetAwayMsgThread(void *arg)
{
// Maybe not needed, but better to be sure that this won't happen faster than core handling return value of GetAwayMsg()
@@ -305,6 +322,8 @@ HANDLE CSteamProto::GetAwayMsg(MCONTACT hContact) return (HANDLE)1;
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
bool CSteamProto::OnContactDeleted(MCONTACT hContact, uint32_t)
{
// remove only authorized contacts
@@ -315,3 +334,17 @@ bool CSteamProto::OnContactDeleted(MCONTACT hContact, uint32_t) }
return true;
}
+
+int CSteamProto::OnPreCreateMessage(WPARAM, LPARAM lParam)
+{
+ MessageWindowEvent *evt = (MessageWindowEvent *)lParam;
+ if (!mir_strcmp(Proto_GetBaseAccountName(evt->hContact), m_szModuleName)) {
+ mir_cslock lck(m_csOwnMessages);
+ if (auto *pOwn = m_arOwnMessages.find((COwnMessage *)&evt->seq)) {
+ evt->dbei->timestamp = pOwn->timestamp;
+ m_arOwnMessages.remove(pOwn);
+ }
+ }
+
+ return 0;
+}
diff --git a/protocols/Steam/src/steam_proto.h b/protocols/Steam/src/steam_proto.h index 0f56ba5e12..c69957cc99 100644 --- a/protocols/Steam/src/steam_proto.h +++ b/protocols/Steam/src/steam_proto.h @@ -16,6 +16,14 @@ #define DBKEY_STEAM_ID "SteamID"
#define DBKEY_ACCOUNT_NAME "Username"
+// Steam services
+#define PollAuthSessionStatus "Authentication.PollAuthSessionStatus#1"
+#define GetPasswordRSAPublicKey "Authentication.GetPasswordRSAPublicKey#1"
+#define BeginAuthSessionViaCredentials "Authentication.BeginAuthSessionViaCredentials#1"
+#define UpdateAuthSessionWithSteamGuardCode "Authentication.UpdateAuthSessionWithSteamGuardCode#1"
+
+#define FriendSendMessage "FriendMessages.SendMessage#1"
+
struct SendAuthParam
{
MCONTACT hContact;
@@ -71,6 +79,7 @@ struct COwnMessage class CSteamProto : public PROTO<CSteamProto>
{
+ friend struct CMPlugin;
friend class CSteamGuardDialog;
friend class CSteamPasswordEditor;
friend class CSteamOptionsMain;
@@ -83,11 +92,7 @@ class CSteamProto : public PROTO<CSteamProto> friend class CSteamProto;
CSteamProto &m_proto;
- CTimer m_poll, m_heartBeat;
- void OnPoll(CTimer *)
- {
- m_proto.SendPollRequest();
- }
+ CTimer m_heartBeat;
void OnHeartBeat(CTimer *)
{
@@ -96,17 +101,15 @@ class CSteamProto : public PROTO<CSteamProto> CProtoImpl(CSteamProto &pro) :
m_proto(pro),
- m_poll(Miranda_GetSystemWindow(), UINT_PTR(this)),
m_heartBeat(Miranda_GetSystemWindow(), UINT_PTR(this)+1)
{
- m_poll.OnEvent = Callback(this, &CProtoImpl::OnPoll);
m_heartBeat.OnEvent = Callback(this, &CProtoImpl::OnHeartBeat);
}
}
m_impl;
ptrW m_password;
- bool m_bTerminated, m_bPollCanceled;
+ bool m_bTerminated;
time_t m_idleTS;
int64_t m_iSteamId, m_iClientId, m_iSessionId;
MBinBuffer m_requestId;
@@ -121,8 +124,6 @@ class CSteamProto : public PROTO<CSteamProto> CMStringA m_szRefreshToken, m_szAccessToken;
ULONG hAuthProcess = 1;
ULONG hMessageProcess = 1;
- int m_iPollingInterval;
- time_t m_iPollingStartTime;
mir_cs m_addContactLock;
mir_cs m_setStatusLock;
@@ -137,11 +138,11 @@ class CSteamProto : public PROTO<CSteamProto> void ProcessMulti(const uint8_t *buf, size_t cbLen);
void ProcessMessage(const uint8_t *buf, size_t cbLen);
+ void ProcessServiceResponce(const uint8_t *buf, size_t cbLen, const char *pszServiceName);
void WSSend(EMsg msgType, const ProtobufCppMessage &msg);
void WSSendHeader(EMsg msgType, const CMsgProtoBufHeader &hdr, const ProtobufCppMessage &msg);
- void WSSendClient(const char *pszServiceName, const ProtobufCppMessage &msg, MsgCallback pCallback = 0);
- void WSSendService(const char *pszServiceName, const ProtobufCppMessage &msg, MsgCallback pCallback = 0);
+ void WSSendService(const char *pszServiceName, const ProtobufCppMessage &msg, bool bAnon = false);
// requests
bool SendRequest(HttpRequest *request);
@@ -150,6 +151,7 @@ class CSteamProto : public PROTO<CSteamProto> void SendHeartBeat();
void SendLogout();
+ void SendPollRequest();
// login
bool IsOnline();
@@ -161,18 +163,16 @@ class CSteamProto : public PROTO<CSteamProto> static INT_PTR CALLBACK EnterTotpCode(void *param);
static INT_PTR CALLBACK EnterEmailCode(void *param);
- void OnBeginSession(const uint8_t *buf, size_t cbLen);
+ void OnBeginSession(const CAuthenticationBeginAuthSessionViaCredentialsResponse *pResponse);
void OnClientLogon(const uint8_t *buf, size_t cbLen);
- void OnGotRsaKey(const uint8_t *buf, size_t cbLen);
- void OnGotConfirmationCode(const uint8_t *buf, size_t cbLen);
- void OnPollSession(const uint8_t *buf, size_t cbLen);
+ void OnGotRsaKey(const CAuthenticationGetPasswordRSAPublicKeyResponse *pResponse);
+ void OnGotConfirmationCode(const CAuthenticationUpdateAuthSessionWithSteamGuardCodeResponse *pResponse);
+ void OnPollSession(const CAuthenticationPollAuthSessionStatusResponse *pResponse);
void OnGotHosts(const JSONNode &root, void *);
- void CancelLoginAttempt();
void DeleteAuthSettings();
void SendConfirmationCode(bool, const char *pszCode);
- void SendPollRequest();
// contacts
void SetAllContactStatuses(int status);
@@ -215,7 +215,8 @@ class CSteamProto : public PROTO<CSteamProto> mir_cs m_csOwnMessages;
OBJLIST<COwnMessage> m_arOwnMessages;
- void OnMessageSent(const uint8_t *buf, size_t cbLen);
+ void SendFriendMessage(uint32_t msgId, int64_t steamId, const char *pszMessage);
+ void OnMessageSent(const CFriendMessagesSendMessageResponse *pResponse);
int __cdecl OnPreCreateMessage(WPARAM, LPARAM lParam);
// history
@@ -344,6 +345,13 @@ struct CMPlugin : public ACCPROTOPLUGIN<CSteamProto> {
CMPlugin();
+ void InitSteamServices();
+
+ std::map<std::string, const ProtobufCServiceDescriptor*> services;
+
+ typedef void (CSteamProto:: *ServiceResponseHandler)(const ProtobufCMessage *);
+ std::map<std::string, ServiceResponseHandler> serviceHandlers;
+
int Load() override;
};
@@ -351,5 +359,6 @@ int OnReloadIcons(WPARAM wParam, LPARAM lParam); void SetContactExtraIcon(MCONTACT hContact, int status);
MBinBuffer RsaEncrypt(const char *pszModulus, const char *exponent, const char *data);
+MBinBuffer createMachineID(const char *accName);
#endif //_STEAM_PROTO_H_
diff --git a/protocols/Steam/src/steam_server.cpp b/protocols/Steam/src/steam_server.cpp index c2d9469207..c6e50bf891 100644 --- a/protocols/Steam/src/steam_server.cpp +++ b/protocols/Steam/src/steam_server.cpp @@ -17,6 +17,39 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "stdafx.h" +void CSteamProto::SendFriendMessage(uint32_t msgId, int64_t steamId, const char *pszMessage) +{ + CMStringA szId(FORMAT, "%d", msgId); + + CFriendMessagesSendMessageRequest request; + request.chat_entry_type = (int)EChatEntryType::ChatMsg; request.has_chat_entry_type = true; + request.client_message_id = szId.GetBuffer(); + request.contains_bbcode = request.has_contains_bbcode = true; + request.steamid = steamId; request.has_steamid = true; + request.message = (char *)pszMessage; + WSSendService(FriendSendMessage, request); +} + +void CSteamProto::OnMessageSent(const CFriendMessagesSendMessageResponse *pResponse) +{ + COwnMessage *pOwn; + { + mir_cslock lck(m_csOwnMessages); + pOwn = m_arOwnMessages.find((COwnMessage *)&pResponse->ordinal); + } + + if (pOwn) { + uint32_t timestamp = (pResponse->has_server_timestamp) ? pResponse->server_timestamp : 0; + if (timestamp > getDword(pOwn->hContact, DB_KEY_LASTMSGTS)) + setDword(pOwn->hContact, DB_KEY_LASTMSGTS, timestamp); + + pOwn->timestamp = timestamp; + ProtoBroadcastAck(pOwn->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)pOwn->iMessageId, 0); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + void CSteamProto::SendHeartBeat() { CMsgClientHeartBeat packet; diff --git a/protocols/Steam/src/steam_utils.cpp b/protocols/Steam/src/steam_utils.cpp index 800abe47e8..ebc3c2b6f8 100644 --- a/protocols/Steam/src/steam_utils.cpp +++ b/protocols/Steam/src/steam_utils.cpp @@ -9,6 +9,45 @@ int64_t getRandomInt() /////////////////////////////////////////////////////////////////////////////////////////
+MBinBuffer createMachineID(const char *accName)
+{
+ uint8_t hashOut[MIR_SHA1_HASH_SIZE];
+ char hashHex[MIR_SHA1_HASH_SIZE * 2 + 1];
+
+ CMStringA _bb3 = CMStringA("SteamUser Hash BB3 ") + accName;
+ CMStringA _ff2 = CMStringA("SteamUser Hash FF2 ") + accName;
+ CMStringA _3b3 = CMStringA("SteamUser Hash 3B3 ") + accName;
+
+ MBinBuffer ret;
+ uint8_t c = 0;
+ ret.append(&c, 1);
+ ret.append("MessageObject", 14);
+
+ c = 1;
+ ret.append(&c, 1);
+ ret.append("BB3", 4);
+ mir_sha1_hash((uint8_t *)_bb3.c_str(), _bb3.GetLength(), hashOut);
+ bin2hex(hashOut, sizeof(hashOut), hashHex);
+ ret.append(hashHex, 41);
+
+ ret.append(&c, 1);
+ ret.append("FF2", 4);
+ mir_sha1_hash((uint8_t *)_ff2.c_str(), _ff2.GetLength(), hashOut);
+ bin2hex(hashOut, sizeof(hashOut), hashHex);
+ ret.append(hashHex, 41);
+
+ ret.append(&c, 1);
+ ret.append("3B3", 4);
+ mir_sha1_hash((uint8_t *)_3b3.c_str(), _3b3.GetLength(), hashOut);
+ bin2hex(hashOut, sizeof(hashOut), hashHex);
+ ret.append(hashHex, 41);
+
+ ret.append("\x08\x08", 2);
+ return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
int64_t CSteamProto::GetId(MCONTACT hContact, const char *pszSetting)
{
return _atoi64(getMStringA(hContact, pszSetting));
diff --git a/protocols/Steam/src/steam_ws.cpp b/protocols/Steam/src/steam_ws.cpp index bbf8a5b7a0..118a303a2d 100644 --- a/protocols/Steam/src/steam_ws.cpp +++ b/protocols/Steam/src/steam_ws.cpp @@ -123,42 +123,41 @@ void CSteamProto::ProcessMulti(const uint8_t *buf, size_t cbLen) void CSteamProto::ProcessMessage(const uint8_t *buf, size_t cbLen) { - Netlib_Dump(HNETLIBCONN(m_ws->getConn()), buf, cbLen, false, 0); - uint32_t dwSign = *(uint32_t *)buf; buf += sizeof(uint32_t); cbLen -= sizeof(uint32_t); EMsg msgType = (EMsg)(dwSign & ~STEAM_PROTOCOL_MASK); bool bIsProto = (dwSign & STEAM_PROTOCOL_MASK) != 0; - CMsgProtoBufHeader hdr; - if (msgType == EMsg::ChannelEncryptRequest || msgType == EMsg::ChannelEncryptResult) { + CMsgProtoBufHeader hdr; hdr.has_jobid_source = hdr.has_jobid_target = true; hdr.jobid_source = *(int64_t *)buf; buf += sizeof(int64_t); hdr.jobid_target = *(int64_t *)buf; buf += sizeof(int64_t); + debugLogA("encrypted results cannot be processed, ignoring"); + return; } - else if (bIsProto) { - uint32_t hdrLen = *(uint32_t *)buf; buf += sizeof(uint32_t); cbLen -= sizeof(uint32_t); - proto::MsgProtoBufHeader tmpHeader(buf, hdrLen); - if (tmpHeader == nullptr) { - debugLogA("Unable to decode message header, exiting"); - return; - } - - memcpy(&hdr, tmpHeader, sizeof(hdr)); - buf += hdrLen; cbLen -= hdrLen; - - if (hdr.has_client_sessionid) - m_iSessionId = hdr.client_sessionid; + + if (!bIsProto) { + debugLogA("Got unknown packet, exiting"); + Netlib_Dump(HNETLIBCONN(m_ws->getConn()), buf, cbLen, false, 0); + return; } - else { - debugLogA("Got unknown header, exiting"); + + uint32_t hdrLen = *(uint32_t *)buf; buf += sizeof(uint32_t); cbLen -= sizeof(uint32_t); + proto::MsgProtoBufHeader hdr(buf, hdrLen); + if (hdr == nullptr) { + debugLogA("Unable to decode message header, exiting"); return; } + buf += hdrLen; cbLen -= hdrLen; + + if (hdr->has_client_sessionid) + m_iSessionId = hdr->client_sessionid; + MsgCallback pCallback = 0; { mir_cslock lck(m_csRequests); - if (auto *pReq = m_arRequests.find((ProtoRequest *)&hdr.jobid_target)) { + if (auto *pReq = m_arRequests.find((ProtoRequest *)&hdr->jobid_target)) { pCallback = pReq->pCallback; m_arRequests.remove(pReq); } @@ -175,10 +174,57 @@ void CSteamProto::ProcessMessage(const uint8_t *buf, size_t cbLen) OnClientLogon(buf, cbLen); break; + case EMsg::ServiceMethodResponse: + ProcessServiceResponce(buf, cbLen, hdr->target_job_name); + break; + case EMsg::ClientLoggedOff: + debugLogA("received logout request"); Logout(); break; + + default: + Netlib_Dump(HNETLIBCONN(m_ws->getConn()), buf, cbLen, false, 0); + } +} + +void CSteamProto::ProcessServiceResponce(const uint8_t *buf, size_t cbLen, const char *pszServiceName) +{ + char *tmpName = NEWSTR_ALLOCA(pszServiceName); + char *p = strchr(tmpName, '.'); + if (!p) { + debugLogA("Invalid service function: %s", pszServiceName); + return; + } + + *p = 0; + auto it = g_plugin.services.find(tmpName); + if (it == g_plugin.services.end()) { + debugLogA("Unregistered service module: %s", tmpName); + return; + } + *p = '.'; + + auto pHandler = g_plugin.serviceHandlers.find(tmpName); + if (pHandler == g_plugin.serviceHandlers.end()) { + debugLogA("Unsupported service function: %s", pszServiceName); + return; + } + + if (char *p1 = strchr(++p, '#')) + *p1 = 0; + + if (auto *pMethod = protobuf_c_service_descriptor_get_method_by_name(it->second, p)) { + auto *pDescr = pMethod->output; + + if (auto *pMessage = protobuf_c_message_unpack(pDescr, 0, cbLen, buf)) { + debugLogA("Processing service message: %s\n%s", pszServiceName, protobuf_c_text_to_string(*pMessage).c_str()); + + (this->*(pHandler->second))(pMessage); + protobuf_c_message_free_unpacked(pMessage, 0); + } } + else debugLogA("Unregistered service method: %s", pszServiceName); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -225,37 +271,14 @@ void CSteamProto::WSSendHeader(EMsg msgType, const CMsgProtoBufHeader &hdr, cons m_ws->sendBinary(hdrbuf.data(), hdrbuf.length()); } -void CSteamProto::WSSendClient(const char *pszServiceName, const ProtobufCppMessage &msg, MsgCallback pCallback) +void CSteamProto::WSSendService(const char *pszServiceName, const ProtobufCppMessage &msg, bool bAnon) { CMsgProtoBufHeader hdr; hdr.has_client_sessionid = hdr.has_steamid = hdr.has_jobid_source = hdr.has_jobid_target = true; - hdr.client_sessionid = m_iSessionId; + hdr.client_sessionid = bAnon ? 0 : m_iSessionId; hdr.jobid_source = getRandomInt(); hdr.jobid_target = -1; hdr.target_job_name = (char *)pszServiceName; hdr.realm = 1; hdr.has_realm = true; - - if (pCallback) { - mir_cslock lck(m_csRequests); - m_arRequests.insert(new ProtoRequest(hdr.jobid_source, pCallback)); - } - - WSSendHeader(EMsg::ServiceMethodCallFromClient, hdr, msg); -} - -void CSteamProto::WSSendService(const char *pszServiceName, const ProtobufCppMessage &msg, MsgCallback pCallback) -{ - CMsgProtoBufHeader hdr; - hdr.has_client_sessionid = hdr.has_steamid = hdr.has_jobid_source = hdr.has_jobid_target = true; - hdr.jobid_source = getRandomInt(); - hdr.jobid_target = -1; - hdr.target_job_name = (char *)pszServiceName; - hdr.realm = 1; hdr.has_realm = true; - - if (pCallback) { - mir_cslock lck(m_csRequests); - m_arRequests.insert(new ProtoRequest(hdr.jobid_source, pCallback)); - } - - WSSendHeader(EMsg::ServiceMethodCallFromClientNonAuthed, hdr, msg); + WSSendHeader(bAnon ? EMsg::ServiceMethodCallFromClientNonAuthed : EMsg::ServiceMethodCallFromClient, hdr, msg); } |