Skip to content

Commit ed5c2f3

Browse files
committed
Check hyperwallet client response content type
1 parent 5901b48 commit ed5c2f3

3 files changed

Lines changed: 76 additions & 11 deletions

File tree

hyperwallet/tests/test_client.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ def test_receive_non_json_response(self, session_mock):
4545

4646
session_mock.return_value = mock.MagicMock(
4747
status_code=404,
48-
content=data
48+
content=data,
49+
headers={
50+
"Content-Type": "application/json"
51+
}
4952
)
5053

5154
with self.assertRaises(HyperwalletAPIException) as exc:
@@ -68,7 +71,10 @@ def test_receive_valid_json_error_response(self, session_mock):
6871

6972
session_mock.return_value = mock.MagicMock(
7073
status_code=400,
71-
content=json.dumps(data)
74+
content=json.dumps(data),
75+
headers={
76+
"Content-Type": "application/json"
77+
}
7278
)
7379

7480
with self.assertRaises(HyperwalletAPIException) as exc:
@@ -88,7 +94,10 @@ def test_receive_valid_json_response(self, session_mock):
8894

8995
session_mock.return_value = mock.MagicMock(
9096
status_code=200,
91-
content=json.dumps(data)
97+
content=json.dumps(data),
98+
headers={
99+
"Content-Type": "application/json"
100+
}
92101
)
93102

94103
encoded = json.dumps(data)
@@ -100,6 +109,29 @@ def test_receive_valid_json_response(self, session_mock):
100109
json.loads(encoded)
101110
)
102111

112+
@mock.patch('requests.Session.request')
113+
def test_receive_json_error_response_when_content_type_is_not_valid(self, session_mock):
114+
115+
data = {
116+
'key': 'value'
117+
}
118+
119+
session_mock.return_value = mock.MagicMock(
120+
status_code=200,
121+
content=json.dumps(data),
122+
headers={
123+
"Content-Type": "wrongContentType"
124+
}
125+
)
126+
127+
with self.assertRaises(HyperwalletAPIException) as exc:
128+
self.client._makeRequest()
129+
130+
self.assertEqual(
131+
exc.exception.message,
132+
'Invalid Content-Type specified in Response Header'
133+
)
134+
103135

104136
if __name__ == '__main__':
105137
unittest.main()

hyperwallet/tests/test_encryption.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
from jwcrypto.common import json_encode
1010
from hyperwallet.exceptions import HyperwalletException
1111
from hyperwallet.utils.encryption import Encryption
12-
from django.core.validators import URLValidator
13-
from django.core.exceptions import ValidationError
12+
from six.moves.urllib.parse import urlparse
1413

1514

1615
class EncryptionTest(unittest.TestCase):
@@ -158,19 +157,37 @@ def test_should_throw_exception_when_jws_signature_has_expired(self):
158157
self.assertEqual(exc.exception.message, 'JWS signature has expired, checked by [exp] JWS header')
159158

160159
def __getJwkKeySet(self, location):
161-
160+
'''
161+
Retrieves JWK key data from given location.
162+
163+
:param location:
164+
Location(can be a URL or path to file) of JWK key data. **REQUIRED**
165+
:returns:
166+
JWK key set found at given location.
167+
'''
162168
try:
163-
URLValidator()(location)
164-
except ValidationError:
169+
url = urlparse(location)
170+
if url.scheme and url.netloc and url.path:
171+
return requests.get(location).text
172+
raise HyperwalletException('Failed to parse url from string = ' + location)
173+
except Exception as e:
165174
if os.path.isfile(location):
166175
with open(location) as f:
167176
return f.read()
168177
else:
169178
raise HyperwalletException('Wrong JWK key set location path = ' + location)
170179

171-
return requests.get(location).text
172-
173180
def __findJwkKeyByAlgorithm(self, jwkKeySet, algorithm):
181+
'''
182+
Finds JWK key by given algorithm.
183+
184+
:param jwkKeySet:
185+
JSON representation of JWK key set. **REQUIRED**
186+
:param algorithm:
187+
Algorithm of the JWK key to be found in key set. **REQUIRED**
188+
:returns:
189+
JWK key with given algorithm.
190+
'''
174191

175192
try:
176193
keySet = json.loads(jwkKeySet)

hyperwallet/utils/apiclient.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def __init__(self, username, password, server, encryptionData=None):
4141
# Hyperwallet SDK.
4242
self.baseHeaders = {
4343
'User-Agent': 'Hyperwallet Python SDK v{}'.format(__version__),
44-
'Accept': 'application/json',
44+
'Accept': 'application/jose+json' if self.encrypted else 'application/json',
4545
'Content-Type': 'application/jose+json' if self.encrypted else 'application/json'
4646
}
4747

@@ -113,6 +113,8 @@ def _makeRequest(self,
113113
if response.status_code is 204:
114114
return {}
115115

116+
self.__checkResponseHeaderContentType(response)
117+
116118
content = response.content
117119
if hasattr(content, 'decode'): # Python 2
118120
content = content.decode('utf-8')
@@ -193,6 +195,20 @@ def doPut(self, partialUrl, data):
193195
data=json.dumps(data).encode('utf-8')
194196
)
195197

198+
def __checkResponseHeaderContentType(self, response):
199+
'''
200+
Check response header Content-Type.
201+
202+
:param response:
203+
Response to be checked. **REQUIRED**
204+
'''
205+
206+
if response is None:
207+
return
208+
contentType = response.headers['Content-Type']
209+
if (not self.encrypted and contentType != 'application/json') or (self.encrypted and contentType != 'application/jose+json'):
210+
raise HyperwalletAPIException('Invalid Content-Type specified in Response Header')
211+
196212
def __getRequestData(self, data):
197213
'''
198214
If encryption is enabled try to encrypt request data, otherwise no action required.

0 commit comments

Comments
 (0)