Use platform independant hashing for transformations.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
Roberto Rosario
2018-08-22 22:35:01 -04:00
parent 34b3cc3286
commit 103ded5145
4 changed files with 54 additions and 43 deletions

View File

@@ -91,6 +91,7 @@
DOCUMENTS_RECENT_COUNT has been renamed to
DOCUMENTS_RECENT_ACCESS_COUNT. New setting
DOCUMENTS_RECENT_ADDED_COUNT added.
- Use platform independant hashing for transformations.
3.0.3 (2018-08-17)
==================

View File

@@ -2,3 +2,14 @@ from __future__ import unicode_literals
TEST_TRANSFORMATION_NAME = 'rotate'
TEST_TRANSFORMATION_ARGUMENT = 'degrees: 180'
TEST_TRANSFORMATION_COMBINED_CACHE_HASH = '384bf78014d2aed7255d9e548a0694c70af0b22545653214bcceb1ac6286b5f7'
TEST_TRANSFORMATION_RESIZE_CACHE_HASH = '4aa319f5a6950985a19380a1f279a66769d04138bd1583844270fe8c269260fc'
TEST_TRANSFORMATION_RESIZE_CACHE_HASH_2 = 'cc8d220d40e810b995181c0c69b44b7a61c3bb039c0be96a5465fcaf698ca99a'
TEST_TRANSFORMATION_RESIZE_HEIGHT = 528
TEST_TRANSFORMATION_RESIZE_HEIGHT_2 = 529
TEST_TRANSFORMATION_RESIZE_WIDTH = 123
TEST_TRANSFORMATION_RESIZE_WIDTH_2 = 124
TEST_TRANSFORMATION_ROTATE_CACHE_HASH = 'df6a5854fccdd3a56145fcd7f7bf52bdf95fe940d6611d435e80dfcaca3b61ac'
TEST_TRANSFORMATION_ROTATE_DEGRESS = 34
TEST_TRANSFORMATION_ZOOM_CACHE_HASH = 'ac7a864de6a95889d5892301e142f8cdc5808f55010c0b820ed056902fc25a73'
TEST_TRANSFORMATION_ZOOM_PERCENT = 49

View File

