94 lines
3.3 KiB
Go
94 lines
3.3 KiB
Go
package realtime
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// testClient builds a client with fixed credentials so signatures are
|
|
// reproducible.
|
|
func testClient(t *testing.T) *SoketiClient {
|
|
t.Helper()
|
|
c := NewSoketiClient("app-1", "test-key", "test-secret", "ws.example.com", 443, true, zap.NewNop())
|
|
if c == nil {
|
|
t.Fatal("NewSoketiClient returned nil for a fully configured client")
|
|
}
|
|
return c
|
|
}
|
|
|
|
// The expected signatures are HMAC-SHA256 vectors computed independently of
|
|
// this package. Recomputing them with the same code under test would only
|
|
// prove the code equals itself; a fixed vector catches a change to the
|
|
// string-to-sign format, which is what Soketi actually verifies against.
|
|
func TestAuthorizeChannel_MatchesKnownVector(t *testing.T) {
|
|
auth, err := testClient(t).AuthorizeChannel("1234.5678", "private-notifications.user-a")
|
|
if err != nil {
|
|
t.Fatalf("AuthorizeChannel: %v", err)
|
|
}
|
|
const want = "test-key:9c436d58a9d030f68b35d636bb3e930c471d5c11edec6745c969e4eee1c3e3df"
|
|
if auth != want {
|
|
t.Errorf("auth = %q, want %q", auth, want)
|
|
}
|
|
}
|
|
|
|
func TestAuthorizePresence_MatchesKnownVector(t *testing.T) {
|
|
auth, channelData, err := testClient(t).AuthorizePresence(
|
|
"1234.5678", "presence-conversation.c1", PresenceData{UserID: "user-a"})
|
|
if err != nil {
|
|
t.Fatalf("AuthorizePresence: %v", err)
|
|
}
|
|
if channelData != `{"user_id":"user-a"}` {
|
|
t.Errorf("channel_data = %q", channelData)
|
|
}
|
|
const want = "test-key:cf5a222b506d46383cb4edac7707ba620e4ba2bbb83f64d1cf6463b4241efd24"
|
|
if auth != want {
|
|
t.Errorf("auth = %q, want %q", auth, want)
|
|
}
|
|
}
|
|
|
|
// Presence signing folds channel_data into the signed string; routing a
|
|
// presence channel through AuthorizeChannel would produce a signature Soketi
|
|
// rejects, so it's refused outright rather than silently mis-signed.
|
|
func TestAuthorizeChannel_RejectsPresenceChannel(t *testing.T) {
|
|
if _, err := testClient(t).AuthorizeChannel("1234.5678", "presence-conversation.c1"); err == nil {
|
|
t.Fatal("expected an error for a presence channel")
|
|
}
|
|
}
|
|
|
|
func TestAuthorize_NilClientReportsNotConfigured(t *testing.T) {
|
|
var c *SoketiClient
|
|
if _, err := c.AuthorizeChannel("1234.5678", "private-x"); !errors.Is(err, ErrNotConfigured) {
|
|
t.Errorf("AuthorizeChannel err = %v, want ErrNotConfigured", err)
|
|
}
|
|
if _, _, err := c.AuthorizePresence("1234.5678", "presence-x", PresenceData{UserID: "u"}); !errors.Is(err, ErrNotConfigured) {
|
|
t.Errorf("AuthorizePresence err = %v, want ErrNotConfigured", err)
|
|
}
|
|
}
|
|
|
|
func TestAuthorize_RequiresArguments(t *testing.T) {
|
|
c := testClient(t)
|
|
if _, err := c.AuthorizeChannel("", "private-x"); err == nil {
|
|
t.Error("expected an error for an empty socket_id")
|
|
}
|
|
if _, err := c.AuthorizeChannel("1234.5678", ""); err == nil {
|
|
t.Error("expected an error for an empty channel")
|
|
}
|
|
if _, _, err := c.AuthorizePresence("1234.5678", "presence-x", PresenceData{}); err == nil {
|
|
t.Error("expected an error for presence data with no user_id")
|
|
}
|
|
}
|
|
|
|
func TestUserChannels(t *testing.T) {
|
|
if got := UserChannel("u1"); got != "private-notifications.u1" {
|
|
t.Errorf("UserChannel = %q", got)
|
|
}
|
|
// The legacy name must stay public-prefixed: it exists so already-cached
|
|
// clients keep receiving events during the migration.
|
|
if got := LegacyUserChannel("u1"); got != "notifications.u1" || strings.HasPrefix(got, "private-") {
|
|
t.Errorf("LegacyUserChannel = %q", got)
|
|
}
|
|
}
|