mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-08 04:55:56 +08:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
19f539df44
@ -430,6 +430,12 @@ 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) {
|
func (pkt *RequestDataVersion2) ReadFrom(r *JceReader) {
|
||||||
pkt.Map = make(map[string]map[string][]byte)
|
pkt.Map = make(map[string]map[string][]byte)
|
||||||
r.ReadMapF(0, func(k interface{}, v interface{}) {
|
r.ReadMapF(0, func(k interface{}, v interface{}) {
|
||||||
|
@ -26,13 +26,14 @@ func (w *JceWriter) writeHead(t byte, tag int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *JceWriter) WriteByte(b byte, tag int) {
|
func (w *JceWriter) WriteByte(b byte, tag int) *JceWriter {
|
||||||
if b == 0 {
|
if b == 0 {
|
||||||
w.writeHead(12, tag)
|
w.writeHead(12, tag)
|
||||||
} else {
|
} else {
|
||||||
w.writeHead(0, tag)
|
w.writeHead(0, tag)
|
||||||
w.buf.WriteByte(b)
|
w.buf.WriteByte(b)
|
||||||
}
|
}
|
||||||
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *JceWriter) WriteBool(b bool, tag int) {
|
func (w *JceWriter) WriteBool(b bool, tag int) {
|
||||||
@ -52,22 +53,23 @@ func (w *JceWriter) WriteInt16(n int16, tag int) {
|
|||||||
_ = goBinary.Write(w.buf, goBinary.BigEndian, n)
|
_ = goBinary.Write(w.buf, goBinary.BigEndian, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *JceWriter) WriteInt32(n int32, tag int) {
|
func (w *JceWriter) WriteInt32(n int32, tag int) *JceWriter {
|
||||||
if n >= -32768 && n <= 32767 { // ? if ((n >= 32768) && (n <= 32767))
|
if n >= -32768 && n <= 32767 { // ? if ((n >= 32768) && (n <= 32767))
|
||||||
w.WriteInt16(int16(n), tag)
|
w.WriteInt16(int16(n), tag)
|
||||||
return
|
return w
|
||||||
}
|
}
|
||||||
w.writeHead(2, tag)
|
w.writeHead(2, tag)
|
||||||
_ = goBinary.Write(w.buf, goBinary.BigEndian, n)
|
_ = goBinary.Write(w.buf, goBinary.BigEndian, n)
|
||||||
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *JceWriter) WriteInt64(n int64, tag int) {
|
func (w *JceWriter) WriteInt64(n int64, tag int) *JceWriter {
|
||||||
if n >= -2147483648 && n <= 2147483647 {
|
if n >= -2147483648 && n <= 2147483647 {
|
||||||
w.WriteInt32(int32(n), tag)
|
return w.WriteInt32(int32(n), tag)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
w.writeHead(3, tag)
|
w.writeHead(3, tag)
|
||||||
_ = goBinary.Write(w.buf, goBinary.BigEndian, n)
|
_ = goBinary.Write(w.buf, goBinary.BigEndian, n)
|
||||||
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *JceWriter) WriteFloat32(n float32, tag int) {
|
func (w *JceWriter) WriteFloat32(n float32, tag int) {
|
||||||
@ -80,17 +82,18 @@ func (w *JceWriter) WriteFloat64(n float64, tag int) {
|
|||||||
_ = goBinary.Write(w.buf, goBinary.BigEndian, n)
|
_ = goBinary.Write(w.buf, goBinary.BigEndian, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *JceWriter) WriteString(s string, tag int) {
|
func (w *JceWriter) WriteString(s string, tag int) *JceWriter {
|
||||||
by := []byte(s)
|
by := []byte(s)
|
||||||
if len(by) > 255 {
|
if len(by) > 255 {
|
||||||
w.writeHead(7, tag)
|
w.writeHead(7, tag)
|
||||||
_ = goBinary.Write(w.buf, goBinary.BigEndian, len(by))
|
_ = goBinary.Write(w.buf, goBinary.BigEndian, len(by))
|
||||||
w.buf.Write(by)
|
w.buf.Write(by)
|
||||||
return
|
return w
|
||||||
}
|
}
|
||||||
w.writeHead(6, tag)
|
w.writeHead(6, tag)
|
||||||
w.buf.WriteByte(byte(len(by)))
|
w.buf.WriteByte(byte(len(by)))
|
||||||
w.buf.Write(by)
|
w.buf.Write(by)
|
||||||
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *JceWriter) WriteBytes(l []byte, tag int) {
|
func (w *JceWriter) WriteBytes(l []byte, tag int) {
|
||||||
@ -167,6 +170,10 @@ func (w *JceWriter) WriteObject(i interface{}, tag int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if t.Kind() == reflect.Slice {
|
if t.Kind() == reflect.Slice {
|
||||||
|
if b, ok := i.([]byte); ok {
|
||||||
|
w.WriteBytes(b, tag)
|
||||||
|
return
|
||||||
|
}
|
||||||
w.WriteSlice(i, tag)
|
w.WriteSlice(i, tag)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -274,7 +274,7 @@ func (c *QQClient) buildConfPushRespPacket(t int32, pktSeq int64, jceBuf []byte)
|
|||||||
req.WriteInt64(pktSeq, 2)
|
req.WriteInt64(pktSeq, 2)
|
||||||
req.WriteBytes(jceBuf, 3)
|
req.WriteBytes(jceBuf, 3)
|
||||||
buf := &jce.RequestDataVersion3{
|
buf := &jce.RequestDataVersion3{
|
||||||
Map: map[string][]byte{"PushResp": packRequestDataV3(req.Bytes())},
|
Map: map[string][]byte{"PushResp": packUniRequestData(req.Bytes())},
|
||||||
}
|
}
|
||||||
pkt := &jce.RequestPacket{
|
pkt := &jce.RequestPacket{
|
||||||
IVersion: 3,
|
IVersion: 3,
|
||||||
@ -298,7 +298,7 @@ func (c *QQClient) buildDeviceListRequestPacket() (uint16, []byte) {
|
|||||||
RequireMax: 20,
|
RequireMax: 20,
|
||||||
GetDevListType: 2,
|
GetDevListType: 2,
|
||||||
}
|
}
|
||||||
buf := &jce.RequestDataVersion3{Map: map[string][]byte{"SvcReqGetDevLoginInfo": packRequestDataV3(req.ToBytes())}}
|
buf := &jce.RequestDataVersion3{Map: map[string][]byte{"SvcReqGetDevLoginInfo": packUniRequestData(req.ToBytes())}}
|
||||||
pkt := &jce.RequestPacket{
|
pkt := &jce.RequestPacket{
|
||||||
IVersion: 3,
|
IVersion: 3,
|
||||||
SServantName: "StatSvc",
|
SServantName: "StatSvc",
|
||||||
@ -353,7 +353,7 @@ func (c *QQClient) buildFriendGroupListRequestPacket(friendStartIndex, friendLis
|
|||||||
SnsTypeList: []int64{13580, 13581, 13582},
|
SnsTypeList: []int64{13580, 13581, 13582},
|
||||||
}
|
}
|
||||||
buf := &jce.RequestDataVersion3{
|
buf := &jce.RequestDataVersion3{
|
||||||
Map: map[string][]byte{"FL": packRequestDataV3(req.ToBytes())},
|
Map: map[string][]byte{"FL": packUniRequestData(req.ToBytes())},
|
||||||
}
|
}
|
||||||
pkt := &jce.RequestPacket{
|
pkt := &jce.RequestPacket{
|
||||||
IVersion: 3,
|
IVersion: 3,
|
||||||
@ -386,8 +386,8 @@ func (c *QQClient) buildSummaryCardRequestPacket(target int64) (uint16, []byte)
|
|||||||
head := jce.NewJceWriter()
|
head := jce.NewJceWriter()
|
||||||
head.WriteInt32(2, 0)
|
head.WriteInt32(2, 0)
|
||||||
buf := &jce.RequestDataVersion3{Map: map[string][]byte{
|
buf := &jce.RequestDataVersion3{Map: map[string][]byte{
|
||||||
"ReqHead": packRequestDataV3(head.Bytes()),
|
"ReqHead": packUniRequestData(head.Bytes()),
|
||||||
"ReqSummaryCard": packRequestDataV3(req.ToBytes()),
|
"ReqSummaryCard": packUniRequestData(req.ToBytes()),
|
||||||
}}
|
}}
|
||||||
pkt := &jce.RequestPacket{
|
pkt := &jce.RequestPacket{
|
||||||
IVersion: 3,
|
IVersion: 3,
|
||||||
@ -869,7 +869,7 @@ func (c *QQClient) buildEditGroupTagPacket(groupCode, memberUin int64, newTag st
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
buf := &jce.RequestDataVersion3{Map: map[string][]byte{"MGCREQ": packRequestDataV3(req.ToBytes())}}
|
buf := &jce.RequestDataVersion3{Map: map[string][]byte{"MGCREQ": packUniRequestData(req.ToBytes())}}
|
||||||
pkt := &jce.RequestPacket{
|
pkt := &jce.RequestPacket{
|
||||||
IVersion: 3,
|
IVersion: 3,
|
||||||
IRequestId: c.nextPacketSeq(),
|
IRequestId: c.nextPacketSeq(),
|
||||||
@ -1051,7 +1051,7 @@ func (c *QQClient) buildQuitGroupPacket(groupCode int64) (uint16, []byte) {
|
|||||||
w.WriteUInt32(uint32(c.Uin))
|
w.WriteUInt32(uint32(c.Uin))
|
||||||
w.WriteUInt32(uint32(groupCode))
|
w.WriteUInt32(uint32(groupCode))
|
||||||
}), 2)
|
}), 2)
|
||||||
buf := &jce.RequestDataVersion3{Map: map[string][]byte{"GroupMngReq": packRequestDataV3(jw.Bytes())}}
|
buf := &jce.RequestDataVersion3{Map: map[string][]byte{"GroupMngReq": packUniRequestData(jw.Bytes())}}
|
||||||
pkt := &jce.RequestPacket{
|
pkt := &jce.RequestPacket{
|
||||||
IVersion: 3,
|
IVersion: 3,
|
||||||
IRequestId: c.nextPacketSeq(),
|
IRequestId: c.nextPacketSeq(),
|
||||||
|
@ -151,7 +151,8 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
|
|||||||
"ProfileService.Pb.ReqSystemMsgNew.Friend": decodeSystemMsgFriendPacket,
|
"ProfileService.Pb.ReqSystemMsgNew.Friend": decodeSystemMsgFriendPacket,
|
||||||
"MultiMsg.ApplyUp": decodeMultiApplyUpResponse,
|
"MultiMsg.ApplyUp": decodeMultiApplyUpResponse,
|
||||||
"MultiMsg.ApplyDown": decodeMultiApplyDownResponse,
|
"MultiMsg.ApplyDown": decodeMultiApplyDownResponse,
|
||||||
"OidbSvc.0x6d6_2": decodeOIDB6d6Response,
|
"OidbSvc.0x6d6_2": decodeOIDB6d62Response,
|
||||||
|
"OidbSvc.0x6d6_3": decodeOIDB6d63Response,
|
||||||
"OidbSvc.0x6d8_1": decodeOIDB6d81Response,
|
"OidbSvc.0x6d8_1": decodeOIDB6d81Response,
|
||||||
"OidbSvc.0x88d_0": decodeGroupInfoResponse,
|
"OidbSvc.0x88d_0": decodeGroupInfoResponse,
|
||||||
"OidbSvc.0xe07_0": decodeImageOcrResponse,
|
"OidbSvc.0xe07_0": decodeImageOcrResponse,
|
||||||
@ -187,11 +188,18 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
|
|||||||
}
|
}
|
||||||
adds, err := net.LookupIP("msfwifi.3g.qq.com") // host servers
|
adds, err := net.LookupIP("msfwifi.3g.qq.com") // host servers
|
||||||
if err == nil && len(adds) > 0 {
|
if err == nil && len(adds) > 0 {
|
||||||
addr := &net.TCPAddr{
|
var hostAddrs []*net.TCPAddr
|
||||||
IP: adds[0],
|
for _, addr := range adds {
|
||||||
Port: 8080,
|
hostAddrs = append(hostAddrs, &net.TCPAddr{
|
||||||
|
IP: addr,
|
||||||
|
Port: 8080,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
cli.servers = append([]*net.TCPAddr{addr}, cli.servers...)
|
cli.servers = append(hostAddrs, cli.servers...)
|
||||||
|
}
|
||||||
|
sso, err := getSSOAddress()
|
||||||
|
if err == nil && len(sso) > 0 {
|
||||||
|
cli.servers = append(sso, cli.servers...)
|
||||||
}
|
}
|
||||||
rand.Read(cli.RandomKey)
|
rand.Read(cli.RandomKey)
|
||||||
return cli
|
return cli
|
||||||
@ -207,8 +215,7 @@ func (c *QQClient) Login() (*LoginResponse, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
go c.netLoop()
|
go c.netLoop()
|
||||||
seq, packet := c.buildLoginPacket()
|
rsp, err := c.sendAndWait(c.buildLoginPacket())
|
||||||
rsp, err := c.sendAndWait(seq, packet)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Disconnect()
|
c.Disconnect()
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -225,6 +232,7 @@ func (c *QQClient) SubmitCaptcha(result string, sign []byte) (*LoginResponse, er
|
|||||||
seq, packet := c.buildCaptchaPacket(result, sign)
|
seq, packet := c.buildCaptchaPacket(result, sign)
|
||||||
rsp, err := c.sendAndWait(seq, packet)
|
rsp, err := c.sendAndWait(seq, packet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
c.Disconnect()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
l := rsp.(LoginResponse)
|
l := rsp.(LoginResponse)
|
||||||
@ -237,6 +245,7 @@ func (c *QQClient) SubmitCaptcha(result string, sign []byte) (*LoginResponse, er
|
|||||||
func (c *QQClient) SubmitSMS(code string) (*LoginResponse, error) {
|
func (c *QQClient) SubmitSMS(code string) (*LoginResponse, error) {
|
||||||
rsp, err := c.sendAndWait(c.buildSMSCodeSubmitPacket(code))
|
rsp, err := c.sendAndWait(c.buildSMSCodeSubmitPacket(code))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
c.Disconnect()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
l := rsp.(LoginResponse)
|
l := rsp.(LoginResponse)
|
||||||
@ -251,7 +260,7 @@ func (c *QQClient) init() {
|
|||||||
_ = c.registerClient()
|
_ = c.registerClient()
|
||||||
c.groupSysMsgCache, _ = c.GetGroupSystemMessages()
|
c.groupSysMsgCache, _ = c.GetGroupSystemMessages()
|
||||||
if !c.heartbeatEnabled {
|
if !c.heartbeatEnabled {
|
||||||
c.startHeartbeat()
|
go c.doHeartbeat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -641,17 +650,19 @@ func (c *QQClient) uploadPrivateImage(target int64, img []byte, count int) (*mes
|
|||||||
count++
|
count++
|
||||||
h := md5.Sum(img)
|
h := md5.Sum(img)
|
||||||
e, err := c.QueryFriendImage(target, h[:], int32(len(img)))
|
e, err := c.QueryFriendImage(target, h[:], int32(len(img)))
|
||||||
if err != nil {
|
if err == ErrNotExists {
|
||||||
// use group highway upload and query again for image id.
|
// use group highway upload and query again for image id.
|
||||||
if _, err = c.UploadGroupImage(target, img); err != nil {
|
if _, err = c.UploadGroupImage(target, img); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// safe
|
|
||||||
if count >= 5 {
|
if count >= 5 {
|
||||||
return nil, errors.New("upload failed")
|
return e, nil
|
||||||
}
|
}
|
||||||
return c.uploadPrivateImage(target, img, count)
|
return c.uploadPrivateImage(target, img, count)
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -698,7 +709,10 @@ func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*mes
|
|||||||
return nil, errors.New(rsp.Message)
|
return nil, errors.New(rsp.Message)
|
||||||
}
|
}
|
||||||
if !rsp.IsExists {
|
if !rsp.IsExists {
|
||||||
return nil, errors.New("image not exists")
|
return &message.FriendImageElement{
|
||||||
|
ImageId: rsp.ResourceId,
|
||||||
|
Md5: hash,
|
||||||
|
}, ErrNotExists
|
||||||
}
|
}
|
||||||
return &message.FriendImageElement{
|
return &message.FriendImageElement{
|
||||||
ImageId: rsp.ResourceId,
|
ImageId: rsp.ResourceId,
|
||||||
@ -1021,6 +1035,9 @@ func (c *QQClient) sendAndWait(seq uint16, pkt []byte) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *QQClient) netLoop() {
|
func (c *QQClient) netLoop() {
|
||||||
|
if c.NetLooping {
|
||||||
|
return
|
||||||
|
}
|
||||||
c.NetLooping = true
|
c.NetLooping = true
|
||||||
reader := binary.NewNetworkReader(c.Conn)
|
reader := binary.NewNetworkReader(c.Conn)
|
||||||
retry := 0
|
retry := 0
|
||||||
@ -1031,13 +1048,14 @@ func (c *QQClient) netLoop() {
|
|||||||
c.Error("connection dropped by server: %v", err)
|
c.Error("connection dropped by server: %v", err)
|
||||||
err = c.connect()
|
err = c.connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
c.Error("connect server error: %v", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
reader = binary.NewNetworkReader(c.Conn)
|
reader = binary.NewNetworkReader(c.Conn)
|
||||||
if c.registerClient() != nil {
|
if e := c.registerClient(); e != nil {
|
||||||
c.Disconnect()
|
c.Disconnect()
|
||||||
c.lastLostMsg = "register client failed."
|
c.lastLostMsg = "register client failed: " + e.Error()
|
||||||
c.Error("reconnect failed: register client failed.")
|
c.Error("reconnect failed: " + e.Error())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1053,7 +1071,7 @@ func (c *QQClient) netLoop() {
|
|||||||
pkt, err := packets.ParseIncomingPacket(data, c.sigInfo.d2Key)
|
pkt, err := packets.ParseIncomingPacket(data, c.sigInfo.d2Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error("parse incoming packet error: %v", err)
|
c.Error("parse incoming packet error: %v", err)
|
||||||
if err == packets.ErrSessionExpired {
|
if err == packets.ErrSessionExpired || err == packets.ErrPacketDropped {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
errCount++
|
errCount++
|
||||||
@ -1109,21 +1127,19 @@ func (c *QQClient) netLoop() {
|
|||||||
c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: c.lastLostMsg})
|
c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: c.lastLostMsg})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *QQClient) startHeartbeat() {
|
|
||||||
c.heartbeatEnabled = true
|
|
||||||
time.AfterFunc(30*time.Second, c.doHeartbeat)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *QQClient) doHeartbeat() {
|
func (c *QQClient) doHeartbeat() {
|
||||||
if c.Online {
|
c.heartbeatEnabled = true
|
||||||
|
for c.Online {
|
||||||
seq := c.nextSeq()
|
seq := c.nextSeq()
|
||||||
sso := packets.BuildSsoPacket(seq, c.version.AppId, "Heartbeat.Alive", SystemDeviceInfo.IMEI, []byte{}, c.OutGoingPacketSessionId, []byte{}, c.ksid)
|
sso := packets.BuildSsoPacket(seq, c.version.AppId, "Heartbeat.Alive", SystemDeviceInfo.IMEI, []byte{}, c.OutGoingPacketSessionId, []byte{}, c.ksid)
|
||||||
packet := packets.BuildLoginPacket(c.Uin, 0, []byte{}, sso, []byte{})
|
packet := packets.BuildLoginPacket(c.Uin, 0, []byte{}, sso, []byte{})
|
||||||
_, err := c.sendAndWait(seq, packet)
|
_, err := c.sendAndWait(seq, packet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.Conn.Close()
|
c.lastLostMsg = "Heartbeat failed: " + err.Error()
|
||||||
|
c.Disconnect()
|
||||||
|
break
|
||||||
}
|
}
|
||||||
time.AfterFunc(30*time.Second, c.doHeartbeat)
|
time.Sleep(time.Second * 30)
|
||||||
}
|
}
|
||||||
c.heartbeatEnabled = false
|
c.heartbeatEnabled = false
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ func decodeLoginResponse(c *QQClient, _ uint16, payload []byte) (interface{}, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StatSvc.register
|
// StatSvc.register
|
||||||
func decodeClientRegisterResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) {
|
func decodeClientRegisterResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) {
|
||||||
request := &jce.RequestPacket{}
|
request := &jce.RequestPacket{}
|
||||||
request.ReadFrom(jce.NewJceReader(payload))
|
request.ReadFrom(jce.NewJceReader(payload))
|
||||||
data := &jce.RequestDataVersion2{}
|
data := &jce.RequestDataVersion2{}
|
||||||
@ -173,6 +173,9 @@ func decodeClientRegisterResponse(_ *QQClient, _ uint16, payload []byte) (interf
|
|||||||
svcRsp := &jce.SvcRespRegister{}
|
svcRsp := &jce.SvcRespRegister{}
|
||||||
svcRsp.ReadFrom(jce.NewJceReader(data.Map["SvcRespRegister"]["QQService.SvcRespRegister"][1:]))
|
svcRsp.ReadFrom(jce.NewJceReader(data.Map["SvcRespRegister"]["QQService.SvcRespRegister"][1:]))
|
||||||
if svcRsp.Result != "" || svcRsp.Status != 11 {
|
if svcRsp.Result != "" || svcRsp.Status != 11 {
|
||||||
|
if svcRsp.Result != "" {
|
||||||
|
c.Error("reg error: %v", svcRsp.Result)
|
||||||
|
}
|
||||||
return nil, errors.New("reg failed")
|
return nil, errors.New("reg failed")
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -221,12 +224,17 @@ func decodePushReqPacket(c *QQClient, _ uint16, payload []byte) (interface{}, er
|
|||||||
Port: int(s.Port),
|
Port: int(s.Port),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
c.SetCustomServer(adds)
|
f := true
|
||||||
for _, e := range c.eventHandlers.serverUpdatedHandlers {
|
for _, e := range c.eventHandlers.serverUpdatedHandlers {
|
||||||
cover(func() {
|
cover(func() {
|
||||||
e(c, &ServerUpdatedEvent{Servers: servers})
|
if !e(c, &ServerUpdatedEvent{Servers: servers}) {
|
||||||
|
f = false
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if f {
|
||||||
|
c.SetCustomServer(adds)
|
||||||
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
ErrAlreadyOnline = errors.New("already online")
|
ErrAlreadyOnline = errors.New("already online")
|
||||||
ErrMemberNotFound = errors.New("member not found")
|
ErrMemberNotFound = errors.New("member not found")
|
||||||
|
ErrNotExists = errors.New("not exists")
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@ -251,7 +252,7 @@ const (
|
|||||||
Member
|
Member
|
||||||
|
|
||||||
AndroidPhone ClientProtocol = 1
|
AndroidPhone ClientProtocol = 1
|
||||||
AndroidPad ClientProtocol = 2
|
IPad ClientProtocol = 2
|
||||||
AndroidWatch ClientProtocol = 3
|
AndroidWatch ClientProtocol = 3
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ type eventHandlers struct {
|
|||||||
newFriendHandlers []func(*QQClient, *NewFriendEvent)
|
newFriendHandlers []func(*QQClient, *NewFriendEvent)
|
||||||
disconnectHandlers []func(*QQClient, *ClientDisconnectedEvent)
|
disconnectHandlers []func(*QQClient, *ClientDisconnectedEvent)
|
||||||
logHandlers []func(*QQClient, *LogEvent)
|
logHandlers []func(*QQClient, *LogEvent)
|
||||||
serverUpdatedHandlers []func(*QQClient, *ServerUpdatedEvent)
|
serverUpdatedHandlers []func(*QQClient, *ServerUpdatedEvent) bool
|
||||||
notifyHandlers []func(*QQClient, IGroupNotifyEvent)
|
notifyHandlers []func(*QQClient, IGroupNotifyEvent)
|
||||||
offlineFileHandlers []func(*QQClient, *OfflineFileEvent)
|
offlineFileHandlers []func(*QQClient, *OfflineFileEvent)
|
||||||
groupMessageReceiptHandlers sync.Map
|
groupMessageReceiptHandlers sync.Map
|
||||||
@ -107,7 +107,7 @@ func (c *QQClient) OnDisconnected(f func(*QQClient, *ClientDisconnectedEvent)) {
|
|||||||
c.eventHandlers.disconnectHandlers = append(c.eventHandlers.disconnectHandlers, f)
|
c.eventHandlers.disconnectHandlers = append(c.eventHandlers.disconnectHandlers, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *QQClient) OnServerUpdated(f func(*QQClient, *ServerUpdatedEvent)) {
|
func (c *QQClient) OnServerUpdated(f func(*QQClient, *ServerUpdatedEvent) bool) {
|
||||||
c.eventHandlers.serverUpdatedHandlers = append(c.eventHandlers.serverUpdatedHandlers, f)
|
c.eventHandlers.serverUpdatedHandlers = append(c.eventHandlers.serverUpdatedHandlers, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,9 +2,11 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Mrs4s/MiraiGo/binary"
|
"github.com/Mrs4s/MiraiGo/binary"
|
||||||
|
"github.com/Mrs4s/MiraiGo/binary/jce"
|
||||||
devinfo "github.com/Mrs4s/MiraiGo/client/pb"
|
devinfo "github.com/Mrs4s/MiraiGo/client/pb"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/oidb"
|
"github.com/Mrs4s/MiraiGo/client/pb/oidb"
|
||||||
@ -12,7 +14,9 @@ import (
|
|||||||
"github.com/Mrs4s/MiraiGo/utils"
|
"github.com/Mrs4s/MiraiGo/utils"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"net"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DeviceInfo struct {
|
type DeviceInfo struct {
|
||||||
@ -102,7 +106,7 @@ var SystemDeviceInfo = &DeviceInfo{
|
|||||||
IMEI: "468356291846738",
|
IMEI: "468356291846738",
|
||||||
AndroidId: []byte("MIRAI.123456.001"),
|
AndroidId: []byte("MIRAI.123456.001"),
|
||||||
APN: []byte("wifi"),
|
APN: []byte("wifi"),
|
||||||
Protocol: AndroidPad,
|
Protocol: IPad,
|
||||||
Version: &Version{
|
Version: &Version{
|
||||||
Incremental: []byte("5891938"),
|
Incremental: []byte("5891938"),
|
||||||
Release: []byte("10"),
|
Release: []byte("10"),
|
||||||
@ -167,10 +171,10 @@ func genVersionInfo(p ClientProtocol) *versionInfo {
|
|||||||
SubSigmap: 0x10400,
|
SubSigmap: 0x10400,
|
||||||
MainSigMap: 34869472,
|
MainSigMap: 34869472,
|
||||||
}
|
}
|
||||||
case AndroidPad: // Dumped from qq-hd v5.8.9
|
case IPad:
|
||||||
return &versionInfo{
|
return &versionInfo{
|
||||||
ApkId: "com.tencent.minihd.qq",
|
ApkId: "com.tencent.minihd.qq",
|
||||||
AppId: 537065549,
|
AppId: 537065739,
|
||||||
SortVersionName: "5.8.9",
|
SortVersionName: "5.8.9",
|
||||||
BuildTime: 1595836208,
|
BuildTime: 1595836208,
|
||||||
ApkSign: []byte{170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199},
|
ApkSign: []byte{170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199},
|
||||||
@ -197,7 +201,7 @@ func (info *DeviceInfo) ToJson() []byte {
|
|||||||
IMEI: info.IMEI,
|
IMEI: info.IMEI,
|
||||||
Protocol: func() int {
|
Protocol: func() int {
|
||||||
switch info.Protocol {
|
switch info.Protocol {
|
||||||
case AndroidPad:
|
case IPad:
|
||||||
return 0
|
return 0
|
||||||
case AndroidPhone:
|
case AndroidPhone:
|
||||||
return 1
|
return 1
|
||||||
@ -234,7 +238,7 @@ func (info *DeviceInfo) ReadJson(d []byte) error {
|
|||||||
case 2:
|
case 2:
|
||||||
info.Protocol = AndroidWatch
|
info.Protocol = AndroidWatch
|
||||||
default:
|
default:
|
||||||
info.Protocol = AndroidPad
|
info.Protocol = IPad
|
||||||
}
|
}
|
||||||
SystemDeviceInfo.GenNewGuid()
|
SystemDeviceInfo.GenNewGuid()
|
||||||
SystemDeviceInfo.GenNewTgtgtKey()
|
SystemDeviceInfo.GenNewTgtgtKey()
|
||||||
@ -272,6 +276,53 @@ func (info *DeviceInfo) GenDeviceInfoData() []byte {
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getSSOAddress() ([]*net.TCPAddr, error) {
|
||||||
|
protocol := genVersionInfo(SystemDeviceInfo.Protocol)
|
||||||
|
key, _ := hex.DecodeString("F0441F5FF42DA58FDCF7949ABA62D411")
|
||||||
|
payload := jce.NewJceWriter(). // see ServerConfig.d
|
||||||
|
WriteInt64(0, 1).WriteInt64(0, 2).WriteByte(1, 3).
|
||||||
|
WriteString("00000", 4).WriteInt32(100, 5).
|
||||||
|
WriteInt32(int32(protocol.AppId), 6).WriteString(SystemDeviceInfo.IMEI, 7).
|
||||||
|
WriteInt64(0, 8).WriteInt64(0, 9).WriteInt64(0, 10).
|
||||||
|
WriteInt64(0, 11).WriteByte(0, 12).WriteInt64(0, 13).WriteByte(1, 14).Bytes()
|
||||||
|
buf := &jce.RequestDataVersion2{
|
||||||
|
Map: map[string]map[string][]byte{"HttpServerListReq": {"ConfigHttp.HttpServerListReq": packUniRequestData(payload)}},
|
||||||
|
}
|
||||||
|
pkt := &jce.RequestPacket{
|
||||||
|
IVersion: 2,
|
||||||
|
SServantName: "ConfigHttp",
|
||||||
|
SFuncName: "HttpServerListReq",
|
||||||
|
SBuffer: buf.ToBytes(),
|
||||||
|
}
|
||||||
|
tea := binary.NewTeaCipher(key)
|
||||||
|
rsp, err := utils.HttpPostBytes("https://configsvr.msf.3g.qq.com/configsvr/serverlist.jsp", tea.Encrypt(binary.NewWriterF(func(w *binary.Writer) {
|
||||||
|
w.WriteIntLvPacket(0, func(w *binary.Writer) {
|
||||||
|
w.Write(pkt.ToBytes())
|
||||||
|
})
|
||||||
|
})))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rspPkt := &jce.RequestPacket{}
|
||||||
|
data := &jce.RequestDataVersion2{}
|
||||||
|
rspPkt.ReadFrom(jce.NewJceReader(tea.Decrypt(rsp)[4:]))
|
||||||
|
data.ReadFrom(jce.NewJceReader(rspPkt.SBuffer))
|
||||||
|
reader := jce.NewJceReader(data.Map["HttpServerListRes"]["ConfigHttp.HttpServerListRes"][1:])
|
||||||
|
servers := []jce.SsoServerInfo{}
|
||||||
|
reader.ReadSlice(&servers, 2)
|
||||||
|
var adds []*net.TCPAddr
|
||||||
|
for _, s := range servers {
|
||||||
|
if strings.Contains(s.Server, "com") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
adds = append(adds, &net.TCPAddr{
|
||||||
|
IP: net.ParseIP(s.Server),
|
||||||
|
Port: int(s.Port),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return adds, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *QQClient) parsePrivateMessage(msg *msg.Message) *message.PrivateMessage {
|
func (c *QQClient) parsePrivateMessage(msg *msg.Message) *message.PrivateMessage {
|
||||||
friend := c.FindFriend(msg.Head.FromUin)
|
friend := c.FindFriend(msg.Head.FromUin)
|
||||||
var sender *message.Sender
|
var sender *message.Sender
|
||||||
@ -459,7 +510,7 @@ func (b *groupMessageBuilder) build() *msg.Message {
|
|||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
func packRequestDataV3(data []byte) (r []byte) {
|
func packUniRequestData(data []byte) (r []byte) {
|
||||||
r = append([]byte{0x0A}, data...)
|
r = append([]byte{0x0A}, data...)
|
||||||
r = append(r, 0x0B)
|
r = append(r, 0x0B)
|
||||||
return
|
return
|
||||||
|
@ -142,6 +142,16 @@ func (fs *GroupFileSystem) GetDownloadUrl(file *GroupFile) string {
|
|||||||
return fs.client.GetGroupFileUrl(file.GroupCode, file.FileId, file.BusId)
|
return fs.client.GetGroupFileUrl(file.GroupCode, file.FileId, file.BusId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteFile 删除群文件,需要管理权限.
|
||||||
|
// 返回错误, 空为删除成功
|
||||||
|
func (fs *GroupFileSystem) DeleteFile(parentFolderId, fileId string, busId int32) string {
|
||||||
|
i, err := fs.client.sendAndWait(fs.client.buildGroupFileDeleteReqPacket(fs.GroupCode, parentFolderId, fileId, busId))
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
return i.(string)
|
||||||
|
}
|
||||||
|
|
||||||
// OidbSvc.0x6d8_1
|
// OidbSvc.0x6d8_1
|
||||||
func (c *QQClient) buildGroupFileListRequestPacket(groupCode int64, folderId string, startIndex uint32) (uint16, []byte) {
|
func (c *QQClient) buildGroupFileListRequestPacket(groupCode int64, folderId string, startIndex uint32) (uint16, []byte) {
|
||||||
seq := c.nextSeq()
|
seq := c.nextSeq()
|
||||||
@ -229,6 +239,27 @@ func (c *QQClient) buildGroupFileDownloadReqPacket(groupCode int64, fileId strin
|
|||||||
return seq, packet
|
return seq, packet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *QQClient) buildGroupFileDeleteReqPacket(groupCode int64, parentFolderId, fileId string, busId int32) (uint16, []byte) {
|
||||||
|
seq := c.nextSeq()
|
||||||
|
body := &oidb.D6D6ReqBody{DeleteFileReq: &oidb.DeleteFileReqBody{
|
||||||
|
GroupCode: groupCode,
|
||||||
|
AppId: 3,
|
||||||
|
BusId: busId,
|
||||||
|
ParentFolderId: parentFolderId,
|
||||||
|
FileId: fileId,
|
||||||
|
}}
|
||||||
|
b, _ := proto.Marshal(body)
|
||||||
|
req := &oidb.OIDBSSOPkg{
|
||||||
|
Command: 1750,
|
||||||
|
ServiceType: 3,
|
||||||
|
Bodybuffer: b,
|
||||||
|
ClientVersion: "android 8.4.8",
|
||||||
|
}
|
||||||
|
payload, _ := proto.Marshal(req)
|
||||||
|
packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x6d6_3", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
|
||||||
|
return seq, packet
|
||||||
|
}
|
||||||
|
|
||||||
func decodeOIDB6d81Response(c *QQClient, _ uint16, payload []byte) (interface{}, error) {
|
func decodeOIDB6d81Response(c *QQClient, _ uint16, payload []byte) (interface{}, error) {
|
||||||
pkg := oidb.OIDBSSOPkg{}
|
pkg := oidb.OIDBSSOPkg{}
|
||||||
rsp := oidb.D6D8RspBody{}
|
rsp := oidb.D6D8RspBody{}
|
||||||
@ -242,7 +273,7 @@ func decodeOIDB6d81Response(c *QQClient, _ uint16, payload []byte) (interface{},
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OidbSvc.0x6d6_2
|
// OidbSvc.0x6d6_2
|
||||||
func decodeOIDB6d6Response(_ *QQClient, _ uint16, payload []byte) (interface{}, error) {
|
func decodeOIDB6d62Response(_ *QQClient, _ uint16, payload []byte) (interface{}, error) {
|
||||||
pkg := oidb.OIDBSSOPkg{}
|
pkg := oidb.OIDBSSOPkg{}
|
||||||
rsp := oidb.D6D6RspBody{}
|
rsp := oidb.D6D6RspBody{}
|
||||||
if err := proto.Unmarshal(payload, &pkg); err != nil {
|
if err := proto.Unmarshal(payload, &pkg); err != nil {
|
||||||
@ -258,3 +289,18 @@ func decodeOIDB6d6Response(_ *QQClient, _ uint16, payload []byte) (interface{},
|
|||||||
url := hex.EncodeToString(rsp.DownloadFileRsp.DownloadUrl)
|
url := hex.EncodeToString(rsp.DownloadFileRsp.DownloadUrl)
|
||||||
return fmt.Sprintf("http://%s/ftn_handler/%s/", ip, url), nil
|
return fmt.Sprintf("http://%s/ftn_handler/%s/", ip, url), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decodeOIDB6d63Response(_ *QQClient, _ uint16, payload []byte) (interface{}, error) {
|
||||||
|
pkg := oidb.OIDBSSOPkg{}
|
||||||
|
rsp := oidb.D6D6RspBody{}
|
||||||
|
if err := proto.Unmarshal(payload, &pkg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if rsp.DeleteFileRsp == nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return rsp.DeleteFileRsp.ClientWording, nil
|
||||||
|
}
|
||||||
|
@ -77,8 +77,8 @@ func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) {
|
|||||||
head := jce.NewJceWriter()
|
head := jce.NewJceWriter()
|
||||||
head.WriteInt32(2, 0)
|
head.WriteInt32(2, 0)
|
||||||
buf := &jce.RequestDataVersion3{Map: map[string][]byte{
|
buf := &jce.RequestDataVersion3{Map: map[string][]byte{
|
||||||
"ReqHead": packRequestDataV3(head.Bytes()),
|
"ReqHead": packUniRequestData(head.Bytes()),
|
||||||
"ReqSearch": packRequestDataV3(req.ToBytes()),
|
"ReqSearch": packUniRequestData(req.ToBytes()),
|
||||||
}}
|
}}
|
||||||
pkt := &jce.RequestPacket{
|
pkt := &jce.RequestPacket{
|
||||||
IVersion: 3,
|
IVersion: 3,
|
||||||
|
@ -33,7 +33,7 @@ type (
|
|||||||
// grayTipProcessor 提取出来专门用于处理群内 notify tips
|
// grayTipProcessor 提取出来专门用于处理群内 notify tips
|
||||||
func (c *QQClient) grayTipProcessor(groupId int64, tipInfo *notify.GeneralGrayTipInfo) {
|
func (c *QQClient) grayTipProcessor(groupId int64, tipInfo *notify.GeneralGrayTipInfo) {
|
||||||
switch tipInfo.TemplId {
|
switch tipInfo.TemplId {
|
||||||
case 10043, 1136: // 戳一戳
|
case 10043, 1136, 1132: // 戳一戳
|
||||||
var sender int64 = 0
|
var sender int64 = 0
|
||||||
receiver := c.Uin
|
receiver := c.Uin
|
||||||
for _, templ := range tipInfo.MsgTemplParam {
|
for _, templ := range tipInfo.MsgTemplParam {
|
||||||
|
@ -432,6 +432,9 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if elem.CustomFace != nil {
|
if elem.CustomFace != nil {
|
||||||
|
if len(elem.CustomFace.Md5) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
res = append(res, &ImageElement{
|
res = append(res, &ImageElement{
|
||||||
Filename: elem.CustomFace.FilePath,
|
Filename: elem.CustomFace.FilePath,
|
||||||
Size: elem.CustomFace.Size,
|
Size: elem.CustomFace.Size,
|
||||||
|
@ -11,6 +11,7 @@ var ErrUnknownFlag = errors.New("unknown flag")
|
|||||||
var ErrInvalidPayload = errors.New("invalid payload")
|
var ErrInvalidPayload = errors.New("invalid payload")
|
||||||
var ErrDecryptFailed = errors.New("decrypt failed")
|
var ErrDecryptFailed = errors.New("decrypt failed")
|
||||||
var ErrSessionExpired = errors.New("session expired")
|
var ErrSessionExpired = errors.New("session expired")
|
||||||
|
var ErrPacketDropped = errors.New("packet dropped")
|
||||||
|
|
||||||
type ISendingPacket interface {
|
type ISendingPacket interface {
|
||||||
CommandId() uint16
|
CommandId() uint16
|
||||||
@ -121,7 +122,7 @@ func ParseIncomingPacket(payload, d2key []byte) (*IncomingPacket, error) {
|
|||||||
func parseSsoFrame(payload []byte, flag2 byte) (*IncomingPacket, error) {
|
func parseSsoFrame(payload []byte, flag2 byte) (*IncomingPacket, error) {
|
||||||
reader := binary.NewReader(payload)
|
reader := binary.NewReader(payload)
|
||||||
if reader.ReadInt32()-4 > int32(reader.Len()) {
|
if reader.ReadInt32()-4 > int32(reader.Len()) {
|
||||||
return nil, errors.New("dropped")
|
return nil, ErrPacketDropped
|
||||||
}
|
}
|
||||||
seqId := reader.ReadInt32()
|
seqId := reader.ReadInt32()
|
||||||
retCode := reader.ReadInt32()
|
retCode := reader.ReadInt32()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user