@@ -10,17 +10,19 @@ from ..transformations import (
TransformationRotate, TransformationZoom
)
TRANSFORMATION_RESIZE_WIDTH = 123
TRANSFORMATION_RESIZE_HEIGHT = 528
TRANSFORMATION_RESIZE_CACHE_HASH = '348d60cb7c028c95'
TRANSFORMATION_RESIZE_WIDTH_2 = 124
TRANSFORMATION_RESIZE_HEIGHT_2 = 529
TRANSFORMATION_RESIZE_CACHE_HASH_2 = '348d78cb5709c1bf'
TRANSFORMATION_ROTATE_DEGRESS = 34
TRANSFORMATION_ROTATE_CACHE_HASH = '45148f480ad5f8bd'
TRANSFORMATION_COMBINED_CACHE_HASH = '1267dbe78a1759da'
TRANSFORMATION_ZOOM_PERCENT = 49
TRANSFORMATION_ZOOM_CACHE_HASH = '1b333603674469e0'
from .literals import (
TEST_TRANSFORMATION_COMBINED_CACHE_HASH,
TEST_TRANSFORMATION_RESIZE_CACHE_HASH,
TEST_TRANSFORMATION_RESIZE_CACHE_HASH_2,
TEST_TRANSFORMATION_RESIZE_HEIGHT,
TEST_TRANSFORMATION_RESIZE_HEIGHT_2,
TEST_TRANSFORMATION_RESIZE_WIDTH,
TEST_TRANSFORMATION_RESIZE_WIDTH_2,
TEST_TRANSFORMATION_ROTATE_CACHE_HASH,
TEST_TRANSFORMATION_ROTATE_DEGRESS,
TEST_TRANSFORMATION_ZOOM_CACHE_HASH,
TEST_TRANSFORMATION_ZOOM_PERCENT,
)
class TransformationBaseTestCase(TestCase):
@@ -45,64 +47,65 @@ class TransformationBaseTestCase(TestCase):
def test_resize_cache_hashing(self):
# Test if the hash is being generated correctly
transformation = TransformationResize(
width=TRANSFORMATION_RESIZE_WIDTH,
height=TRANSFORMATION_RESIZE_HEIGHT
width=TEST_TRANSFORMATION_RESIZE_WIDTH,
height=TEST_TRANSFORMATION_RESIZE_HEIGHT
)
self.assertEqual(
transformation.cache_hash(), TRANSFORMATION_RESIZE_CACHE_HASH
transformation.cache_hash(), TEST_TRANSFORMATION_RESIZE_CACHE_HASH
)
# Test if the hash is being alternated correctly
transformation = TransformationResize(
width=TRANSFORMATION_RESIZE_WIDTH_2,
height=TRANSFORMATION_RESIZE_HEIGHT_2
width=TEST_TRANSFORMATION_RESIZE_WIDTH_2,
height=TEST_TRANSFORMATION_RESIZE_HEIGHT_2
)
self.assertEqual(
transformation.cache_hash(), TRANSFORMATION_RESIZE_CACHE_HASH_2
transformation.cache_hash(),
TEST_TRANSFORMATION_RESIZE_CACHE_HASH_2
)
def test_rotate_cache_hashing(self):
# Test if the hash is being generated correctly
transformation = TransformationRotate(
degrees=TRANSFORMATION_ROTATE_DEGRESS
degrees=TEST_TRANSFORMATION_ROTATE_DEGRESS
)
self.assertEqual(
transformation.cache_hash(), TRANSFORMATION_ROTATE_CACHE_HASH
transformation.cache_hash(), TEST_TRANSFORMATION_ROTATE_CACHE_HASH
)
def test_rotate_zoom_hashing(self):
# Test if the hash is being generated correctly
transformation = TransformationZoom(
percent=TRANSFORMATION_ZOOM_PERCENT
percent=TEST_TRANSFORMATION_ZOOM_PERCENT
)
self.assertEqual(
transformation.cache_hash(), TRANSFORMATION_ZOOM_CACHE_HASH
transformation.cache_hash(), TEST_TRANSFORMATION_ZOOM_CACHE_HASH
)
def test_cache_hash_combining(self):
# Test magic method and hash combining
transformation_resize = TransformationResize(
width=TRANSFORMATION_RESIZE_WIDTH,
height=TRANSFORMATION_RESIZE_HEIGHT
width=TEST_TRANSFORMATION_RESIZE_WIDTH,
height=TEST_TRANSFORMATION_RESIZE_HEIGHT
)
transformation_rotate = TransformationRotate(
degrees=TRANSFORMATION_ROTATE_DEGRESS
degrees=TEST_TRANSFORMATION_ROTATE_DEGRESS
)
transformation_zoom = TransformationZoom(
percent=TRANSFORMATION_ZOOM_PERCENT
percent=TEST_TRANSFORMATION_ZOOM_PERCENT
)
self.assertEqual(
BaseTransformation.combine(
(transformation_rotate, transformation_resize, transformation_zoom)
), TRANSFORMATION_COMBINED_CACHE_HASH
), TEST_TRANSFORMATION_COMBINED_CACHE_HASH
)

View File

@@ -1,11 +1,12 @@
from __future__ import unicode_literals
import hashlib
import logging
from PIL import Image, ImageColor, ImageFilter
from django.utils.six import text_type
from django.utils.translation import string_concat, ugettext_lazy as _
from django.utils.encoding import force_text
logger = logging.getLogger(__name__)
@@ -19,25 +20,17 @@ class BaseTransformation(object):
name = 'base_transformation'
_registry = {}
@staticmethod
def encode_hash(decoded_value):
return hex(abs(decoded_value))[2:]
@staticmethod
def decode_hash(encoded_value):
return int(encoded_value, 16)
@staticmethod
def combine(transformations):
result = None
for index, transformation in enumerate(transformations):
for transformation in transformations:
if not result:
result = hash((BaseTransformation.decode_hash(transformation.cache_hash()), index))
result = hashlib.sha256(transformation.cache_hash())
else:
result ^= hash((BaseTransformation.decode_hash(transformation.cache_hash()), index))
result.update(transformation.cache_hash())
return BaseTransformation.encode_hash(result)
return result.hexdigest()
@classmethod
def register(cls, transformation):
@@ -69,11 +62,14 @@ class BaseTransformation(object):
self.kwargs[argument_name] = kwargs.get(argument_name)
def cache_hash(self):
result = text_type.__hash__(self.name)
for index, (key, value) in enumerate(self.kwargs.items()):
result ^= hash((key, index)) ^ hash((value, index))
result = hashlib.sha256(self.name)
return BaseTransformation.encode_hash(result)
# Sort arguments for guaranteed repeatability
for key, value in sorted(self.kwargs.items()):
result.update(force_text(key))
result.update(force_text(value))
return result.hexdigest()
def execute_on(self, image):
self.image = image