Ctrl K
ComunidadGuías…

internal/mtprotoedge/new_session_uid_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package mtprotoedge

import (
	"testing"
	"time"

	"github.com/iamxvbaba/td/mt"
	"github.com/iamxvbaba/td/proto"
	"github.com/iamxvbaba/td/tg"
)

// TestNewSessionCreatedUniqueIDPerSession verifies that the
// new_session_created.unique_id received on two session establishments differ.
// Clients dedup by unique_id, so reusing the same value would make the
// new_session_created after a reconnect be swallowed, and the difference
// catch-up that depends on it is lost with it.
func TestNewSessionCreatedUniqueIDPerSession(t *testing.T) {
	const dc = 2
	addr, pub, _ := startTestServer(t, Options{DC: dc})
	conn, auth, cipher := dialHandshake(t, addr, dc, pub)

	clientMsgID := proto.NewMessageIDGen(time.Now)
	firstMsgID := clientMsgID.New(proto.MessageFromClient)
	sendEncryptedWithSeq(t, conn, cipher, auth, firstMsgID, 1, &tg.HelpGetConfigRequest{})
	first := collectReplies(t, conn, cipher, auth.AuthKey, mt.NewSessionCreatedTypeID)
	var created1 mt.NewSessionCreated
	if err := created1.Decode(mustHave(t, first, mt.NewSessionCreatedTypeID, "first new_session_created")); err != nil {
		t.Fatalf("decode first new_session_created: %v", err)
	}

	nextSessionID := auth.SessionID + 1
	if nextSessionID == 0 {
		nextSessionID++
	}
	secondMsgID := clientMsgID.New(proto.MessageFromClient)
	body := encodeClientMessageBodyForTest(t, &tg.HelpGetConfigRequest{})
	sendEncryptedWithSessionSaltAndSeq(t, conn, cipher, auth, nextSessionID, auth.ServerSalt, secondMsgID, 1, body)
	second := collectReplies(t, conn, cipher, auth.AuthKey, mt.NewSessionCreatedTypeID)
	var created2 mt.NewSessionCreated
	if err := created2.Decode(mustHave(t, second, mt.NewSessionCreatedTypeID, "second new_session_created")); err != nil {
		t.Fatalf("decode second new_session_created: %v", err)
	}

	if created1.UniqueID == created2.UniqueID {
		t.Fatalf("new_session_created.unique_id reused across sessions: %d", created1.UniqueID)
	}
}

// TestNewSessionCreatedMovesFloorForLaterLowerMessage locks the MTProto rule
// that a server-side session must publish a fresh boundary notification when it
// later accepts a smaller logical client msg_id. Official clients use this
// boundary to decide which requests must be regenerated and resent.
func TestNewSessionCreatedMovesFloorForLaterLowerMessage(t *testing.T) {
	const dc = 2
	addr, pub, _ := startTestServer(t, Options{DC: dc})
	conn, auth, cipher := dialHandshake(t, addr, dc, pub)

	freshIDs := proto.NewMessageIDGen(time.Now)
	firstMsgID := freshIDs.New(proto.MessageFromClient)
	sendEncryptedWithSeq(t, conn, cipher, auth, firstMsgID, 0, &mt.HTTPWaitRequest{
		MaxDelay:  0,
		WaitAfter: 0,
		MaxWait:   25_000,
	})
	first := collectReplies(t, conn, cipher, auth.AuthKey, mt.NewSessionCreatedTypeID)
	var created1 mt.NewSessionCreated
	if err := created1.Decode(mustHave(t, first, mt.NewSessionCreatedTypeID, "first new_session_created")); err != nil {
		t.Fatalf("decode first new_session_created: %v", err)
	}
	if created1.FirstMsgID != firstMsgID {
		t.Fatalf("first boundary = %d, want %d", created1.FirstMsgID, firstMsgID)
	}

	oldIDs := proto.NewMessageIDGen(func() time.Time { return time.Now().Add(-10 * time.Minute) })
	lowerMsgID := oldIDs.New(proto.MessageFromClient)
	outerMsgID := freshIDs.New(proto.MessageFromClient)
	pingBody := mustEncodeTL(t, &mt.PingRequest{PingID: 99})
	sendEncrypted(t, conn, cipher, auth, outerMsgID, &proto.MessageContainer{
		Messages: []proto.Message{{
			ID: lowerMsgID, SeqNo: 1, Bytes: len(pingBody), Body: pingBody,
		}},
	})
	second := collectReplies(t, conn, cipher, auth.AuthKey, mt.PongTypeID)
	var created2 mt.NewSessionCreated
	if err := created2.Decode(mustHave(t, second, mt.NewSessionCreatedTypeID, "lower-boundary new_session_created")); err != nil {
		t.Fatalf("decode lower-boundary new_session_created: %v", err)
	}
	if created2.FirstMsgID != lowerMsgID {
		t.Fatalf("lower boundary = %d, want %d", created2.FirstMsgID, lowerMsgID)
	}
	if created2.UniqueID == created1.UniqueID {
		t.Fatalf("lower-boundary notification reused unique_id %d", created2.UniqueID)
	}
}