88 lines
2.3 KiB
Go
88 lines
2.3 KiB
Go
package auth
|
||
|
||
import (
|
||
"bytes"
|
||
"crypto/ed25519"
|
||
"errors"
|
||
"io"
|
||
"net/http"
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
type ed25519PublicKey = ed25519.PublicKey
|
||
|
||
func TestSign_SetsHeaders(t *testing.T) {
|
||
priv, _ := GenerateKey()
|
||
s := &Signer{Key: priv}
|
||
r, _ := http.NewRequest(http.MethodGet, "https://ingress.example:8443/api/v1/stream", nil)
|
||
if err := s.Sign(r); err != nil {
|
||
t.Fatalf("Sign: %v", err)
|
||
}
|
||
if got := r.Header.Get(HeaderKey); got != EncodePublicKey(priv.Public().(ed25519.PublicKey)) {
|
||
t.Errorf("%s = %q", HeaderKey, got)
|
||
}
|
||
for _, h := range []string{HeaderTimestamp, HeaderNonce, HeaderSignature} {
|
||
if r.Header.Get(h) == "" {
|
||
t.Errorf("Header %s fehlt", h)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestSign_FreshNonceEachTime(t *testing.T) {
|
||
priv, _ := GenerateKey()
|
||
s := &Signer{Key: priv}
|
||
seen := map[string]bool{}
|
||
for range 100 {
|
||
r, _ := http.NewRequest(http.MethodGet, "https://h/x", nil)
|
||
if err := s.Sign(r); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
n := r.Header.Get(HeaderNonce)
|
||
if seen[n] {
|
||
t.Fatalf("Nonce %q doppelt", n)
|
||
}
|
||
seen[n] = true
|
||
}
|
||
}
|
||
|
||
func TestSign_PreservesBody(t *testing.T) {
|
||
priv, _ := GenerateKey()
|
||
r, _ := http.NewRequest(http.MethodPost, "https://h/api/v1/state", strings.NewReader(`{"a":1}`))
|
||
if err := (&Signer{Key: priv}).Sign(r); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
body, _ := io.ReadAll(r.Body)
|
||
if string(body) != `{"a":1}` {
|
||
t.Errorf("Body nach Sign = %q", body)
|
||
}
|
||
if r.GetBody == nil {
|
||
t.Fatal("GetBody fehlt – Redirects/Retries könnten den Body nicht erneut senden")
|
||
}
|
||
again, _ := r.GetBody()
|
||
body, _ = io.ReadAll(again)
|
||
if !bytes.Equal(body, []byte(`{"a":1}`)) {
|
||
t.Errorf("GetBody liefert %q", body)
|
||
}
|
||
}
|
||
|
||
// Kein Signieren für Klartext-Verbindungen: Signatur und Body dürfen nie
|
||
// unverschlüsselt über die Leitung gehen.
|
||
func TestSign_RefusesPlainHTTP(t *testing.T) {
|
||
priv, _ := GenerateKey()
|
||
r, _ := http.NewRequest(http.MethodGet, "http://ingress.example:8080/api/v1/stream", nil)
|
||
if err := (&Signer{Key: priv}).Sign(r); !errors.Is(err, ErrInsecureTransport) {
|
||
t.Errorf("erwartet ErrInsecureTransport, bekommen %v", err)
|
||
}
|
||
if r.Header.Get(HeaderSignature) != "" {
|
||
t.Error("Signatur trotz Klartext gesetzt")
|
||
}
|
||
}
|
||
|
||
func TestSign_NoKey(t *testing.T) {
|
||
r, _ := http.NewRequest(http.MethodGet, "https://h/x", nil)
|
||
if err := (&Signer{}).Sign(r); !errors.Is(err, ErrInvalidKey) {
|
||
t.Errorf("erwartet ErrInvalidKey, bekommen %v", err)
|
||
}
|
||
}
|