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);
|
||||
std::map<std::string, std::string> getTagsFromJson(const Json::Value& json);
|
||||
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
|
||||
|
@ -316,18 +316,9 @@ int Downloader::login()
|
||||
if (!boost::filesystem::remove(Globals::globalConfig.curlConf.sCookiePath))
|
||||
std::cerr << "Failed to delete " << Globals::globalConfig.curlConf.sCookiePath << std::endl;
|
||||
|
||||
int iWebsiteLoginResult = gogWebsite->Login(email, password);
|
||||
if (iWebsiteLoginResult < 1)
|
||||
{
|
||||
std::cerr << "HTTP: Login failed" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "HTTP: Login successful" << std::endl;
|
||||
}
|
||||
int iLoginResult = gogWebsite->Login(email, password);
|
||||
|
||||
if (iWebsiteLoginResult < 2)
|
||||
if (iLoginResult < 1)
|
||||
{
|
||||
std::cerr << "Galaxy: Login failed" << std::endl;
|
||||
return 0;
|
||||
@ -335,12 +326,21 @@ int Downloader::login()
|
||||
else
|
||||
{
|
||||
std::cerr << "Galaxy: Login successful" << std::endl;
|
||||
|
||||
if (!Globals::galaxyConf.getJSON().empty())
|
||||
{
|
||||
this->saveGalaxyJSON();
|
||||
}
|
||||
}
|
||||
|
||||
if (gogWebsite->IsLoggedIn())
|
||||
{
|
||||
std::cerr << "HTTP: Login successful" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "HTTP: Login failed" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
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();
|
||||
|
||||
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::ostringstream memory;
|
||||
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_login = "login[login]";
|
||||
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;
|
||||
tree<htmlcxx::HTML::Node> login_dom = parser.parseTree(login_form_html);
|
||||
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())
|
||||
{
|
||||
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
|
||||
@ -466,47 +495,63 @@ int Website::Login(const std::string& email, const std::string& password)
|
||||
{
|
||||
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
|
||||
}
|
||||
else
|
||||
std::string auth_code;
|
||||
std::string url;
|
||||
|
||||
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())
|
||||
res = 1; // Login was successful
|
||||
auth_code = what[1];
|
||||
}
|
||||
|
||||
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()
|
||||
+ "&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::cout << curl_easy_strerror(result) << std::endl;
|
||||
}
|
||||
|
||||
std::string json = this->getResponse(token_url);
|
||||
if (!json.empty())
|
||||
return auth_code;
|
||||
}
|
||||
|
||||
#ifdef USE_QT_GUI_LOGIN
|
||||
std::string Website::LoginGetAuthCodeGUI(const std::string& email, const std::string& password)
|
||||
{
|
||||
Json::Value token_json;
|
||||
std::istringstream json_stream(json);
|
||||
try {
|
||||
json_stream >> token_json;
|
||||
std::string auth_code;
|
||||
GuiLogin gl;
|
||||
gl.Login(email, password);
|
||||
|
||||
Globals::galaxyConf.setJSON(token_json);
|
||||
res = 2;
|
||||
} catch (const Json::Exception& exc) {
|
||||
std::cerr << "Failed to parse json" << std::endl << json << std::endl;
|
||||
std::cerr << exc.what() << std::endl;
|
||||
auto cookies = gl.getCookies();
|
||||
for (auto cookie : cookies)
|
||||
{
|
||||
curl_easy_setopt(curlhandle, CURLOPT_COOKIELIST, cookie.c_str());
|
||||
}
|
||||
auth_code = gl.getCode();
|
||||
return auth_code;
|
||||
}
|
||||
}
|
||||
|
||||
if (res >= 1)
|
||||
curl_easy_setopt(curlhandle, CURLOPT_COOKIELIST, "FLUSH"); // Write all known cookies to the file specified by CURLOPT_COOKIEJAR
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Website::IsLoggedIn()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user