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  }