mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-04 19:17:38 +08:00
Merge branch 'Mrs4s:master' into master
This commit is contained in:
commit
a277c77cb5
@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"github.com/Mrs4s/MiraiGo/binary"
|
"github.com/Mrs4s/MiraiGo/binary"
|
||||||
"github.com/Mrs4s/MiraiGo/binary/jce"
|
"github.com/Mrs4s/MiraiGo/binary/jce"
|
||||||
"github.com/Mrs4s/MiraiGo/client/internal/auth"
|
|
||||||
"github.com/Mrs4s/MiraiGo/client/internal/network"
|
"github.com/Mrs4s/MiraiGo/client/internal/network"
|
||||||
"github.com/Mrs4s/MiraiGo/client/internal/oicq"
|
"github.com/Mrs4s/MiraiGo/client/internal/oicq"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb"
|
"github.com/Mrs4s/MiraiGo/client/pb"
|
||||||
@ -19,6 +18,7 @@ import (
|
|||||||
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
"github.com/Mrs4s/MiraiGo/client/pb/structmsg"
|
||||||
"github.com/Mrs4s/MiraiGo/internal/proto"
|
"github.com/Mrs4s/MiraiGo/internal/proto"
|
||||||
"github.com/Mrs4s/MiraiGo/internal/tlv"
|
"github.com/Mrs4s/MiraiGo/internal/tlv"
|
||||||
|
"github.com/Mrs4s/MiraiGo/wrapper"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -102,6 +102,25 @@ func (c *QQClient) buildLoginPacket() (uint16, []byte) {
|
|||||||
tlv.T521(0),
|
tlv.T521(0),
|
||||||
tlv.T525(tlv.T536([]byte{0x01, 0x00})),
|
tlv.T525(tlv.T536([]byte{0x01, 0x00})),
|
||||||
)
|
)
|
||||||
|
if wrapper.DandelionEnergy != nil {
|
||||||
|
salt := binary.NewWriterF(func(w *binary.Writer) {
|
||||||
|
// util.int64_to_buf(bArr42, 0, (int) uin2);
|
||||||
|
// util.int16_to_buf(bArr42, 4, u.guid.length); // 故意的还是不小心的
|
||||||
|
w.Write(binary.NewWriterF(func(w *binary.Writer) { w.WriteUInt64(uint64(c.Uin)) })[:4])
|
||||||
|
w.WriteBytesShort(c.Device().Guid)
|
||||||
|
w.WriteBytesShort([]byte(c.version().SdkVersion))
|
||||||
|
w.WriteUInt32(9) // sub command
|
||||||
|
w.WriteUInt32(0) // 被演了
|
||||||
|
})
|
||||||
|
if t544 := tlv.T544Custom(uint64(c.Uin), "810_9", salt, wrapper.DandelionEnergy); t544 != nil {
|
||||||
|
t.Append(t544)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Device().QImei36 != "" {
|
||||||
|
t.Append(tlv.T545([]byte(c.Device().QImei16)))
|
||||||
|
} else {
|
||||||
|
t.Append(tlv.T545([]byte(c.Device().IMEI)))
|
||||||
|
}
|
||||||
req := c.buildOicqRequestPacket(c.Uin, 0x0810, t)
|
req := c.buildOicqRequestPacket(c.Uin, 0x0810, t)
|
||||||
r := network.Request{
|
r := network.Request{
|
||||||
Type: network.RequestTypeLogin,
|
Type: network.RequestTypeLogin,
|
||||||
@ -137,17 +156,15 @@ func (c *QQClient) buildDeviceLockLoginPacket() (uint16, []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *QQClient) buildQRCodeFetchRequestPacket(size, margin, ecLevel uint32) (uint16, []byte) {
|
func (c *QQClient) buildQRCodeFetchRequestPacket(size, margin, ecLevel uint32) (uint16, []byte) {
|
||||||
old := c.version()
|
// old := c.version()
|
||||||
watch := auth.AndroidWatch.Version()
|
// watch := auth.AndroidWatch.Version()
|
||||||
c.transport.Version = watch
|
// c.transport.Version = watch
|
||||||
seq := c.nextSeq()
|
seq := c.nextSeq()
|
||||||
req := oicq.Message{
|
req := oicq.Message{
|
||||||
Command: 0x0812,
|
Command: 0x0812,
|
||||||
EncryptionMethod: oicq.EM_ECDH,
|
EncryptionMethod: oicq.EM_ECDH,
|
||||||
Body: binary.NewWriterF(func(w *binary.Writer) {
|
Body: binary.NewWriterF(func(w *binary.Writer) {
|
||||||
w.WriteHex(`0001110000001000000072000000`) // trans header
|
code2dPacket := buildCode2DRequestPacket(0, 0, 0x31, func(w *binary.Writer) {
|
||||||
w.WriteUInt32(uint32(time.Now().Unix()))
|
|
||||||
w.Write(buildCode2DRequestPacket(0, 0, 0x31, func(w *binary.Writer) {
|
|
||||||
w.WriteUInt16(0) // const
|
w.WriteUInt16(0) // const
|
||||||
w.WriteUInt32(16) // app id
|
w.WriteUInt32(16) // app id
|
||||||
w.WriteUInt64(0) // const
|
w.WriteUInt64(0) // const
|
||||||
@ -155,13 +172,20 @@ func (c *QQClient) buildQRCodeFetchRequestPacket(size, margin, ecLevel uint32) (
|
|||||||
w.WriteBytesShort(EmptyBytes)
|
w.WriteBytesShort(EmptyBytes)
|
||||||
|
|
||||||
w.WriteUInt16(6)
|
w.WriteUInt16(6)
|
||||||
w.Write(tlv.T16(watch.SSOVersion, 16, watch.AppId, c.Device().Guid, []byte(watch.ApkId), []byte(watch.SortVersionName), watch.ApkSign))
|
w.Write(tlv.T16(c.transport.Version.SSOVersion, 16, c.transport.Version.AppId, c.Device().Guid, []byte(c.transport.Version.ApkId), []byte(c.transport.Version.SortVersionName), c.transport.Version.ApkSign))
|
||||||
w.Write(tlv.T1B(0, 0, size, margin, 72, ecLevel, 2))
|
w.Write(tlv.T1B(0, 0, size, margin, 72, ecLevel, 2))
|
||||||
w.Write(tlv.T1D(watch.MiscBitmap))
|
w.Write(tlv.T1D(c.transport.Version.MiscBitmap))
|
||||||
w.Write(tlv.T1F(false, c.Device().OSType, []byte("7.1.2"), []byte("China Mobile GSM"), c.Device().APN, 2))
|
w.Write(tlv.T1F(false, c.Device().OSType, []byte("7.1.2"), []byte("China Mobile GSM"), c.Device().APN, 2))
|
||||||
w.Write(tlv.T33(c.Device().Guid))
|
w.Write(tlv.T33(c.Device().Guid))
|
||||||
w.Write(tlv.T35(8))
|
w.Write(tlv.T35(8))
|
||||||
}))
|
})
|
||||||
|
w.WriteByte(0x0)
|
||||||
|
w.WriteUInt16(uint16(len(code2dPacket)) + 4)
|
||||||
|
w.WriteUInt32(16)
|
||||||
|
w.WriteUInt32(0x72)
|
||||||
|
w.WriteHex("000000")
|
||||||
|
w.WriteUInt32(uint32(time.Now().Unix()))
|
||||||
|
w.Write(code2dPacket)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
r := network.Request{
|
r := network.Request{
|
||||||
@ -173,21 +197,19 @@ func (c *QQClient) buildQRCodeFetchRequestPacket(size, margin, ecLevel uint32) (
|
|||||||
Body: c.oicq.Marshal(&req),
|
Body: c.oicq.Marshal(&req),
|
||||||
}
|
}
|
||||||
payload := c.transport.PackPacket(&r)
|
payload := c.transport.PackPacket(&r)
|
||||||
c.transport.Version = old
|
// c.transport.Version = old
|
||||||
return seq, payload
|
return seq, payload
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *QQClient) buildQRCodeResultQueryRequestPacket(sig []byte) (uint16, []byte) {
|
func (c *QQClient) buildQRCodeResultQueryRequestPacket(sig []byte) (uint16, []byte) {
|
||||||
old := c.version()
|
// old := c.version()
|
||||||
c.transport.Version = auth.AndroidWatch.Version()
|
// c.transport.Version = auth.AndroidWatch.Version()
|
||||||
seq := c.nextSeq()
|
seq := c.nextSeq()
|
||||||
req := oicq.Message{
|
req := oicq.Message{
|
||||||
Command: 0x0812,
|
Command: 0x0812,
|
||||||
EncryptionMethod: oicq.EM_ECDH,
|
EncryptionMethod: oicq.EM_ECDH,
|
||||||
Body: binary.NewWriterF(func(w *binary.Writer) {
|
Body: binary.NewWriterF(func(w *binary.Writer) {
|
||||||
w.WriteHex(`0000620000001000000072000000`) // trans header
|
code2dPacket := buildCode2DRequestPacket(1, 0, 0x12, func(w *binary.Writer) {
|
||||||
w.WriteUInt32(uint32(time.Now().Unix()))
|
|
||||||
w.Write(buildCode2DRequestPacket(1, 0, 0x12, func(w *binary.Writer) {
|
|
||||||
w.WriteUInt16(5) // const
|
w.WriteUInt16(5) // const
|
||||||
w.WriteByte(1) // const
|
w.WriteByte(1) // const
|
||||||
w.WriteUInt32(8) // product type
|
w.WriteUInt32(8) // product type
|
||||||
@ -197,7 +219,14 @@ func (c *QQClient) buildQRCodeResultQueryRequestPacket(sig []byte) (uint16, []by
|
|||||||
w.WriteByte(8) // const
|
w.WriteByte(8) // const
|
||||||
w.WriteBytesShort(EmptyBytes)
|
w.WriteBytesShort(EmptyBytes)
|
||||||
w.WriteUInt16(0) // const
|
w.WriteUInt16(0) // const
|
||||||
}))
|
})
|
||||||
|
w.WriteByte(0x0)
|
||||||
|
w.WriteUInt16(uint16(len(code2dPacket)) + 4)
|
||||||
|
w.WriteUInt32(16)
|
||||||
|
w.WriteUInt32(0x72)
|
||||||
|
w.WriteHex("000000")
|
||||||
|
w.WriteUInt32(uint32(time.Now().Unix()))
|
||||||
|
w.Write(code2dPacket)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
r := network.Request{
|
r := network.Request{
|
||||||
@ -209,7 +238,7 @@ func (c *QQClient) buildQRCodeResultQueryRequestPacket(sig []byte) (uint16, []by
|
|||||||
Body: c.oicq.Marshal(&req),
|
Body: c.oicq.Marshal(&req),
|
||||||
}
|
}
|
||||||
payload := c.transport.PackPacket(&r)
|
payload := c.transport.PackPacket(&r)
|
||||||
c.transport.Version = old
|
// c.transport.Version = old
|
||||||
return seq, payload
|
return seq, payload
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +355,7 @@ func (c *QQClient) buildSMSRequestPacket() (uint16, []byte) {
|
|||||||
|
|
||||||
func (c *QQClient) buildSMSCodeSubmitPacket(code string) (uint16, []byte) {
|
func (c *QQClient) buildSMSCodeSubmitPacket(code string) (uint16, []byte) {
|
||||||
seq := c.nextSeq()
|
seq := c.nextSeq()
|
||||||
req := c.buildOicqRequestPacket(c.Uin, 0x0810, &oicq.TLV{
|
t := &oicq.TLV{
|
||||||
Command: 7,
|
Command: 7,
|
||||||
List: [][]byte{
|
List: [][]byte{
|
||||||
tlv.T8(2052),
|
tlv.T8(2052),
|
||||||
@ -337,7 +366,13 @@ func (c *QQClient) buildSMSCodeSubmitPacket(code string) (uint16, []byte) {
|
|||||||
tlv.T401(c.sig.G),
|
tlv.T401(c.sig.G),
|
||||||
tlv.T198(),
|
tlv.T198(),
|
||||||
},
|
},
|
||||||
})
|
}
|
||||||
|
if wrapper.DandelionEnergy != nil {
|
||||||
|
if t544 := tlv.T544(uint64(c.Uin), "810_7", 7, c.version().SdkVersion, c.Device().Guid, wrapper.DandelionEnergy); t544 != nil {
|
||||||
|
t.Append(t544)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req := c.buildOicqRequestPacket(c.Uin, 0x0810, t)
|
||||||
r := network.Request{
|
r := network.Request{
|
||||||
Type: network.RequestTypeLogin,
|
Type: network.RequestTypeLogin,
|
||||||
EncryptType: network.EncryptTypeEmptyKey,
|
EncryptType: network.EncryptTypeEmptyKey,
|
||||||
@ -363,6 +398,11 @@ func (c *QQClient) buildTicketSubmitPacket(ticket string) (uint16, []byte) {
|
|||||||
if c.sig.T547 != nil {
|
if c.sig.T547 != nil {
|
||||||
t.Append(tlv.T(0x547, c.sig.T547))
|
t.Append(tlv.T(0x547, c.sig.T547))
|
||||||
}
|
}
|
||||||
|
if wrapper.DandelionEnergy != nil {
|
||||||
|
if t544 := tlv.T544(uint64(c.Uin), "810_2", 2, c.version().SdkVersion, c.Device().Guid, wrapper.DandelionEnergy); t544 != nil {
|
||||||
|
t.Append(t544)
|
||||||
|
}
|
||||||
|
}
|
||||||
req := c.buildOicqRequestPacket(c.Uin, 0x0810, t)
|
req := c.buildOicqRequestPacket(c.Uin, 0x0810, t)
|
||||||
r := network.Request{
|
r := network.Request{
|
||||||
Type: network.RequestTypeLogin,
|
Type: network.RequestTypeLogin,
|
||||||
@ -421,16 +461,20 @@ func (c *QQClient) buildRequestTgtgtNopicsigPacket() (uint16, []byte) {
|
|||||||
tlv.T516(),
|
tlv.T516(),
|
||||||
tlv.T521(0),
|
tlv.T521(0),
|
||||||
tlv.T525(tlv.T536([]byte{0x01, 0x00})),
|
tlv.T525(tlv.T536([]byte{0x01, 0x00})),
|
||||||
tlv.T545([]byte(c.Device().IMEI)),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if c.Device().QImei36 != "" {
|
||||||
|
t.Append(tlv.T545([]byte(c.Device().QImei16)))
|
||||||
|
} else {
|
||||||
|
t.Append(tlv.T545([]byte(c.Device().IMEI)))
|
||||||
|
}
|
||||||
m := oicq.Message{
|
m := oicq.Message{
|
||||||
Uin: uint32(c.Uin),
|
Uin: uint32(c.Uin),
|
||||||
Command: 0x810,
|
Command: 0x810,
|
||||||
EncryptionMethod: oicq.EM_ST,
|
EncryptionMethod: oicq.EM_ST,
|
||||||
Body: t.Marshal(),
|
Body: t.Marshal(),
|
||||||
}
|
}
|
||||||
nreq := network.Request{
|
req := network.Request{
|
||||||
Type: network.RequestTypeSimple,
|
Type: network.RequestTypeSimple,
|
||||||
EncryptType: network.EncryptTypeEmptyKey,
|
EncryptType: network.EncryptTypeEmptyKey,
|
||||||
Uin: c.Uin,
|
Uin: c.Uin,
|
||||||
@ -438,7 +482,7 @@ func (c *QQClient) buildRequestTgtgtNopicsigPacket() (uint16, []byte) {
|
|||||||
CommandName: "wtlogin.exchange_emp",
|
CommandName: "wtlogin.exchange_emp",
|
||||||
Body: c.oicq.Marshal(&m),
|
Body: c.oicq.Marshal(&m),
|
||||||
}
|
}
|
||||||
return seq, c.transport.PackPacket(&nreq)
|
return seq, c.transport.PackPacket(&req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *QQClient) buildRequestChangeSigPacket(changeD2 bool) (uint16, []byte) {
|
func (c *QQClient) buildRequestChangeSigPacket(changeD2 bool) (uint16, []byte) {
|
||||||
|
@ -106,6 +106,8 @@ type QQClient struct {
|
|||||||
GroupDigestEvent EventHandle[*GroupDigestEvent]
|
GroupDigestEvent EventHandle[*GroupDigestEvent]
|
||||||
OtherClientStatusChangedEvent EventHandle[*OtherClientStatusChangedEvent]
|
OtherClientStatusChangedEvent EventHandle[*OtherClientStatusChangedEvent]
|
||||||
OfflineFileEvent EventHandle[*OfflineFileEvent]
|
OfflineFileEvent EventHandle[*OfflineFileEvent]
|
||||||
|
GroupDisbandEvent EventHandle[*GroupDisbandEvent]
|
||||||
|
DeleteFriendEvent EventHandle[*DeleteFriendEvent]
|
||||||
|
|
||||||
// message state
|
// message state
|
||||||
msgSvcCache *utils.Cache[unit]
|
msgSvcCache *utils.Cache[unit]
|
||||||
|
@ -51,6 +51,7 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
|
|||||||
if m.Exists(0x546) {
|
if m.Exists(0x546) {
|
||||||
c.sig.T547 = auth.CalcPow(m[0x546])
|
c.sig.T547 = auth.CalcPow(m[0x546])
|
||||||
}
|
}
|
||||||
|
// c.logger.Info("login response %v", t)
|
||||||
if t == 0 { // login success
|
if t == 0 { // login success
|
||||||
// if t150, ok := m[0x150]; ok {
|
// if t150, ok := m[0x150]; ok {
|
||||||
// c.t150 = t150
|
// c.t150 = t150
|
||||||
@ -71,6 +72,7 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
|
|||||||
if m.Exists(0x192) {
|
if m.Exists(0x192) {
|
||||||
return LoginResponse{
|
return LoginResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
Code: t,
|
||||||
VerifyUrl: string(m[0x192]),
|
VerifyUrl: string(m[0x192]),
|
||||||
Error: SliderNeededError,
|
Error: SliderNeededError,
|
||||||
}, nil
|
}, nil
|
||||||
@ -82,6 +84,7 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
|
|||||||
sign := imgData.ReadBytes(int(signLen))
|
sign := imgData.ReadBytes(int(signLen))
|
||||||
return LoginResponse{
|
return LoginResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
Code: t,
|
||||||
Error: NeedCaptcha,
|
Error: NeedCaptcha,
|
||||||
CaptchaImage: imgData.ReadAvailable(),
|
CaptchaImage: imgData.ReadAvailable(),
|
||||||
CaptchaSign: sign,
|
CaptchaSign: sign,
|
||||||
@ -89,6 +92,7 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
|
|||||||
} else {
|
} else {
|
||||||
return LoginResponse{
|
return LoginResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
Code: t,
|
||||||
Error: UnknownLoginError,
|
Error: UnknownLoginError,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -97,6 +101,7 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
|
|||||||
if t == 40 {
|
if t == 40 {
|
||||||
return LoginResponse{
|
return LoginResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
Code: t,
|
||||||
ErrorMessage: "账号被冻结",
|
ErrorMessage: "账号被冻结",
|
||||||
Error: UnknownLoginError,
|
Error: UnknownLoginError,
|
||||||
}, nil
|
}, nil
|
||||||
@ -115,6 +120,7 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
|
|||||||
if t204, ok := m[0x204]; ok { // 同时支持扫码验证 ?
|
if t204, ok := m[0x204]; ok { // 同时支持扫码验证 ?
|
||||||
return LoginResponse{
|
return LoginResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
Code: t,
|
||||||
Error: SMSOrVerifyNeededError,
|
Error: SMSOrVerifyNeededError,
|
||||||
VerifyUrl: string(t204),
|
VerifyUrl: string(t204),
|
||||||
SMSPhone: phone,
|
SMSPhone: phone,
|
||||||
@ -123,6 +129,7 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
|
|||||||
}
|
}
|
||||||
return LoginResponse{
|
return LoginResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
Code: t,
|
||||||
Error: SMSNeededError,
|
Error: SMSNeededError,
|
||||||
SMSPhone: phone,
|
SMSPhone: phone,
|
||||||
ErrorMessage: string(m[0x17e]),
|
ErrorMessage: string(m[0x17e]),
|
||||||
@ -133,6 +140,7 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
|
|||||||
c.sig.T104 = m[0x104]
|
c.sig.T104 = m[0x104]
|
||||||
return LoginResponse{
|
return LoginResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
Code: t,
|
||||||
Error: SMSNeededError,
|
Error: SMSNeededError,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -140,6 +148,7 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
|
|||||||
if t204, ok := m[0x204]; ok { // 扫码验证
|
if t204, ok := m[0x204]; ok { // 扫码验证
|
||||||
return LoginResponse{
|
return LoginResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
Code: t,
|
||||||
Error: UnsafeDeviceError,
|
Error: UnsafeDeviceError,
|
||||||
VerifyUrl: string(t204),
|
VerifyUrl: string(t204),
|
||||||
ErrorMessage: "",
|
ErrorMessage: "",
|
||||||
@ -149,6 +158,7 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
|
|||||||
|
|
||||||
if t == 162 {
|
if t == 162 {
|
||||||
return LoginResponse{
|
return LoginResponse{
|
||||||
|
Code: t,
|
||||||
Error: TooManySMSRequestError,
|
Error: TooManySMSRequestError,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -165,6 +175,7 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
|
|||||||
t149r.ReadStringShort() // title
|
t149r.ReadStringShort() // title
|
||||||
return LoginResponse{
|
return LoginResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
Code: t,
|
||||||
Error: OtherLoginError,
|
Error: OtherLoginError,
|
||||||
ErrorMessage: t149r.ReadStringShort(),
|
ErrorMessage: t149r.ReadStringShort(),
|
||||||
}, nil
|
}, nil
|
||||||
@ -176,6 +187,7 @@ func decodeLoginResponse(c *QQClient, pkt *network.Packet) (any, error) {
|
|||||||
t146r.ReadStringShort() // title
|
t146r.ReadStringShort() // title
|
||||||
return LoginResponse{
|
return LoginResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
Code: t,
|
||||||
Error: OtherLoginError,
|
Error: OtherLoginError,
|
||||||
ErrorMessage: t146r.ReadStringShort(),
|
ErrorMessage: t146r.ReadStringShort(),
|
||||||
}, nil
|
}, nil
|
||||||
@ -732,6 +744,15 @@ func decodeOnlinePushTransPacket(c *QQClient, pkt *network.Packet) (any, error)
|
|||||||
Operator: g.FindMember(operator),
|
Operator: g.FindMember(operator),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
case 0x01, 0x81: // kosbot add: 群解散. 暂时这样 See https://github.com/lz1998/ricq/blob/064ddddca19aa0410e2514852e3a151fd9913371/ricq-core/src/command/online_push/decoder.rs#L86
|
||||||
|
c.GroupDisbandEvent.dispatch(c, &GroupDisbandEvent{
|
||||||
|
Group: g,
|
||||||
|
Operator: g.FindMember(operator),
|
||||||
|
Time: int64(info.MsgTime.Unwrap()),
|
||||||
|
})
|
||||||
|
if err = c.ReloadGroupList(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,11 @@ type (
|
|||||||
|
|
||||||
UserOnlineStatus int
|
UserOnlineStatus int
|
||||||
|
|
||||||
ClientProtocol = auth.Protocol
|
ClientProtocol = auth.ProtocolType
|
||||||
|
|
||||||
LoginResponse struct {
|
LoginResponse struct {
|
||||||
Success bool
|
Success bool
|
||||||
|
Code byte
|
||||||
Error LoginError
|
Error LoginError
|
||||||
|
|
||||||
// Captcha info
|
// Captcha info
|
||||||
@ -191,6 +192,17 @@ type (
|
|||||||
DownloadUrl string
|
DownloadUrl string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroupDisbandEvent struct {
|
||||||
|
Group *GroupInfo
|
||||||
|
Time int64
|
||||||
|
Operator *GroupMemberInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteFriendEvent struct {
|
||||||
|
Uin int64
|
||||||
|
Nickname string
|
||||||
|
}
|
||||||
|
|
||||||
// GroupDigest 群精华消息
|
// GroupDigest 群精华消息
|
||||||
GroupDigest struct {
|
GroupDigest struct {
|
||||||
GroupCode int64 `json:"group_code,string"`
|
GroupCode int64 `json:"group_code,string"`
|
||||||
|
@ -81,6 +81,7 @@ func GenRandomDevice() *DeviceInfo {
|
|||||||
hex.Encode(device.AndroidId, r)
|
hex.Encode(device.AndroidId, r)
|
||||||
device.GenNewGuid()
|
device.GenNewGuid()
|
||||||
device.GenNewTgtgtKey()
|
device.GenNewTgtgtKey()
|
||||||
|
device.RequestQImei()
|
||||||
return device
|
return device
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,6 +106,13 @@ func GenIMEI() string {
|
|||||||
return final.String()
|
return final.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UpdateAppVersion(protocolType auth.ProtocolType, data []byte) error {
|
||||||
|
if _, ok := auth.AppVersions[protocolType]; !ok {
|
||||||
|
return errors.New("unknown protocol type: " + strconv.Itoa(int(protocolType)))
|
||||||
|
}
|
||||||
|
return auth.AppVersions[protocolType].ReadJson(data)
|
||||||
|
}
|
||||||
|
|
||||||
func getSSOAddress(device *auth.Device) ([]netip.AddrPort, error) {
|
func getSSOAddress(device *auth.Device) ([]netip.AddrPort, error) {
|
||||||
protocol := device.Protocol.Version()
|
protocol := device.Protocol.Version()
|
||||||
key, _ := hex.DecodeString("F0441F5FF42DA58FDCF7949ABA62D411")
|
key, _ := hex.DecodeString("F0441F5FF42DA58FDCF7949ABA62D411")
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
//go:generate stringer -type=Protocol -linecomment
|
import (
|
||||||
type Protocol int
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate stringer -type=ProtocolType -linecomment
|
||||||
|
type ProtocolType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Unset Protocol = iota
|
Unset ProtocolType = iota
|
||||||
AndroidPhone // Android Phone
|
AndroidPhone // Android Phone
|
||||||
AndroidWatch // Android Watch
|
AndroidWatch // Android Watch
|
||||||
MacOS // MacOS
|
MacOS // MacOS
|
||||||
@ -13,6 +21,101 @@ const (
|
|||||||
AndroidPad // Android Pad
|
AndroidPad // Android Pad
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
AppVersions = map[ProtocolType]*AppVersion{
|
||||||
|
AndroidPhone: {
|
||||||
|
ApkId: "com.tencent.mobileqq",
|
||||||
|
AppId: 537151682,
|
||||||
|
SubAppId: 537151682,
|
||||||
|
AppKey: "0S200MNJT807V3GE",
|
||||||
|
SortVersionName: "8.9.33.10335",
|
||||||
|
BuildTime: 1673599898,
|
||||||
|
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
|
||||||
|
SdkVersion: "6.0.0.2534",
|
||||||
|
SSOVersion: 19,
|
||||||
|
MiscBitmap: 150470524,
|
||||||
|
SubSigmap: 0x10400,
|
||||||
|
MainSigMap: WLOGIN_A5 | WLOGIN_RESERVED | WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST |
|
||||||
|
WLOGIN_LSKEY | WLOGIN_SKEY | WLOGIN_SIG64 | 1<<16 | WLOGIN_VKEY | WLOGIN_D2 |
|
||||||
|
WLOGIN_SID | WLOGIN_PSKEY | WLOGIN_AQSIG | WLOGIN_LHSIG | WLOGIN_PAYTOKEN, // 16724722
|
||||||
|
Protocol: AndroidPhone,
|
||||||
|
},
|
||||||
|
AndroidPad: {
|
||||||
|
ApkId: "com.tencent.mobileqq",
|
||||||
|
AppId: 537151218,
|
||||||
|
SubAppId: 537151218,
|
||||||
|
AppKey: "0S200MNJT807V3GE",
|
||||||
|
SortVersionName: "8.9.33.10335",
|
||||||
|
BuildTime: 1673599898,
|
||||||
|
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
|
||||||
|
SdkVersion: "6.0.0.2534",
|
||||||
|
SSOVersion: 19,
|
||||||
|
MiscBitmap: 150470524,
|
||||||
|
SubSigmap: 0x10400,
|
||||||
|
MainSigMap: WLOGIN_A5 | WLOGIN_RESERVED | WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST |
|
||||||
|
WLOGIN_LSKEY | WLOGIN_SKEY | WLOGIN_SIG64 | 1<<16 | WLOGIN_VKEY | WLOGIN_D2 |
|
||||||
|
WLOGIN_SID | WLOGIN_PSKEY | WLOGIN_AQSIG | WLOGIN_LHSIG | WLOGIN_PAYTOKEN, // 16724722
|
||||||
|
Protocol: AndroidPad,
|
||||||
|
},
|
||||||
|
AndroidWatch: {
|
||||||
|
ApkId: "com.tencent.qqlite",
|
||||||
|
AppId: 537064446,
|
||||||
|
SubAppId: 537064446,
|
||||||
|
SortVersionName: "2.0.5",
|
||||||
|
BuildTime: 1559564731,
|
||||||
|
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
|
||||||
|
SdkVersion: "6.0.0.236",
|
||||||
|
SSOVersion: 5,
|
||||||
|
MiscBitmap: 16252796,
|
||||||
|
SubSigmap: 0x10400,
|
||||||
|
MainSigMap: WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST | WLOGIN_SKEY | WLOGIN_D2 | WLOGIN_PSKEY | WLOGIN_DA2, // 34869472
|
||||||
|
Protocol: AndroidWatch,
|
||||||
|
},
|
||||||
|
IPad: {
|
||||||
|
ApkId: "com.tencent.minihd.qq",
|
||||||
|
AppId: 537118796,
|
||||||
|
SubAppId: 537118796,
|
||||||
|
SortVersionName: "5.9.3",
|
||||||
|
BuildTime: 1595836208,
|
||||||
|
ApkSign: []byte{170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199},
|
||||||
|
SdkVersion: "6.0.0.2433",
|
||||||
|
SSOVersion: 12,
|
||||||
|
MiscBitmap: 150470524,
|
||||||
|
SubSigmap: 66560,
|
||||||
|
MainSigMap: WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST | WLOGIN_SKEY | WLOGIN_VKEY | WLOGIN_D2 | WLOGIN_SID | WLOGIN_PSKEY, // 1970400
|
||||||
|
Protocol: IPad,
|
||||||
|
},
|
||||||
|
MacOS: {
|
||||||
|
ApkId: "com.tencent.minihd.qq",
|
||||||
|
AppId: 537128930,
|
||||||
|
SubAppId: 537128930,
|
||||||
|
SortVersionName: "5.8.9",
|
||||||
|
BuildTime: 1595836208,
|
||||||
|
ApkSign: []byte{170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199},
|
||||||
|
SdkVersion: "6.0.0.2433",
|
||||||
|
SSOVersion: 12,
|
||||||
|
MiscBitmap: 150470524,
|
||||||
|
SubSigmap: 66560,
|
||||||
|
MainSigMap: WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST | WLOGIN_SKEY | WLOGIN_VKEY | WLOGIN_D2 | WLOGIN_SID | WLOGIN_PSKEY, // 1970400
|
||||||
|
Protocol: MacOS,
|
||||||
|
},
|
||||||
|
QiDian: {
|
||||||
|
ApkId: "com.tencent.qidian",
|
||||||
|
AppId: 537096038,
|
||||||
|
SubAppId: 537036590,
|
||||||
|
SortVersionName: "5.0.0",
|
||||||
|
BuildTime: 1630062176,
|
||||||
|
ApkSign: []byte{160, 30, 236, 171, 133, 233, 227, 186, 43, 15, 106, 21, 140, 133, 92, 41},
|
||||||
|
SdkVersion: "6.0.0.2484",
|
||||||
|
SSOVersion: 18,
|
||||||
|
MiscBitmap: 184024956,
|
||||||
|
SubSigmap: 66560,
|
||||||
|
MainSigMap: WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST | WLOGIN_SKEY | WLOGIN_D2 | WLOGIN_PSKEY | WLOGIN_DA2, // 34869472
|
||||||
|
Protocol: QiDian,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// see oicq/wlogin_sdk/request/WtloginHelper.java class SigType
|
// see oicq/wlogin_sdk/request/WtloginHelper.java class SigType
|
||||||
const (
|
const (
|
||||||
_ = 1 << iota
|
_ = 1 << iota
|
||||||
@ -52,128 +155,44 @@ type AppVersion struct {
|
|||||||
SdkVersion string
|
SdkVersion string
|
||||||
AppId uint32
|
AppId uint32
|
||||||
SubAppId uint32
|
SubAppId uint32
|
||||||
|
AppKey string
|
||||||
BuildTime uint32
|
BuildTime uint32
|
||||||
SSOVersion uint32
|
SSOVersion uint32
|
||||||
MiscBitmap uint32
|
MiscBitmap uint32
|
||||||
SubSigmap uint32
|
SubSigmap uint32
|
||||||
MainSigMap uint32
|
MainSigMap uint32
|
||||||
Protocol Protocol
|
Protocol ProtocolType
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
func (v *AppVersion) String() string {
|
||||||
aPhone = &AppVersion{
|
return fmt.Sprintf("%s %s - %v", v.Protocol.String(), v.SortVersionName, v.BuildTime)
|
||||||
ApkId: "com.tencent.mobileqq",
|
}
|
||||||
AppId: 537143097,
|
|
||||||
SubAppId: 537143097,
|
|
||||||
SortVersionName: "8.9.23.9425",
|
|
||||||
BuildTime: 1640921786,
|
|
||||||
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
|
|
||||||
SdkVersion: "6.0.0.2530",
|
|
||||||
SSOVersion: 19,
|
|
||||||
MiscBitmap: 150470524,
|
|
||||||
SubSigmap: 0x10400,
|
|
||||||
MainSigMap: WLOGIN_A5 | WLOGIN_RESERVED | WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST |
|
|
||||||
WLOGIN_LSKEY | WLOGIN_SKEY | WLOGIN_SIG64 | 1<<16 | WLOGIN_VKEY | WLOGIN_D2 |
|
|
||||||
WLOGIN_SID | WLOGIN_PSKEY | WLOGIN_AQSIG | WLOGIN_LHSIG | WLOGIN_PAYTOKEN, // 16724722
|
|
||||||
Protocol: AndroidPhone,
|
|
||||||
}
|
|
||||||
|
|
||||||
aPad = &AppVersion{
|
func (v *AppVersion) ReadJson(d []byte) error {
|
||||||
ApkId: "com.tencent.mobileqq",
|
var f appVersionFile
|
||||||
AppId: 537142586,
|
if err := json.Unmarshal(d, &f); err != nil {
|
||||||
SubAppId: 537142586,
|
return errors.Wrap(err, "failed to unmarshal json message")
|
||||||
SortVersionName: "8.9.23.9425",
|
|
||||||
BuildTime: 1640921786,
|
|
||||||
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
|
|
||||||
SdkVersion: "6.0.0.2530",
|
|
||||||
SSOVersion: 19,
|
|
||||||
MiscBitmap: 150470524,
|
|
||||||
SubSigmap: 0x10400,
|
|
||||||
MainSigMap: WLOGIN_A5 | WLOGIN_RESERVED | WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST |
|
|
||||||
WLOGIN_LSKEY | WLOGIN_SKEY | WLOGIN_SIG64 | 1<<16 | WLOGIN_VKEY | WLOGIN_D2 |
|
|
||||||
WLOGIN_SID | WLOGIN_PSKEY | WLOGIN_AQSIG | WLOGIN_LHSIG | WLOGIN_PAYTOKEN, // 16724722
|
|
||||||
Protocol: AndroidPad,
|
|
||||||
}
|
|
||||||
|
|
||||||
aWatch = &AppVersion{
|
|
||||||
ApkId: "com.tencent.qqlite",
|
|
||||||
AppId: 537064446,
|
|
||||||
SubAppId: 537064446,
|
|
||||||
SortVersionName: "2.0.5",
|
|
||||||
BuildTime: 1559564731,
|
|
||||||
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
|
|
||||||
SdkVersion: "6.0.0.236",
|
|
||||||
SSOVersion: 5,
|
|
||||||
MiscBitmap: 16252796,
|
|
||||||
SubSigmap: 0x10400,
|
|
||||||
MainSigMap: WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST | WLOGIN_SKEY | WLOGIN_D2 | WLOGIN_PSKEY | WLOGIN_DA2, // 34869472
|
|
||||||
Protocol: AndroidWatch,
|
|
||||||
}
|
|
||||||
|
|
||||||
ipad = &AppVersion{
|
|
||||||
ApkId: "com.tencent.minihd.qq",
|
|
||||||
AppId: 537118796,
|
|
||||||
SubAppId: 537118796,
|
|
||||||
SortVersionName: "5.9.3",
|
|
||||||
BuildTime: 1595836208,
|
|
||||||
ApkSign: []byte{170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199},
|
|
||||||
SdkVersion: "6.0.0.2433",
|
|
||||||
SSOVersion: 12,
|
|
||||||
MiscBitmap: 150470524,
|
|
||||||
SubSigmap: 66560,
|
|
||||||
MainSigMap: WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST | WLOGIN_SKEY | WLOGIN_VKEY | WLOGIN_D2 | WLOGIN_SID | WLOGIN_PSKEY, // 1970400
|
|
||||||
Protocol: IPad,
|
|
||||||
}
|
|
||||||
|
|
||||||
macOS = &AppVersion{
|
|
||||||
ApkId: "com.tencent.minihd.qq",
|
|
||||||
AppId: 537128930,
|
|
||||||
SubAppId: 537128930,
|
|
||||||
SortVersionName: "5.8.9",
|
|
||||||
BuildTime: 1595836208,
|
|
||||||
ApkSign: []byte{170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199},
|
|
||||||
SdkVersion: "6.0.0.2433",
|
|
||||||
SSOVersion: 12,
|
|
||||||
MiscBitmap: 150470524,
|
|
||||||
SubSigmap: 66560,
|
|
||||||
MainSigMap: WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST | WLOGIN_SKEY | WLOGIN_VKEY | WLOGIN_D2 | WLOGIN_SID | WLOGIN_PSKEY, // 1970400
|
|
||||||
Protocol: MacOS,
|
|
||||||
}
|
|
||||||
|
|
||||||
qidian = &AppVersion{
|
|
||||||
ApkId: "com.tencent.qidian",
|
|
||||||
AppId: 537096038,
|
|
||||||
SubAppId: 537036590,
|
|
||||||
SortVersionName: "5.0.0",
|
|
||||||
BuildTime: 1630062176,
|
|
||||||
ApkSign: []byte{160, 30, 236, 171, 133, 233, 227, 186, 43, 15, 106, 21, 140, 133, 92, 41},
|
|
||||||
SdkVersion: "6.0.0.2484",
|
|
||||||
SSOVersion: 18,
|
|
||||||
MiscBitmap: 184024956,
|
|
||||||
SubSigmap: 66560,
|
|
||||||
MainSigMap: WLOGIN_STWEB | WLOGIN_A2 | WLOGIN_ST | WLOGIN_SKEY | WLOGIN_D2 | WLOGIN_PSKEY | WLOGIN_DA2, // 34869472
|
|
||||||
Protocol: QiDian,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (i Protocol) Version() *AppVersion {
|
|
||||||
switch i {
|
|
||||||
case AndroidPhone:
|
|
||||||
return aPhone
|
|
||||||
case AndroidPad:
|
|
||||||
return aPad
|
|
||||||
case AndroidWatch:
|
|
||||||
return aWatch
|
|
||||||
case IPad:
|
|
||||||
return ipad
|
|
||||||
case MacOS:
|
|
||||||
return macOS
|
|
||||||
case QiDian:
|
|
||||||
return qidian
|
|
||||||
}
|
}
|
||||||
|
v.ApkId = f.ApkId
|
||||||
|
v.AppId = f.AppId
|
||||||
|
v.SubAppId = f.SubAppId
|
||||||
|
v.AppKey = f.AppKey
|
||||||
|
v.SortVersionName = f.SortVersionName
|
||||||
|
v.BuildTime = f.BuildTime
|
||||||
|
v.ApkSign, _ = hex.DecodeString(f.ApkSign)
|
||||||
|
v.SdkVersion = f.SdkVersion
|
||||||
|
v.SSOVersion = f.SSOVersion
|
||||||
|
v.MiscBitmap = f.MiscBitmap
|
||||||
|
v.SubSigmap = f.SubSigmap
|
||||||
|
v.MainSigMap = f.MainSigMap
|
||||||
|
v.Protocol = f.ProtocolType
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i ProtocolType) Version() *AppVersion {
|
||||||
|
return AppVersions[i]
|
||||||
|
}
|
||||||
|
|
||||||
type SigInfo struct {
|
type SigInfo struct {
|
||||||
LoginBitmap uint64
|
LoginBitmap uint64
|
||||||
TGT []byte
|
TGT []byte
|
||||||
@ -216,3 +235,19 @@ type SigInfo struct {
|
|||||||
Ksid []byte
|
Ksid []byte
|
||||||
// msgCtrlBuf []byte
|
// msgCtrlBuf []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type appVersionFile struct {
|
||||||
|
ApkId string `json:"apk_id"`
|
||||||
|
AppId uint32 `json:"app_id"`
|
||||||
|
SubAppId uint32 `json:"sub_app_id"`
|
||||||
|
AppKey string `json:"app_key"`
|
||||||
|
SortVersionName string `json:"sort_version_name"`
|
||||||
|
BuildTime uint32 `json:"build_time"`
|
||||||
|
ApkSign string `json:"apk_sign"` // hex encoded
|
||||||
|
SdkVersion string `json:"sdk_version"`
|
||||||
|
SSOVersion uint32 `json:"sso_version"`
|
||||||
|
MiscBitmap uint32 `json:"misc_bitmap"`
|
||||||
|
MainSigMap uint32 `json:"main_sig_map"`
|
||||||
|
SubSigmap uint32 `json:"sub_sig_map"`
|
||||||
|
ProtocolType ProtocolType `json:"protocol_type"`
|
||||||
|
}
|
||||||
|
@ -45,7 +45,9 @@ type Device struct {
|
|||||||
VendorOSName []byte
|
VendorOSName []byte
|
||||||
Guid []byte
|
Guid []byte
|
||||||
TgtgtKey []byte
|
TgtgtKey []byte
|
||||||
Protocol Protocol
|
QImei16 string
|
||||||
|
QImei36 string
|
||||||
|
Protocol ProtocolType
|
||||||
Version *OSVersion
|
Version *OSVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +137,7 @@ func (info *Device) ReadJson(d []byte) error {
|
|||||||
|
|
||||||
switch f.Protocol {
|
switch f.Protocol {
|
||||||
case 1, 2, 3, 4, 5, 6:
|
case 1, 2, 3, 4, 5, 6:
|
||||||
info.Protocol = Protocol(f.Protocol)
|
info.Protocol = ProtocolType(f.Protocol)
|
||||||
default:
|
default:
|
||||||
info.Protocol = AndroidPad
|
info.Protocol = AndroidPad
|
||||||
}
|
}
|
||||||
@ -149,6 +151,7 @@ func (info *Device) ReadJson(d []byte) error {
|
|||||||
|
|
||||||
info.GenNewGuid()
|
info.GenNewGuid()
|
||||||
info.GenNewTgtgtKey()
|
info.GenNewTgtgtKey()
|
||||||
|
info.RequestQImei() // 应该可以缓存, 理论上同一设备每次请求都是一样的
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
// Code generated by "stringer -type=Protocol -linecomment"; DO NOT EDIT.
|
|
||||||
|
|
||||||
package auth
|
|
||||||
|
|
||||||
import "strconv"
|
|
||||||
|
|
||||||
func _() {
|
|
||||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
|
||||||
// Re-run the stringer command to generate them again.
|
|
||||||
var x [1]struct{}
|
|
||||||
_ = x[Unset-0]
|
|
||||||
_ = x[AndroidPhone-1]
|
|
||||||
_ = x[AndroidWatch-2]
|
|
||||||
_ = x[MacOS-3]
|
|
||||||
_ = x[QiDian-4]
|
|
||||||
_ = x[IPad-5]
|
|
||||||
_ = x[AndroidPad-6]
|
|
||||||
}
|
|
||||||
|
|
||||||
const _Protocol_name = "UnsetAndroid PhoneAndroid WatchMacOS企点iPadAndroid Pad"
|
|
||||||
|
|
||||||
var _Protocol_index = [...]uint8{0, 5, 18, 31, 36, 42, 46, 57}
|
|
||||||
|
|
||||||
func (i Protocol) String() string {
|
|
||||||
if i < 0 || i >= Protocol(len(_Protocol_index)-1) {
|
|
||||||
return "Protocol(" + strconv.FormatInt(int64(i), 10) + ")"
|
|
||||||
}
|
|
||||||
return _Protocol_name[_Protocol_index[i]:_Protocol_index[i+1]]
|
|
||||||
}
|
|
29
client/internal/auth/protocoltype_string.go
Normal file
29
client/internal/auth/protocoltype_string.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Code generated by "stringer -type=ProtocolType -linecomment"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[Unset-0]
|
||||||
|
_ = x[AndroidPhone-1]
|
||||||
|
_ = x[AndroidWatch-2]
|
||||||
|
_ = x[MacOS-3]
|
||||||
|
_ = x[QiDian-4]
|
||||||
|
_ = x[IPad-5]
|
||||||
|
_ = x[AndroidPad-6]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _ProtocolType_name = "UnsetAndroid PhoneAndroid WatchMacOS企点iPadAndroid Pad"
|
||||||
|
|
||||||
|
var _ProtocolType_index = [...]uint8{0, 5, 18, 31, 36, 42, 46, 57}
|
||||||
|
|
||||||
|
func (i ProtocolType) String() string {
|
||||||
|
if i < 0 || i >= ProtocolType(len(_ProtocolType_index)-1) {
|
||||||
|
return "ProtocolType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
return _ProtocolType_name[_ProtocolType_index[i]:_ProtocolType_index[i+1]]
|
||||||
|
}
|
192
client/internal/auth/qimei.go
Normal file
192
client/internal/auth/qimei.go
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Mrs4s/MiraiGo/utils"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
secret = "ZdJqM15EeO2zWc08"
|
||||||
|
rsaKey = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEIxgwoutfwoJxcGQeedgP7FG9
|
||||||
|
qaIuS0qzfR8gWkrkTZKM2iWHn2ajQpBRZjMSoSf6+KJGvar2ORhBfpDXyVtZCKpq
|
||||||
|
LQ+FLkpncClKVIrBwv6PHyUvuCb0rIarmgDnzkfQAqVufEtR64iazGDKatvJ9y6B
|
||||||
|
9NMbHddGSAUmRTCrHQIDAQAB
|
||||||
|
-----END PUBLIC KEY-----`
|
||||||
|
)
|
||||||
|
|
||||||
|
func (info *Device) RequestQImei() {
|
||||||
|
if info.Protocol.Version().AppKey == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init params
|
||||||
|
payload, _ := json.Marshal(genRandomPayloadByDevice(info))
|
||||||
|
cryptKey := utils.RandomStringRange(16, "abcdef1234567890")
|
||||||
|
ts := time.Now().Unix() * 1000
|
||||||
|
nonce := utils.RandomStringRange(16, "abcdef1234567890")
|
||||||
|
|
||||||
|
// init rsa key and aes key
|
||||||
|
publicKey := initPublicKey()
|
||||||
|
encryptedAesKey, _ := rsa.EncryptPKCS1v15(rand.New(rand.NewSource(time.Now().UnixNano())), publicKey, []byte(cryptKey))
|
||||||
|
|
||||||
|
encryptedPayload := aesEncrypt(payload, []byte(cryptKey))
|
||||||
|
|
||||||
|
key := base64.StdEncoding.EncodeToString(encryptedAesKey)
|
||||||
|
params := base64.StdEncoding.EncodeToString(encryptedPayload)
|
||||||
|
|
||||||
|
postData, _ := json.Marshal(map[string]any{
|
||||||
|
"key": key,
|
||||||
|
"params": params,
|
||||||
|
"time": ts,
|
||||||
|
"nonce": nonce,
|
||||||
|
"sign": sign(key, params, fmt.Sprint(ts), nonce),
|
||||||
|
"extra": "",
|
||||||
|
})
|
||||||
|
|
||||||
|
resp, _ := utils.HttpPostBytesWithCookie("https://snowflake.qq.com/ola/android", postData, "", "application/json")
|
||||||
|
if gjson.GetBytes(resp, "code").Int() != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
encryptedResponse, _ := base64.StdEncoding.DecodeString(gjson.GetBytes(resp, "data").String())
|
||||||
|
decryptedResponse := aesDecrypt(encryptedResponse, []byte(cryptKey))
|
||||||
|
info.QImei16 = gjson.GetBytes(decryptedResponse, "q16").String()
|
||||||
|
info.QImei36 = gjson.GetBytes(decryptedResponse, "q36").String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func initPublicKey() *rsa.PublicKey {
|
||||||
|
blockPub, _ := pem.Decode([]byte(rsaKey))
|
||||||
|
pub, _ := x509.ParsePKIXPublicKey(blockPub.Bytes)
|
||||||
|
return pub.(*rsa.PublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sign(key, params, ts, nonce string) string {
|
||||||
|
h := md5.Sum([]byte(key + params + ts + nonce + secret))
|
||||||
|
return hex.EncodeToString(h[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func aesEncrypt(src []byte, key []byte) []byte {
|
||||||
|
block, _ := aes.NewCipher(key)
|
||||||
|
ecb := cipher.NewCBCEncrypter(block, key)
|
||||||
|
content := src
|
||||||
|
content = pkcs5Padding(content, block.BlockSize())
|
||||||
|
crypted := make([]byte, len(content))
|
||||||
|
ecb.CryptBlocks(crypted, content)
|
||||||
|
return crypted
|
||||||
|
}
|
||||||
|
|
||||||
|
func aesDecrypt(crypt []byte, key []byte) []byte {
|
||||||
|
block, _ := aes.NewCipher(key)
|
||||||
|
ecb := cipher.NewCBCDecrypter(block, key)
|
||||||
|
decrypted := make([]byte, len(crypt))
|
||||||
|
ecb.CryptBlocks(decrypted, crypt)
|
||||||
|
return pkcs5Trimming(decrypted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pkcs5Padding(ciphertext []byte, blockSize int) []byte {
|
||||||
|
padding := blockSize - len(ciphertext)%blockSize
|
||||||
|
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||||
|
return append(ciphertext, padtext...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pkcs5Trimming(encrypt []byte) []byte {
|
||||||
|
padding := encrypt[len(encrypt)-1]
|
||||||
|
return encrypt[:len(encrypt)-int(padding)]
|
||||||
|
}
|
||||||
|
|
||||||
|
func genRandomPayloadByDevice(info *Device) map[string]any {
|
||||||
|
now := time.Now()
|
||||||
|
seed := int64(0x6F4)
|
||||||
|
for _, b := range info.Guid {
|
||||||
|
seed += int64(b)
|
||||||
|
}
|
||||||
|
fixedRand := rand.New(rand.NewSource(seed))
|
||||||
|
years := now.Year()
|
||||||
|
month := now.Month()
|
||||||
|
if month == 1 {
|
||||||
|
years--
|
||||||
|
month = 12
|
||||||
|
} else {
|
||||||
|
month--
|
||||||
|
}
|
||||||
|
reserved := map[string]string{
|
||||||
|
"harmony": "0",
|
||||||
|
"clone": "0",
|
||||||
|
"containe": "",
|
||||||
|
"oz": "UhYmelwouA+V2nPWbOvLTgN2/m8jwGB+yUB5v9tysQg=",
|
||||||
|
"oo": "Xecjt+9S1+f8Pz2VLSxgpw==",
|
||||||
|
"kelong": "0",
|
||||||
|
"uptimes": time.Date(years, month, fixedRand.Intn(27)+1, fixedRand.Intn(60), fixedRand.Intn(60), fixedRand.Intn(60), fixedRand.Intn(1e9), now.Location()).Format("2006-01-02 15:04:05"),
|
||||||
|
"multiUser": "0",
|
||||||
|
"bod": string(info.Board),
|
||||||
|
"brd": string(info.Brand),
|
||||||
|
"dv": string(info.Device),
|
||||||
|
"firstLevel": "",
|
||||||
|
"manufact": string(info.Brand),
|
||||||
|
"name": string(info.Model),
|
||||||
|
"host": "se.infra",
|
||||||
|
"kernel": string(info.ProcVersion),
|
||||||
|
}
|
||||||
|
reservedBytes, _ := json.Marshal(reserved)
|
||||||
|
deviceType := "Phone"
|
||||||
|
if info.Protocol == AndroidPad {
|
||||||
|
deviceType = "Pad"
|
||||||
|
}
|
||||||
|
beaconId := ""
|
||||||
|
timeMonth := time.Now().Format("2006-01-") + "01"
|
||||||
|
rand1 := fixedRand.Intn(899999) + 100000
|
||||||
|
rand2 := fixedRand.Intn(899999999) + 100000000
|
||||||
|
for i := 1; i <= 40; i++ {
|
||||||
|
switch i {
|
||||||
|
case 1, 2, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30, 33, 34, 37, 38:
|
||||||
|
beaconId += fmt.Sprintf("k%v:%v%v.%v", i, timeMonth, rand1, rand2)
|
||||||
|
case 3:
|
||||||
|
beaconId += "k3:0000000000000000"
|
||||||
|
case 4:
|
||||||
|
beaconId += "k4:" + utils.RandomStringRange(16, "123456789abcdef")
|
||||||
|
default:
|
||||||
|
beaconId += fmt.Sprintf("k%v:%v", i, fixedRand.Intn(10000))
|
||||||
|
}
|
||||||
|
beaconId += ";"
|
||||||
|
}
|
||||||
|
return map[string]any{
|
||||||
|
"androidId": string(info.AndroidId),
|
||||||
|
"platformId": 1,
|
||||||
|
"appKey": info.Protocol.Version().AppKey,
|
||||||
|
"appVersion": info.Protocol.Version().SortVersionName,
|
||||||
|
"beaconIdSrc": beaconId,
|
||||||
|
"brand": string(info.Brand),
|
||||||
|
"channelId": "2017",
|
||||||
|
"cid": "",
|
||||||
|
"imei": info.IMEI,
|
||||||
|
"imsi": "",
|
||||||
|
"mac": "",
|
||||||
|
"model": string(info.Model),
|
||||||
|
"networkType": "unknown",
|
||||||
|
"oaid": "",
|
||||||
|
"osVersion": "Android " + string(info.Version.Release) + ",level " + fmt.Sprint(info.Version.SDK),
|
||||||
|
"qimei": "",
|
||||||
|
"qimei36": "",
|
||||||
|
"sdkVersion": "1.2.13.6",
|
||||||
|
"audit": "",
|
||||||
|
"userId": "{}",
|
||||||
|
"packageId": info.Protocol.Version().ApkId,
|
||||||
|
"deviceType": deviceType,
|
||||||
|
"sdkName": "",
|
||||||
|
"reserved": string(reservedBytes),
|
||||||
|
}
|
||||||
|
}
|
@ -208,6 +208,10 @@ func msgType0x210Sub27Decoder(c *QQClient, protobuf []byte) error {
|
|||||||
if m.DelFriend != nil {
|
if m.DelFriend != nil {
|
||||||
frdUin := m.DelFriend.Uins[0]
|
frdUin := m.DelFriend.Uins[0]
|
||||||
if frd := c.FindFriend(int64(frdUin)); frd != nil {
|
if frd := c.FindFriend(int64(frdUin)); frd != nil {
|
||||||
|
c.DeleteFriendEvent.dispatch(c, &DeleteFriendEvent{
|
||||||
|
Uin: frd.Uin,
|
||||||
|
Nickname: frd.Nickname,
|
||||||
|
})
|
||||||
if err := c.ReloadFriendList(); err != nil {
|
if err := c.ReloadFriendList(); err != nil {
|
||||||
return errors.Wrap(err, "failed to reload friend list")
|
return errors.Wrap(err, "failed to reload friend list")
|
||||||
}
|
}
|
||||||
|
33
internal/tlv/t544.go
Normal file
33
internal/tlv/t544.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package tlv
|
||||||
|
|
||||||
|
import "github.com/Mrs4s/MiraiGo/binary"
|
||||||
|
|
||||||
|
// temporary solution
|
||||||
|
|
||||||
|
func T544(userId uint64, moduleId string, subCmd uint32, sdkVersion string, guid []byte, signer func(uint64, string, []byte) ([]byte, error)) []byte {
|
||||||
|
salt := binary.NewWriterF(func(w *binary.Writer) {
|
||||||
|
w.WriteUInt64(userId)
|
||||||
|
w.WriteBytesShort(guid)
|
||||||
|
w.WriteBytesShort([]byte(sdkVersion))
|
||||||
|
w.WriteUInt32(subCmd)
|
||||||
|
})
|
||||||
|
sign, err := signer(userId, moduleId, salt)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return binary.NewWriterF(func(w *binary.Writer) {
|
||||||
|
w.WriteUInt16(0x544)
|
||||||
|
w.WriteBytesShort(sign)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func T544Custom(userId uint64, moduleId string, salt []byte, signer func(uint64, string, []byte) ([]byte, error)) []byte {
|
||||||
|
sign, err := signer(userId, moduleId, salt)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return binary.NewWriterF(func(w *binary.Writer) {
|
||||||
|
w.WriteUInt16(0x544)
|
||||||
|
w.WriteBytesShort(sign)
|
||||||
|
})
|
||||||
|
}
|
@ -2,9 +2,9 @@ package tlv
|
|||||||
|
|
||||||
import "github.com/Mrs4s/MiraiGo/binary"
|
import "github.com/Mrs4s/MiraiGo/binary"
|
||||||
|
|
||||||
func T545(imei []byte) []byte {
|
func T545(qimei []byte) []byte {
|
||||||
return binary.NewWriterF(func(w *binary.Writer) {
|
return binary.NewWriterF(func(w *binary.Writer) {
|
||||||
w.WriteUInt16(0x545)
|
w.WriteUInt16(0x545)
|
||||||
w.WriteBytesShort(imei)
|
w.WriteBytesShort(qimei)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
3
wrapper/codec.go
Normal file
3
wrapper/codec.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package wrapper
|
||||||
|
|
||||||
|
var DandelionEnergy func(uint64, string, []byte) ([]byte, error)
|
Loading…
x
Reference in New Issue
Block a user