Exemplo n.º 1
0
    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)
Exemplo n.º 2
0
def test_parse_urls_without_image():

    options = Url.parse_options(
        'unsafe/meta/10x11:12x13/-300x-200/left/top/smart/')

    assert options

    options = Url.parse_options(
        '/unsafe/meta/10x11:12x13/-300x-200/left/top/smart/')

    assert options
    assert options['meta'] == True

    assert options['crop']['left'] == 10
    assert options['crop']['top'] == 11
    assert options['crop']['right'] == 12
    assert options['crop']['bottom'] == 13

    assert options['width'] == 300
    assert options['height'] == 200

    assert options['horizontal_flip'] == True
    assert options['vertical_flip'] == True

    assert options['halign'] == 'left'
    assert options['valign'] == 'top'

    assert options['smart'] == True
Exemplo n.º 3
0
def test_parse_urls_without_image():

    options = Url.parse_options("unsafe/meta/10x11:12x13/-300x-200/left/top/smart/")

    assert options

    options = Url.parse_options("/unsafe/meta/10x11:12x13/-300x-200/left/top/smart/")

    assert options
    assert options['meta'] == True

    assert options['crop']['left'] == 10
    assert options['crop']['top'] == 11
    assert options['crop']['right'] == 12
    assert options['crop']['bottom'] == 13

    assert options['width'] == 300
    assert options['height'] == 200

    assert options['horizontal_flip'] == True
    assert options['vertical_flip'] == True

    assert options['halign'] == 'left'
    assert options['valign'] == 'top'

    assert options['smart'] == True
Exemplo n.º 4
0
def test_parse_urls_with_image():

    image_url = 's.glbimg.com/es/ge/f/original/2011/03/29/orlandosilva_60.jpg'

    options = Url.parse('/unsafe/meta/10x11:12x13/-300x-200/left/top/smart/%s' % image_url)

    assert options['image']
    assert options['image'] == image_url

    options = Url.parse('unsafe/meta/10x11:12x13/-300x-200/left/top/smart/%s' % image_url)
 
    assert options['image']
    assert options['image'] == image_url
Exemplo n.º 5
0
def test_parse_urls_with_image():

    image_url = 's.glbimg.com/es/ge/f/original/2011/03/29/orlandosilva_60.jpg'

    options = Url.parse(
        '/unsafe/meta/10x11:12x13/-300x-200/left/top/smart/%s' % image_url)

    assert options['image']
    assert options['image'] == image_url

    options = Url.parse('unsafe/meta/10x11:12x13/-300x-200/left/top/smart/%s' %
                        image_url)

    assert options['image']
    assert options['image'] == image_url
Exemplo n.º 6
0
    def encrypt(self, 
                width,
                height,
                smart,
                fit_in,
                flip_horizontal,
                flip_vertical,
                halign,
                valign,
                crop_left,
                crop_top,
                crop_right,
                crop_bottom,
                image):

        url = "%s/%s" % (Url.generate_options(width,
                                              height,
                                              smart,
                                              False,
                                              fit_in,
                                              flip_horizontal,
                                              flip_vertical,
                                              halign,
                                              valign,
                                              crop_left,
                                              crop_top,
                                              crop_right,
                                              crop_bottom),
                        hashlib.md5(image).hexdigest())

        pad = lambda s: s + (16 - len(s) % 16) * "{"
        cipher = AES.new(self.salt)
        encrypted = base64.urlsafe_b64encode(cipher.encrypt(pad(url)))

        return encrypted
Exemplo n.º 7
0
    def get_handlers(self):
        handlers = [
            (r'/', HealthcheckHandler),
            (r'/favicon.ico', FaviconHandler),
        ]

        if self.context.config.UPLOAD_ENABLED:
            # TODO: Old handler to upload images. Will be deprecated soon.
            handlers.append(
                (r'/upload', LegacyImageUploadHandler, {'context': self.context})
            )

            # Handler to upload images (POST).
            handlers.append(
                (r'/image', ImageUploadHandler, {'context': self.context})
            )

            # Handler to retrieve or modify existing images  (GET, PUT, DELETE)
            handlers.append(
                (r'/image/(.*)', ImageResourceHandler, {'context': self.context})
            )

        if self.context.config.USE_BLACKLIST:
            handlers.append(
                (r'/blacklist', BlacklistHandler, {'context': self.context})
            )

        # Imaging handler (GET)
        handlers.append(
            (Url.regex(), ImagingHandlerMine, {'context': self.context})
        )

        return handlers
