summaryrefslogtreecommitdiff
path: root/haunt/static/js
diff options
context:
space:
mode:
Diffstat (limited to 'haunt/static/js')
-rw-r--r--haunt/static/js/proof-of-work.js117
1 files changed, 94 insertions, 23 deletions
diff --git a/haunt/static/js/proof-of-work.js b/haunt/static/js/proof-of-work.js
index 5207ac6..1a57c2a 100644
--- a/haunt/static/js/proof-of-work.js
+++ b/haunt/static/js/proof-of-work.js
@@ -1,34 +1,105 @@
-const text = 'An obscure body in the S-K System, your majesty. The inhabitants refer to it as the planet Earth.';
+/*
+ * proof-of-work.js -- Alternative captcha based on SHA-256 proof-of-work.
+ * Copyright © 2022 Jakob L. Kreuze <zerodaysfordays@sdf.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
function makeid(length) {
- var result = '';
- var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- var charactersLength = characters.length;
- for ( var i = 0; i < length; i++ ) {
- result += characters.charAt(Math.floor(Math.random() * charactersLength));
- }
- return result;
+ let result = '';
+ let alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+ for (let i = 0; i < length; i++) {
+ result += alphabet.charAt(Math.floor(Math.random() * alphabet.length));
+ }
+ return result;
}
async function digestMessage(message) {
- const msgUint8 = new TextEncoder().encode(message); // encode as (utf-8) Uint8Array
- const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8); // hash the message
- const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
- const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join(''); // convert bytes to hex string
+ const msgUtf8 = new TextEncoder().encode(message);
+ const hashBuffer = await crypto.subtle.digest('SHA-256', msgUtf8);
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
+ const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
return hashHex;
}
-const HARDNESS = 4;
-
-async function findPrefix(challenge) {
- while (true) {
- let prefix = makeid(32);
- let digestHex = await digestMessage(prefix + challenge);
- if (digestHex.startsWith("0".repeat(HARDNESS))) {
- return [prefix + challenge, digestHex];
- }
+async function findPrefix(hardness, nonce) {
+ while (true) {
+ let prefix = makeid(32);
+ let digestHex = await digestMessage(prefix + nonce);
+ if (digestHex.startsWith("0".repeat(hardness))) {
+ return prefix;
}
+ }
+}
+
+function makeRequest (method, url) {
+ return new Promise(function (resolve, reject) {
+ var xhr = new XMLHttpRequest();
+ xhr.open(method, url);
+ xhr.onload = function () {
+ if (xhr.status >= 200 && xhr.status < 300) {
+ resolve(xhr.response);
+ } else {
+ reject({
+ status: xhr.status,
+ statusText: xhr.statusText
+ });
+ }
+ };
+ xhr.onerror = function () {
+ reject({
+ status: xhr.status,
+ statusText: xhr.statusText
+ });
+ };
+ xhr.send();
+ });
}
-const suffix = "p12IyPB2dZsmBHYZyaEMrR5OUxqNc5Z9Cijal+9/iuQ=";
-findPrefix(suffix).then(console.log);
+
+function raceEndpoint() {
+ return new Promise(function (resolve, reject) {
+ makeRequest("GET", "/api/challenge")
+ .then(function (data) {
+ let challengeData = JSON.parse(data);
+ findPrefix(challengeData.hardness, challengeData.nonce)
+ .then((prefix) => { resolve([prefix, challengeData["challenge-id"]]) } );
+ })
+ .catch(reject);
+ });
+}
+
+let trigger = document.getElementById("pow-trigger");
+trigger.hidden = false;
+trigger.addEventListener("click", (e) => {
+ trigger.innerHTML = "Please wait...";
+ trigger.disabled = true;
+ raceEndpoint()
+ .then((result) => {
+ let resultField = document.getElementById("captcha-alt");
+ let challengeIdField = document.getElementById("captcha-alt-id");
+ resultField.value = result[0];
+ challengeIdField.value = result[1];
+ trigger.innerHTML = "Proof-of-Work completed successfully!";
+ trigger.disabled = true;
+ })
+ .catch((err) => {
+ console.log(err);
+ trigger.innerHTML = "Proof-of-Work failed!";
+ trigger.disabled = true;
+ });
+ e.preventDefault();
+})
+