From 1f9219eb0abc61710a0ed5ddf0b23877be08360d Mon Sep 17 00:00:00 2001 From: Piotr Piastucki Date: Mon, 19 Oct 2015 23:49:45 +0000 Subject: MSN: Periodically refresh OAuth so that connection doesn't timeout with error 922 after 24 hours. git-svn-id: http://svn.miranda-ng.org/main/trunk@15573 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/MSN/src/msn_auth.cpp | 98 +++++++++++++++++++++++++++++++++++++- protocols/MSN/src/msn_commands.cpp | 73 ++++++++++------------------ protocols/MSN/src/msn_ieembed.cpp | 3 +- protocols/MSN/src/msn_proto.h | 7 ++- protocols/MSN/src/msn_threads.cpp | 10 ++++ 5 files changed, 139 insertions(+), 52 deletions(-) (limited to 'protocols/MSN') diff --git a/protocols/MSN/src/msn_auth.cpp b/protocols/MSN/src/msn_auth.cpp index 0485fd1ae0..35c9fd3b9e 100644 --- a/protocols/MSN/src/msn_auth.cpp +++ b/protocols/MSN/src/msn_auth.cpp @@ -158,6 +158,26 @@ int CMsnProto::MSN_GetPassportAuth(void) { int retVal = -1; + if (!bPassportAuth && authRefreshToken) { + // Slow authentication required by fetching multiple tokens, i.e. 2-factor auth :( + char szToken[1024]; + + if (authMethod == 2 && RefreshOAuth(authRefreshToken, "service::chatservice.live.com::MBI_SSL", szToken+2)) { + memcpy (szToken, "t=", 2); + replaceStr(authStrToken, szToken); + setString("authStrToken", authStrToken); + } + if (RefreshOAuth(authRefreshToken, "service::contacts.msn.com::MBI_SSL", szToken)) { + replaceStr(authContactToken, szToken); + setString("authContactToken", authContactToken); + } + if (RefreshOAuth(authRefreshToken, "service::storage.msn.com::MBI_SSL", szToken)) { + replaceStr(authStorageToken, szToken); + setString("authStorageToken", authStorageToken); + } + return 0; + } + char szPassword[100]; db_get_static(NULL, m_szModuleName, "Password", szPassword, sizeof(szPassword)); szPassword[16] = 0; @@ -666,6 +686,7 @@ void CMsnProto::LoadAuthTokensDB(void) authTokenExpiretime = getDword("authTokenExpiretime", 0); authMethod = getDword("authMethod", 0); + bPassportAuth = getByte("PassportAuth", true); if (getString("authUser", &dbv) == 0) { replaceStr(authUser, dbv.pszVal); db_free(&dbv); @@ -800,7 +821,7 @@ LRESULT CALLBACK AuthWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPar else pAuth->pszCookies = mir_u2a(pAuth->pEmbed->getCookies()); PostMessage(hwnd, WM_CLOSE, 0, 0); } - else if (wcsstr((WCHAR*)lParam, L"res=cancel")) { + else if (wcsstr((WCHAR*)lParam, L"res=cancel") || wcsstr((WCHAR*)lParam, L"access_denied")) { PostMessage(hwnd, WM_CLOSE, 0, 0); } return(0); @@ -887,6 +908,77 @@ bool CMsnProto::parseLoginPage(char *pszHTML, NETLIBHTTPREQUEST *nlhr, CMStringA return false; } +// -1 - Refresh failed +// 0 - No need to refresh +// 1 - Refresh succeeded +int CMsnProto::MSN_RefreshOAuthTokens(void) +{ + time_t t; + char szToken[1024], szRefreshToken[1024]; + bool bPassportAuthBak = bPassportAuth; + + if (!authTokenExpiretime || time(&t)+3600 < authTokenExpiretime) return 0; + + // Ensure that we won't be invoked twice + t = authTokenExpiretime; + authTokenExpiretime = 0x7FFFFFFF; + + bPassportAuth = false; + MSN_GetPassportAuth(); + bPassportAuth = bPassportAuthBak; + + if (authSSLToken && RefreshOAuth(authRefreshToken, "service::ssl.live.com::MBI_SSL", szToken)) { + replaceStr(authSSLToken, szToken); + setString("authSSLToken", authSSLToken); + } + + if (!RefreshOAuth(authRefreshToken, "service::skype.com::MBI_SSL", szToken, szRefreshToken, &authTokenExpiretime)) { + authTokenExpiretime = t; + return -1; + } + if (authSkypeComToken) replaceStr(authSkypeComToken, szToken); + replaceStr(authRefreshToken, szRefreshToken); + setDword("authTokenExpiretime", authTokenExpiretime); + setString("authRefreshToken", authRefreshToken); + + return 1; +} + +void CMsnProto::MSN_SendATH(ThreadData* info) +{ + if (MyOptions.netId!=NETID_SKYPE) { + /* MSN account login */ + + switch (authMethod) + { + case 1: + info->sendPacketPayload("ATH", "CON\\USER", + "t=%s" + "%s" + "%s%s\r\n", + authSSLToken ? ptrA(HtmlEncode(authSSLToken)) : "", + authUIC, + GetMyUsername(NETID_MSN), GetMyUsername(NETID_SKYPE)); + break; + + case 2: + info->sendPacketPayload("ATH", "CON\\USER", + "%s" + "%s" + "chatservice.live.com" + "\r\n", + authStrToken ? ptrA(HtmlEncode(authStrToken)) : "", + authUIC); + break; + } + + } else { + info->sendPacketPayload("ATH", "CON\\USER", + "%s%s\r\n", + authUIC, MyOptions.szEmail); + } +} + // -1 - Error on login sequence // 0 - Login failed (invalid username?) // 1 - Login via Skype login server succeeded @@ -894,7 +986,6 @@ bool CMsnProto::parseLoginPage(char *pszHTML, NETLIBHTTPREQUEST *nlhr, CMStringA int CMsnProto::MSN_AuthOAuth(void) { int retVal = -1; - bool bPassportAuth = true; NETLIBHTTPREQUEST nlhr = { 0 }; NETLIBHTTPREQUEST *nlhrReply; NETLIBHTTPHEADER headers[3]; @@ -952,6 +1043,8 @@ int CMsnProto::MSN_AuthOAuth(void) char *pszURL=NULL, *pAccessToken, *pEnd; hHttpsConnection = nlhrReply2->nlc; + bPassportAuth = true; + if (nlhrReply2->resultCode == 302) { /* Extract access_token from Location can be found */ for (int i = 0; i < nlhrReply2->headersCount; i++) { @@ -979,6 +1072,7 @@ int CMsnProto::MSN_AuthOAuth(void) bPassportAuth = false; } } + setByte("PassportAuth", bPassportAuth); CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)nlhrReply); nlhrReply = nlhrReply2; diff --git a/protocols/MSN/src/msn_commands.cpp b/protocols/MSN/src/msn_commands.cpp index 38539e0658..a55920569f 100644 --- a/protocols/MSN/src/msn_commands.cpp +++ b/protocols/MSN/src/msn_commands.cpp @@ -418,7 +418,7 @@ void CMsnProto::MSN_ProcessURIObject(MCONTACT hContact, ezxml_t xmli) if ((pszSkypeToken=GetSkypeToken(true)) && xmli) { /* FIXME: As soon as core has functions to POST images in a conversation AND gives the possibility to supply a - * callback for fetching thta image, this may be possible, but currently due to required Auth-Header, this + * callback for fetching that image, this may be possible, but currently due to required Auth-Header, this * is not possible and we just send an incoming file transfer const char *thumb = ezxml_attr(xmli, "url_thumbnail"); if (thumb && ServiceExists("IEVIEW/NewWindow")) { @@ -914,26 +914,28 @@ LBL_InvalidCommand: HReadBuffer buf(info, 0); buf.surelyRead(atol(data.strMsgBytes)); - if (!bSentBND) - { - info->sendPacketPayload("BND", "CON\\MSGR", - "%d%s%s%s" - "%.*s\r\n", - msnP24Ver, (msnP24Ver>1?"1":""), - msnStoreAppId, msnProductVer, - mir_strlen(MyOptions.szMachineGuid)-2, MyOptions.szMachineGuid+1); - bSentBND = true; - } - else - { - msnLoggedIn = true; - isConnectSuccess = true; - emailEnabled = MyOptions.netId==NETID_MSN; // Let's assume it? - MSN_SetServerStatus(m_iDesiredStatus); - MSN_EnableMenuItems(true); - // Fork refreshing and populating contact list to the background - ForkThread(&CMsnProto::msn_loginThread, NULL); - } + if (!bIgnoreATH) { + if (!bSentBND) + { + info->sendPacketPayload("BND", "CON\\MSGR", + "%d%s%s%s" + "%.*s\r\n", + msnP24Ver, (msnP24Ver>1?"1":""), + msnStoreAppId, msnProductVer, + mir_strlen(MyOptions.szMachineGuid)-2, MyOptions.szMachineGuid+1); + bSentBND = true; + } + else + { + msnLoggedIn = true; + isConnectSuccess = true; + emailEnabled = MyOptions.netId==NETID_MSN; // Let's assume it? + MSN_SetServerStatus(m_iDesiredStatus); + MSN_EnableMenuItems(true); + // Fork refreshing and populating contact list to the background + ForkThread(&CMsnProto::msn_loginThread, NULL); + } + } else bIgnoreATH = false; } break; @@ -985,29 +987,7 @@ LBL_InvalidCommand: if (MyOptions.netId!=NETID_SKYPE) { /* MSN account login */ - switch (MSN_AuthOAuth()) - { - case 1: - info->sendPacketPayload("ATH", "CON\\USER", - "t=%s" - "%s" - "%s%s\r\n", - authSSLToken ? ptrA(HtmlEncode(authSSLToken)) : "", - authUIC, - GetMyUsername(NETID_MSN), GetMyUsername(NETID_SKYPE)); - break; - - case 2: - info->sendPacketPayload("ATH", "CON\\USER", - "%s" - "%s" - "chatservice.live.com" - "\r\n", - authStrToken ? ptrA(HtmlEncode(authStrToken)) : "", - authUIC); - break; - - default: + if (MSN_AuthOAuth()<1) { m_iDesiredStatus = ID_STATUS_OFFLINE; return 1; } @@ -1020,12 +1000,11 @@ LBL_InvalidCommand: char szUIC[1024]={0}; MSN_SkypeAuth(xmlnonce->txt, szUIC); - info->sendPacketPayload("ATH", "CON\\USER", - "%s%s\r\n", - szUIC, MyOptions.szEmail); + replaceStr(authUIC, szUIC); } ezxml_free(xmlcnt); } + MSN_SendATH(info); bSentBND = false; if (!hKeepAliveThreadEvt) ForkThread(&CMsnProto::msn_keepAliveThread, NULL); diff --git a/protocols/MSN/src/msn_ieembed.cpp b/protocols/MSN/src/msn_ieembed.cpp index f231bbafed..996a531093 100644 --- a/protocols/MSN/src/msn_ieembed.cpp +++ b/protocols/MSN/src/msn_ieembed.cpp @@ -126,7 +126,8 @@ static LRESULT CALLBACK IEEmbedServerWindowProcedure(HWND hwnd, UINT message, WP break; */ case WM_KEYDOWN: - (*view)->translateAccelerator(message, wParam, lParam); + if (LOWORD(wParam) != VK_BACK) + (*view)->translateAccelerator(message, wParam, lParam); break; /* diff --git a/protocols/MSN/src/msn_proto.h b/protocols/MSN/src/msn_proto.h index d5dc0d0152..528be998a8 100644 --- a/protocols/MSN/src/msn_proto.h +++ b/protocols/MSN/src/msn_proto.h @@ -118,10 +118,10 @@ struct CMsnProto : public PROTO char *authStorageToken; char *hotSecretToken, *hotAuthToken; char *authUser, *authUIC, *authCookies, *authSSLToken, *authAccessToken, *authRefreshToken, *authSkypeComToken, *authSkypeToken; - bool bAskingForAuth; + bool bAskingForAuth, bPassportAuth; int authMethod; time_t authTokenExpiretime; - bool bSentBND; + bool bSentBND, bIgnoreATH; char *abCacheKey, *sharingCacheKey, *storageCacheKey; @@ -278,6 +278,7 @@ struct CMsnProto : public PROTO void __cdecl msn_keepAliveThread(void* arg); void __cdecl msn_loginThread(void* arg); void __cdecl msn_IEAuthThread(void* arg); + void __cdecl msn_refreshOAuthThread(void*); void __cdecl MSNServerThread(void* arg); void __cdecl MsnFileAckThread(void* arg); @@ -499,6 +500,8 @@ struct CMsnProto : public PROTO int LoginSkypeOAuth(const char *pRefreshToken); bool RefreshOAuth(const char *pszRefreshToken, const char *pszService, char *pszAccessToken, char *pszOutRefreshToken=NULL, time_t *ptExpires=NULL); int MSN_AuthOAuth(void); + int MSN_RefreshOAuthTokens(void); + void MSN_SendATH(ThreadData* info); CMStringA HotmailLogin(const char* url); void FreeAuthTokens(void); int GetMyNetID(void); diff --git a/protocols/MSN/src/msn_threads.cpp b/protocols/MSN/src/msn_threads.cpp index e72575e1fb..8671f2032a 100644 --- a/protocols/MSN/src/msn_threads.cpp +++ b/protocols/MSN/src/msn_threads.cpp @@ -29,6 +29,7 @@ along with this program. If not, see . void __cdecl CMsnProto::msn_keepAliveThread(void*) { bool keepFlag = true; + time_t t; hKeepAliveThreadEvt = CreateEvent(NULL, FALSE, FALSE, NULL); @@ -58,6 +59,8 @@ void __cdecl CMsnProto::msn_keepAliveThread(void*) mStatusMsgTS = 0; ForkThread(&CMsnProto::msn_storeProfileThread, NULL); } + if (MyOptions.netId!=NETID_SKYPE && time(&t) >= authTokenExpiretime-3600) + ForkThread(&CMsnProto::msn_refreshOAuthThread, msnNsThread); break; case WAIT_OBJECT_0: @@ -80,6 +83,13 @@ void __cdecl CMsnProto::msn_loginThread(void*) MSN_FetchRecentMessages(); } +void __cdecl CMsnProto::msn_refreshOAuthThread(void *param) +{ + if (MSN_RefreshOAuthTokens() > 0) { + bIgnoreATH = true; + MSN_SendATH((ThreadData*)param); + } +} ///////////////////////////////////////////////////////////////////////////////////////// // MSN server thread - read and process commands from a server -- cgit v1.2.3