Skip to content

Commit 69b618f

Browse files
authored
Merge pull request #15 from akreisman-epam/fix-content-type-with-charset-header-check
Fix response content type header check when content type header contains charset substring
2 parents 745831f + b5b5dbc commit 69b618f

4 files changed

Lines changed: 188 additions & 3 deletions

File tree

CHANGELOG.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
Changelog
22
=========
33

4+
1.2.1 (2019-01-17)
5+
------------------
6+
7+
- FIX: Resolved issue with restricted "Accept" & "Content-Type" headers to support only "application/json" or "application/jose+json"
8+
49
1.2.0 (2018-12-20)
510
------------------
611

712
- Restricted “Accept” & “Content-Type” headers to support only “application/json” or “application/jose+json”
813
- Related resources “relatedResources” in error representation is added
9-
- Added Authentication token endpoint
14+
- Added Authentication token endpoint
1015

1116
1.1.4 (2018-12-04)
1217
------------------

hyperwallet/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
__email__ = 'devsupport@hyperwallet.com'
77
__copyright__ = 'Copyright (c) 2018 Hyperwallet'
88
__license__ = 'MIT'
9-
__version__ = '1.2.0'
9+
__version__ = '1.2.1'
1010
__url__ = 'https://github.com/hyperwallet/python-sdk'
1111
__download_url__ = 'https://pypi.python.org/pypi/hyperwallet-sdk'
1212
__description__ = 'A Python wrapper around the Hyperwallet API'

hyperwallet/tests/test_client.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import mock
44
import json
55
import unittest
6+
import os.path
67

78
from hyperwallet.utils import ApiClient
89
from hyperwallet.config import SERVER
910
from hyperwallet.exceptions import HyperwalletAPIException
11+
from hyperwallet.utils.encryption import Encryption
1012

1113

1214
class ApiClientTest(unittest.TestCase):
@@ -19,6 +21,17 @@ def setUp(self):
1921
SERVER
2022
)
2123

24+
localDir = os.path.abspath(os.path.dirname(__file__))
25+
clientPath = os.path.join(localDir, 'resources', 'private-jwkset1')
26+
hyperwalletPath = os.path.join(localDir, 'resources', 'public-jwkset1')
27+
28+
self.clientWithEncryption = ApiClient(
29+
'test-user',
30+
'test-pass',
31+
SERVER,
32+
{'clientPrivateKeySetLocation': clientPath, 'hyperwalletKeySetLocation': hyperwalletPath}
33+
)
34+
2235
def test_failed_connection(self):
2336

2437
with self.assertRaises(HyperwalletAPIException) as exc:
@@ -120,6 +133,173 @@ def test_receive_valid_json_response(self, session_mock):
120133
json.loads(encoded)
121134
)
122135

