Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Msgid fix #135

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions internal/mtproto/messages/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (

ige "github.com/xelaj/mtproto/internal/aes_ige"
"github.com/xelaj/mtproto/internal/encoding/tl"
"github.com/xelaj/mtproto/internal/mtproto"
"github.com/xelaj/mtproto/internal/utils"
)

Expand All @@ -30,7 +31,7 @@ type Common interface {

type Encrypted struct {
Msg []byte
MsgID int64
MsgID mtproto.MsgID
AuthKeyHash []byte

Salt int64
Expand Down Expand Up @@ -82,7 +83,7 @@ func DeserializeEncrypted(data, authKey []byte) (*Encrypted, error) {
}
msg.Salt = d.PopLong()
msg.SessionID = d.PopLong()
msg.MsgID = d.PopLong()
msg.MsgID = mtproto.MsgID(d.PopLong())
msg.SeqNo = d.PopInt()
messageLen := d.PopInt()

Expand Down Expand Up @@ -119,15 +120,15 @@ func (msg *Encrypted) GetSeqNo() int {

type Unencrypted struct {
Msg []byte
MsgID int64
MsgID mtproto.MsgID
}

func (msg *Unencrypted) Serialize(client MessageInformator) ([]byte, error) {
buf := bytes.NewBuffer(nil)
e := tl.NewEncoder(buf)
// authKeyHash, always 0 if unencrypted
e.PutLong(0)
e.PutLong(msg.MsgID)
e.PutLong(int64(msg.MsgID))
e.PutInt(int32(len(msg.Msg)))
e.PutRawBytes(msg.Msg)
return buf.Bytes(), nil
Expand All @@ -138,7 +139,7 @@ func DeserializeUnencrypted(data []byte) (*Unencrypted, error) {
d, _ := tl.NewDecoder(bytes.NewBuffer(data))
_ = d.PopRawBytes(tl.LongLen) // authKeyHash, always 0 if unencrypted

msg.MsgID = d.PopLong()
msg.MsgID = mtproto.MsgID(d.PopLong())

mod := msg.MsgID & 3
if mod != 1 && mod != 3 {
Expand Down Expand Up @@ -183,15 +184,15 @@ type MessageInformator interface {
GetAuthKey() []byte
}

func serializePacket(client MessageInformator, msg []byte, messageID int64, requireToAck bool) []byte {
func serializePacket(client MessageInformator, msg []byte, id mtproto.MsgID, requireToAck bool) []byte {
buf := bytes.NewBuffer(nil)
d := tl.NewEncoder(buf)

saltBytes := make([]byte, tl.LongLen)
binary.LittleEndian.PutUint64(saltBytes, uint64(client.GetServerSalt()))
d.PutRawBytes(saltBytes)
d.PutLong(client.GetSessionID())
d.PutLong(messageID)
d.PutLong(int64(id))
if requireToAck { // не спрашивай, как это работает
d.PutInt(client.GetSeqNo() | 1) // почему тут добавляется бит не ебу
} else {
Expand Down
53 changes: 53 additions & 0 deletions internal/mtproto/msg_id.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package mtproto

import (
"crypto/rand"
"encoding/binary"
"math"
"time"
)

const (
minDiff = 300 * time.Second
maxDiff = -30 * time.Second
)

type MsgTyp uint8

const (
MsgClient MsgTyp = 0b00
MsgServerResp MsgTyp = 0b01
MsgServerUpd MsgTyp = 0b11
)

// https://core.telegram.org/mtproto/description#message-identifier-msg-id
// 1-32: current unix time
// 33-62: random bits
// 63: for server-side only: 0 if msg is answer to request, 1 if server update
// 64: 1 if msg server-side, 0 if client-side
type MsgID uint64

func (m MsgID) At() time.Time { return time.Unix(int64(m)>>32, 0) }

func (m MsgID) IsValid(at time.Time) bool {
t := m.At().Sub(at)
return minDiff > t && t > maxDiff
}

func NewMsgID(at time.Time, typ MsgTyp) MsgID {
if typ >= 4 {
panic("invalid type")
}

timePart := uint64(at.Unix()) << 32
randPart := randUint32() & (math.MaxUint32 - 3)
return MsgID(timePart) | MsgID(randPart) | MsgID(typ)
}

func randUint32() uint32 {
b := make([]byte, 4)
if _, err := rand.Read(b); err != nil {
panic("unreachable") // to be sure that we will never get any problems
}
return binary.LittleEndian.Uint32(b)
}
8 changes: 6 additions & 2 deletions internal/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@ import (

// GenerateMessageId отдает по сути unix timestamp но ужасно специфическим образом
// TODO: нахуя нужно битовое и на -4??
func GenerateMessageId() int64 {
func GenerateMessageId(prevID int64) int64 {
const billion = 1000 * 1000 * 1000
unixnano := time.Now().UnixNano()
seconds := unixnano / billion
nanoseconds := unixnano % billion
return (seconds << 32) | (nanoseconds & -4)
newID := (seconds << 32) | (nanoseconds & -4)
if newID <= prevID {
return GenerateMessageId(prevID)
}
return newID
}

func AuthKeyHash(key []byte) []byte {
Expand Down
5 changes: 3 additions & 2 deletions network.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ package mtproto
import (
"reflect"
"strconv"
"time"

"github.com/pkg/errors"
"github.com/xelaj/errs"

"github.com/xelaj/mtproto/internal/encoding/tl"
"github.com/xelaj/mtproto/internal/mtproto"
"github.com/xelaj/mtproto/internal/mtproto/messages"
"github.com/xelaj/mtproto/internal/mtproto/objects"
"github.com/xelaj/mtproto/internal/utils"
)

func (m *MTProto) sendPacket(request tl.Object, expectedTypes ...reflect.Type) (chan tl.Object, error) {
Expand All @@ -26,7 +27,7 @@ func (m *MTProto) sendPacket(request tl.Object, expectedTypes ...reflect.Type) (

var (
data messages.Common
msgID = utils.GenerateMessageId()
msgID = mtproto.NewMsgID(time.Now(), mtproto.MsgClient)
)

// adding types for parser if required
Expand Down