handle difficulty

main
Bill Mill 2 years ago
parent 3c5b876ebd
commit 5ac47534f7
  1. 54
      server/main.go
  2. 5
      server/templates/index.html

@ -13,12 +13,14 @@ import (
"bytes"
"crypto/ed25519"
"database/sql"
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"math"
"net/http"
"os"
"strings"
@ -28,6 +30,8 @@ import (
_ "github.com/mattn/go-sqlite3"
)
const MAX_SIG = (1 << 256) - 1
func must(err error) {
if err != nil {
log.Fatal(err)
@ -142,6 +146,25 @@ func (s *Spring83Server) getBoard(key string) (*Board, error) {
}, nil
}
func (s *Spring83Server) boardCount() (int, error) {
query := `
SELECT count(*)
FROM boards
`
row := s.db.QueryRow(query)
var count int
err := row.Scan(&count)
if err != nil {
if err != sql.ErrNoRows {
return 0, err
}
panic(err)
}
return count, nil
}
func (s *Spring83Server) publishBoard(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Spring-Version", "83")
@ -186,7 +209,36 @@ func (s *Spring83Server) publishBoard(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Old content", http.StatusConflict)
return
}
log.Printf("%s\n", mtime)
// if the server doesn't have any board stored for <key>, then it must
// apply another check. The key, interpreted as a 256-bit number, must be
// less than a threshold defined by the server's difficulty factor:
if curBoard == nil {
count, err := s.boardCount()
if err != nil {
log.Printf(err.Error())
http.Error(w, "internal error", http.StatusInternalServerError)
return
}
difficultyFactor := math.Pow(float64(count)/10_000_000, 4)
w.Header().Add("Spring-Difficulty", fmt.Sprintf("%f", difficultyFactor))
keyThreshold := MAX_SIG * (1.0 - difficultyFactor)
// Using that difficulty factor, we can calculate the key threshold:
//
// MAX_KEY = (2**256 - 1)
// key_threshold = MAX_KEY * (1.0 - 0.52) = <an inscrutable gigantic number>
//
// The server must reject PUT requests for new keys that are not less
// than <an inscrutable gigantic number>
if binary.BigEndian.Uint64(key) >= uint64(keyThreshold) {
if err != nil || len(key) != 32 {
// the spec doesn't specify the proper return value in this case
http.Error(w, "Key greater than threshold", http.StatusBadRequest)
return
}
}
}
var signature []byte
if authorizationHeaders, ok := r.Header["Authorization"]; !ok {

@ -4,6 +4,8 @@
.board {
border: 1px solid black;
margin: 10px;
padding: 10px;
display: inline-flex;
}
</style>
<script>
@ -13,6 +15,9 @@ window.addEventListener("DOMContentLoaded", (_evt) => {
return `<div id="b${board.Key}" class="board"></div>\n`
});
document.querySelector("#containers").innerHTML = divs.join("\n");
// maybe use: https://developer.mozilla.org/en-US/docs/Web/API/Sanitizer/sanitize
// to try and strip XSS/scripts?
boards.forEach(board => {
const container = document.querySelector(`#b${board.Key}`);
const shadow = container.attachShadow({mode: 'closed'});

Loading…
Cancel
Save