Exemplo n.º 8
0
def send_data(event, result, start_time):
    time_now = datetime.datetime.utcnow().isoformat()
    time_stamp = str(time_now)
    postDict = {}
    size = '-'
    filters = Url.parse_decrypted(event['path'])
    del filters['image']
    if int(result['statusCode']) == 200:
        size = (len(result['body'] * 3)) / 4
    postDict['Data'] = {
        'Version': get_distribution('image_handler').version,
        'Company': 'AWS',
        'Name': 'AWS Serverless Image Handler',
        'Region': os.environ.get('AWS_DEFAULT_REGION'),
        'Filters': filters,
        'StatusCode': result['statusCode'],
        'ResponseSize': size,
        'ResponseTime': round(timeit.default_timer() - start_time, 3)
    }
    postDict['TimeStamp'] = time_stamp
    postDict['Solution'] = 'SO0023'
    postDict['UUID'] = os.environ.get('UUID')
    # API Gateway URL to make HTTP POST call
    url = 'https://metrics.awssolutionsbuilder.com/generic'
    data = json.dumps(postDict)
    headers = {'content-type': 'application/json'}
    req = Request(url, data, headers)
    rsp = urlopen(req)
    content = rsp.read()
    rspcode = rsp.getcode()
    logging.debug('Response Code: {}'.format(rspcode))
    logging.debug('Response Content: {}'.format(content))
    return req
Exemplo n.º 9
0
    def path_to_parameters(cls, path):
        '''
        :param path: url path
        :return: A dictionary of parameters to be used with
                ImagingHandler instances
        '''
        if not cls._url_regex:
            cls._url_regex = re.compile(Url.regex())

        if cls._url_regex.groups:
            match = cls._url_regex.match(path)

            # Pass matched groups to the handler.  Since
            # match.groups() includes both named and
            # unnamed groups, we want to use either groups
            # or groupdict but not both.
            if cls._url_regex.groupindex:
                parameters = dict((str(k), tornado.web._unquote_or_none(v))
                                  for (k, v) in match.groupdict().items())
            else:
                parameters = [
                    tornado.web._unquote_or_none(s) for s in match.groups()
                ]
        else:
            parameters = dict()

        return parameters
Exemplo n.º 10
0
    def encrypt(self, width, height, smart, adaptive, full, fit_in,
                flip_horizontal, flip_vertical, halign, valign, trim,
                crop_left, crop_top, crop_right, crop_bottom, filters, image):

        generated_url = Url.generate_options(width=width,
                                             height=height,
                                             smart=smart,
                                             meta=False,
                                             adaptive=adaptive,
                                             full=full,
                                             fit_in=fit_in,
                                             horizontal_flip=flip_horizontal,
                                             vertical_flip=flip_vertical,
                                             halign=halign,
                                             valign=valign,
                                             trim=trim,
                                             crop_left=crop_left,
                                             crop_top=crop_top,
                                             crop_right=crop_right,
                                             crop_bottom=crop_bottom,
                                             filters=filters)

        url = "%s/%s" % (generated_url, hashlib.md5(image).hexdigest())

        def pad(s):
            return s + (16 - len(s) % 16) * "{"

        cipher = AES.new(self.security_key, MODE_ECB)
        encrypted = base64.urlsafe_b64encode(
            cipher.encrypt(pad(url.encode('utf-8'))))

        return encrypted
Exemplo n.º 11
0
    def get_handlers(self):
        handlers = [
            (r'/healthcheck', HealthcheckHandler),
        ]

        if self.context.config.UPLOAD_ENABLED:
            # TODO Old handler to upload images
            handlers.append((r'/upload', UploadHandler, {
                'context': self.context
            }))

            # Handler to upload images (POST).
            handlers.append((r'/image', ImagesHandler, {
                'context': self.context
            }))

            # Handler to retrieve or modify existing images  (GET, PUT, DELETE)
            handlers.append((r'/image/(.*)', ImageHandler, {
                'context': self.context
            }))

        # Imaging handler (GET)
        handlers.append((Url.regex(), ImagingHandler, {
            'context': self.context
        }))

        return handlers
Exemplo n.º 12
0
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
Exemplo n.º 13
0
Arquivo: web.py Projeto: Bladrak/core
    def path_to_parameters(cls, path):
        '''
        :param path: url path
        :return: A dictionary of parameters to be used with
                ImagingHandler instances
        '''
        if not cls._url_regex:
            cls._url_regex = re.compile(Url.regex())

        if cls._url_regex.groups:
            match = cls._url_regex.match(path)

            # See https://github.com/tornadoweb/tornado/blob/01c78ebfcc993ff4f1d8336c2c45844fe9dab60e/tornado/web.py#L1951
            # Pass matched groups to the handler.  Since
            # match.groups() includes both named and
            # unnamed groups, we want to use either groups
            # or groupdict but not both.
            if cls._url_regex.groupindex:
                parameters = dict(
                    (str(k), tornado.web._unquote_or_none(v))
                    for (k, v) in match.groupdict().items())
            else:
                parameters = [
                    tornado.web._unquote_or_none(s)
                    for s in match.groups()
                ]
        else:
            parameters = dict()

        return parameters
Exemplo n.º 14
0
    def get_handlers(self):
        handlers = [
            (self.context.config.HEALTHCHECK_ROUTE, HealthcheckHandler),
        ]

        if self.context.config.UPLOAD_ENABLED:
            # Handler to upload images (POST).
            handlers.append((r'/image', ImageUploadHandler, {
                'context': self.context
            }))

            # Handler to retrieve or modify existing images  (GET, PUT, DELETE)
            handlers.append((r'/image/(.*)', ImageResourceHandler, {
                'context': self.context
            }))

        if self.context.config.USE_BLACKLIST:
            handlers.append((r'/blacklist', BlacklistHandler, {
                'context': self.context
            }))

        # Imaging handler (GET)
        handlers.append((Url.regex(), ImagingHandler, {
            'context': self.context
        }))

        return handlers
