turnstile_service.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. package repository
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "net/http"
  7. "net/url"
  8. "strings"
  9. "time"
  10. "github.com/Wei-Shaw/sub2api/internal/pkg/httpclient"
  11. "github.com/Wei-Shaw/sub2api/internal/service"
  12. )
  13. const turnstileVerifyURL = "https://challenges.cloudflare.com/turnstile/v0/siteverify"
  14. type turnstileVerifier struct {
  15. httpClient *http.Client
  16. verifyURL string
  17. }
  18. func NewTurnstileVerifier() service.TurnstileVerifier {
  19. sharedClient, err := httpclient.GetClient(httpclient.Options{
  20. Timeout: 10 * time.Second,
  21. ValidateResolvedIP: true,
  22. })
  23. if err != nil {
  24. sharedClient = &http.Client{Timeout: 10 * time.Second}
  25. }
  26. return &turnstileVerifier{
  27. httpClient: sharedClient,
  28. verifyURL: turnstileVerifyURL,
  29. }
  30. }
  31. func (v *turnstileVerifier) VerifyToken(ctx context.Context, secretKey, token, remoteIP string) (*service.TurnstileVerifyResponse, error) {
  32. formData := url.Values{}
  33. formData.Set("secret", secretKey)
  34. formData.Set("response", token)
  35. if remoteIP != "" {
  36. formData.Set("remoteip", remoteIP)
  37. }
  38. req, err := http.NewRequestWithContext(ctx, http.MethodPost, v.verifyURL, strings.NewReader(formData.Encode()))
  39. if err != nil {
  40. return nil, fmt.Errorf("create request: %w", err)
  41. }
  42. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  43. resp, err := v.httpClient.Do(req)
  44. if err != nil {
  45. return nil, fmt.Errorf("send request: %w", err)
  46. }
  47. defer func() { _ = resp.Body.Close() }()
  48. var result service.TurnstileVerifyResponse
  49. if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
  50. return nil, fmt.Errorf("decode response: %w", err)
  51. }
  52. return &result, nil
  53. }