forked from dustinkirkland/pollen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pollen_test.go
149 lines (125 loc) · 4.06 KB
/
pollen_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package main
import (
"bufio"
"encoding/hex"
"fmt"
"io"
"net/http"
"net/http/httptest"
"net/url"
"testing"
)
type Suite struct {
*httptest.Server
t *testing.T
}
type testHandler struct{}
func (h testHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
handler(w, req)
}
func NewSuite(t *testing.T) *Suite {
return &Suite{httptest.NewServer(testHandler{}), t}
}
func (s *Suite) Assert(v bool, args ...interface{}) {
if !v {
s.t.Error(args...)
}
}
func (s *Suite) TearDown() {
s.Server.Close()
}
// MustScan scans a single token. There must be a token available and it must
// scan successfully or an error is returned.
func MustScan(s *bufio.Scanner) error {
if !s.Scan() {
return fmt.Errorf("Missing expected text")
}
return s.Err()
}
// ParseResp parses the pollen response to the challenge & response
// in the output, as well as any error that occurred with reading or
// validating it.
func ReadResp(r io.Reader) (challenge, response string, err error) {
scanner := bufio.NewScanner(r)
if err = MustScan(scanner); err != nil {
return
}
challenge = scanner.Text()
if err = MustScan(scanner); err != nil {
return
}
response = scanner.Text()
return
}
// CheckHex returns an error if the given string is not valid hex.
func CheckHex(s string) error {
_, err := hex.DecodeString(s)
return err
}
// TestNoChallenge tests the pollen service when no challenge is given
// in the request.
func TestNoChallenge(t *testing.T) {
s := NewSuite(t)
defer s.TearDown()
res, err := http.Get(s.URL)
s.Assert(err == nil, "http client error:", err)
defer res.Body.Close()
_, _, err = ReadResp(res.Body)
s.Assert(err != nil, "response error:", err)
}
func (s *Suite) SanityCheck(chal, seed string) {
s.Assert(chal != seed, "challenge response and seed were the same!")
s.Assert(len(chal) == len(seed), "challenge response and seed length not equal")
s.Assert(CheckHex(chal) == nil, "invalid hex:", chal)
s.Assert(CheckHex(seed) == nil, "invalid hex:", seed)
}
// PorkChopSha512 is $(echo -n "pork chop sandwiches" | sha512sum)
const PorkChopSha512 = "a75751ccd71ba00d7b6c3b74cc0c02373f3f26c14dfe47afd580b0d87bf9fd8cebc73ea29b1cae15586e0d118922342ea7e94d0cb73a0f918d7d8c7ec065e873"
// TestPorkChopSandwiches tests the pollen service when given
// pork chop sandwiches.
func TestPorkChopSandwiches(t *testing.T) {
s := NewSuite(t)
defer s.TearDown()
res, err := http.Get(s.URL + "?challenge=pork+chop+sandwiches")
s.Assert(err == nil, "http client error:", err)
defer res.Body.Close()
chal, resp, err := ReadResp(res.Body)
s.Assert(err == nil, "response error:", err)
s.Assert(chal == PorkChopSha512, "expected:", PorkChopSha512, "got:", chal)
s.SanityCheck(chal, resp)
}
// TestPorkChopPost tests the pollen service when the
// pork chop sandwiches are POSTed.
func TestPostChopSandwiches(t *testing.T) {
s := NewSuite(t)
defer s.TearDown()
res, err := http.PostForm(s.URL, url.Values{"challenge": []string{"pork chop sandwiches"}})
s.Assert(err == nil, "http client error:", err)
defer res.Body.Close()
chal, resp, err := ReadResp(res.Body)
s.Assert(err == nil, "response error:", err)
s.Assert(chal == PorkChopSha512, "expected:", PorkChopSha512, "got:", chal)
s.SanityCheck(chal, resp)
}
const UniqueChainRounds = 100
// TestUniqueChaining tests the uniqueness of seeds and challenge responses
// when fed into successive requests as challenges.
func TestUniqueChaining(t *testing.T) {
s := NewSuite(t)
defer s.TearDown()
challengeResps := make(map[string]bool)
seeds := make(map[string]bool)
challenge := "the bassomatic '76"
for i := 0; i < UniqueChainRounds; i++ {
res, err := http.Get(fmt.Sprintf("%s/?challenge=%s", s.URL, url.QueryEscape(challenge)))
s.Assert(err == nil, "http client error:", err)
challengeResp, seed, err := ReadResp(res.Body)
err = res.Body.Close()
s.Assert(err == nil, "response error:", err)
challengeResps[challengeResp] = true
seeds[seed] = true
challenge = seed
}
s.Assert(len(challengeResps) == UniqueChainRounds, "non-unique challenge response")
s.Assert(len(seeds) == UniqueChainRounds, "non-unique seed response")
}