package transcode_test import ( "context" "encoding/json" "net/http" "testing" flatbuffers "github.com/google/flatbuffers/go" "scrabble/gateway/internal/connector" "scrabble/gateway/internal/transcode" fb "scrabble/pkg/fbs/scrabblefb" ) // fakeValidator stands in for the connector's ValidateInitData RPC. type fakeValidator struct { user connector.User err error } func (f fakeValidator) ValidateInitData(context.Context, string) (connector.User, error) { return f.user, f.err } func (f fakeValidator) ValidateLoginWidget(context.Context, string) (connector.User, error) { return f.user, f.err } func telegramLoginPayload(initData string) []byte { b := flatbuffers.NewBuilder(0) off := b.CreateString(initData) fb.TelegramLoginRequestStart(b) fb.TelegramLoginRequestAddInitData(b, off) b.Finish(fb.TelegramLoginRequestEnd(b)) return b.FinishedBytes() } func TestTelegramAuthForwardsSeedFields(t *testing.T) { var gotBody map[string]string backend, cleanup := fakeBackend(t, func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/api/v1/internal/sessions/telegram" { t.Errorf("unexpected path %q", r.URL.Path) } _ = json.NewDecoder(r.Body).Decode(&gotBody) _, _ = w.Write([]byte(`{"token":"tok-tg","user_id":"u-tg","is_guest":false,"display_name":"Иван"}`)) }) defer cleanup() v := fakeValidator{user: connector.User{ExternalID: "42", Username: "neo", FirstName: "Иван", LanguageCode: "ru", ServiceLanguage: "ru", SupportedLanguages: []string{"ru"}}} reg := transcode.NewRegistry(backend, v) op, ok := reg.Lookup(transcode.MsgAuthTelegram) if !ok { t.Fatal("auth.telegram not registered") } payload, err := op.Handler(context.Background(), transcode.Request{Payload: telegramLoginPayload("init")}) if err != nil { t.Fatalf("handler: %v", err) } sess := fb.GetRootAsSession(payload, 0) if string(sess.Token()) != "tok-tg" || string(sess.UserId()) != "u-tg" { t.Fatalf("session decoded wrong: token=%q user=%q", sess.Token(), sess.UserId()) } // The validating bot's supported languages ride the Session so the UI gates the // New Game variant choice (here: ru -> Russian + Эрудит only). if got := sessionLanguages(sess); len(got) != 1 || got[0] != "ru" { t.Errorf("session supported_languages = %v, want [ru]", got) } // The validated launch fields are forwarded so the backend can seed a new account; // service_language is recorded to route the account's later out-of-app push. if gotBody["external_id"] != "42" || gotBody["language_code"] != "ru" || gotBody["first_name"] != "Иван" || gotBody["service_language"] != "ru" { t.Errorf("forwarded body = %+v, want external_id=42 language_code=ru first_name=Иван service_language=ru", gotBody) } } // sessionLanguages reads the supported_languages vector off a decoded Session. func sessionLanguages(s *fb.Session) []string { out := make([]string, s.SupportedLanguagesLength()) for i := range out { out[i] = string(s.SupportedLanguages(i)) } return out } // TestGuestAuthSeedsDefaultLanguages confirms a non-platform (guest) session carries // the gateway's default supported-languages set, so the web client is ungated. func TestGuestAuthSeedsDefaultLanguages(t *testing.T) { backend, cleanup := fakeBackend(t, func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte(`{"token":"tok-g","user_id":"u-g","is_guest":true,"display_name":"Guest"}`)) }) defer cleanup() reg := transcode.NewRegistry(backend, nil, "en", "ru") op, _ := reg.Lookup(transcode.MsgAuthGuest) payload, err := op.Handler(context.Background(), transcode.Request{}) if err != nil { t.Fatalf("handler: %v", err) } if got := sessionLanguages(fb.GetRootAsSession(payload, 0)); len(got) != 2 || got[0] != "en" || got[1] != "ru" { t.Errorf("guest session supported_languages = %v, want [en ru]", got) } } func TestTelegramAuthInvalidInitData(t *testing.T) { backend, cleanup := fakeBackend(t, func(http.ResponseWriter, *http.Request) { t.Error("backend must not be called when initData is invalid") }) defer cleanup() reg := transcode.NewRegistry(backend, fakeValidator{err: connector.ErrInvalidInitData}) op, _ := reg.Lookup(transcode.MsgAuthTelegram) _, err := op.Handler(context.Background(), transcode.Request{Payload: telegramLoginPayload("bad")}) if code, ok := transcode.DomainCode(err); !ok || code != "invalid_init_data" { t.Errorf("DomainCode = (%q, %v), want (invalid_init_data, true)", code, ok) } } // TestTelegramAuthDisabledWithoutConnector confirms a nil validator leaves // auth.telegram unregistered. func TestTelegramAuthDisabledWithoutConnector(t *testing.T) { backend, cleanup := fakeBackend(t, func(http.ResponseWriter, *http.Request) {}) defer cleanup() reg := transcode.NewRegistry(backend, nil) if _, ok := reg.Lookup(transcode.MsgAuthTelegram); ok { t.Error("auth.telegram should be unregistered without a connector") } }