Skip to content

Commit 1d218ce

Browse files
committed
feat: make python2/3 compatible
Closes #3
1 parent 4464fb9 commit 1d218ce

File tree

5 files changed

+35
-21
lines changed

5 files changed

+35
-21
lines changed

.coveragerc

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
[report]
22
omit = *noseplugin*
3+
show_missing = True

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 0.4.0 (2016-06-05)
2+
feat: make python 2.7 / 3.5 polyglot
3+
14
## 0.3.4 (2016-05-17)
25
bug: make header keys case insenstive
36

pywebpush/__init__.py

+20-11
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ def __init__(self, subscription_info):
8686
the client.
8787
8888
"""
89+
# Python 2 v. 3 hack
90+
try:
91+
self.basestr = basestring
92+
except NameError:
93+
self.basestr = str
8994
if 'endpoint' not in subscription_info:
9095
raise WebPushException("subscription_info missing endpoint URL")
9196
if 'keys' not in subscription_info:
@@ -95,22 +100,22 @@ def __init__(self, subscription_info):
95100
for k in ['p256dh', 'auth']:
96101
if keys.get(k) is None:
97102
raise WebPushException("Missing keys value: %s", k)
98-
receiver_raw = base64.urlsafe_b64decode(
99-
self._repad(keys['p256dh'].encode('utf8')))
103+
if isinstance(keys[k], self.basestr):
104+
keys[k] = bytes(keys[k].encode('utf8'))
105+
receiver_raw = base64.urlsafe_b64decode(self._repad(keys['p256dh']))
100106
if len(receiver_raw) != 65 and receiver_raw[0] != "\x04":
101107
raise WebPushException("Invalid p256dh key specified")
102108
self.receiver_key = receiver_raw
103-
self.auth_key = base64.urlsafe_b64decode(
104-
self._repad(keys['auth'].encode('utf8')))
109+
self.auth_key = base64.urlsafe_b64decode(self._repad(keys['auth']))
105110

106-
def _repad(self, str):
111+
def _repad(self, data):
107112
"""Add base64 padding to the end of a string, if required"""
108-
return str + "===="[:len(str) % 4]
113+
return data + b"===="[:len(data) % 4]
109114

110115
def encode(self, data):
111116
"""Encrypt the data.
112117
113-
:param data: A serialized block of data (String, JSON, bit array,
118+
:param data: A serialized block of byte data (String, JSON, bit array,
114119
etc.) Make sure that whatever you send, your client knows how
115120
to understand it.
116121
@@ -124,6 +129,9 @@ def encode(self, data):
124129
# ID tag.
125130
server_key_id = base64.urlsafe_b64encode(server_key.get_pubkey()[1:])
126131

132+
if isinstance(data, self.basestr):
133+
data = bytes(data.encode('utf8'))
134+
127135
# http_ece requires that these both be set BEFORE encrypt or
128136
# decrypt is called if you specify the key as "dh".
129137
http_ece.keys[server_key_id] = server_key
@@ -138,8 +146,8 @@ def encode(self, data):
138146

139147
return CaseInsensitiveDict({
140148
'crypto_key': base64.urlsafe_b64encode(
141-
server_key.get_pubkey()).strip('='),
142-
'salt': base64.urlsafe_b64encode(salt).strip("="),
149+
server_key.get_pubkey()).strip(b'='),
150+
'salt': base64.urlsafe_b64encode(salt).strip(b'='),
143151
'body': encrypted,
144152
})
145153

@@ -160,11 +168,12 @@ def send(self, data, headers={}, ttl=0):
160168
crypto_key = headers.get("crypto-key", "")
161169
if crypto_key:
162170
crypto_key += ','
163-
crypto_key += "keyid=p256dh;dh=" + encoded["crypto_key"]
171+
crypto_key += "keyid=p256dh;dh=" + encoded["crypto_key"].decode('utf8')
164172
headers.update({
165173
'crypto-key': crypto_key,
166174
'content-encoding': 'aesgcm',
167-
'encryption': "keyid=p256dh;salt=" + encoded['salt'],
175+
'encryption': "keyid=p256dh;salt=" +
176+
encoded['salt'].decode('utf8'),
168177
})
169178
if 'ttl' not in headers or ttl:
170179
headers['ttl'] = ttl

pywebpush/tests/test_webpush.py

+10-9
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ def _gen_subscription_info(self, recv_key):
1515
return {
1616
"endpoint": "https://example.com/",
1717
"keys": {
18-
'auth': base64.urlsafe_b64encode(os.urandom(16)).strip('='),
18+
'auth': base64.urlsafe_b64encode(os.urandom(16)).strip(b'='),
1919
'p256dh': base64.urlsafe_b64encode(
20-
recv_key.get_pubkey()).strip('='),
20+
recv_key.get_pubkey()).strip(b'='),
2121
}
2222
}
2323

@@ -31,6 +31,11 @@ def test_init(self):
3131
u"auth": u"k8JV6sjdbhAi1n3_LDBLvA"
3232
}
3333
}
34+
rk_decode = (b'\x04\xea\xe7"\xc9W\xadJ0\xd9P3(%\x00\x13\x8b'
35+
b'\x08l\xad4u\xa1\x19\n\xcc\x0eq\xff&\xdd1'
36+
b'|W\xcd\x81\xf8\xeaN\x83\x92[\x99\x82\xe0\xe3'
37+
b'\x89\x11r\xf4\x02\xd4M\xa00\x9b!\xb1F\x00'
38+
b'\xfb\xfc\xcc=\x1f')
3439
self.assertRaises(
3540
WebPushException,
3641
WebPusher,
@@ -55,12 +60,8 @@ def test_init(self):
5560

5661
push = WebPusher(subscription_info)
5762
eq_(push.subscription_info, subscription_info)
58-
eq_(push.receiver_key, ('\x04\xea\xe7"\xc9W\xadJ0\xd9P3(%\x00\x13\x8b'
59-
'\x08l\xad4u\xa1\x19\n\xcc\x0eq\xff&\xdd1'
60-
'|W\xcd\x81\xf8\xeaN\x83\x92[\x99\x82\xe0\xe3'
61-
'\x89\x11r\xf4\x02\xd4M\xa00\x9b!\xb1F\x00'
62-
'\xfb\xfc\xcc=\x1f'))
63-
eq_(push.auth_key, '\x93\xc2U\xea\xc8\xddn\x10"\xd6}\xff,0K\xbc')
63+
eq_(push.receiver_key, rk_decode)
64+
eq_(push.auth_key, b'\x93\xc2U\xea\xc8\xddn\x10"\xd6}\xff,0K\xbc')
6465

6566
def test_encode(self):
6667
recv_key = pyelliptic.ECC(curve="prime256v1")
@@ -88,7 +89,7 @@ def test_encode(self):
8889
authSecret=raw_auth
8990
)
9091

91-
eq_(decoded, data)
92+
eq_(decoded.decode('utf8'), data)
9293

9394
@patch("requests.post")
9495
def test_send(self, mock_post):

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from setuptools import find_packages, setup
55

6-
__version__ = "0.3.4"
6+
__version__ = "0.4.0"
77

88

99
def read_from(file):

0 commit comments

Comments
 (0)