Exemplo n.º 15
0
    def get_handlers(self):
        handlers = [
            (r'/healthcheck', HealthcheckHandler),
        ]

        if self.context.config.UPLOAD_ENABLED:
            # Handler to upload images (POST).
            handlers.append(
                (r'/image', ImageUploadHandler, {'context': self.context})
            )

            # Handler to retrieve or modify existing images  (GET, PUT, DELETE)
            handlers.append(
                (r'/image/(.*)', ImageResourceHandler, {'context': self.context})
            )

        if self.context.config.USE_BLACKLIST:
            handlers.append(
                (r'/blacklist', BlacklistHandler, {'context': self.context})
            )

        # Imaging handler (GET)
        handlers.append(
            (Url.regex(), ImagingHandler, {'context': self.context})
        )

        return handlers
Exemplo n.º 16
0
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
Exemplo n.º 17
0
    def post(self, **kw):
        paths = self.get_arguments('paths[]')

        if len(paths) > MultiHandler.paths_limit:
            self.set_status(400)
            super(MultiHandler, self).write('Too many paths: %d max' %
                                            MultiHandler.paths_limit)
            super(MultiHandler, self).finish()
            return

        for path in paths:
            request = HTTPServerRequest(method='GET',
                                        uri=path,
                                        host=self.request.host,
                                        connection=self.request.connection)

            handler = MultiHandler(self.application,
                                   request,
                                   context=self.context)

            # Copy over the storage as-is, which allows those requests to
            # share storage if needed (useful for request-storage)
            handler.context.modules.storage = self.context.modules.storage

            m = re.match(Url.regex(), path)
            yield handler.check_image(m.groupdict())

        # Close the request ASAP, the work is to be done async
        self.set_status(200)
        super(MultiHandler, self).finish()
Exemplo n.º 18
0
def test_url_generate_with_alignments():
    url = Url.generate_options(
        halign='left',
        valign='top'
    )

    assert url == "0x0/left/top", url
Exemplo n.º 19
0
def test_url_generate_min():
    url = Url.generate_options(
        width=300,
        height=200
    )

    assert url == "300x200"
Exemplo n.º 20
0
    def get_handlers(self):
        handlers = [
            (r'/healthcheck', HealthcheckHandler),
        ]

        if self.context.config.UPLOAD_ENABLED:
            # TODO: Old handler to upload images. Will be deprecated soon.
            handlers.append(
                (r'/upload', LegacyImageUploadHandler, {'context': self.context})
            )

            # Handler to upload images (POST).
            handlers.append(
                (r'/image', ImageUploadHandler, {'context': self.context})
            )

            # Handler to retrieve or modify existing images  (GET, PUT, DELETE)
            handlers.append(
                (r'/image/(.*)', ImageResourceHandler, {'context': self.context})
            )

        if self.context.config.USE_BLACKLIST:
            handlers.append(
                (r'/blacklist', BlacklistHandler, {'context': self.context})
            )

        # Imaging handler (GET)
        handlers.append(
            (Url.regex(not self.context.config.SECURITY_DISABLE_KEY), ImagingHandler, {'context': self.context})
        )

        return handlers
Exemplo n.º 21
0
    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)'
        )
Exemplo n.º 22
0
    def post(self, **kw):
        paths = self.get_arguments('paths[]')

        if len(paths) > MultiHandler.paths_limit:
            self.set_status(400)
            super(MultiHandler, self).write(
                'Too many paths: %d max' % MultiHandler.paths_limit
            )
            super(MultiHandler, self).finish()
            return

        for path in paths:
            request = HTTPServerRequest(
                method='GET',
                uri=path,
                host=self.request.host,
                connection=self.request.connection
            )

            handler = MultiHandler(
                self.application,
                request,
                context=self.context
            )

            # Copy over the storage as-is, which allows those requests to
            # share storage if needed (useful for request-storage)
            handler.context.modules.storage = self.context.modules.storage

            m = re.match(Url.regex(), path)
            yield handler.check_image(m.groupdict())

        # Close the request ASAP, the work is to be done async
        self.set_status(200)
        super(MultiHandler, self).finish()
Exemplo n.º 23
0
def test_returns_route_regex_with_filters():
    class TestFilter(object):
        regex = r'some-filter-fake-regex'

    url = Url.regex(filters=[TestFilter])

    assert url == '/?unsafe/(?:(?P<meta>meta)/)?(?:(?P<crop_left>\d+)x(?P<crop_top>\d+):(?P<crop_right>\d+)x(?P<crop_bottom>\d+)/)?(?:(?P<fit_in>fit-in)/)?(?:(?P<horizontal_flip>-)?(?P<width>\d+)?x(?P<vertical_flip>-)?(?P<height>\d+)?/)?(?:(?P<halign>left|right|center)/)?(?:(?P<valign>top|bottom|middle)/)?(?:(?P<smart>smart)/)?some-filter-fake-regex(?P<image>.+)'
