From 0e4b1c602b47f072edffca43e1382054f743f1cd Mon Sep 17 00:00:00 2001 From: Mrs4s <1844812067@qq.com> Date: Wed, 8 Jul 2020 00:04:24 +0800 Subject: [PATCH] fix issue of repeatedly trigger for OnlinePush events. --- binary/jce/reader.go | 4 +-- binary/jce/structs.go | 67 ++++++++++++++++++++++--------------------- binary/jce/writer.go | 20 +++++++++++-- binary/utils.go | 15 ---------- client/builders.go | 30 ++++++++++++++++++- client/client.go | 8 ++++-- client/decoders.go | 37 +++++++++++++++++------- utils/string.go | 20 +++++++++++++ 8 files changed, 134 insertions(+), 67 deletions(-) create mode 100644 utils/string.go diff --git a/binary/jce/reader.go b/binary/jce/reader.go index 764c9baa..eb11f5f1 100644 --- a/binary/jce/reader.go +++ b/binary/jce/reader.go @@ -348,7 +348,7 @@ func (r *JceReader) readObject(t reflect.Type, tag int) reflect.Value { r.ReadObject(&s, tag) return reflect.ValueOf(s) case reflect.Slice: - s := reflect.New(t.Elem()).Interface().(IJecStruct) + s := reflect.New(t.Elem()).Interface().(IJceStruct) r.readHead() s.ReadFrom(r) r.skipToStructEnd() @@ -410,7 +410,7 @@ func (r *JceReader) ReadObject(i interface{}, tag int) { *o = r.ReadFloat64(tag) case *string: *o = r.ReadString(tag) - case IJecStruct: + case IJceStruct: o.ReadFrom(r) } } diff --git a/binary/jce/structs.go b/binary/jce/structs.go index 3ff8d8b1..6796645e 100644 --- a/binary/jce/structs.go +++ b/binary/jce/structs.go @@ -1,7 +1,7 @@ package jce -type IJecStruct interface { - ToBytes() []byte +type IJceStruct interface { + //ToBytes() []byte ReadFrom(*JceReader) } @@ -86,6 +86,25 @@ type ( } SvcRespPushMsg struct { + Uin int64 `jceId:"0"` + DelInfos []IJceStruct `jceId:"1"` + Svrip int32 `jceId:"2"` + PushToken []byte `jceId:"3"` + ServiceType int32 `jceId:"4"` + } + + DelMsgInfo struct { + FromUin int64 `jceId:"0"` + MsgTime int64 `jceId:"1"` + MsgSeq int16 `jceId:"2"` + MsgCookies []byte `jceId:"3"` + Cmd int16 `jceId:"4"` + MsgType int64 `jceId:"5"` + AppId int64 `jceId:"6"` + SendTime int64 `jceId:"7"` + SsoSeq int32 `jceId:"8"` + SsoIp int32 `jceId:"9"` + ClientIp int32 `jceId:"10"` } FriendListRequest struct { @@ -304,12 +323,6 @@ func (pkt *RequestDataVersion3) ReadFrom(r *JceReader) { }) } -func (pkt *RequestDataVersion2) ToBytes() []byte { - w := NewJceWriter() - w.WriteJceStructRaw(pkt) - return w.Bytes() -} - func (pkt *RequestDataVersion2) ReadFrom(r *JceReader) { pkt.Map = make(map[string]map[string][]byte) r.ReadMapF(0, func(k interface{}, v interface{}) { @@ -340,12 +353,6 @@ func (pkt *FriendListRequest) ReadFrom(r *JceReader) { } -func (pkt *FriendInfo) ToBytes() []byte { - w := NewJceWriter() - w.WriteJceStructRaw(pkt) - return w.Bytes() -} - func (pkt *FriendInfo) ReadFrom(r *JceReader) { pkt.FriendUin = r.ReadInt64(0) pkt.GroupId = r.ReadByte(1) @@ -370,12 +377,6 @@ func (pkt *TroopListRequest) ReadFrom(r *JceReader) { } -func (pkt *TroopNumber) ToBytes() []byte { - w := NewJceWriter() - w.WriteJceStructRaw(pkt) - return w.Bytes() -} - func (pkt *TroopNumber) ReadFrom(r *JceReader) { pkt.GroupUin = r.ReadInt64(0) pkt.GroupCode = r.ReadInt64(1) @@ -396,12 +397,6 @@ func (pkt *TroopMemberListRequest) ReadFrom(r *JceReader) { } -func (pkt *TroopMemberInfo) ToBytes() []byte { - w := NewJceWriter() - w.WriteJceStructRaw(pkt) - return w.Bytes() -} - func (pkt *TroopMemberInfo) ReadFrom(r *JceReader) { pkt.MemberUin = r.ReadInt64(0) pkt.FaceId = r.ReadInt16(1) @@ -417,12 +412,6 @@ func (pkt *TroopMemberInfo) ReadFrom(r *JceReader) { pkt.Job = r.ReadString(25) } -func (pkt *PushMessageInfo) ToBytes() []byte { - w := NewJceWriter() - w.WriteJceStructRaw(pkt) - return w.Bytes() -} - func (pkt *PushMessageInfo) ReadFrom(r *JceReader) { pkt.FromUin = r.ReadInt64(0) pkt.MsgTime = r.ReadInt64(1) @@ -430,6 +419,20 @@ func (pkt *PushMessageInfo) ReadFrom(r *JceReader) { pkt.MsgSeq = r.ReadInt16(3) pkt.Msg = r.ReadString(4) pkt.VMsg = r.ReadAny(6).([]byte) + pkt.MsgCookies = r.ReadAny(8).([]byte) + pkt.MsgUid = r.ReadInt64(10) pkt.FromMobile = r.ReadString(16) pkt.FromName = r.ReadString(17) } + +func (pkt *SvcRespPushMsg) ToBytes() []byte { + w := NewJceWriter() + w.WriteJceStructRaw(pkt) + return w.Bytes() +} + +func (pkt *SvcRespPushMsg) ReadFrom(r *JceReader) { +} + +func (pkt *DelMsgInfo) ReadFrom(r *JceReader) { +} diff --git a/binary/jce/writer.go b/binary/jce/writer.go index 650da8f4..9ba3f703 100644 --- a/binary/jce/writer.go +++ b/binary/jce/writer.go @@ -112,6 +112,18 @@ func (w *JceWriter) WriteInt64Slice(l []int64, tag int) { } } +func (w *JceWriter) WriteJceStructSlice(l []IJceStruct, tag int) { + w.writeHead(9, tag) + if len(l) == 0 { + w.WriteInt32(0, 0) + return + } + w.WriteInt32(int32(len(l)), 0) + for _, v := range l { + w.WriteJceStruct(v, 0) + } +} + func (w *JceWriter) WriteMap(m interface{}, tag int) { if m == nil { w.writeHead(8, tag) @@ -158,12 +170,14 @@ func (w *JceWriter) WriteObject(i interface{}, tag int) { w.WriteBytes(o, tag) case []int64: w.WriteInt64Slice(o, tag) - case IJecStruct: + case IJceStruct: w.WriteJceStruct(o, tag) + case []IJceStruct: + w.WriteJceStructSlice(o, tag) } } -func (w *JceWriter) WriteJceStructRaw(s IJecStruct) { +func (w *JceWriter) WriteJceStructRaw(s IJceStruct) { var ( t = reflect.TypeOf(s).Elem() v = reflect.ValueOf(s).Elem() @@ -181,7 +195,7 @@ func (w *JceWriter) WriteJceStructRaw(s IJecStruct) { } } -func (w *JceWriter) WriteJceStruct(s IJecStruct, tag int) { +func (w *JceWriter) WriteJceStruct(s IJceStruct, tag int) { w.writeHead(10, tag) w.WriteJceStructRaw(s) w.writeHead(11, 0) diff --git a/binary/utils.go b/binary/utils.go index 3f80e7b9..9267fff3 100644 --- a/binary/utils.go +++ b/binary/utils.go @@ -3,12 +3,10 @@ package binary import ( "bytes" "compress/zlib" - "crypto/rand" binary2 "encoding/binary" "encoding/hex" "fmt" "io" - "math/big" "strings" ) @@ -20,19 +18,6 @@ func ZlibUncompress(src []byte) []byte { return out.Bytes() } -func RandomString(len int) string { - var res string - var str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" - b := bytes.NewBufferString(str) - length := b.Len() - bigInt := big.NewInt(int64(length)) - for i := 0; i < len; i++ { - randomInt, _ := rand.Int(rand.Reader, bigInt) - res += string(str[randomInt.Int64()]) - } - return res -} - func CalculateImageResourceId(md5 []byte) string { return strings.ToUpper(fmt.Sprintf( "{%s-%s-%s-%s-%s}.png", diff --git a/client/builders.go b/client/builders.go index 932db50b..612317a1 100644 --- a/client/builders.go +++ b/client/builders.go @@ -10,6 +10,7 @@ import ( "github.com/Mrs4s/MiraiGo/protocol/crypto" "github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/tlv" + "github.com/Mrs4s/MiraiGo/utils" "github.com/golang/protobuf/proto" "math/rand" "strconv" @@ -327,6 +328,33 @@ func (c *QQClient) buildDeleteMessageRequestPacket(msg []*pb.MessageItem) (uint1 return seq, packet } +func (c *QQClient) buildDeleteOnlinePushPacket(uin int64, seq uint16, delMsg []jce.PushMessageInfo) []byte { + req := &jce.SvcRespPushMsg{Uin: uin} + for _, m := range delMsg { + req.DelInfos = append(req.DelInfos, &jce.DelMsgInfo{ + FromUin: m.FromUin, + MsgSeq: m.MsgSeq, + MsgCookies: m.MsgCookies, + MsgTime: m.MsgTime, + }) + } + b := append([]byte{0x0A}, req.ToBytes()...) + b = append(b, 0x0B) + buf := &jce.RequestDataVersion3{ + Map: map[string][]byte{"resp": b}, + } + pkt := &jce.RequestPacket{ + IVersion: 3, + IRequestId: int32(seq), + SServantName: "OnlinePush", + SFuncName: "SvcRespPushMsg", + SBuffer: buf.ToBytes(), + Context: make(map[string]string), + Status: make(map[string]string), + } + return packets.BuildUniPacket(c.Uin, seq, "OnlinePush.RespPush", 1, c.OutGoingPacketSessionId, []byte{}, c.sigInfo.d2Key, pkt.ToBytes()) +} + func (c *QQClient) buildGroupSendingPacket(groupCode int64, m *message.SendingMessage) (uint16, []byte) { seq := c.nextSeq() req := &msg.SendMessageRequest{ @@ -350,7 +378,7 @@ func (c *QQClient) buildGroupSendingPacket(groupCode int64, m *message.SendingMe func (c *QQClient) buildGroupImageStorePacket(groupCode int64, md5 [16]byte, size int32) (uint16, []byte) { seq := c.nextSeq() - name := binary.RandomString(16) + ".gif" + name := utils.RandomString(16) + ".gif" req := &pb.D388ReqBody{ NetType: 3, Subcmd: 1, diff --git a/client/client.go b/client/client.go index 1c4715a3..f149c9db 100644 --- a/client/client.go +++ b/client/client.go @@ -33,7 +33,7 @@ type QQClient struct { RandomKey []byte Conn net.Conn - decoders map[string]func(*QQClient, []byte) (interface{}, error) + decoders map[string]func(*QQClient, uint16, []byte) (interface{}, error) handlers map[uint16]func(interface{}, error) syncCookie []byte @@ -52,6 +52,7 @@ type QQClient struct { running bool lastMessageSeq int32 + onlinePushCache []int16 // reset on reconnect requestPacketRequestId int32 messageSeq int32 groupDataTransSeq int32 @@ -84,7 +85,7 @@ func NewClient(uin int64, password string) *QQClient { SequenceId: 0x3635, RandomKey: make([]byte, 16), OutGoingPacketSessionId: []byte{0x02, 0xB0, 0x5B, 0x8B}, - decoders: map[string]func(*QQClient, []byte) (interface{}, error){ + decoders: map[string]func(*QQClient, uint16, []byte) (interface{}, error){ "wtlogin.login": decodeLoginResponse, "StatSvc.register": decodeClientRegisterResponse, "MessageSvc.PushNotify": decodeSvcNotify, @@ -312,6 +313,7 @@ func (c *QQClient) connect() error { return err } c.Conn = conn + c.onlinePushCache = []int16{} return nil } @@ -411,7 +413,7 @@ func (c *QQClient) loop() { } return } - rsp, err := decoder(c, payload) + rsp, err := decoder(c, pkt.SequenceId, payload) if err != nil { log.Println("decode", pkt.CommandName, "error:", err) } diff --git a/client/decoders.go b/client/decoders.go index 1dbf4d89..737a611f 100644 --- a/client/decoders.go +++ b/client/decoders.go @@ -10,7 +10,7 @@ import ( "time" ) -func decodeLoginResponse(c *QQClient, payload []byte) (interface{}, error) { +func decodeLoginResponse(c *QQClient, seq uint16, payload []byte) (interface{}, error) { reader := binary.NewReader(payload) reader.ReadUInt16() // sub command t := reader.ReadByte() @@ -91,7 +91,7 @@ func decodeLoginResponse(c *QQClient, payload []byte) (interface{}, error) { return nil, nil // ? } -func decodeClientRegisterResponse(c *QQClient, payload []byte) (interface{}, error) { +func decodeClientRegisterResponse(c *QQClient, seq uint16, payload []byte) (interface{}, error) { request := &jce.RequestPacket{} request.ReadFrom(jce.NewJceReader(payload)) data := &jce.RequestDataVersion2{} @@ -99,7 +99,7 @@ func decodeClientRegisterResponse(c *QQClient, payload []byte) (interface{}, err return nil, nil } -func decodePushReqPacket(c *QQClient, payload []byte) (interface{}, error) { +func decodePushReqPacket(c *QQClient, s uint16, payload []byte) (interface{}, error) { request := &jce.RequestPacket{} request.ReadFrom(jce.NewJceReader(payload)) data := &jce.RequestDataVersion2{} @@ -113,7 +113,7 @@ func decodePushReqPacket(c *QQClient, payload []byte) (interface{}, error) { return nil, c.send(pkt) } -func decodeMessageSvcPacket(c *QQClient, payload []byte) (interface{}, error) { +func decodeMessageSvcPacket(c *QQClient, seq uint16, payload []byte) (interface{}, error) { rsp := msg.GetMessageResponse{} err := proto.Unmarshal(payload, &rsp) if err != nil { @@ -163,7 +163,7 @@ func decodeMessageSvcPacket(c *QQClient, payload []byte) (interface{}, error) { return nil, err } -func decodeGroupMessagePacket(c *QQClient, payload []byte) (interface{}, error) { +func decodeGroupMessagePacket(c *QQClient, seq uint16, payload []byte) (interface{}, error) { pkt := msg.PushMessagePacket{} err := proto.Unmarshal(payload, &pkt) if err != nil { @@ -176,12 +176,12 @@ func decodeGroupMessagePacket(c *QQClient, payload []byte) (interface{}, error) return nil, nil } -func decodeSvcNotify(c *QQClient, payload []byte) (interface{}, error) { +func decodeSvcNotify(c *QQClient, seq uint16, payload []byte) (interface{}, error) { _, pkt := c.buildGetMessageRequestPacket(msg.SyncFlag_START, time.Now().Unix()) return nil, c.send(pkt) } -func decodeFriendGroupListResponse(c *QQClient, payload []byte) (interface{}, error) { +func decodeFriendGroupListResponse(c *QQClient, seq uint16, payload []byte) (interface{}, error) { request := &jce.RequestPacket{} request.ReadFrom(jce.NewJceReader(payload)) data := &jce.RequestDataVersion3{} @@ -206,7 +206,7 @@ func decodeFriendGroupListResponse(c *QQClient, payload []byte) (interface{}, er return rsp, nil } -func decodeGroupListResponse(c *QQClient, payload []byte) (interface{}, error) { +func decodeGroupListResponse(c *QQClient, seq uint16, payload []byte) (interface{}, error) { request := &jce.RequestPacket{} request.ReadFrom(jce.NewJceReader(payload)) data := &jce.RequestDataVersion3{} @@ -229,7 +229,7 @@ func decodeGroupListResponse(c *QQClient, payload []byte) (interface{}, error) { return l, nil } -func decodeGroupMemberListResponse(c *QQClient, payload []byte) (interface{}, error) { +func decodeGroupMemberListResponse(c *QQClient, seq uint16, payload []byte) (interface{}, error) { request := &jce.RequestPacket{} request.ReadFrom(jce.NewJceReader(payload)) data := &jce.RequestDataVersion3{} @@ -258,7 +258,7 @@ func decodeGroupMemberListResponse(c *QQClient, payload []byte) (interface{}, er }, nil } -func decodeGroupImageStoreResponse(c *QQClient, payload []byte) (interface{}, error) { +func decodeGroupImageStoreResponse(c *QQClient, seq uint16, payload []byte) (interface{}, error) { pkt := pb.D388RespBody{} err := proto.Unmarshal(payload, &pkt) if err != nil { @@ -281,15 +281,29 @@ func decodeGroupImageStoreResponse(c *QQClient, payload []byte) (interface{}, er }, nil } -func decodeOnlinePushReqPacket(c *QQClient, payload []byte) (interface{}, error) { +func decodeOnlinePushReqPacket(c *QQClient, seq uint16, payload []byte) (interface{}, error) { request := &jce.RequestPacket{} request.ReadFrom(jce.NewJceReader(payload)) data := &jce.RequestDataVersion2{} data.ReadFrom(jce.NewJceReader(request.SBuffer)) jr := jce.NewJceReader(data.Map["req"]["OnlinePushPack.SvcReqPushMsg"][1:]) msgInfos := []jce.PushMessageInfo{} + uin := jr.ReadInt64(0) jr.ReadSlice(&msgInfos, 2) + _ = c.send(c.buildDeleteOnlinePushPacket(uin, seq, msgInfos)) + seqExists := func(ms int16) bool { + for _, s := range c.onlinePushCache { + if ms == s { + return true + } + } + return false + } for _, m := range msgInfos { + if seqExists(m.MsgSeq) { + continue + } + c.onlinePushCache = append(c.onlinePushCache, m.MsgSeq) if m.MsgType == 732 { r := binary.NewReader(m.VMsg) groupId := int64(uint32(r.ReadInt32())) @@ -329,5 +343,6 @@ func decodeOnlinePushReqPacket(c *QQClient, payload []byte) (interface{}, error) } } } + return nil, nil } diff --git a/utils/string.go b/utils/string.go new file mode 100644 index 00000000..ea6de605 --- /dev/null +++ b/utils/string.go @@ -0,0 +1,20 @@ +package utils + +import ( + "bytes" + "crypto/rand" + "math/big" +) + +func RandomString(len int) string { + var res string + var str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" + b := bytes.NewBufferString(str) + length := b.Len() + bigInt := big.NewInt(int64(length)) + for i := 0; i < len; i++ { + randomInt, _ := rand.Int(rand.Reader, bigInt) + res += string(str[randomInt.Int64()]) + } + return res +}