github.com/chanxuehong/wechat@v0.0.0-20230222024006-36f0325263cd/mp/core/server.go (about)

     1  package core
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/base64"
     6  	"encoding/xml"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	"log"
    12  	"net/http"
    13  	"net/url"
    14  	"strconv"
    15  	"sync"
    16  	"sync/atomic"
    17  	"unicode"
    18  	"unsafe"
    19  
    20  	"github.com/chanxuehong/util/security"
    21  
    22  	"github.com/chanxuehong/wechat/internal/debug/callback"
    23  	"github.com/chanxuehong/wechat/internal/util"
    24  )
    25  
    26  // Server 用于处理微信服务器的回调请求, 并发安全!
    27  //
    28  //	通常情况下一个 Server 实例用于处理一个公众号的消息(事件), 此时建议指定 oriId(原始ID) 和 appId(明文模式下无需指定) 用于约束消息(事件);
    29  //	特殊情况下也可以一个 Server 实例用于处理多个公众号的消息(事件), 此时要求这些公众号的 token 是一样的, 并且 oriId 和 appId 必须设置为 "".
    30  type Server struct {
    31  	oriId string
    32  	appId string
    33  
    34  	tokenBucketPtrMutex sync.Mutex     // used only by writers
    35  	tokenBucketPtr      unsafe.Pointer // *tokenBucket
    36  
    37  	aesKeyBucketPtrMutex sync.Mutex     // used only by writers
    38  	aesKeyBucketPtr      unsafe.Pointer // *aesKeyBucket
    39  
    40  	handler      Handler
    41  	errorHandler ErrorHandler
    42  }
    43  
    44  func (srv *Server) OriId() string {
    45  	return srv.oriId
    46  }
    47  func (srv *Server) AppId() string {
    48  	return srv.appId
    49  }
    50  
    51  type tokenBucket struct {
    52  	currentToken string
    53  	lastToken    string
    54  }
    55  
    56  type aesKeyBucket struct {
    57  	currentAESKey []byte
    58  	lastAESKey    []byte
    59  }
    60  
    61  // NewServer 创建一个新的 Server.
    62  //
    63  //	oriId:        可选; 公众号的原始ID(微信公众号管理后台查看), 如果设置了值则该Server只能处理 ToUserName 为该值的公众号的消息(事件);
    64  //	appId:        可选; 公众号的AppId, 如果设置了值则安全模式时该Server只能处理 AppId 为该值的公众号的消息(事件);
    65  //	token:        必须; 公众号用于验证签名的token;
    66  //	base64AESKey: 可选; aes加密解密key, 43字节长(base64编码, 去掉了尾部的'='), 安全模式必须设置;
    67  //	handler:      必须; 处理微信服务器推送过来的消息(事件)的Handler;
    68  //	errorHandler: 可选; 用于处理Server在处理消息(事件)过程中产生的错误, 如果没有设置则默认使用 DefaultErrorHandler.
    69  func NewServer(oriId, appId, token, base64AESKey string, handler Handler, errorHandler ErrorHandler) (srv *Server) {
    70  	if token == "" {
    71  		panic("empty token")
    72  	}
    73  	if handler == nil {
    74  		panic("nil Handler")
    75  	}
    76  	if errorHandler == nil {
    77  		errorHandler = DefaultErrorHandler
    78  	}
    79  
    80  	var (
    81  		aesKey []byte
    82  		err    error
    83  	)
    84  	if base64AESKey != "" {
    85  		if len(base64AESKey) != 43 {
    86  			panic("the length of base64AESKey must equal to 43")
    87  		}
    88  		aesKey, err = base64.StdEncoding.DecodeString(base64AESKey + "=")
    89  		if err != nil {
    90  			panic(fmt.Sprintf("Decode base64AESKey:%s failed", base64AESKey))
    91  		}
    92  	}
    93  
    94  	return &Server{
    95  		oriId:           oriId,
    96  		appId:           appId,
    97  		tokenBucketPtr:  unsafe.Pointer(&tokenBucket{currentToken: token}),
    98  		aesKeyBucketPtr: unsafe.Pointer(&aesKeyBucket{currentAESKey: aesKey}),
    99  		handler:         handler,
   100  		errorHandler:    errorHandler,
   101  	}
   102  }
   103  
   104  func (srv *Server) getToken() (currentToken, lastToken string) {
   105  	if p := (*tokenBucket)(atomic.LoadPointer(&srv.tokenBucketPtr)); p != nil {
   106  		return p.currentToken, p.lastToken
   107  	}
   108  	return
   109  }
   110  
   111  // SetToken 设置签名token.
   112  func (srv *Server) SetToken(token string) (err error) {
   113  	if token == "" {
   114  		return errors.New("empty token")
   115  	}
   116  
   117  	srv.tokenBucketPtrMutex.Lock()
   118  	defer srv.tokenBucketPtrMutex.Unlock()
   119  
   120  	currentToken, _ := srv.getToken()
   121  	if token == currentToken {
   122  		return
   123  	}
   124  
   125  	bucket := tokenBucket{
   126  		currentToken: token,
   127  		lastToken:    currentToken,
   128  	}
   129  	atomic.StorePointer(&srv.tokenBucketPtr, unsafe.Pointer(&bucket))
   130  	return
   131  }
   132  
   133  func (srv *Server) removeLastToken(lastToken string) {
   134  	srv.tokenBucketPtrMutex.Lock()
   135  	defer srv.tokenBucketPtrMutex.Unlock()
   136  
   137  	currentToken2, lastToken2 := srv.getToken()
   138  	if lastToken != lastToken2 {
   139  		return
   140  	}
   141  
   142  	bucket := tokenBucket{
   143  		currentToken: currentToken2,
   144  	}
   145  	atomic.StorePointer(&srv.tokenBucketPtr, unsafe.Pointer(&bucket))
   146  	return
   147  }
   148  
   149  func (srv *Server) getAESKey() (currentAESKey, lastAESKey []byte) {
   150  	if p := (*aesKeyBucket)(atomic.LoadPointer(&srv.aesKeyBucketPtr)); p != nil {
   151  		return p.currentAESKey, p.lastAESKey
   152  	}
   153  	return
   154  }
   155  
   156  // SetAESKey 设置aes加密解密key.
   157  //
   158  //	base64AESKey: aes加密解密key, 43字节长(base64编码, 去掉了尾部的'=').
   159  func (srv *Server) SetAESKey(base64AESKey string) (err error) {
   160  	if len(base64AESKey) != 43 {
   161  		return errors.New("the length of base64AESKey must equal to 43")
   162  	}
   163  	aesKey, err := base64.StdEncoding.DecodeString(base64AESKey + "=")
   164  	if err != nil {
   165  		return
   166  	}
   167  
   168  	srv.aesKeyBucketPtrMutex.Lock()
   169  	defer srv.aesKeyBucketPtrMutex.Unlock()
   170  
   171  	currentAESKey, _ := srv.getAESKey()
   172  	if bytes.Equal(aesKey, currentAESKey) {
   173  		return
   174  	}
   175  
   176  	bucket := aesKeyBucket{
   177  		currentAESKey: aesKey,
   178  		lastAESKey:    currentAESKey,
   179  	}
   180  	atomic.StorePointer(&srv.aesKeyBucketPtr, unsafe.Pointer(&bucket))
   181  	return
   182  }
   183  
   184  func (srv *Server) removeLastAESKey(lastAESKey []byte) {
   185  	srv.aesKeyBucketPtrMutex.Lock()
   186  	defer srv.aesKeyBucketPtrMutex.Unlock()
   187  
   188  	currentAESKey2, lastAESKey2 := srv.getAESKey()
   189  	if !bytes.Equal(lastAESKey, lastAESKey2) {
   190  		return
   191  	}
   192  
   193  	bucket := aesKeyBucket{
   194  		currentAESKey: currentAESKey2,
   195  	}
   196  	atomic.StorePointer(&srv.aesKeyBucketPtr, unsafe.Pointer(&bucket))
   197  	return
   198  }
   199  
   200  // ServeHTTP 处理微信服务器的回调请求, query 参数可以为 nil.
   201  func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request, query url.Values) {
   202  	callback.DebugPrintRequest(r)
   203  	if query == nil {
   204  		query = r.URL.Query()
   205  	}
   206  	errorHandler := srv.errorHandler
   207  
   208  	switch r.Method {
   209  	case "POST": // 推送消息(事件)
   210  		switch encryptType := query.Get("encrypt_type"); encryptType {
   211  		case "aes":
   212  			haveSignature := query.Get("signature")
   213  			if haveSignature == "" {
   214  				errorHandler.ServeError(w, r, errors.New("not found signature query parameter"))
   215  				return
   216  			}
   217  			haveMsgSignature := query.Get("msg_signature")
   218  			if haveMsgSignature == "" {
   219  				errorHandler.ServeError(w, r, errors.New("not found msg_signature query parameter"))
   220  				return
   221  			}
   222  			timestampString := query.Get("timestamp")
   223  			if timestampString == "" {
   224  				errorHandler.ServeError(w, r, errors.New("not found timestamp query parameter"))
   225  				return
   226  			}
   227  			timestamp, err := strconv.ParseInt(timestampString, 10, 64)
   228  			if err != nil {
   229  				err = fmt.Errorf("can not parse timestamp query parameter %q to int64", timestampString)
   230  				errorHandler.ServeError(w, r, err)
   231  				return
   232  			}
   233  			nonce := query.Get("nonce")
   234  			if nonce == "" {
   235  				errorHandler.ServeError(w, r, errors.New("not found nonce query parameter"))
   236  				return
   237  			}
   238  
   239  			var token string
   240  			currentToken, lastToken := srv.getToken()
   241  			if currentToken == "" {
   242  				err = errors.New("token was not set for Server, see NewServer function or Server.SetToken method")
   243  				errorHandler.ServeError(w, r, err)
   244  				return
   245  			}
   246  			token = currentToken
   247  			wantSignature := util.Sign(token, timestampString, nonce)
   248  			if !security.SecureCompareString(haveSignature, wantSignature) {
   249  				if lastToken == "" {
   250  					err = fmt.Errorf("check signature failed, have: %s, want: %s", haveSignature, wantSignature)
   251  					errorHandler.ServeError(w, r, err)
   252  					return
   253  				}
   254  				token = lastToken
   255  				wantSignature = util.Sign(token, timestampString, nonce)
   256  				if !security.SecureCompareString(haveSignature, wantSignature) {
   257  					err = fmt.Errorf("check signature failed, have: %s, want: %s", haveSignature, wantSignature)
   258  					errorHandler.ServeError(w, r, err)
   259  					return
   260  				}
   261  			} else {
   262  				if lastToken != "" {
   263  					srv.removeLastToken(lastToken)
   264  				}
   265  			}
   266  
   267  			buffer := textBufferPool.Get().(*bytes.Buffer)
   268  			buffer.Reset()
   269  			defer textBufferPool.Put(buffer)
   270  
   271  			if _, err = buffer.ReadFrom(r.Body); err != nil {
   272  				errorHandler.ServeError(w, r, err)
   273  				return
   274  			}
   275  			requestBodyBytes := buffer.Bytes()
   276  
   277  			var requestHttpBody cipherRequestHttpBody
   278  			if err = xmlUnmarshal(requestBodyBytes, &requestHttpBody); err != nil {
   279  				errorHandler.ServeError(w, r, err)
   280  				return
   281  			}
   282  
   283  			haveToUserName := requestHttpBody.ToUserName
   284  			wantToUserName := srv.oriId
   285  			if wantToUserName != "" && !security.SecureCompareString(haveToUserName, wantToUserName) {
   286  				err = fmt.Errorf("the message ToUserName mismatch, have: %s, want: %s",
   287  					haveToUserName, wantToUserName)
   288  				errorHandler.ServeError(w, r, err)
   289  				return
   290  			}
   291  
   292  			wantMsgSignature := util.MsgSign(token, timestampString, nonce, string(requestHttpBody.Base64EncryptedMsg))
   293  			if !security.SecureCompareString(haveMsgSignature, wantMsgSignature) {
   294  				err = fmt.Errorf("check msg_signature failed, have: %s, want: %s", haveMsgSignature, wantMsgSignature)
   295  				errorHandler.ServeError(w, r, err)
   296  				return
   297  			}
   298  
   299  			encryptedMsg := make([]byte, base64.StdEncoding.DecodedLen(len(requestHttpBody.Base64EncryptedMsg)))
   300  			encryptedMsgLen, err := base64.StdEncoding.Decode(encryptedMsg, requestHttpBody.Base64EncryptedMsg)
   301  			if err != nil {
   302  				errorHandler.ServeError(w, r, err)
   303  				return
   304  			}
   305  			encryptedMsg = encryptedMsg[:encryptedMsgLen]
   306  
   307  			var aesKey []byte
   308  			currentAESKey, lastAESKey := srv.getAESKey()
   309  			if currentAESKey == nil {
   310  				err = errors.New("aes key was not set for Server, see NewServer function or Server.SetAESKey method")
   311  				errorHandler.ServeError(w, r, err)
   312  				return
   313  			}
   314  			aesKey = currentAESKey
   315  			random, msgPlaintext, haveAppIdBytes, err := util.AESDecryptMsg(encryptedMsg, aesKey)
   316  			if err != nil {
   317  				if lastAESKey == nil {
   318  					errorHandler.ServeError(w, r, err)
   319  					return
   320  				}
   321  				aesKey = lastAESKey
   322  				random, msgPlaintext, haveAppIdBytes, err = util.AESDecryptMsg(encryptedMsg, aesKey)
   323  				if err != nil {
   324  					errorHandler.ServeError(w, r, err)
   325  					return
   326  				}
   327  			} else {
   328  				if lastAESKey != nil {
   329  					srv.removeLastAESKey(lastAESKey)
   330  				}
   331  			}
   332  			callback.DebugPrintPlainRequestMessage(msgPlaintext)
   333  
   334  			haveAppId := string(haveAppIdBytes)
   335  			wantAppId := srv.appId
   336  			if wantAppId != "" && !security.SecureCompareString(haveAppId, wantAppId) {
   337  				err = fmt.Errorf("the message AppId mismatch, have: %s, want: %s", haveAppId, wantAppId)
   338  				errorHandler.ServeError(w, r, err)
   339  				return
   340  			}
   341  
   342  			var mixedMsg MixedMsg
   343  			if err = xml.Unmarshal(msgPlaintext, &mixedMsg); err != nil {
   344  				errorHandler.ServeError(w, r, err)
   345  				return
   346  			}
   347  			if haveToUserName != mixedMsg.ToUserName {
   348  				err = fmt.Errorf("the message ToUserName mismatch between ciphertext and plaintext, %q != %q",
   349  					haveToUserName, mixedMsg.ToUserName)
   350  				errorHandler.ServeError(w, r, err)
   351  				return
   352  			}
   353  
   354  			ctx := &Context{
   355  				ResponseWriter: w,
   356  				Request:        r,
   357  
   358  				QueryParams:  query,
   359  				EncryptType:  encryptType,
   360  				MsgSignature: haveMsgSignature,
   361  				Signature:    haveSignature,
   362  				Timestamp:    timestamp,
   363  				Nonce:        nonce,
   364  
   365  				MsgCiphertext: requestHttpBody.Base64EncryptedMsg,
   366  				MsgPlaintext:  msgPlaintext,
   367  				MixedMsg:      &mixedMsg,
   368  
   369  				Token:  token,
   370  				AESKey: aesKey,
   371  				Random: random,
   372  				AppId:  haveAppId,
   373  
   374  				handlerIndex: initHandlerIndex,
   375  			}
   376  			srv.handler.ServeMsg(ctx)
   377  
   378  		case "", "raw":
   379  			haveSignature := query.Get("signature")
   380  			if haveSignature == "" {
   381  				errorHandler.ServeError(w, r, errors.New("not found signature query parameter"))
   382  				return
   383  			}
   384  			timestampString := query.Get("timestamp")
   385  			if timestampString == "" {
   386  				errorHandler.ServeError(w, r, errors.New("not found timestamp query parameter"))
   387  				return
   388  			}
   389  			timestamp, err := strconv.ParseInt(timestampString, 10, 64)
   390  			if err != nil {
   391  				err = fmt.Errorf("can not parse timestamp query parameter %q to int64", timestampString)
   392  				errorHandler.ServeError(w, r, err)
   393  				return
   394  			}
   395  			nonce := query.Get("nonce")
   396  			if nonce == "" {
   397  				errorHandler.ServeError(w, r, errors.New("not found nonce query parameter"))
   398  				return
   399  			}
   400  
   401  			var token string
   402  			currentToken, lastToken := srv.getToken()
   403  			if currentToken == "" {
   404  				err = errors.New("token was not set for Server, see NewServer function or Server.SetToken method")
   405  				errorHandler.ServeError(w, r, err)
   406  				return
   407  			}
   408  			token = currentToken
   409  			wantSignature := util.Sign(token, timestampString, nonce)
   410  			if !security.SecureCompareString(haveSignature, wantSignature) {
   411  				if lastToken == "" {
   412  					err = fmt.Errorf("check signature failed, have: %s, want: %s", haveSignature, wantSignature)
   413  					errorHandler.ServeError(w, r, err)
   414  					return
   415  				}
   416  				token = lastToken
   417  				wantSignature = util.Sign(token, timestampString, nonce)
   418  				if !security.SecureCompareString(haveSignature, wantSignature) {
   419  					err = fmt.Errorf("check signature failed, have: %s, want: %s", haveSignature, wantSignature)
   420  					errorHandler.ServeError(w, r, err)
   421  					return
   422  				}
   423  			} else {
   424  				if lastToken != "" {
   425  					srv.removeLastToken(lastToken)
   426  				}
   427  			}
   428  
   429  			msgPlaintext, err := ioutil.ReadAll(r.Body)
   430  			if err != nil {
   431  				errorHandler.ServeError(w, r, err)
   432  				return
   433  			}
   434  			callback.DebugPrintPlainRequestMessage(msgPlaintext)
   435  
   436  			var mixedMsg MixedMsg
   437  			if err = xml.Unmarshal(msgPlaintext, &mixedMsg); err != nil {
   438  				errorHandler.ServeError(w, r, err)
   439  				return
   440  			}
   441  
   442  			haveToUserName := mixedMsg.ToUserName
   443  			wantToUserName := srv.oriId
   444  			if wantToUserName != "" && !security.SecureCompareString(haveToUserName, wantToUserName) {
   445  				err = fmt.Errorf("the message ToUserName mismatch, have: %s, want: %s",
   446  					haveToUserName, wantToUserName)
   447  				errorHandler.ServeError(w, r, err)
   448  				return
   449  			}
   450  
   451  			ctx := &Context{
   452  				ResponseWriter: w,
   453  				Request:        r,
   454  
   455  				QueryParams: query,
   456  				EncryptType: encryptType,
   457  				Signature:   haveSignature,
   458  				Timestamp:   timestamp,
   459  				Nonce:       nonce,
   460  
   461  				MsgPlaintext: msgPlaintext,
   462  				MixedMsg:     &mixedMsg,
   463  
   464  				Token: token,
   465  
   466  				handlerIndex: initHandlerIndex,
   467  			}
   468  			srv.handler.ServeMsg(ctx)
   469  
   470  		default:
   471  			errorHandler.ServeError(w, r, errors.New("unknown encrypt_type: "+encryptType))
   472  		}
   473  
   474  	case "GET": // 验证回调URL是否有效
   475  		haveSignature := query.Get("signature")
   476  		if haveSignature == "" {
   477  			errorHandler.ServeError(w, r, errors.New("not found signature query parameter"))
   478  			return
   479  		}
   480  		timestamp := query.Get("timestamp")
   481  		if timestamp == "" {
   482  			errorHandler.ServeError(w, r, errors.New("not found timestamp query parameter"))
   483  			return
   484  		}
   485  		nonce := query.Get("nonce")
   486  		if nonce == "" {
   487  			errorHandler.ServeError(w, r, errors.New("not found nonce query parameter"))
   488  			return
   489  		}
   490  		echostr := query.Get("echostr")
   491  		if echostr == "" {
   492  			errorHandler.ServeError(w, r, errors.New("not found echostr query parameter"))
   493  			return
   494  		}
   495  
   496  		var token string
   497  		currentToken, lastToken := srv.getToken()
   498  		if currentToken == "" {
   499  			err := errors.New("token was not set for Server, see NewServer function or Server.SetToken method")
   500  			errorHandler.ServeError(w, r, err)
   501  			return
   502  		}
   503  		token = currentToken
   504  		wantSignature := util.Sign(token, timestamp, nonce)
   505  		if !security.SecureCompareString(haveSignature, wantSignature) {
   506  			if lastToken == "" {
   507  				err := fmt.Errorf("check signature failed, have: %s, want: %s", haveSignature, wantSignature)
   508  				errorHandler.ServeError(w, r, err)
   509  				return
   510  			}
   511  			token = lastToken
   512  			wantSignature = util.Sign(token, timestamp, nonce)
   513  			if !security.SecureCompareString(haveSignature, wantSignature) {
   514  				err := fmt.Errorf("check signature failed, have: %s, want: %s", haveSignature, wantSignature)
   515  				errorHandler.ServeError(w, r, err)
   516  				return
   517  			}
   518  		} else {
   519  			if lastToken != "" {
   520  				srv.removeLastToken(lastToken)
   521  			}
   522  		}
   523  
   524  		io.WriteString(w, echostr)
   525  	}
   526  }
   527  
   528  // =====================================================================================================================
   529  
   530  type cipherRequestHttpBody struct {
   531  	XMLName            struct{} `xml:"xml"`
   532  	ToUserName         string   `xml:"ToUserName"`
   533  	Base64EncryptedMsg []byte   `xml:"Encrypt"`
   534  }
   535  
   536  var (
   537  	msgStartElementLiteral = []byte("<xml>")
   538  	msgEndElementLiteral   = []byte("</xml>")
   539  
   540  	msgToUserNameStartElementLiteral = []byte("<ToUserName>")
   541  	msgToUserNameEndElementLiteral   = []byte("</ToUserName>")
   542  
   543  	msgEncryptStartElementLiteral = []byte("<Encrypt>")
   544  	msgEncryptEndElementLiteral   = []byte("</Encrypt>")
   545  
   546  	cdataStartLiteral = []byte("<![CDATA[")
   547  	cdataEndLiteral   = []byte("]]>")
   548  )
   549  
   550  // <xml>
   551  //
   552  //	<ToUserName><![CDATA[gh_b1eb3f8bd6c6]]></ToUserName>
   553  //	<Encrypt><![CDATA[DlCGq+lWQuyjNNK+vDaO0zUltpdUW3u4V00WCzsdNzmZGEhrU7TPxG52viOKCWYPwTMbCzgbCtakZHyNxr5hjoZJ7ORAUYoIAGQy/LDWtAnYgDO+ppKLp0rDq+67Dv3yt+vatMQTh99NII6x9SEGpY3O2h8RpG99+NYevQiOLVKqiQYzan21sX/jE4Y3wZaeudsb4QVjqzRAPaCJ5nS3T31uIR9fjSRgHTDRDOzjQ1cHchge+t6faUhniN5VQVTE+wIYtmnejc55BmHYPfBnTkYah9+cTYnI3diUPJRRiyVocJyHlb+XOZN22dsx9yzKHBAyagaoDIV8Yyb/PahcUbsqGv5wziOgLJQIa6z93/VY7d2Kq2C2oBS+Qb+FI9jLhgc3RvCi+Yno2X3cWoqbsRwoovYdyg6jme/H7nMZn77PSxOGRt/dYiWx2NuBAF7fNFigmbRiive3DyOumNCMvA==]]></Encrypt>
   554  //
   555  // </xml>
   556  func xmlUnmarshal(data []byte, p *cipherRequestHttpBody) error {
   557  	data = bytes.TrimSpace(data)
   558  	if !bytes.HasPrefix(data, msgStartElementLiteral) || !bytes.HasSuffix(data, msgEndElementLiteral) {
   559  		log.Printf("[WARNING] xmlUnmarshal failed, data:\n%s\n", data)
   560  		return xml.Unmarshal(data, p)
   561  	}
   562  	data2 := data[len(msgStartElementLiteral) : len(data)-len(msgEndElementLiteral)]
   563  
   564  	// ToUserName
   565  	ToUserNameElementBytes := data2
   566  	i := bytes.Index(ToUserNameElementBytes, msgToUserNameStartElementLiteral)
   567  	if i == -1 {
   568  		log.Printf("[WARNING] xmlUnmarshal failed, data:\n%s\n", data)
   569  		return xml.Unmarshal(data, p)
   570  	}
   571  	ToUserNameElementBytes = ToUserNameElementBytes[i+len(msgToUserNameStartElementLiteral):]
   572  	ToUserNameElementBytes = bytes.TrimLeftFunc(ToUserNameElementBytes, unicode.IsSpace)
   573  	if !bytes.HasPrefix(ToUserNameElementBytes, cdataStartLiteral) {
   574  		log.Printf("[WARNING] xmlUnmarshal failed, data:\n%s\n", data)
   575  		return xml.Unmarshal(data, p)
   576  	}
   577  	ToUserNameElementBytes = ToUserNameElementBytes[len(cdataStartLiteral):]
   578  	i = bytes.Index(ToUserNameElementBytes, cdataEndLiteral)
   579  	if i == -1 {
   580  		log.Printf("[WARNING] xmlUnmarshal failed, data:\n%s\n", data)
   581  		return xml.Unmarshal(data, p)
   582  	}
   583  	ToUserName := ToUserNameElementBytes[:i]
   584  	ToUserNameElementBytes = ToUserNameElementBytes[i+len(cdataEndLiteral):]
   585  	ToUserNameElementBytes = bytes.TrimLeftFunc(ToUserNameElementBytes, unicode.IsSpace)
   586  	if !bytes.HasPrefix(ToUserNameElementBytes, msgToUserNameEndElementLiteral) {
   587  		log.Printf("[WARNING] xmlUnmarshal failed, data:\n%s\n", data)
   588  		return xml.Unmarshal(data, p)
   589  	}
   590  	ToUserNameElementBytes = ToUserNameElementBytes[len(msgToUserNameEndElementLiteral):]
   591  
   592  	// Encrypt
   593  	EncryptElementBytes := ToUserNameElementBytes
   594  	i = bytes.Index(EncryptElementBytes, msgEncryptStartElementLiteral)
   595  	if i == -1 {
   596  		EncryptElementBytes = data2
   597  		i = bytes.Index(EncryptElementBytes, msgEncryptStartElementLiteral)
   598  		if i == -1 {
   599  			log.Printf("[WARNING] xmlUnmarshal failed, data:\n%s\n", data)
   600  			return xml.Unmarshal(data, p)
   601  		}
   602  	}
   603  	EncryptElementBytes = EncryptElementBytes[i+len(msgEncryptStartElementLiteral):]
   604  	EncryptElementBytes = bytes.TrimLeftFunc(EncryptElementBytes, unicode.IsSpace)
   605  	if !bytes.HasPrefix(EncryptElementBytes, cdataStartLiteral) {
   606  		log.Printf("[WARNING] xmlUnmarshal failed, data:\n%s\n", data)
   607  		return xml.Unmarshal(data, p)
   608  	}
   609  	EncryptElementBytes = EncryptElementBytes[len(cdataStartLiteral):]
   610  	i = bytes.Index(EncryptElementBytes, cdataEndLiteral)
   611  	if i == -1 {
   612  		log.Printf("[WARNING] xmlUnmarshal failed, data:\n%s\n", data)
   613  		return xml.Unmarshal(data, p)
   614  	}
   615  	Encrypt := EncryptElementBytes[:i]
   616  	EncryptElementBytes = EncryptElementBytes[i+len(cdataEndLiteral):]
   617  	EncryptElementBytes = bytes.TrimLeftFunc(EncryptElementBytes, unicode.IsSpace)
   618  	if !bytes.HasPrefix(EncryptElementBytes, msgEncryptEndElementLiteral) {
   619  		log.Printf("[WARNING] xmlUnmarshal failed, data:\n%s\n", data)
   620  		return xml.Unmarshal(data, p)
   621  	}
   622  
   623  	p.ToUserName = string(ToUserName)
   624  	p.Base64EncryptedMsg = Encrypt
   625  	return nil
   626  }