diff --git a/HISTORY.md b/HISTORY.md index 1245e814..9263f6ed 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -6,19 +6,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [3.1.1](https://github.com/uploadcare/pyuploadcare/compare/v3.1.0...v3.1.1) - TBD +## [3.2.0](https://github.com/uploadcare/pyuploadcare/compare/v3.1.0...v3.2.0) - TBD + ### Changed - freeze `httpx` dependency for py37+ (`=0.23.0`) to prevent breaking changes in processing files opened in text mode +### Fixed + + - Akamai signed URL generation + ## [3.1.0](https://github.com/uploadcare/pyuploadcare/compare/v3.0.1...v3.1.0) - 2022-10-24 ### Changed - Bumped `httpx` dependency for py37+ - Add `follow_redirects` argument for Client request method - - Using `allow_redirects` argument is allowed, but will cause a deprecating warning + - Using `allow_redirects` argument is allowed, but will cause a deprecating warning - Bumped `black` dependency ## [3.0.1](https://github.com/uploadcare/pyuploadcare/compare/v3.0.0...v3.0.1) - 2022-10-06 @@ -275,12 +280,12 @@ UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 ... - Widget was updated up to *0.8.1.2*. - It was invoking `File.store()`, `FileGroup.store()` methods on every model instance saving, e.g.: - + ``` python photo.title = 'new title' photo.save() ``` - + Now it happens while saving by form, namely by calling `your_model_form.is_valid()`. There is other thing that can trigger storing -- calling `photo.full_clean()` directly. diff --git a/pyproject.toml b/pyproject.toml index 6825488e..66d4e266 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pyuploadcare" -version = "3.1.1" +version = "3.2.0" description = "Python library for Uploadcare.com" authors = ["Uploadcare Inc "] readme = "README.md" diff --git a/pyuploadcare/__init__.py b/pyuploadcare/__init__.py index db309f27..c826dcca 100644 --- a/pyuploadcare/__init__.py +++ b/pyuploadcare/__init__.py @@ -1,5 +1,5 @@ # isort: skip_file -__version__ = "3.1.1" +__version__ = "3.2.0" from pyuploadcare.resources.file import File # noqa: F401 from pyuploadcare.resources.file_group import FileGroup # noqa: F401 diff --git a/pyuploadcare/secure_url.py b/pyuploadcare/secure_url.py index 2a84979d..035017f0 100644 --- a/pyuploadcare/secure_url.py +++ b/pyuploadcare/secure_url.py @@ -1,3 +1,4 @@ +import binascii import hashlib import hmac import time @@ -26,7 +27,7 @@ def __init__( cdn_url: str, secret_key: str, window: int = 300, - hash_algo=hashlib.sha1, + hash_algo=hashlib.sha256, ): self.secret_key = secret_key self.cdn_url = cdn_url @@ -87,7 +88,7 @@ def _build_signature(self, expire: int, acl: str) -> str: ] signature = hmac.new( - self.secret_key.encode(), + binascii.a2b_hex(self.secret_key.encode()), self.field_delimeter.join(hash_source).encode(), self.hash_algo, ).hexdigest() diff --git a/tests/functional/test_secure_url.py b/tests/functional/test_secure_url.py index 0cebf98c..3ff7bd46 100644 --- a/tests/functional/test_secure_url.py +++ b/tests/functional/test_secure_url.py @@ -4,9 +4,16 @@ from pyuploadcare.secure_url import AkamaiSecureUrlBuilder +known_secret = ( + "73636b61519adede42191efe1e73f02a67c7b692e3765f90c250c230be095211" +) + + @pytest.mark.freeze_time("2021-10-12") def test_generate_secure_url(): - secure_url_bulder = AkamaiSecureUrlBuilder("cdn.yourdomain.com", "secret") + secure_url_bulder = AkamaiSecureUrlBuilder( + "cdn.yourdomain.com", known_secret + ) secure_url = secure_url_bulder.build( "52da3bfc-7cd8-4861-8b05-126fef7a6994" ) @@ -14,13 +21,15 @@ def test_generate_secure_url(): "https://cdn.yourdomain.com/52da3bfc-7cd8-4861-8b05-126fef7a6994/?token=" "exp=1633997100~" "acl=/52da3bfc-7cd8-4861-8b05-126fef7a6994/~" - "hmac=a33cfc66c3e3592e712cdd1f82bd79d51df93b06" + "hmac=81852547d9dbd9eefd24bee2cada6eab02244b9013533bc8511511923098df72" ) @pytest.mark.freeze_time("2021-10-12") def test_generate_secure_url_with_transformation(): - secure_url_bulder = AkamaiSecureUrlBuilder("cdn.yourdomain.com", "secret") + secure_url_bulder = AkamaiSecureUrlBuilder( + "cdn.yourdomain.com", known_secret + ) secure_url = secure_url_bulder.build( "52da3bfc-7cd8-4861-8b05-126fef7a6994/-/resize/640x/other/transformations/" ) @@ -29,13 +38,15 @@ def test_generate_secure_url_with_transformation(): "-/resize/640x/other/transformations/?token=" "exp=1633997100~" "acl=/52da3bfc-7cd8-4861-8b05-126fef7a6994/-/resize/640x/other/transformations/~" - "hmac=24d11299339bdf9dcba26c7a5603c7ca63503fda" + "hmac=a3ae2b3e3adfcb5d41ca753598e19d17264ac87d2b0b828ccdac5136e63f2f1a" ) @pytest.mark.freeze_time("2021-10-12") def test_client_generate_secure_url(): - secure_url_bulder = AkamaiSecureUrlBuilder("cdn.yourdomain.com", "secret") + secure_url_bulder = AkamaiSecureUrlBuilder( + "cdn.yourdomain.com", known_secret + ) uploadcare = Uploadcare( public_key="public", @@ -49,5 +60,5 @@ def test_client_generate_secure_url(): "https://cdn.yourdomain.com/52da3bfc-7cd8-4861-8b05-126fef7a6994/?token=" "exp=1633997100~" "acl=/52da3bfc-7cd8-4861-8b05-126fef7a6994/~" - "hmac=a33cfc66c3e3592e712cdd1f82bd79d51df93b06" + "hmac=81852547d9dbd9eefd24bee2cada6eab02244b9013533bc8511511923098df72" )