From 1fce6fc0b417e2e6c8afbaf2034d9e3f87c3e8aa Mon Sep 17 00:00:00 2001 From: j842 Date: Tue, 10 Jun 2025 09:47:48 +1200 Subject: [PATCH] Now with HTTPS working!! --- ipdemo/src/http_utils.cpp | 127 ++++++++++++++++++++++++++++++++++++++ ipdemo/src/http_utils.hpp | 14 ++++- ipdemo/src/main.cpp | 2 +- 3 files changed, 141 insertions(+), 2 deletions(-) diff --git a/ipdemo/src/http_utils.cpp b/ipdemo/src/http_utils.cpp index a1812bf..a56350d 100644 --- a/ipdemo/src/http_utils.cpp +++ b/ipdemo/src/http_utils.cpp @@ -1,4 +1,32 @@ #include "http_utils.hpp" +#include +#include +#include + +static std::string find_ca_certificates() { + // Common CA certificate locations across different Linux distributions + const std::vector ca_paths = { + "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Raspbian + "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL/CentOS + "/etc/ssl/ca-bundle.pem", // OpenSUSE + "/etc/pki/tls/cert.pem", // Fedora/RHEL alternative + "/etc/ssl/certs/ca-bundle.crt", // Some distros + "/etc/ssl/cert.pem", // Alpine Linux + "/usr/local/share/certs/ca-root-nss.crt", // FreeBSD + "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7+ + "/etc/ca-certificates/extracted/tls-ca-bundle.pem" // Arch Linux + }; + + for (const auto& path : ca_paths) { + std::ifstream file(path); + if (file.good()) { + file.close(); + return path; + } + } + + return ""; +} HttpResponse http_get(const std::string& url, const std::string& path, bool use_https, double timeout_seconds) { HttpResponse result{0, "", false}; @@ -14,6 +42,105 @@ HttpResponse http_get(const std::string& url, const std::string& path, bool use_ &loop ); + // Configure SSL certificates for HTTPS + if (use_https) { + std::string ca_path = find_ca_certificates(); + if (!ca_path.empty()) { + std::cerr << "Debug: Found CA certificates at: " << ca_path << std::endl; + // Use addSSLConfigs with proper parameter names for OpenSSL + std::vector> sslConfigs; + sslConfigs.push_back({"VerifyCAFile", ca_path}); + client->addSSLConfigs(sslConfigs); + } else { + // If no CA certificates found, print warning but continue + std::cerr << "Warning: No system CA certificates found. SSL verification may fail." << std::endl; + } + } + + auto req = drogon::HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->setPath(path); + + client->sendRequest(req, [&](drogon::ReqResult res, const drogon::HttpResponsePtr &resp) { + std::lock_guard lock(mtx); + if (res == drogon::ReqResult::Ok && resp) { + result.status_code = resp->statusCode(); + result.body = resp->body(); + result.success = true; + } else { + result.status_code = 0; + result.body = ""; + result.success = false; + } + done = true; + cv.notify_one(); + loop.quit(); + }, timeout_seconds); + + loop.loop(); + }); + + // Wait for completion + { + std::unique_lock lock(mtx); + cv.wait(lock, [&] { return done; }); + } + + worker.join(); + return result; +} + +HttpResponse http_get_with_ssl(const std::string& url, const std::string& path, const HttpClientSSLConfig& ssl_config, double timeout_seconds) { + HttpResponse result{0, "", false}; + bool done = false; + std::mutex mtx; + std::condition_variable cv; + + std::thread worker([&]() { + trantor::EventLoop loop; + + // Create HTTPS client with SSL configuration options + auto client = drogon::HttpClient::newHttpClient( + "https://" + url, + &loop, + ssl_config.use_old_tls, + ssl_config.validate_cert + ); + + // Configure client certificate if provided + if (!ssl_config.cert_path.empty() && !ssl_config.key_path.empty()) { + client->setCertPath(ssl_config.cert_path, ssl_config.key_path); + } + + // Configure SSL settings + std::vector> finalSslConfigs = ssl_config.ssl_configs; + + // Set CA certificates path if not explicitly disabled + if (ssl_config.validate_cert) { + // Check if cafile is provided in ssl_configs + bool ca_path_set = false; + for (const auto& config : ssl_config.ssl_configs) { + if (config.first == "cafile" || config.first == "CAfile" || + config.first == "VerifyCAFile") { + ca_path_set = true; + break; + } + } + + // If no cafile provided, use system certificates + if (!ca_path_set) { + std::string ca_path = find_ca_certificates(); + if (!ca_path.empty()) { + finalSslConfigs.push_back({"VerifyCAFile", ca_path}); + } + } + } + + // Add all SSL configurations at once + if (!finalSslConfigs.empty()) { + client->addSSLConfigs(finalSslConfigs); + } + auto req = drogon::HttpRequest::newHttpRequest(); req->setMethod(drogon::Get); req->setPath(path); diff --git a/ipdemo/src/http_utils.hpp b/ipdemo/src/http_utils.hpp index 7fd8eb6..53b9f43 100644 --- a/ipdemo/src/http_utils.hpp +++ b/ipdemo/src/http_utils.hpp @@ -13,5 +13,17 @@ struct HttpResponse { bool success; }; +// SSL configuration options for HTTP client +struct HttpClientSSLConfig { + std::string cert_path; // Client certificate path + std::string key_path; // Client key path + bool validate_cert = true; // Whether to validate server certificate + bool use_old_tls = false; // Enable TLS 1.0/1.1 + std::vector> ssl_configs; // Additional SSL_CONF_cmd options +}; + // Utility function for blocking HTTP GET requests -HttpResponse http_get(const std::string& url, const std::string& path, bool use_https = false, double timeout_seconds = 10.0); \ No newline at end of file +HttpResponse http_get(const std::string& url, const std::string& path, bool use_https = false, double timeout_seconds = 10.0); + +// Utility function for blocking HTTP GET requests with SSL configuration +HttpResponse http_get_with_ssl(const std::string& url, const std::string& path, const HttpClientSSLConfig& ssl_config, double timeout_seconds = 10.0); \ No newline at end of file diff --git a/ipdemo/src/main.cpp b/ipdemo/src/main.cpp index 88301d6..a6fa21e 100644 --- a/ipdemo/src/main.cpp +++ b/ipdemo/src/main.cpp @@ -15,7 +15,7 @@ int main() { std::cout << "Retrieving IP address..." << std::endl; // Use the utility function for HTTP GET - auto response = http_get("ipinfo.io", "/ip", false, 10.0); + auto response = http_get("ipinfo.io", "/ip", true, 10.0); ASSERT(response.success && response.status_code == 200, "Failed to get IP");