Exemplo n.º 24
0
 def get_handlers(self):
     # Imaging handler (GET)
     return [(BuzzFeedHandler.regex(), BuzzFeedHandler, {
         'context': self.context
     }), (Url.regex(), ImagingHandler, {
         'context': self.context
     })]
Exemplo n.º 25
0
def test_returns_route_regex_with_filters():
    class TestFilter(object):
        regex = r'some-filter-fake-regex'

    url = Url.regex(filters=[TestFilter])

    assert url == '/?unsafe/(?:(?P<meta>meta)/)?(?:(?P<crop_left>\d+)x(?P<crop_top>\d+):(?P<crop_right>\d+)x(?P<crop_bottom>\d+)/)?(?:(?P<fit_in>fit-in)/)?(?:(?P<horizontal_flip>-)?(?P<width>\d+)?x(?P<vertical_flip>-)?(?P<height>\d+)?/)?(?:(?P<halign>left|right|center)/)?(?:(?P<valign>top|bottom|middle)/)?(?:(?P<smart>smart)/)?some-filter-fake-regex(?P<image>.+)'
Exemplo n.º 26
0
Arquivo: app.py Projeto: Hazer/thumbor
    def __init__(self, context):
        self.context = context

        handlers = [
            (r'/healthcheck', HealthcheckHandler),
        ]

        if context.config.UPLOAD_ENABLED:
            # TODO Old handler to upload images
            handlers.append(
                (r'/upload', UploadHandler, {'context': self.context})
            )

            # Handler to upload images (POST).
            handlers.append(
                (r'/image', ImagesHandler, {'context': self.context})
            )

            # Handler to retrieve or modify existing images  (GET, PUT, DELETE)
            handlers.append(
                (r'/image/(.*)', ImageHandler, {'context': self.context})
            )

        # Imaging handler (GET)
        handlers.append(
            (Url.regex(), ImagingHandler, {'context': self.context})
        )

        super(ThumborServiceApp, self).__init__(handlers)
Exemplo n.º 27
0
    def check_image(self, kw):
        if self.context.config.MAX_ID_LENGTH > 0:
            # Check if an image with an uuid exists in storage
            exists = yield gen.maybe_future(
                self.context.modules.storage.exists(kw["image"][: self.context.config.MAX_ID_LENGTH])
            )
            if exists:
                kw["image"] = kw["image"][: self.context.config.MAX_ID_LENGTH]

        url = self.request.uri

        if not self.validate(kw["image"]):
            self._error(400, "No original image was specified in the given URL")
            return

        kw["request"] = self.request
        kw["image"] = quote(kw["image"].encode("utf-8"))
        kw["config"] = self.context.config

        self.context.request = RequestParameters(**kw)

        has_none = not self.context.request.unsafe and not self.context.request.hash
        has_both = self.context.request.unsafe and self.context.request.hash

        if has_none or has_both:
            self._error(400, "URL does not have hash or unsafe, or has both: %s" % url)
            return

        if self.context.request.unsafe and not self.context.config.ALLOW_UNSAFE_URL:
            self._error(400, "URL has unsafe but unsafe is not allowed by the config: %s" % url)
            return

        if self.context.config.USE_BLACKLIST:
            blacklist = yield self.get_blacklist_contents()
            if self.context.request.image_url in blacklist:
                self._error(400, "Source image url has been blacklisted: %s" % self.context.request.image_url)
                return

        url_signature = self.context.request.hash
        if url_signature:
            signer = self.context.modules.url_signer(self.context.server.security_key)

            url_to_validate = Url.encode_url(url).replace("/%s/" % self.context.request.hash, "")
            valid = signer.validate(url_signature, url_to_validate)

            if not valid and self.context.config.STORES_CRYPTO_KEY_FOR_EACH_IMAGE:
                # Retrieves security key for this image if it has been seen before
                security_key = yield gen.maybe_future(
                    self.context.modules.storage.get_crypto(self.context.request.image_url)
                )
                if security_key is not None:
                    signer = self.context.modules.url_signer(security_key)
                    valid = signer.validate(url_signature, url_to_validate)

            if not valid:
                self._error(400, "Malformed URL: %s" % url)
                return

        self.execute_image_operations()
Exemplo n.º 28
0
def test_url_generate_with_flipping():
    url = Url.generate_options(width=300,
                               height=200,
                               smart=True,
                               horizontal_flip=True,
                               vertical_flip=True)

    assert url == '-300x-200/smart'
Exemplo n.º 29
0
def test_url_generate_with_smart():
    url = Url.generate_options(
        width=300,
        height=200,
        smart=True
    )

    assert url == "300x200/smart"
Exemplo n.º 30
0
def test_url_generate_with_manual_crop():
    url = Url.generate_options(width=300,
                               height=200,
                               crop_left=10,
                               crop_top=11,
                               crop_right=12,
                               crop_bottom=13)

    assert url == '10x11:12x13/300x200'
