package files import ( "strings" "testing" "time" ) func TestSignVerifyRoundTrip(t *testing.T) { secret := []byte("0123456789abcdef0123456789abcdef") now := time.Now() token := SignToken(secret, "01JFILE", now.Add(time.Hour)) if !VerifyToken(secret, "01JFILE", token, now) { t.Fatal("fresh token must verify") } if !VerifyToken(secret, "01JFILE", token, now.Add(59*time.Minute)) { t.Fatal("token must verify just before expiry") } } func TestVerifyRejections(t *testing.T) { secret := []byte("0123456789abcdef0123456789abcdef") now := time.Now() token := SignToken(secret, "01JFILE", now.Add(time.Hour)) tests := []struct { name string fileID string token string at time.Time }{ {"expired", "01JFILE", token, now.Add(2 * time.Hour)}, {"wrong file", "01JOTHER", token, now}, {"garbage token", "01JFILE", "not-a-token", now}, {"empty token", "01JFILE", "", now}, {"truncated token", "01JFILE", token[:len(token)-10], now}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if VerifyToken(secret, tt.fileID, tt.token, tt.at) { t.Error("must not verify") } }) } if VerifyToken([]byte("another-secret-another-secret-xx"), "01JFILE", token, now) { t.Error("different secret must not verify") } } func TestSignedURLShape(t *testing.T) { secret := []byte("0123456789abcdef0123456789abcdef") u := SignedURL("http://localhost:8787", secret, "01JFILE", time.Now().Add(time.Hour)) if !strings.HasPrefix(u, "http://localhost:8787/files/01JFILE?st=") { t.Fatalf("unexpected URL %q", u) } token := u[strings.Index(u, "?st=")+4:] if !VerifyToken(secret, "01JFILE", token, time.Now()) { t.Fatal("token embedded in URL must verify") } }