diff --git a/server/main.go b/server/main.go index 2e882b5..d36b68c 100644 --- a/server/main.go +++ b/server/main.go @@ -35,7 +35,7 @@ import ( _ "github.com/mattn/go-sqlite3" ) -const MAX_SIG = (1 << 256) - 1 +const MAX_KEY_64 = (1 << 64) - 1 const MAX_BODY_SIZE = 2217 var ( @@ -140,7 +140,7 @@ func (s *Spring83Server) getBoard(key string) (*Board, error) { row := s.db.QueryRow(query, key) var dbkey, board, creation, expiry string - err := row.Scan(&dbkey, &board, &expiry) + err := row.Scan(&dbkey, &board, &creation, &expiry) if err != nil { if err != sql.ErrNoRows { return nil, err @@ -191,8 +191,16 @@ func (s *Spring83Server) getDifficulty() (float64, uint64, error) { return 0, 0, err } + // The calculation of the difficulty factor is not part of this specification, but here's an example formula that works well: + // + // difficulty_factor = ( num_boards_stored / max_boards )**4 + // + // a threshold defined by the server's difficulty factor: + // + // MAX_KEY_64 = (2**64 - 1) + // key_64_threshold = round(MAX_KEY_64 * ( 1.0 - difficulty_factor)) difficultyFactor := math.Pow(float64(count)/10_000_000, 4) - keyThreshold := uint64(MAX_SIG * (1.0 - difficultyFactor)) + keyThreshold := uint64(math.Round(MAX_KEY_64 * (1.0 - difficultyFactor))) return difficultyFactor, keyThreshold, nil } @@ -237,14 +245,16 @@ func (s *Spring83Server) publishBoard(w http.ResponseWriter, r *http.Request) { w.Header().Add("Spring-Difficulty", fmt.Sprintf("%f", difficultyFactor)) - // Using that difficulty factor, we can calculate the key threshold: + // If the server doesn't yet have any board stored for the key, then it + // must apply an additional check. The key's first 16 hex characters, + // interpreted as a 64-bit number, must be less than a threshold + // defined by the server's difficulty factor: // - // MAX_KEY = (2**256 - 1) - // key_threshold = MAX_KEY * (1.0 - 0.52) = + // MAX_KEY_64 = (2**64 - 1) + // key_64_threshold = round(MAX_KEY_64 * ( 1.0 - difficulty_factor)) // - // The server must reject PUT requests for new keys that are not less - // than - if binary.BigEndian.Uint64(key) >= keyThreshold { + // If the key fails this check, the server must reject the PUT request, returning 403 Forbidden. + if binary.BigEndian.Uint64(key[:8]) < keyThreshold { if err != nil || len(key) != 32 { http.Error(w, "Key greater than threshold", http.StatusForbidden) return @@ -378,6 +388,7 @@ func (s *Spring83Server) publishBoard(w http.ResponseWriter, r *http.Request) { } expiry := time.Now().AddDate(0, 0, 7).Format(time.RFC3339) + bodyTimeISO := bodyTime.Format(time.RFC3339) _, err = s.db.Exec(` INSERT INTO boards (key, board, creation_datetime, expiry_datetime) values(?, ?, ?, ?) @@ -385,7 +396,7 @@ func (s *Spring83Server) publishBoard(w http.ResponseWriter, r *http.Request) { board=?, creation_datetime=?, expiry_datetime=? - `, keyStr, body, bodyTime, expiry, body, bodyTime, expiry) + `, keyStr, body, bodyTimeISO, expiry, body, bodyTimeISO, expiry) if err != nil { log.Printf("%s", err) @@ -414,7 +425,7 @@ func (s *Spring83Server) loadBoards() ([]Board, error) { for rows.Next() { var key, board, creation, expiry string - err = rows.Scan(&key, &board, &expiry) + err = rows.Scan(&key, &board, &creation, &expiry) if err != nil { return nil, err }