proofofwork_test.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package proofofwork
  2. import (
  3. "errors"
  4. "log/slog"
  5. "net/http"
  6. "net/http/httptest"
  7. "testing"
  8. "github.com/TecharoHQ/anubis/lib/challenge"
  9. "github.com/TecharoHQ/anubis/lib/config"
  10. "github.com/TecharoHQ/anubis/lib/policy"
  11. )
  12. func mkRequest(t *testing.T, values map[string]string) *http.Request {
  13. t.Helper()
  14. req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
  15. if err != nil {
  16. t.Fatal(err)
  17. }
  18. q := req.URL.Query()
  19. for k, v := range values {
  20. q.Set(k, v)
  21. }
  22. req.URL.RawQuery = q.Encode()
  23. return req
  24. }
  25. func TestBasic(t *testing.T) {
  26. i := &Impl{Algorithm: "fast"}
  27. bot := &policy.Bot{
  28. Challenge: &config.ChallengeRules{
  29. Algorithm: "fast",
  30. Difficulty: 0,
  31. },
  32. }
  33. const challengeStr = "hunter"
  34. const response = "2652bdba8fb4d2ab39ef28d8534d7694c557a4ae146c1e9237bd8d950280500e"
  35. for _, cs := range []struct {
  36. name string
  37. req *http.Request
  38. err error
  39. challengeStr string
  40. }{
  41. {
  42. name: "allgood",
  43. req: mkRequest(t, map[string]string{
  44. "nonce": "0",
  45. "elapsedTime": "69",
  46. "response": response,
  47. }),
  48. err: nil,
  49. challengeStr: challengeStr,
  50. },
  51. {
  52. name: "no-params",
  53. req: mkRequest(t, map[string]string{}),
  54. err: challenge.ErrMissingField,
  55. challengeStr: challengeStr,
  56. },
  57. {
  58. name: "missing-nonce",
  59. req: mkRequest(t, map[string]string{
  60. "elapsedTime": "69",
  61. "response": response,
  62. }),
  63. err: challenge.ErrMissingField,
  64. challengeStr: challengeStr,
  65. },
  66. {
  67. name: "missing-elapsedTime",
  68. req: mkRequest(t, map[string]string{
  69. "nonce": "0",
  70. "response": response,
  71. }),
  72. err: challenge.ErrMissingField,
  73. challengeStr: challengeStr,
  74. },
  75. {
  76. name: "missing-response",
  77. req: mkRequest(t, map[string]string{
  78. "nonce": "0",
  79. "elapsedTime": "69",
  80. }),
  81. err: challenge.ErrMissingField,
  82. challengeStr: challengeStr,
  83. },
  84. {
  85. name: "wrong-nonce-format",
  86. req: mkRequest(t, map[string]string{
  87. "nonce": "taco",
  88. "elapsedTime": "69",
  89. "response": response,
  90. }),
  91. err: challenge.ErrInvalidFormat,
  92. challengeStr: challengeStr,
  93. },
  94. {
  95. name: "wrong-elapsedTime-format",
  96. req: mkRequest(t, map[string]string{
  97. "nonce": "0",
  98. "elapsedTime": "taco",
  99. "response": response,
  100. }),
  101. err: challenge.ErrInvalidFormat,
  102. challengeStr: challengeStr,
  103. },
  104. {
  105. name: "invalid-response",
  106. req: mkRequest(t, map[string]string{
  107. "nonce": "0",
  108. "elapsedTime": "69",
  109. "response": response,
  110. }),
  111. err: challenge.ErrFailed,
  112. challengeStr: "Tacos are tasty",
  113. },
  114. } {
  115. t.Run(cs.name, func(t *testing.T) {
  116. lg := slog.With()
  117. i.Setup(http.NewServeMux())
  118. inp := &challenge.IssueInput{
  119. Rule: bot,
  120. Challenge: &challenge.Challenge{
  121. RandomData: cs.challengeStr,
  122. },
  123. }
  124. if _, err := i.Issue(httptest.NewRecorder(), cs.req, lg, inp); err != nil {
  125. t.Errorf("can't issue challenge: %v", err)
  126. }
  127. if err := i.Validate(cs.req, lg, &challenge.ValidateInput{
  128. Rule: bot,
  129. Challenge: &challenge.Challenge{
  130. RandomData: cs.challengeStr,
  131. },
  132. }); !errors.Is(err, cs.err) {
  133. t.Errorf("got wrong error from Validate, got %v but wanted %v", err, cs.err)
  134. }
  135. })
  136. }
  137. }