github.com/Mrs4s/MiraiGo@v0.0.0-20240226124653-54bdd873e3fe/client/internal/network/response.go (about) 1 package network 2 3 import ( 4 "strconv" 5 6 "github.com/pkg/errors" 7 8 "github.com/Mrs4s/MiraiGo/binary" 9 ) 10 11 type Response struct { 12 Type RequestType 13 EncryptType EncryptType 14 SequenceID int32 15 Uin int64 16 CommandName string 17 Body []byte 18 19 Message string 20 21 // Request is the original request that obtained this response. 22 // Request *Request 23 } 24 25 var ( 26 ErrSessionExpired = errors.New("session expired") 27 ErrPacketDropped = errors.New("packet dropped") 28 ErrInvalidPacketType = errors.New("invalid packet type") 29 ) 30 31 func (t *Transport) ReadResponse(head []byte) (*Response, error) { 32 resp := new(Response) 33 r := binary.NewReader(head) 34 resp.Type = RequestType(r.ReadInt32()) 35 if resp.Type != RequestTypeLogin && resp.Type != RequestTypeSimple { 36 return resp, ErrInvalidPacketType 37 } 38 resp.EncryptType = EncryptType(r.ReadByte()) 39 _ = r.ReadByte() // 0x00? 40 41 resp.Uin, _ = strconv.ParseInt(r.ReadString(), 10, 64) 42 body := r.ReadAvailable() 43 switch resp.EncryptType { 44 case EncryptTypeNoEncrypt: 45 // nothing to do 46 case EncryptTypeD2Key: 47 body = binary.NewTeaCipher(t.Sig.D2Key).Decrypt(body) 48 case EncryptTypeEmptyKey: 49 emptyKey := make([]byte, 16) 50 body = binary.NewTeaCipher(emptyKey).Decrypt(body) 51 } 52 err := t.readSSOFrame(resp, body) 53 return resp, err 54 } 55 56 func (t *Transport) readSSOFrame(resp *Response, payload []byte) error { 57 reader := binary.NewReader(payload) 58 headLen := reader.ReadInt32() 59 if headLen < 4 || headLen-4 > int32(reader.Len()) { 60 return errors.WithStack(ErrPacketDropped) 61 } 62 63 head := binary.NewReader(reader.ReadBytes(int(headLen) - 4)) 64 resp.SequenceID = head.ReadInt32() 65 switch retCode := head.ReadInt32(); retCode { 66 case 0: 67 // ok 68 case -10008: 69 return errors.WithStack(ErrSessionExpired) 70 default: 71 return errors.Errorf("return code unsuccessful: %d", retCode) 72 } 73 resp.Message = head.ReadString() 74 resp.CommandName = head.ReadString() 75 if resp.CommandName == "Heartbeat.Alive" { 76 return nil 77 } 78 _ = head.ReadInt32Bytes() // session id 79 compressedFlag := head.ReadInt32() 80 81 bodyLen := reader.ReadInt32() - 4 82 body := reader.ReadAvailable() 83 if bodyLen > 0 && bodyLen < int32(len(body)) { 84 body = body[:bodyLen] 85 } 86 switch compressedFlag { 87 case 0, 8: 88 case 1: 89 body = binary.ZlibUncompress(body) 90 } 91 resp.Body = body 92 return nil 93 }