From 9f8fc11ed5e28683a1afe2eb772b01da849b4d64 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 15 Mar 2025 18:48:47 -0500 Subject: [PATCH] updates for pow-bot-deterrent-rp -- fixing cross domain webworker issue --- Dockerfile | 1 - README.md | 16 ++-- build-docker.sh | 18 ++-- example/index.html | 27 +----- main.go | 170 ++++++++++++++++++++++---------- proofOfWorkerStub.js | 3 +- static/pow-bot-deterrent.js | 186 ++++++++++++++++-------------------- static/proofOfWorker.js | 6 +- wasm_build/build_wasm.sh | 3 +- 9 files changed, 229 insertions(+), 201 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8ee1b38..d5ad1cd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,6 +16,5 @@ WORKDIR /app COPY --from=build /build/pow-bot-deterrent /app/pow-bot-deterrent COPY static /app/static COPY PoW_Bot_Deterrent_API_Tokens /app/PoW_Bot_Deterrent_API_Tokens -RUN chmod +x /app/pow-bot-deterrent ENTRYPOINT ["/app/pow-bot-deterrent"] diff --git a/README.md b/README.md index 6baf085..de3ac45 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ Return type: `text/plain` (error/status messages only) Otherwise it returns 404, 400, or 500. -#### `GET /static/` +#### `GET /pow-bot-deterrent-static/` Return type: depends on file @@ -236,7 +236,7 @@ When `pow-bot-deterrent.js` runs, if it finds an element with `data-pow-bot-dete > 💬 *INFO* the element with the `pow-bot-deterrent` data properties should probably be styled to have a very small font size. When I was designing the css for the bot deterrent element, I made everything scale based on the font size (by using `em`). But because the page I was testing it on had a small font by default, I accidentally made it huge when it is rendered on a default HTML page. So for now you will want to make the font size of the element which contains it fairly small, like `10px` or `11px`. -#### `window.botBotDeterrentInit` +#### `window.powBotDeterrentInit` The bot deterrent event listeners, elements, css, & webworkers **won't be loaded until this function is called**. @@ -248,15 +248,15 @@ For example: ``` ``` #### `window.powBotDeterrentReset` -Resets the bot deterrent(s), stops the webworkers, etc. Use this if you have updated the page and you need to call `window.botBotDeterrentInit` again. +Resets the bot deterrent(s), stops the webworkers, etc. Use this if you have updated the page and you need to call `window.powBotDeterrentInit` again. -#### `window.botBotDeterrentInitDone` +#### `window.powBotDeterrentInitDone` A boolean variable that `pow-bot-deterrent.js` uses internally, so it can know if it has already been initialized or not. @@ -296,10 +296,10 @@ function MyComponent({botDeterrentURL, challenge}) { // Maybe less clear than the above, but JavaScript heads might enjoy this more: // window[uniqueCallback] = setNonce; - if(window.botBotDeterrentInitDone) { + if(window.powBotDeterrentInitDone) { window.powBotDeterrentReset(); } - window.botBotDeterrentInit(); + window.powBotDeterrentInit(); }, [uniqueCallback]); return ( @@ -484,7 +484,7 @@ There are two main important parts, the form and the javascript at the bottom: document.querySelector("form input[type='submit']").disabled = false; }; - + ``` ⚠️ **NOTE** that the element with the `pow-bot-deterrent` data properties is placed **inside a form element**. This is required because the bot deterrent needs to know which input elements it should trigger on. We only want it to trigger when the user actually intends to submit the form; otherwise we are wasting a lot of their CPU cycles for no reason! diff --git a/build-docker.sh b/build-docker.sh index 7e13c18..fa2489c 100755 --- a/build-docker.sh +++ b/build-docker.sh @@ -1,6 +1,10 @@ #!/bin/bash -e -VERSION="0.0.13" +tag="0.0.0" +if git describe --tags --abbrev=0 > /dev/null 2>&1 ; then + tag="$(git describe --tags --abbrev=0)" +fi +VERSION="$tag-$(git rev-parse --short HEAD)-$(hexdump -n 2 -ve '1/1 "%.2x"' /dev/urandom)" rm -rf dockerbuild || true mkdir dockerbuild @@ -9,17 +13,17 @@ cp Dockerfile dockerbuild/Dockerfile-amd64 cp Dockerfile dockerbuild/Dockerfile-arm cp Dockerfile dockerbuild/Dockerfile-arm64 -sed -E 's|FROM alpine|FROM amd64/alpine|' -i dockerbuild/Dockerfile-amd64 -sed -E 's|FROM alpine|FROM arm32v7/alpine|' -i dockerbuild/Dockerfile-arm -sed -E 's|FROM alpine|FROM arm64v8/alpine|' -i dockerbuild/Dockerfile-arm64 +sed -E 's|FROM alpine|FROM --platform=linux/amd64 alpine|' -i dockerbuild/Dockerfile-amd64 +sed -E 's|FROM alpine|FROM --platform=linux/arm/v7 alpine|' -i dockerbuild/Dockerfile-arm +sed -E 's|FROM alpine|FROM --platform=linux/arm64/v8 alpine|' -i dockerbuild/Dockerfile-arm64 sed -E 's/GOARCH=/GOARCH=amd64/' -i dockerbuild/Dockerfile-amd64 sed -E 's/GOARCH=/GOARCH=arm/' -i dockerbuild/Dockerfile-arm sed -E 's/GOARCH=/GOARCH=arm64/' -i dockerbuild/Dockerfile-arm64 -docker build -f dockerbuild/Dockerfile-amd64 -t sequentialread/pow-bot-deterrent:$VERSION-amd64 . -docker build -f dockerbuild/Dockerfile-arm -t sequentialread/pow-bot-deterrent:$VERSION-arm . -docker build -f dockerbuild/Dockerfile-arm64 -t sequentialread/pow-bot-deterrent:$VERSION-arm64 . +docker build --progress=plain -f dockerbuild/Dockerfile-amd64 -t sequentialread/pow-bot-deterrent:$VERSION-amd64 . +docker build --progress=plain -f dockerbuild/Dockerfile-arm -t sequentialread/pow-bot-deterrent:$VERSION-arm . +docker build --progress=plain -f dockerbuild/Dockerfile-arm64 -t sequentialread/pow-bot-deterrent:$VERSION-arm64 . docker push sequentialread/pow-bot-deterrent:$VERSION-amd64 docker push sequentialread/pow-bot-deterrent:$VERSION-arm diff --git a/example/index.html b/example/index.html index ab179c5..57f257d 100644 --- a/example/index.html +++ b/example/index.html @@ -47,31 +47,6 @@ document.querySelector("form input[type='submit']").disabled = false; }; - - + \ No newline at end of file diff --git a/main.go b/main.go index 35357e8..32e00b2 100644 --- a/main.go +++ b/main.go @@ -14,15 +14,34 @@ import ( "os/exec" "path" "path/filepath" + "reflect" "regexp" "strconv" "strings" "time" + configlite "git.sequentialread.com/forest/config-lite" errors "git.sequentialread.com/forest/pkg-errors" "golang.org/x/crypto/scrypt" ) +type Config struct { + ListenPort int `json:"listen_port"` + BatchSize int `json:"batch_size"` + DeprecateAfterBatches int `json:"deprecate_after_batches"` + ScryptCPUAndMemoryCost int `json:"scrypt_cpu_and_memory_cost"` + AdminAPIToken string `json:"admin_api_token"` + + EmailAddress string `json:"email_address"` + // port 993 (IMAPS) + // port 143 (STARTTLS) [deprecated!] + ImapHost string `json:"imap_host"` + ImapPort int `json:"imap_port"` + ImapEncryption string `json:"imap_encryption"` + ImapUsername string `json:"imap_username"` + ImapPassword string `json:"imap_password"` +} + // https://en.wikipedia.org/wiki/Scrypt type ScryptParameters struct { CPUAndMemoryCost int `json:"N"` @@ -38,6 +57,9 @@ type Challenge struct { DifficultyLevel int `json:"dl"` } +var config Config +var appDirectory string +var scryptParameters ScryptParameters var currentChallengesGeneration = map[string]int{} var challenges = map[string]map[string]int{} @@ -45,51 +67,7 @@ func main() { var err error - batchSize := 1000 - deprecateAfterBatches := 10 - portNumber := 2370 - scryptCPUAndMemoryCost := 16384 - batchSizeEnv := os.ExpandEnv("$POW_BOT_DETERRENT_BATCH_SIZE") - deprecateAfterBatchesEnv := os.ExpandEnv("$POW_BOT_DETERRENT_DEPRECATE_AFTER_BATCHES") - portNumberEnv := os.ExpandEnv("$POW_BOT_DETERRENT_LISTEN_PORT") - scryptCPUAndMemoryCostEnv := os.ExpandEnv("$POW_BOT_DETERRENT_SCRYPT_CPU_AND_MEMORY_COST") - if batchSizeEnv != "" { - batchSize, err = strconv.Atoi(batchSizeEnv) - if err != nil { - panic(errors.Wrapf(err, "can't start the app because the POW_BOT_DETERRENT_BATCH_SIZE '%s' can't be converted to an integer", batchSizeEnv)) - } - } - if deprecateAfterBatchesEnv != "" { - deprecateAfterBatches, err = strconv.Atoi(deprecateAfterBatchesEnv) - if err != nil { - panic(errors.Wrapf(err, "can't start the app because the POW_BOT_DETERRENT_DEPRECATE_AFTER_BATCHES '%s' can't be converted to an integer", deprecateAfterBatchesEnv)) - } - } - if portNumberEnv != "" { - portNumber, err = strconv.Atoi(portNumberEnv) - if err != nil { - panic(errors.Wrapf(err, "can't start the app because the POW_BOT_DETERRENT_LISTEN_PORT '%s' can't be converted to an integer", portNumberEnv)) - } - } - if scryptCPUAndMemoryCostEnv != "" { - scryptCPUAndMemoryCost, err = strconv.Atoi(scryptCPUAndMemoryCostEnv) - if err != nil { - panic(errors.Wrapf(err, "can't start the app because the POW_BOT_DETERRENT_SCRYPT_CPU_AND_MEMORY_COST '%s' can't be converted to an integer", scryptCPUAndMemoryCostEnv)) - } - } - - apiTokensFolder := locateAPITokensFolder() - adminAPIToken := os.ExpandEnv("$POW_BOT_DETERRENT_ADMIN_API_TOKEN") - if adminAPIToken == "" { - panic(errors.New("can't start the app, the POW_BOT_DETERRENT_ADMIN_API_TOKEN environment variable is required")) - } - - scryptParameters := ScryptParameters{ - CPUAndMemoryCost: scryptCPUAndMemoryCost, - BlockSize: 8, - Paralellization: 1, - KeyLength: 16, - } + apiTokensFolder := readConfiguration() requireMethod := func(method string) func(http.ResponseWriter, *http.Request) bool { return func(responseWriter http.ResponseWriter, request *http.Request) bool { @@ -103,7 +81,7 @@ func main() { } requireAdmin := func(responseWriter http.ResponseWriter, request *http.Request) bool { - if request.Header.Get("Authorization") != fmt.Sprintf("Bearer %s", adminAPIToken) { + if request.Header.Get("Authorization") != fmt.Sprintf("Bearer %s", config.AdminAPIToken) { http.Error(responseWriter, "401 Unauthorized", http.StatusUnauthorized) return true } @@ -262,8 +240,8 @@ func main() { return true } - toReturn := make([]string, batchSize) - for i := 0; i < batchSize; i++ { + toReturn := make([]string, config.BatchSize) + for i := 0; i < config.BatchSize; i++ { preimageBytes := make([]byte, 8) _, err := rand.Read(preimageBytes) if err != nil { @@ -309,7 +287,7 @@ func main() { } toRemove := []string{} for k, generation := range challenges[token] { - if generation+deprecateAfterBatches < currentChallengesGeneration[token] { + if generation+config.DeprecateAfterBatches < currentChallengesGeneration[token] { toRemove = append(toRemove, k) } } @@ -417,11 +395,23 @@ func main() { return true }) + http.HandleFunc("/static/captcha.css", func(responseWriter http.ResponseWriter, request *http.Request) { + bytez, _ := os.ReadFile("./static/pow-bot-deterrent.css") + responseWriter.Header().Set("Content-Type", "text/css") + responseWriter.Write(bytez) + }) + http.HandleFunc("/static/captcha.js", func(responseWriter http.ResponseWriter, request *http.Request) { + bytez, _ := os.ReadFile("./static/pow-bot-deterrent.js") + responseWriter.Header().Set("Content-Type", "application/javascript") + responseWriter.Write(bytez) + }) + http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static/")))) + http.Handle("/pow-bot-deterrent-static/", http.StripPrefix("/pow-bot-deterrent-static/", http.FileServer(http.Dir("./static/")))) - log.Printf("💥 PoW! Bot Deterrent server listening on port %d", portNumber) + log.Printf("💥 PoW! Bot Deterrent server listening on port %d", config.ListenPort) - err = http.ListenAndServe(fmt.Sprintf(":%d", portNumber), nil) + err = http.ListenAndServe(fmt.Sprintf(":%d", config.ListenPort), nil) // if got this far it means server crashed! panic(err) @@ -489,3 +479,81 @@ func getCurrentExecDir() (dir string, err error) { return dir, nil } + +func readConfiguration() string { + apiTokensFolderPath := locateAPITokensFolder() + appDirectory = filepath.Dir(apiTokensFolderPath) + configJsonPath := filepath.Join(appDirectory, "config.json") + err := configlite.ReadConfiguration(configJsonPath, "POW_BOT_DETERRENT", []string{}, reflect.ValueOf(&config)) + if err != nil { + panic(errors.Wrap(err, "ReadConfiguration returned")) + } + + errors := []string{} + if config.ListenPort == 0 { + config.ListenPort = 2370 + } + if config.BatchSize == 0 { + config.BatchSize = 1000 + } + if config.DeprecateAfterBatches == 0 { + config.DeprecateAfterBatches = 10 + } + if config.ScryptCPUAndMemoryCost == 0 { + config.ScryptCPUAndMemoryCost = 16384 + } + if config.AdminAPIToken == "" { + errors = append(errors, "the POW_BOT_DETERRENT_ADMIN_API_TOKEN environment variable is required") + } + + if config.EmailAddress != "" { + if config.ImapHost == "" { + config.ImapHost = "localhost" + } + if config.ImapPort == 0 { + config.ImapPort = 993 + } + if config.ImapEncryption == "" { + config.ImapEncryption = "SMTPS" + } + if config.ImapEncryption != "STARTTLS" && config.ImapEncryption != "IMAPS" && config.ImapEncryption != "NONE" { + errors = append(errors, fmt.Sprintf("ImapEncryption '%s' must be IMAPS, STARTTLS or NONE", config.ImapEncryption)) + } + if config.ImapUsername == "" { + errors = append(errors, "ImapUsername is required") + } + if config.ImapPassword == "" { + errors = append(errors, "ImapPassword is required") + } + } + + if len(errors) > 0 { + log.Fatalln("💥 PoW Bot Deterrent can't start because there are configuration issues:") + log.Fatalln(strings.Join(errors, "\n")) + } + + scryptParameters = ScryptParameters{ + CPUAndMemoryCost: config.ScryptCPUAndMemoryCost, + BlockSize: 8, + Paralellization: 1, + KeyLength: 16, + } + + log.Println("💥 PoW Bot Deterrent starting up with config:") + configToLogBytes, _ := json.MarshalIndent(config, "", " ") + configToLogString := regexp.MustCompile( + `("admin_api_token": ")[^"]+(",)`, + ).ReplaceAllString( + string(configToLogBytes), + "$1******$2", + ) + configToLogString = regexp.MustCompile( + `("imap_password": ")[^"]+(",?)`, + ).ReplaceAllString( + configToLogString, + "$1******$2", + ) + log.Println(configToLogString) + + return apiTokensFolderPath +} diff --git a/proofOfWorkerStub.js b/proofOfWorkerStub.js index bc5e8e8..7cf2725 100644 --- a/proofOfWorkerStub.js +++ b/proofOfWorkerStub.js @@ -7,6 +7,7 @@ let scrypt; let scryptPromise; +let wasm; let working = false; const batchSize = 8; @@ -125,7 +126,7 @@ onmessage = function(e) { } }; - if(scrypt) { + if(wasm && scrypt) { doWork(); } else { scryptPromise.then(() => { diff --git a/static/pow-bot-deterrent.js b/static/pow-bot-deterrent.js index b4757e8..2f85e89 100644 --- a/static/pow-bot-deterrent.js +++ b/static/pow-bot-deterrent.js @@ -3,31 +3,27 @@ const numberOfWebWorkersToCreate = 4; window.powBotDeterrentReset = () => { - window.botBotDeterrentInitDone = false; + window.powBotDeterrentInitDone = false; }; - window.botBotDeterrentInit = () => { - if(window.botBotDeterrentInitDone) { - console.error("botBotDeterrentInit was called twice!"); + const trimSlashes = x => x.replace(/^\/|\/$/g, ''); + + window.powBotDeterrentInit = () => { + if(window.powBotDeterrentInitDone) { + console.error("powBotDeterrentInit was called twice!"); return } - window.botBotDeterrentInitDone = true; + window.powBotDeterrentInitDone = true; const challenges = Array.from(document.querySelectorAll("[data-pow-bot-deterrent-challenge]")); const challengesMap = {}; - let url = null; + let staticAssetsPath = trimSlashes("/pow-bot-deterrent-static/") let proofOfWorker = { postMessage: () => console.error("error: proofOfWorker was never loaded. ") }; challenges.forEach(element => { - if(!url) { - if(!element.dataset.powBotDeterrentUrl) { - console.error("error: element with data-pow-bot-deterrent-challenge property is missing the data-pow-bot-deterrent-url property"); - } - url = element.dataset.powBotDeterrentUrl; - if(url.endsWith("/")) { - url = url.substring(0, url.length-1) - } + if(element.dataset.powBotDeterrentStaticAssetsPath) { + staticAssetsPath = trimSlashes(element.dataset.powBotDeterrentStaticAssetsPath); } if(!element.dataset.powBotDeterrentCallback) { @@ -62,7 +58,7 @@ //todo } - let cssIsAlreadyLoaded = document.querySelector(`link[href='${url}/static/pow-bot-deterrent.css']`); + let cssIsAlreadyLoaded = document.querySelector(`link[href='/${staticAssetsPath}/pow-bot-deterrent.css']`); cssIsAlreadyLoaded = cssIsAlreadyLoaded || Array.from(document.styleSheets).some(x => { try { @@ -78,7 +74,7 @@ "charset": "utf8", }); stylesheet.onload = () => renderProgressInfo(element); - stylesheet.setAttribute("href", `${url}/static/pow-bot-deterrent.css`); + stylesheet.setAttribute("href", `${staticAssetsPath}/pow-bot-deterrent.css`); } else { renderProgressInfo(element); } @@ -133,104 +129,88 @@ //todo } - if(url) { - - // // https://stackoverflow.com/questions/21913673/execute-web-worker-from-different-origin/62914052#62914052 - // const webWorkerUrlWhichIsProbablyCrossOrigin = `${url}/static/proofOfWorker.js`; - - // const webWorkerPointerDataURL = URL.createObjectURL( - // new Blob( - // [ `importScripts( "${ webWorkerUrlWhichIsProbablyCrossOrigin }" );` ], - // { type: "text/javascript" } - // ) - // ); - - // return - let webWorkers; - webWorkers = [...Array(numberOfWebWorkersToCreate)].map((_, i) => { - const webWorker = new Worker('/static/proofOfWorker.js'); - webWorker.onmessage = function(e) { - const challengeState = challengesMap[e.data.challenge] - if(!challengeState) { - console.error(`error: webworker sent message with unknown challenge '${e.data.challenge}'`); + let webWorkers; + webWorkers = [...Array(numberOfWebWorkersToCreate)].map((_, i) => { + const webWorker = new Worker(`/${staticAssetsPath}/proofOfWorker.js`); + webWorker.onmessage = function(e) { + const challengeState = challengesMap[e.data.challenge] + if(!challengeState) { + console.error(`error: webworker sent message with unknown challenge '${e.data.challenge}'`); + } + if(e.data.type == "progress") { + challengeState.difficulty = e.data.difficulty; + challengeState.probabilityOfFailurePerAttempt = e.data.probabilityOfFailurePerAttempt; + if(!challengeState.smallestHash || challengeState.smallestHash > e.data.smallestHash) { + challengeState.smallestHash = e.data.smallestHash; } - if(e.data.type == "progress") { - challengeState.difficulty = e.data.difficulty; - challengeState.probabilityOfFailurePerAttempt = e.data.probabilityOfFailurePerAttempt; - if(!challengeState.smallestHash || challengeState.smallestHash > e.data.smallestHash) { - challengeState.smallestHash = e.data.smallestHash; - } - challengeState.attempts += e.data.attempts; - } else if(e.data.type == "success") { - if(!challengeState.done) { - challengeState.done = true; - clearInterval(challengeState.updateProgressInterval); - - const element = challengeState.element; - const progressBar = element.querySelector(".pow-bot-deterrent-progress-bar"); - const checkmark = element.querySelector(".pow-checkmark-icon"); - const gears = element.querySelector(".pow-gears-icon"); - const bestHashElement = element.querySelector(".pow-bot-deterrent-best-hash"); - const description = element.querySelector(".pow-bot-deterrent-description"); - challengeState.smallestHash = e.data.smallestHash; - bestHashElement.textContent = getHashProgressText(challengeState); - bestHashElement.classList.add("pow-bot-deterrent-best-hash-done"); - checkmark.style.display = "block"; - checkmark.style.animationPlayState = "running"; - gears.style.display = "none"; - progressBar.style.width = "100%"; - - description.innerHTML = ""; - createElement( - description, - "a", - {"href": "https://en.wikipedia.org/wiki/Proof_of_work"}, - "PoW" - ); - appendFragment(description, " complete, you may continue."); - createElement(description, "br"); - appendFragment(description, "Privacy-respecting anti-spam measure."); - - webWorkers.forEach(x => x.postMessage({stop: "STOP"})); - - const callback = getCallbackFromGlobalNamespace(element.dataset.powBotDeterrentCallback); - if(!callback) { - console.error(`error: data-pow-bot-deterrent-callback '${element.dataset.powBotDeterrentCallback}' ` - + "is not defined in the global namespace!"); - } else { - console.log(`firing callback for challenge ${e.data.challenge} w/ nonce ${e.data.nonce}, smallestHash: ${e.data.smallestHash}, difficulty: ${e.data.difficulty}`); - callback(e.data.nonce); - } + challengeState.attempts += e.data.attempts; + } else if(e.data.type == "success") { + if(!challengeState.done) { + challengeState.done = true; + clearInterval(challengeState.updateProgressInterval); + + const element = challengeState.element; + const progressBar = element.querySelector(".pow-bot-deterrent-progress-bar"); + const checkmark = element.querySelector(".pow-checkmark-icon"); + const gears = element.querySelector(".pow-gears-icon"); + const bestHashElement = element.querySelector(".pow-bot-deterrent-best-hash"); + const description = element.querySelector(".pow-bot-deterrent-description"); + challengeState.smallestHash = e.data.smallestHash; + bestHashElement.textContent = getHashProgressText(challengeState); + bestHashElement.classList.add("pow-bot-deterrent-best-hash-done"); + checkmark.style.display = "block"; + checkmark.style.animationPlayState = "running"; + gears.style.display = "none"; + progressBar.style.width = "100%"; + + description.innerHTML = ""; + createElement( + description, + "a", + {"href": "https://en.wikipedia.org/wiki/Proof_of_work"}, + "PoW" + ); + appendFragment(description, " complete, you may continue."); + createElement(description, "br"); + appendFragment(description, "Privacy-respecting anti-spam measure."); + + webWorkers.forEach(x => x.postMessage({stop: "STOP"})); + + const callback = getCallbackFromGlobalNamespace(element.dataset.powBotDeterrentCallback); + if(!callback) { + console.error(`error: data-pow-bot-deterrent-callback '${element.dataset.powBotDeterrentCallback}' ` + + "is not defined in the global namespace!"); } else { - console.log("success recieved twice"); + console.log(`firing callback for challenge ${e.data.challenge} w/ nonce ${e.data.nonce}, smallestHash: ${e.data.smallestHash}, difficulty: ${e.data.difficulty}`); + callback(e.data.nonce); } - } else if(e.data.type == "error") { - console.error(`error: webworker errored out: '${e.data.message}'`); } else { - console.error(`error: webworker sent message with unknown type '${e.data.type}'`); + console.log("success recieved twice"); } - }; - return webWorker; - }); - - // URL.revokeObjectURL(webWorkerPointerDataURL); - - proofOfWorker = { - postMessage: arg => webWorkers.forEach((x, i) => { - x.postMessage({ ...arg, workerId: i }) - }) + } else if(e.data.type == "error") { + console.error(`error: webworker errored out: '${e.data.message}'`); + } else { + console.error(`error: webworker sent message with unknown type '${e.data.type}'`); + } }; + return webWorker; + }); - window.powBotDeterrentReset = () => { - window.botBotDeterrentInitDone = false; - webWorkers.forEach(x => x.terminate()); - }; - } + proofOfWorker = { + postMessage: arg => webWorkers.forEach((x, i) => { + x.postMessage({ ...arg, workerId: i }) + }) + }; + + window.powBotDeterrentReset = () => { + window.powBotDeterrentInitDone = false; + webWorkers.forEach(x => x.terminate()); + }; }; const challenges = Array.from(document.querySelectorAll("[data-pow-bot-deterrent-challenge]")); if(challenges.length) { - window.botBotDeterrentInit(); + window.powBotDeterrentInit(); } function getCallbackFromGlobalNamespace(callbackString) { diff --git a/static/proofOfWorker.js b/static/proofOfWorker.js index f4e9238..77db74b 100644 --- a/static/proofOfWorker.js +++ b/static/proofOfWorker.js @@ -7,6 +7,7 @@ let scrypt; let scryptPromise; +let wasm = undefined; let working = false; const batchSize = 4; @@ -149,7 +150,6 @@ let wasm_bindgen; if (typeof document !== 'undefined' && document.currentScript !== null) { script_src = new URL(document.currentScript.src, location.href).toString(); } - let wasm = undefined; let WASM_VECTOR_LEN = 0; @@ -365,11 +365,11 @@ let wasm_bindgen; return __wbg_finalize_init(instance, module); } - wasm_bindgen = Object.assign(__wbg_init, { initSync }, __exports); + /pow-bot-deterrent-static/_bindgen = Object.assign(__wbg_init, { initSync }, __exports); })(); scrypt = wasm_bindgen.scrypt; -scryptPromise = wasm_bindgen({module_or_path: "/static/scrypt.wasm"}); +scryptPromise = wasm_bindgen({module_or_path: "/pow-bot-deterrent-static/scrypt.wasm"}); diff --git a/wasm_build/build_wasm.sh b/wasm_build/build_wasm.sh index 11a8c9f..274a323 100755 --- a/wasm_build/build_wasm.sh +++ b/wasm_build/build_wasm.sh @@ -46,7 +46,8 @@ echo ' cat ../proofOfWorkerStub.js | tail -n +6 >> ../static/proofOfWorker.js -cat scrypt-wasm/pkg/scrypt_wasm.js >> ../static/proofOfWorker.js +# wasm was defined at the top of proofOfWorker.js, so don't define it again. +cat scrypt-wasm/pkg/scrypt_wasm.js | grep -v 'let wasm = ' >> ../static/proofOfWorker.js # see: https://rustwasm.github.io/docs/wasm-bindgen/examples/without-a-bundler.html echo '