summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2024-12-15 15:50:25 +0300
committerGeorge Hazan <george.hazan@gmail.com>2024-12-15 15:50:25 +0300
commit4bbe001b15dec9cacd882ee55fe54f85c56a147f (patch)
treef181de7f9180492ac67a4a724697aad48eb6edb7
parentd2c72c9bf3492fd40960c2f0935c9c675795d28a (diff)
Steam: service calls switched to static handlers
-rw-r--r--protocols/Steam/src/main.cpp31
-rw-r--r--protocols/Steam/src/proto.h5
-rw-r--r--protocols/Steam/src/protobuf-c/protobuf-c-text.cpp20
-rw-r--r--protocols/Steam/src/stdafx.h1
-rw-r--r--protocols/Steam/src/steam_login.cpp211
-rw-r--r--protocols/Steam/src/steam_messages.cpp60
-rw-r--r--protocols/Steam/src/steam_proto.cpp33
-rw-r--r--protocols/Steam/src/steam_proto.h47
-rw-r--r--protocols/Steam/src/steam_server.cpp33
-rw-r--r--protocols/Steam/src/steam_utils.cpp39
-rw-r--r--protocols/Steam/src/steam_ws.cpp115
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);
}