Exemplo n.º 31
0
def test_url_generate_with_flipping():
    url = Url.generate_options(
        width=300,
        height=200,
        smart=True,
        horizontal_flip=True,
        vertical_flip=True
    )

    assert url == "-300x-200/smart"
Exemplo n.º 32
0
    def get_handlers(self):
        handlers = ThumborServiceApp.get_handlers(self)

        # Remove the default image handler
        handlers.pop()

        # Then install our own image handler
        handlers.append((Url.regex(), RewriteHandler, {
            'context': self.context
        }))
        return handlers
Exemplo n.º 33
0
def test_url_generate_with_manual_crop():
    url = Url.generate_options(
        width=300,
        height=200,
        crop_left=10,
        crop_top=11,
        crop_right=12,
        crop_bottom=13
    )

    assert url == "10x11:12x13/300x200"
Exemplo n.º 34
0
    def test_can_get_handlers(self):
        ctx = mock.Mock(config=mock.Mock(
            UPLOAD_ENABLED=False,
            USE_BLACKLIST=False,
        ))
        app = ThumborServiceApp(ctx)

        handlers = app.get_handlers()
        expect(handlers).to_length(2)
        expect(handlers[0][0]).to_equal(r'/healthcheck')
        expect(handlers[1][0]).to_equal(Url.regex())
Exemplo n.º 35
0
    def check_image(self, kw):
        if self.context.config.MAX_ID_LENGTH > 0:
            # Check if an image with an uuid exists in storage
            exists = yield gen.maybe_future(self.context.modules.storage.exists(kw['image'][:self.context.config.MAX_ID_LENGTH]))
            if exists:
                kw['image'] = kw['image'][:self.context.config.MAX_ID_LENGTH]

        url = self.request.uri

        if not self.validate(kw['image']):
            self._error(400, 'No original image was specified in the given URL')
            return

        kw['request'] = self.request
        kw['image'] = quote(kw['image'].encode('utf-8'))

        self.context.request = RequestParameters(**kw)

        has_none = not self.context.request.unsafe and not self.context.request.hash
        has_both = self.context.request.unsafe and self.context.request.hash

        if has_none or has_both:
            self._error(400, 'URL does not have hash or unsafe, or has both: %s' % url)
            return

        if self.context.request.unsafe and not self.context.config.ALLOW_UNSAFE_URL:
            self._error(400, 'URL has unsafe but unsafe is not allowed by the config: %s' % url)
            return

        if self.context.config.USE_BLACKLIST:
            blacklist = yield self.get_blacklist_contents()
            if self.context.request.image_url in blacklist:
                self._error(400, 'Source image url has been blacklisted: %s' % self.context.request.image_url)
                return

        url_signature = self.context.request.hash
        if url_signature:
            signer = self.context.modules.url_signer(self.context.server.security_key)

            url_to_validate = Url.encode_url(url).replace('/%s/' % self.context.request.hash, '')
            valid = signer.validate(url_signature, url_to_validate)

            if not valid and self.context.config.STORES_CRYPTO_KEY_FOR_EACH_IMAGE:
                # Retrieves security key for this image if it has been seen before
                security_key = yield gen.maybe_future(self.context.modules.storage.get_crypto(self.context.request.image_url))
                if security_key is not None:
                    signer = self.context.modules.url_signer(security_key)
                    valid = signer.validate(url_signature, url_to_validate)

            if not valid:
                self._error(400, 'Malformed URL: %s' % url)
                return

        self.execute_image_operations()
Exemplo n.º 36
0
    def __init__(self, context):
        self.context = context

        handlers = [(r"/healthcheck", HealthcheckHandler)]

        if context.config.ENABLE_ORIGINAL_PHOTO_UPLOAD:
            handlers.append((r"/upload", UploadHandler, {"context": context}))

        handlers.append((Url.regex(), ImageProcessHandler, {"context": context}))

        super(ThumborServiceApp, self).__init__(handlers)
Exemplo n.º 37
0
    def decrypt(self, encrypted):
        cipher = AES.new(self.salt)

        debased = base64.urlsafe_b64decode(encrypted.encode("utf-8"))
        decrypted = cipher.decrypt(debased).rstrip('{')

        result = Url.parse('/%s' % decrypted, with_unsafe=False)

        result['image_hash'] = result['image']
        del result['image']

        return result
Exemplo n.º 38
0
    def decrypt(self, encrypted):
        cipher = AES.new(self.salt)

        debased = base64.urlsafe_b64decode(encrypted.encode("utf-8"))
        decrypted = cipher.decrypt(debased).rstrip('{')

        result = Url.parse('/%s' % decrypted, with_unsafe=False)

        result['image_hash'] = result['image']
        del result['image']

        return result
