mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-04 11:07:40 +08:00
128 lines
3.0 KiB
Go
128 lines
3.0 KiB
Go
package network
|
|
|
|
import (
|
|
"strconv"
|
|
"sync"
|
|
|
|
"github.com/Mrs4s/MiraiGo/binary"
|
|
"github.com/Mrs4s/MiraiGo/client/internal/auth"
|
|
)
|
|
|
|
// Transport is a network transport.
|
|
type Transport struct {
|
|
sessionMu sync.Mutex
|
|
// todo: combine session fields to a struct
|
|
tgt []byte
|
|
d2key []byte
|
|
sessionID []byte
|
|
ksid []byte
|
|
|
|
version *auth.AppVersion
|
|
device *auth.Device
|
|
|
|
// connection
|
|
conn *TCPListener
|
|
}
|
|
|
|
func (t *Transport) packBody(req *Request, w *binary.Writer) {
|
|
w.WriteIntLvPacket(4, func(writer *binary.Writer) {
|
|
if req.Type == RequestTypeLogin {
|
|
writer.WriteUInt32(uint32(req.SequenceID))
|
|
writer.WriteUInt32(t.version.AppId)
|
|
writer.WriteUInt32(t.version.SubAppId)
|
|
writer.Write([]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00})
|
|
if len(t.tgt) == 0 || len(t.tgt) == 4 {
|
|
writer.WriteUInt32(0x04)
|
|
} else {
|
|
writer.WriteUInt32(uint32(len(t.tgt) + 4))
|
|
writer.Write(t.tgt)
|
|
}
|
|
}
|
|
|
|
writer.WriteString(req.Method)
|
|
writer.WriteUInt32(uint32(len(t.sessionID) + 4))
|
|
w.Write(t.sessionID)
|
|
if req.Type == RequestTypeLogin {
|
|
writer.WriteString(t.device.IMEI)
|
|
writer.WriteUInt32(0x04)
|
|
{
|
|
writer.WriteUInt16(uint16(len(t.ksid)) + 2)
|
|
writer.Write(t.ksid)
|
|
}
|
|
}
|
|
writer.WriteUInt32(0x04)
|
|
})
|
|
|
|
w.WriteUInt32(uint32(len(req.Body) + 4))
|
|
w.Write(req.Body)
|
|
}
|
|
|
|
func (t *Transport) Send(req *Request) error {
|
|
// todo: return response
|
|
head := binary.NewWriterF(func(w *binary.Writer) {
|
|
w.WriteUInt32(uint32(req.Type))
|
|
w.WriteUInt32(uint32(req.EncryptType))
|
|
switch req.Type {
|
|
case RequestTypeLogin:
|
|
switch req.EncryptType {
|
|
case EncryptTypeD2Key:
|
|
w.WriteUInt32(uint32(len(t.d2key) + 4))
|
|
w.Write(t.d2key)
|
|
default:
|
|
w.WriteUInt32(4)
|
|
}
|
|
case RequestTypeSimple:
|
|
w.WriteUInt32(uint32(req.SequenceID))
|
|
}
|
|
w.WriteString(strconv.FormatInt(req.Uin, 10))
|
|
})
|
|
|
|
w := binary.SelectWriter()
|
|
defer binary.PutWriter(w)
|
|
t.packBody(req, w)
|
|
body := w.Bytes()
|
|
|
|
// encrypt body
|
|
switch req.EncryptType {
|
|
case EncryptTypeD2Key:
|
|
body = binary.NewTeaCipher(t.d2key).Encrypt(body)
|
|
case EncryptTypeEmptyKey:
|
|
body = binary.NewTeaCipher(emptyKey).Encrypt(body)
|
|
}
|
|
|
|
w2 := binary.SelectWriter()
|
|
defer binary.PutWriter(w2)
|
|
w2.WriteUInt32(uint32(len(head) + len(body) + 4))
|
|
w2.Write(head)
|
|
w2.Write(body)
|
|
err := t.conn.Write(w2.Bytes())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (t *Transport) parse(head []byte) *Request {
|
|
req := new(Request)
|
|
r := binary.NewReader(head)
|
|
req.Type = RequestType(r.ReadInt32())
|
|
encryptType := EncryptType(r.ReadInt32())
|
|
switch req.Type {
|
|
case RequestTypeLogin:
|
|
// req.Key = r.ReadBytes(int(encryptType))
|
|
case RequestTypeSimple:
|
|
req.SequenceID = r.ReadInt32()
|
|
}
|
|
_ = r.ReadString() // req.Uin
|
|
body := r.ReadAvailable()
|
|
switch encryptType {
|
|
case EncryptTypeNoEncrypt:
|
|
req.Body = body
|
|
case EncryptTypeD2Key:
|
|
req.Body = binary.NewTeaCipher(t.d2key).Decrypt(body)
|
|
case EncryptTypeEmptyKey:
|
|
req.Body = binary.NewTeaCipher(emptyKey).Decrypt(body)
|
|
}
|
|
return req
|
|
}
|