handler/stop: add no js solution option
This commit is contained in:
@@ -154,6 +154,19 @@
|
|||||||
transition: ease-in-out 0.1s;
|
transition: ease-in-out 0.1s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.link,
|
||||||
|
.link:visited,
|
||||||
|
.link:link,
|
||||||
|
.link:focus,
|
||||||
|
.link:active {
|
||||||
|
color: #c03940;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
@media (pointer:none),
|
@media (pointer:none),
|
||||||
(pointer:coarse) {
|
(pointer:coarse) {
|
||||||
.big-icon {
|
.big-icon {
|
||||||
@@ -198,10 +211,76 @@
|
|||||||
|
|
||||||
<noscript>
|
<noscript>
|
||||||
<p class="text-description">
|
<p class="text-description">
|
||||||
This website uses <a href="https://github.com/vaxerski/checkpoint">checkpoint</a> and requires javascript. Please enable javascript to complete the Proof of Work challenge.
|
This website uses <a class="link" href="https://github.com/vaxerski/checkpoint">checkpoint</a> and
|
||||||
|
requires
|
||||||
|
javascript to
|
||||||
|
automatically verify you are not a bot.<br /><br />
|
||||||
|
You seem to be running without Javascript enabled, and thus will have to do this manually.<br /><br />
|
||||||
|
Paste this command into your Linux terminal and provide the output below:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p class="code-block">
|
||||||
|
perl -MDigest::SHA=sha256_hex -e '$nonce="{{ tl:text challengeNonce }}"; $d={{ tl:text
|
||||||
|
challengeDifficulty
|
||||||
|
}}; for($i=0;; $i++){ $h=sha256_hex($nonce.$i); if(substr($h,0,$d) eq "0"x$d){ print "$i\n"; last }}'
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form action="/checkpoint/challengeNoJs" method="get">
|
||||||
|
<div>
|
||||||
|
<label class="form-label" for="name">Enter the output: </label>
|
||||||
|
<input class="form-input" type="text" name="solution" id="solution" required />
|
||||||
|
</div>
|
||||||
|
<input class="input-hidden" type="text" name="fingerprint" id="fingerprint"
|
||||||
|
value="{{ tl:text challengeFingerprint }}" />
|
||||||
|
<input class="input-hidden" type="text" name="challenge" id="challenge"
|
||||||
|
value="{{ tl:text challengeNonce }}" />
|
||||||
|
<input class="input-hidden" type="text" name="sig" id="sig" value="{{ tl:text challengeSignature }}" />
|
||||||
|
<input class="input-hidden" type="text" name="timestamp" id="timestamp"
|
||||||
|
value="{{ tl:text challengeTimestamp }}" />
|
||||||
|
<input class="input-hidden" type="text" name="difficulty" id="difficulty"
|
||||||
|
value="{{ tl:text challengeDifficulty }}" />
|
||||||
|
<input class="form-button" type="submit" value="Send" />
|
||||||
|
</form>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.form-label {
|
||||||
|
color: #fff;
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-button {
|
||||||
|
margin-left: 9.5rem;
|
||||||
|
width: calc(100%-19rem);
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input {
|
||||||
|
margin-left: 9.5rem;
|
||||||
|
width: calc(100%-19rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-block {
|
||||||
|
background-color: #161616;
|
||||||
|
color: #d9d9d9;
|
||||||
|
border-radius: 1rem;
|
||||||
|
font: "Monospace";
|
||||||
|
margin: 1rem;
|
||||||
|
width: calc(100% - 3rem);
|
||||||
|
max-width: 100%;
|
||||||
|
text-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
padding: 0.5rem;
|
||||||
|
text-align: left;
|
||||||
|
border: 1px solid #280d0e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
.require-js {
|
.require-js {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -46,6 +46,38 @@ CChallenge::CChallenge(const std::string& jsonResponse) {
|
|||||||
m_valid = true;
|
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 {
|
std::string CChallenge::fingerprint() const {
|
||||||
return m_fingerprint;
|
return m_fingerprint;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,14 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <pistache/http.h>
|
||||||
|
|
||||||
class CChallenge {
|
class CChallenge {
|
||||||
public:
|
public:
|
||||||
|
CChallenge() = default;
|
||||||
CChallenge(const std::string& fingerprint, const std::string& challenge, int difficulty);
|
CChallenge(const std::string& fingerprint, const std::string& challenge, int difficulty);
|
||||||
CChallenge(const std::string& jsonResponse);
|
CChallenge(const std::string& jsonResponse);
|
||||||
|
CChallenge(const Pistache::Http::Request& reqResponse);
|
||||||
|
|
||||||
std::string fingerprint() const;
|
std::string fingerprint() const;
|
||||||
std::string challenge() const;
|
std::string challenge() const;
|
||||||
|
|||||||
@@ -195,7 +195,15 @@ void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Htt
|
|||||||
|
|
||||||
if (req.resource() == "/checkpoint/challenge") {
|
if (req.resource() == "/checkpoint/challenge") {
|
||||||
if (req.method() == Pistache::Http::Method::Post)
|
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
|
else
|
||||||
response.send(Pistache::Http::Code::Bad_Request, "Bad Request");
|
response.send(Pistache::Http::Code::Bad_Request, "Bad Request");
|
||||||
return;
|
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());
|
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 JSON = req.body();
|
||||||
const auto FINGERPRINT = fingerprintForRequest(req);
|
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()) {
|
if (!CHALLENGE.valid()) {
|
||||||
response.send(Pistache::Http::Code::Bad_Request, "Bad request");
|
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(
|
response.headers().add(
|
||||||
std::make_shared<SetCookieHeader>(std::string{TOKEN_COOKIE_NAME} + "=" + TOKEN.tokenCookie() + "; Domain=" + hostDomain + "; HttpOnly; Path=/; Secure; SameSite=Lax"));
|
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) {
|
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("challengeTimestamp", CTinylatesProp(CHALLENGE.timestampAsString()));
|
||||||
page.add("hostDomain", CTinylatesProp(hostDomain));
|
page.add("hostDomain", CTinylatesProp(hostDomain));
|
||||||
page.add("checkpointVersion", CTinylatesProp(CHECKPOINT_VERSION));
|
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"));
|
response.send(Pistache::Http::Code::Ok, page.render().value_or("error"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class CServerHandler : public Pistache::Http::Handler {
|
|||||||
void proxyPass(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response);
|
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 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 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 fingerprintForRequest(const Pistache::Http::Request& req);
|
||||||
std::string ipForRequest(const Pistache::Http::Request& req);
|
std::string ipForRequest(const Pistache::Http::Request& req);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user