Skip to content

修改为兼容PY3 #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ dist
*.egg-info
*.pyc
*.db
*.swp
.idea
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# 变更说明

作者:[@raptorz](https://github.com/raptorz)

* 支持python3
* 符合PEP8
* 增加token管理,包括js_ticket
* 增加模板消息发送功能
* 可选是否验证https证书(原版为不验证)
* event_map改为可扩展

# 微信公众号Python-SDK

作者: [@jeff_kit](http://twitter.com/jeff_kit)
Expand Down
44 changes: 35 additions & 9 deletions wechat/crypt.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#encoding=utf-8
# encoding=utf-8

import base64
import string
Expand All @@ -8,10 +8,21 @@
import struct
from Crypto.Cipher import AES
import xml.etree.cElementTree as ET
import sys
import socket
reload(sys)
sys.setdefaultencoding('utf-8')
import sys


if sys.version < "3":
reload(sys)
sys.setdefaultencoding('utf-8')
PY3 = False

def str2bytes(s):
return s
else:
def str2bytes(s):
return s.encode("utf-8") if isinstance(s, str) else s


WXBizMsgCrypt_OK = 0
WXBizMsgCrypt_ValidateSignature_Error = -40001
Expand Down Expand Up @@ -63,6 +74,13 @@ def getSHA1(self, token, timestamp, nonce, encrypt):
except Exception:
return WXBizMsgCrypt_ComputeSignature_Error, None

@staticmethod
def getSignature(token, timestamp, nonce):
sign_ele = [token, timestamp, nonce]
sign_ele.sort()
s = "".join(sign_ele)
return hashlib.sha1(str2bytes(s)).hexdigest()


class XMLParse:
"""提供提取消息格式中的密文及生成回复消息格式的接口"""
Expand All @@ -82,7 +100,7 @@ def extract(self, xmltext):
xml_tree = ET.fromstring(xmltext)
encrypt = xml_tree.find("Encrypt")
touser_name = xml_tree.find("ToUserName")
if touser_name != None:
if touser_name is not None:
touser_name = touser_name.text
return WXBizMsgCrypt_OK, encrypt.text, touser_name
except Exception:
Expand Down Expand Up @@ -139,7 +157,7 @@ class Prpcrypt(object):
"""提供接收和推送给公众平台消息的加解密接口"""

def __init__(self, key):
#self.key = base64.b64decode(key+"=")
# self.key = base64.b64decode(key+"=")
self.key = key
# 设置加解密模式为AES的CBC模式
self.mode = AES.MODE_CBC
Expand Down Expand Up @@ -178,8 +196,8 @@ def decrypt(self, text, appid):
try:
pad = ord(plain_text[-1])
# 去掉补位字符串
#pkcs7 = PKCS7Encoder()
#plain_text = pkcs7.encode(plain_text)
# pkcs7 = PKCS7Encoder()
# plain_text = pkcs7.encode(plain_text)
# 去除16位随机字符串
content = plain_text[16:-pad]
xml_len = socket.ntohl(struct.unpack("I", content[:4])[0])
Expand All @@ -202,17 +220,21 @@ def get_random_str(self):

class WXBizMsgCrypt(object):
def __init__(self, sToken, sEncodingAESKey, sCorpId):
(sToken, sEncodingAESKey, sCorpId) = \
map(str2bytes, (sToken, sEncodingAESKey, sCorpId))
try:
self.key = base64.b64decode(sEncodingAESKey+"=")
assert len(self.key) == 32
except:
throw_exception("[error]: EncodingAESKey unvalid !",
FormatException)
#return WXBizMsgCrypt_IllegalAesKey)
# return WXBizMsgCrypt_IllegalAesKey)
self.m_sToken = sToken
self.m_sCorpid = sCorpId

def VerifyURL(self, sMsgSignature, sTimeStamp, sNonce, sEchoStr):
(sMsgSignature, sTimeStamp, sNonce, sEchoStr) = \
map(str2bytes, (sMsgSignature, sTimeStamp, sNonce, sEchoStr))
sha1 = SHA1()
ret, signature = sha1.getSHA1(self.m_sToken,
sTimeStamp, sNonce, sEchoStr)
Expand All @@ -225,6 +247,8 @@ def VerifyURL(self, sMsgSignature, sTimeStamp, sNonce, sEchoStr):
return ret, sReplyEchoStr

def EncryptMsg(self, sReplyMsg, sNonce, timestamp=None):
(sReplyMsg, sNonce, timestamp) = \
map(str2bytes, (sReplyMsg, sNonce, timestamp))
pc = Prpcrypt(self.key)
ret, encrypt = pc.encrypt(sReplyMsg, self.m_sCorpid)
if ret != 0:
Expand All @@ -241,6 +265,8 @@ def EncryptMsg(self, sReplyMsg, sNonce, timestamp=None):
return ret, xmlParse.generate(encrypt, signature, timestamp, sNonce)

def DecryptMsg(self, sPostData, sMsgSignature, sTimeStamp, sNonce):
(sPostData, sMsgSignature, sTimeStamp, sNonce) = \
map(str2bytes, (sPostData, sMsgSignature, sTimeStamp, sNonce))
xmlParse = XMLParse()
ret, encrypt, touser_name = xmlParse.extract(sPostData)
if ret != 0:
Expand Down
22 changes: 10 additions & 12 deletions wechat/enterprise.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#encoding=utf-8
# encoding=utf-8

import requests
import time
Expand All @@ -9,6 +9,8 @@
WxVideoResponse, WxNewsResponse, APIError, WxEmptyResponse
from .official import WxApplication as BaseApplication, WxBaseApi
from .crypt import WXBizMsgCrypt
import sys


__all__ = ['WxRequest', 'WxResponse', 'WxArticle', 'WxImage',
'WxVoice', 'WxVideo', 'WxLink', 'WxTextResponse',
Expand Down Expand Up @@ -60,7 +62,7 @@ def process(self, params, xml=None, token=None, corp_id=None,
self.pre_process()
rsp = func(self.req)
self.post_process()
result = rsp.as_xml().encode('UTF-8')
result = rsp.as_xml().encode('UTF-8')

if not result:
return ''
Expand Down Expand Up @@ -114,7 +116,7 @@ def get_access_token(self, url=None, **kwargs):
params.update(kwargs)
rsp = requests.get(url or self.api_entry + 'cgi-bin/gettoken',
params=params,
verify=False)
verify=WxBaseApi.VERIFY)
return self._process_response(rsp)

def departments(self):
Expand Down Expand Up @@ -335,16 +337,12 @@ def delete_menu(self, agentid):
# OAuth2
def authorize_url(self, appid, redirect_uri, response_type='code',
scope='snsapi_base', state=None):
# 变态的微信实现,参数的顺序也有讲究。。艹!这个实现太恶心,太恶心!
url = 'https://open.weixin.qq.com/connect/oauth2/authorize?'
rd_uri = urllib.urlencode({'redirect_uri': redirect_uri})
url += 'appid=%s&' % appid
url += rd_uri
url += '&response_type=' + response_type
url += '&scope=' + scope
params = dict(appid=appid, redirect_uri=redirect_uri, response_type=response_type, scope=scope)
if state:
url += '&state=' + state
return url + '#wechat_redirect'
params['state'] = state
url = '?'.join(['https://open.weixin.qq.com/connect/oauth2/authorize', urllib.urlencode(sorted(params.items()))])
url = '#'.join([url, 'wechat_redirect'])
return url

def get_user_info(self, agentid, code):
return self._get('cgi-bin/user/getuserinfo',
Expand Down
7 changes: 6 additions & 1 deletion wechat/models.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
#encoding=utf-8
# encoding=utf-8

from xml.dom import minidom
import collections
import time
import sys

if sys.version > "3":
long = int
unicode = str


def kv2element(key, value, doc):
Expand Down
Loading