Exemple #1
0
 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
Exemple #2
0
    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"]
Exemple #3
0
    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
Exemple #4
0
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)
Exemple #5
0
 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
Exemple #6
0
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)
Exemple #7
0
    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))
Exemple #8
0
    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
                          }})
Exemple #9
0
    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"],
        )
Exemple #10
0
    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)
Exemple #11
0
    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
Exemple #12
0
    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
Exemple #13
0
    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}})
Exemple #14
0
    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}})
Exemple #15
0
    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,
        )
Exemple #16
0
    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
Exemple #17
0
    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,
            },
        )
Exemple #18
0
 def __to_text(self, value):
     return to_text(value)
Exemple #19
0
 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))
Exemple #21
0
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
Exemple #22
0
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())