122 lines
2.9 KiB
Go
122 lines
2.9 KiB
Go
package remotecontrol
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestNewPairingTokenIsHex256Bit(t *testing.T) {
|
|
s := NewTokenStore()
|
|
value, err := s.NewPairing(time.Minute)
|
|
if err != nil {
|
|
t.Fatalf("NewPairing: %v", err)
|
|
}
|
|
// 32 bytes -> 64 hex chars.
|
|
if len(value) != tokenBytes*2 {
|
|
t.Fatalf("token length = %d, want %d", len(value), tokenBytes*2)
|
|
}
|
|
for _, c := range value {
|
|
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) {
|
|
t.Fatalf("token has non-hex char %q", c)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPairingIsSingleUse(t *testing.T) {
|
|
s := NewTokenStore()
|
|
value, err := s.NewPairing(time.Minute)
|
|
if err != nil {
|
|
t.Fatalf("NewPairing: %v", err)
|
|
}
|
|
if !s.ConsumePairing(value) {
|
|
t.Fatal("first ConsumePairing = false, want true")
|
|
}
|
|
if s.ConsumePairing(value) {
|
|
t.Fatal("second ConsumePairing = true, want false (single-use)")
|
|
}
|
|
}
|
|
|
|
func TestConsumePairingUnknownToken(t *testing.T) {
|
|
s := NewTokenStore()
|
|
if s.ConsumePairing("deadbeef") {
|
|
t.Fatal("ConsumePairing on unknown token = true, want false")
|
|
}
|
|
}
|
|
|
|
func TestPairingExpires(t *testing.T) {
|
|
now := time.Unix(1_700_000_000, 0)
|
|
s := NewTokenStore()
|
|
s.now = func() time.Time { return now }
|
|
value, err := s.NewPairing(10 * time.Minute)
|
|
if err != nil {
|
|
t.Fatalf("NewPairing: %v", err)
|
|
}
|
|
// Advance clock just past the TTL.
|
|
now = now.Add(10*time.Minute + time.Second)
|
|
if s.ConsumePairing(value) {
|
|
t.Fatal("ConsumePairing after expiry = true, want false")
|
|
}
|
|
}
|
|
|
|
func TestPairingValidJustBeforeExpiry(t *testing.T) {
|
|
now := time.Unix(1_700_000_000, 0)
|
|
s := NewTokenStore()
|
|
s.now = func() time.Time { return now }
|
|
value, err := s.NewPairing(10 * time.Minute)
|
|
if err != nil {
|
|
t.Fatalf("NewPairing: %v", err)
|
|
}
|
|
now = now.Add(10*time.Minute - time.Second)
|
|
if !s.ConsumePairing(value) {
|
|
t.Fatal("ConsumePairing just before expiry = false, want true")
|
|
}
|
|
}
|
|
|
|
func TestIssueAndValidateSession(t *testing.T) {
|
|
s := NewTokenStore()
|
|
cred, err := s.IssueSession()
|
|
if err != nil {
|
|
t.Fatalf("IssueSession: %v", err)
|
|
}
|
|
if len(cred) != tokenBytes*2 {
|
|
t.Fatalf("cred length = %d, want %d", len(cred), tokenBytes*2)
|
|
}
|
|
if !s.ValidateSession(cred) {
|
|
t.Fatal("ValidateSession(issued) = false, want true")
|
|
}
|
|
if s.ValidateSession("") {
|
|
t.Fatal("ValidateSession(\"\") = true, want false")
|
|
}
|
|
if s.ValidateSession("not-a-real-cred") {
|
|
t.Fatal("ValidateSession(bogus) = true, want false")
|
|
}
|
|
}
|
|
|
|
func TestClearWipesState(t *testing.T) {
|
|
s := NewTokenStore()
|
|
value, _ := s.NewPairing(time.Minute)
|
|
cred, _ := s.IssueSession()
|
|
s.Clear()
|
|
if s.ConsumePairing(value) {
|
|
t.Fatal("pairing token survived Clear")
|
|
}
|
|
if s.ValidateSession(cred) {
|
|
t.Fatal("session credential survived Clear")
|
|
}
|
|
}
|
|
|
|
func TestTokensAreUnique(t *testing.T) {
|
|
s := NewTokenStore()
|
|
seen := make(map[string]struct{})
|
|
for range 100 {
|
|
v, err := s.NewPairing(time.Minute)
|
|
if err != nil {
|
|
t.Fatalf("NewPairing: %v", err)
|
|
}
|
|
if _, dup := seen[v]; dup {
|
|
t.Fatalf("duplicate token generated: %s", v)
|
|
}
|
|
seen[v] = struct{}{}
|
|
}
|
|
}
|