carlos / movement Public

Clone
git clone https://amadan.net/carlos/movement

Plain git — no account needed to clone.

Download

Download this file

1// Wires the signup form to the solver.
2//
3// The submit button is rendered disabled, with an explanation inside
4// <noscript>, and this module enables it once it has loaded. That ordering is
5// the only one that fails safe: JavaScript cannot enable a control that lives
6// inside <noscript>, and a module that throws on an old browser leaves the
7// honest disabled state rather than a form that looks live and silently does
8// nothing.
9//
10// Signing up genuinely requires JavaScript here — the proof of work is
11// mandatory. A visitor who cannot run it deserves to learn that immediately,
12// and from us.
13
14// This module does no hashing itself — the worker imports sha256.js.
15
16const form = document.querySelector("[data-pow-form]");
17
18if (form) {
19 const submit = form.querySelector("[data-pow-submit]");
20 const email = form.querySelector("[data-pow-email]");
21 const counter = form.querySelector("[data-pow-counter]");
22 const status = form.querySelector("[data-pow-status]");
23 const workerURL = form.dataset.powWorker;
24 const difficulty = parseInt(form.dataset.powDifficulty, 10);
25 const nonce = form.dataset.powNonce;
26
27 const idleLabel = submit.dataset.label || submit.textContent;
28 const workingLabel = submit.dataset.workingLabel || idleLabel;
29
30 // Everything above resolved, so the form can be used.
31 submit.disabled = false;
32
33 let solved = false;
34
35 form.addEventListener("submit", (event) => {
36 if (solved) return; // second pass: the counter is in, let it through.
37
38 event.preventDefault();
39 if (!email.value.trim()) {
40 email.reportValidity();
41 return;
42 }
43
44 submit.disabled = true;
45 submit.textContent = workingLabel;
46 if (status) status.hidden = false;
47
48 // The worker is addressed by a fingerprinted URL the template supplies,
49 // because static assets are content-hashed and this module cannot guess
50 // the name. Module type, so it can import sha256.js the same way.
51 const worker = new Worker(workerURL, { type: "module" });
52
53 worker.onmessage = (e) => {
54 if (!e.data.done) {
55 if (status) status.textContent = String(e.data.tried);
56 return;
57 }
58 worker.terminate();
59 counter.value = e.data.counter;
60 solved = true;
61 form.requestSubmit ? form.requestSubmit() : form.submit();
62 };
63
64 worker.onerror = () => {
65 worker.terminate();
66 // Nothing clever to do: without a solution the server will refuse the
67 // submission anyway, so say so here rather than posting something we
68 // know will be rejected.
69 submit.disabled = false;
70 submit.textContent = idleLabel;
71 if (status) status.textContent = "";
72 form.dispatchEvent(new CustomEvent("pow:failed"));
73 };
74
75 worker.postMessage({
76 nonce,
77 email: email.value,
78 difficulty,
79 });
80 });
81}
82