diff options
| author | Xe Iaso <me@xeiaso.net> | 2025-01-18 17:09:02 -0500 |
|---|---|---|
| committer | Xe Iaso <me@xeiaso.net> | 2025-01-18 17:09:02 -0500 |
| commit | bcc7c0d28e8c225c730b5574718aa7d963c1cdea (patch) | |
| tree | 08b6abb8fa8009600a07ad2548a9b968ca0f7549 /cmd/anubis/static/js | |
| parent | b586be783c91f4d579bfa3907e8062f5c6ada739 (diff) | |
| download | x-bcc7c0d28e8c225c730b5574718aa7d963c1cdea.tar.xz x-bcc7c0d28e8c225c730b5574718aa7d963c1cdea.zip | |
cmd: add Anubis
Signed-off-by: Xe Iaso <me@xeiaso.net>
Diffstat (limited to 'cmd/anubis/static/js')
| -rw-r--r-- | cmd/anubis/static/js/main.mjs | 47 | ||||
| -rw-r--r-- | cmd/anubis/static/js/proof-of-work.mjs | 65 |
2 files changed, 112 insertions, 0 deletions
diff --git a/cmd/anubis/static/js/main.mjs b/cmd/anubis/static/js/main.mjs new file mode 100644 index 0000000..d13e1ad --- /dev/null +++ b/cmd/anubis/static/js/main.mjs @@ -0,0 +1,47 @@ +import { process } from './proof-of-work.mjs'; + +// from Xeact +const u = (url = "", params = {}) => { + let result = new URL(url, window.location.href); + Object.entries(params).forEach((kv) => { + let [k, v] = kv; + result.searchParams.set(k, v); + }); + return result.toString(); +}; + +(async () => { + const status = document.getElementById('status'); + const image = document.getElementById('image'); + const title = document.getElementById('title'); + + status.innerHTML = 'Calculating...'; + + const { challenge, difficulty } = await fetch("/.within.website/x/cmd/anubis/api/make-challenge", { method: "POST" }) + .then(r => { + if (!r.ok) { + throw new Error("Failed to fetch config"); + } + return r.json(); + }) + .catch(err => { + status.innerHTML = `Failed to fetch config: ${err.message}`; + image.src = "/.within.website/x/cmd/anubis/static/img/sad.webp"; + throw err; + }); + + status.innerHTML = `Calculating...<br/>Difficulty: ${difficulty}`; + + const t0 = Date.now(); + const { hash, nonce } = await process(challenge, difficulty); + const t1 = Date.now(); + + title.innerHTML = "Success!"; + status.innerHTML = `Done! Took ${t1 - t0}ms, ${nonce} iterations`; + image.src = "/.within.website/x/cmd/anubis/static/img/happy.webp"; + + setTimeout(() => { + const redir = window.location.href; + window.location.href = u("/.within.website/x/cmd/anubis/api/pass-challenge", { response: hash, nonce, redir, elapsedTime: t1 - t0 }); + }, 2000); +})();
\ No newline at end of file diff --git a/cmd/anubis/static/js/proof-of-work.mjs b/cmd/anubis/static/js/proof-of-work.mjs new file mode 100644 index 0000000..4019fec --- /dev/null +++ b/cmd/anubis/static/js/proof-of-work.mjs @@ -0,0 +1,65 @@ +// https://dev.to/ratmd/simple-proof-of-work-in-javascript-3kgm + +export function process(data, difficulty = 5) { + return new Promise((resolve, reject) => { + let webWorkerURL = URL.createObjectURL(new Blob([ + '(', processTask(), ')()' + ], { type: 'application/javascript' })); + + let worker = new Worker(webWorkerURL); + + worker.onmessage = (event) => { + worker.terminate(); + resolve(event.data); + }; + + worker.onerror = (event) => { + worker.terminate(); + reject(); + }; + + worker.postMessage({ + data, + difficulty + }); + + URL.revokeObjectURL(webWorkerURL); + }); +} + +function processTask() { + return function () { + function sha256(text) { + return new Promise((resolve, reject) => { + let buffer = (new TextEncoder).encode(text); + + crypto.subtle.digest('SHA-256', buffer.buffer).then(result => { + resolve(Array.from(new Uint8Array(result)).map( + c => c.toString(16).padStart(2, '0') + ).join('')); + }, reject); + }); + } + + addEventListener('message', async (event) => { + let data = event.data.data; + let difficulty = event.data.difficulty; + + let hash; + let nonce = 0; + do { + hash = await sha256(data + nonce++); + } while (hash.substr(0, difficulty) !== Array(difficulty + 1).join('0')); + + nonce -= 1; // last nonce was post-incremented + + postMessage({ + hash, + data, + difficulty, + nonce, + }); + }); + }.toString(); +} + |
