mirror of
https://github.com/Sude-/lgogdownloader.git
synced 2024-11-20 11:49:17 +01:00
Refactor login code
Users can now get around reCATPCHA without the downloader being built with GUI enabled by using their browser to login
This commit is contained in:
parent
9e5e833691
commit
c26e28a564
@ -33,6 +33,12 @@ class Website
|
|||||||
bool IsLoggedInComplex(const std::string& email);
|
bool IsLoggedInComplex(const std::string& email);
|
||||||
std::map<std::string, std::string> getTagsFromJson(const Json::Value& json);
|
std::map<std::string, std::string> getTagsFromJson(const Json::Value& json);
|
||||||
int retries;
|
int retries;
|
||||||
|
std::string LoginGetAuthCode(const std::string& email, const std::string& password);
|
||||||
|
std::string LoginGetAuthCodeCurl(const std::string& login_form_html, const std::string& email, const std::string& password);
|
||||||
|
std::string LoginGetAuthCodeBrowser(const std::string& auth_url);
|
||||||
|
#ifdef USE_QT_GUI_LOGIN
|
||||||
|
std::string LoginGetAuthCodeGUI(const std::string& email, const std::string& password);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WEBSITE_H
|
#endif // WEBSITE_H
|
||||||
|
@ -316,18 +316,9 @@ int Downloader::login()
|
|||||||
if (!boost::filesystem::remove(Globals::globalConfig.curlConf.sCookiePath))
|
if (!boost::filesystem::remove(Globals::globalConfig.curlConf.sCookiePath))
|
||||||
std::cerr << "Failed to delete " << Globals::globalConfig.curlConf.sCookiePath << std::endl;
|
std::cerr << "Failed to delete " << Globals::globalConfig.curlConf.sCookiePath << std::endl;
|
||||||
|
|
||||||
int iWebsiteLoginResult = gogWebsite->Login(email, password);
|
int iLoginResult = gogWebsite->Login(email, password);
|
||||||
if (iWebsiteLoginResult < 1)
|
|
||||||
{
|
|
||||||
std::cerr << "HTTP: Login failed" << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cerr << "HTTP: Login successful" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iWebsiteLoginResult < 2)
|
if (iLoginResult < 1)
|
||||||
{
|
{
|
||||||
std::cerr << "Galaxy: Login failed" << std::endl;
|
std::cerr << "Galaxy: Login failed" << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
@ -335,12 +326,21 @@ int Downloader::login()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "Galaxy: Login successful" << std::endl;
|
std::cerr << "Galaxy: Login successful" << std::endl;
|
||||||
|
|
||||||
if (!Globals::galaxyConf.getJSON().empty())
|
if (!Globals::galaxyConf.getJSON().empty())
|
||||||
{
|
{
|
||||||
this->saveGalaxyJSON();
|
this->saveGalaxyJSON();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gogWebsite->IsLoggedIn())
|
||||||
|
{
|
||||||
|
std::cerr << "HTTP: Login successful" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "HTTP: Login failed" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
195
src/website.cpp
195
src/website.cpp
@ -268,6 +268,80 @@ int Website::Login(const std::string& email, const std::string& password)
|
|||||||
Globals::galaxyConf.resetClient();
|
Globals::galaxyConf.resetClient();
|
||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
std::string auth_code;
|
||||||
|
|
||||||
|
auth_code = this->LoginGetAuthCode(email, password);
|
||||||
|
|
||||||
|
if (!auth_code.empty())
|
||||||
|
{
|
||||||
|
std::string token_url = "https://auth.gog.com/token?client_id=" + Globals::galaxyConf.getClientId()
|
||||||
|
+ "&client_secret=" + Globals::galaxyConf.getClientSecret()
|
||||||
|
+ "&grant_type=authorization_code&code=" + auth_code
|
||||||
|
+ "&redirect_uri=" + (std::string)curl_easy_escape(curlhandle, Globals::galaxyConf.getRedirectUri().c_str(), Globals::galaxyConf.getRedirectUri().size());
|
||||||
|
|
||||||
|
std::string json = this->getResponse(token_url);
|
||||||
|
if (!json.empty())
|
||||||
|
{
|
||||||
|
Json::Value token_json;
|
||||||
|
std::istringstream json_stream(json);
|
||||||
|
try {
|
||||||
|
json_stream >> token_json;
|
||||||
|
|
||||||
|
Globals::galaxyConf.setJSON(token_json);
|
||||||
|
res = 1;
|
||||||
|
} catch (const Json::Exception& exc) {
|
||||||
|
std::cerr << "Failed to parse json" << std::endl << json << std::endl;
|
||||||
|
std::cerr << exc.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Failed to get auth code" << std::endl;
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res >= 1)
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_COOKIELIST, "FLUSH"); // Write all known cookies to the file specified by CURLOPT_COOKIEJAR
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Website::LoginGetAuthCode(const std::string& email, const std::string& password)
|
||||||
|
{
|
||||||
|
std::string auth_code;
|
||||||
|
bool bRecaptcha = false;
|
||||||
|
|
||||||
|
std::string auth_url = "https://auth.gog.com/auth?client_id=" + Globals::galaxyConf.getClientId() + "&redirect_uri=" + (std::string)curl_easy_escape(curlhandle, Globals::galaxyConf.getRedirectUri().c_str(), Globals::galaxyConf.getRedirectUri().size()) + "&response_type=code&layout=default&brand=gog";
|
||||||
|
|
||||||
|
std::string login_form_html = this->getResponse(auth_url);
|
||||||
|
if (Globals::globalConfig.iMsgLevel >= MSGLEVEL_DEBUG)
|
||||||
|
{
|
||||||
|
std::cerr << "DEBUG INFO (Website::LoginGetAuthCode)" << std::endl;
|
||||||
|
std::cerr << login_form_html << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (login_form_html.find("class=\"g-recaptcha form__recaptcha\"") != std::string::npos)
|
||||||
|
{
|
||||||
|
bRecaptcha = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auth_code = this->LoginGetAuthCodeCurl(login_form_html, email, password);
|
||||||
|
|
||||||
|
#ifdef USE_QT_GUI_LOGIN
|
||||||
|
if (Globals::globalConfig.bEnableLoginGUI && auth_code.empty())
|
||||||
|
auth_code = this->LoginGetAuthCodeGUI(email, password);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (auth_code.empty() && bRecaptcha)
|
||||||
|
auth_code = this->LoginGetAuthCodeBrowser(auth_url);
|
||||||
|
|
||||||
|
return auth_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Website::LoginGetAuthCodeCurl(const std::string& login_form_html, const std::string& email, const std::string& password)
|
||||||
|
{
|
||||||
|
std::string auth_code;
|
||||||
std::string postdata;
|
std::string postdata;
|
||||||
std::ostringstream memory;
|
std::ostringstream memory;
|
||||||
std::string token;
|
std::string token;
|
||||||
@ -275,52 +349,7 @@ int Website::Login(const std::string& email, const std::string& password)
|
|||||||
std::string tagname_password = "login[password]";
|
std::string tagname_password = "login[password]";
|
||||||
std::string tagname_login = "login[login]";
|
std::string tagname_login = "login[login]";
|
||||||
std::string tagname_token;
|
std::string tagname_token;
|
||||||
std::string auth_url = "https://auth.gog.com/auth?client_id=" + Globals::galaxyConf.getClientId() + "&redirect_uri=" + (std::string)curl_easy_escape(curlhandle, Globals::galaxyConf.getRedirectUri().c_str(), Globals::galaxyConf.getRedirectUri().size()) + "&response_type=code&layout=default&brand=gog";
|
|
||||||
std::string auth_code;
|
|
||||||
bool bRecaptcha = false;
|
|
||||||
|
|
||||||
std::string login_form_html = this->getResponse(auth_url);
|
|
||||||
if (Globals::globalConfig.iMsgLevel >= MSGLEVEL_DEBUG)
|
|
||||||
{
|
|
||||||
std::cerr << "DEBUG INFO (Website::Login)" << std::endl;
|
|
||||||
std::cerr << login_form_html << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (login_form_html.find("class=\"g-recaptcha form__recaptcha\"") != std::string::npos)
|
|
||||||
{
|
|
||||||
bRecaptcha = true;
|
|
||||||
#ifndef USE_QT_GUI_LOGIN
|
|
||||||
std::cout << "Login form contains reCAPTCHA (https://www.google.com/recaptcha/)" << std::endl
|
|
||||||
<< "Try to login later or compile LGOGDownloader with -DUSE_QT_GUI=ON" << std::endl;
|
|
||||||
return res = 0;
|
|
||||||
#else
|
|
||||||
if (!Globals::globalConfig.bEnableLoginGUI)
|
|
||||||
{
|
|
||||||
std::cout << "Login form contains reCAPTCHA but GUI login is disabled." << std::endl
|
|
||||||
<< "Enable GUI login with --enable-login-gui or try to login later." << std::endl;
|
|
||||||
return res = 0;
|
|
||||||
}
|
|
||||||
GuiLogin gl;
|
|
||||||
gl.Login(email, password);
|
|
||||||
|
|
||||||
auto cookies = gl.getCookies();
|
|
||||||
for (auto cookie : cookies)
|
|
||||||
{
|
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_COOKIELIST, cookie.c_str());
|
|
||||||
}
|
|
||||||
auth_code = gl.getCode();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bRecaptcha)
|
|
||||||
{
|
|
||||||
// This should never be reached but do additional check here just in case
|
|
||||||
#ifndef USE_QT_GUI_LOGIN
|
|
||||||
return res = 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
htmlcxx::HTML::ParserDom parser;
|
htmlcxx::HTML::ParserDom parser;
|
||||||
tree<htmlcxx::HTML::Node> login_dom = parser.parseTree(login_form_html);
|
tree<htmlcxx::HTML::Node> login_dom = parser.parseTree(login_form_html);
|
||||||
tree<htmlcxx::HTML::Node>::iterator login_it = login_dom.begin();
|
tree<htmlcxx::HTML::Node>::iterator login_it = login_dom.begin();
|
||||||
@ -341,7 +370,7 @@ int Website::Login(const std::string& email, const std::string& password)
|
|||||||
if (token.empty())
|
if (token.empty())
|
||||||
{
|
{
|
||||||
std::cout << "Failed to get login token" << std::endl;
|
std::cout << "Failed to get login token" << std::endl;
|
||||||
return res = 0;
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Create postdata - escape characters in email/password to support special characters
|
//Create postdata - escape characters in email/password to support special characters
|
||||||
@ -466,47 +495,63 @@ int Website::Login(const std::string& email, const std::string& password)
|
|||||||
{
|
{
|
||||||
std::cout << curl_easy_strerror(result) << std::endl;
|
std::cout << curl_easy_strerror(result) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return auth_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->IsLoggedInComplex(email))
|
std::string Website::LoginGetAuthCodeBrowser(const std::string& auth_url)
|
||||||
{
|
{
|
||||||
res = 1; // Login was successful
|
std::string auth_code;
|
||||||
}
|
std::string url;
|
||||||
else
|
|
||||||
|
std::cerr << "Login using browser at the following url" << std::endl;
|
||||||
|
std::cerr << auth_url << std::endl << std::endl;
|
||||||
|
std::cerr << "then copy & paste the full url here" << std::endl;
|
||||||
|
std::cerr << "URL: ";
|
||||||
|
std::getline(std::cin, url);
|
||||||
|
|
||||||
|
boost::regex re(".*code=(.*?)([\?&].*|$)", boost::regex_constants::icase);
|
||||||
|
boost::match_results<std::string::const_iterator> what;
|
||||||
|
if (boost::regex_search(url, what, re))
|
||||||
{
|
{
|
||||||
if (this->IsloggedInSimple())
|
auth_code = what[1];
|
||||||
res = 1; // Login was successful
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res == 1 && !auth_code.empty())
|
std::ostringstream memory;
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, Util::CurlWriteMemoryCallback);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, &memory);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_URL, url.c_str());
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_HTTPGET, 1);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_MAXREDIRS, -1);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_FOLLOWLOCATION, 1);
|
||||||
|
CURLcode result = curl_easy_perform(curlhandle);
|
||||||
|
memory.str(std::string());
|
||||||
|
|
||||||
|
if (result != CURLE_OK)
|
||||||
{
|
{
|
||||||
std::string token_url = "https://auth.gog.com/token?client_id=" + Globals::galaxyConf.getClientId()
|
std::cout << curl_easy_strerror(result) << std::endl;
|
||||||
+ "&client_secret=" + Globals::galaxyConf.getClientSecret()
|
}
|
||||||
+ "&grant_type=authorization_code&code=" + auth_code
|
|
||||||
+ "&redirect_uri=" + (std::string)curl_easy_escape(curlhandle, Globals::galaxyConf.getRedirectUri().c_str(), Globals::galaxyConf.getRedirectUri().size());
|
|
||||||
|
|
||||||
std::string json = this->getResponse(token_url);
|
return auth_code;
|
||||||
if (!json.empty())
|
}
|
||||||
|
|
||||||
|
#ifdef USE_QT_GUI_LOGIN
|
||||||
|
std::string Website::LoginGetAuthCodeGUI(const std::string& email, const std::string& password)
|
||||||
{
|
{
|
||||||
Json::Value token_json;
|
std::string auth_code;
|
||||||
std::istringstream json_stream(json);
|
GuiLogin gl;
|
||||||
try {
|
gl.Login(email, password);
|
||||||
json_stream >> token_json;
|
|
||||||
|
|
||||||
Globals::galaxyConf.setJSON(token_json);
|
auto cookies = gl.getCookies();
|
||||||
res = 2;
|
for (auto cookie : cookies)
|
||||||
} catch (const Json::Exception& exc) {
|
{
|
||||||
std::cerr << "Failed to parse json" << std::endl << json << std::endl;
|
curl_easy_setopt(curlhandle, CURLOPT_COOKIELIST, cookie.c_str());
|
||||||
std::cerr << exc.what() << std::endl;
|
|
||||||
}
|
}
|
||||||
|
auth_code = gl.getCode();
|
||||||
|
return auth_code;
|
||||||
}
|
}
|
||||||
}
|
#endif
|
||||||
|
|
||||||
if (res >= 1)
|
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_COOKIELIST, "FLUSH"); // Write all known cookies to the file specified by CURLOPT_COOKIEJAR
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Website::IsLoggedIn()
|
bool Website::IsLoggedIn()
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user