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