package main import ( "crypto/rand" "crypto/sha256" "encoding/hex" "fmt" "html/template" "log" "net/http" "strconv" "sync" "time" ) const ( port = 3000 difficulty = 20 ) var ( challengeStore = make(map[string]time.Time) storeMutex sync.Mutex ) func generateChallenge() string { b := make([]byte, 12) _, err := rand.Read(b) if err != nil { panic(err) } return hex.EncodeToString(b) } func checkDifficulty(hash []byte, bits int) bool { i := 0 for bits > 0 { b := hash[i] if bits >= 8 { if b != 0 { return false } bits -= 8 } else { mask := byte(0xFF << (8 - bits)) if b&mask != 0 { return false } bits = 0 } i++ } return true } func indexHandler(w http.ResponseWriter, r *http.Request) { challenge := generateChallenge() storeMutex.Lock() challengeStore[challenge] = time.Now() storeMutex.Unlock() tmpl.Execute(w, map[string]string{ "Challenge": challenge, "Difficulty": strconv.Itoa(difficulty), }) } func postHandler(w http.ResponseWriter, r *http.Request) { challenge := r.FormValue("challenge") nonce := r.FormValue("nonce") storeMutex.Lock() _, ok := challengeStore[challenge] if ok { delete(challengeStore, challenge) } storeMutex.Unlock() if !ok { fmt.Fprint(w, "

Invalid challenge.

Try again") return } hash := sha256.Sum256([]byte(challenge + nonce)) if checkDifficulty(hash[:], difficulty) { fmt.Fprint(w, "

Success! Valid nonce.

Try again
") } else { fmt.Fprint(w, "

Invalid nonce.

Try again
") } } var tmpl = template.Must(template.New("page").Parse(` NOJSCAP demo

NOJSCAP demo

https://git.libroot.org/libroot/NOJSCAP/

If you don't already have the NOJSCAP client:

$ git clone https://git.libroot.org/libroot/NOJSCAP/$ cd NOJSCAP/client/

$ python3 nojscap.py {{.Challenge}} {{.Difficulty}}

Go:

$ go run nojscap.go {{.Challenge}} {{.Difficulty}}

Node.js:

$ node nojscap.js {{.Challenge}} {{.Difficulty}}

Rust:

$ rustc nojscap.rs -o nojscap_rs$ nojscap_rs {{.Challenge}} {{.Difficulty}}

C:

$ gcc -O2 -o nojscap nojscap.c -lssl -lcrypto$ ./nojscap {{.Challenge}} {{.Difficulty}}

`)) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodPost { postHandler(w, r) } else { indexHandler(w, r) } }) fmt.Printf("Running on http://localhost:%d\n", port) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil)) }