Initial commit.
This commit is contained in:
commit
0a9434be1b
18 changed files with 1860 additions and 0 deletions
5
server/go-http/README.md
Normal file
5
server/go-http/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
NOJSCAP Go server example with net/http + html/template.
|
||||
|
||||
# Running
|
||||
|
||||
go run server.go
|
175
server/go-http/server.go
Normal file
175
server/go-http/server.go
Normal file
|
@ -0,0 +1,175 @@
|
|||
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, "<p>Invalid challenge.</p><a href='/'>Try again</a>")
|
||||
return
|
||||
}
|
||||
|
||||
hash := sha256.Sum256([]byte(challenge + nonce))
|
||||
if checkDifficulty(hash[:], difficulty) {
|
||||
fmt.Fprint(w, "<p>Success! Valid nonce.</p><a href='/'>Try again</a>")
|
||||
} else {
|
||||
fmt.Fprint(w, "<p>Invalid nonce.</p><a href='/'>Try again</a>")
|
||||
}
|
||||
}
|
||||
|
||||
var tmpl = template.Must(template.New("page").Parse(`
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>NOJSCAP demo</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
body {
|
||||
padding: 20px;
|
||||
margin-bottom: 300px;
|
||||
background: #cacaca;
|
||||
color: black;
|
||||
}
|
||||
code {
|
||||
white-space: break-spaces;
|
||||
background: black;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
display: block;
|
||||
max-width: 500px;
|
||||
}
|
||||
.h {
|
||||
font-size: 21px;
|
||||
font-weight: bolder;
|
||||
width: 100%;
|
||||
float: left;
|
||||
}
|
||||
button {
|
||||
background: #006ed0;
|
||||
color: white;
|
||||
border: 1px solid #006ed0;
|
||||
padding: 10px 20px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
input {
|
||||
background: black;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
display: block;
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
border: 0px solid transparent;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>NOJSCAP demo</h1>
|
||||
<p><a href="https://git.libroot.org/libroot/NOJSCAP/" target="_blank">https://git.libroot.org/libroot/NOJSCAP/</a></p>
|
||||
<p>If you don't already have the <b><em>NOJSCAP</em></b> client:</p>
|
||||
<code>$ git clone https://git.libroot.org/libroot/NOJSCAP/$ cd NOJSCAP/client/</code>
|
||||
<p><code>$ python3 pow_client.py {{.Challenge}} {{.Difficulty}}</code></p>
|
||||
<p><strong>Go:</strong></p>
|
||||
<p><code>$ go run pow_client.go {{.Challenge}} {{.Difficulty}}</code></p>
|
||||
<p><strong>Node.js:</strong></p>
|
||||
<p><code>$ node pow_client.js {{.Challenge}} {{.Difficulty}}</code></p>
|
||||
<p><strong>Rust:</strong></p>
|
||||
<p><code>$ rustc pow_client.rs -o pow_client_rs$ pow_client_rs {{.Challenge}} {{.Difficulty}}</code></p>
|
||||
<p><strong>C:</strong></p>
|
||||
<p><code>$ gcc -O2 -o pow_client pow_client.c -lssl -lcrypto$ ./pow_client {{.Challenge}} {{.Difficulty}}</code></p>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="challenge" value="{{.Challenge}}">
|
||||
<label class="h">Nonce: <input name="nonce"></label>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
`))
|
||||
|
||||
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))
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue