Enhance announcement storage functionality by adding a method to save all announcements by source, retaining the latest 100 per source. Update related logging and comments for clarity. Adjusted the main script to utilize the new storage method and log the saving process. Updated the markdown file timestamp.
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
注意事项
|
||||
1.WXBizMsgCrypt.py文件封装了WXBizMsgCrypt接口类(Python3以及以上版本使用 WXBizMsgCrypt3.py),提供了用户接入企业微信的三个接口,Sample.py文件提供了如何使用这三个接口的示例,ierror.py提供了错误码。
|
||||
2.WXBizMsgCrypt封装了VerifyURL, DecryptMsg, EncryptMsg三个接口,分别用于开发者验证回调url,收到用户回复消息的解密以及开发者回复消息的加密过程。使用方法可以参考Sample.py文件。
|
||||
3.加解密协议请参考企业微信官方文档。
|
||||
4.本代码用到了pycrypto第三方库,请开发者自行安装此库再使用。
|
||||
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#########################################################################
|
||||
# Author: jonyqin
|
||||
# Created Time: Thu 11 Sep 2014 03:55:41 PM CST
|
||||
# File Name: Sample.py
|
||||
# Description: WXBizMsgCrypt 使用demo文件
|
||||
#########################################################################
|
||||
from WXBizMsgCrypt import WXBizMsgCrypt
|
||||
import xml.etree.cElementTree as ET
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 企业在企业微信后台上设置的密钥相关配置在这里 TODO
|
||||
sToken = "xxxxxxx"
|
||||
sEncodingAESKey = "xxxxxxx"
|
||||
sCorpID = "ww1436e0e65a779aee"
|
||||
'''
|
||||
------------使用示例一:验证回调URL---------------
|
||||
*企业开启回调模式时,企业号会向验证url发送一个get请求
|
||||
假设点击验证时,企业收到类似请求:
|
||||
* GET /cgi-bin/wxpush?msg_signature=5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3×tamp=1409659589&nonce=263014780&echostr=P9nAzCzyDtyTWESHep1vC5X9xho%2FqYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp%2B4RPcs8TgAE7OaBO%2BFZXvnaqQ%3D%3D
|
||||
* HTTP/1.1 Host: qy.weixin.qq.com
|
||||
|
||||
接收到该请求时,企业应 1.解析出Get请求的参数,包括消息体签名(msg_signature),时间戳(timestamp),随机数字串(nonce)以及企业微信推送过来的随机加密字符串(echostr),
|
||||
这一步注意作URL解码。
|
||||
2.验证消息体签名的正确性
|
||||
3. 解密出echostr原文,将原文当作Get请求的response,返回给企业微信
|
||||
第2,3步可以用企业微信提供的库函数VerifyURL来实现。
|
||||
'''
|
||||
wxcpt=WXBizMsgCrypt(sToken,sEncodingAESKey,sCorpID)
|
||||
#sVerifyMsgSig=HttpUtils.ParseUrl("msg_signature")
|
||||
#ret = wxcpt.VerifyAESKey()
|
||||
#print ret
|
||||
sVerifyMsgSig="012bc692d0a58dd4b10f8dfe5c4ac00ae211ebeb"
|
||||
#sVerifyTimeStamp=HttpUtils.ParseUrl("timestamp")
|
||||
sVerifyTimeStamp="1476416373"
|
||||
#sVerifyNonce=HttpUitls.ParseUrl("nonce")
|
||||
sVerifyNonce="47744683"
|
||||
#sVerifyEchoStr=HttpUtils.ParseUrl("echostr")
|
||||
sVerifyEchoStr="fsi1xnbH4yQh0+PJxcOdhhK6TDXkjMyhEPA7xB2TGz6b+g7xyAbEkRxN/3cNXW9qdqjnoVzEtpbhnFyq6SVHyA=="
|
||||
ret,sEchoStr=wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,sVerifyNonce,sVerifyEchoStr)
|
||||
if(ret!=0):
|
||||
print "ERR: VerifyURL ret: " + str(ret)
|
||||
sys.exit(1)
|
||||
#验证URL成功,将sEchoStr返回给企业号
|
||||
#HttpUtils.SetResponse(sEchoStr)
|
||||
|
||||
'''
|
||||
------------使用示例二:对用户回复的消息解密---------------
|
||||
用户回复消息或者点击事件响应时,企业会收到回调消息,此消息是经过企业微信加密之后的密文以post形式发送给企业,密文格式请参考官方文档
|
||||
假设企业收到企业微信的回调消息如下:
|
||||
POST /cgi-bin/wxpush? msg_signature=477715d11cdb4164915debcba66cb864d751f3e6×tamp=1409659813&nonce=1372623149 HTTP/1.1
|
||||
Host: qy.weixin.qq.com
|
||||
Content-Length: 613
|
||||
<xml> <ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt>
|
||||
<AgentID><![CDATA[218]]></AgentID>
|
||||
</xml>
|
||||
|
||||
企业收到post请求之后应该 1.解析出url上的参数,包括消息体签名(msg_signature),时间戳(timestamp)以及随机数字串(nonce)
|
||||
2.验证消息体签名的正确性。 3.将post请求的数据进行xml解析,并将<Encrypt>标签的内容进行解密,解密出来的明文即是用户回复消息的明文,明文格式请参考官方文档
|
||||
第2,3步可以用企业微信提供的库函数DecryptMsg来实现。
|
||||
'''
|
||||
# sReqMsgSig = HttpUtils.ParseUrl("msg_signature")
|
||||
sReqMsgSig = "0c3914025cb4b4d68103f6bfc8db550f79dcf48e"
|
||||
sReqTimeStamp = "1476422779"
|
||||
sReqNonce = "1597212914"
|
||||
sReqData = "<xml><ToUserName><![CDATA[ww1436e0e65a779aee]]></ToUserName>\n<Encrypt><![CDATA[Kl7kjoSf6DMD1zh7rtrHjFaDapSCkaOnwu3bqLc5tAybhhMl9pFeK8NslNPVdMwmBQTNoW4mY7AIjeLvEl3NyeTkAgGzBhzTtRLNshw2AEew+kkYcD+Fq72Kt00fT0WnN87hGrW8SqGc+NcT3mu87Ha3dz1pSDi6GaUA6A0sqfde0VJPQbZ9U+3JWcoD4Z5jaU0y9GSh010wsHF8KZD24YhmZH4ch4Ka7ilEbjbfvhKkNL65HHL0J6EYJIZUC2pFrdkJ7MhmEbU2qARR4iQHE7wy24qy0cRX3Mfp6iELcDNfSsPGjUQVDGxQDCWjayJOpcwocugux082f49HKYg84EpHSGXAyh+/oxwaWbvL6aSDPOYuPDGOCI8jmnKiypE+]]></Encrypt>\n<AgentID><![CDATA[1000002]]></AgentID>\n</xml>"
|
||||
ret,sMsg=wxcpt.DecryptMsg( sReqData, sReqMsgSig, sReqTimeStamp, sReqNonce)
|
||||
print ret,sMsg
|
||||
if( ret!=0 ):
|
||||
print "ERR: DecryptMsg ret: " + str(ret)
|
||||
sys.exit(1)
|
||||
# 解密成功,sMsg即为xml格式的明文
|
||||
# TODO: 对明文的处理
|
||||
# For example:
|
||||
xml_tree = ET.fromstring(sMsg)
|
||||
content = xml_tree.find("Content").text
|
||||
print content
|
||||
# ...
|
||||
# ...
|
||||
|
||||
'''
|
||||
------------使用示例三:企业回复用户消息的加密---------------
|
||||
企业被动回复用户的消息也需要进行加密,并且拼接成密文格式的xml串。
|
||||
假设企业需要回复用户的明文如下:
|
||||
<xml>
|
||||
<ToUserName><![CDATA[mycreate]]></ToUserName>
|
||||
<FromUserName><![CDATA[wx5823bf96d3bd56c7]]></FromUserName>
|
||||
<CreateTime>1348831860</CreateTime>
|
||||
<MsgType><![CDATA[text]]></MsgType>
|
||||
<Content><![CDATA[this is a test]]></Content>
|
||||
<MsgId>1234567890123456</MsgId>
|
||||
<AgentID>128</AgentID>
|
||||
</xml>
|
||||
|
||||
为了将此段明文回复给用户,企业应: 1.自己生成时间时间戳(timestamp),随机数字串(nonce)以便生成消息体签名,也可以直接用从企业微信的post url上解析出的对应值。
|
||||
2.将明文加密得到密文。 3.用密文,步骤1生成的timestamp,nonce和企业在企业微信设定的token生成消息体签名。 4.将密文,消息体签名,时间戳,随机数字串拼接成xml格式的字符串,发送给企业号。
|
||||
以上2,3,4步可以用企业微信提供的库函数EncryptMsg来实现。
|
||||
'''
|
||||
sRespData = "<xml><ToUserName>ww1436e0e65a779aee</ToUserName><FromUserName>ChenJiaShun</FromUserName><CreateTime>1476422779</CreateTime><MsgType>text</MsgType><Content>你好</Content><MsgId>1456453720</MsgId><AgentID>1000002</AgentID></xml>"
|
||||
ret,sEncryptMsg=wxcpt.EncryptMsg(sRespData, sReqNonce, sReqTimeStamp)
|
||||
if( ret!=0 ):
|
||||
print "ERR: EncryptMsg ret: " + str(ret)
|
||||
sys.exit(1)
|
||||
#ret == 0 加密成功,企业需要将sEncryptMsg返回给企业号
|
||||
#TODO:
|
||||
#HttpUitls.SetResponse(sEncryptMsg) #测试解密
|
||||
@@ -0,0 +1,274 @@
|
||||
#!/usr/bin/env python
|
||||
#-*- encoding:utf-8 -*-
|
||||
|
||||
""" 对企业微信发送给企业后台的消息加解密示例代码.
|
||||
@copyright: Copyright (c) 1998-2014 Tencent Inc.
|
||||
|
||||
"""
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
import base64
|
||||
import string
|
||||
import random
|
||||
import hashlib
|
||||
import time
|
||||
import struct
|
||||
from Crypto.Cipher import AES
|
||||
import xml.etree.cElementTree as ET
|
||||
import sys
|
||||
import socket
|
||||
stdi,stdo,stde=sys.stdin,sys.stdout,sys.stderr
|
||||
reload(sys)
|
||||
sys.stdin,sys.stdout,sys.stderr=stdi,stdo,stde
|
||||
import ierror
|
||||
sys.setdefaultencoding('utf-8')
|
||||
|
||||
"""
|
||||
关于Crypto.Cipher模块,ImportError: No module named 'Crypto'解决方案
|
||||
请到官方网站 https://www.dlitz.net/software/pycrypto/ 下载pycrypto。
|
||||
下载后,按照README中的“Installation”小节的提示进行pycrypto安装。
|
||||
"""
|
||||
class FormatException(Exception):
|
||||
pass
|
||||
|
||||
def throw_exception(message, exception_class=FormatException):
|
||||
"""my define raise exception function"""
|
||||
raise exception_class(message)
|
||||
|
||||
class SHA1:
|
||||
"""计算企业微信的消息签名接口"""
|
||||
|
||||
def getSHA1(self, token, timestamp, nonce, encrypt):
|
||||
"""用SHA1算法生成安全签名
|
||||
@param token: 票据
|
||||
@param timestamp: 时间戳
|
||||
@param encrypt: 密文
|
||||
@param nonce: 随机字符串
|
||||
@return: 安全签名
|
||||
"""
|
||||
try:
|
||||
sortlist = [token, timestamp, nonce, encrypt]
|
||||
sortlist.sort()
|
||||
sha = hashlib.sha1()
|
||||
sha.update("".join(sortlist))
|
||||
return ierror.WXBizMsgCrypt_OK, sha.hexdigest()
|
||||
except Exception,e:
|
||||
print e
|
||||
return ierror.WXBizMsgCrypt_ComputeSignature_Error, None
|
||||
|
||||
|
||||
class XMLParse:
|
||||
"""提供提取消息格式中的密文及生成回复消息格式的接口"""
|
||||
|
||||
# xml消息模板
|
||||
AES_TEXT_RESPONSE_TEMPLATE = """<xml>
|
||||
<Encrypt><![CDATA[%(msg_encrypt)s]]></Encrypt>
|
||||
<MsgSignature><![CDATA[%(msg_signaturet)s]]></MsgSignature>
|
||||
<TimeStamp>%(timestamp)s</TimeStamp>
|
||||
<Nonce><![CDATA[%(nonce)s]]></Nonce>
|
||||
</xml>"""
|
||||
|
||||
def extract(self, xmltext):
|
||||
"""提取出xml数据包中的加密消息
|
||||
@param xmltext: 待提取的xml字符串
|
||||
@return: 提取出的加密消息字符串
|
||||
"""
|
||||
try:
|
||||
xml_tree = ET.fromstring(xmltext)
|
||||
encrypt = xml_tree.find("Encrypt")
|
||||
return ierror.WXBizMsgCrypt_OK, encrypt.text
|
||||
except Exception,e:
|
||||
print e
|
||||
return ierror.WXBizMsgCrypt_ParseXml_Error,None
|
||||
|
||||
def generate(self, encrypt, signature, timestamp, nonce):
|
||||
"""生成xml消息
|
||||
@param encrypt: 加密后的消息密文
|
||||
@param signature: 安全签名
|
||||
@param timestamp: 时间戳
|
||||
@param nonce: 随机字符串
|
||||
@return: 生成的xml字符串
|
||||
"""
|
||||
resp_dict = {
|
||||
'msg_encrypt' : encrypt,
|
||||
'msg_signaturet': signature,
|
||||
'timestamp' : timestamp,
|
||||
'nonce' : nonce,
|
||||
}
|
||||
resp_xml = self.AES_TEXT_RESPONSE_TEMPLATE % resp_dict
|
||||
return resp_xml
|
||||
|
||||
|
||||
class PKCS7Encoder():
|
||||
"""提供基于PKCS7算法的加解密接口"""
|
||||
|
||||
block_size = 32
|
||||
def encode(self, text):
|
||||
""" 对需要加密的明文进行填充补位
|
||||
@param text: 需要进行填充补位操作的明文
|
||||
@return: 补齐明文字符串
|
||||
"""
|
||||
text_length = len(text)
|
||||
# 计算需要填充的位数
|
||||
amount_to_pad = self.block_size - (text_length % self.block_size)
|
||||
if amount_to_pad == 0:
|
||||
amount_to_pad = self.block_size
|
||||
# 获得补位所用的字符
|
||||
pad = chr(amount_to_pad)
|
||||
return text + pad * amount_to_pad
|
||||
|
||||
def decode(self, decrypted):
|
||||
"""删除解密后明文的补位字符
|
||||
@param decrypted: 解密后的明文
|
||||
@return: 删除补位字符后的明文
|
||||
"""
|
||||
pad = ord(decrypted[-1])
|
||||
if pad<1 or pad >32:
|
||||
pad = 0
|
||||
return decrypted[:-pad]
|
||||
|
||||
|
||||
class Prpcrypt(object):
|
||||
"""提供接收和推送给企业微信消息的加解密接口"""
|
||||
|
||||
def __init__(self,key):
|
||||
|
||||
#self.key = base64.b64decode(key+"=")
|
||||
self.key = key
|
||||
# 设置加解密模式为AES的CBC模式
|
||||
self.mode = AES.MODE_CBC
|
||||
|
||||
|
||||
def encrypt(self,text,receiveid):
|
||||
"""对明文进行加密
|
||||
@param text: 需要加密的明文
|
||||
@return: 加密得到的字符串
|
||||
"""
|
||||
# 16位随机字符串添加到明文开头
|
||||
text = self.get_random_str() + struct.pack("I",socket.htonl(len(text))) + text + receiveid
|
||||
# 使用自定义的填充方式对明文进行补位填充
|
||||
pkcs7 = PKCS7Encoder()
|
||||
text = pkcs7.encode(text)
|
||||
# 加密
|
||||
cryptor = AES.new(self.key,self.mode,self.key[:16])
|
||||
try:
|
||||
ciphertext = cryptor.encrypt(text)
|
||||
# 使用BASE64对加密后的字符串进行编码
|
||||
return ierror.WXBizMsgCrypt_OK, base64.b64encode(ciphertext)
|
||||
except Exception,e:
|
||||
print e
|
||||
return ierror.WXBizMsgCrypt_EncryptAES_Error,None
|
||||
|
||||
def decrypt(self,text,receiveid):
|
||||
"""对解密后的明文进行补位删除
|
||||
@param text: 密文
|
||||
@return: 删除填充补位后的明文
|
||||
"""
|
||||
try:
|
||||
cryptor = AES.new(self.key,self.mode,self.key[:16])
|
||||
# 使用BASE64对密文进行解码,然后AES-CBC解密
|
||||
plain_text = cryptor.decrypt(base64.b64decode(text))
|
||||
except Exception,e:
|
||||
print e
|
||||
return ierror.WXBizMsgCrypt_DecryptAES_Error,None
|
||||
try:
|
||||
pad = ord(plain_text[-1])
|
||||
# 去掉补位字符串
|
||||
#pkcs7 = PKCS7Encoder()
|
||||
#plain_text = pkcs7.encode(plain_text)
|
||||
# 去除16位随机字符串
|
||||
content = plain_text[16:-pad]
|
||||
xml_len = socket.ntohl(struct.unpack("I",content[ : 4])[0])
|
||||
xml_content = content[4 : xml_len+4]
|
||||
from_receiveid = content[xml_len+4:]
|
||||
except Exception,e:
|
||||
print e
|
||||
return ierror.WXBizMsgCrypt_IllegalBuffer,None
|
||||
if from_receiveid != receiveid:
|
||||
return ierror.WXBizMsgCrypt_ValidateCorpid_Error,None
|
||||
return 0,xml_content
|
||||
|
||||
def get_random_str(self):
|
||||
""" 随机生成16位字符串
|
||||
@return: 16位字符串
|
||||
"""
|
||||
rule = string.letters + string.digits
|
||||
str = random.sample(rule, 16)
|
||||
return "".join(str)
|
||||
|
||||
class WXBizMsgCrypt(object):
|
||||
#构造函数
|
||||
def __init__(self,sToken,sEncodingAESKey,sReceiveId):
|
||||
try:
|
||||
self.key = base64.b64decode(sEncodingAESKey+"=")
|
||||
assert len(self.key) == 32
|
||||
except:
|
||||
throw_exception("[error]: EncodingAESKey unvalid !", FormatException)
|
||||
# return ierror.WXBizMsgCrypt_IllegalAesKey,None
|
||||
self.m_sToken = sToken
|
||||
self.m_sReceiveId = sReceiveId
|
||||
|
||||
#验证URL
|
||||
#@param sMsgSignature: 签名串,对应URL参数的msg_signature
|
||||
#@param sTimeStamp: 时间戳,对应URL参数的timestamp
|
||||
#@param sNonce: 随机串,对应URL参数的nonce
|
||||
#@param sEchoStr: 随机串,对应URL参数的echostr
|
||||
#@param sReplyEchoStr: 解密之后的echostr,当return返回0时有效
|
||||
#@return:成功0,失败返回对应的错误码
|
||||
|
||||
def VerifyURL(self, sMsgSignature, sTimeStamp, sNonce, sEchoStr):
|
||||
sha1 = SHA1()
|
||||
ret,signature = sha1.getSHA1(self.m_sToken, sTimeStamp, sNonce, sEchoStr)
|
||||
if ret != 0:
|
||||
return ret, None
|
||||
if not signature == sMsgSignature:
|
||||
return ierror.WXBizMsgCrypt_ValidateSignature_Error, None
|
||||
pc = Prpcrypt(self.key)
|
||||
ret,sReplyEchoStr = pc.decrypt(sEchoStr,self.m_sReceiveId)
|
||||
return ret,sReplyEchoStr
|
||||
|
||||
def EncryptMsg(self, sReplyMsg, sNonce, timestamp = None):
|
||||
#将企业回复用户的消息加密打包
|
||||
#@param sReplyMsg: 企业号待回复用户的消息,xml格式的字符串
|
||||
#@param sTimeStamp: 时间戳,可以自己生成,也可以用URL参数的timestamp,如为None则自动用当前时间
|
||||
#@param sNonce: 随机串,可以自己生成,也可以用URL参数的nonce
|
||||
#sEncryptMsg: 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串,
|
||||
#return:成功0,sEncryptMsg,失败返回对应的错误码None
|
||||
pc = Prpcrypt(self.key)
|
||||
ret,encrypt = pc.encrypt(sReplyMsg, self.m_sReceiveId)
|
||||
if ret != 0:
|
||||
return ret,None
|
||||
if timestamp is None:
|
||||
timestamp = str(int(time.time()))
|
||||
# 生成安全签名
|
||||
sha1 = SHA1()
|
||||
ret,signature = sha1.getSHA1(self.m_sToken, timestamp, sNonce, encrypt)
|
||||
if ret != 0:
|
||||
return ret,None
|
||||
xmlParse = XMLParse()
|
||||
return ret,xmlParse.generate(encrypt, signature, timestamp, sNonce)
|
||||
|
||||
def DecryptMsg(self, sPostData, sMsgSignature, sTimeStamp, sNonce):
|
||||
# 检验消息的真实性,并且获取解密后的明文
|
||||
# @param sMsgSignature: 签名串,对应URL参数的msg_signature
|
||||
# @param sTimeStamp: 时间戳,对应URL参数的timestamp
|
||||
# @param sNonce: 随机串,对应URL参数的nonce
|
||||
# @param sPostData: 密文,对应POST请求的数据
|
||||
# xml_content: 解密后的原文,当return返回0时有效
|
||||
# @return: 成功0,失败返回对应的错误码
|
||||
# 验证安全签名
|
||||
xmlParse = XMLParse()
|
||||
ret,encrypt = xmlParse.extract(sPostData)
|
||||
if ret != 0:
|
||||
return ret, None
|
||||
sha1 = SHA1()
|
||||
ret,signature = sha1.getSHA1(self.m_sToken, sTimeStamp, sNonce, encrypt)
|
||||
if ret != 0:
|
||||
return ret, None
|
||||
if not signature == sMsgSignature:
|
||||
return ierror.WXBizMsgCrypt_ValidateSignature_Error, None
|
||||
pc = Prpcrypt(self.key)
|
||||
ret,xml_content = pc.decrypt(encrypt,self.m_sReceiveId)
|
||||
return ret,xml_content
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#########################################################################
|
||||
# Author: jonyqin
|
||||
# Created Time: Thu 11 Sep 2014 01:53:58 PM CST
|
||||
# File Name: ierror.py
|
||||
# Description:定义错误码含义
|
||||
#########################################################################
|
||||
WXBizMsgCrypt_OK = 0
|
||||
WXBizMsgCrypt_ValidateSignature_Error = -40001
|
||||
WXBizMsgCrypt_ParseXml_Error = -40002
|
||||
WXBizMsgCrypt_ComputeSignature_Error = -40003
|
||||
WXBizMsgCrypt_IllegalAesKey = -40004
|
||||
WXBizMsgCrypt_ValidateCorpid_Error = -40005
|
||||
WXBizMsgCrypt_EncryptAES_Error = -40006
|
||||
WXBizMsgCrypt_DecryptAES_Error = -40007
|
||||
WXBizMsgCrypt_IllegalBuffer = -40008
|
||||
WXBizMsgCrypt_EncodeBase64_Error = -40009
|
||||
WXBizMsgCrypt_DecodeBase64_Error = -40010
|
||||
WXBizMsgCrypt_GenReturnXml_Error = -40011
|
||||
Reference in New Issue
Block a user