diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/auth/auth.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/auth/auth.cpp')
-rw-r--r-- | Src/auth/auth.cpp | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/Src/auth/auth.cpp b/Src/auth/auth.cpp new file mode 100644 index 00000000..83a2e235 --- /dev/null +++ b/Src/auth/auth.cpp @@ -0,0 +1,479 @@ +#include "api.h" + +#include "../nu/ns_wc.h" +#include <api/service/waservicefactory.h> +#include "OAuthKey.h" +#include "../nu/AutoCharFn.h" +#include "../nu/AutoChar.h" +#include "auth.h" +#include "./loginbox/loginbox.h" + +#include "ifc_authcallback.h" +#include "main.h" +#include "../nu/AutoUrl.h" +#include <api/syscb/callbacks/authcb.h> + +#include "../Winamp/buildType.h" +#include <strsafe.h> + +//#ifdef INTERNAL +//// QA +////const char *openauth_url ="https://authapi.qa.aol.com:8439/auth/clientLogin"; +//// QH +//const char *openauth_url ="https://authapi.qh.aol.com:6443/auth/clientLogin"; +//#else +const char *openauth_url ="https://api.screenname.aol.com:443/auth/clientLogin"; +//#endif + +static void CleanPassword(char *password) +{ + char *src = password; + char *dest = password; + + while (src && *src) + { + char c = *src++; + if (c >= 'a' && c <= 'z') + *dest++ = c; + else if (c >= 'A' && c <= 'Z') + *dest++ = c; + else if (c >= '0' && c <= '9') + *dest++ = c; + } + *dest=0; +} + +static void ParsePassword(const wchar_t *password, char **password_url, char **securid=0) +{ + const wchar_t *find_slash = wcschr(password, L'/'); + if (find_slash) + { + *password_url = AutoUrlDupN(password, find_slash-password); + if (securid) + *securid = AutoUrlDup(find_slash+1); + } + else + { + *password_url = AutoUrlDup(password); + if (securid) + *securid=0; + } +} + +// TODO: benski> use &forceRateLimit=true to force captcha request +int PostXML(const char *url, const char *post_data, obj_xml *parser, ifc_authcallback *callback); +static int Authorize(obj_xml *parser, const wchar_t *username, const wchar_t *password, ifc_authcallback *callback) +{ + char *password_url, *securid; + ParsePassword(password, &password_url, &securid); + + char post_data[2048] = {0}; + StringCbPrintfA(post_data, sizeof(post_data), + "devId=%s" + "&f=xml" + "&pwd=%s" + "&s=%s" + "%s%s" + "&tokenType=longterm", + OPENAUTH_DEVID, + password_url, + AutoUrl(username), + (securid?"&securid=":""), + (securid?securid:"") + ); + + free(password_url); + free(securid); + return PostXML(openauth_url, post_data, parser, callback); +} + +static int AuthorizeSecurID(obj_xml *parser, const wchar_t *username, const char *context, const wchar_t *securid, ifc_authcallback *callback) +{ + char post_data[2048] = {0}; + StringCbPrintfA(post_data, sizeof(post_data), + "devId=%s" + "&f=xml" + "&s=%s" + "&context=%s" + "&securid=%s" + "&tokenType=longterm", + OPENAUTH_DEVID, + AutoUrl(username), + AutoUrl(context), + AutoUrl(securid) + ); + + return PostXML(openauth_url, post_data, parser, callback); +} + + +void OpenAuthParser::RegisterCallbacks(obj_xml *parser) +{ + parser->xmlreader_registerCallback(L"response\fstatusCode", &statusCode); + parser->xmlreader_registerCallback(L"response\fstatusText", &statusText); + parser->xmlreader_registerCallback(L"response\fstatusDetailCode", &statusDetailCode); + parser->xmlreader_registerCallback(L"response\fdata\ftoken\fa", &token); + parser->xmlreader_registerCallback(L"response\fdata\ftoken\fexpiresIn", &expire); + parser->xmlreader_registerCallback(L"response\fdata\fsessionSecret", &session_secret); + parser->xmlreader_registerCallback(L"response\fdata\fchallenge\fcontext", &context); + +} +void OpenAuthParser::UnregisterCallbacks(obj_xml *parser) +{ + parser->xmlreader_unregisterCallback(&statusCode); + parser->xmlreader_unregisterCallback(&statusText); + parser->xmlreader_unregisterCallback(&statusDetailCode); + parser->xmlreader_unregisterCallback(&token); + parser->xmlreader_unregisterCallback(&expire); + parser->xmlreader_unregisterCallback(&session_secret); + parser->xmlreader_unregisterCallback(&context); +} + + +int Auth::SetupLogin(OpenAuthParser &authParser, waServiceFactory *&parserFactory, obj_xml *&parser) +{ + parserFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID); + if (parserFactory) + parser = (obj_xml *)parserFactory->getInterface(); + + if (parser) + { + parser->xmlreader_setCaseSensitive(); + authParser.RegisterCallbacks(parser); + parser->xmlreader_open(); + return AUTH_SUCCESS; + } + else + return AUTH_NOPARSER; +} + +int Auth::ParseAuth(const wchar_t *password, OpenAuthParser &authParser, AuthResults *results) +{ + switch(authParser.statusCode.GetUInt32()) + { + case 200: + { + char *password_url; + ParsePassword(password, &password_url); + UrlDecode(password_url); + OAuthKey key(password_url, strlen(password_url)); + AutoChar session_utf8(authParser.session_secret.GetString(), CP_UTF8); + key.FeedMessage((char *)session_utf8, strlen(session_utf8)); + key.EndMessage(); + key.GetBase64(results->session_key, sizeof(results->session_key)); + WideCharToMultiByteSZ(CP_UTF8, 0, authParser.token.GetString(), -1, results->token, sizeof(results->token), 0, 0); + results->expire = authParser.expire.GetUInt32() + _time64(0); + free(password_url); + return AUTH_SUCCESS; + } + case 330: + switch(authParser.statusDetailCode.GetUInt32()) + { + case 3011: // Password-LoginId Required/Invalid + return AUTH_INVALIDCRED; + case 3012: // SecurId Required/Invalid + case 3013: // SecurId Next Token Required + WideCharToMultiByteSZ(CP_UTF8, 0, authParser.context.GetString(), -1, results->context, sizeof(results->context), 0, 0); + return AUTH_SECURID; + } + break; + case 401: + switch(authParser.statusDetailCode.GetUInt32()) + { + case 3020: + return AUTH_UNCONFIRMED; + } + break; + } + + return AUTH_NOT_AUTHORIZED; +} + +int Auth::Login(const wchar_t *username, const wchar_t *password, AuthResults *results, ifc_authcallback *callback) +{ + SecureZeroMemory(results, sizeof(AuthResults)); + OpenAuthParser authParser; + obj_xml *parser = 0; + waServiceFactory *parserFactory = 0; + + int err = SetupLogin(authParser, parserFactory, parser); + if (err == AUTH_SUCCESS) + { + err = Authorize(parser, username, password, callback); + authParser.UnregisterCallbacks(parser); + parser->xmlreader_close(); + parserFactory->releaseInterface(parser); + if (err != AUTH_SUCCESS) + return err; + + return ParseAuth(password, authParser, results); + } + else + return err; + + return AUTH_NOT_AUTHORIZED; +} + +int Auth::LoginSecurID(const wchar_t *username, const wchar_t *password, const char *context, const wchar_t *securid, AuthResults *results, ifc_authcallback *callback) +{ + SecureZeroMemory(results, sizeof(AuthResults)); + OpenAuthParser authParser; + obj_xml *parser = 0; + waServiceFactory *parserFactory = 0; + + int err = SetupLogin(authParser, parserFactory, parser); + if (err == AUTH_SUCCESS) + { + err = AuthorizeSecurID(parser, username, context, securid, callback); + authParser.UnregisterCallbacks(parser); + parser->xmlreader_close(); + parserFactory->releaseInterface(parser); + if (err != AUTH_SUCCESS) + return err; + + return ParseAuth(password, authParser, results); + } + else + return err; + + return AUTH_NOT_AUTHORIZED; +} + +const char *Auth::GetDevID() +{ + return OPENAUTH_DEVID; +} + +int Auth::SetCredentials(GUID realm, const char *session_key, const char *token, const wchar_t *username, __time64_t expire) +{ + if (NULL != WASABI_API_SYSCB) + WASABI_API_SYSCB->syscb_issueCallback(SysCallback::AUTH, AuthCallback::CREDENTIALS_ABOUTTOCHANGE, (intptr_t)this, (intptr_t)&realm); + + char guid_str[40] = {0}; + if (realm != GUID_NULL) + { + StringCbPrintfA( guid_str, sizeof(guid_str), "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + (int)realm.Data1, (int)realm.Data2, (int)realm.Data3, + (int)realm.Data4[0], (int)realm.Data4[1], + (int)realm.Data4[2], (int)realm.Data4[3], + (int)realm.Data4[4], (int)realm.Data4[5], + (int)realm.Data4[6], (int)realm.Data4[7] ); + } + else + { + StringCbCopyA(guid_str, sizeof(guid_str), "default"); + } + + if (session_key && session_key[0]) + { + WritePrivateProfileStringA(guid_str, "session_key", session_key, inifile); + WritePrivateProfileStringA(guid_str, "token", token, inifile); + WritePrivateProfileStringA(guid_str, "username", AutoChar(username, CP_UTF8), inifile); + char temp[128] = {0}; + StringCbPrintfA(temp, sizeof(temp), "%I64d", expire); + WritePrivateProfileStringA(guid_str, "expiration", temp, inifile); + } + else + { + char empty[2] = {0,0}; + WritePrivateProfileSectionA(guid_str, empty, inifile); + if (username && username[0]) // they might want to save their username tho + WritePrivateProfileStringA(guid_str, "username", AutoChar(username, CP_UTF8), inifile); + } + + if (NULL != WASABI_API_SYSCB) + WASABI_API_SYSCB->syscb_issueCallback(SysCallback::AUTH, AuthCallback::CREDENTIALS_CHANGED, (intptr_t)this, (intptr_t)&realm); + + return AUTH_SUCCESS; +} + +int Auth::GetCredentials(GUID realm, char *session_key, size_t session_key_len, char *token, size_t token_len, wchar_t *username, size_t username_len, __time64_t *expire) +{ + char guid_str[40] = {0}; + if (realm != GUID_NULL) + { + StringCbPrintfA( guid_str, sizeof(guid_str), "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + (int)realm.Data1, (int)realm.Data2, (int)realm.Data3, + (int)realm.Data4[0], (int)realm.Data4[1], + (int)realm.Data4[2], (int)realm.Data4[3], + (int)realm.Data4[4], (int)realm.Data4[5], + (int)realm.Data4[6], (int)realm.Data4[7] ); + } + else + { + StringCbCopyA(guid_str, sizeof(guid_str), "default"); + } + + GetPrivateProfileStringA(guid_str, "session_key", "", session_key, (DWORD)session_key_len, inifile); + GetPrivateProfileStringA(guid_str, "token", "", token, (DWORD)token_len, inifile); + char temp[1024] = {0}; + GetPrivateProfileStringA(guid_str, "username", "", temp, sizeof(temp), inifile); + MultiByteToWideCharSZ(CP_UTF8, 0, temp, -1, username, (DWORD)username_len); + + GetPrivateProfileStringA(guid_str, "expiration", "", temp, sizeof(temp), inifile); + *expire = _atoi64(temp); + return AUTH_SUCCESS; +} + +int Auth::GetUserName(GUID realm, wchar_t *username, size_t username_len) +{ + char guid_str[40] = {0}; + if (realm != GUID_NULL) + { + StringCbPrintfA( guid_str, sizeof(guid_str), "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + (int)realm.Data1, (int)realm.Data2, (int)realm.Data3, + (int)realm.Data4[0], (int)realm.Data4[1], + (int)realm.Data4[2], (int)realm.Data4[3], + (int)realm.Data4[4], (int)realm.Data4[5], + (int)realm.Data4[6], (int)realm.Data4[7] ); + } + else + { + StringCbCopyA(guid_str, sizeof(guid_str), "default"); + } + + char temp[1024] = {0}; + GetPrivateProfileStringA(guid_str, "username", "", temp, sizeof(temp), inifile); + MultiByteToWideCharSZ(CP_UTF8, 0, temp, -1, username, (DWORD)username_len); + return AUTH_SUCCESS; +} + + +Auth::Auth() +{ + inifile=0; +} +void Auth::Init() +{ + wchar_t inifileW[MAX_PATH] = {0}; + const wchar_t *settings_path = WASABI_API_APP->path_getUserSettingsPath(); + PathCombineW(inifileW, settings_path, L"auth.ini"); + inifile = _strdup(AutoCharFn(inifileW)); +} + +void Auth::Quit() +{ + free(inifile); +} + +static void AddParameter(char *&position, size_t &len, const char *param, const wchar_t *val) +{ + AutoUrl encoded_val(val); + StringCchPrintfExA(position, len, &position, &len, 0, "&%s=%s", param, encoded_val); +} + +static void AddParameter(char *&position, size_t &len, const char *param, const char *val) +{ + AutoUrl encoded_val(val); + StringCchPrintfExA(position, len, &position, &len, 0, "&%s=%s", param, encoded_val); +} + +static void AddParameter(char *&position, size_t &len, const char *param, int64_t val) +{ + char temp[64] = {0}; + StringCchPrintfA(temp, 64, "%I64d", val); + StringCchPrintfExA(position, len, &position, &len, 0, "&%s=%s", param, temp); +} + +//#ifdef INTERNAL +// QA +//static const char *c2w_server="my.screenname.qa.aol.com"; +//static const char *c2w_path="/_cqr/login/login.psp"; +//static const char *c2w_path_encoded="%2F_cqr%2Flogin%2Flogin.psp"; +// QH +//static const char *c2w_server="my.screenname.qh.aol.com"; +//static const char *c2w_path="/_cqr/login/login.psp"; +//static const char *c2w_path_encoded="%2F_cqr%2Flogin%2Flogin.psp"; +//#else +static const char *c2w_server="my.screenname.aol.com"; +static const char *c2w_path="/_cqr/login/login.psp"; +static const char *c2w_path_encoded="%2F_cqr%2Flogin%2Flogin.psp"; +//#endif + + +int Auth::ClientToWeb(GUID realm, const wchar_t *destination_url, wchar_t *url, size_t urlcch) +{ + char session_key[1024], token[1024] = {0}; + wchar_t username[1024] = {0}; + __time64_t expire; + int ret = GetCredentials(realm, session_key, 1024, token, 1024, username, 1024, &expire); + if (ret) + return ret; + + if (!session_key[0] || !token[0] || !username[0]) + return 1; + + char post_data[2048]=""; + char *post_itr=post_data; + size_t post_cch=sizeof(post_data)/sizeof(*post_data); + + OAuthKey key(session_key, strlen(session_key)); + + key.FeedMessage("GET&", 4); + key.FeedMessage("http%3A%2F%2F", 13); + key.FeedMessage(c2w_server, strlen(c2w_server)); + key.FeedMessage(c2w_path_encoded, strlen(c2w_path_encoded)); + key.FeedMessage("&", 1); + + // parameters + StringCbPrintfExA(post_itr, post_cch, &post_itr, &post_cch, 0, "a=%s", AutoUrl(token)); + char *start = post_itr; + key.FeedMessage("a%3D", 4); + AutoUrl token_a_url1(token); + AutoUrl token_a_url((char *)token_a_url1); + key.FeedMessage(token_a_url, strlen((char *)token_a_url)); + + AddParameter(post_itr, post_cch, "destUrl", destination_url); + AddParameter(post_itr, post_cch, "devId", GetDevID()); + AddParameter(post_itr, post_cch, "entryType", L"client2Web"); + __time64_t t = _time64(0); + AddParameter(post_itr, post_cch, "ts", t); + + AutoUrl encoded_post(start); + key.FeedMessage((char *)encoded_post, strlen(encoded_post)); + + key.EndMessage(); + char hash[512] = {0}; + key.GetBase64(hash, 512); + + StringCchPrintfA(post_itr, post_cch, "&sig_sha256=%s", AutoUrl(hash)); + + char urla[2048] = {0}; + StringCbPrintfA(urla, sizeof(urla), "http://%s%s?%s", c2w_server, c2w_path, post_data); + + MultiByteToWideCharSZ(CP_UTF8, 0, urla, -1, url, (int)urlcch); + + return 0; +} + +HWND Auth::CreateLoginWindow(GUID realm, HWND owner, UINT style) +{ +#ifndef USE_LOGINBOX + return NULL; +#else + return LoginBox_CreateWindow(this, &realm, owner, style); +#endif +} + +INT_PTR Auth::LoginBox(GUID realm, HWND owner, UINT style) +{ +#ifndef USE_LOGINBOX + return -1; +#else + return LoginBox_Show(this, &realm, owner, style); +#endif +} + +#define CBCLASS Auth +START_DISPATCH; +CB(API_AUTH_LOGIN, Login) +CB(API_AUTH_GETDEVID, GetDevID) +CB(API_AUTH_LOGIN_SECURID, LoginSecurID) +CB(API_AUTH_SETCREDENTIALS, SetCredentials) +CB(API_AUTH_GETCREDENTIALS, GetCredentials) +CB(API_AUTH_CLIENT_TO_WEB, ClientToWeb) +CB(API_AUTH_CREATELOGINWINDOW, CreateLoginWindow) +CB(API_AUTH_LOGINBOX, LoginBox) +CB(API_AUTH_GETUSERNAME, GetUserName) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file |