a73x

internal/server/hosttoken/hosttoken_generation_test.go

Ref:   Size: 1.7 KiB   History

package hosttoken

import (
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// TestMintVerifyRoundTrip pins the credential contract:
// host_id.gen.issued_unix.hmac, HMAC over the three dotted fields.
func TestMintVerifyRoundTrip(t *testing.T) {
	secret := []byte("s3cret")
	issued := time.Unix(1_750_000_000, 0)
	cred := Mint(secret, "abc123", 3, issued)

	claims, ok := Verify(secret, cred)
	require.True(t, ok)
	assert.Equal(t, "abc123", claims.HostID)
	assert.Equal(t, int64(3), claims.Generation)
	assert.True(t, claims.IssuedAt.Equal(issued))
}

// TestVerifyRejectsTampering: flipping any field invalidates the HMAC, and a
// wrong secret never verifies.
func TestVerifyRejectsTampering(t *testing.T) {
	secret := []byte("s3cret")
	cred := Mint(secret, "abc123", 1, time.Unix(1_750_000_000, 0))
	parts := strings.Split(cred, ".")
	require.Len(t, parts, 4)

	for i, repl := range []string{"otherhost", "9", "1750000001"} {
		mut := make([]string, 4)
		copy(mut, parts)
		mut[i] = repl
		_, ok := Verify(secret, strings.Join(mut, "."))
		assert.False(t, ok, "tampered field %d must fail", i)
	}
	_, ok := Verify([]byte("wrong"), cred)
	assert.False(t, ok)
}

// TestVerifyRejectsMalformed: anything that is not exactly the four signed
// fields is rejected.
func TestVerifyRejectsMalformed(t *testing.T) {
	secret := []byte("s3cret")
	for _, cred := range []string{
		"", "abc123", "a.b.c", // too few parts
		"abc123.deadbeef",       // two parts
		"a.b.c.d.e",             // too many parts
		"abc123.x.170.deadbeef", // non-numeric generation
		"abc123.1.x.deadbeef",   // non-numeric issued_unix
	} {
		_, ok := Verify(secret, cred)
		assert.False(t, ok, "must reject %q", cred)
	}
}