Exemplo n.º 39
0
    def test_can_get_regex_without_unsafe(self):
        regex = Url.regex(False)

        expect(regex).to_equal(
            '/?(?:(?P<debug>debug)/)?(?:(?P<meta>meta)/)?'
            '(?:(?P<trim>trim(?::(?:top-left|bottom-right))?(?::\\d+)?)/)?'
            '(?:(?P<crop_left>\\d+)x(?P<crop_top>\\d+):(?P<crop_right>\\d+)x(?P<crop_bottom>\\d+)/)?'
            '(?:(?P<adaptive>adaptive-)?(?P<full>full-)?(?P<fit_in>fit-in)/)?(?:(?P<horizontal_flip>-)?'
            '(?P<width>(?:\\d+|orig))?x(?P<vertical_flip>-)?(?P<height>(?:\\d+|orig))?/)?'
            '(?:(?P<halign>left|right|center)/)?(?:(?P<valign>top|bottom|middle)/)?'
            '(?:(?P<smart>smart)/)?(?:filters:(?P<filters>.+?\\))/)?(?P<image>.+)'
        )
Exemplo n.º 40
0
    def test_can_get_regex_without_unsafe(self):
        regex = Url.regex(False)

        expect(regex).to_equal(
            '/?(?:(?P<debug>debug)/)?(?:(?P<meta>meta)/)?'
            '(?:(?P<trim>trim(?::(?:top-left|bottom-right))?(?::\\d+)?)/)?'
            '(?:(?P<crop_left>\\d+)x(?P<crop_top>\\d+):(?P<crop_right>\\d+)x(?P<crop_bottom>\\d+)/)?'
            '(?:(?P<adaptive>adaptive-)?(?P<full>full-)?(?P<fit_in>fit-in)/)?(?:(?P<horizontal_flip>-)?'
            '(?P<width>(?:\\d+|orig))?x(?P<vertical_flip>-)?(?P<height>(?:\\d+|orig))?/)?'
            '(?:(?P<halign>left|right|center)/)?(?:(?P<valign>top|bottom|middle)/)?'
            '(?:(?P<smart>smart)/)?(?:filters:(?P<filters>.+?\\))/)?(?P<image>.+)'
        )
Exemplo n.º 41
0
    def test_can_get_handlers(self):
        ctx = mock.Mock(
            config=mock.Mock(
                UPLOAD_ENABLED=False,
                USE_BLACKLIST=False,
            )
        )
        app = ThumborServiceApp(ctx)

        handlers = app.get_handlers()
        expect(handlers).to_length(2)
        expect(handlers[0][0]).to_equal(r'/healthcheck')
        expect(handlers[1][0]).to_equal(Url.regex())
Exemplo n.º 42
0
def test_complete_url():
    url = Url.generate_options(width=300,
                               height=200,
                               smart=True,
                               meta=True,
                               horizontal_flip=True,
                               vertical_flip=True,
                               crop_left=10,
                               crop_top=11,
                               crop_right=12,
                               crop_bottom=13)

    assert url == 'meta/10x11:12x13/-300x-200/smart', url
Exemplo n.º 43
0
    def __init__(self, context):
        self.context = context

        handlers = [
            (r'/healthcheck', HealthcheckHandler),
        ]

        if context.config.UPLOAD_ENABLED:
            handlers.append(
                (r'/upload', UploadHandler, { 'context': context })
            )

        handlers.append(
            (Url.regex(has_unsafe_or_hash=False,with_save=True), SaveHandler, { 'context': context })
        )

        handlers.append(
            (Url.regex(), ImageProcessHandler, { 'context':  context })
        )


        super(ThumborServiceApp, self).__init__(handlers)
Exemplo n.º 44
0
    def __init__(self, conf_file=None, security_key=None, custom_handlers=None):
        if conf_file is None:
            conf_file = ThumborServiceApp.get_conf_file(conf_file)

        logger.info('Config file: %s' % conf_file)
        parse_config_file(conf_file)

        self.loader = real_import(conf.LOADER)
        self.storage = real_import(conf.STORAGE)
        self.engine = real_import(conf.ENGINE)
        self.detectors = [real_import(detector_name).Detector for detector_name in conf.DETECTORS]
        self.filters = [real_import(filter_name).Filter for filter_name in conf.FILTERS]
        filters.compile_filters(self.filters)

        # run again to overwrite the default settings on the
        # imported modules with the ones defined into the config file
        parse_config_file(conf_file)

        #storage = storage.Storage()
        #self.engine = self.engine.Engine()

        if security_key:
            options.SECURITY_KEY = security_key

        handler_context = {
            'loader': self.loader,
            'storage': self.storage,
            'engine': self.engine,
            'detectors': self.detectors,
            'filters': self.filters
        }

        handlers = [
            (r'/healthcheck', HealthcheckHandler)
        ]

        if conf.ALLOW_UNSAFE_URL:
            handlers.append(
                (Url.regex(), MainHandler, handler_context),
            )

        if custom_handlers:
            for handler in custom_handlers:
                handlers.append((handler[0], handler[1], handler_context))
        else:
            handlers.append(
                (r'/(?P<crypto>[^/]+)/(?P<image>(.+))', CryptoHandler, handler_context)
            )

        super(ThumborServiceApp, self).__init__(handlers)
