93 lines
2.2 KiB
Go
93 lines
2.2 KiB
Go
|
|
package token
|
||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/base64"
|
||
|
|
"encoding/json"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// buildTestJWT builds a JWT string with the given payload (no real signature).
|
||
|
|
func buildTestJWT(claims map[string]interface{}) string {
|
||
|
|
header := base64.RawURLEncoding.EncodeToString([]byte(`{"alg":"RS256","typ":"JWT"}`))
|
||
|
|
payload, _ := json.Marshal(claims)
|
||
|
|
payloadEnc := base64.RawURLEncoding.EncodeToString(payload)
|
||
|
|
sig := base64.RawURLEncoding.EncodeToString([]byte("fakesig"))
|
||
|
|
return header + "." + payloadEnc + "." + sig
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestDecodePayload(t *testing.T) {
|
||
|
|
claims := map[string]interface{}{
|
||
|
|
"iss": "https://id.example.com/realms/test",
|
||
|
|
"sub": "user123",
|
||
|
|
"exp": float64(1700000000),
|
||
|
|
"aud": "nix-cache",
|
||
|
|
}
|
||
|
|
|
||
|
|
jwt := buildTestJWT(claims)
|
||
|
|
|
||
|
|
decoded, err := DecodePayload(jwt)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if decoded["iss"] != "https://id.example.com/realms/test" {
|
||
|
|
t.Errorf("iss = %v, want %v", decoded["iss"], "https://id.example.com/realms/test")
|
||
|
|
}
|
||
|
|
if decoded["sub"] != "user123" {
|
||
|
|
t.Errorf("sub = %v, want %v", decoded["sub"], "user123")
|
||
|
|
}
|
||
|
|
if decoded["aud"] != "nix-cache" {
|
||
|
|
t.Errorf("aud = %v, want %v", decoded["aud"], "nix-cache")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestExpiryInfo(t *testing.T) {
|
||
|
|
futureExp := time.Now().Add(1 * time.Hour).Unix()
|
||
|
|
claims := map[string]interface{}{
|
||
|
|
"exp": float64(futureExp),
|
||
|
|
}
|
||
|
|
|
||
|
|
exp, remaining := ExpiryInfo(claims)
|
||
|
|
|
||
|
|
if exp.Unix() != futureExp {
|
||
|
|
t.Errorf("exp = %v, want %v", exp.Unix(), futureExp)
|
||
|
|
}
|
||
|
|
if remaining < 59*time.Minute || remaining > 61*time.Minute {
|
||
|
|
t.Errorf("remaining = %v, expected ~1 hour", remaining)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestExpiryInfoPast(t *testing.T) {
|
||
|
|
pastExp := time.Now().Add(-1 * time.Hour).Unix()
|
||
|
|
claims := map[string]interface{}{
|
||
|
|
"exp": float64(pastExp),
|
||
|
|
}
|
||
|
|
|
||
|
|
_, remaining := ExpiryInfo(claims)
|
||
|
|
|
||
|
|
if remaining >= 0 {
|
||
|
|
t.Errorf("remaining = %v, expected negative (expired)", remaining)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestDecodePayloadMalformed(t *testing.T) {
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
token string
|
||
|
|
}{
|
||
|
|
{"no dots", "nodots"},
|
||
|
|
{"one dot", "one.dot"},
|
||
|
|
{"empty payload", "header..sig"},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tt := range tests {
|
||
|
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
|
_, err := DecodePayload(tt.token)
|
||
|
|
if err == nil {
|
||
|
|
t.Error("expected error, got nil")
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|