136+
@mock.patch('requests.Session.request')
137+
def test_request_with_encryption_successful(self, session_mock):
138+
139+
data = {
140+
'key': 'value'
141+
}
142+
143+
localDir = os.path.abspath(os.path.dirname(__file__))
144+
clientPath = os.path.join(localDir, 'resources', 'private-jwkset1')
145+
hyperwalletPath = os.path.join(localDir, 'resources', 'public-jwkset1')
146+
encryption = Encryption(clientPath, hyperwalletPath)
147+
encryptedMessage = encryption.encrypt(json.dumps(data))
148+
149+
session_mock.return_value = mock.MagicMock(
150+
status_code=200,
151+
content=encryptedMessage,
152+
headers={
153+
"Content-Type": "application/jose+json"
154+
}
155+
)
156+
157+
encoded = json.dumps(data)
158+
if hasattr(encoded, 'decode'): # Python 2
159+
encoded = encoded.decode('utf-8')
160+
161+
self.assertEqual(
162+
self.clientWithEncryption._makeRequest(),
163+
json.loads(encoded)
164+
)
165+
166+
@mock.patch('requests.Session.request')
167+
def test_request_with_encryption_when_content_type_contains_charset(self, session_mock):
168+
169+
data = {
170+
'key': 'value'
171+
}
172+
173+
localDir = os.path.abspath(os.path.dirname(__file__))
174+
clientPath = os.path.join(localDir, 'resources', 'private-jwkset1')
175+
hyperwalletPath = os.path.join(localDir, 'resources', 'public-jwkset1')
176+
encryption = Encryption(clientPath, hyperwalletPath)
177+
encryptedMessage = encryption.encrypt(json.dumps(data))
178+
179+
session_mock.return_value = mock.MagicMock(
180+
status_code=200,
181+
content=encryptedMessage,
182+
headers={
183+
"Content-Type": "application/jose+json;charset=utf-8"
184+
}
185+
)
186+
187+
encoded = json.dumps(data)
188+
if hasattr(encoded, 'decode'): # Python 2
189+
encoded = encoded.decode('utf-8')
190+
191+
self.assertEqual(
192+
self.clientWithEncryption._makeRequest(),
193+
json.loads(encoded)
194+
)
195+
196+
@mock.patch('requests.Session.request')
197+
def test_request_with_encryption_when_content_type_contains_charset_ahead(self, session_mock):
198+
199+
data = {
200+
'key': 'value'
201+
}
202+
203+
localDir = os.path.abspath(os.path.dirname(__file__))
204+
clientPath = os.path.join(localDir, 'resources', 'private-jwkset1')
205+
hyperwalletPath = os.path.join(localDir, 'resources', 'public-jwkset1')
206+
encryption = Encryption(clientPath, hyperwalletPath)
207+
encryptedMessage = encryption.encrypt(json.dumps(data))
208+
209+
session_mock.return_value = mock.MagicMock(
210+
status_code=200,
211+
content=encryptedMessage,
212+
headers={
213+
"Content-Type": "charset=utf-8;application/jose+json"
214+
}
215+
)
216+
217+
encoded = json.dumps(data)
218+
if hasattr(encoded, 'decode'): # Python 2
219+
encoded = encoded.decode('utf-8')
220+
221+
self.assertEqual(
222+
self.clientWithEncryption._makeRequest(),
223+
json.loads(encoded)
224+
)
225+
226+
@mock.patch('requests.Session.request')
227+
def test_request_with_encryption_when_response_content_type_is_not_valid(self, session_mock):
228+
229+
data = {
230+
'key': 'value'
231+
}
232+
233+
localDir = os.path.abspath(os.path.dirname(__file__))
234+
clientPath = os.path.join(localDir, 'resources', 'private-jwkset1')
235+
hyperwalletPath = os.path.join(localDir, 'resources', 'public-jwkset1')
236+
encryption = Encryption(clientPath, hyperwalletPath)
237+
encryptedMessage = encryption.encrypt(json.dumps(data))
238+
239+
session_mock.return_value = mock.MagicMock(
240+
status_code=200,
241+
content=encryptedMessage,
242+
headers={
243+
"Content-Type": "wrongContentType"
244+
}
245+
)
246+
247+
with self.assertRaises(HyperwalletAPIException) as exc:
248+
self.clientWithEncryption._makeRequest()
249+
250+
self.assertEqual(
251+
exc.exception.message,
252+
'Invalid Content-Type specified in Response Header'
253+
)
254+
255+
@mock.patch('requests.Session.request')
256+
def test_receive_valid_json_response_when_content_type_contains_charset(self, session_mock):
257+
258+
data = {
259+
'key': 'value'
260+
}
261+
262+
session_mock.return_value = mock.MagicMock(
263+
status_code=200,
264+
content=json.dumps(data),
265+
headers={
266+
"Content-Type": "application/json;charset=utf-8"
267+
}
268+
)
269+
270+
encoded = json.dumps(data)
271+
if hasattr(encoded, 'decode'): # Python 2
272+
encoded = encoded.decode('utf-8')
273+
274+
self.assertEqual(
275+
self.client._makeRequest(),
276+
json.loads(encoded)
277+
)
278+
279+
@mock.patch('requests.Session.request')
280+
def test_receive_valid_json_response_when_content_type_starts_with_charset(self, session_mock):
281+
282+
data = {
283+
'key': 'value'
284+
}
285+
286+
session_mock.return_value = mock.MagicMock(
287+
status_code=200,
288+
content=json.dumps(data),
289+
headers={
290+
"Content-Type": "charset=utf-8;application/json"
291+
}
292+
)
293+
294+
encoded = json.dumps(data)
295+
if hasattr(encoded, 'decode'): # Python 2
296+
encoded = encoded.decode('utf-8')
297+
298+
self.assertEqual(
299+
self.client._makeRequest(),
300+
json.loads(encoded)
301+
)
302+
123303
@mock.patch('requests.Session.request')
124304
def test_receive_json_error_response_when_content_type_is_not_valid(self, session_mock):
125305

hyperwallet/utils/apiclient.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ def __checkResponseHeaderContentType(self, response):
204204
'''
205205

206206
contentType = response.headers['Content-Type']
207-
if (not self.encrypted and contentType != 'application/json') or (self.encrypted and contentType != 'application/jose+json'):
207+
if (not self.encrypted and 'application/json' not in contentType) or (self.encrypted and 'application/jose+json' not in contentType):
208208
raise HyperwalletAPIException('Invalid Content-Type specified in Response Header')
209209

210210
def __getRequestData(self, data):

0 commit comments

Comments
 (0)