def _encrypt_message(self, msg, nonce, timestamp=None, crypto_class=None): from wechatpy_tornado.replies import BaseReply xml = """<xml> <Encrypt><![CDATA[{encrypt}]]></Encrypt> <MsgSignature><![CDATA[{signature}]]></MsgSignature> <TimeStamp>{timestamp}</TimeStamp> <Nonce><![CDATA[{nonce}]]></Nonce> </xml>""" if isinstance(msg, BaseReply): msg = msg.render() timestamp = timestamp or to_text(int(time.time())) pc = crypto_class(self.key) encrypt = to_text(pc.encrypt(msg, self._id)) signature = _get_signature(self.token, timestamp, nonce, encrypt) return to_text(xml.format( encrypt=encrypt, signature=signature, timestamp=timestamp, nonce=nonce ))
def _decrypt(self, text, _id, exception=None): text = to_binary(text) plain_text = self.cipher.decrypt(base64.b64decode(text)) padding = byte2int(plain_text[-1]) content = plain_text[16:-padding] xml_length = socket.ntohl(struct.unpack(b'I', content[:4])[0]) xml_content = to_text(content[4:xml_length + 4]) from_id = to_text(content[xml_length + 4:]) if from_id != _id: exception = exception or Exception raise exception() return xml_content
def _decrypt_message(self, msg, appid, mch_id, crypto_class=None): import xmltodict if not isinstance(msg, dict): msg = xmltodict.parse(to_text(msg))['xml'] req_info = msg['req_info'] if msg['appid'] != appid: raise InvalidAppIdException() if msg['mch_id'] != mch_id: raise InvalidMchIdException() pc = crypto_class(self.key) ret = pc.decrypt(req_info) return xmltodict.parse(to_text(ret))['root']
async def update(self, group_id, name): """ 修改分组名 详情请参考 http://mp.weixin.qq.com/wiki/0/56d992c605a97245eb7e617854b169fc.html :param group_id: 分组id,由微信分配 :param name: 分组名字(30个字符以内) :return: 返回的 JSON 数据包 使用示例:: from wechatpy_tornado import WeChatClient client = WeChatClient('appid', 'secret') res = client.group.update(1234, 'New Name') """ name = to_text(name) return await self._post( 'groups/update', data={ 'group': { 'id': int(group_id), 'name': name } } )
def __repr__(self): _repr = "{klass}({msg})".format(klass=self.__class__.__name__, msg=repr(self._data)) if six.PY2: return to_binary(_repr) else: return to_text(_repr)
async def get_jsapi_params(self, prepay_id, timestamp=None, nonce_str=None, jssdk=False): """ 获取 JSAPI 参数 :param prepay_id: 统一下单接口返回的 prepay_id 参数值 :param timestamp: 可选,时间戳,默认为当前时间戳 :param nonce_str: 可选,随机字符串,默认自动生成 :param jssdk: 前端调用方式,默认使用 WeixinJSBridge 使用 jssdk 调起支付的话,timestamp 的 s 为小写 使用 WeixinJSBridge 调起支付的话,timeStamp 的 S 为大写 :return: 参数 """ data = { 'appId': self.sub_appid or self.appid, 'timeStamp': timestamp or to_text(int(time.time())), 'nonceStr': nonce_str or random_string(32), 'signType': 'MD5', 'package': 'prepay_id={0}'.format(prepay_id), } sign = calculate_signature( data, self._client.api_key if not self._client.sandbox else await self._client.sandbox_api_key()) logger.debug('JSAPI payment parameters: data = %s, sign = %s', data, sign) data['paySign'] = sign if jssdk: data['timestamp'] = data.pop('timeStamp') return data
def __str__(self): _repr = 'Error code: {code}, message: {msg}'.format(code=self.errcode, msg=self.errmsg) if six.PY2: return to_binary(_repr) else: return to_text(_repr)
def parse_message(xml): """ 解析微信服务器推送的 XML 消息 :param xml: XML 消息 :return: 解析成功返回对应的消息或事件,否则返回 ``UnknownMessage`` """ if not xml: return message = xmltodict.parse(to_text(xml))['xml'] message_type = message['MsgType'].lower() event_type = None if message_type == 'event' or message_type.startswith('device_'): if 'Event' in message: event_type = message['Event'].lower() # special event type for device_event if event_type is None and message_type.startswith('device_'): event_type = message_type elif message_type.startswith('device_'): event_type = 'device_{event}'.format(event=event_type) if event_type == 'subscribe' and message.get('EventKey'): event_key = message['EventKey'] if event_key.startswith(('scanbarcode|', 'scanimage|')): event_type = 'subscribe_scan_product' message['Event'] = event_type elif event_key.startswith('qrscene_'): # Scan to subscribe with scene id event event_type = 'subscribe_scan' message['Event'] = event_type message['EventKey'] = event_key[len('qrscene_'):] message_class = EVENT_TYPES.get(event_type, UnknownMessage) else: message_class = MESSAGE_TYPES.get(message_type, UnknownMessage) return message_class(message)
def decrypt_message(self, msg): raw_data = base64.b64decode(msg) decrypted = self.cipher.decrypt(raw_data) plaintext = PKCS7Encoder.decode(decrypted) decrypted_msg = json.loads(to_text(plaintext)) if decrypted_msg['watermark']['appid'] != self.app_id: raise InvalidAppIdException() return decrypted_msg
def __repr__(self): _repr = '{klass}({code}, {msg})'.format(klass=self.__class__.__name__, code=self.errcode, msg=self.errmsg) if six.PY2: return to_binary(_repr) else: return to_text(_repr)
def __repr__(self): _repr = '{klass}({name})'.format( klass=self.__class__.__name__, name=repr(self.name) ) if six.PY2: return to_binary(_repr) else: return to_text(_repr)
def dict_to_xml(d, sign=None): xml = ['<xml>\n'] for k in sorted(d): # use sorted to avoid test error on Py3k v = d[k] if isinstance(v, six.integer_types) or (isinstance(v, six.string_types) and v.isdigit()): xml.append('<{0}>{1}</{0}>\n'.format(to_text(k), to_text(v))) else: xml.append('<{0}><![CDATA[{1}]]></{0}>\n'.format( to_text(k), to_text(v))) if sign: xml.append('<sign><![CDATA[{0}]]></sign>\n</xml>'.format( to_text(sign))) else: xml.append('</xml>') return ''.join(xml)
def __str__(self): _str = 'Error code: {code}, message: {msg}. Pay Error code: {pay_code}, message: {pay_msg}'.format( code=self.return_code, msg=self.return_msg, pay_code=self.errcode, pay_msg=self.errmsg) if six.PY2: return to_binary(_str) else: return to_text(_str)
def parse_message(xml): if not xml: return message = xmltodict.parse(to_text(xml))['xml'] message_type = message['MsgType'].lower() if message_type == 'event': event_type = message['Event'].lower() message_class = EVENT_TYPES.get(event_type, UnknownMessage) else: message_class = MESSAGE_TYPES.get(message_type, UnknownMessage) return message_class(message)
async def create(self, name): """ 创建标签 :param name: 标签名(30个字符以内) :return: 返回的 JSON 数据包 """ name = to_text(name) return await self._post('tags/create', data={'tag': { 'name': name }}, result_processor=lambda x: x['tag'])
async def update(self, tag_id, name): """ 编辑标签 :param tag_id: 标签id,由微信分配 :param name: 标签名字(30个字符以内) :return: 返回的 JSON 数据包 """ name = to_text(name) return await self._post( 'tags/update', data={'tag': { 'id': int(tag_id), 'name': name }})
def get_unauthorized(self, msg, signature, timestamp, nonce): """ 处理取消授权通知 :params msg: 加密内容 :params signature: 消息签名 :params timestamp: 时间戳 :params nonce: 随机数 """ warnings.warn( '`get_unauthorized` method of `WeChatComponent` is deprecated,' 'Use `parse_message` instead', DeprecationWarning, stacklevel=2) content = self.crypto.decrypt_message(msg, signature, timestamp, nonce) message = xmltodict.parse(to_text(content))['xml'] return ComponentUnauthorizedMessage(message)
def _decrypt_message(self, msg, signature, timestamp, nonce, crypto_class=None): if not isinstance(msg, dict): import xmltodict msg = xmltodict.parse(to_text(msg))['xml'] encrypt = msg['Encrypt'] _signature = _get_signature(self.token, timestamp, nonce, encrypt) if _signature != signature: raise InvalidSignatureException() pc = crypto_class(self.key) return pc.decrypt(encrypt, self._id)
def cache_component_verify_ticket(self, msg, signature, timestamp, nonce): """ 处理 wechat server 推送的 component_verify_ticket消息 :params msg: 加密内容 :params signature: 消息签名 :params timestamp: 时间戳 :params nonce: 随机数 """ warnings.warn( '`cache_component_verify_ticket` method of `WeChatComponent` is deprecated,' 'Use `parse_message` instead', DeprecationWarning, stacklevel=2) content = self.crypto.decrypt_message(msg, signature, timestamp, nonce) message = xmltodict.parse(to_text(content))['xml'] o = ComponentVerifyTicketMessage(message) self.session.set(o.type, o.verify_ticket)
def get_appapi_params(self, prepay_id, timestamp=None, nonce_str=None): """ 获取 APP 支付参数 :param prepay_id: 统一下单接口返回的 prepay_id 参数值 :param timestamp: 可选,时间戳,默认为当前时间戳 :param nonce_str: 可选,随机字符串,默认自动生成 :return: 签名 """ data = { 'appid': self.appid, 'partnerid': self.mch_id, 'prepayid': prepay_id, 'package': 'Sign=WXPay', 'timestamp': timestamp or to_text(int(time.time())), 'noncestr': nonce_str or random_string(32) } sign = calculate_signature(data, self._client.api_key) data['sign'] = sign return data
async def get_jsapi_signature(self, prepay_id, timestamp=None, nonce_str=None): """ 获取 JSAPI 签名 :param prepay_id: 统一下单接口返回的 prepay_id 参数值 :param timestamp: 可选,时间戳,默认为当前时间戳 :param nonce_str: 可选,随机字符串,默认自动生成 :return: 签名 """ data = { 'appId': self.sub_appid or self.appid, 'timeStamp': timestamp or to_text(int(time.time())), 'nonceStr': nonce_str or random_string(32), 'signType': 'MD5', 'package': 'prepay_id={0}'.format(prepay_id), } return calculate_signature( data, self._client.api_key if not self._client.sandbox else await self._client.sandbox_api_key())
async def parse_message(self, msg, msg_signature, timestamp, nonce): """ 处理 wechat server 推送消息 :params msg: 加密内容 :params msg_signature: 消息签名 :params timestamp: 时间戳 :params nonce: 随机数 """ content = self.crypto.decrypt_message(msg, msg_signature, timestamp, nonce) message = xmltodict.parse(to_text(content))['xml'] message_type = message['InfoType'].lower() message_class = COMPONENT_MESSAGE_TYPES.get(message_type, ComponentUnknownMessage) msg = message_class(message) if msg.type == 'component_verify_ticket': self.session.set(msg.type, msg.verify_ticket) elif msg.type in ('authorized', 'updateauthorized'): msg.query_auth_result = await self.query_auth( msg.authorization_code) return msg
async def create(self, name): """ 创建分组 详情请参考 http://mp.weixin.qq.com/wiki/0/56d992c605a97245eb7e617854b169fc.html :param name: 分组名字(30个字符以内) :return: 返回的 JSON 数据包 使用示例:: from wechatpy_tornado import WeChatClient client = WeChatClient('appid', 'secret') res = client.group.create('New Group') """ name = to_text(name) return await self._post( 'groups/create', data={'group': {'name': name}} )
def __str__(self): if six.PY2: return to_binary(self.render()) else: return to_text(self.render())
def __base64_decode(self, text): return to_text(base64.b64decode(to_binary(text)))
def calculate_signature_hmac(params, api_key): url = format_url(params, api_key) sign = to_text( hmac.new(api_key.encode(), msg=url, digestmod=hashlib.sha256).hexdigest().upper()) return sign
def calculate_signature(params, api_key): url = format_url(params, api_key) logger.debug("Calculate Signature URL: %s", url) return to_text(hashlib.md5(url).hexdigest().upper())
def get(self, key, default=None): key = self.key_name(key) value = self.mc.get(key) if value is None: return default return json.loads(to_text(value))
def __to_text(self, value): return to_text(value)