Exemplo n.º 45
0
class Filter(BaseFilter):
    phase = PHASE_PRE_LOAD

    domain_regex = re.compile(r'^(https?://)?.*?/')
    url_regex = re.compile(Url.regex())

    def parse_url(self, url):
        level = 0
        while level < MAX_LEVEL:
            url = self.domain_regex.sub('', url)
            result = self.url_regex.match(url)
            if not result:
                return None

            parts = result.groupdict()
            image = parts.get('image', None)

            if not (image and
                    (parts.get('hash', None) or parts.get('unsafe', None))):
                return None

            top, right, left, bottom = parts.get('crop_top', None), parts.get(
                'crop_right',
                None), parts.get('crop_left',
                                 None), parts.get('crop_bottom', None)
            if top and right and left and bottom:
                return (image, top, right, left, bottom)

            url = image
            level += 1

        return None

    @filter_method()
    def extract_focal(self):
        parts = self.parse_url(self.context.request.image_url)
        if parts:
            image, top, right, left, bottom = parts
            top, right, left, bottom = int(top), int(right), int(left), int(
                bottom)

            width = right - left
            height = bottom - top
            self.context.request.focal_points.append(
                FocalPoint.from_square(left,
                                       top,
                                       width,
                                       height,
                                       origin="Original Extraction"))
            self.context.request.image_url = image
Exemplo n.º 46
0
    def encrypt(self, width, height, smart, fit_in, flip_horizontal,
                flip_vertical, halign, valign, crop_left, crop_top, crop_right,
                crop_bottom, image):

        url = "%s/%s" % (Url.generate_options(
            width, height, smart, False, fit_in, flip_horizontal,
            flip_vertical, halign, valign, crop_left, crop_top, crop_right,
            crop_bottom), hashlib.md5(image).hexdigest())

        pad = lambda s: s + (16 - len(s) % 16) * "{"
        cipher = AES.new(self.salt)
        encrypted = base64.urlsafe_b64encode(cipher.encrypt(pad(url)))

        return encrypted
Exemplo n.º 47
0
    def __init__(self, context):
        self.context = context

        handlers = [(r'/healthcheck', HealthcheckHandler)]

        if context.config.ALLOW_UNSAFE_URL:
            handlers.append((Url.regex(), MainHandler, {'context': context}), )

        handlers.append(
            (r'/(?P<crypto>[^/]+)/(?P<image>(?:.+))', CryptoHandler, {
                'context': context
            }))

        super(ThumborServiceApp, self).__init__(handlers)
Exemplo n.º 48
0
    def decrypt(self, encrypted):
        cipher = AES.new(self.security_key)

        try:
            debased = base64.urlsafe_b64decode(encrypted.encode("utf-8"))
            decrypted = cipher.decrypt(debased).rstrip("{")
        except TypeError:
            return None

        result = Url.parse("/%s" % decrypted)

        result["image_hash"] = result["image"]
        del result["image"]

        return result
Exemplo n.º 49
0
    def decrypt(self, encrypted):
        cipher = AES.new(self.security_key)

        try:
            debased = base64.urlsafe_b64decode(encrypted.encode("utf-8"))
            decrypted = cipher.decrypt(debased).rstrip('{')
        except TypeError:
            return None

        result = Url.parse_decrypted('/%s' % decrypted)

        result['image_hash'] = result['image']
        del result['image']

        return result
Exemplo n.º 50
0
    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)
Exemplo n.º 51
0
    def decrypt(self, encrypted):
        cipher = AES.new(self.security_key, MODE_ECB)

        try:
            debased = base64.urlsafe_b64decode(encrypted.encode("utf-8"))
            decrypted = cipher.decrypt(debased).rstrip('{')
        except TypeError:
            return None

        result = Url.parse_decrypted('/%s' % decrypted)

        result['image_hash'] = result['image']
        del result['image']

        return result
Exemplo n.º 52
0
    def __init__(self, context):
        self.context = context

        handlers = [
            (r'/healthcheck', HealthcheckHandler),
        ]

        if context.config.UPLOAD_ENABLED:
            handlers.append((r'/upload', UploadHandler, {'context': context}))

        handlers.append((Url.regex(), ImageProcessHandler, {
            'context': context
        }))

        super(ThumborServiceApp, self).__init__(handlers)
Exemplo n.º 53
0
def test_complete_url():
    url = Url.generate_options(
        width=300,
        height=200,
        smart=True,
        meta=True,
        horizontal_flip=True,
        vertical_flip=True,
        crop_left=10,
        crop_top=11,
        crop_right=12,
        crop_bottom=13
    )

    assert url == "meta/10x11:12x13/-300x-200/smart", url
