diff options
Diffstat (limited to 'haunt/static/js')
| -rw-r--r-- | haunt/static/js/proof-of-work.js | 117 |
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(); +}) + |