def thumb(self, image, **kwargs): url = image.url if not url: return None if settings.THUMBOR_BASE_URL: # If THUMBOR_BASE_URL is explicity set, use that base = settings.THUMBOR_BASE_URL else: # otherwise assume that thumbor is setup behind the same # CDN behind the `thumbor` namespace. scheme, netloc = urlparse.urlsplit(url)[:2] base = '{}://{}/thumbor'.format(scheme, netloc) crypto = CryptoURL(key=settings.THUMBOR_KEY) # just for code clarity thumbor_kwargs = kwargs if not 'fit_in' in thumbor_kwargs: thumbor_kwargs['fit_in'] = False thumbor_kwargs['image_url'] = url path = crypto.generate(**thumbor_kwargs) return u'{}{}'.format(base, path)
def test_image_already_generated_by_thumbor_2_times(self): with open( normalize_unicode_path(u'./tests/fixtures/images/alabama1_ap620é.jpg'), 'r' ) as f: self.context.modules.storage.put( quote("http://test.com/smart/alabama1_ap620é"), f.read() ) crypto = CryptoURL('ACME-SEC') image_url = self.get_url( crypto.generate( image_url=quote(self.get_url( crypto.generate( image_url=quote("http://test.com/smart/alabama1_ap620é") ) )) ) ) url = crypto.generate( image_url=quote(image_url) ) response = self.fetch(url) expect(response.code).to_equal(200)
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, crop_left=0, crop_top=0, crop_right=0, crop_bottom=0, filters=[], ) thumbor_url = (f"{thumbor_url}/{image}").lstrip("/") signature = thumbor_signer.signature(thumbor_url).decode("ascii") thumbor_url = f"/{signature}/{thumbor_url}" crypto = CryptoURL(key=key) url = crypto.generate(width=300, height=200, smart=True, image_url=image) assert url == thumbor_url
def main(arguments=None): '''Converts a given url with the specified arguments.''' parsed_options, arguments = get_options(arguments) image_url = arguments[0] image_url = quote(image_url) try: config = Config.load(None) except: config = None if not parsed_options.key and not config: sys.stdout.write( 'Error: The -k or --key argument is mandatory. For more information type thumbor-url -h\n' ) return security_key, thumbor_params = get_thumbor_params(image_url, parsed_options, config) crypto = CryptoURL(key=security_key) url = crypto.generate(**thumbor_params) sys.stdout.write('URL:\n') sys.stdout.write('%s\n' % url) return url
def test_usage(): key = "my-security-key" image = "s.glbimg.com/et/bb/f/original/2011/03/24/VN0JiwzmOw0b0lg.jpg" thumbor_crypto = Cryptor(key) thumbor_options = thumbor_crypto.encrypt(width=300, height=200, smart=True, adaptive=False, full=False, fit_in=False, flip_horizontal=False, flip_vertical=False, halign='center', valign='middle', trim=None, crop_left=0, crop_top=0, crop_right=0, crop_bottom=0, filters=[], image=image) thumbor_url = "/%s/%s" % (thumbor_options, image) crypto = CryptoURL(key=key) url = crypto.generate(width=300, height=200, smart=True, image_url=image, old=True) assert url == thumbor_url
def test_usage(): key = "my-security-key" image = "s.glbimg.com/et/bb/f/original/2011/03/24/VN0JiwzmOw0b0lg.jpg" thumbor_crypto = Crypto(salt=key) thumbor_options = thumbor_crypto.encrypt( 300, 200, True, False, False, 'center', 'middle', 0, 0, 0, 0, image=image ) thumbor_url = "/%s/%s" % (thumbor_options, image) crypto = CryptoURL(key=key) url = crypto.generate( width=300, height=200, smart=True, image_url=image ) assert url == thumbor_url
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('/') thumbor_url = '/%s/%s' % (thumbor_signer.signature(thumbor_url), thumbor_url) crypto = CryptoURL(key=key) url = crypto.generate(width=300, height=200, smart=True, image_url=image) assert url == thumbor_url
def generate_thumbnail_url(path: str, size: str = '0x0') -> str: if not (path.startswith('https://') or path.startswith('http://')): path = '/' + path if not is_thumbor_enabled(): if path.startswith('http://'): return get_camo_url(path) return path if not user_uploads_or_external(path): return path source_type = get_source_type(path) safe_url = base64.urlsafe_b64encode(path.encode()).decode('utf-8') image_url = '%s/source_type/%s' % (safe_url, source_type) width, height = map(int, size.split('x')) crypto = CryptoURL(key=settings.THUMBOR_KEY) encrypted_url = crypto.generate( width=width, height=height, smart=True, filters=['no_upscale()', 'sharpen(0.5,0.2,true)'], image_url=image_url) if settings.THUMBOR_URL == 'http://127.0.0.1:9995': # If THUMBOR_URL is the default then thumbor is hosted on same machine # as the Zulip server and we should serve a relative URL. # We add a /thumbor in front of the relative url because we make # use of a proxy pass to redirect request internally in Nginx to 9995 # port where thumbor is running. thumbnail_url = '/thumbor' + encrypted_url else: thumbnail_url = urllib.parse.urljoin(settings.THUMBOR_URL, encrypted_url) return thumbnail_url
def main(arguments=None): """Converts a given url with the specified arguments.""" parsed_options, arguments = get_options(arguments) if not arguments: sys.stdout.write( "Error: The image argument is mandatory. For more information type thumbor-url -h\n" ) sys.exit(1) image_url = arguments[0] image_url = quote(image_url) try: config = Config.load(None) except Exception: # pylint: disable=broad-except config = None if not parsed_options.key and not config: sys.stdout.write("Error: The -k or --key argument is mandatory." " For more information type thumbor-url -h\n") sys.exit(1) security_key, thumbor_params = get_thumbor_params(image_url, parsed_options, config) crypto = CryptoURL(key=security_key) url = crypto.generate(**thumbor_params) sys.stdout.write("URL:\n") sys.stdout.write(f"{url}\n")
def thumb(img, **kwargs): ''' returns a thumbor url for 'img' with **kwargs as thumbor options. Positional arguments: img -- can be a string representing the image path or any object with a url property. Keyword arguments: For the complete list of thumbor options https://github.com/globocom/thumbor/wiki/Usage and the actual implementation for the url generation https://github.com/heynemann/libthumbor/blob/master/libthumbor/url.py ''' # url is DNS sharded url try: url = img.url except ValueError: # When trying to access the url of an image object when # the image does not exist, a ValueError is raised logger.exception("No file for object (%s) in thumbor", img.instance) return '' except AttributeError: # If it's an attribute error, assume it's a string already url = img if settings.THUMBOR_BASE_URL: # If THUMBOR_BASE_URL is explicity set, use that base = settings.THUMBOR_BASE_URL else: # otherwise assume that thumbor is setup behind the same # CDN behind the `thumbor` namespace. scheme, netloc = urlparse.urlsplit(url)[:2] base = '{}://{}/thumbor'.format(scheme, netloc) url = remove_url_scheme(url) # just for code clarity thumbor_kwargs = kwargs if 'fit_in' not in thumbor_kwargs: thumbor_kwargs['fit_in'] = True # normalizes url to make it work localy if settings.LOCAL: thumbor_kwargs['unsafe'] = True # strips 'media/' from the start of the url if url.startswith('media/'): url = url[len('media/'):] url = '{}/{}'.format(settings.AWS_S3_CUSTOM_DOMAIN, url) thumbor_kwargs['image_url'] = url crypto = CryptoURL(key=settings.THUMBOR_KEY) path = crypto.generate(**thumbor_kwargs).lstrip('/') return '{}/{}'.format(base, path)
def own_thumbnail(m, s): global thumbor proto = 'http%s' % s thumbor_base = config.thumbor % {'proto': proto} if thumbor is None: thumbor = CryptoURL(key=config.thumbor_key) return thumbor_base + thumbor.generate(image_url=m(0), **config.thumbor_pars)
def test_image_with_utf8_url(self): with open('./tests/fixtures/images/maracujá.jpg', 'r') as f: self.context.modules.storage.put( quote(u"http://test.com/maracujá.jpg".encode('utf-8')), f.read()) crypto = CryptoURL('ACME-SEC') image_url = self.get_url( quote(u"/unsafe/http://test.com/maracujá.jpg".encode('utf-8'))) url = crypto.generate(image_url=quote(image_url)) response = self.fetch(url) expect(response.code).to_equal(200)
async def test_image_with_utf8_url(self): with open("./tests/fixtures/images/maracujá.jpg", "rb") as fixture: await self.context.modules.storage.put( quote("http://test.com/maracujá.jpg".encode("utf-8")), fixture.read(), ) crypto = CryptoURL("ACME-SEC") image_url = self.get_url( quote("/unsafe/http://test.com/maracujá.jpg".encode("utf-8"))) url = crypto.generate(image_url=quote(image_url)) response = await self.async_fetch(url) expect(response.code).to_equal(200)
def fit_in_urls(self, original_url, sizes): crypto = CryptoURL(key=self._config.THUMBOR_SECURITY_KEY) unschemed_original_url = original_url.replace('http://', '') urls = {} for size in sizes: split_size = size.split('x') path = crypto.generate(image_url=unschemed_original_url, width=split_size[0], height=split_size[1], fit_in=True) urls[size] = self._config.THUMBOR_SERVER_URL.rstrip('/') + path return urls
async def test_shouldnt_auto_convert_png_to_jpg_if_png_has_transparency_with_signed_images( # NOQA self, context_mock): context_mock.return_value = self.context crypto = CryptoURL("ACME-SEC") url = crypto.generate(image_url="watermark.png") self.context.request = self.get_request(url=url) # save on result storage response = await self.async_fetch(url) expect(response.code).to_equal(200) expect(response.headers).not_to_include("Vary") expect(response.body).to_be_png()
def _fetch_images(self): crypto = CryptoURL(key=self.context.server.security_key) image_ops = [] if not hasattr(self.context.config, 'DISTRIBUTED_COLLAGE_FILTER_HTTP_LOADER'): self.context.config.DISTRIBUTED_COLLAGE_FILTER_HTTP_LOADER = 'thumbor.loaders.http_loader' self.context.modules.importer.import_item( 'DISTRIBUTED_COLLAGE_FILTER_HTTP_LOADER') loader = self.context.modules.importer.distributed_collage_filter_http_loader for i, url in enumerate(self.urls): width = self.image_width if i < len( self.urls) - 1 else self.last_image_width params = { 'width': int(width), 'height': int(self.context.request.height), 'image_url': url, 'smart': True, 'halign': 'center', 'valign': 'middle', 'filters': ['quality(100)'], } thumbor_host = getattr( self.context.config, 'DISTRIBUTED_COLLAGE_FILTER_THUMBOR_SERVER_URL', '%s://%s' % ( self.context.request_handler.request.protocol, self.context.request_handler.request.host, ), ) encrypted_url = '%s%s' % (thumbor_host, crypto.generate(**params)) image_ops.append(loader.load(self.context, encrypted_url)) images = yield image_ops successful = all([image.successful for image in images]) if not successful: logger.error( 'Retrieving at least one of the collaged images failed: %s' % (', '.join( [image.error for image in images if not image.successful]), )) self.callback() return max_age = min([ self.get_max_age(image.metadata.get('Cache-Control'), self.max_age) for image in images ]) self.assembly_images(images) self.callback()
async def test_image_already_generated_by_thumbor(self): with open("./tests/fixtures/images/image.jpg", "rb") as fixture: await self.context.modules.storage.put( quote("http://test.com/smart/image.jpg"), fixture.read()) crypto = CryptoURL("ACME-SEC") image_url = self.get_url( crypto.generate( image_url=quote("http://test.com/smart/image.jpg"))) url = crypto.generate(image_url=quote(image_url)) response = await self.async_fetch(url) expect(response.code).to_equal(200)
def test_image_already_generated_by_thumbor(self): with open('./tests/fixtures/images/image.jpg', 'r') as f: self.context.modules.storage.put( quote("http://test.com/smart/image.jpg"), f.read()) crypto = CryptoURL('ACME-SEC') image_url = self.get_url( crypto.generate( image_url=quote("http://test.com/smart/image.jpg"))) url = crypto.generate(image_url=quote(image_url)) response = self.fetch(url) expect(response.code).to_equal(200)
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(signature, url)
def test_can_auto_convert_jpeg_from_result_storage(self, context_mock): context_mock.return_value = self.context crypto = CryptoURL('ACME-SEC') url = crypto.generate(image_url=quote("http://test.com/smart/image.jpg")) self.context.request = self.get_request(url=url, accepts_webp=True) with open('./tests/fixtures/images/image.webp', 'r') as f: self.context.modules.result_storage.put(f.read()) response = self.get_as_webp(url) expect(response.code).to_equal(200) expect(response.headers).to_include('Vary') expect(response.headers['Vary']).to_include('Accept') expect(response.body).to_be_webp()
async def test_should_auto_convert_png_to_webp_if_auto_webp_is_true_and_png_has_transparency_with_signed_images( # NOQA self, context_mock): self.config.AUTO_WEBP = True context_mock.return_value = self.context crypto = CryptoURL("ACME-SEC") url = crypto.generate(image_url="watermark.png") self.context.request = self.get_request(url=url) # save on result storage response = await self.get_as_webp(url) expect(response.code).to_equal(200) expect(response.headers).to_include("Vary") expect(response.body).to_be_webp()
def test_thumbor_filter(self): testing.setUp(settings={ 'thumbor.security_key': 'foo', }) crypto = CryptoURL(key='foo') self.assertEqual( thumbor_filter({}, 'image', 25, 25), crypto.generate(width=25, height=25, image_url='image')) self.assertEqual(thumbor_filter({}, 'image', 25), crypto.generate(width=25, image_url='image')) self.assertEqual( thumbor_filter({}, 'image', 25, None), crypto.generate(width=25, height=0, image_url='image'))
async def test_should_auto_convert_png_to_jpg_with_signed_images( self, context_mock): context_mock.return_value = self.context crypto = CryptoURL("ACME-SEC") url = crypto.generate( image_url="Giunchedi%2C_Filippo_January_2015_01.png") self.context.request = self.get_request(url=url) context_mock.return_value = self.context response = await self.async_fetch(url) expect(response.code).to_equal(200) expect(response.headers).not_to_include("Vary") expect(response.body).to_be_jpeg()
def thumbor_filter(ctx, image, width, height=0): registry = get_current_registry(context=ctx) security_key = registry.settings.get('thumbor.security_key') if not all([security_key, image]): return '' # libthumbor generates an invalid url when height is None: # https://github.com/thumbor/libthumbor/blob/master/libthumbor/url.py#L19 # Coerce it to 0. This scales the height proportionally. if height is None: height = 0 crypto = CryptoURL(key=security_key) return crypto.generate(width=width, height=height, image_url=image)
def thumborurl(image, size): ''' Método que cria, através da libthumbor a url codificada para exibição de imagens na galeria ''' #print "CODIFICANDO:", size, image crypto = CryptoURL(key=app.config['THUMBOR_KEY']) codigo = crypto.generate( width=size[0] if isinstance(size[0], int) else None, height=size[1] if isinstance(size[1], int) else None, smart=True, image_url=image.replace('http://', '')) #print "CODIGO:", codigo return app.config['THUMBOR_URL'] + codigo
async def test_should_auto_convert_png_to_webp_if_auto_webp_is_true_with_signed_images( # NOQA self, context_mock): self.config.AUTO_WEBP = True context_mock.return_value = self.context crypto = CryptoURL("ACME-SEC") url = crypto.generate( image_url="Giunchedi%2C_Filippo_January_2015_01.png") self.context.request = self.get_request(url=url, accepts_webp=True) # save on result storage response = await self.get_as_webp(url) expect(response.code).to_equal(200) expect(response.headers).to_include("Vary") expect(response.body).to_be_webp()
async def test_can_auto_convert_jpeg_from_result_storage( self, context_mock): # NOQA context_mock.return_value = self.context crypto = CryptoURL("ACME-SEC") url = crypto.generate( image_url=quote("http://test.com/smart/image.jpg")) self.context.request = self.get_request(url=url, accepts_webp=True) with open("./tests/fixtures/images/image.webp", "rb") as fixture: await self.context.modules.result_storage.put(fixture.read()) response = await self.get_as_webp(url) expect(response.code).to_equal(200) expect(response.headers).to_include("Vary") expect(response.headers["Vary"]).to_include("Accept") expect(response.body).to_be_webp()
def generate_thumbnail_url(path: str, size: str = '0x0', is_camo_url: bool = False) -> str: path = urljoin("/", path) if not is_thumbor_enabled(): if is_safe_url(path, allowed_hosts=None): return path return get_camo_url(path) if is_safe_url( path, allowed_hosts=None) and not path.startswith("/user_uploads/"): return path source_type = get_source_type(path) safe_url = base64.urlsafe_b64encode(path.encode()).decode('utf-8') image_url = f'{safe_url}/source_type/{source_type}' width, height = map(int, size.split('x')) crypto = CryptoURL(key=settings.THUMBOR_KEY) smart_crop_enabled = True apply_filters = ['no_upscale()'] if is_camo_url: smart_crop_enabled = False apply_filters.append('quality(100)') if size != '0x0': apply_filters.append('sharpen(0.5,0.2,true)') encrypted_url = crypto.generate( width=width, height=height, smart=smart_crop_enabled, filters=apply_filters, image_url=image_url, ) if settings.THUMBOR_URL == 'http://127.0.0.1:9995': # If THUMBOR_URL is the default then thumbor is hosted on same machine # as the Zulip server and we should serve a relative URL. # We add a /thumbor in front of the relative url because we make # use of a proxy pass to redirect request internally in Nginx to 9995 # port where thumbor is running. thumbnail_url = '/thumbor' + encrypted_url else: thumbnail_url = urllib.parse.urljoin(settings.THUMBOR_URL, encrypted_url) return thumbnail_url
def get(self, **kwargs): # check if request is valid yield gen.maybe_future(self.check_pdf(kwargs.copy())) pdf = PDF(self.context) pdf_path = kwargs.pop('pdf') url_parts, pdf_url = pdf.url_parts(pdf_path) preview_path = pdf_path.replace('/pdf/', '').replace('.pdf', '.png') # Check if preview image already exists path = quote(preview_path.encode('utf-8')) exists = yield gen.maybe_future(pdf.get(path)) if not exists: # create a new preview data = yield self.create_preview(pdf_url) if not data: raise tornado.web.HTTPError(400) # store it in storage yield gen.maybe_future(pdf.put(path, data)) else: logger.debug('PDF preview already exists..') crypto = CryptoURL(key=self.context.server.security_key) options = {k: v for k, v in kwargs.items() if v and k != 'hash'} preview_url = crypto.generate(image_url=preview_path, **options) kwargs['hash'] = RequestParser.path_to_parameters(preview_url)['hash'] # Patch the request uri to allow normal thumbor operations self.request.uri = preview_url self.request.path = preview_url kwargs['request'] = self.request kwargs['image'] = preview_path self.context.request = RequestParameters(**kwargs) # set valid file name in headers name = os.path.basename(kwargs.get('image', None)) if name: self.set_header('Content-Disposition', 'inline; filename="{name}"'.format(name=name)) # Call the original ImageHandler.get method to serve the image. super(PDFHandler, self).get(**kwargs)
def get_image_url(self, image_host, image_uuid, width=None, height=None): security_key = self.settings.get('thumbor.security_key') if not (security_key and image_host and image_uuid): return '' crypto = CryptoURL(key=security_key) if not (width or height): image_url = crypto.generate(image_url=image_uuid) elif width and height: image_url = crypto.generate( width=width, height=height, image_url=image_uuid) elif width: image_url = crypto.generate( width=width, height=0, image_url=image_uuid) else: image_url = crypto.generate( width=0, height=height, image_url=image_uuid) return urljoin(image_host, image_url)