Exemplo n.º 54
0
    def encrypt(self,
                width,
                height,
                smart,
                adaptive,
                full,
                fit_in,
                flip_horizontal,
                flip_vertical,
                halign,
                valign,
                trim,
                crop_left,
                crop_top,
                crop_right,
                crop_bottom,
                filters,
                image):

        generated_url = Url.generate_options(
            width=width,
            height=height,
            smart=smart,
            meta=False,
            adaptive=adaptive,
            full=full,
            fit_in=fit_in,
            horizontal_flip=flip_horizontal,
            vertical_flip=flip_vertical,
            halign=halign,
            valign=valign,
            trim=trim,
            crop_left=crop_left,
            crop_top=crop_top,
            crop_right=crop_right,
            crop_bottom=crop_bottom,
            filters=filters
        )

        url = "%s/%s" % (generated_url, hashlib.md5(image).hexdigest())

        def pad(s):
            return s + (16 - len(s) % 16) * "{"

        cipher = AES.new(self.security_key, MODE_ECB)
        encrypted = base64.urlsafe_b64encode(cipher.encrypt(pad(url.encode('utf-8'))))

        return encrypted
Exemplo n.º 55
0
    def get(self, url):
        url = url.encode('utf-8')
        image = ""

        if self.context.config.get('SHORTENER_GENERATOR_PRESERVE_NAME'):
            reg = re.compile(Url.regex())
            result = reg.match(url)

            if result is None:
                raise ValueError("URL does not match thumbor's URL pattern")

            result = result.groupdict()

            image = "/{image}".format(image=os.path.basename(result['image']))

        return "{hash}{image}".format(hash=self.shorten(url), image=image)
Exemplo n.º 56
0
    def __init__(self, conf_file=None, custom_handlers=None):

        if conf_file is None:
            conf_file = ThumborServiceApp.get_conf_file(conf_file)

        logger.info('Config file: %s' % conf_file)
        parse_config_file(conf_file)

        loader = real_import(options.LOADER)
        storage = real_import(options.STORAGE)
        engine = real_import(options.ENGINE)
        detectors = [
            real_import(detector_name).Detector
            for detector_name in options.DETECTORS
        ]
        filters = [
            real_import(filter_name).Filter for filter_name in options.FILTERS
        ]

        # run again to overwrite the default settings on the
        # imported modules with the ones defined into the config file
        parse_config_file(conf_file)

        storage = storage.Storage()
        engine = engine.Engine()

        handler_context = {
            'loader': loader,
            'storage': storage,
            'engine': engine,
            'detectors': detectors,
            'filters': filters
        }

        handlers = [(r'/healthcheck', HealthcheckHandler)]

        if options.ALLOW_UNSAFE_URL:
            handlers.append((Url.regex(), MainHandler, handler_context), )

        if custom_handlers:
            for handler in custom_handlers:
                handlers.append((handler[0], handler[1], handler_context))
        else:
            handlers.append((r'/(?P<crypto>[^/]+)/(?P<image>(.+))',
                             EncryptedHandler, handler_context))

        super(ThumborServiceApp, self).__init__(handlers)
Exemplo n.º 57
0
    def __init__(self, context):
        self.context = context

        handlers = [
            (r'/healthcheck', HealthcheckHandler)
        ]

        if context.config.ALLOW_UNSAFE_URL:
            handlers.append(
                (Url.regex(), MainHandler, { 'context': context }),
            )

        handlers.append(
            (r'/(?P<crypto>[^/]+)/(?P<image>(?:.+))', CryptoHandler, { 'context': context })
        )

        super(ThumborServiceApp, self).__init__(handlers)
Exemplo n.º 58
0
    def get_handlers(self):
        handlers = [(r"/healthcheck", HealthcheckHandler)]

        if self.context.config.UPLOAD_ENABLED:
            # TODO Old handler to upload images
            handlers.append((r"/upload", UploadHandler, {"context": self.context}))

            # Handler to upload images (POST).
            handlers.append((r"/image", ImagesHandler, {"context": self.context}))

            # Handler to retrieve or modify existing images  (GET, PUT, DELETE)
            handlers.append((r"/image/(.*)", ImageHandler, {"context": self.context}))

        # Imaging handler (GET)
        handlers.append((Url.regex(), ImagingHandler, {"context": self.context}))

        return handlers
Exemplo n.º 59
0
    def decrypt(self, encrypted):
        cipher = AES.new(self.salt)

        debased = base64.urlsafe_b64decode(encrypted)
        decrypted = cipher.decrypt(debased).rstrip('{')

        if not decrypted or not urlparse.urlparse(decrypted):
            return None

        result = Url.parse('/%s' % decrypted, with_unsafe=False)
        if not result:
            return None

        result['image_hash'] = result['image']
        del result['image']

        return result
Exemplo n.º 60
0
    def get(self, **kw):
        hash = kw['hash']
        url = kw['image']
        unsafe = kw['unsafe']

        try:
            decrypted = decode_uri(url, self.cipher, is_decrypted=True)
        except Exception as e:
            logger = logging.getLogger(__name__)
            logger.error(u"GetError: %s" % str(e))
            return self.check_image(kw)
        kwargs = Url.parse_decrypted(decrypted)
        kwargs['hash'] = hash
        kwargs['unsafe'] = unsafe

        crop = kwargs.pop("crop", {})
        kwargs.update({"crop_{0}".format(key): crop[key] for key in ["bottom", "left", "right", "top"] if crop.has_key(key)})
        self.check_image(kwargs)