From 8e673cbb08615865044ed546a133259ff2756128 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Mon, 19 Oct 2020 18:14:41 -0600 Subject: [PATCH] web_backend: fix a regression introduced in 39c8d18 * A regression was in 39c8d18 and token verification function was broken. * The reason being `httplib` now requires OpenSSL 1.1+ API while LibreSSL 2.x provided OpenSSL 1.0 compatible API. * The bundled LibreSSL has been updated to 3.2.2 so it now provides OpenSSL 1.1 compatible API now. * Also the path hint has been added so that it will find the correct path to the CA certs on *nix systems. * An option is provided so that *nix system distributions/providers can use their own SSL implementations when compiling Yuzu/Citra to (hopefully) complies with their maintenance guidelines. * LURLParse is also removed since `httplib` can handle `scheme:host:port` string itself now. --- CMakeLists.txt | 2 + externals/CMakeLists.txt | 25 +-- externals/libressl | 2 +- externals/lurlparser/CMakeLists.txt | 8 - externals/lurlparser/LUrlParser.cpp | 265 ---------------------------- externals/lurlparser/LUrlParser.h | 78 -------- externals/lurlparser/README.md | 19 -- src/web_service/CMakeLists.txt | 2 +- src/web_service/web_backend.cpp | 20 +-- 9 files changed, 19 insertions(+), 402 deletions(-) delete mode 100644 externals/lurlparser/CMakeLists.txt delete mode 100644 externals/lurlparser/LUrlParser.cpp delete mode 100644 externals/lurlparser/LUrlParser.h delete mode 100644 externals/lurlparser/README.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e9502a974..366e86b7da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,8 @@ option(ENABLE_VULKAN "Enables Vulkan backend" ON) option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF) +option(USE_SYSTEM_SSL "Use system provided SSL library" OFF) + # Default to a Release build get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index e01ff69303..b8114f42ba 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -73,17 +73,20 @@ if (NOT LIBZIP_FOUND) endif() if (ENABLE_WEB_SERVICE) - # LibreSSL - set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "") - add_subdirectory(libressl EXCLUDE_FROM_ALL) - target_include_directories(ssl INTERFACE ./libressl/include) - target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP) - get_directory_property(OPENSSL_LIBRARIES - DIRECTORY libressl - DEFINITION OPENSSL_LIBS) - - # lurlparser - add_subdirectory(lurlparser EXCLUDE_FROM_ALL) + if (USE_SYSTEM_SSL) + find_package(OpenSSL 1.1 REQUIRED) + set(OPENSSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto) + else() + # LibreSSL + set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "") + set(OPENSSLDIR "/etc/ssl/") + add_subdirectory(libressl EXCLUDE_FROM_ALL) + target_include_directories(ssl INTERFACE ./libressl/include) + target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP) + get_directory_property(OPENSSL_LIBRARIES + DIRECTORY libressl + DEFINITION OPENSSL_LIBS) + endif() # httplib add_library(httplib INTERFACE) diff --git a/externals/libressl b/externals/libressl index 7d01cb01cb..8289d0d07d 160000 --- a/externals/libressl +++ b/externals/libressl @@ -1 +1 @@ -Subproject commit 7d01cb01cb1a926ecb4c9c98b107ef3c26f59dfb +Subproject commit 8289d0d07de6553bf4b900bf60e808ea3f7f59da diff --git a/externals/lurlparser/CMakeLists.txt b/externals/lurlparser/CMakeLists.txt deleted file mode 100644 index 45046ffd36..0000000000 --- a/externals/lurlparser/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -add_library(lurlparser - LUrlParser.cpp - LUrlParser.h -) - -create_target_directory_groups(lurlparser) - -target_include_directories(lurlparser INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/externals/lurlparser/LUrlParser.cpp b/externals/lurlparser/LUrlParser.cpp deleted file mode 100644 index 9c134e3303..0000000000 --- a/externals/lurlparser/LUrlParser.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Lightweight URL & URI parser (RFC 1738, RFC 3986) - * https://github.com/corporateshark/LUrlParser - * - * The MIT License (MIT) - * - * Copyright (C) 2015 Sergey Kosarevsky (sk@linderdaum.com) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "LUrlParser.h" - -#include -#include -#include - -// check if the scheme name is valid -static bool IsSchemeValid( const std::string& SchemeName ) -{ - for ( auto c : SchemeName ) - { - if ( !isalpha( c ) && c != '+' && c != '-' && c != '.' ) return false; - } - - return true; -} - -bool LUrlParser::clParseURL::GetPort( int* OutPort ) const -{ - if ( !IsValid() ) { return false; } - - int Port = atoi( m_Port.c_str() ); - - if ( Port <= 0 || Port > 65535 ) { return false; } - - if ( OutPort ) { *OutPort = Port; } - - return true; -} - -// based on RFC 1738 and RFC 3986 -LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL ) -{ - LUrlParser::clParseURL Result; - - const char* CurrentString = URL.c_str(); - - /* - * : - * := [a-z\+\-\.]+ - * For resiliency, programs interpreting URLs should treat upper case letters as equivalent to lower case in scheme names - */ - - // try to read scheme - { - const char* LocalString = strchr( CurrentString, ':' ); - - if ( !LocalString ) - { - return clParseURL( LUrlParserError_NoUrlCharacter ); - } - - // save the scheme name - Result.m_Scheme = std::string( CurrentString, LocalString - CurrentString ); - - if ( !IsSchemeValid( Result.m_Scheme ) ) - { - return clParseURL( LUrlParserError_InvalidSchemeName ); - } - - // scheme should be lowercase - std::transform( Result.m_Scheme.begin(), Result.m_Scheme.end(), Result.m_Scheme.begin(), ::tolower ); - - // skip ':' - CurrentString = LocalString+1; - } - - /* - * //:@:/ - * any ":", "@" and "/" must be normalized - */ - - // skip "//" - if ( *CurrentString++ != '/' ) return clParseURL( LUrlParserError_NoDoubleSlash ); - if ( *CurrentString++ != '/' ) return clParseURL( LUrlParserError_NoDoubleSlash ); - - // check if the user name and password are specified - bool bHasUserName = false; - - const char* LocalString = CurrentString; - - while ( *LocalString ) - { - if ( *LocalString == '@' ) - { - // user name and password are specified - bHasUserName = true; - break; - } - else if ( *LocalString == '/' ) - { - // end of : specification - bHasUserName = false; - break; - } - - LocalString++; - } - - // user name and password - LocalString = CurrentString; - - if ( bHasUserName ) - { - // read user name - while ( *LocalString && *LocalString != ':' && *LocalString != '@' ) LocalString++; - - Result.m_UserName = std::string( CurrentString, LocalString - CurrentString ); - - // proceed with the current pointer - CurrentString = LocalString; - - if ( *CurrentString == ':' ) - { - // skip ':' - CurrentString++; - - // read password - LocalString = CurrentString; - - while ( *LocalString && *LocalString != '@' ) LocalString++; - - Result.m_Password = std::string( CurrentString, LocalString - CurrentString ); - - CurrentString = LocalString; - } - - // skip '@' - if ( *CurrentString != '@' ) - { - return clParseURL( LUrlParserError_NoAtSign ); - } - - CurrentString++; - } - - bool bHasBracket = ( *CurrentString == '[' ); - - // go ahead, read the host name - LocalString = CurrentString; - - while ( *LocalString ) - { - if ( bHasBracket && *LocalString == ']' ) - { - // end of IPv6 address - LocalString++; - break; - } - else if ( !bHasBracket && ( *LocalString == ':' || *LocalString == '/' ) ) - { - // port number is specified - break; - } - - LocalString++; - } - - Result.m_Host = std::string( CurrentString, LocalString - CurrentString ); - - CurrentString = LocalString; - - // is port number specified? - if ( *CurrentString == ':' ) - { - CurrentString++; - - // read port number - LocalString = CurrentString; - - while ( *LocalString && *LocalString != '/' ) LocalString++; - - Result.m_Port = std::string( CurrentString, LocalString - CurrentString ); - - CurrentString = LocalString; - } - - // end of string - if ( !*CurrentString ) - { - Result.m_ErrorCode = LUrlParserError_Ok; - - return Result; - } - - // skip '/' - if ( *CurrentString != '/' ) - { - return clParseURL( LUrlParserError_NoSlash ); - } - - CurrentString++; - - // parse the path - LocalString = CurrentString; - - while ( *LocalString && *LocalString != '#' && *LocalString != '?' ) LocalString++; - - Result.m_Path = std::string( CurrentString, LocalString - CurrentString ); - - CurrentString = LocalString; - - // check for query - if ( *CurrentString == '?' ) - { - // skip '?' - CurrentString++; - - // read query - LocalString = CurrentString; - - while ( *LocalString && *LocalString != '#' ) LocalString++; - - Result.m_Query = std::string( CurrentString, LocalString - CurrentString ); - - CurrentString = LocalString; - } - - // check for fragment - if ( *CurrentString == '#' ) - { - // skip '#' - CurrentString++; - - // read fragment - LocalString = CurrentString; - - while ( *LocalString ) LocalString++; - - Result.m_Fragment = std::string( CurrentString, LocalString - CurrentString ); - - CurrentString = LocalString; - } - - Result.m_ErrorCode = LUrlParserError_Ok; - - return Result; -} diff --git a/externals/lurlparser/LUrlParser.h b/externals/lurlparser/LUrlParser.h deleted file mode 100644 index 25d2109811..0000000000 --- a/externals/lurlparser/LUrlParser.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Lightweight URL & URI parser (RFC 1738, RFC 3986) - * https://github.com/corporateshark/LUrlParser - * - * The MIT License (MIT) - * - * Copyright (C) 2015 Sergey Kosarevsky (sk@linderdaum.com) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#pragma once - -#include - -namespace LUrlParser -{ -enum LUrlParserError -{ - LUrlParserError_Ok = 0, - LUrlParserError_Uninitialized = 1, - LUrlParserError_NoUrlCharacter = 2, - LUrlParserError_InvalidSchemeName = 3, - LUrlParserError_NoDoubleSlash = 4, - LUrlParserError_NoAtSign = 5, - LUrlParserError_UnexpectedEndOfLine = 6, - LUrlParserError_NoSlash = 7, -}; - -class clParseURL -{ -public: - LUrlParserError m_ErrorCode; - std::string m_Scheme; - std::string m_Host; - std::string m_Port; - std::string m_Path; - std::string m_Query; - std::string m_Fragment; - std::string m_UserName; - std::string m_Password; - - clParseURL() - : m_ErrorCode( LUrlParserError_Uninitialized ) - {} - - /// return 'true' if the parsing was successful - bool IsValid() const { return m_ErrorCode == LUrlParserError_Ok; } - - /// helper to convert the port number to int, return 'true' if the port is valid (within the 0..65535 range) - bool GetPort( int* OutPort ) const; - - /// parse the URL - static clParseURL ParseURL( const std::string& URL ); - -private: - explicit clParseURL( LUrlParserError ErrorCode ) - : m_ErrorCode( ErrorCode ) - {} -}; - -} // namespace LUrlParser diff --git a/externals/lurlparser/README.md b/externals/lurlparser/README.md deleted file mode 100644 index be7f0135a8..0000000000 --- a/externals/lurlparser/README.md +++ /dev/null @@ -1,19 +0,0 @@ -From https://github.com/corporateshark/LUrlParser/commit/455d5e2d27e3946f11ad0328fee9ee2628e6a8e2 - -MIT License - -=== - -Lightweight URL & URI parser (RFC 1738, RFC 3986) - -(C) Sergey Kosarevsky, 2015 - -@corporateshark sk@linderdaum.com - -http://www.linderdaum.com - -http://blog.linderdaum.com - -============================= - -A tiny and lightweight URL & URI parser (RFC 1738, RFC 3986) written in C++. diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt index 7e484b9064..ae85a72ea0 100644 --- a/src/web_service/CMakeLists.txt +++ b/src/web_service/CMakeLists.txt @@ -9,4 +9,4 @@ add_library(web_service STATIC ) create_target_directory_groups(web_service) -target_link_libraries(web_service PRIVATE common nlohmann_json::nlohmann_json httplib lurlparser) +target_link_libraries(web_service PRIVATE common nlohmann_json::nlohmann_json httplib) diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp index 534960d099..c56cd7c71f 100644 --- a/src/web_service/web_backend.cpp +++ b/src/web_service/web_backend.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -19,9 +18,6 @@ namespace WebService { constexpr std::array API_VERSION{'1'}; -constexpr int HTTP_PORT = 80; -constexpr int HTTPS_PORT = 443; - constexpr std::size_t TIMEOUT_SECONDS = 30; struct Client::Impl { @@ -67,21 +63,7 @@ struct Client::Impl { const std::string& jwt = "", const std::string& username = "", const std::string& token = "") { if (cli == nullptr) { - const auto parsedUrl = LUrlParser::clParseURL::ParseURL(host); - int port{}; - if (parsedUrl.m_Scheme == "http") { - if (!parsedUrl.GetPort(&port)) { - port = HTTP_PORT; - } - } else if (parsedUrl.m_Scheme == "https") { - if (!parsedUrl.GetPort(&port)) { - port = HTTPS_PORT; - } - } else { - LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme); - return WebResult{WebResult::Code::InvalidURL, "Bad URL scheme", ""}; - } - cli = std::make_unique(parsedUrl.m_Host.c_str(), port); + cli = std::make_unique(host.c_str()); } cli->set_connection_timeout(TIMEOUT_SECONDS); cli->set_read_timeout(TIMEOUT_SECONDS);