From 83bc5e3fd64ea96fc08aa3c3b21c706b39c4c321 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 31 Jul 2019 16:28:18 -0700 Subject: [PATCH 1/4] Add build tags to Windows launcher --- launchers/win32/LauncherManager.cpp | 92 ++++++++++++++++++++--------- launchers/win32/LauncherManager.h | 11 +++- 2 files changed, 73 insertions(+), 30 deletions(-) diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp index 5e452b97b2..9aaae7c8ca 100644 --- a/launchers/win32/LauncherManager.cpp +++ b/launchers/win32/LauncherManager.cpp @@ -36,6 +36,7 @@ void LauncherManager::init(BOOL allowUpdate, ContinueActionOnStart continueActio } addToLog(_T("Launcher is running version: " + _launcherVersion)); addToLog(_T("Getting most recent builds")); + _isInstalled = isApplicationInstalled(_currentVersion, _domainURL, _contentURL, _loggedIn, _organizationBuildTag); getMostRecentBuilds(_latestLauncherURL, _latestLauncherVersion, _latestApplicationURL, _latestVersion); } @@ -260,14 +261,14 @@ BOOL LauncherManager::deleteShortcuts() { } BOOL LauncherManager::isApplicationInstalled(CString& version, CString& domain, - CString& content, bool& loggedIn) { + CString& content, bool& loggedIn, CString& organizationBuildTag) { CString applicationDir; getAndCreatePaths(PathType::Launcher_Directory, applicationDir); CString applicationPath = applicationDir + "interface\\interface.exe"; BOOL isInstalled = PathFileExistsW(applicationPath); BOOL configFileExist = PathFileExistsW(applicationDir + _T("interface\\config.json")); if (configFileExist) { - LauncherUtils::ResponseError status = readConfigJSON(version, domain, content, loggedIn); + LauncherUtils::ResponseError status = readConfigJSON(version, domain, content, loggedIn, organizationBuildTag); return isInstalled && status == LauncherUtils::ResponseError::NoError; } return FALSE; @@ -326,7 +327,6 @@ BOOL LauncherManager::getInstalledVersion(const CString& path, CString& version) return success; } - HWND LauncherManager::launchApplication() { CString installDir; LauncherManager::getAndCreatePaths(PathType::Interface_Directory, installDir); @@ -368,6 +368,7 @@ BOOL LauncherManager::createConfigJSON() { config["launcherPath"] = LauncherUtils::cStringToStd(applicationPath); config["version"] = LauncherUtils::cStringToStd(_latestVersion); config["domain"] = LauncherUtils::cStringToStd(_domainURL); + config["organizationBuildTag"] = LauncherUtils::cStringToStd(_organizationBuildTag); CString content; getAndCreatePaths(PathType::Content_Directory, content); config["content"] = LauncherUtils::cStringToStd(content); @@ -377,7 +378,7 @@ BOOL LauncherManager::createConfigJSON() { } LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, CString& domain, - CString& content, bool& loggedIn) { + CString& content, bool& loggedIn, CString& organizationBuildTag) { CString configPath; getAndCreatePaths(PathType::Interface_Directory, configPath); configPath += "\\config.json"; @@ -394,6 +395,13 @@ LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, C version = config["version"].asCString(); domain = config["domain"].asCString(); content = config["content"].asCString(); + + if (config["organizationBuildTag"].isString()) { + organizationBuildTag = config["organizationBuildTag"].asCString(); + } else { + organizationBuildTag = ""; + } + configFile.close(); return LauncherUtils::ResponseError::NoError; } @@ -401,6 +409,37 @@ LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, C return LauncherUtils::ResponseError::ParsingJSON; } +bool findBuildInResponse(const Json::Value& json, const CString& tag, CString& interfaceUrlOut, CString& interfaceVersionOut) { + if (json["results"].isArray()) { + auto& results = json["results"]; + int count = results.size(); + for (int i = 0; i < count; i++) { + if (results[i].isObject()) { + Json::Value result = results[i]; + if (result["name"].asCString() == tag) { + if (result["latest_version"].isInt()) { + std::string version = std::to_string(result["latest_version"].asInt()); + interfaceVersionOut = CString(version.c_str()); + } else { + return false; + } + if (result["installers"].isObject() && + result["installers"]["windows"].isObject() && + result["installers"]["windows"]["zip_url"].isString()) { + interfaceUrlOut = result["installers"]["windows"]["zip_url"].asCString(); + } else { + return false; + } + return true; + } + } + } + } + + return false; +} + + LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString& hash) { CString contentTypeJson = L"content-type:application/json"; CString response; @@ -417,6 +456,13 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString if (json["content_set_url"].isString() && json["domain"].isString()) { _contentURL = json["content_set_url"].asCString(); _domainURL = json["domain"].asCString(); + _organizationBuildTag = json.get("build_tag", "").asCString(); + auto buildTag = _organizationBuildTag.IsEmpty() ? _defaultBuildTag : _organizationBuildTag; + + if (!findBuildInResponse(_latestBuilds, buildTag, _latestApplicationURL, _latestVersion)) { + return LauncherUtils::ResponseError::ParsingJSON; + } + return LauncherUtils::ResponseError::NoError; } } @@ -429,7 +475,9 @@ void LauncherManager::getMostRecentBuilds(CString& launcherUrlOut, CString& laun std::function httpCallback = [&](CString response, int err) { LauncherUtils::ResponseError error = LauncherUtils::ResponseError(err); if (error == LauncherUtils::ResponseError::NoError) { - Json::Value json; + Json::Value& json = _latestBuilds; + _defaultBuildTag = json.get("default_tag", "hqlauncher").asCString(); + auto buildTag = _organizationBuildTag.IsEmpty() ? _defaultBuildTag : _organizationBuildTag; if (LauncherUtils::parseJSON(response, json)) { if (json["launcher"].isObject()) { if (json["launcher"]["windows"].isObject() && json["launcher"]["windows"]["url"].isString()) { @@ -440,24 +488,12 @@ void LauncherManager::getMostRecentBuilds(CString& launcherUrlOut, CString& laun launcherVersionOut = CString(version.c_str()); } } - int count = json["count"].isInt() ? json["count"].asInt() : 0; - if (count > 0 && json["results"].isArray()) { - for (int i = 0; i < count; i++) { - if (json["results"][i].isObject()) { - Json::Value result = json["results"][i]; - if (result["latest_version"].isInt()) { - std::string version = std::to_string(result["latest_version"].asInt()); - interfaceVersionOut = CString(version.c_str()); - } - if (result["installers"].isObject() && - result["installers"]["windows"].isObject() && - result["installers"]["windows"]["zip_url"].isString()) { - interfaceUrlOut = result["installers"]["windows"]["zip_url"].asCString(); - } - } - } + + if (launcherUrlOut.IsEmpty() || launcherVersionOut.IsEmpty()) { + error = LauncherUtils::ResponseError::ParsingJSON; } - if (launcherUrlOut.IsEmpty() || launcherVersionOut.IsEmpty() || interfaceUrlOut.IsEmpty() || interfaceVersionOut.IsEmpty()) { + + if (!findBuildInResponse(json, buildTag, _latestApplicationURL, _latestVersion)) { error = LauncherUtils::ResponseError::ParsingJSON; } } @@ -473,8 +509,8 @@ void LauncherManager::getMostRecentBuilds(CString& launcherUrlOut, CString& laun void LauncherManager::onMostRecentBuildsReceived(const CString& response, LauncherUtils::ResponseError error) { if (error == LauncherUtils::ResponseError::NoError) { addToLog(_T("Latest launcher version: ") + _latestLauncherVersion); - CString currentVersion; - BOOL isInstalled = (isApplicationInstalled(currentVersion, _domainURL, _contentURL, _loggedIn) && _loggedIn); + CString currentVersion = _currentVersion; + BOOL isInstalled = _isInstalled && _loggedIn; bool newInterfaceVersion = _latestVersion.Compare(currentVersion) != 0; bool newLauncherVersion = _latestLauncherVersion.Compare(_launcherVersion) != 0 && _updateLauncherAllowed; if (newLauncherVersion) { @@ -511,7 +547,7 @@ void LauncherManager::onMostRecentBuildsReceived(const CString& response, Launch _shouldWait = FALSE; } else { - _hasFailed = true; + setFailed(true); CString msg; msg.Format(_T("Getting most recent builds has failed with error: %d"), error); addToLog(msg); @@ -611,7 +647,7 @@ BOOL LauncherManager::extractApplication() { onZipExtracted((ProcessType)type, size); } else { addToLog(_T("Error decompressing application zip file.")); - _hasFailed = true; + setFailed(true); } }; std::function onProgress = [&](float progress) { @@ -688,7 +724,7 @@ BOOL LauncherManager::installContent() { } else { addToLog(_T("Error decompressing content zip file.")); - _hasFailed = true; + setFailed(_hasFailed); } }; std::function onProgress = [&](float progress) { @@ -728,7 +764,7 @@ BOOL LauncherManager::downloadFile(ProcessType type, const CString& url, CString } else { addToLog(_T("Error downloading application.")); } - _hasFailed = true; + setFailed(_hasFailed); } }; std::function onProgress = [&, type](float progress) { diff --git a/launchers/win32/LauncherManager.h b/launchers/win32/LauncherManager.h index d0c81ae75b..bba54fb10b 100644 --- a/launchers/win32/LauncherManager.h +++ b/launchers/win32/LauncherManager.h @@ -76,7 +76,7 @@ public: BOOL getAndCreatePaths(PathType type, CString& outPath); BOOL getInstalledVersion(const CString& path, CString& version); BOOL isApplicationInstalled(CString& version, CString& domain, - CString& content, bool& loggedIn); + CString& content, bool& loggedIn, CString& organizationBuildTag); LauncherUtils::ResponseError getAccessTokenForCredentials(const CString& username, const CString& password); void getMostRecentBuilds(CString& launcherUrlOut, CString& launcherVersionOut, @@ -84,7 +84,7 @@ public: CString& interfaceVersionOut); LauncherUtils::ResponseError readOrganizationJSON(const CString& hash); LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain, - CString& content, bool& loggedIn); + CString& content, bool& loggedIn, CString& organizationBuildTag); BOOL createConfigJSON(); BOOL createApplicationRegistryKeys(int size); BOOL deleteApplicationRegistryKeys(); @@ -139,10 +139,12 @@ public: private: ProcessType _currentProcess { ProcessType::DownloadApplication }; void onMostRecentBuildsReceived(const CString& response, LauncherUtils::ResponseError error); + CString _latestApplicationURL; CString _latestVersion; CString _latestLauncherURL; CString _latestLauncherVersion; + CString _contentURL; CString _domainURL; CString _version; @@ -152,6 +154,8 @@ private: CString _contentZipPath; CString _launcherVersion; CString _tempLauncherPath; + CString _currentVersion; + bool _isInstalled{ false }; bool _loggedIn { false }; bool _hasFailed { false }; BOOL _shouldUpdate { FALSE }; @@ -171,4 +175,7 @@ private: float _progressOffset { 0.0f }; float _progress { 0.0f }; CStdioFile _logFile; + Json::Value _latestBuilds; + CString _defaultBuildTag; + CString _organizationBuildTag; }; From da1b2e9ec8502ded8dff7c816a50dd16821ef1d3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 12 Aug 2019 16:30:19 -0700 Subject: [PATCH 2/4] Add method for overriding builds API url in win32 launcher --- launchers/win32/LauncherManager.cpp | 27 ++++++++++++++++++++++++--- launchers/win32/LauncherUtils.cpp | 11 ++++++----- launchers/win32/LauncherUtils.h | 5 +++-- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp index 9aaae7c8ca..bba23966a6 100644 --- a/launchers/win32/LauncherManager.cpp +++ b/launchers/win32/LauncherManager.cpp @@ -445,7 +445,7 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString CString response; CString url = _T("/organizations/") + hash + _T(".json"); LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(getHttpUserAgent(), - L"orgs.highfidelity.com", url, + true, L"orgs.highfidelity.com", url, contentTypeJson, CStringA(), response, false); if (error != LauncherUtils::ResponseError::NoError) { @@ -500,9 +500,29 @@ void LauncherManager::getMostRecentBuilds(CString& launcherUrlOut, CString& laun } onMostRecentBuildsReceived(response, error); }; + + bool useHTTPS{ true }; + + CString domainName; + if (domainName.GetEnvironmentVariable(L"HQ_LAUNCHER_BUILDS_DOMAIN")) { + addToLog(_T("Using overridden builds domain: ") + domainName); + useHTTPS = false; + } else { + domainName = L"thunder.highfidelity.com"; + } + + CString pathName; + if (pathName.GetEnvironmentVariable(L"HQ_LAUNCHER_BUILDS_PATH")) { + addToLog(_T("Using overridden builds path: ") + pathName); + useHTTPS = false; + } else { + pathName = L"/builds/api/tags/latest?format=json"; + } + LauncherUtils::httpCallOnThread(getHttpUserAgent(), - L"thunder.highfidelity.com", - L"/builds/api/tags/latest?format=json", + useHTTPS, + domainName, + pathName, contentTypeJson, CStringA(), false, httpCallback); } @@ -567,6 +587,7 @@ LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString contentTypeText = L"content-type:application/x-www-form-urlencoded"; CString response; LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(getHttpUserAgent(), + true, L"metaverse.highfidelity.com", L"/oauth/token", contentTypeText, post, diff --git a/launchers/win32/LauncherUtils.cpp b/launchers/win32/LauncherUtils.cpp index e0a85302f0..ef23073ca5 100644 --- a/launchers/win32/LauncherUtils.cpp +++ b/launchers/win32/LauncherUtils.cpp @@ -181,7 +181,7 @@ BOOL LauncherUtils::deleteRegistryKey(const CString& registryPath) { } LauncherUtils::ResponseError LauncherUtils::makeHTTPCall(const CString& callerName, - const CString& mainUrl, const CString& dirUrl, + bool useHTTPS, const CString& mainUrl, const CString& dirUrl, const CString& contentType, CStringA& postData, CString& response, bool isPost = false) { @@ -190,12 +190,12 @@ LauncherUtils::ResponseError LauncherUtils::makeHTTPCall(const CString& callerNa if (!hopen) { return ResponseError::Open; } - HINTERNET hconnect = WinHttpConnect(hopen, mainUrl, INTERNET_DEFAULT_HTTPS_PORT, 0); + HINTERNET hconnect = WinHttpConnect(hopen, mainUrl, useHTTPS ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0); if (!hconnect) { return ResponseError::Connect; } HINTERNET hrequest = WinHttpOpenRequest(hconnect, isPost ? L"POST" : L"GET", dirUrl, - NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); + NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, useHTTPS ? WINHTTP_FLAG_SECURE : 0); if (!hrequest) { return ResponseError::OpenRequest; } @@ -497,7 +497,7 @@ DWORD WINAPI LauncherUtils::deleteDirectoryThread(LPVOID lpParameter) { DWORD WINAPI LauncherUtils::httpThread(LPVOID lpParameter) { HttpThreadData& data = *((HttpThreadData*)lpParameter); CString response; - auto error = LauncherUtils::makeHTTPCall(data._callerName, data._mainUrl, data._dirUrl, + auto error = LauncherUtils::makeHTTPCall(data._callerName, data._useHTTPS, data._mainUrl, data._dirUrl, data._contentType, data._postData, response, data._isPost); data._callback(response, error); return 0; @@ -552,12 +552,13 @@ BOOL LauncherUtils::deleteDirectoryOnThread(const CString& dirPath, std::functio return FALSE; } -BOOL LauncherUtils::httpCallOnThread(const CString& callerName, const CString& mainUrl, const CString& dirUrl, +BOOL LauncherUtils::httpCallOnThread(const CString& callerName, bool useHTTPS, const CString& mainUrl, const CString& dirUrl, const CString& contentType, CStringA& postData, bool isPost, std::function callback) { DWORD myThreadID; HttpThreadData* httpThreadData = new HttpThreadData(); httpThreadData->_callerName = callerName; + httpThreadData->_useHTTPS = useHTTPS; httpThreadData->_mainUrl = mainUrl; httpThreadData->_dirUrl = dirUrl; httpThreadData->_contentType = contentType; diff --git a/launchers/win32/LauncherUtils.h b/launchers/win32/LauncherUtils.h index 32cd5031b4..6e4e2b6ad8 100644 --- a/launchers/win32/LauncherUtils.h +++ b/launchers/win32/LauncherUtils.h @@ -120,6 +120,7 @@ public: struct HttpThreadData { CString _callerName; + bool _useHTTPS; CString _mainUrl; CString _dirUrl; CString _contentType; @@ -137,7 +138,7 @@ public: }; static BOOL parseJSON(const CString& jsonTxt, Json::Value& jsonObject); - static ResponseError makeHTTPCall(const CString& callerName, const CString& mainUrl, + static ResponseError makeHTTPCall(const CString& callerName, bool useHTTPS, const CString& mainUrl, const CString& dirUrl, const CString& contentType, CStringA& postData, CString& response, bool isPost); static std::string cStringToStd(CString cstring); @@ -163,7 +164,7 @@ public: std::function callback, std::function progressCallback); static BOOL deleteDirectoryOnThread(const CString& dirPath, std::function callback); - static BOOL httpCallOnThread(const CString& callerName, const CString& mainUrl, const CString& dirUrl, + static BOOL httpCallOnThread(const CString& callerName, bool useHTTPS, const CString& mainUrl, const CString& dirUrl, const CString& contentType, CStringA& postData, bool isPost, std::function callback); From 328896b9edc6ce9c2dc811e92a214b1ffc30d330 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 12 Aug 2019 16:32:30 -0700 Subject: [PATCH 3/4] Fix calls to setFailed in win32 launcher --- launchers/win32/LauncherManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp index bba23966a6..ea9073763d 100644 --- a/launchers/win32/LauncherManager.cpp +++ b/launchers/win32/LauncherManager.cpp @@ -745,7 +745,7 @@ BOOL LauncherManager::installContent() { } else { addToLog(_T("Error decompressing content zip file.")); - setFailed(_hasFailed); + setFailed(true); } }; std::function onProgress = [&](float progress) { @@ -785,7 +785,7 @@ BOOL LauncherManager::downloadFile(ProcessType type, const CString& url, CString } else { addToLog(_T("Error downloading application.")); } - setFailed(_hasFailed); + setFailed(true); } }; std::function onProgress = [&, type](float progress) { From cf64492185bfdb577f415045e600e27b08a7ccbf Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 16 Aug 2019 12:51:09 -0700 Subject: [PATCH 4/4] Fix default_tag in win32 launcher not working --- launchers/win32/LauncherManager.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp index ea9073763d..991f7bd412 100644 --- a/launchers/win32/LauncherManager.cpp +++ b/launchers/win32/LauncherManager.cpp @@ -476,9 +476,11 @@ void LauncherManager::getMostRecentBuilds(CString& launcherUrlOut, CString& laun LauncherUtils::ResponseError error = LauncherUtils::ResponseError(err); if (error == LauncherUtils::ResponseError::NoError) { Json::Value& json = _latestBuilds; - _defaultBuildTag = json.get("default_tag", "hqlauncher").asCString(); - auto buildTag = _organizationBuildTag.IsEmpty() ? _defaultBuildTag : _organizationBuildTag; if (LauncherUtils::parseJSON(response, json)) { + _defaultBuildTag = json.get("default_tag", "").asCString(); + auto buildTag = _organizationBuildTag.IsEmpty() ? _defaultBuildTag : _organizationBuildTag; + addToLog(_T("Build tag is: ") + buildTag); + if (json["launcher"].isObject()) { if (json["launcher"]["windows"].isObject() && json["launcher"]["windows"]["url"].isString()) { launcherUrlOut = json["launcher"]["windows"]["url"].asCString(); @@ -494,6 +496,7 @@ void LauncherManager::getMostRecentBuilds(CString& launcherUrlOut, CString& laun } if (!findBuildInResponse(json, buildTag, _latestApplicationURL, _latestVersion)) { + addToLog(_T("Failed to find build")); error = LauncherUtils::ResponseError::ParsingJSON; } }