ai-code-battle/starters/go/main.go
jedarden fe04cd275d fix(starter-kits): complete incomplete refactoring and fix build errors
The starter kits had uncommitted changes from a refactoring that broke
the Rust and TypeScript builds. This commit completes the refactoring
and fixes the build errors.

**Rust starter fixes:**
- Add `http::header` import to fix `header::HeaderName` reference
- Replace `hmac::compare_digest` (non-existent) with constant-time comparison

**TypeScript starter fixes:**
- Rename `GameState` -> `VisibleState` and `MoveResponse` -> `TurnResponse`
- Fix `strategy.ts` to use `bot.position.row` instead of `bot.row`
- Fix Move type to use `position: {row, col}` structure

**Go starter fixes:**
- Remove unused `strings` import

All 8 starter kits now build successfully with their respective toolchains.

Closes: bf-2rwz

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 22:40:37 -04:00

96 lines
2.4 KiB
Go

package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"strconv"
)
var sharedSecret string
func main() {
secret := os.Getenv("SHARED_SECRET")
if secret == "" {
log.Fatal("SHARED_SECRET environment variable must be set")
}
sharedSecret = secret
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
http.HandleFunc("/health", handleHealth)
http.HandleFunc("/turn", handleTurn)
fmt.Printf("Bot listening on port %s\n", port)
log.Fatal(http.ListenAndServe(":"+port, nil))
}
func handleHealth(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
}
func handleTurn(w http.ResponseWriter, r *http.Request) {
// Read body
var state VisibleState
if err := json.NewDecoder(r.Body).Decode(&state); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
// Get auth headers
matchID := r.Header.Get("X-ACB-Match-Id")
turnStr := r.Header.Get("X-ACB-Turn")
signature := r.Header.Get("X-ACB-Signature")
// Verify signature (optional but recommended)
body, _ := json.Marshal(state)
if !verifySignature(body, matchID, turnStr, signature) {
http.Error(w, "Invalid signature", http.StatusUnauthorized)
return
}
// Compute moves
moves := ComputeMoves(&state)
// Send response
response := map[string]any{"moves": moves}
responseBody, _ := json.Marshal(response)
turn, _ := strconv.Atoi(turnStr)
sig := signResponse(responseBody, matchID, turn)
w.Header().Set("Content-Type", "application/json")
w.Header().Set("X-ACB-Signature", sig)
w.WriteHeader(http.StatusOK)
w.Write(responseBody)
}
func verifySignature(body []byte, matchID, turnStr, signature string) bool {
if signature == "" {
return true // Skip verification if not provided
}
bodyHash := sha256.Sum256(body)
signingString := fmt.Sprintf("%s.%s.%s", matchID, turnStr, hex.EncodeToString(bodyHash[:]))
mac := hmac.New(sha256.New, []byte(sharedSecret))
mac.Write([]byte(signingString))
expectedSig := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(signature), []byte(expectedSig))
}
func signResponse(body []byte, matchID string, turn int) string {
bodyHash := sha256.Sum256(body)
signingString := fmt.Sprintf("%s.%d.%s", matchID, turn, hex.EncodeToString(bodyHash[:]))
mac := hmac.New(sha256.New, []byte(sharedSecret))
mac.Write([]byte(signingString))
return hex.EncodeToString(mac.Sum(nil))
}