Skip to content
This repository has been archived by the owner on Jul 13, 2023. It is now read-only.

Commit

Permalink
bug: Strip padding from key content
Browse files Browse the repository at this point in the history
The client will soon reject any key content that includes padding.
The server will need to watch and strip it. We should also return a
warning message, however the likelihood of that warning being noticed
is minimal.

Closes #451
  • Loading branch information
jrconlin committed Apr 28, 2016
1 parent 8b888ca commit ec48a6c
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 5 deletions.
21 changes: 17 additions & 4 deletions autopush/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,9 @@ class EndpointHandler(AutoendpointHandler):
"encryption-key", "content-type",
"authorization"]
cors_response_headers = ["location", "www-authenticate"]
# Remove trailing padding characters from complex header items like
# Crypto-Key and Encryption
strip_padding = re.compile('=+(?=[,;]|$)')

#############################################################
# Cyclone HTTP Methods
Expand All @@ -409,7 +412,6 @@ def put(self, api_ver="v0", token=None):
api_ver = api_ver or "v0"
self.start_time = time.time()
crypto_key_header = self.request.headers.get('crypto-key')

content_encoding = self.request.headers.get('content-encoding', "")
if content_encoding.lower() == 'aesgcm128' and crypto_key_header:
self.log.debug("Invalid crypto state; aesgcm128 + Crypto-Key",
Expand Down Expand Up @@ -518,21 +520,29 @@ def _uaid_lookup_results(self, result):

def _route_notification(self, version, result, data, ttl=None):
self.version = self._client_info['message_id'] = version
warning = ""
# Clean up the header values (remove padding)
for hdr in ['crypto-key', 'encryption']:
if self.strip_padding.search(self.request.headers.get(hdr, "")):
warning = ("Padded content detected. Please strip"
" base64 encoding padding.")
head = self.request.headers[hdr].replace('"', '')
self.request.headers[hdr] = self.strip_padding.sub("", head)
notification = Notification(version=version, data=data,
channel_id=self.chid,
headers=self.request.headers,
ttl=ttl)

d = Deferred()
d.addCallback(self.router.route_notification, result)
d.addCallback(self._router_completed, result)
d.addCallback(self._router_completed, result, warning)
d.addErrback(self._router_fail_err)
d.addErrback(self._response_err)

# Call the prepared router
d.callback(notification)

def _router_completed(self, response, uaid_data):
def _router_completed(self, response, uaid_data, warning=""):
"""Called after router has completed successfully"""
# TODO: Add some custom wake logic here

Expand All @@ -548,7 +558,8 @@ def _router_completed(self, response, uaid_data):
uaid_data)
response.router_data = None
d.addCallback(lambda x: self._router_completed(response,
uaid_data))
uaid_data,
warning))
return d
else:
if response.status_code == 200 or response.logged_status == 200:
Expand All @@ -558,6 +569,8 @@ def _router_completed(self, response, uaid_data):
**self._client_info)
time_diff = time.time() - self.start_time
self.metrics.timing("updates.handled", duration=time_diff)
response.response_body = (
response.response_body + " " + warning).strip()
self._router_response(response)


Expand Down
12 changes: 11 additions & 1 deletion autopush/tests/test_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,10 @@ def test_webpush_payload_encoding(self):
frouter = self.settings.routers["webpush"]
frouter.route_notification.return_value = RouterResponse()
self.endpoint.chid = dummy_chid
self.request_mock.headers["encryption"] = "stuff"
self.request_mock.headers["encryption"] = "keyid=p256;dh=stuff=="
self.request_mock.headers["crypto-key"] = (
"keyid=spad=;dh=AQ==,p256ecdsa=Ag=;foo=\"bar==\""
)
self.request_mock.headers["content-encoding"] = "aes128"
self.request_mock.body = b"\xc3\x28\xa0\xa1"
self.endpoint._uaid_lookup_results(fresult)
Expand All @@ -403,8 +406,15 @@ def handle_finish(value):
calls = frouter.route_notification.mock_calls
eq_(len(calls), 1)
(_, (notification, _), _) = calls[0]
eq_(notification.headers.get('encryption'),
'keyid=p256;dh=stuff')
eq_(notification.headers.get('crypto-key'),
'keyid=spad;dh=AQ,p256ecdsa=Ag;foo=bar')
eq_(notification.channel_id, dummy_chid)
eq_(notification.data, b"wyigoQ")
self.endpoint.set_status.assert_called_with(200)
ok_('Padded content detected' in
self.endpoint.write.call_args[0][0])

self.finish_deferred.addCallback(handle_finish)
return self.finish_deferred
Expand Down

0 comments on commit ec48a6c

Please sign in to comment.