diff options
Diffstat (limited to 'main.go')
-rw-r--r-- | main.go | 85 |
1 files changed, 82 insertions, 3 deletions
@@ -79,11 +79,89 @@ Encode your selected value in base64 and submit it below: </form> <br /> <details> -<summary> -Program to solve this -</summary><pre>` + html.EscapeString(solverProgram) + `</pre> +<summary>Program to solve this</summary> +<pre>` + html.EscapeString(solverProgram) + `</pre> </details> +<p id="solver_status"></p> </body> +<script> +document.addEventListener("DOMContentLoaded", function() { + let challenge_b64 = "{{.UnsignedTokenBase64}}"; + let difficulty = {{.NeedBits}}; + let form = document.querySelector("form"); + let field = form.querySelector("input[name='powxy']"); + let status_el = document.getElementById("solver_status"); + + if (!window.crypto || !window.crypto.subtle) { + status_el.textContent = "SubtleCrypto not available. You must solve the challenge externally."; + return; + } + status_el.textContent = "SubtleCrypto detected. Attempting to solve in JS..."; + + let solver_active = true; + form.addEventListener("submit", function() { + solver_active = false; + }); + + async function solve_pow() { + let token_bytes = Uint8Array.from( + atob(challenge_b64), + ch => ch.charCodeAt(0) + ); + + let nonce = 0n; + let buf = new ArrayBuffer(8); + let view = new DataView(buf); + + while (solver_active) { + view.setBigUint64(0, nonce, true); + + let candidate = new Uint8Array(token_bytes.length + 8); + candidate.set(token_bytes, 0); + candidate.set(new Uint8Array(buf), token_bytes.length); + + let digest_buffer = await crypto.subtle.digest("SHA-256", candidate); + let digest = new Uint8Array(digest_buffer); + + if (has_leading_zero_bits(digest, difficulty)) { + let nonce_str = String.fromCharCode(...new Uint8Array(buf)); + field.value = btoa(nonce_str); + + status_el.textContent = "Solution found. Submitting..."; + form.submit(); + return; + } + + nonce++; + + // Update status every 65536 tries + if ((nonce & 0xFFFFn) === 0n) { + status_el.textContent = "Tried " + nonce + " candidates so far..."; + await new Promise(r => setTimeout(r, 0)); + } + } + } + + function has_leading_zero_bits(digest, bits) { + let full_bytes = bits >>> 3; + for (let i = 0; i < full_bytes; i++) { + if (digest[i] !== 0) { + return false; + } + } + let remainder = bits & 7; + if (remainder !== 0) { + let mask = 0xFF << (8 - remainder); + if ((digest[full_bytes] & mask) !== 0) { + return false; + } + } + return true; + } + + solve_pow(); +}); +</script> </html> `) if err != nil { @@ -173,6 +251,7 @@ func validateCookie(cookie *http.Cookie, expectedToken []byte) bool { return subtle.ConstantTimeCompare(gotToken, expectedToken) == 1 } + func makeSignedToken(request *http.Request) []byte { buf := make([]byte, 0, 2*sha256.Size) |