def _decrypt(self, text, _id, exception=None): text = to_binary(text) plain_text = self.cipher.decrypt(base64.b64decode(text)) padding = 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"]
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": f"prepay_id={prepay_id}", } sign = calculate_signature( data, self._client.api_key if not self._client.sandbox else 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 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 = f"device_{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 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)
def _encrypt_message(self, msg, nonce, timestamp=None, crypto_class=None): from findy.vendor.wechatpy.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 update(self, tag_id, name): """ 编辑标签 :param tag_id: 标签id,由微信分配 :param name: 标签名字(30个字符以内) :return: 返回的 JSON 数据包 """ name = to_text(name) return self._post("tags/update", data={"tag": { "id": int(tag_id), "name": name }})
def create(self, name): """ 创建标签 :param name: 标签名(30个字符以内) :return: 返回的 JSON 数据包 """ name = to_text(name) return self._post( "tags/create", data={"tag": { "name": name }}, result_processor=lambda x: x["tag"], )
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 get_qrcode_url(self, ticket, data=None): """ 通过 ticket 换取二维码地址 详情请参考 https://iot.weixin.qq.com/wiki/new/index.html?page=3-4-4 :param ticket: 二维码 ticket :param data: 额外数据 :return: 二维码地址 """ url = f"https://we.qq.com/d/{ticket}" if data: if isinstance(data, (dict, tuple, list)): data = urllib.urlencode(data) data = to_text(base64.b64encode(to_binary(data))) url = f"{url}#{data}" return url
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
def create(self, name): """ 创建分组 详情请参考 http://mp.weixin.qq.com/wiki/0/56d992c605a97245eb7e617854b169fc.html :param name: 分组名字(30个字符以内) :return: 返回的 JSON 数据包 使用示例:: from findy.vendor.wechatpy import WeChatClient client = WeChatClient('appid', 'secret') res = client.group.create('New Group') """ name = to_text(name) return self._post("groups/create", data={"group": {"name": name}})
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 findy.vendor.wechatpy import WeChatClient client = WeChatClient('appid', 'secret') res = client.group.update(1234, 'New Name') """ name = to_text(name) return self._post("groups/update", data={"group": {"id": int(group_id), "name": name}})
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": f"prepay_id={prepay_id}", } return calculate_signature( data, self._client.api_key if not self._client.sandbox else self._client.sandbox_api_key, )
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 = self.query_auth(msg.authorization_code) return msg
def send_message(self, device_type, device_id, user_id, content): """ 主动发送消息给设备 详情请参考 https://iot.weixin.qq.com/wiki/new/index.html?page=3-4-3 :param device_type: 设备类型,目前为“公众账号原始ID” :param device_id: 设备ID :param user_id: 微信用户账号的openid :param content: 消息内容,BASE64编码 :return: 返回的 JSON 数据包 """ content = to_text(base64.b64encode(to_binary(content))) return self._post( "transmsg", data={ "device_type": device_type, "device_id": device_id, "open_id": user_id, "content": content, }, )
def __to_text(self, value): return to_text(value)
def __base64_decode(self, text): return to_text(base64.b64decode(to_binary(text)))
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 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())