Skip to content
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

some fix to be compatible with py3k #33

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ dist
*.pyc
*.db
.idea
/venv*

### Django ###
*.log
Expand Down
24 changes: 24 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
clean_pyc:
@find . -name "*.pyc" -exec rm {} +

new_venv:
#@virtualenv venv
@python3 -mvenv venv

install:
@source venv/bin/activate; pip install -e .

init: new_venv
@source venv/bin/activate; pip install --upgrade pip
$(MAKE) install

clean:
@rm -rf dist build

dist: clean
@source venv/bin/activate; pip install --upgrade setuptools wheel
@source venv/bin/activate; python setup.py sdist bdist_wheel

publish: dist
@source venv/bin/activate; pip install --upgrade twine
@source venv/bin/activate; twine upload dist/*
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# 微信公众号Python-SDK

![](https://img.shields.io/pypi/pyversions/wechat3)

作者: [@jeff_kit](http://twitter.com/jeff_kit)

本SDK支持微信公众号以及企业号的上行消息及OAuth接口。本文档及SDK假设使用者已经具备微信公众号开发的基础知识,及有能力通过微信公众号、企业号的文档来查找相关的接口详情。
Expand All @@ -9,11 +11,11 @@

### pip

pip install wechat
pip install wechat3

### 源码安装

git clone git@github.com:jeffkit/wechat.git
git clone https://github.com/tclh123/wechat.git
cd wechat
python setup.py install

Expand Down
49 changes: 34 additions & 15 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
#!/usr/bin/env python

from io import open
from setuptools import setup, find_packages
from wechat import VERSION

url="https://github.com/jeffkit/wechat"

long_description="Wechat Python SDK"

setup(name="wechat",
version=VERSION,
description=long_description,
maintainer="jeff kit",
maintainer_email="bbmyth@gmail.com",
url = url,
long_description=long_description,
install_requires = ['requests'],
packages=find_packages('.'),
)


setup(
name='wechat3',
version=VERSION,
description='Wechat Python SDK',
long_description=open("README.md", encoding='utf-8').read(),
long_description_content_type='text/markdown',
classifiers=[
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Development Status :: 5 - Production/Stable',
'Environment :: Console',
'Intended Audience :: Developers',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Operating System :: POSIX :: Linux',
'Topic :: Software Development :: Libraries :: Python Modules'
],
author='jeff kit',
author_email='bbmyth@gmail.com',
maintainer='Harry Lee',
maintainer_email='tclh123@gmail.com',
url='https://github.com/tclh123/wechat',
keywords=['wechat', 'SDK'],
license="GPLv3",
packages=find_packages(exclude=['demo*', 'tests*']),
include_package_data=True,
zip_safe=False,
install_requires=['requests', 'cryptography'],
)
30 changes: 30 additions & 0 deletions tests/test_crypto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from __future__ import print_function

import os
import socket
import struct

from wechat.crypt import Prpcrypt


key = os.urandom(32)
text = sReplyMsg = b'hello'
appid = m_sCorpid = b'10001'

pc = Prpcrypt(key)

text = pc.get_random_str() + struct.pack("I", socket.htonl(len(text))) + text + appid
print(text)
content = text[16:]
print(content)
xml_len = socket.ntohl(struct.unpack("I", content[:4])[0])
print(xml_len)
xml_content = content[4:xml_len+4]
print(xml_content)
from_appid = content[xml_len+4:]
print(from_appid)

ret, encrypt = pc.encrypt(sReplyMsg, m_sCorpid)

ret, xml_content = pc.decrypt(encrypt, m_sCorpid)
print('decrypted:', xml_content)
118 changes: 59 additions & 59 deletions wechat/crypt.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
#encoding=utf-8
# encoding=utf-8

import os
import base64
import string
import random
# 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
reload(sys)
sys.setdefaultencoding('utf-8')

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import (
Cipher, algorithms, modes
)

WXBizMsgCrypt_OK = 0
WXBizMsgCrypt_ValidateSignature_Error = -40001
Expand All @@ -27,13 +30,6 @@
WXBizMsgCrypt_GenReturnXml_Error = -40011


"""
关于Crypto.Cipher模块,ImportError: No module named 'Crypto'解决方案
请到官方网站 https://www.dlitz.net/software/pycrypto/ 下载pycrypto。
下载后,按照README中的“Installation”小节的提示进行pycrypto安装。
"""


class FormatException(Exception):
pass

Expand Down Expand Up @@ -82,7 +78,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 All @@ -106,33 +102,33 @@ def generate(self, encrypt, signature, timestamp, nonce):
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 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):
Expand All @@ -141,8 +137,8 @@ class Prpcrypt(object):
def __init__(self, key):
#self.key = base64.b64decode(key+"=")
self.key = key
# 设置加解密模式为AES的CBC模式
self.mode = AES.MODE_CBC
# # 设置加解密模式为AES的CBC模式
# self.mode = AES.MODE_CBC

def encrypt(self, text, appid):
"""对明文进行加密
Expand All @@ -152,13 +148,15 @@ def encrypt(self, text, appid):
# 16位随机字符串添加到明文开头
text = self.get_random_str() + struct.pack(
"I", socket.htonl(len(text))) + text + appid
# 使用自定义的填充方式对明文进行补位填充
pkcs7 = PKCS7Encoder()
text = pkcs7.encode(text)
# 加密
cryptor = AES.new(self.key, self.mode, self.key[:16])
encryptor = Cipher(
algorithms.AES(self.key),
modes.CBC(self.key[:16]),
backend=default_backend()
).encryptor()
padder = padding.PKCS7(algorithms.AES.block_size).padder()
try:
ciphertext = cryptor.encrypt(text)
ciphertext = encryptor.update(padder.update(text) + padder.finalize()) + encryptor.finalize()
# 使用BASE64对加密后的字符串进行编码
return WXBizMsgCrypt_OK, base64.b64encode(ciphertext)
except Exception:
Expand All @@ -169,19 +167,20 @@ def decrypt(self, text, appid):
@param text: 密文
@return: 删除填充补位后的明文
"""
decryptor = Cipher(
algorithms.AES(self.key),
modes.CBC(self.key[:16]),
backend=default_backend()
).decryptor()
unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
try:
cryptor = AES.new(self.key, self.mode, self.key[:16])
# 使用BASE64对密文进行解码,然后AES-CBC解密
plain_text = cryptor.decrypt(base64.b64decode(text))
plain_text = unpadder.update(decryptor.update(base64.b64decode(text)) + decryptor.finalize()) + unpadder.finalize()
except Exception:
return WXBizMsgCrypt_DecryptAES_Error, None
try:
pad = ord(plain_text[-1])
# 去掉补位字符串
#pkcs7 = PKCS7Encoder()
#plain_text = pkcs7.encode(plain_text)
# 去除16位随机字符串
content = plain_text[16:-pad]
content = plain_text[16:]
xml_len = socket.ntohl(struct.unpack("I", content[:4])[0])
xml_content = content[4:xml_len+4]
from_appid = content[xml_len+4:]
Expand All @@ -195,9 +194,10 @@ def get_random_str(self):
""" 随机生成16位字符串
@return: 16位字符串
"""
rule = string.letters + string.digits
str = random.sample(rule, 16)
return "".join(str)
# rule = string.ascii_letters + string.digits
# s = random.sample(rule, 16)
# return "".join(s)
return os.urandom(16)


class WXBizMsgCrypt(object):
Expand Down
10 changes: 3 additions & 7 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 Down Expand Up @@ -60,7 +60,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 All @@ -79,11 +79,7 @@ def format_list(data):


def simplify_send_parmas(params):
keys = params.keys()
for key in keys:
if not params[key]:
del params[key]
return params
return {k: v for k, v in params.items() if v}


class WxApi(WxBaseApi):
Expand Down