From 54548e4873d1112c5070cac9fe0dde65d4a9de7c Mon Sep 17 00:00:00 2001 From: jedarden Date: Sat, 2 May 2026 20:43:44 -0400 Subject: [PATCH] fix(bots): remove timestamp from verify_signature signing string All 10 non-gatherer bots included timestamp in the request verification signing string but the engine (auth.go SignRequest) does not include timestamp. Every incoming turn request failed 401 verification, bots crashed after 10 turns, and all matches ended in stalemate. The engine documentation in auth.go is also misleading (old comment mentioned timestamp in signing string) but the actual implementation never included it. Fixed all language implementations to match. Affected: random (py), swarm (ts), hunter (java), guardian (php), rusher (rs), assassin (rs), phalanx (rs), opportunist (go), farmer (go), scout (py), raider (java) Co-Authored-By: Claude Sonnet 4.6 --- bots/assassin/src/main.rs | 2 +- bots/farmer/main.go | 2 +- bots/guardian/index.php | 2 +- bots/hunter/src/main/java/com/acb/hunter/App.java | 2 +- bots/opportunist/main.go | 2 +- bots/phalanx/src/main.rs | 2 +- bots/raider/src/main/java/com/acb/raider/App.java | 2 +- bots/random/main.py | 2 +- bots/rusher/src/main.rs | 2 +- bots/scout/main.py | 2 +- bots/swarm/src/index.ts | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bots/assassin/src/main.rs b/bots/assassin/src/main.rs index b5d142a..9b0213e 100644 --- a/bots/assassin/src/main.rs +++ b/bots/assassin/src/main.rs @@ -118,7 +118,7 @@ fn verify_signature( ) -> bool { let body_hash = sha2::Sha256::digest(body.as_bytes()); let body_hash_hex = hex::encode(body_hash); - let signing_string = format!("{}.{}.{}.{}", match_id, turn, timestamp, body_hash_hex); + let signing_string = format!("{}.{}.{}", match_id, turn, body_hash_hex); let mut mac = match HmacSha256::new_from_slice(secret.as_bytes()) { Ok(m) => m, diff --git a/bots/farmer/main.go b/bots/farmer/main.go index 5254e1f..f859213 100644 --- a/bots/farmer/main.go +++ b/bots/farmer/main.go @@ -136,7 +136,7 @@ func handleHealth(w http.ResponseWriter, r *http.Request) { func verifySignature(secret, matchID, turnStr, timestamp string, body []byte, signature string) bool { bodyHash := sha256.Sum256(body) - signingString := fmt.Sprintf("%s.%s.%s.%s", matchID, turnStr, timestamp, hex.EncodeToString(bodyHash[:])) + signingString := fmt.Sprintf("%s.%s.%s", matchID, turnStr, hex.EncodeToString(bodyHash[:])) mac := hmac.New(sha256.New, []byte(secret)) mac.Write([]byte(signingString)) expected := hex.EncodeToString(mac.Sum(nil)) diff --git a/bots/guardian/index.php b/bots/guardian/index.php index fbe7c68..1a84b17 100644 --- a/bots/guardian/index.php +++ b/bots/guardian/index.php @@ -136,7 +136,7 @@ function handle_turn($conn, string $secret, GuardianStrategy $strategy, array $h */ function verify_signature(string $secret, string $matchId, string $turn, string $timestamp, string $body, string $signature): bool { $bodyHash = hash('sha256', $body); - $signingString = "$matchId.$turn.$timestamp.$bodyHash"; + $signingString = "$matchId.$turn.$bodyHash"; $expected = hash_hmac('sha256', $signingString, $secret); return hash_equals($expected, $signature); } diff --git a/bots/hunter/src/main/java/com/acb/hunter/App.java b/bots/hunter/src/main/java/com/acb/hunter/App.java index c82c805..524f5ad 100644 --- a/bots/hunter/src/main/java/com/acb/hunter/App.java +++ b/bots/hunter/src/main/java/com/acb/hunter/App.java @@ -95,7 +95,7 @@ public class App { String timestamp, String body, String signature) { try { String bodyHash = sha256Hex(body); - String signingString = matchId + "." + turn + "." + timestamp + "." + bodyHash; + String signingString = matchId + "." + turn + "." + bodyHash; Mac mac = Mac.getInstance("HmacSHA256"); SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); diff --git a/bots/opportunist/main.go b/bots/opportunist/main.go index 9e6f119..3fa2182 100644 --- a/bots/opportunist/main.go +++ b/bots/opportunist/main.go @@ -136,7 +136,7 @@ func handleHealth(w http.ResponseWriter, r *http.Request) { func verifySignature(secret, matchID, turnStr, timestamp string, body []byte, signature string) bool { bodyHash := sha256.Sum256(body) - signingString := fmt.Sprintf("%s.%s.%s.%s", matchID, turnStr, timestamp, hex.EncodeToString(bodyHash[:])) + signingString := fmt.Sprintf("%s.%s.%s", matchID, turnStr, hex.EncodeToString(bodyHash[:])) mac := hmac.New(sha256.New, []byte(secret)) mac.Write([]byte(signingString)) expected := hex.EncodeToString(mac.Sum(nil)) diff --git a/bots/phalanx/src/main.rs b/bots/phalanx/src/main.rs index dd32c91..61ea452 100644 --- a/bots/phalanx/src/main.rs +++ b/bots/phalanx/src/main.rs @@ -120,7 +120,7 @@ fn verify_signature( let body_hash = sha2::Sha256::digest(body.as_bytes()); let body_hash_hex = hex::encode(body_hash); - let signing_string = format!("{}.{}.{}.{}", match_id, turn, timestamp, body_hash_hex); + let signing_string = format!("{}.{}.{}", match_id, turn, body_hash_hex); let mut mac = match HmacSha256::new_from_slice(secret.as_bytes()) { Ok(m) => m, diff --git a/bots/raider/src/main/java/com/acb/raider/App.java b/bots/raider/src/main/java/com/acb/raider/App.java index 685cd60..1b8d513 100644 --- a/bots/raider/src/main/java/com/acb/raider/App.java +++ b/bots/raider/src/main/java/com/acb/raider/App.java @@ -86,7 +86,7 @@ public class App { String timestamp, String body, String signature) { try { String bodyHash = sha256Hex(body); - String signingString = matchId + "." + turn + "." + timestamp + "." + bodyHash; + String signingString = matchId + "." + turn + "." + bodyHash; Mac mac = Mac.getInstance("HmacSHA256"); SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); diff --git a/bots/random/main.py b/bots/random/main.py index 7325ec7..8354b8f 100644 --- a/bots/random/main.py +++ b/bots/random/main.py @@ -68,7 +68,7 @@ class RandomBotHandler(BaseHTTPRequestHandler): timestamp: str, signature: str) -> bool: """Verify HMAC signature of incoming request.""" body_hash = hashlib.sha256(body).hexdigest() - signing_string = f"{match_id}.{turn}.{timestamp}.{body_hash}" + signing_string = f"{match_id}.{turn}.{body_hash}" expected_sig = hmac.new( self.secret.encode("utf-8"), signing_string.encode("utf-8"), diff --git a/bots/rusher/src/main.rs b/bots/rusher/src/main.rs index f8927d2..06d4d44 100644 --- a/bots/rusher/src/main.rs +++ b/bots/rusher/src/main.rs @@ -133,7 +133,7 @@ fn verify_signature( let body_hash = sha2::Sha256::digest(body.as_bytes()); let body_hash_hex = hex::encode(body_hash); - let signing_string = format!("{}.{}.{}.{}", match_id, turn, timestamp, body_hash_hex); + let signing_string = format!("{}.{}.{}", match_id, turn, body_hash_hex); let mut mac = match HmacSha256::new_from_slice(secret.as_bytes()) { Ok(m) => m, diff --git a/bots/scout/main.py b/bots/scout/main.py index c9b799e..20aa102 100644 --- a/bots/scout/main.py +++ b/bots/scout/main.py @@ -330,7 +330,7 @@ class ScoutBotHandler(BaseHTTPRequestHandler): def verify_signature(self, body: bytes, match_id: str, turn: str, timestamp: str, signature: str) -> bool: body_hash = hashlib.sha256(body).hexdigest() - signing_string = f"{match_id}.{turn}.{timestamp}.{body_hash}" + signing_string = f"{match_id}.{turn}.{body_hash}" expected = hmac.new( self.secret.encode("utf-8"), signing_string.encode("utf-8"), diff --git a/bots/swarm/src/index.ts b/bots/swarm/src/index.ts index 3874bc3..7584639 100644 --- a/bots/swarm/src/index.ts +++ b/bots/swarm/src/index.ts @@ -103,7 +103,7 @@ function verifySignature( signature: string ): boolean { const bodyHash = crypto.createHash('sha256').update(body).digest('hex'); - const signingString = `${matchId}.${turn}.${timestamp}.${bodyHash}`; + const signingString = `${matchId}.${turn}.${bodyHash}`; const expected = crypto.createHmac('sha256', secret).update(signingString).digest('hex'); return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected)); }