This commit is contained in:
Sude 2022-10-01 20:18:12 +03:00
commit 6ae6ab2469
9 changed files with 1195 additions and 32 deletions

View File

@ -19,6 +19,7 @@ struct DirectoryConfig
{ {
bool bSubDirectories; bool bSubDirectories;
std::string sDirectory; std::string sDirectory;
std::string sWinePrefix;
std::string sGameSubdir; std::string sGameSubdir;
std::string sInstallersSubdir; std::string sInstallersSubdir;
std::string sExtrasSubdir; std::string sExtrasSubdir;
@ -102,6 +103,16 @@ class GalaxyConfig
return this->token_json; return this->token_json;
} }
std::string getUserId() {
std::unique_lock<std::mutex> lock(m);
if(this->token_json.isMember("user_id")) {
return this->token_json["user_id"].asString();
}
return {};
}
void setJSON(Json::Value json) void setJSON(Json::Value json)
{ {
std::unique_lock<std::mutex> lock(m); std::unique_lock<std::mutex> lock(m);
@ -131,16 +142,34 @@ class GalaxyConfig
return this->filepath; return this->filepath;
} }
void resetClient() {
std::lock_guard<std::mutex> lock(m);
if(token_json.isMember("client_id")) {
token_json["client_id"] = default_client_id;
}
if(token_json.isMember("client_secret")) {
token_json["client_secret"] = default_client_secret;
}
}
std::string getClientId() std::string getClientId()
{ {
std::unique_lock<std::mutex> lock(m); std::lock_guard<std::mutex> lock(m);
return this->client_id; if(token_json.isMember("client_id")) {
return token_json["client_id"].asString();
}
return default_client_id;
} }
std::string getClientSecret() std::string getClientSecret()
{ {
std::unique_lock<std::mutex> lock(m); std::lock_guard<std::mutex> lock(m);
return this->client_secret; if(token_json.isMember("client_secret")) {
return token_json["client_secret"].asString();
}
return default_client_secret;
} }
std::string getRedirectUri() std::string getRedirectUri()
@ -154,8 +183,6 @@ class GalaxyConfig
GalaxyConfig(const GalaxyConfig& other) GalaxyConfig(const GalaxyConfig& other)
{ {
std::lock_guard<std::mutex> guard(other.m); std::lock_guard<std::mutex> guard(other.m);
client_id = other.client_id;
client_secret = other.client_secret;
redirect_uri = other.redirect_uri; redirect_uri = other.redirect_uri;
filepath = other.filepath; filepath = other.filepath;
token_json = other.token_json; token_json = other.token_json;
@ -169,8 +196,6 @@ class GalaxyConfig
std::unique_lock<std::mutex> lock1(m, std::defer_lock); std::unique_lock<std::mutex> lock1(m, std::defer_lock);
std::unique_lock<std::mutex> lock2(other.m, std::defer_lock); std::unique_lock<std::mutex> lock2(other.m, std::defer_lock);
std::lock(lock1, lock2); std::lock(lock1, lock2);
client_id = other.client_id;
client_secret = other.client_secret;
redirect_uri = other.redirect_uri; redirect_uri = other.redirect_uri;
filepath = other.filepath; filepath = other.filepath;
token_json = other.token_json; token_json = other.token_json;
@ -178,8 +203,9 @@ class GalaxyConfig
} }
protected: protected:
private: private:
std::string client_id = "46899977096215655"; const std::string default_client_id = "46899977096215655";
std::string client_secret = "9d85c43b1482497dbbce61f6e4aa173a433796eeae2ca8c5f6129f2dc4de46d9"; const std::string default_client_secret = "9d85c43b1482497dbbce61f6e4aa173a433796eeae2ca8c5f6129f2dc4de46d9";
std::string redirect_uri = "https://embed.gog.com/on_login_success?origin=client"; std::string redirect_uri = "https://embed.gog.com/on_login_success?origin=client";
std::string filepath; std::string filepath;
Json::Value token_json; Json::Value token_json;
@ -281,6 +307,12 @@ class Config
Blacklist blacklist; Blacklist blacklist;
Blacklist ignorelist; Blacklist ignorelist;
Blacklist gamehasdlc; Blacklist gamehasdlc;
// Cloud save options
std::vector<std::string> cloudWhiteList;
std::vector<std::string> cloudBlackList;
bool bCloudForce;
std::string sGameHasDLCList; std::string sGameHasDLCList;
// Integers // Integers

