HTTP Hashcash implemented in Go.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

331 lines
5.0 KiB

package hashcash
import (
"crypto/rand"
"encoding/base64"
"errors"
"testing"
"time"
)
var never = time.Date(3006, time.January, 1, 15, 4, 5, 0, time.UTC)
func TestNew(t *testing.T) {
h1 := New(Hashcash{})
h2, err := Parse(h1.String())
if nil != err {
t.Fatal(err)
return
}
if h1.Tag != h2.Tag {
t.Fatal("wrong tag version")
return
}
if h1.Difficulty != h2.Difficulty {
t.Fatal("wrong difficulty")
return
}
if h1.ExpiresAt != h2.ExpiresAt {
t.Fatal("wrong expiresat")
return
}
if h1.Subject != h2.Subject {
t.Fatal("wrong subject")
return
}
if h1.Nonce != h2.Nonce {
t.Fatal("wrong nonce")
return
}
if h1.Alg != h2.Alg {
t.Fatal("wrong algorithm")
return
}
if h1.Solution != h2.Solution {
t.Fatal("wrong solution")
return
}
}
func TestExplicit(t *testing.T) {
nonce := make([]byte, 16)
_, _ = rand.Read(nonce)
h0 := Hashcash{
Tag: "H",
Difficulty: 1000,
ExpiresAt: time.Now().UTC().Truncate(time.Second),
Subject: "example.com",
Nonce: base64.RawURLEncoding.EncodeToString(nonce),
Alg: "FOOBAR",
Solution: "incorrect",
}
h1 := New(h0)
h2, err := Parse(h1.String())
if nil != err {
t.Fatal(err)
return
}
h3 := New(*h2)
if h0.Tag != h3.Tag {
t.Fatal("wrong tag version")
return
}
if h0.Difficulty != h3.Difficulty {
t.Fatal("wrong difficulty")
return
}
if h0.ExpiresAt != h3.ExpiresAt {
t.Fatal("wrong expiresat")
return
}
if h0.Subject != h3.Subject {
t.Fatal("wrong subject")
return
}
if h0.Nonce != h3.Nonce {
t.Fatal("wrong nonce")
return
}
if h0.Alg != h3.Alg {
t.Fatal("wrong algorithm")
return
}
if h0.Solution != h3.Solution {
t.Fatal("wrong solution")
return
}
}
func TestExpired(t *testing.T) {
h := New(Hashcash{
Alg: "SHA-256",
Difficulty: 10,
ExpiresAt: time.Now().Add(-5 * time.Second),
})
err := h.Verify(h.Subject)
if nil == err {
t.Error("verified expired token")
return
}
if err != ErrExpired {
t.Error("expired token error is not ErrExpired")
return
}
}
func TestNoExpiry(t *testing.T) {
h := New(Hashcash{})
h.ExpiresAt = time.Time{}
if err := h.Solve(20); nil != err {
t.Error(err)
return
}
if err := h.Verify(h.Subject); nil != err {
t.Error(err)
return
}
}
func TestSolve0(t *testing.T) {
h := New(Hashcash{
ExpiresAt: never,
Nonce: "DeadBeef",
})
h.Difficulty = 0
if err := h.Solve(1); nil != err {
t.Error(err)
return
}
if err := h.Verify(h.Subject); nil != err {
t.Error(err)
return
}
}
func TestSolve1(t *testing.T) {
h := New(Hashcash{
Difficulty: 1,
ExpiresAt: never,
Nonce: "DeadBeef",
})
if err := h.Solve(2); nil != err {
t.Error(err)
return
}
if err := h.Verify(h.Subject); nil != err {
t.Error(err)
return
}
}
func TestSolve2(t *testing.T) {
h := New(Hashcash{
Difficulty: 2,
ExpiresAt: never,
Nonce: "DeadBeef",
})
if err := h.Solve(3); nil != err {
t.Error(err)
return
}
if err := h.Verify(h.Subject); nil != err {
t.Error(err)
return
}
}
func TestSolve7(t *testing.T) {
h := New(Hashcash{
Difficulty: 7,
ExpiresAt: never,
Nonce: "DeadBeef",
})
if err := h.Solve(8); nil != err {
t.Error(err)
return
}
if err := h.Verify(h.Subject); nil != err {
t.Error(err)
return
}
}
func TestSolve8(t *testing.T) {
h := New(Hashcash{
Difficulty: 8,
ExpiresAt: never,
Nonce: "DeadBeef",
})
if err := h.Solve(9); nil != err {
t.Error(err)
return
}
if err := h.Verify(h.Subject); nil != err {
t.Error(err)
return
}
}
func TestSolve9(t *testing.T) {
h := New(Hashcash{
Difficulty: 9,
ExpiresAt: never,
Nonce: "DeadBeef",
})
if err := h.Solve(10); nil != err {
t.Error(err)
return
}
if err := h.Verify(h.Subject); nil != err {
t.Error(err)
return
}
}
func TestSolve15(t *testing.T) {
h := New(Hashcash{
Difficulty: 15,
ExpiresAt: never,
Nonce: "DeadBeef",
})
if err := h.Solve(16); nil != err {
t.Error(err)
return
}
if err := h.Verify(h.Subject); nil != err {
t.Error(err)
return
}
}
func TestSolve16(t *testing.T) {
h := New(Hashcash{
Difficulty: 16,
ExpiresAt: never,
Nonce: "DeadBeef",
})
if err := h.Solve(17); nil != err {
t.Error(err)
return
}
if err := h.Verify(h.Subject); nil != err {
t.Error(err)
return
}
}
func TestSolve17(t *testing.T) {
h := New(Hashcash{
Difficulty: 17,
ExpiresAt: never,
Nonce: "DeadBeef",
})
if err := h.Solve(18); nil != err {
t.Error(err)
return
}
if err := h.Verify(h.Subject); nil != err {
t.Error(err)
return
}
if "H:17:32693036645:*:DeadBeef:SHA-256:R7sIAA" != h.String() {
t.Errorf("unexpected hashcash string: %s, has the implementation changed?", h.String())
}
}
func TestTooHard(t *testing.T) {
h := New(Hashcash{
Alg: "SHA-256",
Difficulty: 24,
ExpiresAt: never,
Nonce: "DeadBeef",
})
err := h.Solve(20)
if nil == err {
t.Error(errors.New("the challenge is too hard, should've quite"))
return
}
if ErrInvalidDifficulty != err {
t.Error(errors.New("incorrect error"))
return
}
}