pax_global_header00006660000000000000000000000064135666146010014522gustar00rootroot0000000000000052 comment=14d8027d3a716c10df354beafd8b688537582eb0 libthumbor-1.3.3/000077500000000000000000000000001356661460100136755ustar00rootroot00000000000000libthumbor-1.3.3/.coveragerc000066400000000000000000000004501356661460100160150ustar00rootroot00000000000000[run] omit = test_*.py branch = True source = libthumbor [report] exclude_lines = pragma: no cover def __repr__ raise NotImplementedError if __name__ == .__main__.: from urllib.parse import parse_qs except ImportError: from nose_focus import focus @focus libthumbor-1.3.3/.gitignore000066400000000000000000000000761356661460100156700ustar00rootroot00000000000000*.swp *.pyc .DS_Store dist libthumbor.egg-info *.db .coverage libthumbor-1.3.3/.travis.yml000066400000000000000000000003671356661460100160140ustar00rootroot00000000000000language: python python: - 2.7 - 3.5 - 3.6 - 3.7 - 3.8 - pypy cache: directories: - $HOME/.cache/pip matrix: fast_finish: true install: - make setup - pip install coveralls script: make ci_test after_success: coveralls libthumbor-1.3.3/CONTRIBUTING000066400000000000000000000023111356661460100155240ustar00rootroot00000000000000So you want to contribute with libthumbor? Welcome onboard! There are a few things you'll need in order to properly start hacking on it. First step is to fork it at http://help.github.com/fork-a-repo/ and create your own clone of libthumbor. ## Dependencies We seriously advise you to use virtualenv (http://pypi.python.org/pypi/virtualenv) since it will keep your environment clean of libthumbor's dependencies and you can choose when to "turn them on". You'll also need python >= 2.6 and < 3.0. After that, just issue a `make setup` command and you'll be ready to start hacking. ## Running the Tests Running the tests is as easy as: make test ## Pull Requests After hacking and testing your contribution, it is time to make a pull request. Make sure that your code is already integrated with the master branch of libthumbor before asking for a pull request. To add thumbor's remote as a valid remote for your repository: git remote add libthumbor git://github.com/thumbor/libthumbor.git To merge thumbor's master with your fork: git pull libthumbor master If there was anything to merge, just run your tests again. If they pass, send a pull request (http://help.github.com/send-pull-requests/). libthumbor-1.3.3/LICENSE000066400000000000000000000020641356661460100147040ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2014 Globo.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. libthumbor-1.3.3/MANIFEST.in000066400000000000000000000000311356661460100154250ustar00rootroot00000000000000prune dist prune build libthumbor-1.3.3/Makefile000066400000000000000000000005661356661460100153440ustar00rootroot00000000000000COVERAGE = $(or $(shell which coverage), $(shell which python-coverage), coverage) test ci_test: @$(COVERAGE) run --branch `which nosetests` -v --with-yanc -s tests/ @$(MAKE) coverage @$(MAKE) static coverage: @$(COVERAGE) report -m --fail-under=75 publish: python setup.py sdist upload setup: @pip install -U -e .\[tests\] static: @flake8 --config=./flake8 . libthumbor-1.3.3/README.mkd000066400000000000000000000017771356661460100153430ustar00rootroot00000000000000[![Build Status](https://secure.travis-ci.org/thumbor/libthumbor.png)](http://travis-ci.org/thumbor/libthumbor) [![Coverage Status](https://coveralls.io/repos/thumbor/libthumbor/badge.svg?branch=master&service=github)](https://coveralls.io/github/thumbor/libthumbor?branch=master) libthumbor allows easy usage of [thumbor](http://github.com/thumbor/thumbor) in Python. Check the docs for django integration. This version is compliant with the new URL generation schema (thumbor 3.0.0 and up). ### Warning 2.x version won't support old url's ## Using it from libthumbor import CryptoURL crypto = CryptoURL(key='my-security-key') encrypted_url = crypto.generate( width=300, height=200, smart=True, image_url='/path/to/my/image.jpg' ) ## Docs Check the wiki for more information on using libthumbor. ## Contributions ### Bernardo Heynemann * Generic URL encryption ### Rafael Caricio * Django Generic View and URL ### Fábio Costa * Django Generic View and URL libthumbor-1.3.3/flake8000066400000000000000000000001431356661460100147700ustar00rootroot00000000000000[flake8] exclude = ./.tox/*,./build/*,./tests/testproj/* max-line-length = 151 max-complexity = 22 libthumbor-1.3.3/libthumbor/000077500000000000000000000000001356661460100160445ustar00rootroot00000000000000libthumbor-1.3.3/libthumbor/__init__.py000066400000000000000000000014261356661460100201600ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # libthumbor - python extension to thumbor # http://github.com/heynemann/libthumbor # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license # Copyright (c) 2011 Bernardo Heynemann heynemann@gmail.com '''libthumbor is the library used to access thumbor's images in python''' from pkg_resources import get_distribution, DistributionNotFound __project__ = 'libthumbor' try: __version__ = get_distribution(__project__).version except DistributionNotFound: # Returns a local version. For tests. __version__ = '{}-local'.format(__project__) from libthumbor.crypto import CryptoURL # NOQA from libthumbor.url import Url # NOQA from libthumbor.url_signers.base64_hmac_sha1 import UrlSigner as Signer # NOQA libthumbor-1.3.3/libthumbor/crypto.py000066400000000000000000000034261356661460100177430ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # libthumbor - python extension to thumbor # http://github.com/heynemann/libthumbor # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license # Copyright (c) 2011 Bernardo Heynemann heynemann@gmail.com '''Encrypted URLs for thumbor encryption.''' from __future__ import absolute_import import base64 import hmac import hashlib from six import text_type, b, PY3 from libthumbor.url import unsafe_url, plain_image_url class CryptoURL(object): '''Class responsible for generating encrypted URLs for thumbor''' def __init__(self, key): ''' Initializes the encryptor with the proper key :param key: secret key to use for hashing. :param thread_safe: if True (default) CryptoURL will not reuse the hmac instance on every generate call, instead a copy of the hmac object will be created. Consider setting this parameter to False when only one thread has access to the CryptoURL object at a time. ''' if isinstance(key, text_type): key = str(key) self.key = key self.computed_key = (key * 16)[:16] self.hmac = hmac.new(b(key), digestmod=hashlib.sha1) def generate_new(self, options): url = plain_image_url(**options) _hmac = self.hmac.copy() _hmac.update(text_type(url).encode('utf-8')) signature = base64.urlsafe_b64encode(_hmac.digest()) if PY3: signature = signature.decode('ascii') return '/%s/%s' % (signature, url) def generate(self, **options): '''Generates an encrypted URL with the specified options''' if options.get('unsafe', False): return unsafe_url(**options) else: return self.generate_new(options) libthumbor-1.3.3/libthumbor/django/000077500000000000000000000000001356661460100173065ustar00rootroot00000000000000libthumbor-1.3.3/libthumbor/django/__init__.py000066400000000000000000000000001356661460100214050ustar00rootroot00000000000000libthumbor-1.3.3/libthumbor/django/urls.py000066400000000000000000000003661356661460100206520ustar00rootroot00000000000000try: from django.conf.urls.defaults import patterns, url except ImportError: from django.conf.urls import patterns, url urlpatterns = patterns( 'libthumbor.django.views', url("^$", 'generate_url', name="generate_thumbor_url"), ) libthumbor-1.3.3/libthumbor/django/views.py000066400000000000000000000046361356661460100210260ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # libthumbor - python extension to thumbor # http://github.com/heynemann/libthumbor # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license # Copyright (c) 2011 Bernardo Heynemann heynemann@gmail.com '''Generic view for create thumbor encrypted urls.''' import logging from django.http import HttpResponseBadRequest, HttpResponseNotAllowed, HttpResponse from django.conf import settings from libthumbor.crypto import CryptoURL THUMBOR_SECURITY_KEY = getattr( settings, 'THUMBOR_SECURITY_KEY', 'my-security-key' ) THUMBOR_SERVER = getattr(settings, 'THUMBOR_SERVER', 'http://localhost:8888/') def generate_url(request): if request.method != 'GET': return HttpResponseNotAllowed(['GET']) crypto = CryptoURL(THUMBOR_SECURITY_KEY) args = request.GET args = dict(zip(map(str, args.keys()), args.values())) error_message = None try: if 'width' in args: args['width'] = int(args['width']) except ValueError: error_message = "The width value '%s' is not an integer." % \ args['width'] try: if 'height' in args: args['height'] = int(args['height']) except ValueError: error_message = "The height value '%s' is not an integer." % \ args['height'] try: if 'crop_top' in args or 'crop_left' in args or 'crop_right' in args or 'crop_bottom' in args: args['crop'] = ( (int(args['crop_left']), int(args['crop_top'])), (int(args['crop_right']), int(args['crop_bottom'])) ) except KeyError: error_message = ''' Missing values for cropping. Expected all 'crop_left', 'crop_top', 'crop_right', 'crop_bottom' values. ''' except ValueError: error_message = ''' Invalid values for cropping. Expected all 'crop_left', 'crop_top', 'crop_right', 'crop_bottom' to be integers. ''' if error_message is not None: logging.warning(error_message) return HttpResponseBadRequest(error_message) try: return HttpResponse(THUMBOR_SERVER + crypto.generate(**args).strip("/"), content_type="text/plain") except (ValueError, KeyError) as e: error_message = str(e) logging.warning(error_message) return HttpResponseBadRequest(error_message) libthumbor-1.3.3/libthumbor/url.py000066400000000000000000000217441356661460100172300ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # libthumbor - python extension to thumbor # http://github.com/heynemann/libthumbor # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license # Copyright (c) 2011 Bernardo Heynemann heynemann@gmail.com '''URL composer to create options-based URLs for thumbor encryption.''' import hashlib import re from six import b AVAILABLE_HALIGN = ['left', 'center', 'right'] AVAILABLE_VALIGN = ['top', 'middle', 'bottom'] def calculate_width_and_height(url_parts, options): '''Appends width and height information to url''' width = options.get('width', 0) has_width = width height = options.get('height', 0) has_height = height flip = options.get('flip', False) flop = options.get('flop', False) if flip: width = width * -1 if flop: height = height * -1 if not has_width and not has_height: if flip: width = "-0" if flop: height = "-0" if width or height: url_parts.append('%sx%s' % (width, height)) def url_for(**options): '''Returns the url for the specified options''' url_parts = get_url_parts(**options) image_hash = hashlib.md5(b(options['image_url'])).hexdigest() url_parts.append(image_hash) return "/".join(url_parts) def unsafe_url(**options): '''Returns the unsafe url with the specified options''' return 'unsafe/%s' % plain_image_url(**options) def plain_image_url(**options): url_parts = get_url_parts(**options) url_parts.append(options['image_url']) return '/'.join(url_parts) def get_url_parts(**options): if 'image_url' not in options: raise ValueError('The image_url argument is mandatory.') url_parts = [] if options.get('meta', False): url_parts.append('meta') trim = options.get('trim', None) if trim: bits = ['trim'] if not isinstance(trim, bool): bits.append(trim[0] if trim[0] else '') if trim[1]: bits.append(str(trim[1])) url_parts.append(':'.join(bits)) crop = options.get('crop', None) if crop: crop_left = crop[0][0] crop_top = crop[0][1] crop_right = crop[1][0] crop_bottom = crop[1][1] if crop_left > 0 or crop_top > 0 or crop_bottom > 0 or crop_right > 0: url_parts.append("%sx%s:%sx%s" % ( crop_left, crop_top, crop_right, crop_bottom )) fit_in = False full_fit_in = False if options.get('fit_in', None): fit_in = True url_parts.append('fit-in') if options.get('full_fit_in', None): full_fit_in = True url_parts.append('full-fit-in') if options.get('adaptive_fit_in', None): fit_in = True url_parts.append('adaptive-fit-in') if options.get('adaptive_full_fit_in', None): full_fit_in = True url_parts.append('adaptive-full-fit-in') if (fit_in or full_fit_in) and not (options.get('width', None) or options.get('height', None)): raise ValueError('When using fit-in or full-fit-in, you must specify width and/or height.') calculate_width_and_height(url_parts, options) halign = options.get('halign', 'center') valign = options.get('valign', 'middle') if halign not in AVAILABLE_HALIGN: raise ValueError('Only "left", "center" and "right" are' + ' valid values for horizontal alignment.') if valign not in AVAILABLE_VALIGN: raise ValueError('Only "top", "middle" and "bottom" are' + ' valid values for vertical alignment.') if halign != 'center': url_parts.append(halign) if valign != 'middle': url_parts.append(valign) if options.get('smart', False): url_parts.append('smart') if options.get('filters', False): filters_string = ['filters'] for filter_value in options['filters']: filters_string.append(filter_value) url_parts.append(':'.join(filters_string)) return url_parts class Url(object): unsafe_or_hash = r'(?:(?:(?Punsafe)|(?P.+?))/)?' debug = r'(?:(?Pdebug)/)?' meta = r'(?:(?Pmeta)/)?' trim = r'(?:(?Ptrim(?::(?:top-left|bottom-right))?(?::\d+)?)/)?' crop = r'(?:(?P\d+)x(?P\d+):(?P\d+)x(?P\d+)/)?' fit_in = r'(?:(?Padaptive-)?(?Pfull-)?(?Pfit-in)/)?' dimensions = r'(?:(?P-)?(?P(?:\d+|orig))?x(?P-)?(?P(?:\d+|orig))?/)?' halign = r'(?:(?Pleft|right|center)/)?' valign = r'(?:(?Ptop|bottom|middle)/)?' smart = r'(?:(?Psmart)/)?' filters = r'(?:filters:(?P.+?\))/)?' image = r'(?P.+)' compiled_regex = None @classmethod def regex(cls, has_unsafe_or_hash=True): reg = ['/?'] if has_unsafe_or_hash: reg.append(cls.unsafe_or_hash) reg.append(cls.debug) reg.append(cls.meta) reg.append(cls.trim) reg.append(cls.crop) reg.append(cls.fit_in) reg.append(cls.dimensions) reg.append(cls.halign) reg.append(cls.valign) reg.append(cls.smart) reg.append(cls.filters) reg.append(cls.image) return ''.join(reg) @classmethod def parse_decrypted(cls, url): if cls.compiled_regex: reg = cls.compiled_regex else: reg = cls.compiled_regex = re.compile(cls.regex(has_unsafe_or_hash=False)) result = reg.match(url) if not result: return None result = result.groupdict() def int_or_0(value): return 0 if value is None else int(value) adaptive = (result.get('adaptive', '') or '').startswith('adaptive') full = (result.get('full', '') or '').startswith('full') values = { 'debug': result['debug'] == 'debug', 'meta': result['meta'] == 'meta', 'trim': result['trim'], 'crop': { 'left': int_or_0(result['crop_left']), 'top': int_or_0(result['crop_top']), 'right': int_or_0(result['crop_right']), 'bottom': int_or_0(result['crop_bottom']) }, 'adaptive': adaptive, 'full': full, 'fit_in': result['fit_in'] == 'fit-in', 'width': result['width'] == 'orig' and 'orig' or int_or_0(result['width']), 'height': result['height'] == 'orig' and 'orig' or int_or_0(result['height']), 'horizontal_flip': result['horizontal_flip'] == '-', 'vertical_flip': result['vertical_flip'] == '-', 'halign': result['halign'] or 'center', 'valign': result['valign'] or 'middle', 'smart': result['smart'] == 'smart', 'filters': result['filters'] or '', 'image': 'image' in result and result['image'] or None } return values @classmethod # NOQA def generate_options(cls, debug=False, width=0, height=0, smart=False, meta=False, trim=None, adaptive=False, full=False, fit_in=False, horizontal_flip=False, vertical_flip=False, halign='center', valign='middle', crop_left=None, crop_top=None, crop_right=None, crop_bottom=None, filters=None): url = [] if debug: url.append('debug') if meta: url.append('meta') if trim: if isinstance(trim, bool): url.append('trim') else: url.append('trim:%s' % trim) crop = crop_left or crop_top or crop_right or crop_bottom if crop: url.append('%sx%s:%sx%s' % ( crop_left, crop_top, crop_right, crop_bottom )) if fit_in: fit_ops = [] if adaptive: fit_ops.append('adaptive') if full: fit_ops.append('full') fit_ops.append('fit-in') url.append('-'.join(fit_ops)) if horizontal_flip: width = '-%s' % width if vertical_flip: height = '-%s' % height if width or height: url.append('%sx%s' % (width, height)) if halign != 'center': url.append(halign) if valign != 'middle': url.append(valign) if smart: url.append('smart') if filters: url.append('filters:%s' % filters) return '/'.join(url) libthumbor-1.3.3/libthumbor/url_signers/000077500000000000000000000000001356661460100204005ustar00rootroot00000000000000libthumbor-1.3.3/libthumbor/url_signers/__init__.py000066400000000000000000000012731356661460100225140ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # thumbor imaging service # https://github.com/thumbor/thumbor/wiki # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license # Copyright (c) 2011 globo.com timehome@corp.globo.com from six import text_type class BaseUrlSigner(object): def __init__(self, security_key): if isinstance(security_key, text_type): security_key = security_key.encode('utf-8') self.security_key = security_key def validate(self, actual_signature, url): url_signature = self.signature(url) return url_signature == actual_signature def signature(self, url): raise NotImplementedError() libthumbor-1.3.3/libthumbor/url_signers/base64_hmac_sha1.py000066400000000000000000000007021356661460100237410ustar00rootroot00000000000000# -*- coding: utf-8 -*- import base64 import hashlib import hmac from six import text_type from libthumbor.url_signers import BaseUrlSigner class UrlSigner(BaseUrlSigner): """Validate urls and sign them using base64 hmac-sha1 """ def signature(self, url): return base64.urlsafe_b64encode( hmac.new( self.security_key, text_type(url).encode('utf-8'), hashlib.sha1 ).digest() ) libthumbor-1.3.3/setup.py000066400000000000000000000032721356661460100154130ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # libthumbor - python extension to thumbor # http://github.com/heynemann/libthumbor # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license # Copyright (c) 2011 Bernardo Heynemann heynemann@gmail.com '''Module that configures setuptools to package libthumbor''' from setuptools import setup, find_packages tests_require = [ 'nose', 'coverage', 'yanc', 'preggy', 'flake8', ] setup( name='libthumbor', version="1.3.3", description="libthumbor is the python extension to thumbor", long_description=""" libthumbor is the python extension to thumbor. It allows users to generate safe urls easily. """, keywords='imaging face detection feature thumbor thumbnail' + ' imagemagick pil opencv', author='Bernardo Heynemann', author_email='heynemann@gmail.com', url='http://github.com/heynemann/libthumbor', license='MIT', classifiers=['Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Natural Language :: English', 'Operating System :: MacOS', 'Operating System :: POSIX :: Linux', 'Programming Language :: Python :: 2.6', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Multimedia :: Graphics :: Presentation' ], packages=find_packages(), package_dir={"libthumbor": "libthumbor"}, include_package_data=True, package_data={ }, extras_require={ 'tests': tests_require, }, install_requires=[ "six" ], ) libthumbor-1.3.3/test_requirements.txt000066400000000000000000000000051356661460100202130ustar00rootroot00000000000000nose libthumbor-1.3.3/tests/000077500000000000000000000000001356661460100150375ustar00rootroot00000000000000libthumbor-1.3.3/tests/test_cryptourl.py000066400000000000000000000055201356661460100205150ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # libthumbor - python extension to thumbor # http://github.com/heynemann/libthumbor # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license # Copyright (c) 2011 Bernardo Heynemann heynemann@gmail.com '''libthumbor cryptography tests''' from unittest import TestCase from six import text_type from libthumbor.crypto import CryptoURL IMAGE_URL = 'my.server.com/some/path/to/image.jpg' KEY = 'my-security-key' class NewFormatUrlTestsMixin: def test_generated_url_1(self): url = self.crypto.generate(image_url=IMAGE_URL, width=300, height=200) assert url == '/8ammJH8D-7tXy6kU3lTvoXlhu4o=/300x200/my.server.com/some/path/to/image.jpg' def test_generated_url_2(self): url = self.crypto.generate(image_url=IMAGE_URL, width=300, height=200, crop=((10, 10), (200, 200))) assert url == '/B35oBEIwztbc3jm7vsdqLez2C78=/10x10:200x200/300x200/my.server.com/some/path/to/image.jpg' def test_generated_url_3(self): url = self.crypto.generate(image_url=IMAGE_URL, width=300, height=200, crop=((10, 10), (200, 200)), filters=("brightness(20)", "contrast(10)")) assert url == '/as8U2DbUUtTMgvPF26LkjS3MocY=/10x10:200x200/300x200/filters:brightness(20):contrast(10)/my.server.com/some/path/to/image.jpg' def test_generated_url_4(self): url = self.crypto.generate(image_url=IMAGE_URL, width=300, height=200, crop=((10, 10), (200, 200)), filters=("brightness(20)", "contrast(10)")) assert url == '/as8U2DbUUtTMgvPF26LkjS3MocY=/10x10:200x200/300x200/filters:brightness(20):contrast(10)/my.server.com/some/path/to/image.jpg' # making sure no internal state affects subsequent calls. url = self.crypto.generate(image_url=IMAGE_URL, width=300, height=200, crop=((10, 10), (200, 200)), filters=("brightness(20)", "contrast(10)")) assert url == '/as8U2DbUUtTMgvPF26LkjS3MocY=/10x10:200x200/300x200/filters:brightness(20):contrast(10)/my.server.com/some/path/to/image.jpg' class NewFormatUrl(TestCase, NewFormatUrlTestsMixin): def setUp(self): self.crypto = CryptoURL(KEY) class NewFormatUrlWithUnicodeKey(TestCase, NewFormatUrlTestsMixin): def setUp(self): self.crypto = CryptoURL(text_type(KEY)) class GenerateWithUnsafeTestCase(TestCase): def setUp(self): self.crypto = CryptoURL(KEY) def test_should_pass_unsafe_to_generate_and_get_an_unsafe_url(self): url = self.crypto.generate(image_url=IMAGE_URL, crop=((10, 20), (30, 40)), unsafe=True) self.assertTrue(url.startswith('unsafe'), "url should starts with unsafe") def test_should_not_get_an_unsafe_url_when_unsafe_is_false(self): url = self.crypto.generate(image_url=IMAGE_URL, crop=((10, 20), (30, 40)), unsafe=False) self.assertFalse(url.startswith('unsafe'), "url should not starts with unsafe") libthumbor-1.3.3/tests/test_generic_views.py000066400000000000000000000131011356661460100212750ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # libthumbor - python extension to thumbor # http://github.com/heynemann/libthumbor # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license # Copyright (c) 2011 Bernardo Heynemann heynemann@gmail.com '''libthumbor generic views tests''' import os from libthumbor.crypto import CryptoURL from six import b os.environ["DJANGO_SETTINGS_MODULE"] = 'testproj.settings' try: from django.conf import settings from django.test import TestCase from django.http import QueryDict DJANGO_PRESENT = True except ImportError: DJANGO_PRESENT = False if DJANGO_PRESENT: HTTP_NOT_FOUND = 404 HTTP_METHOD_NOT_ALLOWED = 405 HTTP_OK = 200 HTTP_BAD_REQUEST = 400 class GenericViewsTestCase(TestCase): def setUp(self): self.url_query = QueryDict("", mutable=True) def test_without_url_param(self): response = self.client.get('/gen_url/') assert HTTP_BAD_REQUEST == response.status_code, "Got %d" % response.status_code def test_generate_url_with_params_via_post(self): image_args = {'image_url': 'globo.com/media/img/my_image.jpg'} response = self.client.post('/gen_url/', image_args) assert HTTP_METHOD_NOT_ALLOWED == response.status_code, "Got %d" % response.status_code def test_generate_url_with_params_via_get(self): crypto = CryptoURL(settings.THUMBOR_SECURITY_KEY) image_args = {'image_url': 'globo.com/media/img/my_image.jpg'} self.url_query.update(image_args) response = self.client.get('/gen_url/?' + self.url_query.urlencode()) assert HTTP_OK == response.status_code, "Got %d" % response.status_code assert response.content == b(settings.THUMBOR_SERVER + crypto.generate(**image_args).strip("/")) def test_passing_invalid_value_for_width(self): self.url_query.update({ 'image_url': 'globo.com/media/img/my_image.jpg', 'width': 1.2 }) response = self.client.get('/gen_url/?' + self.url_query.urlencode()) assert HTTP_BAD_REQUEST == response.status_code, "Got %d" % response.status_code assert b("The width value '1.2' is not an integer.") == response.content def test_passing_invalid_value_for_height(self): self.url_query.update({ 'image_url': 'globo.com/media/img/my_image.jpg', 'height': 's' }) response = self.client.get('/gen_url/?' + self.url_query.urlencode()) assert HTTP_BAD_REQUEST == response.status_code, "Got %d" % response.status_code assert b("The height value 's' is not an integer.") == response.content def test_passing_invalid_aligns(self): self.url_query.update({ 'image_url': 'globo.com/media/img/my_image.jpg', 'halign': 'sss' }) response = self.client.get('/gen_url/?' + self.url_query.urlencode()) assert HTTP_BAD_REQUEST == response.status_code, "Got %d" % response.status_code def test_passing_only_one_crop_value(self): self.url_query.update({ 'image_url': 'globo.com/media/img/my_image.jpg', 'crop_left': 100, }) response = self.client.get('/gen_url/?' + self.url_query.urlencode()) assert HTTP_BAD_REQUEST == response.status_code, "Got %d" % response.status_code assert "Missing values for cropping" in response.content def test_passing_only_one_crop_with_invalid_value(self): self.url_query.update({ 'image_url': 'globo.com/media/img/my_image.jpg', 'crop_top': 'bla', 'crop_left': 200, 'crop_right': '1', 'crop_bottom': 'blas' }) response = self.client.get('/gen_url/?' + self.url_query.urlencode()) assert HTTP_BAD_REQUEST == response.status_code, "Got %d" % response.status_code assert "Invalid values for cropping" in response.content def test_passing_various_erroneous_values(self): self.url_query.update({ 'image_url': 'globo.com/media/img/my_image.jpg', 'crop_left': 100, 'width': 'aaa', 'height': 123 }) response = self.client.get('/gen_url/?' + self.url_query.urlencode()) assert HTTP_BAD_REQUEST == response.status_code, "Got %d" % response.status_code def test_passing_all_params(self): image_args = { 'image_url': 'globo.com/media/img/my_image.jpg', 'halign': 'left', 'valign': 'middle', 'meta': True, 'smart': True, 'width': 400, 'height': 400, 'flip': True, 'flop': True } self.url_query.update(image_args) self.url_query.update({ 'crop_top': 100, 'crop_left': 100, 'crop_bottom': 200, 'crop_right': 200 }) image_args.update({'crop': ((100, 100), (200, 200))}) crypto = CryptoURL(settings.THUMBOR_SECURITY_KEY) response = self.client.get('/gen_url/?' + self.url_query.urlencode()) assert HTTP_OK == response.status_code, "Got %d" % response.status_code assert response.content == b(settings.THUMBOR_SERVER + crypto.generate(**image_args).strip("/")) libthumbor-1.3.3/tests/test_libthumbor.py000066400000000000000000000033721356661460100206240ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # libthumbor - python extension to thumbor # http://github.com/heynemann/libthumbor # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license # Copyright (c) 2011 Bernardo Heynemann heynemann@gmail.com import re from six import b, PY3 from libthumbor import CryptoURL, Url, Signer def test_usage_new_format(): key = "my-security-key" image = "s.glbimg.com/et/bb/f/original/2011/03/24/VN0JiwzmOw0b0lg.jpg" thumbor_signer = Signer(key) thumbor_url = Url.generate_options( width=300, height=200, smart=True, adaptive=False, fit_in=False, horizontal_flip=False, vertical_flip=False, halign='center', valign='middle', crop_left=0, crop_top=0, crop_right=0, crop_bottom=0, filters=[] ) thumbor_url = ('%s/%s' % (thumbor_url, image)).lstrip('/') signature = thumbor_signer.signature(thumbor_url) if PY3: signature = signature.decode('ascii') thumbor_url = '/%s/%s' % (signature, thumbor_url) crypto = CryptoURL(key=key) url = crypto.generate( width=300, height=200, smart=True, image_url=image ) assert url == thumbor_url def test_thumbor_can_decrypt_lib_thumbor_generated_url_new_format(): key = "my-security-key" image = "s.glbimg.com/et/bb/f/original/2011/03/24/VN0JiwzmOw0b0lg.jpg" thumbor_signer = Signer(key) crypto = CryptoURL(key=key) url = crypto.generate( width=300, height=200, smart=True, image_url=image ) reg = "/([^/]+)/(.+)" (signature, url) = re.match(reg, url).groups() assert thumbor_signer.validate(b(signature), url) libthumbor-1.3.3/tests/test_url.py000066400000000000000000000114261356661460100172560ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # thumbor imaging service # https://github.com/thumbor/thumbor/wiki # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license # Copyright (c) 2011 globo.com timehome@corp.globo.com from unittest import TestCase from preggy import expect from libthumbor.url import Url class UrlTestCase(TestCase): def setUp(self): Url.compiled_regex = None def test_can_get_regex(self): regex = Url.regex() expect(regex).to_equal( '/?(?:(?:(?Punsafe)|(?P.+?))/)?(?:(?Pdebug)/)?(?:(?Pmeta)/)?' '(?:(?Ptrim(?::(?:top-left|bottom-right))?(?::\\d+)?)/)?' '(?:(?P\\d+)x(?P\\d+):(?P\\d+)x(?P\\d+)/)?' '(?:(?Padaptive-)?(?Pfull-)?(?Pfit-in)/)?(?:(?P-)?' '(?P(?:\\d+|orig))?x(?P-)?(?P(?:\\d+|orig))?/)?' '(?:(?Pleft|right|center)/)?(?:(?Ptop|bottom|middle)/)?' '(?:(?Psmart)/)?(?:filters:(?P.+?\\))/)?(?P.+)' ) def test_can_get_regex_without_unsafe(self): regex = Url.regex(False) expect(regex).to_equal( '/?(?:(?Pdebug)/)?(?:(?Pmeta)/)?' '(?:(?Ptrim(?::(?:top-left|bottom-right))?(?::\\d+)?)/)?' '(?:(?P\\d+)x(?P\\d+):(?P\\d+)x(?P\\d+)/)?' '(?:(?Padaptive-)?(?Pfull-)?(?Pfit-in)/)?(?:(?P-)?' '(?P(?:\\d+|orig))?x(?P-)?(?P(?:\\d+|orig))?/)?' '(?:(?Pleft|right|center)/)?(?:(?Ptop|bottom|middle)/)?' '(?:(?Psmart)/)?(?:filters:(?P.+?\\))/)?(?P.+)' ) def test_parsing_invalid_url(self): expect(Url.compiled_regex).to_be_null() url = "" expect(Url.parse_decrypted(url)).to_be_null() def test_parsing_complete_url(self): url = '/debug/meta/trim/300x200:400x500/adaptive-full-fit-in/-300x-400/' \ 'left/top/smart/filters:brightness(100)/some/image.jpg' expected = { 'trim': 'trim', 'full': True, 'halign': 'left', 'fit_in': True, 'vertical_flip': True, 'image': 'some/image.jpg', 'crop': {'top': 200, 'right': 400, 'bottom': 500, 'left': 300}, 'height': 400, 'width': 300, 'meta': True, 'horizontal_flip': True, 'filters': 'brightness(100)', 'valign': 'top', 'debug': True, 'adaptive': True, 'smart': True, } result = Url.parse_decrypted(url) expect(result).not_to_be_null() expect(result).to_be_like(expected) # do it again to use compiled regex result = Url.parse_decrypted(url) expect(result).not_to_be_null() expect(result).to_be_like(expected) def test_can_generate_url(self): url = Url.generate_options( debug=True, width=300, height=200, smart=True, meta=True, trim=True, adaptive=True, full=True, fit_in=True, horizontal_flip=True, vertical_flip=True, halign='left', valign='top', crop_left=100, crop_top=100, crop_right=400, crop_bottom=400, filters='brightness(100)' ) expect(url).to_equal( 'debug/meta/trim/100x100:400x400/adaptive-full-fit-in/-300x-200/left/top/smart/filters:brightness(100)' ) def test_can_generate_url_with_defaults(self): url = Url.generate_options() expect(url).to_be_empty() def test_can_generate_url_with_fitin(self): url = Url.generate_options(fit_in=True, adaptive=False, full=False) expect(url).to_equal('fit-in') def test_can_generate_url_with_custom_trim(self): url = Url.generate_options( debug=True, width=300, height=200, smart=True, meta=True, trim='300x200', adaptive=True, full=True, fit_in=True, horizontal_flip=True, vertical_flip=True, halign='left', valign='top', crop_left=100, crop_top=100, crop_right=400, crop_bottom=400, filters='brightness(100)' ) expect(url).to_equal( 'debug/meta/trim:300x200/100x100:400x400/adaptive-full-fit-in/-300x-200/left/top/smart/filters:brightness(100)' ) libthumbor-1.3.3/tests/test_url_composer.py000066400000000000000000000427271356661460100211750ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # libthumbor - python extension to thumbor # http://github.com/heynemann/libthumbor # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license # Copyright (c) 2011 Bernardo Heynemann heynemann@gmail.com '''libthumbor URL composer tests''' import sys from unittest import TestCase from libthumbor.url import url_for from libthumbor.url import unsafe_url IMAGE_URL = 'my.server.com/some/path/to/image.jpg' IMAGE_MD5 = '84996242f65a4d864aceb125e1c4c5ba' # def decrypt_in_thumbor(key, encrypted): # '''Uses thumbor to decrypt libthumbor's encrypted URL''' # crypto = Cryptor(key) # return crypto.decrypt(encrypted) def test_no_options_specified(): '''test_no_options_specified Given An image URL of "my.server.com/some/path/to/image.jpg" When I ask my library for an URL Then I get "84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(image_url=IMAGE_URL) assert url == IMAGE_MD5, url def test_url_raises_if_no_url(): '''test_url_raises_if_no_url Given An image URL of "" or null When I ask my library for an URL Then I get an exception that says image URL is mandatory ''' try: url_for() except ValueError as err: assert str(err) == 'The image_url argument is mandatory.' return True assert False, 'Should not have gotten this far' def test_url_width_height_1(): '''test_url_width_height_1 Given An image URL of "my.server.com/some/path/to/image.jpg" And a width of 300 When I ask my library for an URL Then I get "300x0/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(width=300, image_url=IMAGE_URL) assert url == "300x0/84996242f65a4d864aceb125e1c4c5ba", url def test_url_width_height_2(): '''test_url_width_height_2 Given An image URL of "my.server.com/some/path/to/image.jpg" And a height of 300 When I ask my library for an URL Then I get "0x300/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(height=300, image_url=IMAGE_URL) assert url == "0x300/84996242f65a4d864aceb125e1c4c5ba", url def test_url_width_height_3(): '''test_url_width_height_3 Given An image URL of "my.server.com/some/path/to/image.jpg" And a width of 200 And a height of 300 When I ask my library for an URL Then I get "200x300/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(width=200, height=300, image_url=IMAGE_URL) assert url == "200x300/84996242f65a4d864aceb125e1c4c5ba", url def test_url_width_height_4(): '''test_url_width_height_4 Given An image URL of "my.server.com/some/path/to/image.jpg" And a width of orig When I ask my library for an URL Then I get "origx0/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(width="orig", image_url=IMAGE_URL) assert url == "origx0/84996242f65a4d864aceb125e1c4c5ba", url def test_url_width_height_5(): '''test_url_width_height_5 Given An image URL of "my.server.com/some/path/to/image.jpg" And a height of orig When I ask my library for an URL Then I get "0xorig/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(height="orig", image_url=IMAGE_URL) assert url == "0xorig/84996242f65a4d864aceb125e1c4c5ba", url def test_url_width_height_6(): '''test_url_width_height_6 Given An image URL of "my.server.com/some/path/to/image.jpg" And a width of 100 And a height of orig When I ask my library for an URL Then I get "100xorig/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(width=100, height="orig", image_url=IMAGE_URL) assert url == "100xorig/84996242f65a4d864aceb125e1c4c5ba", url def test_url_width_height_7(): '''test_url_width_height_7 Given An image URL of "my.server.com/some/path/to/image.jpg" And a height of 100 And a width of orig When I ask my library for an URL Then I get "origx100/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(width="orig", height=100, image_url=IMAGE_URL) assert url == "origx100/84996242f65a4d864aceb125e1c4c5ba", url def test_url_width_height_8(): '''test_url_width_height_8 Given An image URL of "my.server.com/some/path/to/image.jpg" And a height of orig And a width of orig When I ask my library for an URL Then I get "origxorig/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(width="orig", height="orig", image_url=IMAGE_URL) assert url == "origxorig/84996242f65a4d864aceb125e1c4c5ba", url def test_smart_url(): '''test_smart_url Given An image URL of "my.server.com/some/path/to/image.jpg" And a width of 200 And a height of 300 And the smart flag When I ask my library for an URL Then I get "200x300/smart/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(width=200, height=300, smart=True, image_url=IMAGE_URL) assert url == "200x300/smart/84996242f65a4d864aceb125e1c4c5ba", url def test_fit_in_url(): '''test_fit_in_url Given An image URL of "my.server.com/some/path/to/image.jpg" And a width of 200 And a height of 300 And the fit-in flag When I ask my library for an URL Then I get "fit-in/200x300/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(width=200, height=300, fit_in=True, image_url=IMAGE_URL) assert url == "fit-in/200x300/84996242f65a4d864aceb125e1c4c5ba", url def test_adaptive_fit_in_url(): '''test_adaptive_fit_in_url Given An image URL of "my.server.com/some/path/to/image.jpg" And a width of 200 And a height of 300 And the adaptive fit-in flag When I ask my library for an URL Then I get "adaptive-fit-in/200x300/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(width=200, height=300, adaptive_fit_in=True, image_url=IMAGE_URL) assert url == "adaptive-fit-in/200x300/84996242f65a4d864aceb125e1c4c5ba", url def test_fit_in_fails_if_no_width_supplied(): try: url_for(fit_in=True, image_url=IMAGE_URL) except ValueError: err = sys.exc_info()[1] assert err is not None else: assert False, "Should not have gotten this far" def test_full_fit_in_fails_if_no_width_supplied(): try: url_for(full_fit_in=True, image_url=IMAGE_URL) except ValueError: err = sys.exc_info()[1] assert err is not None else: assert False, "Should not have gotten this far" def test_adaptive_fit_in_fails_if_no_width_supplied(): try: url_for(adaptive_fit_in=True, image_url=IMAGE_URL) except ValueError: err = sys.exc_info()[1] assert err is not None else: assert False, "Should not have gotten this far" def test_adaptive_full_fit_in_fails_if_no_width_supplied(): try: url_for(adaptive_full_fit_in=True, image_url=IMAGE_URL) except ValueError: err = sys.exc_info()[1] assert err is not None else: assert False, "Should not have gotten this far" def test_full_fit_in_url(): '''test_full_fit_in_url Given An image URL of "my.server.com/some/path/to/image.jpg" And a width of 200 And a height of 300 And the full-fit-in flag When I ask my library for an URL Then I get "full-fit-in/200x300/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(width=200, height=300, full_fit_in=True, image_url=IMAGE_URL) assert url == "full-fit-in/200x300/84996242f65a4d864aceb125e1c4c5ba", url def test_adaptive_full_fit_in_url(): '''test_adaptive_full_fit_in_url Given An image URL of "my.server.com/some/path/to/image.jpg" And a width of 200 And a height of 300 And the adaptive full-fit-in flag When I ask my library for an URL Then I get "adaptive-full-fit-in/200x300/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(width=200, height=300, adaptive_full_fit_in=True, image_url=IMAGE_URL) assert url == "adaptive-full-fit-in/200x300/84996242f65a4d864aceb125e1c4c5ba", url def test_flip_1(): '''test_flip_1 Given An image URL of "my.server.com/some/path/to/image.jpg" And the flip flag When I ask my library for an URL Then I get "-0x0/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(flip=True, image_url=IMAGE_URL) assert url == "-0x0/84996242f65a4d864aceb125e1c4c5ba", url def test_flip_2(): '''test_flip_2 Given An image URL of "my.server.com/some/path/to/image.jpg" And a width of 200 And the flip flag When I ask my library for an URL Then I get "-200x0/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(flip=True, width=200, image_url=IMAGE_URL) assert url == "-200x0/84996242f65a4d864aceb125e1c4c5ba", url def test_flop_1(): '''test_flop_1 Given An image URL of "my.server.com/some/path/to/image.jpg" And the flop flag When I ask my library for an URL Then I get "0x-0/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(flop=True, image_url=IMAGE_URL) assert url == "0x-0/84996242f65a4d864aceb125e1c4c5ba", url def test_flop_2(): '''test_flop_2 Given An image URL of "my.server.com/some/path/to/image.jpg" And a height of 200 And the flop flag When I ask my library for an URL Then I get "0x-200/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(flop=True, height=200, image_url=IMAGE_URL) assert url == "0x-200/84996242f65a4d864aceb125e1c4c5ba", url def test_flip_flop(): '''test_flip_flop Given An image URL of "my.server.com/some/path/to/image.jpg" And the flip flag And the flop flag When I ask my library for an URL Then I get "-0x-0/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(flip=True, flop=True, image_url=IMAGE_URL) assert url == "-0x-0/84996242f65a4d864aceb125e1c4c5ba", url def test_flip_flop2(): '''test_flip_flop2 Given An image URL of "my.server.com/some/path/to/image.jpg" And a width of 200 And a height of 300 And the flip flag And the flop flag When I ask my library for an URL Then I get "-200x-300/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(flip=True, flop=True, width=200, height=300, image_url=IMAGE_URL) assert url == "-200x-300/84996242f65a4d864aceb125e1c4c5ba", url def test_horizontal_alignment(): '''test_horizontal_alignment Given An image URL of "my.server.com/some/path/to/image.jpg" And a 'left' horizontal alignment option When I ask my library for an URL Then I get "left/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(halign='left', image_url=IMAGE_URL) assert url == 'left/84996242f65a4d864aceb125e1c4c5ba', url def test_horizontal_alignment2(): '''test_horizontal_alignment2 Given An image URL of "my.server.com/some/path/to/image.jpg" And a 'center' horizontal alignment option When I ask my library for an URL Then I get "84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(halign='center', image_url=IMAGE_URL) assert url == '84996242f65a4d864aceb125e1c4c5ba', url def test_vertical_alignment(): '''test_vertical_alignment Given An image URL of "my.server.com/some/path/to/image.jpg" And a 'top' vertical alignment option When I ask my library for an URL Then I get "top/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(valign='top', image_url=IMAGE_URL) assert url == 'top/84996242f65a4d864aceb125e1c4c5ba', url def test_vertical_alignment2(): '''test_vertical_alignment2 Given An image URL of "my.server.com/some/path/to/image.jpg" And a 'middle' vertical alignment option When I ask my library for an URL Then I get "84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(valign='middle', image_url=IMAGE_URL) assert url == '84996242f65a4d864aceb125e1c4c5ba', url def test_both_alignments(): '''test_both_alignments Given An image URL of "my.server.com/some/path/to/image.jpg" And a 'left' horizontal alignment option And a 'top' vertical alignment option When I ask my library for an URL Then I get "left/top/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(halign='left', valign='top', image_url=IMAGE_URL) assert url == 'left/top/84996242f65a4d864aceb125e1c4c5ba', url def test_proper_haligns(): '''test_proper_haligns''' try: url_for(halign='wrong', image_url=IMAGE_URL) except ValueError as err: assert str(err) == 'Only "left", "center" and "right"' + \ ' are valid values for horizontal alignment.' return True assert False, "Should not have gotten this far." def test_proper_valigns(): '''test_proper_haligns''' try: url_for(valign='wrong', image_url=IMAGE_URL) except ValueError as err: assert str(err) == 'Only "top", "middle" and "bottom"' + \ ' are valid values for vertical alignment.' return True assert False, "Should not have gotten this far." def test_proper_meta(): '''test_proper_meta Given An image URL of "my.server.com/some/path/to/image.jpg" And a 'meta' flag When I ask my library for an URL Then I get "meta/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(meta=True, image_url=IMAGE_URL) assert url == 'meta/84996242f65a4d864aceb125e1c4c5ba', url def test_trim_standard(): url = url_for(trim=True, image_url=IMAGE_URL) assert url == 'trim/84996242f65a4d864aceb125e1c4c5ba', url def test_trim_pixel_and_tolerance(): url = url_for(trim=('bottom-right', 15), image_url=IMAGE_URL) assert url == 'trim:bottom-right:15/84996242f65a4d864aceb125e1c4c5ba', url def test_trim_pixel_only(): url = url_for(trim=('top-left', None), image_url=IMAGE_URL) assert url == 'trim:top-left/84996242f65a4d864aceb125e1c4c5ba', url def test_trim_tolerance_only(): url = url_for(trim=(None, 15), image_url=IMAGE_URL) assert url == 'trim::15/84996242f65a4d864aceb125e1c4c5ba', url def test_manual_crop_1(): '''test_manual_crop_1 Given An image URL of "my.server.com/some/path/to/image.jpg" And a manual crop left-top point of (10, 20) And a manual crop right-bottom point of (30, 40) When I ask my library for an URL Then I get "10x20:30x40/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(crop=((10, 20), (30, 40)), image_url=IMAGE_URL) assert url == '10x20:30x40/84996242f65a4d864aceb125e1c4c5ba', url def test_manual_crop_2(): '''test_manual_crop_2 Given An image URL of "my.server.com/some/path/to/image.jpg" And a manual crop left-top point of (0, 0) And a manual crop right-bottom point of (0, 0) When I ask my library for an URL Then I get "84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(crop=((0, 0), (0, 0)), image_url=IMAGE_URL) assert url == '84996242f65a4d864aceb125e1c4c5ba', url def test_smart_after_alignments(): '''test_smart_after_alignments Given An image URL of "my.server.com/some/path/to/image.jpg" And a 'smart' flag And a 'left' horizontal alignment option When I ask my library for an URL Then I get "left/smart/84996242f65a4d864aceb125e1c4c5ba" as URL ''' url = url_for(smart=True, halign='left', image_url=IMAGE_URL) assert url == 'left/smart/84996242f65a4d864aceb125e1c4c5ba', url class UnsafeUrlTestCase(TestCase): def test_should_return_a_valid_unsafe_url_with_no_params(self): self.assertEqual('unsafe/%s' % IMAGE_URL, unsafe_url(image_url=IMAGE_URL)) def test_should_return_an_unsafe_url_with_width_and_height(self): self.assertEqual('unsafe/100x140/%s' % IMAGE_URL, unsafe_url(image_url=IMAGE_URL, width=100, height=140)) def test_should_return_an_unsafe_url_with_crop_and_smart(self): self.assertEqual('unsafe/100x140/smart/%s' % IMAGE_URL, unsafe_url(image_url=IMAGE_URL, width=100, height=140, smart=True)) libthumbor-1.3.3/tests/testproj/000077500000000000000000000000001356661460100167115ustar00rootroot00000000000000libthumbor-1.3.3/tests/testproj/__init__.py000066400000000000000000000000001356661460100210100ustar00rootroot00000000000000libthumbor-1.3.3/tests/testproj/manage.py000066400000000000000000000010431356661460100205110ustar00rootroot00000000000000#!/usr/bin/env python from django.core.management import execute_manager try: import settings # Assumed to be in the same directory. except ImportError: import sys sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) sys.exit(1) if __name__ == "__main__": execute_manager(settings) libthumbor-1.3.3/tests/testproj/settings.py000066400000000000000000000060001356661460100211170ustar00rootroot00000000000000# Django settings for testproj project. import logging DEBUG = True TEMPLATE_DEBUG = DEBUG ADMINS = ( # ('Your Name', 'your_email@domain.com'), ) MANAGERS = ADMINS DATABASE_SUPPORTS_TRANSACTIONS = True DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. DATABASE_NAME = 'test.db' # Or path to database file if using sqlite3. DATABASE_USER = '' # Not used with sqlite3. DATABASE_PASSWORD = '' # Not used with sqlite3. DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. DATABASES = { 'default': { 'ENGINE': 'django.db.backends.{}'.format(DATABASE_ENGINE), 'NAME': DATABASE_NAME, 'USER': '', 'PASSWORD': '', 'HOST': '', 'PORT': '', } } # Local time zone for this installation. Choices can be found here: # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name # although not all choices may be available on all operating systems. # If running in a Windows environment this must be set to the same as your # system time zone. TIME_ZONE = 'America/Chicago' # Language code for this installation. All choices can be found here: # http://www.i18nguy.com/unicode/language-identifiers.html LANGUAGE_CODE = 'en-us' SITE_ID = 1 # If you set this to False, Django will make some optimizations so as not # to load the internationalization machinery. USE_I18N = True # Absolute path to the directory that holds media. # Example: "/home/media/media.lawrence.com/" MEDIA_ROOT = '' # URL that handles the media served from MEDIA_ROOT. Make sure to use a # trailing slash if there is a path component (optional in other cases). # Examples: "http://media.lawrence.com", "http://example.com/media/" MEDIA_URL = '' # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a # trailing slash. # Examples: "http://foo.com/media/", "/media/". ADMIN_MEDIA_PREFIX = '/media/' # Make this unique, and don't share it with anybody. SECRET_KEY = 'r2+#7pwvtvou#d_d6*ftt+pud^%s6vl-+2duag37x@xxy@$yu^' # List of callables that know how to import templates from various sources. TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.load_template_source', 'django.template.loaders.app_directories.load_template_source', # 'django.template.loaders.eggs.load_template_source', ) MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', ) ROOT_URLCONF = 'testproj.urls' TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. ) INSTALLED_APPS = ( ) logging.basicConfig(level=logging.DEBUG) THUMBOR_SECURITY_KEY = 'my-security-key' THUMBOR_SERVER = 'http://localhost:8888/' libthumbor-1.3.3/tests/testproj/urls.py000066400000000000000000000003151356661460100202470ustar00rootroot00000000000000try: from django.conf.urls.defaults import * except ImportError: from django.conf.urls import patterns, include urlpatterns = patterns('', (r"^gen_url/", include('libthumbor.django.urls')), ) libthumbor-1.3.3/tests/url_signers/000077500000000000000000000000001356661460100173735ustar00rootroot00000000000000libthumbor-1.3.3/tests/url_signers/__init__.py000066400000000000000000000000001356661460100214720ustar00rootroot00000000000000libthumbor-1.3.3/tests/url_signers/test_base64_hmac_sha1_signer.py000066400000000000000000000021421356661460100253420ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # thumbor imaging service # https://github.com/thumbor/thumbor/wiki # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license # Copyright (c) 2011 globo.com timehome@corp.globo.com import base64 import hmac import hashlib from unittest import TestCase from preggy import expect from six import text_type from libthumbor.url_signers.base64_hmac_sha1 import ( UrlSigner ) class Base64HmacSha1UrlSignerTestCase(TestCase): def test_can_create_signer(self): signer = UrlSigner(security_key="something") expect(signer).to_be_instance_of(UrlSigner) expect(signer.security_key).to_equal('something') def test_can_sign_url(self): signer = UrlSigner(security_key="something") url = '10x11:12x13/-300x-300/center/middle/smart/some/image.jpg' expected = base64.urlsafe_b64encode( hmac.new( 'something'.encode(), text_type(url).encode('utf-8'), hashlib.sha1 ).digest() ) actual = signer.signature(url) expect(actual).to_equal(expected) libthumbor-1.3.3/tests/url_signers/test_base_url_signer.py000066400000000000000000000025171356661460100241540ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # thumbor imaging service # https://github.com/thumbor/thumbor/wiki # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license # Copyright (c) 2011 globo.com timehome@corp.globo.com from __future__ import unicode_literals from unittest import TestCase from preggy import expect from libthumbor.url_signers import ( BaseUrlSigner ) class BaseSignerTestCase(TestCase): def test_can_create_signer(self): signer = BaseUrlSigner(security_key="something") expect(signer).to_be_instance_of(BaseUrlSigner) expect(signer.security_key).to_equal('something') def test_can_create_unicode_signer(self): signer = BaseUrlSigner(security_key="téste") expect(signer).to_be_instance_of(BaseUrlSigner) expect(signer.security_key).to_equal("téste") def test_can_validate_url(self): class TestSigner(BaseUrlSigner): def signature(self, url): return "%s+1" % url signer = TestSigner(security_key="téste") expect(signer.validate("http://www.test.com+1", "http://www.test.com")).to_be_true() def test_has_abstract_method(self): signer = BaseUrlSigner(security_key="téste") with expect.error_to_happen(NotImplementedError): signer.signature("test-url")