View File

@ -32,9 +32,11 @@
#include <curl/curl.h> #include <curl/curl.h>
#include <json/json.h> #include <json/json.h>
#include <ctime> #include <ctime>
#include <functional>
#include <fstream> #include <fstream>
#include <deque> #include <deque>
class cloudSaveFile;
class Timer class Timer
{ {
public: public:
@ -99,6 +101,14 @@ class Downloader
void clearUpdateNotifications(); void clearUpdateNotifications();
void repair(); void repair();
void download(); void download();
void downloadCloudSaves(const std::string& product_id, int build_index = -1);
void downloadCloudSavesById(const std::string& product_id, int build_index = -1);
void uploadCloudSaves(const std::string& product_id, int build_index = -1);
void uploadCloudSavesById(const std::string& product_id, int build_index = -1);
void deleteCloudSaves(const std::string& product_id, int build_index = -1);
void deleteCloudSavesById(const std::string& product_id, int build_index = -1);
void checkOrphans(); void checkOrphans();
void checkStatus(); void checkStatus();
void updateCache(); void updateCache();
@ -113,9 +123,16 @@ class Downloader
void galaxyInstallGame(const std::string& product_id, int build_index = -1, const unsigned int& iGalaxyArch = GlobalConstants::ARCH_X64); void galaxyInstallGame(const std::string& product_id, int build_index = -1, const unsigned int& iGalaxyArch = GlobalConstants::ARCH_X64);
void galaxyInstallGameById(const std::string& product_id, int build_index = -1, const unsigned int& iGalaxyArch = GlobalConstants::ARCH_X64); void galaxyInstallGameById(const std::string& product_id, int build_index = -1, const unsigned int& iGalaxyArch = GlobalConstants::ARCH_X64);
void galaxyShowBuilds(const std::string& product_id, int build_index = -1); void galaxyShowBuilds(const std::string& product_id, int build_index = -1);
void galaxyShowCloudSaves(const std::string& product_id, int build_index = -1);
void galaxyShowLocalCloudSaves(const std::string& product_id, int build_index = -1);
void galaxyShowLocalCloudSavesById(const std::string& product_id, int build_index = -1);
void galaxyShowBuildsById(const std::string& product_id, int build_index = -1); void galaxyShowBuildsById(const std::string& product_id, int build_index = -1);
void galaxyShowCloudSavesById(const std::string& product_id, int build_index = -1);
protected: protected:
private: private:
std::map<std::string, std::string> cloudSaveLocations(const std::string& product_id, int build_index);
int cloudSaveListByIdForEach(const std::string& product_id, int build_index, const std::function<void(cloudSaveFile &)> &f);
CURLcode downloadFile(const std::string& url, const std::string& filepath, const std::string& xml_data = std::string(), const std::string& gamename = std::string()); CURLcode downloadFile(const std::string& url, const std::string& filepath, const std::string& xml_data = std::string(), const std::string& gamename = std::string());
int repairFile(const std::string& url, const std::string& filepath, const std::string& xml_data = std::string(), const std::string& gamename = std::string()); int repairFile(const std::string& url, const std::string& filepath, const std::string& xml_data = std::string(), const std::string& gamename = std::string());
int getGameDetails(); int getGameDetails();
@ -133,6 +150,8 @@ class Downloader
static std::string getChangelogFromJSON(const Json::Value& json); static std::string getChangelogFromJSON(const Json::Value& json);
void saveChangelog(const std::string& changelog, const std::string& filepath); void saveChangelog(const std::string& changelog, const std::string& filepath);
static void processDownloadQueue(Config conf, const unsigned int& tid); static void processDownloadQueue(Config conf, const unsigned int& tid);
static void processCloudSaveDownloadQueue(Config conf, const unsigned int& tid);
static void processCloudSaveUploadQueue(Config conf, const unsigned int& tid);
static int progressCallbackForThread(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow); static int progressCallbackForThread(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
template <typename T> void printProgress(const ThreadSafeQueue<T>& download_queue); template <typename T> void printProgress(const ThreadSafeQueue<T>& download_queue);
static void getGameDetailsThread(Config config, const unsigned int& tid); static void getGameDetailsThread(Config config, const unsigned int& tid);

View File

@ -46,16 +46,20 @@ class galaxyAPI
galaxyAPI(CurlConfig& conf); galaxyAPI(CurlConfig& conf);
virtual ~galaxyAPI(); virtual ~galaxyAPI();
int init(); int init();
bool isTokenExpired(); bool isTokenExpired();
bool refreshLogin(); bool refreshLogin();
bool refreshLogin(const std::string &clientId, const std::string &clientSecret, const std::string &refreshToken, bool newSession);
Json::Value getProductBuilds(const std::string& product_id, const std::string& platform = "windows", const std::string& generation = "2"); Json::Value getProductBuilds(const std::string& product_id, const std::string& platform = "windows", const std::string& generation = "2");
Json::Value getManifestV1(const std::string& product_id, const std::string& build_id, const std::string& manifest_id = "repository", const std::string& platform = "windows"); Json::Value getManifestV1(const std::string& product_id, const std::string& build_id, const std::string& manifest_id = "repository", const std::string& platform = "windows");
Json::Value getManifestV1(const std::string& manifest_url); Json::Value getManifestV1(const std::string& manifest_url);
Json::Value getManifestV2(std::string manifest_hash, const bool& is_dependency = false); Json::Value getManifestV2(std::string manifest_hash, const bool& is_dependency = false);
Json::Value getCloudPathAsJson(const std::string &clientId);
Json::Value getSecureLink(const std::string& product_id, const std::string& path); Json::Value getSecureLink(const std::string& product_id, const std::string& path);
Json::Value getDependencyLink(const std::string& path); Json::Value getDependencyLink(const std::string& path);
std::string getResponse(const std::string& url); std::string getResponse(const std::string& url, const char *encoding = nullptr);
Json::Value getResponseJson(const std::string& url); Json::Value getResponseJson(const std::string& url, const char *encoding = nullptr);
std::string hashToGalaxyPath(const std::string& hash); std::string hashToGalaxyPath(const std::string& hash);
std::vector<galaxyDepotItem> getDepotItemsVector(const std::string& hash, const bool& is_dependency = false); std::vector<galaxyDepotItem> getDepotItemsVector(const std::string& hash, const bool& is_dependency = false);
Json::Value getProductInfo(const std::string& product_id); Json::Value getProductInfo(const std::string& product_id);

View File

@ -66,6 +66,7 @@ namespace Util
int createXML(std::string filepath, uintmax_t chunk_size, std::string xml_dir = std::string()); int createXML(std::string filepath, uintmax_t chunk_size, std::string xml_dir = std::string());
int getGameSpecificConfig(std::string gamename, gameSpecificConfig* conf, std::string directory = std::string()); int getGameSpecificConfig(std::string gamename, gameSpecificConfig* conf, std::string directory = std::string());
int replaceString(std::string& str, const std::string& to_replace, const std::string& replace_with); int replaceString(std::string& str, const std::string& to_replace, const std::string& replace_with);
int replaceAllString(std::string& str, const std::string& to_replace, const std::string& replace_with);
void filepathReplaceReservedStrings(std::string& str, const std::string& gamename, const unsigned int& platformId = 0, const std::string& dlcname = ""); void filepathReplaceReservedStrings(std::string& str, const std::string& gamename, const unsigned int& platformId = 0, const std::string& dlcname = "");
void setFilePermissions(const boost::filesystem::path& path, const boost::filesystem::perms& permissions); void setFilePermissions(const boost::filesystem::path& path, const boost::filesystem::perms& permissions);
int getTerminalWidth(); int getTerminalWidth();
@ -90,6 +91,7 @@ namespace Util
CURLcode CurlHandleGetResponse(CURL* curlhandle, std::string& response, int max_retries = -1); CURLcode CurlHandleGetResponse(CURL* curlhandle, std::string& response, int max_retries = -1);
curl_off_t CurlWriteMemoryCallback(char *ptr, curl_off_t size, curl_off_t nmemb, void *userp); curl_off_t CurlWriteMemoryCallback(char *ptr, curl_off_t size, curl_off_t nmemb, void *userp);
curl_off_t CurlWriteChunkMemoryCallback(void *contents, curl_off_t size, curl_off_t nmemb, void *userp); curl_off_t CurlWriteChunkMemoryCallback(void *contents, curl_off_t size, curl_off_t nmemb, void *userp);
curl_off_t CurlReadChunkMemoryCallback(void *contents, curl_off_t size, curl_off_t nmemb, ChunkMemoryStruct *userp);
template<typename ... Args> std::string formattedString(const std::string& format, Args ... args) template<typename ... Args> std::string formattedString(const std::string& format, Args ... args)
{ {

View File

@ -24,6 +24,18 @@ template<typename T> void set_vm_value(std::map<std::string, bpo::variable_value
vm[option].value() = boost::any(value); vm[option].value() = boost::any(value);
} }
void ensure_trailing_slash(std::string &path, const char *default_ = nullptr) {
if (!path.empty())
{
if (path.at(path.length()-1)!='/')
path += "/";
}
else
{
path = default_; // Directory wasn't specified, use current directory
}
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct sigaction act; struct sigaction act;
@ -151,6 +163,11 @@ int main(int argc, char *argv[])
std::string galaxy_product_id_install; std::string galaxy_product_id_install;
std::string galaxy_product_id_show_builds; std::string galaxy_product_id_show_builds;
std::string galaxy_product_id_show_cloud_paths;
std::string galaxy_product_id_show_local_cloud_paths;
std::string galaxy_product_cloud_saves;
std::string galaxy_product_cloud_saves_delete;
std::string galaxy_upload_product_cloud_saves;
std::string tags; std::string tags;
std::vector<std::string> vFileIdStrings; std::vector<std::string> vFileIdStrings;
@ -213,6 +230,11 @@ int main(int argc, char *argv[])
("cacert", bpo::value<std::string>(&Globals::globalConfig.curlConf.sCACertPath)->default_value(""), "Path to CA certificate bundle in PEM format") ("cacert", bpo::value<std::string>(&Globals::globalConfig.curlConf.sCACertPath)->default_value(""), "Path to CA certificate bundle in PEM format")
("respect-umask", bpo::value<bool>(&Globals::globalConfig.bRespectUmask)->zero_tokens()->default_value(false), "Do not adjust permissions of sensitive files") ("respect-umask", bpo::value<bool>(&Globals::globalConfig.bRespectUmask)->zero_tokens()->default_value(false), "Do not adjust permissions of sensitive files")
("user-agent", bpo::value<std::string>(&Globals::globalConfig.curlConf.sUserAgent)->default_value(DEFAULT_USER_AGENT), "Set user agent") ("user-agent", bpo::value<std::string>(&Globals::globalConfig.curlConf.sUserAgent)->default_value(DEFAULT_USER_AGENT), "Set user agent")
("wine-prefix", bpo::value<std::string>(&Globals::globalConfig.dirConf.sWinePrefix)->default_value("."), "Set wineprefix directory")
("cloud-whitelist", bpo::value<std::vector<std::string>>(&Globals::globalConfig.cloudWhiteList)->multitoken(), "Include this list of cloud saves, by default all cloud saves are included\n Example: --cloud-whitelist saves/AutoSave-0 saves/AutoSave-1/screenshot.png")
("cloud-blacklist", bpo::value<std::vector<std::string>>(&Globals::globalConfig.cloudBlackList)->multitoken(), "Exclude this list of cloud saves\n Example: --cloud-blacklist saves/AutoSave-0 saves/AutoSave-1/screenshot.png")
("cloud-force", bpo::value<bool>(&Globals::globalConfig.bCloudForce)->zero_tokens()->default_value(false), "Download or Upload cloud saves even if they're up-to-date\nDelete remote cloud saves even if no saves are whitelisted")
#ifdef USE_QT_GUI_LOGIN #ifdef USE_QT_GUI_LOGIN
("enable-login-gui", bpo::value<bool>(&Globals::globalConfig.bEnableLoginGUI)->zero_tokens()->default_value(false), "Enable login GUI when encountering reCAPTCHA on login form") ("enable-login-gui", bpo::value<bool>(&Globals::globalConfig.bEnableLoginGUI)->zero_tokens()->default_value(false), "Enable login GUI when encountering reCAPTCHA on login form")
#endif #endif
@ -271,6 +293,11 @@ int main(int argc, char *argv[])
options_cli_experimental.add_options() options_cli_experimental.add_options()
("galaxy-install", bpo::value<std::string>(&galaxy_product_id_install)->default_value(""), "Install game using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345") ("galaxy-install", bpo::value<std::string>(&galaxy_product_id_install)->default_value(""), "Install game using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-show-builds", bpo::value<std::string>(&galaxy_product_id_show_builds)->default_value(""), "Show game builds using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345") ("galaxy-show-builds", bpo::value<std::string>(&galaxy_product_id_show_builds)->default_value(""), "Show game builds using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-download-cloud-saves", bpo::value<std::string>(&galaxy_product_cloud_saves)->default_value(""), "Download cloud saves using product-id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-upload-cloud-saves", bpo::value<std::string>(&galaxy_upload_product_cloud_saves)->default_value(""), "Upload cloud saves using product-id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-show-cloud-saves", bpo::value<std::string>(&galaxy_product_id_show_cloud_paths)->default_value(""), "Show game cloud-saves using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-show-local-cloud-saves", bpo::value<std::string>(&galaxy_product_id_show_local_cloud_paths)->default_value(""), "Show local cloud-saves using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-delete-cloud-saves", bpo::value<std::string>(&galaxy_product_cloud_saves_delete)->default_value(""), "Delete cloud-saves using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-platform", bpo::value<std::string>(&sGalaxyPlatform)->default_value("w"), galaxy_platform_text.c_str()) ("galaxy-platform", bpo::value<std::string>(&sGalaxyPlatform)->default_value("w"), galaxy_platform_text.c_str())
("galaxy-language", bpo::value<std::string>(&sGalaxyLanguage)->default_value("en"), galaxy_language_text.c_str()) ("galaxy-language", bpo::value<std::string>(&sGalaxyLanguage)->default_value("en"), galaxy_language_text.c_str())
("galaxy-arch", bpo::value<std::string>(&sGalaxyArch)->default_value("x64"), galaxy_arch_text.c_str()) ("galaxy-arch", bpo::value<std::string>(&sGalaxyArch)->default_value("x64"), galaxy_arch_text.c_str())
@ -578,15 +605,8 @@ int main(int argc, char *argv[])
} }
// Make sure that directory has trailing slash // Make sure that directory has trailing slash
if (!Globals::globalConfig.dirConf.sDirectory.empty()) ensure_trailing_slash(Globals::globalConfig.dirConf.sDirectory, "./");
{ ensure_trailing_slash(Globals::globalConfig.dirConf.sWinePrefix, "./");
if (Globals::globalConfig.dirConf.sDirectory.at(Globals::globalConfig.dirConf.sDirectory.length()-1)!='/')
Globals::globalConfig.dirConf.sDirectory += "/";
}
else
{
Globals::globalConfig.dirConf.sDirectory = "./"; // Directory wasn't specified, use current directory
}
// CA certificate bundle // CA certificate bundle
if (Globals::globalConfig.curlConf.sCACertPath.empty()) if (Globals::globalConfig.curlConf.sCACertPath.empty())
@ -777,6 +797,39 @@ int main(int argc, char *argv[])
} }
downloader.galaxyShowBuilds(product_id, build_index); downloader.galaxyShowBuilds(product_id, build_index);
} }
else if (!galaxy_product_id_show_cloud_paths.empty())
{
int build_index = -1;
std::vector<std::string> tokens = Util::tokenize(galaxy_product_id_show_cloud_paths, "/");
std::string product_id = tokens[0];
if (tokens.size() == 2)
{
build_index = std::stoi(tokens[1]);
}
downloader.galaxyShowCloudSaves(product_id, build_index);
}
else if (!galaxy_product_id_show_local_cloud_paths.empty())
{
int build_index = -1;
std::vector<std::string> tokens = Util::tokenize(galaxy_product_id_show_local_cloud_paths, "/");
std::string product_id = tokens[0];
if (tokens.size() == 2)
{
build_index = std::stoi(tokens[1]);
}
downloader.galaxyShowLocalCloudSaves(product_id, build_index);
}
else if (!galaxy_product_cloud_saves_delete.empty())
{
int build_index = -1;
std::vector<std::string> tokens = Util::tokenize(galaxy_product_cloud_saves_delete, "/");
std::string product_id = tokens[0];
if (tokens.size() == 2)
{
build_index = std::stoi(tokens[1]);
}
downloader.deleteCloudSaves(product_id, build_index);
}
else if (!galaxy_product_id_install.empty()) else if (!galaxy_product_id_install.empty())
{ {
int build_index = -1; int build_index = -1;
@ -788,6 +841,26 @@ int main(int argc, char *argv[])
} }
downloader.galaxyInstallGame(product_id, build_index, Globals::globalConfig.dlConf.iGalaxyArch); downloader.galaxyInstallGame(product_id, build_index, Globals::globalConfig.dlConf.iGalaxyArch);
} }
else if (!galaxy_product_cloud_saves.empty()) {
int build_index = -1;
std::vector<std::string> tokens = Util::tokenize(galaxy_product_cloud_saves, "/");
std::string product_id = tokens[0];
if (tokens.size() == 2)
{
build_index = std::stoi(tokens[1]);
}
downloader.downloadCloudSaves(product_id, build_index);
}
else if (!galaxy_upload_product_cloud_saves.empty()) {
int build_index = -1;
std::vector<std::string> tokens = Util::tokenize(galaxy_upload_product_cloud_saves, "/");
std::string product_id = tokens[0];
if (tokens.size() == 2)
{
build_index = std::stoi(tokens[1]);
}
downloader.uploadCloudSaves(product_id, build_index);
}
else else
{ {
if (!Globals::globalConfig.bLogin) if (!Globals::globalConfig.bLogin)

File diff suppressed because it is too large Load Diff

View File

@ -53,23 +53,33 @@ int galaxyAPI::init()
return res; return res;
} }
bool galaxyAPI::refreshLogin() bool galaxyAPI::refreshLogin(const std::string &clientId, const std::string &clientSecret, const std::string &refreshToken, bool newSession)
{ {
std::string refresh_url = "https://auth.gog.com/token?client_id=" + Globals::galaxyConf.getClientId() std::string refresh_url = "https://auth.gog.com/token?client_id=" + clientId
+ "&client_secret=" + Globals::galaxyConf.getClientSecret() + "&client_secret=" + clientSecret
+ "&grant_type=refresh_token" + "&grant_type=refresh_token"
+ "&refresh_token=" + Globals::galaxyConf.getRefreshToken(); + "&refresh_token=" + refreshToken
+ (newSession ? "" : "&without_new_session=1");
// std::cout << refresh_url << std::endl;
Json::Value token_json = this->getResponseJson(refresh_url); Json::Value token_json = this->getResponseJson(refresh_url);
if (token_json.empty()) if (token_json.empty())
return false; return false;
token_json["client_id"] = clientId;
token_json["client_secret"] = clientSecret;
Globals::galaxyConf.setJSON(token_json); Globals::galaxyConf.setJSON(token_json);
return true; return true;
} }
bool galaxyAPI::refreshLogin()
{
return refreshLogin(Globals::galaxyConf.getClientId(), Globals::galaxyConf.getClientSecret(), Globals::galaxyConf.getRefreshToken(), true);
}
bool galaxyAPI::isTokenExpired() bool galaxyAPI::isTokenExpired()
{ {
bool res = false; bool res = false;
@ -80,7 +90,7 @@ bool galaxyAPI::isTokenExpired()
return res; return res;
} }
std::string galaxyAPI::getResponse(const std::string& url) std::string galaxyAPI::getResponse(const std::string& url, const char *encoding)
{ {
struct curl_slist *header = NULL; struct curl_slist *header = NULL;
@ -92,13 +102,26 @@ std::string galaxyAPI::getResponse(const std::string& url)
std::string bearer = "Authorization: Bearer " + access_token; std::string bearer = "Authorization: Bearer " + access_token;
header = curl_slist_append(header, bearer.c_str()); header = curl_slist_append(header, bearer.c_str());
} }
if(encoding) {
auto accept = "Accept: " + std::string(encoding);
header = curl_slist_append(header, accept.c_str());
}
curl_easy_setopt(curlhandle, CURLOPT_HTTPHEADER, header); curl_easy_setopt(curlhandle, CURLOPT_HTTPHEADER, header);
curl_easy_setopt(curlhandle, CURLOPT_URL, url.c_str()); curl_easy_setopt(curlhandle, CURLOPT_URL, url.c_str());
curl_easy_setopt(curlhandle, CURLOPT_ACCEPT_ENCODING, ""); curl_easy_setopt(curlhandle, CURLOPT_ACCEPT_ENCODING, "");
int max_retries = std::min(3, Globals::globalConfig.iRetries); int max_retries = std::min(3, Globals::globalConfig.iRetries);
std::string response; std::string response;
Util::CurlHandleGetResponse(curlhandle, response, max_retries); auto res = Util::CurlHandleGetResponse(curlhandle, response, max_retries);
if(res) {
long int response_code = 0;
curl_easy_getinfo(curlhandle, CURLINFO_RESPONSE_CODE, &response_code);
std::cout << "Response code for " << url << " is [" << response_code << ']' << std::endl;
}
curl_easy_setopt(curlhandle, CURLOPT_ACCEPT_ENCODING, NULL); curl_easy_setopt(curlhandle, CURLOPT_ACCEPT_ENCODING, NULL);
curl_easy_setopt(curlhandle, CURLOPT_HTTPHEADER, NULL); curl_easy_setopt(curlhandle, CURLOPT_HTTPHEADER, NULL);
@ -107,9 +130,9 @@ std::string galaxyAPI::getResponse(const std::string& url)
return response; return response;
} }
Json::Value galaxyAPI::getResponseJson(const std::string& url) Json::Value galaxyAPI::getResponseJson(const std::string& url, const char *encoding)
{ {
std::istringstream response(this->getResponse(url)); std::istringstream response(this->getResponse(url, encoding));
Json::Value json; Json::Value json;
if (!response.str().empty()) if (!response.str().empty())
@ -149,8 +172,13 @@ Json::Value galaxyAPI::getResponseJson(const std::string& url)
catch(const Json::Exception& exc) catch(const Json::Exception& exc)
{ {
// Failed to parse json // Failed to parse json
std::cout << "Failed to parse json: " << exc.what();
} }
} }
else {
std::cout << "Failed to parse json: " << exc.what();
}
} }
} }
@ -190,6 +218,12 @@ Json::Value galaxyAPI::getManifestV2(std::string manifest_hash, const bool& is_d
return this->getResponseJson(url); return this->getResponseJson(url);
} }
Json::Value galaxyAPI::getCloudPathAsJson(const std::string &clientId) {
std::string url = "https://remote-config.gog.com/components/galaxy_client/clients/" + clientId + "?component_version=2.0.51";
return this->getResponseJson(url);
}
Json::Value galaxyAPI::getSecureLink(const std::string& product_id, const std::string& path) Json::Value galaxyAPI::getSecureLink(const std::string& product_id, const std::string& path)
{ {
std::string url = "https://content-system.gog.com/products/" + product_id + "/secure_link?generation=2&path=" + path + "&_version=2"; std::string url = "https://content-system.gog.com/products/" + product_id + "/secure_link?generation=2&path=" + path + "&_version=2";

View File

@ -8,6 +8,9 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/algorithm/string/case_conv.hpp> #include <boost/algorithm/string/case_conv.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <tinyxml2.h> #include <tinyxml2.h>
#include <json/json.h> #include <json/json.h>
#include <fstream> #include <fstream>
@ -391,6 +394,22 @@ int Util::replaceString(std::string& str, const std::string& to_replace, const s
return 1; return 1;
} }
int Util::replaceAllString(std::string& str, const std::string& to_replace, const std::string& replace_with) {
size_t pos = str.find(to_replace);
if (pos == std::string::npos)
{
return 0;
}
do {
str.replace(str.begin()+pos, str.begin()+pos+to_replace.length(), replace_with);
pos = str.find(to_replace, pos + to_replace.length());
} while(pos != std::string::npos);
return 1;
}
void Util::filepathReplaceReservedStrings(std::string& str, const std::string& gamename, const unsigned int& platformId, const std::string& dlcname) void Util::filepathReplaceReservedStrings(std::string& str, const std::string& gamename, const unsigned int& platformId, const std::string& dlcname)
{ {
std::string platform; std::string platform;
@ -749,7 +768,6 @@ void Util::CurlHandleSetDefaultOptions(CURL* curlhandle, const CurlConfig& conf)
curl_easy_setopt(curlhandle, CURLOPT_USERAGENT, conf.sUserAgent.c_str()); curl_easy_setopt(curlhandle, CURLOPT_USERAGENT, conf.sUserAgent.c_str());
curl_easy_setopt(curlhandle, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(curlhandle, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1); curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1);
curl_easy_setopt(curlhandle, CURLOPT_FAILONERROR, true);
curl_easy_setopt(curlhandle, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curlhandle, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curlhandle, CURLOPT_CONNECTTIMEOUT, conf.iTimeout); curl_easy_setopt(curlhandle, CURLOPT_CONNECTTIMEOUT, conf.iTimeout);
curl_easy_setopt(curlhandle, CURLOPT_FAILONERROR, true); curl_easy_setopt(curlhandle, CURLOPT_FAILONERROR, true);
@ -823,8 +841,9 @@ CURLcode Util::CurlHandleGetResponse(CURL* curlhandle, std::string& response, in
// Retry on CURLE_HTTP_RETURNED_ERROR if response code is not "404 Not Found" // Retry on CURLE_HTTP_RETURNED_ERROR if response code is not "404 Not Found"
case CURLE_HTTP_RETURNED_ERROR: case CURLE_HTTP_RETURNED_ERROR:
curl_easy_getinfo(curlhandle, CURLINFO_RESPONSE_CODE, &response_code); curl_easy_getinfo(curlhandle, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code == 404) if (response_code == 404 || response_code == 403) {
bShouldRetry = false; bShouldRetry = false;
}
else else
bShouldRetry = true; bShouldRetry = true;
break; break;
@ -865,3 +884,14 @@ curl_off_t Util::CurlWriteChunkMemoryCallback(void *contents, curl_off_t size, c
return realsize; return realsize;
} }
curl_off_t Util::CurlReadChunkMemoryCallback(void *contents, curl_off_t size, curl_off_t nmemb, ChunkMemoryStruct *mem) {
curl_off_t realsize = std::min(size * nmemb, mem->size);
std::copy(mem->memory, mem->memory + realsize, (char*)contents);
mem->size -= realsize;
mem->memory += realsize;
return realsize;
}

View File

@ -264,6 +264,9 @@ std::vector<gameItem> Website::getGames()
// Login to GOG website // Login to GOG website
int Website::Login(const std::string& email, const std::string& password) int Website::Login(const std::string& email, const std::string& password)
{ {
// Reset client id and client secret to ensure we can log-in
Globals::galaxyConf.resetClient();
int res = 0; int res = 0;
std::string postdata; std::string postdata;
std::ostringstream memory; std::ostringstream memory;