The codebase that powers boop.cat boop.cat
at main 65 lines 1.4 kB view raw
1// Copyright 2025 boop.cat 2// Licensed under the Apache License, Version 2.0 3// See LICENSE file for details. 4 5package lib 6 7import ( 8 "encoding/json" 9 "net/http" 10 "net/url" 11 "os" 12 "strings" 13) 14 15type TurnstileResult struct { 16 OK bool 17 Error string 18} 19 20func VerifyTurnstile(token, remoteIP string) TurnstileResult { 21 secret := os.Getenv("TURNSTILE_SECRET_KEY") 22 if secret == "" { 23 24 return TurnstileResult{OK: true} 25 } 26 27 if token == "" { 28 return TurnstileResult{OK: false, Error: "missing-token"} 29 } 30 31 data := url.Values{} 32 data.Set("secret", secret) 33 data.Set("response", token) 34 if remoteIP != "" { 35 data.Set("remoteip", remoteIP) 36 } 37 38 resp, err := http.Post( 39 "https://challenges.cloudflare.com/turnstile/v0/siteverify", 40 "application/x-www-form-urlencoded", 41 strings.NewReader(data.Encode()), 42 ) 43 if err != nil { 44 return TurnstileResult{OK: false, Error: "verification-failed"} 45 } 46 defer resp.Body.Close() 47 48 var result struct { 49 Success bool `json:"success"` 50 ErrorCodes []string `json:"error-codes"` 51 } 52 if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { 53 return TurnstileResult{OK: false, Error: "parse-failed"} 54 } 55 56 if !result.Success { 57 errCode := "captcha-failed" 58 if len(result.ErrorCodes) > 0 { 59 errCode = result.ErrorCodes[0] 60 } 61 return TurnstileResult{OK: false, Error: errCode} 62 } 63 64 return TurnstileResult{OK: true} 65}