From 9b3fd6efacb390e95d37ecc8543c31b30c9af5a0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 13 Apr 2025 15:28:37 +0100 Subject: [PATCH] core: fix git support --- example/config.jsonc | 5 +++- src/config/Config.hpp | 1 + src/core/Handler.cpp | 61 ++++++++++++++++++++++++++++--------------- src/debug/log.hpp | 4 +++ 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/example/config.jsonc b/example/config.jsonc index fbc8d21..ae87760 100644 --- a/example/config.jsonc +++ b/example/config.jsonc @@ -15,5 +15,8 @@ "max_request_size": 10000000, // Timeout of 2 minutes for the proxy requests - "proxy_timeout_sec": 120 + "proxy_timeout_sec": 120, + + // enables (a lot) more logging + "trace_logging": false } \ No newline at end of file diff --git a/src/config/Config.hpp b/src/config/Config.hpp index 736e403..7f9103c 100644 --- a/src/config/Config.hpp +++ b/src/config/Config.hpp @@ -15,6 +15,7 @@ class CConfig { unsigned long int max_request_size = 10000000; // 10MB bool git_host = false; unsigned long int proxy_timeout_sec = 120; // 2 minutes + bool trace_logging = false; } m_config; }; diff --git a/src/core/Handler.cpp b/src/core/Handler.cpp index b284b68..3cc7389 100644 --- a/src/core/Handler.cpp +++ b/src/core/Handler.cpp @@ -150,15 +150,16 @@ void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Htt ; // silent ignore } - Debug::log(LOG, "Got request for: {}:{}{}", hostHeader->host(), hostHeader->port().toString(), req.resource()); - Debug::log(LOG, "Request author: IP {}", req.address().host()); + Debug::log(LOG, "New request: {}:{}{}", hostHeader->host(), hostHeader->port().toString(), req.resource()); + + Debug::log(LOG, " | Request author: IP {}", req.address().host()); if (cfHeader) - Debug::log(LOG, "CloudFlare reports IP: {}", cfHeader->ip()); + Debug::log(LOG, " | CloudFlare reports IP: {}", cfHeader->ip()); else - Debug::log(WARN, "Connection does not come through CloudFlare"); + Debug::log(TRACE, "Connection does not come through CloudFlare"); if (userAgentHeader) - Debug::log(LOG, "UA: {}", userAgentHeader->agent()); + Debug::log(LOG, " | UA: {}", userAgentHeader->agent()); if (req.resource() == "/checkpoint/challenge") { if (req.method() == Pistache::Http::Method::Post) @@ -169,17 +170,31 @@ void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Htt } if (g_pConfig->m_config.git_host) { - // TODO: ratelimit and check this. This can be faked! - if (gitProtocolHeader && userAgentHeader) { - Debug::log(LOG, "Request looks like it is coming from git (UA + GP). Accepting."); + // TODO: ratelimit this, probably. - proxyPass(req, response); - return; - } else if (userAgentHeader->agent().starts_with("git/")) { - Debug::log(LOG, "Request looks like it is coming from git (UA git). Accepting."); + const auto RES = req.resource(); + bool validGitResource = RES.ends_with("/info/refs") || RES.ends_with("/info/packs") || RES.ends_with("HEAD") || RES.ends_with(".git"); - proxyPass(req, response); - return; + if (RES.contains("/objects/")) { + const std::string_view repo = std::string_view{RES}.substr(0, RES.find("/objects/")); + if (std::count(repo.begin(), repo.end(), '/') == 2) + validGitResource = true; + } + + if (validGitResource) { + if (gitProtocolHeader && userAgentHeader) { + Debug::log(LOG, " | Action: PASS (git)"); + Debug::log(TRACE, "Request looks like it is coming from git (UA + GP). Accepting."); + + proxyPass(req, response); + return; + } else if (userAgentHeader->agent().starts_with("git/")) { + Debug::log(LOG, " | Action: PASS (git)"); + Debug::log(TRACE, "Request looks like it is coming from git (UA git). Accepting."); + + proxyPass(req, response); + return; + } } } @@ -189,6 +204,7 @@ void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Htt if (TOKEN) { const auto AGE = std::chrono::milliseconds(std::time(nullptr)).count() - TOKEN->epoch; if (AGE <= TOKEN_MAX_AGE_MS && TOKEN->ip == (cfHeader ? cfHeader->ip() : req.address().host())) { + Debug::log(LOG, " | Action: PASS (token)"); proxyPass(req, response); return; } else // token has been used from a different IP or is expired. Nuke it. @@ -196,6 +212,7 @@ void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Htt } } + Debug::log(LOG, " | Action: CHALLENGE"); serveStop(req, response); } @@ -284,7 +301,7 @@ void CServerHandler::serveStop(const Pistache::Http::Request& req, Pistache::Htt void CServerHandler::proxyPass(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response) { const std::string FORWARD_ADDR = g_pConfig->m_config.forward_address; - Debug::log(LOG, "Method ({}): Forwarding to {}", (uint32_t)req.method(), FORWARD_ADDR + req.resource()); + Debug::log(TRACE, "Method ({}): Forwarding to {}", (uint32_t)req.method(), FORWARD_ADDR + req.resource()); auto builder = m_client->prepareRequest(FORWARD_ADDR + req.resource(), req.method()); builder.body(req.body()); @@ -294,14 +311,16 @@ void CServerHandler::proxyPass(const Pistache::Http::Request& req, Pistache::Htt const auto HEADERS = req.headers().list(); for (auto& h : HEADERS) { // FIXME: why does this break e.g. gitea if we include it? - if (std::string_view{h->name()} == "Host" || std::string_view{h->name()} == "Cache-Control") { - Debug::log(LOG, "Header in: {}: {} (DROPPED)", h->name(), req.headers().getRaw(h->name()).value()); + if (std::string_view{h->name()} == "Host" || std::string_view{h->name()} == "Cache-Control" || std::string_view{h->name()} == "Connection") { + Debug::log(TRACE, "Header in: {}: {} (DROPPED)", h->name(), req.headers().getRaw(h->name()).value()); continue; } - Debug::log(LOG, "Header in: {}: {}", h->name(), req.headers().getRaw(h->name()).value()); + Debug::log(TRACE, "Header in: {}: {}", h->name(), req.headers().getRaw(h->name()).value()); builder.header(h); } + builder.header(std::make_shared(Pistache::Http::ConnectionControl::KeepAlive)); + builder.timeout(std::chrono::seconds(g_pConfig->m_config.proxy_timeout_sec)); // TODO: implement streaming for git's large objects? @@ -313,11 +332,11 @@ void CServerHandler::proxyPass(const Pistache::Http::Request& req, Pistache::Htt for (auto& h : HEADERSRESP) { if (std::string_view{h->name()} == "Transfer-Encoding") { - Debug::log(LOG, "Header out: {}: {} (DROPPED)", h->name(), resp.headers().getRaw(h->name()).value()); + Debug::log(TRACE, "Header out: {}: {} (DROPPED)", h->name(), resp.headers().getRaw(h->name()).value()); continue; } - - Debug::log(LOG, "Header out: {}: {}", h->name(), resp.headers().getRaw(h->name()).value()); + + Debug::log(TRACE, "Header out: {}: {}", h->name(), resp.headers().getRaw(h->name()).value()); response.headers().add(h); } diff --git a/src/debug/log.hpp b/src/debug/log.hpp index ef3ed70..d9ec762 100644 --- a/src/debug/log.hpp +++ b/src/debug/log.hpp @@ -2,6 +2,7 @@ #include #include #include +#include "../config/Config.hpp" enum LogLevel { NONE = -1, @@ -19,6 +20,9 @@ namespace Debug { std::string logMsg = ""; + if (g_pConfig && !g_pConfig->m_config.trace_logging && level == TRACE) + return; + switch (level) { case LOG: logMsg += "[LOG] "; break; case WARN: logMsg += "[WARN] "; break;