handler: Handle any checkpoint resource, determine Content-Type with libmagic (#22)
* Handle any resource * Determine Content-Type for static files with libmagic --------- Co-authored-by: Vaxry <vaxry@vaxry.net>
This commit is contained in:
@@ -29,7 +29,7 @@ add_compile_definitions(CHECKPOINT_VERSION="${CHECKPOINT_VERSION}")
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
pkg_check_modules(deps IMPORTED_TARGET openssl re2)
|
||||
pkg_check_modules(deps IMPORTED_TARGET openssl re2 libmagic)
|
||||
|
||||
target_include_directories(checkpoint
|
||||
PRIVATE
|
||||
|
||||
@@ -26,7 +26,7 @@ If you are using this, it's almost certain search engines will stop indexing you
|
||||
|
||||
## Setup guide
|
||||
|
||||
1. Clone and build this repo. You will need `openssl`, `g++>=12`, `re2`, and deps for `pistache`, `fmt` and `tinylates`.
|
||||
1. Clone and build this repo. You will need `openssl`, `g++>=12`, `re2`, `libmagic`, and deps for `pistache`, `fmt` and `tinylates`.
|
||||
2. Create a `config.jsonc`. An example one is in `example/`.
|
||||
3. Adjust the config to your needs. Options are documented with comments in the example config.
|
||||
4. Set up your IP rules if you want. These allow you to set up IPs that are automatically blocked, or allowed to access without a challenge. This is useful for e.g. search engine scrapers. Some IP ranges can be found in `example/index_bots.jsonc`.
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <fmt/format.h>
|
||||
#include <glaze/glaze.hpp>
|
||||
#include <openssl/evp.h>
|
||||
#include <magic.h>
|
||||
|
||||
constexpr const uint64_t TOKEN_MAX_AGE_MS = 1000 * 60 * 60; // 1hr
|
||||
constexpr const char* TOKEN_COOKIE_NAME = "checkpoint-token";
|
||||
@@ -94,7 +95,7 @@ std::string CServerHandler::fingerprintForRequest(const Pistache::Http::Request&
|
||||
}
|
||||
|
||||
bool CServerHandler::isResourceCheckpoint(const std::string_view& res) {
|
||||
return res == "/checkpoint/NotoSans.woff";
|
||||
return res.starts_with("/checkpoint/");
|
||||
}
|
||||
|
||||
std::string CServerHandler::ipForRequest(const Pistache::Http::Request& req) {
|
||||
@@ -200,12 +201,6 @@ void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Htt
|
||||
return;
|
||||
}
|
||||
|
||||
if (isResourceCheckpoint(req.resource())) {
|
||||
// no directory traversal is possible when resource is checkpoint
|
||||
response.send(Pistache::Http::Code::Ok, NFsUtils::readFileAsString(NFsUtils::htmlPath(req.resource().substr(req.resource().find("checkpoint/") + 11))).value());
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_pConfig->m_config.git_host) {
|
||||
// TODO: ratelimit this, probably.
|
||||
|
||||
@@ -289,6 +284,42 @@ void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Htt
|
||||
} else
|
||||
Debug::log(LOG, " | Action: CHALLENGE (no token)");
|
||||
|
||||
if (isResourceCheckpoint(req.resource())) {
|
||||
static const auto HTML_ROOT = std::filesystem::canonical(NFsUtils::htmlPath("")).string();
|
||||
|
||||
const auto RESOURCE_PATH = req.resource().substr(req.resource().find("checkpoint/") + 11);
|
||||
const auto PATH_RAW = NFsUtils::htmlPath(RESOURCE_PATH);
|
||||
|
||||
std::error_code ec;
|
||||
const auto PATH_ABSOLUTE = std::filesystem::canonical(PATH_RAW, ec);
|
||||
|
||||
if (ec) {
|
||||
// bad resource
|
||||
response.send(Pistache::Http::Code::Bad_Request, "Bad Request");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PATH_ABSOLUTE.string().starts_with(HTML_ROOT)) {
|
||||
// directory traversal
|
||||
response.send(Pistache::Http::Code::Bad_Request, "Bad Request");
|
||||
return;
|
||||
}
|
||||
|
||||
// attempt to handle mime
|
||||
magic_t magic = magic_open(MAGIC_MIME_TYPE);
|
||||
if (magic && magic_load(magic, nullptr) == 0) {
|
||||
const char* m = magic_file(magic, PATH_ABSOLUTE.c_str());
|
||||
auto mimeType = Pistache::Http::Mime::MediaType::fromString(m ? std::string(m) : std::string("application/octet-stream"));
|
||||
response.headers().add<Pistache::Http::Header::ContentType>(mimeType);
|
||||
}
|
||||
if (magic)
|
||||
magic_close(magic);
|
||||
|
||||
auto body = NFsUtils::readFileAsString(PATH_ABSOLUTE).value_or("");
|
||||
response.send(body.empty() ? Pistache::Http::Code::Internal_Server_Error : Pistache::Http::Code::Ok, body);
|
||||
return;
|
||||
}
|
||||
|
||||
serveStop(req, response, challengeDifficulty);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user