mirror of
https://github.com/sequentialread/pow-captcha.git
synced 2025-11-23 22:15:47 +00:00
updates for pow-bot-deterrent-rp -- fixing cross domain webworker issue
This commit is contained in:
parent
86a1d903dc
commit
9f8fc11ed5
@ -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"]
|
||||
|
||||
|
||||
16
README.md
16
README.md
@ -142,7 +142,7 @@ Return type: `text/plain` (error/status messages only)
|
||||
Otherwise it returns 404, 400, or 500.
|
||||
|
||||
|
||||
#### `GET /static/<filename>`
|
||||
#### `GET /pow-bot-deterrent-static/<filename>`
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
<script>
|
||||
window.botBotDeterrentInit();
|
||||
window.powBotDeterrentInit();
|
||||
</script>
|
||||
```
|
||||
|
||||
#### `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;
|
||||
};
|
||||
</script>
|
||||
<script src="{{ .PowAPIURL }}/static/pow-bot-deterrent.js"></script>
|
||||
<script src="{{ .PowAPIURL }}/pow-bot-deterrent-static/pow-bot-deterrent.js"></script>
|
||||
```
|
||||
|
||||
⚠️ **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!
|
||||
|
||||
@ -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
|
||||
|
||||
@ -47,31 +47,6 @@
|
||||
document.querySelector("form input[type='submit']").disabled = false;
|
||||
};
|
||||
</script>
|
||||
<script src="/static/pow-bot-deterrent.js"></script>
|
||||
<!-- <script src='./static/scrypt_wasm.js'></script>
|
||||
<script>
|
||||
const { scrypt } = wasm_bindgen;
|
||||
|
||||
async function run() {
|
||||
console.log("a");
|
||||
await wasm_bindgen();
|
||||
|
||||
console.log(scrypt(hexEncode('password in hex'), hexEncode('password in hex'), 4096, 8, 1, 16))
|
||||
}
|
||||
|
||||
run();
|
||||
|
||||
function hexEncode(s){
|
||||
var hex, i;
|
||||
|
||||
var result = "";
|
||||
for (i=0; i<s.length; i++) {
|
||||
hex = s.charCodeAt(i).toString(16);
|
||||
result += ("000"+hex).slice(-4);
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
</script> -->
|
||||
<script src="/pow-bot-deterrent-static/pow-bot-deterrent.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
170
main.go
170
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
|
||||
}
|
||||
|
||||
@ -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(() => {
|
||||
|
||||
@ -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);
|
||||
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%";
|
||||
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.");
|
||||
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"}));
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
|
||||
@ -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"});
|
||||
|
||||
|
||||
|
||||
@ -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 '
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user