handler/stop: add no js solution option

This commit is contained in:
Vaxry
2025-04-22 00:26:44 +01:00
parent a8ca03f1d6
commit 6f77f5acb1
6 changed files with 142 additions and 8 deletions

View File

@@ -46,6 +46,38 @@ CChallenge::CChallenge(const std::string& jsonResponse) {
m_valid = true;
}
CChallenge::CChallenge(const Pistache::Http::Request& reqResponse) {
auto& q = reqResponse.query();
if (!q.has("solution")
|| !q.has("fingerprint")
|| !q.has("challenge")
|| !q.has("timestamp")
|| !q.has("sig")
|| !q.has("difficulty"))
return;
m_challenge = q.get("challenge").value();
m_fingerprint = q.get("fingerprint").value();
m_sig = q.get("sig").value();
try {
m_issued = std::chrono::system_clock::time_point(std::chrono::seconds(std::stoull(q.get("timestamp").value())));
} catch (std::exception& e) { return; }
if (!g_pCrypto->verifySignature(getSigString(), m_sig))
return;
const auto SHA = g_pCrypto->sha256(m_challenge + q.get("solution").value());
for (size_t i = 0; i < m_difficulty; ++i) {
if (SHA.at(i) != '0')
return;
}
m_valid = true;
}
std::string CChallenge::fingerprint() const {
return m_fingerprint;
}

View File

@@ -3,10 +3,14 @@
#include <string>
#include <chrono>
#include <pistache/http.h>
class CChallenge {
public:
CChallenge() = default;
CChallenge(const std::string& fingerprint, const std::string& challenge, int difficulty);
CChallenge(const std::string& jsonResponse);
CChallenge(const Pistache::Http::Request& reqResponse);
std::string fingerprint() const;
std::string challenge() const;

View File

@@ -195,7 +195,15 @@ void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Htt
if (req.resource() == "/checkpoint/challenge") {
if (req.method() == Pistache::Http::Method::Post)
challengeSubmitted(req, response);
challengeSubmitted(req, response, true);
else
response.send(Pistache::Http::Code::Bad_Request, "Bad Request");
return;
}
if (req.resource() == "/checkpoint/challengeNoJs") {
if (req.method() == Pistache::Http::Method::Get)
challengeSubmitted(req, response, false);
else
response.send(Pistache::Http::Code::Bad_Request, "Bad Request");
return;
@@ -323,11 +331,15 @@ void CServerHandler::onTimeout(const Pistache::Http::Request& request, Pistache:
response.send(Pistache::Http::Code::Request_Timeout, "Timeout").then([=](ssize_t) {}, PrintException());
}
void CServerHandler::challengeSubmitted(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response) {
void CServerHandler::challengeSubmitted(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response, bool js) {
const auto JSON = req.body();
const auto FINGERPRINT = fingerprintForRequest(req);
const auto CHALLENGE = CChallenge(req.body());
CChallenge CHALLENGE;
if (!js)
CHALLENGE = CChallenge(req);
else
CHALLENGE = CChallenge(req.body());
if (!CHALLENGE.valid()) {
response.send(Pistache::Http::Code::Bad_Request, "Bad request");
@@ -353,7 +365,12 @@ void CServerHandler::challengeSubmitted(const Pistache::Http::Request& req, Pist
response.headers().add(
std::make_shared<SetCookieHeader>(std::string{TOKEN_COOKIE_NAME} + "=" + TOKEN.tokenCookie() + "; Domain=" + hostDomain + "; HttpOnly; Path=/; Secure; SameSite=Lax"));
response.send(Pistache::Http::Code::Ok, "Ok");
if (js)
response.send(Pistache::Http::Code::Ok, "Ok");
else {
response.headers().add<Pistache::Http::Header::Location>("/");
response.send(Pistache::Http::Code::Moved_Permanently, "");
}
}
void CServerHandler::serveStop(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response, int difficulty) {
@@ -376,6 +393,8 @@ void CServerHandler::serveStop(const Pistache::Http::Request& req, Pistache::Htt
page.add("challengeTimestamp", CTinylatesProp(CHALLENGE.timestampAsString()));
page.add("hostDomain", CTinylatesProp(hostDomain));
page.add("checkpointVersion", CTinylatesProp(CHECKPOINT_VERSION));
response.setMime(Pistache::Http::Mime::MediaType("text/html"));
response.send(Pistache::Http::Code::Ok, page.render().value_or("error"));
}

View File

@@ -21,7 +21,7 @@ class CServerHandler : public Pistache::Http::Handler {
void proxyPass(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response);
void proxyPassInternal(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response, bool async = false);
void proxyPassAsync(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response);
void challengeSubmitted(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response);
void challengeSubmitted(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response, bool js);
std::string fingerprintForRequest(const Pistache::Http::Request& req);
std::string ipForRequest(const Pistache::Http::Request& req);