mirror of
https://github.com/Sude-/lgogdownloader.git
synced 2025-02-02 05:52:31 +01:00
Add GUI login
Use QtWebEngine for getting cookies and authorization code if login form contains recaptcha and downloader is compiled with -DUSE_QT_GUI=ON
This commit is contained in:
parent
01eed3ec9e
commit
1e8ebbfd94
@ -4,6 +4,13 @@ project (lgogdownloader LANGUAGES C CXX VERSION 3.4)
|
|||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
|
||||||
set(LINK_LIBCRYPTO 0)
|
set(LINK_LIBCRYPTO 0)
|
||||||
|
|
||||||
|
option(USE_QT_GUI "Build with Qt GUI login support" OFF)
|
||||||
|
if(USE_QT_GUI)
|
||||||
|
add_definitions(-DUSE_QT_GUI_LOGIN=1)
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
endif(USE_QT_GUI)
|
||||||
|
|
||||||
find_program(READELF readelf DOC "Location of the readelf program")
|
find_program(READELF readelf DOC "Location of the readelf program")
|
||||||
find_program(GREP grep DOC "Location of the grep program")
|
find_program(GREP grep DOC "Location of the grep program")
|
||||||
find_package(Boost
|
find_package(Boost
|
||||||
@ -51,6 +58,17 @@ file(GLOB SRC_FILES
|
|||||||
src/ziputil.cpp
|
src/ziputil.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(USE_QT_GUI)
|
||||||
|
find_package(Qt5Widgets CONFIG REQUIRED)
|
||||||
|
find_package(Qt5WebEngineWidgets CONFIG REQUIRED)
|
||||||
|
|
||||||
|
file(GLOB QT_GUI_SRC_FILES
|
||||||
|
src/gui_login.cpp
|
||||||
|
)
|
||||||
|
list(APPEND SRC_FILES ${QT_GUI_SRC_FILES})
|
||||||
|
endif(USE_QT_GUI)
|
||||||
|
|
||||||
|
|
||||||
set(GIT_CHECKOUT FALSE)
|
set(GIT_CHECKOUT FALSE)
|
||||||
if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||||
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||||
@ -127,6 +145,13 @@ if(LINK_LIBCRYPTO EQUAL 1)
|
|||||||
)
|
)
|
||||||
endif(LINK_LIBCRYPTO EQUAL 1)
|
endif(LINK_LIBCRYPTO EQUAL 1)
|
||||||
|
|
||||||
|
if(USE_QT_GUI)
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
PRIVATE Qt5::Widgets
|
||||||
|
PRIVATE Qt5::WebEngineWidgets
|
||||||
|
)
|
||||||
|
endif(USE_QT_GUI)
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
# Force to always compile with W4
|
# Force to always compile with W4
|
||||||
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||||
|
@ -13,6 +13,7 @@ This repository contains the code of unofficial [GOG](http://www.gog.com/) downl
|
|||||||
* [boost](http://www.boost.org/) (regex, date-time, system, filesystem, program-options, iostreams)
|
* [boost](http://www.boost.org/) (regex, date-time, system, filesystem, program-options, iostreams)
|
||||||
* [libcrypto](https://www.openssl.org/) if libcurl is built with OpenSSL
|
* [libcrypto](https://www.openssl.org/) if libcurl is built with OpenSSL
|
||||||
* [zlib](https://www.zlib.net/)
|
* [zlib](https://www.zlib.net/)
|
||||||
|
* [qtwebengine](https://www.qt.io/) if built with -DUSE_QT_GUI=ON
|
||||||
|
|
||||||
## Make dependencies
|
## Make dependencies
|
||||||
* [cmake](https://cmake.org/) >= 3.0.0
|
* [cmake](https://cmake.org/) >= 3.0.0
|
||||||
@ -26,7 +27,7 @@ This repository contains the code of unofficial [GOG](http://www.gog.com/) downl
|
|||||||
libjsoncpp-dev liboauth-dev librhash-dev libtinyxml2-dev libhtmlcxx-dev \
|
libjsoncpp-dev liboauth-dev librhash-dev libtinyxml2-dev libhtmlcxx-dev \
|
||||||
libboost-system-dev libboost-filesystem-dev libboost-program-options-dev \
|
libboost-system-dev libboost-filesystem-dev libboost-program-options-dev \
|
||||||
libboost-date-time-dev libboost-iostreams-dev help2man cmake libssl-dev \
|
libboost-date-time-dev libboost-iostreams-dev help2man cmake libssl-dev \
|
||||||
pkg-config zlib1g-dev
|
pkg-config zlib1g-dev qtwebengine5-dev
|
||||||
|
|
||||||
## Build and install
|
## Build and install
|
||||||
|
|
||||||
|
41
include/gui_login.h
Normal file
41
include/gui_login.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/* This program is free software. It comes without any warranty, to
|
||||||
|
* the extent permitted by applicable law. You can redistribute it
|
||||||
|
* and/or modify it under the terms of the Do What The Fuck You Want
|
||||||
|
* To Public License, Version 2, as published by Sam Hocevar. See
|
||||||
|
* http://www.wtfpl.net/ for more details. */
|
||||||
|
|
||||||
|
#ifndef GUI_LOGIN_H
|
||||||
|
#define GUI_LOGIN_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QWebEngineCookieStore>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class GuiLogin : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
GuiLogin();
|
||||||
|
virtual ~GuiLogin();
|
||||||
|
|
||||||
|
void Login();
|
||||||
|
std::string getCode();
|
||||||
|
std::vector<std::string> getCookies();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWebEngineCookieStore *cookiestore;
|
||||||
|
std::vector<std::string> cookies;
|
||||||
|
std::string auth_code;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void loadFinished(bool success);
|
||||||
|
void cookieAdded(const QNetworkCookie &cookie);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GUI_LOGIN_H
|
134
src/gui_login.cpp
Normal file
134
src/gui_login.cpp
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/* This program is free software. It comes without any warranty, to
|
||||||
|
* the extent permitted by applicable law. You can redistribute it
|
||||||
|
* and/or modify it under the terms of the Do What The Fuck You Want
|
||||||
|
* To Public License, Version 2, as published by Sam Hocevar. See
|
||||||
|
* http://www.wtfpl.net/ for more details. */
|
||||||
|
|
||||||
|
#include "gui_login.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QtWidgets/QWidget>
|
||||||
|
#include <QtWebEngineWidgets/QWebEngineView>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QLayout>
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
#include <QWebEngineProfile>
|
||||||
|
|
||||||
|
GuiLogin::GuiLogin()
|
||||||
|
{
|
||||||
|
// constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiLogin::~GuiLogin()
|
||||||
|
{
|
||||||
|
// destructor
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiLogin::loadFinished(bool success)
|
||||||
|
{
|
||||||
|
QWebEngineView *view = qobject_cast<QWebEngineView*>(sender());
|
||||||
|
std::string url = view->page()->url().toString().toUtf8().constData();
|
||||||
|
if (success && url.find("https://embed.gog.com/on_login_success") != std::string::npos)
|
||||||
|
{
|
||||||
|
std::string find_str = "code=";
|
||||||
|
auto pos = url.find(find_str);
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
pos += find_str.length();
|
||||||
|
std::string code;
|
||||||
|
code.assign(url.begin()+pos, url.end());
|
||||||
|
if (!code.empty())
|
||||||
|
{
|
||||||
|
this->auth_code = code;
|
||||||
|
QCoreApplication::exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiLogin::cookieAdded(const QNetworkCookie& cookie)
|
||||||
|
{
|
||||||
|
std::string raw_cookie = cookie.toRawForm().toStdString();
|
||||||
|
if (!raw_cookie.empty())
|
||||||
|
{
|
||||||
|
std::string set_cookie = "Set-Cookie: " + raw_cookie;
|
||||||
|
bool duplicate = false;
|
||||||
|
for (auto cookie : this->cookies)
|
||||||
|
{
|
||||||
|
if (set_cookie == cookie)
|
||||||
|
{
|
||||||
|
duplicate = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!duplicate)
|
||||||
|
this->cookies.push_back(set_cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiLogin::Login()
|
||||||
|
{
|
||||||
|
QByteArray redirect_uri = QUrl::toPercentEncoding(QString::fromStdString(Globals::galaxyConf.getRedirectUri()));
|
||||||
|
std::string auth_url = "https://auth.gog.com/auth?client_id=" + Globals::galaxyConf.getClientId() + "&redirect_uri=" + redirect_uri.toStdString() + "&response_type=code";
|
||||||
|
QUrl url = QString::fromStdString(auth_url);
|
||||||
|
|
||||||
|
std::vector<char> version_string(
|
||||||
|
Globals::globalConfig.sVersionString.c_str(),
|
||||||
|
Globals::globalConfig.sVersionString.c_str() + Globals::globalConfig.sVersionString.size() + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
int argc = 1;
|
||||||
|
char *argv[] = {&version_string[0]};
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
QWidget window;
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout;
|
||||||
|
QSize window_size(440, 540);
|
||||||
|
|
||||||
|
window.setGeometry(
|
||||||
|
QStyle::alignedRect(
|
||||||
|
Qt::LeftToRight,
|
||||||
|
Qt::AlignCenter,
|
||||||
|
window_size,
|
||||||
|
qApp->desktop()->availableGeometry()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
QWebEngineView *webengine = new QWebEngineView(&window);
|
||||||
|
layout->addWidget(webengine);
|
||||||
|
QWebEngineProfile profile;
|
||||||
|
profile.setHttpUserAgent(QString::fromStdString(Globals::globalConfig.curlConf.sUserAgent));
|
||||||
|
QWebEnginePage page(&profile);
|
||||||
|
cookiestore = profile.cookieStore();
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
webengine, SIGNAL(loadFinished(bool)),
|
||||||
|
this, SLOT(loadFinished(bool))
|
||||||
|
);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
this->cookiestore, SIGNAL(cookieAdded(const QNetworkCookie&)),
|
||||||
|
this, SLOT(cookieAdded(const QNetworkCookie&))
|
||||||
|
);
|
||||||
|
|
||||||
|
webengine->resize(window.frameSize());
|
||||||
|
webengine->setPage(&page);
|
||||||
|
webengine->setUrl(url);
|
||||||
|
|
||||||
|
window.setLayout(layout);
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
app.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GuiLogin::getCode()
|
||||||
|
{
|
||||||
|
return this->auth_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> GuiLogin::getCookies()
|
||||||
|
{
|
||||||
|
return this->cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_gui_login.cpp"
|
@ -10,6 +10,10 @@
|
|||||||
#include <htmlcxx/html/ParserDom.h>
|
#include <htmlcxx/html/ParserDom.h>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
#include <boost/algorithm/string/case_conv.hpp>
|
||||||
|
|
||||||
|
#ifdef USE_QT_GUI_LOGIN
|
||||||
|
#include "gui_login.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
Website::Website()
|
Website::Website()
|
||||||
{
|
{
|
||||||
this->retries = 0;
|
this->retries = 0;
|
||||||
@ -297,6 +301,7 @@ int Website::Login(const std::string& email, const std::string& password)
|
|||||||
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_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;
|
std::string auth_code;
|
||||||
|
bool bRecaptcha = false;
|
||||||
|
|
||||||
std::string login_form_html = this->getResponse(auth_url);
|
std::string login_form_html = this->getResponse(auth_url);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@ -305,11 +310,33 @@ int Website::Login(const std::string& email, const std::string& password)
|
|||||||
#endif
|
#endif
|
||||||
if (login_form_html.find("google.com/recaptcha") != std::string::npos)
|
if (login_form_html.find("google.com/recaptcha") != std::string::npos)
|
||||||
{
|
{
|
||||||
|
bRecaptcha = true;
|
||||||
|
#ifndef USE_QT_GUI_LOGIN
|
||||||
std::cout << "Login form contains reCAPTCHA (https://www.google.com/recaptcha/)" << std::endl
|
std::cout << "Login form contains reCAPTCHA (https://www.google.com/recaptcha/)" << std::endl
|
||||||
<< "Try to login later" << std::endl;
|
<< "Try to login later or compile LGOGDownloader with -DUSE_QT_GUI=ON" << std::endl;
|
||||||
return res = 0;
|
return res = 0;
|
||||||
|
#else
|
||||||
|
GuiLogin gl;
|
||||||
|
gl.Login();
|
||||||
|
|
||||||
|
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();
|
||||||
@ -459,6 +486,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this->IsLoggedInComplex(email))
|
if (this->IsLoggedInComplex(email))
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user