Skip to content

Commit 3ca8fab

Browse files
authored
Merge pull request #27 from transloadit/upgrade_to_sha384
2 parents 8fc9de9 + de85428 commit 3ca8fab

File tree

5 files changed

+90
-9
lines changed

5 files changed

+90
-9
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
### Unreleased
1+
### 0.2.2 / 2023-27-03 ###
2+
- Added `sha_384` as hash algorithm for the signature authentication.
23
- Drop Python 3.6 from CI. It has been unsupported since December 2021 and github actions runner don't support anymore (https://github.com/actions/setup-python/issues/544)
34

45
### 0.2.1/ 2022-29-08 ###

tests/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1+
import datetime
2+
3+
14
def request_body_matcher(pattern):
25
def _callback(request):
36
return pattern in request.text
47

58
return _callback
9+
10+
11+
def get_test_time():
12+
return datetime.datetime.fromisoformat("2024-04-04T04:44:44")
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import copy
2+
import json
3+
import unittest
4+
import requests_mock
5+
from datetime import timedelta
6+
from transloadit.client import Transloadit
7+
from transloadit.request import Request
8+
from . import get_test_time, request_body_matcher
9+
10+
11+
class TestSignatureAuthentication(unittest.TestCase):
12+
def setUp(self):
13+
self.mock_client = MockClient("TRANSLOADIT_KEY", "TRANSLOADIT_SECRET")
14+
self.json_response = (
15+
'{"ok": "ASSEMBLY_COMPLETED", "assembly_id": "abcdef45673"}'
16+
)
17+
18+
@requests_mock.Mocker()
19+
def test_fixed_signature(self, mock):
20+
# Test a request with a fixed timestamp in order to have reproducible results
21+
assembly = self.mock_client.new_assembly()
22+
assembly.add_step("import", "/http/import",
23+
options={"url": "https://demos.transloadit.com/inputs/chameleon.jpg"})
24+
assembly.add_step("resize", "/image/resize", {"use:": "import", "width": 70, "height": 70})
25+
26+
url = f"{self.mock_client.service}/assemblies"
27+
mock.post(
28+
url,
29+
text=self.json_response,
30+
additional_matcher=request_body_matcher(
31+
"signature=sha384"
32+
"%3A46943b5542af95679940d94507865b20b36cb1808a7a9dc64c6255f26d1e921bd6574443b80b0dcd595769268f74273c"),
33+
)
34+
35+
assembly.create(resumable=False)
36+
37+
38+
class MockClient(Transloadit):
39+
"""
40+
Mock Class of the Transloadit Clients, which loads the modified MockRequest Class
41+
instead of the Standard Request class.
42+
"""
43+
44+
def __init__(self,
45+
auth_key: str,
46+
auth_secret: str,
47+
service: str = "https://api2.transloadit.com",
48+
duration: int = 300):
49+
if not service.startswith(("http://", "https://")):
50+
service = "https://" + service
51+
52+
self.service = service
53+
self.auth_key = auth_key
54+
self.auth_secret = auth_secret
55+
self.duration = duration
56+
self.request = MockRequest(self)
57+
58+
59+
class MockRequest(Request):
60+
"""
61+
Mock Request Class, which uses a fixed datetime for generating the signature.
62+
This is for having a reproducible value to test against.
63+
"""
64+
def _to_payload(self, data):
65+
data = copy.deepcopy(data or {})
66+
expiry = timedelta(seconds=self.transloadit.duration) + get_test_time()
67+
data["auth"] = {
68+
"key": self.transloadit.auth_key,
69+
"expires": expiry.strftime("%Y/%m/%d %H:%M:%S+00:00"),
70+
}
71+
json_data = json.dumps(data)
72+
73+
return {"params": json, "signature": self._sign_data(json_data)}

transloadit/client.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
if typing.TYPE_CHECKING:
88
from requests import Response
99

10+
1011
class Transloadit:
1112
"""
1213
This class serves as a client interface to the Transloadit API.
@@ -30,11 +31,11 @@ class Transloadit:
3031
"""
3132

3233
def __init__(
33-
self,
34-
auth_key: str,
35-
auth_secret: str,
36-
service: str = "https://api2.transloadit.com",
37-
duration: int = 300,
34+
self,
35+
auth_key: str,
36+
auth_secret: str,
37+
service: str = "https://api2.transloadit.com",
38+
duration: int = 300,
3839
):
3940
if not service.startswith(("http://", "https://")):
4041
service = "https://" + service

transloadit/request.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,8 @@ def _to_payload(self, data):
123123
return {"params": json_data, "signature": self._sign_data(json_data)}
124124

125125
def _sign_data(self, message):
126-
return hmac.new(
127-
b(self.transloadit.auth_secret), message.encode("utf-8"), hashlib.sha1
128-
).hexdigest()
126+
hash_string = hmac.new(b(self.transloadit.auth_secret), message.encode("utf-8"), hashlib.sha384).hexdigest()
127+
return f"sha384:{hash_string}"
129128

130129
def _get_full_url(self, url):
131130
if url.startswith(("http://", "https://")):

0 commit comments

Comments
 (0)