fix: preserve Android negotiated layer

This commit is contained in:
A 2026-07-05 03:27:04 +08:00
parent 240fc2b526
commit 2f399d5df2
10 changed files with 465 additions and 29 deletions

View file

@ -2,10 +2,13 @@ package mtprotoedge
import (
"bytes"
"encoding/binary"
"testing"
"github.com/gotd/td/bin"
"github.com/gotd/td/proto"
"github.com/gotd/td/tg"
"go.uber.org/zap/zaptest"
)
// TestConnDowngradedClone verifies the outbound seam downgrades a canonical
@ -63,3 +66,141 @@ func TestConnDowngradedClone(t *testing.T) {
t.Errorf("227 passthrough altered bytes")
}
}
func TestEncodeRPCResultDowngradesDifferenceMessagesForNegotiatedLayer225(t *testing.T) {
const (
message227CRC = 0x7600b9d3
message225CRC = 0x95ef6f2b
)
c := &Conn{metrics: NopMetrics{}}
c.SetClientLayer(225)
diff := &tg.UpdatesDifference{
NewMessages: []tg.MessageClass{
&tg.Message{
ID: 2,
FromID: &tg.PeerUser{UserID: 3},
PeerID: &tg.PeerUser{UserID: 3},
Date: 1,
Message: "hi",
},
},
NewEncryptedMessages: []tg.EncryptedMessageClass{},
OtherUpdates: []tg.UpdateClass{},
Chats: []tg.ChatClass{},
Users: []tg.UserClass{},
State: tg.UpdatesState{Pts: 2, Date: 1},
}
s := &Server{log: zaptest.NewLogger(t)}
encoded, err := s.encodeRPCResult(c, 12345, diff)
if err != nil {
t.Fatalf("encode rpc_result: %v", err)
}
var result proto.Result
if err := result.Decode(&bin.Buffer{Buf: encoded.body}); err != nil {
t.Fatalf("decode rpc_result: %v", err)
}
if result.RequestMessageID != 12345 {
t.Fatalf("req_msg_id = %d, want 12345", result.RequestMessageID)
}
if !bytes.Contains(result.Result, littleEndianID(message225CRC)) {
t.Fatalf("rpc_result inner object does not contain layer 225 message id %#08x", message225CRC)
}
if bytes.Contains(result.Result, littleEndianID(message227CRC)) {
t.Fatalf("rpc_result inner object still contains canonical message id %#08x", message227CRC)
}
}
func TestEncodeRPCResultDowngradesDialogMessagesForNegotiatedLayer225(t *testing.T) {
const (
message227CRC = 0x7600b9d3
message225CRC = 0x95ef6f2b
)
c := &Conn{metrics: NopMetrics{}}
c.SetClientLayer(225)
dialogs := &tg.MessagesDialogs{
Dialogs: []tg.DialogClass{
&tg.Dialog{
Peer: &tg.PeerUser{UserID: 3},
TopMessage: 2,
NotifySettings: tg.PeerNotifySettings{},
},
},
Messages: []tg.MessageClass{
&tg.Message{
ID: 2,
FromID: &tg.PeerUser{UserID: 3},
PeerID: &tg.PeerUser{UserID: 3},
Date: 1,
Message: "hi",
},
},
Chats: []tg.ChatClass{},
Users: []tg.UserClass{
&tg.User{ID: 3, AccessHash: 5, FirstName: "A"},
},
}
s := &Server{log: zaptest.NewLogger(t)}
encoded, err := s.encodeRPCResult(c, 12345, dialogs)
if err != nil {
t.Fatalf("encode rpc_result: %v", err)
}
var result proto.Result
if err := result.Decode(&bin.Buffer{Buf: encoded.body}); err != nil {
t.Fatalf("decode rpc_result: %v", err)
}
if !bytes.Contains(result.Result, littleEndianID(message225CRC)) {
t.Fatalf("rpc_result inner object does not contain layer 225 message id %#08x", message225CRC)
}
if bytes.Contains(result.Result, littleEndianID(message227CRC)) {
t.Fatalf("rpc_result inner object still contains canonical message id %#08x", message227CRC)
}
}
func TestConnDowngradedCloneDowngradesUpdateNewMessageForLayer225(t *testing.T) {
const (
message227CRC = 0x7600b9d3
message225CRC = 0x95ef6f2b
)
updates := &tg.Updates{
Updates: []tg.UpdateClass{
&tg.UpdateNewMessage{
Message: &tg.Message{
ID: 2,
FromID: &tg.PeerUser{UserID: 3},
PeerID: &tg.PeerUser{UserID: 3},
Date: 1,
Message: "hi",
},
Pts: 2,
PtsCount: 1,
},
},
Users: []tg.UserClass{
&tg.User{ID: 3, AccessHash: 5, FirstName: "A"},
},
Chats: []tg.ChatClass{},
Date: 1,
Seq: 1,
}
enc, err := encodeOutboundMessage(updates)
if err != nil {
t.Fatalf("encode updates: %v", err)
}
c := &Conn{metrics: NopMetrics{}}
c.SetClientLayer(225)
out := c.downgradedClone(enc)
if !bytes.Contains(out.body, littleEndianID(message225CRC)) {
t.Fatalf("push update does not contain layer 225 message id %#08x", message225CRC)
}
if bytes.Contains(out.body, littleEndianID(message227CRC)) {
t.Fatalf("push update still contains canonical message id %#08x", message227CRC)
}
}
func littleEndianID(id uint32) []byte {
buf := make([]byte, 4)
binary.LittleEndian.PutUint32(buf, id)
return buf
}