Ejemplo 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)
Ejemplo n.º 2
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
Ejemplo n.º 3
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,
            auth=
            "requester(CVZzFCbz4Rcf2Lmu9mvtC1CmvPukHy5kS2LNtNaBFM2N):contract(Du2kswW2h1gNVnTWdfNdSxBrC2F9ofoaZsXA6ki1PhG6):document(profile):field(avatarURL):owner(8vagK6r9BnYct3k8WWYXNFadY1hG8TjikR3SfXceFnRQ):updatedAt(1602042152761)",
            filters="brightness(100)",
        )

        expect(url).to_equal(
            "debug/meta/trim/100x100:400x400/adaptive-full-fit-in/-300x-200/left/top/smart/auth:requester(CVZzFCbz4Rcf2Lmu9mvtC1CmvPukHy5kS2LNtNaBFM2N):contract(Du2kswW2h1gNVnTWdfNdSxBrC2F9ofoaZsXA6ki1PhG6):document(profile):field(avatarURL):owner(8vagK6r9BnYct3k8WWYXNFadY1hG8TjikR3SfXceFnRQ):updatedAt(1602042152761)/filters:brightness(100)"
        )
Ejemplo n.º 4
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
Ejemplo n.º 5
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)

            # 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), _unquote_or_none(v))
                                  for (k, v) in match.groupdict().items())
            else:
                parameters = [_unquote_or_none(s) for s in match.groups()]
        else:
            parameters = dict()

        return parameters
Ejemplo n.º 6
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
Ejemplo n.º 7
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)"
        )
Ejemplo n.º 8
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)"
        )
Ejemplo n.º 9
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)
        encrypted = base64.urlsafe_b64encode(
            cipher.encrypt(pad(url.encode('utf-8'))))

        return encrypted
Ejemplo n.º 10
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)

            # 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
    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()
Ejemplo n.º 12
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()
    async 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
Ejemplo n.º 13
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())
Ejemplo n.º 14
0
    def test_can_get_handlers(self):
        ctx = self.get_context()
        ctx.config.UPLOAD_ENABLED = False
        ctx.config.USE_BLACKLIST = False
        ctx.config.HEALTHCHECK_ROUTE = "/health"
        app = ThumborServiceApp(ctx)

        handlers = app.get_handlers()
        expect(handlers).to_length(2)
        expect(handlers[0][0]).to_equal(r"/health")
        expect(handlers[1][0]).to_equal(Url.regex())
Ejemplo n.º 15
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>.+)'
        )
Ejemplo n.º 16
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>.+)"
        )
Ejemplo n.º 17
0
    def get_handlers(self):
        handlers = []
        for handler_list in self.context.modules.importer.handler_lists:
            get_handlers = getattr(handler_list, 'get_handlers', None)
            if get_handlers is None:
                continue
            handlers.extend(get_handlers(self.context))

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

        return handlers
Ejemplo n.º 18
0
    def test_parsing_complete_url(self):
        url = (
            "/debug/meta/trim/300x200:400x500/adaptive-full-fit-in/-300x-400/"
            "left/top/smart/auth:requester(CVZzFCbz4Rcf2Lmu9mvtC1CmvPukHy5kS2LNtNaBFM2N):contract(Du2kswW2h1gNVnTWdfNdSxBrC2F9ofoaZsXA6ki1PhG6):document(profile):field(avatarURL):owner(8vagK6r9BnYct3k8WWYXNFadY1hG8TjikR3SfXceFnRQ):updatedAt(1602042152761)/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,
            "auth":
            "requester(CVZzFCbz4Rcf2Lmu9mvtC1CmvPukHy5kS2LNtNaBFM2N):contract(Du2kswW2h1gNVnTWdfNdSxBrC2F9ofoaZsXA6ki1PhG6):document(profile):field(avatarURL):owner(8vagK6r9BnYct3k8WWYXNFadY1hG8TjikR3SfXceFnRQ):updatedAt(1602042152761)",
            "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)
Ejemplo n.º 19
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())
Ejemplo n.º 20
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)
Ejemplo n.º 21
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
Ejemplo n.º 22
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)
Ejemplo n.º 23
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
Ejemplo n.º 24
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)
        encrypted = base64.urlsafe_b64encode(cipher.encrypt(pad(url.encode('utf-8'))))

        return encrypted
Ejemplo n.º 25
0
    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)'
        )
Ejemplo n.º 26
0
    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')
Ejemplo n.º 27
0
    def test_can_generate_url_with_defaults(self):
        url = Url.generate_options()

        expect(url).to_be_empty()
Ejemplo n.º 28
0
    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 check_image(self, kw):
     result = re.match(Url.regex(), kw['request'])
     return super(CoreHandler, self).check_image(result.groupdict())
Ejemplo n.º 30
0
    def test_parsing_invalid_url(self):
        expect(Url.compiled_regex).to_be_null()

        url = ""
        expect(Url.parse_decrypted(url)).to_be_null()
Ejemplo n.º 31
0
    def test_can_generate_url_with_defaults(self):
        url = Url.generate_options()

        expect(url).to_be_empty()
Ejemplo n.º 32
0
    def test_parsing_invalid_url(self):
        expect(Url.compiled_regex).to_be_null()

        url = ""
        expect(Url.parse_decrypted(url)).to_be_null()