package rpc import ( "bytes" "context" "encoding/binary" "errors" "fmt" "testing" "github.com/iamxvbaba/td/bin" "github.com/iamxvbaba/td/clock" "github.com/iamxvbaba/td/tg" "github.com/iamxvbaba/td/tgerr" "go.uber.org/zap/zaptest" appfiles "telesrv/internal/app/files" "telesrv/internal/domain" "telesrv/internal/postresponse" ) func TestLayerAdmissionAndroidPrivateOverlayUsesExactProfile(t *testing.T) { r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) // DrKLO's private messages.forwardMessages constructor has the canonical // body layout for this empty flags/vectors fixture, but is not an official // Layer 227 method id. var body bin.Buffer body.PutID(0x41d41ade) body.PutInt(0) body.PutID(0x7f3b18ea) // inputPeerEmpty body.PutVectorHeader(0) body.PutVectorHeader(0) body.PutID(0x7f3b18ea) // inputPeerEmpty admitted, err := r.AdmitLayer(tg.LayerProfile227, &body, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } if body.Len() != 0 { t.Fatalf("private request left %d bytes", body.Len()) } call := admitted.Call() if call.Profile() != tg.LayerProfile227 || call.Method() != tg.LayerSemanticMethodMessagesForwardMessages { t.Fatalf("private admission = profile:%d method:%#x", call.Profile(), call.Method()) } if want, ok := tg.LayerWireID(tg.LayerProfile227, call.Method()); !ok || call.WireID() != want { t.Fatalf("private admission wire id = %#x, want %#x (ok=%v)", call.WireID(), want, ok) } } func TestLayerAdmissionOfficialProfileOwnsOverlappingAndroidID(t *testing.T) { r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) request := &tg.ContactsSearchRequest{Q: "exact", Limit: 20} body := encodeExactLayerRPC(t, tg.LayerProfile225, request) admitted, err := r.AdmitLayer(tg.LayerProfile225, &body, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } if body.Len() != 0 || admitted.Call().Method() != tg.LayerSemanticMethodContactsSearch { t.Fatalf("official overlap = remaining:%d method:%#x", body.Len(), admitted.Call().Method()) } } func TestLayerAdmissionAndroidOverlayFailureDoesNotConsumeInput(t *testing.T) { r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) bounded := bin.Buffer{Buf: androidPrivateForwardMessagesWire()} boundedOriginal := bounded.Copy() if _, err := r.AdmitLayer(tg.LayerProfile227, &bounded, tg.LayerDecodeLimits{MaxWireBytes: len(boundedOriginal) - 1}); err == nil { t.Fatal("oversized Android-private request was admitted") } if !bytes.Equal(bounded.Raw(), boundedOriginal) { t.Fatal("wire-limited Android-private request consumed or mutated caller input") } malformed := bin.Buffer{} malformed.PutID(0x41d41ade) original := malformed.Copy() if _, err := r.AdmitLayer(tg.LayerProfile227, &malformed, tg.LayerDecodeLimits{}); err == nil { t.Fatal("malformed Android-private request was admitted") } if string(malformed.Raw()) != string(original) { t.Fatal("failed Android-private admission consumed or mutated caller input") } unknown := bin.Buffer{} unknown.PutID(0xdeadbeef) original = unknown.Copy() if _, err := r.AdmitLayer(tg.LayerProfile227, &unknown, tg.LayerDecodeLimits{}); !errors.Is(err, tg.ErrLayerUnknownRPCMethod) { t.Fatalf("official unknown error = %v", err) } if string(unknown.Raw()) != string(original) { t.Fatal("unknown official request consumed or mutated caller input") } } func androidPrivateForwardMessagesWire() []byte { var body bin.Buffer body.PutID(0x41d41ade) body.PutInt(0) body.PutID(0x7f3b18ea) // inputPeerEmpty body.PutVectorHeader(0) body.PutVectorHeader(0) body.PutID(0x7f3b18ea) // inputPeerEmpty return body.Copy() } func replaceTerminalRPC(t *testing.T, encoded *bin.Buffer, terminal []byte) { t.Helper() var placeholder bin.Buffer if err := (&tg.HelpGetConfigRequest{}).Encode(&placeholder); err != nil { t.Fatal(err) } if !bytes.HasSuffix(encoded.Raw(), placeholder.Raw()) { t.Fatalf("wrapper does not end in placeholder RPC: %x", encoded.Raw()) } encoded.Buf = append(encoded.Buf[:encoded.Len()-placeholder.Len()], terminal...) } func TestLayerAdmissionAndroidPrivateInnermostAcrossWrappers(t *testing.T) { r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) private := androidPrivateForwardMessagesWire() var withoutUpdates bin.Buffer withoutUpdates.PutID(tg.InvokeWithoutUpdatesRequestTypeID) withoutUpdates.Put(private) var afterMsg bin.Buffer afterMsg.PutID(tg.InvokeAfterMsgRequestTypeID) afterMsg.PutLong(11) afterMsg.Put(private) var afterMsgs bin.Buffer afterMsgs.PutID(tg.InvokeAfterMsgsRequestTypeID) afterMsgs.PutVectorHeader(2) afterMsgs.PutLong(11) afterMsgs.PutLong(12) afterMsgs.Put(private) init := &tg.InitConnectionRequest{ APIID: 6, DeviceModel: "Android", SystemVersion: "test", AppVersion: "private-layer", SystemLangCode: "en", LangPack: "android", LangCode: "en", Query: &tg.HelpGetConfigRequest{}, } var initWire bin.Buffer if err := init.Encode(&initWire); err != nil { t.Fatal(err) } replaceTerminalRPC(t, &initWire, private) var unprofiledInit bin.Buffer unprofiledInit.PutID(tg.InvokeWithLayerRequestTypeID) unprofiledInit.PutInt(int(tg.LayerProfile227)) unprofiledInit.Put(initWire.Raw()) var unprofiledBare bin.Buffer unprofiledBare.PutID(tg.InvokeWithLayerRequestTypeID) unprofiledBare.PutInt(int(tg.LayerProfile227)) unprofiledBare.Put(private) tests := []struct { name string body []byte unprofiled bool wrappers int }{ {"naked", private, false, 0}, {"invokeWithoutUpdates", withoutUpdates.Copy(), false, 1}, {"invokeAfterMsg", afterMsg.Copy(), false, 1}, {"invokeAfterMsgs", afterMsgs.Copy(), false, 1}, {"invokeWithLayer", unprofiledBare.Copy(), true, 1}, {"invokeWithLayer_initConnection", unprofiledInit.Copy(), true, 2}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { body := bin.Buffer{Buf: append([]byte(nil), tc.body...)} var ( admitted tg.LayerRequest err error ) if tc.unprofiled { admitted, err = r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) } else { admitted, err = r.AdmitLayer(tg.LayerProfile227, &body, tg.LayerDecodeLimits{}) } if err != nil { t.Fatal(err) } if body.Len() != 0 || admitted.WrapperCount() != tc.wrappers || admitted.Call().Method() != tg.LayerSemanticMethodMessagesForwardMessages { t.Fatalf("admission = remaining:%d wrappers:%d method:%#x", body.Len(), admitted.WrapperCount(), admitted.Call().Method()) } }) } } func TestLayerAdmissionAndroidPrivateFieldPolicyBeforeTypedMaterialization(t *testing.T) { r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) request := &tg.MessagesCreateChatRequest{ Users: repeatLayerPreflightValue[tg.InputUserClass](201, &tg.InputUserEmpty{}), Title: "private-field-policy", } var body bin.Buffer if err := request.Encode(&body); err != nil { t.Fatal(err) } // DrKLO's private createChat constructor is body-identical to canonical. binary.LittleEndian.PutUint32(body.Buf[:4], 0x0034a818) original := body.Copy() if _, err := r.AdmitLayer(tg.LayerProfile227, &body, tg.LayerDecodeLimits{MaxVectorElements: 8 << 10}); !tgerr.Is(err, "LIMIT_INVALID") { t.Fatalf("private createChat admission err = %v, want LIMIT_INVALID", err) } if !bytes.Equal(body.Raw(), original) { t.Fatal("field-rejected private createChat consumed or mutated input") } } func TestLayerDispatchExactProfilesShareOneHandler(t *testing.T) { for _, profile := range []tg.LayerProfile{tg.LayerProfile225, tg.LayerProfile227} { t.Run(fmt.Sprintf("layer_%d", profile), func(t *testing.T) { r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) request := &tg.InvokeWithLayerRequest{ Layer: int(profile), Query: &tg.InitConnectionRequest{ APIID: 123, DeviceModel: "Desktop", SystemVersion: "Windows", AppVersion: "test", SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", Query: &tg.HelpGetConfigRequest{}, }, } var body bin.Buffer if err := request.Encode(&body); err != nil { t.Fatal(err) } admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } if body.Len() != 0 || admitted.Call().Profile() != profile { t.Fatalf("admission = profile:%d remaining:%d", admitted.Call().Profile(), body.Len()) } result, method, err := r.DispatchAdmitted(context.Background(), [8]byte{1}, 10, 0, 0, admitted) if err != nil { t.Fatal(err) } if method != "help.getConfig" || result.Prepared().Call().Identity() != admitted.Call().Identity() { t.Fatalf("result = method:%q call:%#v", method, result.Prepared().Call()) } var exact bin.Buffer if err := result.Encode(&exact); err != nil { t.Fatal(err) } decoded, err := tg.DecodeLayer(profile, tg.LayerConstructorConfigType(), &exact) if err != nil { t.Fatal(err) } if exact.Len() != 0 || decoded.ThisDC != 2 { t.Fatalf("decoded config = dc:%d remaining:%d", decoded.ThisDC, exact.Len()) } frozen, err := result.Freeze() if err != nil { t.Fatal(err) } prepared, err := admitted.Call().PrepareFrozenResult(frozen) if err != nil { t.Fatal(err) } var replay bin.Buffer if err := prepared.Encode(admitted.Call(), &replay); err != nil { t.Fatal(err) } if string(replay.Raw()) != string(tgBufferBytes(t, result)) { t.Fatalf("prepared replay differs from direct result") } }) } } func TestLayerDispatchUnprofiledInvariantDoesNotPublishRepresentativeLayer(t *testing.T) { rawAuthKeyID := [8]byte{1} const sessionID = int64(10) auth := &captureAuthService{ authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ rawAuthKeyID: {Layer: 225, DeviceModel: "stale-device"}, }, } sessions := &layerCaptureSessions{} r := New( Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{Auth: auth, Sessions: sessions}, zaptest.NewLogger(t), clock.System, ) request := &tg.AuthBindTempAuthKeyRequest{ PermAuthKeyID: 1, Nonce: 2, ExpiresAt: 3, EncryptedMessage: []byte("bind"), } var body bin.Buffer if err := request.Encode(&body); err != nil { t.Fatal(err) } admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } if _, ok := admitted.ProfileEvidence(); ok { t.Fatal("unprofiled invariant request exposed its canonical codec representative as client evidence") } if !admitted.Call().WireInvariant() { t.Fatal("auth.bindTempAuthKey did not carry generated wire-invariant proof") } result, method, err := r.DispatchAdmitted(WithLayer(context.Background(), 226), rawAuthKeyID, sessionID, 0, 0, admitted) if err != nil { t.Fatal(err) } if method != "auth.bindTempAuthKey" || result == nil || !result.WireInvariant() { t.Fatalf("invariant dispatch = method:%q result:%T invariant:%v", method, result, result != nil && result.WireInvariant()) } if auth.bindTempCalls != 1 || auth.bindTempLayer != 0 { t.Fatalf("unprofiled bind handler context = calls:%d layer:%d, want one call with unknown layer", auth.bindTempCalls, auth.bindTempLayer) } if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { t.Fatalf("stale auth metadata reached exact layer binder: %+v", calls) } if layer, ok := r.NegotiatedSessionLayer(rawAuthKeyID, sessionID); ok || layer != 0 { t.Fatalf("unprofiled invariant published session layer = (%d,%v)", layer, ok) } var profiledBody bin.Buffer if err := (&tg.InvokeWithLayerRequest{Layer: 227, Query: request}).Encode(&profiledBody); err != nil { t.Fatal(err) } profiled, err := r.AdmitUnprofiled(&profiledBody, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } if profile, ok := profiled.ProfileEvidence(); !ok || profile != tg.LayerProfile227 { t.Fatalf("profiled bind evidence = (%d,%v), want layer 227", profile, ok) } freezeAndPublishLayer(t, r, rawAuthKeyID, sessionID, 100, 1, 227) if _, _, err := r.DispatchAdmitted(context.Background(), rawAuthKeyID, sessionID, 100, 1, profiled); err != nil { t.Fatal(err) } if auth.bindTempCalls != 2 || auth.bindTempLayer != 227 { t.Fatalf("profiled bind handler context = calls:%d layer:%d, want layer 227", auth.bindTempCalls, auth.bindTempLayer) } if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { t.Fatalf("Router duplicated edge exact-profile binder calls = %+v", calls) } if layer, ok := r.NegotiatedSessionLayer(rawAuthKeyID, sessionID); !ok || layer != 227 { t.Fatalf("authoritative wrapper session layer = (%d,%v), want (227,true)", layer, ok) } } func TestLayerDispatchInheritedDefaultIsEffectiveWithoutBecomingExplicitEvidence(t *testing.T) { rawAuthKeyID := [8]byte{0x73} const sessionID = int64(73) auth := &captureAuthService{} r := New( Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System, ) request := &tg.AuthBindTempAuthKeyRequest{PermAuthKeyID: businessAuthKeyInt64(rawAuthKeyID)} var body bin.Buffer if err := request.Encode(&body); err != nil { t.Fatal(err) } admitted, err := r.AdmitDefaultLayer(tg.LayerProfile225, &body, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } if profile, ok := admitted.EffectiveProfile(); !ok || profile != tg.LayerProfile225 { t.Fatalf("effective profile = (%d,%v), want (225,true)", profile, ok) } if profile, ok := admitted.ProfileEvidence(); ok || profile != tg.LayerProfile(0) { t.Fatalf("explicit evidence = (%d,%v), want (0,false)", profile, ok) } result, _, err := r.DispatchAdmitted(WithLayer(context.Background(), 227), rawAuthKeyID, sessionID, 0, 0, admitted) if err != nil || result == nil { t.Fatalf("dispatch inherited default = (%T,%v)", result, err) } if auth.bindTempLayer != 225 { t.Fatalf("handler layer = %d, want immutable effective 225", auth.bindTempLayer) } if layer, ok := r.NegotiatedSessionLayer(rawAuthKeyID, sessionID); ok || layer != 0 { t.Fatalf("inherited default became explicit registry state = (%d,%v)", layer, ok) } } func TestLayerDispatchProfiledBareIgnoresStaleMetadataLayer(t *testing.T) { rawAuthKeyID := [8]byte{2, 2, 0} const sessionID = int64(225) auth := &captureAuthService{ authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ rawAuthKeyID: {Layer: 227, DeviceModel: "newer-device-metadata"}, }, } sessions := &layerCaptureSessions{} r := New( Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{Auth: auth, Sessions: sessions}, zaptest.NewLogger(t), clock.System, ) request := &tg.AuthBindTempAuthKeyRequest{ PermAuthKeyID: 1, Nonce: 2, ExpiresAt: 3, EncryptedMessage: []byte("bind"), } body := encodeExactLayerRPC(t, tg.LayerProfile225, request) admitted, err := r.AdmitLayer(tg.LayerProfile225, &body, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } if _, _, err := r.DispatchAdmitted(WithLayer(context.Background(), 226), rawAuthKeyID, sessionID, 0, 0, admitted); err != nil { t.Fatal(err) } if auth.bindTempCalls != 1 || auth.bindTempLayer != 225 { t.Fatalf("profiled bare handler context = calls:%d layer:%d, want one call at 225", auth.bindTempCalls, auth.bindTempLayer) } if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { t.Fatalf("profiled bare request rebound stale metadata before exact evidence: %+v", calls) } } func TestLayerDispatchUnprofiledInvariantWithholdsUpdatesReadinessUntilEvidence(t *testing.T) { const ( userID = int64(1000000227) sessionID = int64(220227) ) rawAuthKeyID := [8]byte{0x22, 0x02, 0x27} auth := &captureAuthService{ userID: userID, authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ rawAuthKeyID: {Layer: 225, DeviceModel: "stale-device"}, }, } sessions := &layerCaptureSessions{} r := New( Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{Auth: auth, Sessions: sessions}, zaptest.NewLogger(t), clock.System, ) // updates.getState stages readiness inside its handler in addition to the // common bare-RPC path, so this locks both no-evidence gates. request := &tg.UpdatesGetStateRequest{} var body bin.Buffer if err := request.Encode(&body); err != nil { t.Fatal(err) } admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } if _, evidence := admitted.ProfileEvidence(); evidence || !admitted.Call().WireInvariant() { t.Fatalf("unprofiled getState evidence/invariant = %v/%v", evidence, admitted.Call().WireInvariant()) } dispatchCtx := postresponse.WithCallbacks(context.Background()) result, method, err := r.DispatchAdmitted(dispatchCtx, rawAuthKeyID, sessionID, 10, 1, admitted) if err != nil || result == nil || method != "updates.getState" { t.Fatalf("unprofiled getState dispatch = method:%q result:%T err:%v", method, result, err) } postresponse.Run(dispatchCtx) if got := sessions.snapshot(); got.receives || got.receivesCalls != 0 { t.Fatalf("unprofiled invariant activated updates after delivery: %+v", got) } if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { t.Fatalf("unprofiled invariant bound stale layer: %+v", calls) } restore, err := r.PrepareAdmittedReplay(context.Background(), rawAuthKeyID, sessionID, 10, 1, admitted) if err != nil || restore == nil { t.Fatalf("prepare unprofiled invariant replay = callback:%v err:%v", restore != nil, err) } if err := restore(); err != nil { t.Fatal(err) } if got := sessions.snapshot(); got.receives || got.receivesCalls != 0 { t.Fatalf("unprofiled invariant replay activated updates: %+v", got) } var wrapped bin.Buffer if err := (&tg.InvokeWithLayerRequest{Layer: 227, Query: request}).Encode(&wrapped); err != nil { t.Fatal(err) } profiled, err := r.AdmitUnprofiled(&wrapped, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } freezeAndPublishLayer(t, r, rawAuthKeyID, sessionID, 20, 2, 227) profiledCtx := postresponse.WithCallbacks(context.Background()) if _, _, err := r.DispatchAdmitted(profiledCtx, rawAuthKeyID, sessionID, 20, 2, profiled); err != nil { t.Fatal(err) } postresponse.Run(profiledCtx) if got := sessions.snapshot(); !got.receives || got.receivesCalls != 1 { t.Fatalf("authoritative profile did not activate updates: %+v", got) } if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { t.Fatalf("Router duplicated edge authoritative-profile bind: %+v", calls) } } func TestLayerAdmissionPreflightRunsBeforeLargeVectorDecode(t *testing.T) { r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) users := make([]tg.InputUserClass, 101) for index := range users { users[index] = &tg.InputUserEmpty{} } request := &tg.InvokeWithLayerRequest{ Layer: int(tg.LayerProfile225), Query: &tg.UsersGetUsersRequest{ID: users}, } var body bin.Buffer if err := request.Encode(&body); err != nil { t.Fatal(err) } if _, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}); !tgerr.Is(err, "INPUT_REQUEST_TOO_LONG") { t.Fatalf("admission err = %v, want INPUT_REQUEST_TOO_LONG", err) } } func TestLayerAdmissionFieldPoliciesCoverEveryRoutableProfile(t *testing.T) { type vectorCase struct { name string method tg.LayerSemanticID max int errorCode string request func(int) bin.Object } cases := []vectorCase{ {"users.getUsers", tg.LayerSemanticMethodUsersGetUsers, 100, "INPUT_REQUEST_TOO_LONG", func(n int) bin.Object { return &tg.UsersGetUsersRequest{ID: repeatLayerPreflightValue[tg.InputUserClass](n, &tg.InputUserEmpty{})} }}, {"users.getRequirementsToContact", tg.LayerSemanticMethodUsersGetRequirementsToContact, maxRequirementsToContactUsers, "LIMIT_INVALID", func(n int) bin.Object { return &tg.UsersGetRequirementsToContactRequest{ID: repeatLayerPreflightValue[tg.InputUserClass](n, &tg.InputUserEmpty{})} }}, {"contacts.importContacts", tg.LayerSemanticMethodContactsImportContacts, maxContactImportBatch, "LIMIT_INVALID", func(n int) bin.Object { return &tg.ContactsImportContactsRequest{Contacts: make([]tg.InputPhoneContact, n)} }}, {"contacts.deleteContacts", tg.LayerSemanticMethodContactsDeleteContacts, maxContactDeleteBatch, "LIMIT_INVALID", func(n int) bin.Object { return &tg.ContactsDeleteContactsRequest{ID: repeatLayerPreflightValue[tg.InputUserClass](n, &tg.InputUserEmpty{})} }}, {"contacts.editCloseFriends", tg.LayerSemanticMethodContactsEditCloseFriends, maxCloseFriendsCount, "LIMIT_INVALID", func(n int) bin.Object { return &tg.ContactsEditCloseFriendsRequest{ID: make([]int64, n)} }}, {"contacts.setBlocked", tg.LayerSemanticMethodContactsSetBlocked, maxContactSetBlocked, "LIMIT_INVALID", func(n int) bin.Object { return &tg.ContactsSetBlockedRequest{ID: repeatLayerPreflightValue[tg.InputPeerClass](n, &tg.InputPeerEmpty{})} }}, {"messages.getMessages", tg.LayerSemanticMethodMessagesGetMessages, maxGetMessagesIDs, "LIMIT_INVALID", func(n int) bin.Object { return &tg.MessagesGetMessagesRequest{ID: repeatLayerPreflightValue[tg.InputMessageClass](n, &tg.InputMessageID{})} }}, {"messages.getChats", tg.LayerSemanticMethodMessagesGetChats, maxGetMessagesIDs, "LIMIT_INVALID", func(n int) bin.Object { return &tg.MessagesGetChatsRequest{ID: make([]int64, n)} }}, {"messages.getPeerDialogs", tg.LayerSemanticMethodMessagesGetPeerDialogs, maxDialogInputPeers, "LIMIT_INVALID", func(n int) bin.Object { return &tg.MessagesGetPeerDialogsRequest{Peers: repeatLayerPreflightValue[tg.InputDialogPeerClass](n, &tg.InputDialogPeer{Peer: &tg.InputPeerEmpty{}})} }}, {"messages.readMessageContents", tg.LayerSemanticMethodMessagesReadMessageContents, maxGetMessagesIDs, "LIMIT_INVALID", func(n int) bin.Object { return &tg.MessagesReadMessageContentsRequest{ID: make([]int, n)} }}, {"messages.getCustomEmojiDocuments", tg.LayerSemanticMethodMessagesGetCustomEmojiDocuments, maxEmojiDocuments, "LIMIT_INVALID", func(n int) bin.Object { return &tg.MessagesGetCustomEmojiDocumentsRequest{DocumentID: make([]int64, n)} }}, {"messages.deleteMessages", tg.LayerSemanticMethodMessagesDeleteMessages, domain.MaxDeleteMessageIDs, "LIMIT_INVALID", func(n int) bin.Object { return &tg.MessagesDeleteMessagesRequest{ID: make([]int, n)} }}, {"messages.createChat", tg.LayerSemanticMethodMessagesCreateChat, 200, "LIMIT_INVALID", func(n int) bin.Object { return &tg.MessagesCreateChatRequest{Users: repeatLayerPreflightValue[tg.InputUserClass](n, &tg.InputUserEmpty{}), Title: "layer-policy"} }}, {"channels.getChannels", tg.LayerSemanticMethodChannelsGetChannels, maxGetMessagesIDs, "LIMIT_INVALID", func(n int) bin.Object { return &tg.ChannelsGetChannelsRequest{ID: repeatLayerPreflightValue[tg.InputChannelClass](n, &tg.InputChannelEmpty{})} }}, } r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) limits := tg.LayerDecodeLimits{MaxVectorElements: 8 << 10} for profile := tg.LayerProfile225; profile <= tg.LayerProfile227; profile++ { for _, tc := range cases { tc := tc if _, available := tg.LayerWireID(profile, tc.method); !available { continue } t.Run(fmt.Sprintf("layer_%d/%s/at_cap", profile, tc.name), func(t *testing.T) { body := encodeExactLayerRPC(t, profile, tc.request(tc.max)) if _, err := r.AdmitLayer(profile, &body, limits); err != nil { t.Fatal(err) } if body.Len() != 0 { t.Fatalf("admitted request left %d bytes", body.Len()) } }) t.Run(fmt.Sprintf("layer_%d/%s/over_cap", profile, tc.name), func(t *testing.T) { body := encodeExactLayerRPC(t, profile, tc.request(tc.max+1)) original := body.Copy() if _, err := r.AdmitLayer(profile, &body, limits); !tgerr.Is(err, tc.errorCode) { t.Fatalf("admission err = %v, want %s", err, tc.errorCode) } if string(body.Raw()) != string(original) { t.Fatal("rejected request consumed or mutated caller input") } }) } } } func TestLayerAdmissionUploadFieldsCoverEveryProfile(t *testing.T) { r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) for profile := tg.LayerProfile225; profile <= tg.LayerProfile227; profile++ { t.Run(fmt.Sprintf("layer_%d/saveFilePart", profile), func(t *testing.T) { atCap := encodeExactLayerRPC(t, profile, &tg.UploadSaveFilePartRequest{Bytes: make([]byte, appfiles.MaxUploadPartBytes)}) if _, err := r.AdmitLayer(profile, &atCap, tg.LayerDecodeLimits{}); err != nil { t.Fatal(err) } over := encodeExactLayerRPC(t, profile, &tg.UploadSaveFilePartRequest{Bytes: make([]byte, appfiles.MaxUploadPartBytes+1)}) original := over.Copy() if _, err := r.AdmitLayer(profile, &over, tg.LayerDecodeLimits{}); !tgerr.Is(err, "FILE_PART_TOO_BIG") { t.Fatalf("oversized part err = %v", err) } if string(over.Raw()) != string(original) { t.Fatal("oversized part consumed input") } }) t.Run(fmt.Sprintf("layer_%d/saveBigFilePart", profile), func(t *testing.T) { atCap := encodeExactLayerRPC(t, profile, &tg.UploadSaveBigFilePartRequest{FileTotalParts: appfiles.MaxUploadParts, Bytes: make([]byte, appfiles.MaxUploadPartBytes)}) if _, err := r.AdmitLayer(profile, &atCap, tg.LayerDecodeLimits{}); err != nil { t.Fatal(err) } for _, totalParts := range []int{0, -1, appfiles.MaxUploadParts + 1} { body := encodeExactLayerRPC(t, profile, &tg.UploadSaveBigFilePartRequest{FileTotalParts: totalParts}) original := body.Copy() if _, err := r.AdmitLayer(profile, &body, tg.LayerDecodeLimits{}); !tgerr.Is(err, "FILE_PART_INVALID") { t.Fatalf("total parts %d err = %v", totalParts, err) } if string(body.Raw()) != string(original) { t.Fatalf("invalid total parts %d consumed input", totalParts) } } over := encodeExactLayerRPC(t, profile, &tg.UploadSaveBigFilePartRequest{FileTotalParts: 1, Bytes: make([]byte, appfiles.MaxUploadPartBytes+1)}) if _, err := r.AdmitLayer(profile, &over, tg.LayerDecodeLimits{}); !tgerr.Is(err, "FILE_PART_TOO_BIG") { t.Fatalf("oversized big part err = %v", err) } }) } } func repeatLayerPreflightValue[T any](n int, value T) []T { result := make([]T, n) for index := range result { result[index] = value } return result } func encodeExactLayerRPC(t *testing.T, profile tg.LayerProfile, request bin.Object) bin.Buffer { t.Helper() outbound, err := tg.PrepareLayerOutboundCall(profile, request) if err != nil { t.Fatal(err) } var body bin.Buffer if err := outbound.Encode(&body); err != nil { t.Fatal(err) } return body } func TestLayerDispatchRejectsUnsupportedWrapperBeforeHandler(t *testing.T) { r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) request := &tg.InvokeWithLayerRequest{ Layer: int(tg.LayerProfile227), Query: &tg.InvokeWithTakeoutRequest{ TakeoutID: 1, Query: &tg.HelpGetConfigRequest{}, }, } var body bin.Buffer if err := request.Encode(&body); err != nil { t.Fatal(err) } admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } if _, method, err := r.DispatchAdmitted(context.Background(), [8]byte{1}, 10, 0, 0, admitted); method != "help.getConfig" || !tgerr.Is(err, "NOT_IMPLEMENTED") { t.Fatalf("dispatch = method:%q err:%v", method, err) } } func TestPrepareAdmittedReplayRestoresReadinessOnlyAfterDelivery(t *testing.T) { const ( userID = int64(1000000901) sessionID = int64(901) ) authKeyID := [8]byte{9, 0, 1} sessions := &captureSessions{userID: userID, userResolved: true} r := New( Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{Sessions: sessions}, zaptest.NewLogger(t), clock.System, ) request := &tg.InvokeWithLayerRequest{ Layer: int(tg.LayerProfile225), Query: &tg.InitConnectionRequest{ APIID: 123, DeviceModel: "Desktop", SystemVersion: "Windows", AppVersion: "test", SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", Query: &tg.HelpGetConfigRequest{}, }, } var body bin.Buffer if err := request.Encode(&body); err != nil { t.Fatal(err) } admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } freezeAndPublishLayer(t, r, authKeyID, sessionID, 9010, 1, 225) after, err := r.PrepareAdmittedReplay(context.Background(), authKeyID, sessionID, 9010, 1, admitted) if err != nil { t.Fatal(err) } if after == nil { t.Fatal("successful naked replay has no delivery callback") } if got := sessions.snapshot(); got.receives || got.receivesCalls != 0 { t.Fatalf("replay marked ready before physical delivery: %+v", got) } if layer, ok := r.NegotiatedSessionLayer(authKeyID, sessionID); !ok || layer != 225 { t.Fatalf("admission-time protocol evidence = (%d,%v), want (225,true)", layer, ok) } if err := after(); err != nil { t.Fatalf("restore delivered replay: %v", err) } if got := sessions.snapshot(); !got.receives || got.receivesCalls != 1 { t.Fatalf("delivered replay readiness = %+v", got) } if layer, ok := r.NegotiatedSessionLayer(authKeyID, sessionID); !ok || layer != 225 { t.Fatalf("delivered replay changed protocol evidence = (%d,%v), want (225,true)", layer, ok) } if err := after(); err != nil { t.Fatalf("idempotent replay restore: %v", err) } if got := sessions.snapshot(); got.receivesCalls != 1 { t.Fatalf("replay delivery callback was not idempotent: %+v", got) } } func TestRequestBoundOnlyLayerRPCDoesNotPublishMetadataOrReadiness(t *testing.T) { for _, mode := range []string{"dispatch", "replay"} { t.Run(mode, func(t *testing.T) { authKeyID := [8]byte{9, 0, 11, byte(len(mode))} const sessionID = int64(911) sessions := &captureSessions{} r := New( Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{Sessions: sessions}, zaptest.NewLogger(t), clock.System, ) request := &tg.InvokeWithLayerRequest{ Layer: int(tg.LayerProfile225), Query: &tg.InitConnectionRequest{ APIID: 123, DeviceModel: "Stale Desktop", SystemVersion: "Windows", AppVersion: "stale", SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", Query: &tg.HelpGetConfigRequest{}, }, } var body bin.Buffer if err := request.Encode(&body); err != nil { t.Fatal(err) } admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } ctx := r.WithLayerRPCProfileEvidenceFresh(context.Background(), false) switch mode { case "dispatch": if result, method, err := r.DispatchAdmitted(ctx, authKeyID, sessionID, 9011, 1, admitted); err != nil || result == nil || method != "help.getConfig" { t.Fatalf("request-bound dispatch = (%T,%q,%v)", result, method, err) } case "replay": after, err := r.PrepareAdmittedReplay(ctx, authKeyID, sessionID, 9011, 1, admitted) if err != nil { t.Fatal(err) } if err := after(); err != nil { t.Fatal(err) } } if got := sessions.snapshot(); got.receives || got.receivesCalls != 0 { t.Fatalf("request-bound %s published readiness: %+v", mode, got) } r.clientInfoMu.RLock() sessionInfo := r.clientInfo[clientInfoSessionKey{rawAuthKeyID: authKeyID, sessionID: sessionID}] authInfo := r.authInfo[authKeyID] r.clientInfoMu.RUnlock() if sessionInfo.hasClientInfo || authInfo.hasClientInfo { t.Fatalf("request-bound %s published init metadata: session=%+v auth=%+v", mode, sessionInfo, authInfo) } }) } } func TestPrepareAdmittedReplayDoesNotRollBackNewerExplicitLayerOrClientInfo(t *testing.T) { authKeyID := [8]byte{9, 0, 2} const sessionID = int64(902) auth := &captureAuthService{authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo)} sessions := &layerCaptureSessions{} r := New( Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{Auth: auth, Sessions: sessions}, zaptest.NewLogger(t), clock.System, ) oldRequest := &tg.InvokeWithLayerRequest{ Layer: int(tg.LayerProfile225), Query: &tg.InitConnectionRequest{ APIID: 123, DeviceModel: "Old Desktop", SystemVersion: "Windows 10", AppVersion: "old", SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", Query: &tg.HelpGetConfigRequest{}, }, } var body bin.Buffer if err := oldRequest.Encode(&body); err != nil { t.Fatal(err) } admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } freezeAndPublishLayer(t, r, authKeyID, sessionID, 10, 1, 225) after, err := r.PrepareAdmittedReplay(context.Background(), authKeyID, sessionID, 10, 1, admitted) if err != nil { t.Fatal(err) } freezeAndPublishLayer(t, r, authKeyID, sessionID, 20, 2, 227) newerCtx := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), authKeyID), sessionID), authKeyID) r.rememberClientInfoAt(newerCtx, ClientInfo{ APIID: 123, DeviceModel: "New Desktop", SystemVersion: "Windows 11", AppVersion: "new", Type: ClientTypeTDesktop, }, 2) if err := after(); err != nil { t.Fatalf("restore old replay after correction: %v", err) } if layer, ok := r.NegotiatedSessionLayer(authKeyID, sessionID); !ok || layer != 227 { t.Fatalf("exact session rolled back = (%d,%v), want (227,true)", layer, ok) } if got := auth.authKeyClientInfos[authKeyID].Layer; got != 227 { t.Fatalf("durable default rolled back = %d, want 227", got) } if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { t.Fatalf("Router replay touched edge-owned exact binder: %+v", calls) } info, ok, _ := r.clientSessionInfo(newerCtx) if !ok || !info.hasClientInfo || info.clientInfo.DeviceModel != "New Desktop" || info.clientInfo.AppVersion != "new" { t.Fatalf("newer client info was overwritten by replay: %+v ok=%v", info, ok) } } func TestDelayedExplicitDispatchCannotRollBackAdmissionTimeLayerOrInitMetadata(t *testing.T) { authKeyID := [8]byte{9, 0, 3} const sessionID = int64(903) auth := &captureAuthService{authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo)} sessions := &layerCaptureSessions{} r := New( Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{Auth: auth, Sessions: sessions}, zaptest.NewLogger(t), clock.System, ) admit := func(layer int, device, version string) tg.LayerRequest { t.Helper() request := &tg.InvokeWithLayerRequest{ Layer: layer, Query: &tg.InitConnectionRequest{ APIID: 123, DeviceModel: device, SystemVersion: "Windows", AppVersion: version, SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", Query: &tg.HelpGetConfigRequest{}, }, } var body bin.Buffer if err := request.Encode(&body); err != nil { t.Fatal(err) } admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } return admitted } old := admit(225, "Old Desktop", "old") newer := admit(227, "New Desktop", "new") freezeAndPublishLayer(t, r, authKeyID, sessionID, 10, 1, 225) freezeAndPublishLayer(t, r, authKeyID, sessionID, 20, 2, 227) if _, _, err := r.DispatchAdmitted(context.Background(), authKeyID, sessionID, 20, 2, newer); err != nil { t.Fatal(err) } if _, _, err := r.DispatchAdmitted(context.Background(), authKeyID, sessionID, 10, 1, old); err != nil { t.Fatal(err) } if layer, msgID, ok := r.NegotiatedSessionLayerEvidence(authKeyID, sessionID); !ok || layer != 227 || msgID != 20 { t.Fatalf("exact evidence after delayed dispatch = (%d,%d,%v), want (227,20,true)", layer, msgID, ok) } if got := auth.authKeyClientInfos[authKeyID]; got.Layer != 227 || got.DeviceModel != "New Desktop" || got.AppVersion != "new" { t.Fatalf("durable protocol metadata rolled back: %+v", got) } if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { t.Fatalf("handler dispatch duplicated/rolled back edge profile binding: %+v", calls) } } func TestSameLayerNakedInitConnectionUsesMessageIDWatermark(t *testing.T) { authKeyID := [8]byte{9, 0, 4} const sessionID = int64(904) auth := &captureAuthService{authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ authKeyID: {Layer: 227}, }} r := New( Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System, ) admit := func(device, version string) tg.LayerRequest { t.Helper() request := &tg.InitConnectionRequest{ APIID: 123, DeviceModel: device, SystemVersion: "Windows", AppVersion: version, SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", Query: &tg.HelpGetConfigRequest{}, } var body bin.Buffer if err := request.Encode(&body); err != nil { t.Fatal(err) } admitted, err := r.AdmitDefaultLayer(tg.LayerProfile227, &body, tg.LayerDecodeLimits{}) if err != nil { t.Fatal(err) } return admitted } newer := admit("New Desktop", "new") old := admit("Old Desktop", "old") if _, _, err := r.DispatchAdmitted(context.Background(), authKeyID, sessionID, 20, 2, newer); err != nil { t.Fatal(err) } if _, _, err := r.DispatchAdmitted(context.Background(), authKeyID, sessionID, 10, 1, old); err != nil { t.Fatal(err) } if got := auth.authKeyClientInfos[authKeyID]; got.DeviceModel != "New Desktop" || got.AppVersion != "new" || got.Layer != 227 { t.Fatalf("same-layer naked init metadata rolled back: %+v", got) } ctx := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), authKeyID), sessionID), authKeyID) info, ok, _ := r.clientSessionInfo(ctx) if !ok || info.wrapperMsgID != 20 || !info.hasClientInfo || info.clientInfo.DeviceModel != "New Desktop" { t.Fatalf("session wrapper watermark/client info = %+v ok=%v", info, ok) } } func TestCrossSessionInitMetadataUsesAdmissionSequence(t *testing.T) { rawOld := [8]byte{9, 0, 5, 1} rawNew := [8]byte{9, 0, 5, 2} permAuthKeyID := [8]byte{9, 0, 5, 3} auth := &captureAuthService{ resolvedAuthKeyID: permAuthKeyID, hasResolved: true, authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo), } r := New(Config{DC: 2}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System) newCtx := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), rawNew), 2), permAuthKeyID) oldCtx := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), rawOld), 1), permAuthKeyID) r.rememberClientInfoAt(newCtx, ClientInfo{APIID: 123, DeviceModel: "New Desktop", AppVersion: "new", Type: ClientTypeTDesktop}, 2) r.rememberClientInfoAt(oldCtx, ClientInfo{APIID: 123, DeviceModel: "Old Desktop", AppVersion: "old", Type: ClientTypeTDesktop}, 1) if got := auth.authKeyClientInfos[permAuthKeyID]; got.DeviceModel != "New Desktop" || got.AppVersion != "new" { t.Fatalf("cross-session durable metadata rolled back: %+v", got) } oldInfo, ok, _ := r.clientSessionInfo(oldCtx) if !ok || !oldInfo.hasClientInfo || oldInfo.clientInfo.DeviceModel != "Old Desktop" { t.Fatalf("old session lost its request-local metadata: %+v ok=%v", oldInfo, ok) } } func tgBufferBytes(t *testing.T, encoder interface{ Encode(*bin.Buffer) error }) []byte { t.Helper() var encoded bin.Buffer if err := encoder.Encode(&encoded); err != nil { t.Fatal(err) } return encoded.Copy() }