Example #1
0
    def post(self) -> None:  # type: ignore
        """POST handler for the 'web' side of things."""

        expiry = self.get_body_argument("expiry")

        if expiry not in utility.expiries:
            log.info(
                "CreateAction.post: a paste was submitted with an invalid expiry"
            )
            raise error.ValidationError()

        auto_scale = self.get_body_argument("long", None) is None

        lexers = self.get_body_arguments("lexer")
        raws = self.get_body_arguments("raw", strip=False)
        filenames = self.get_body_arguments("filename")

        if not all([lexers, raws, filenames]):
            # Prevent empty argument lists from making it through
            raise error.ValidationError()

        if not all(raw.strip() for raw in raws):
            # Prevent empty raws from making it through
            raise error.ValidationError()

        with database.session() as session:
            paste = database.Paste(utility.expiries[expiry], "web", auto_scale)

            if any(len(L) != len(lexers) for L in [lexers, raws, filenames]):
                log.info("CreateAction.post: mismatching argument lists")
                raise error.ValidationError()

            for (lexer, raw, filename) in zip(lexers, raws, filenames):
                if lexer == 'AUTO':
                    try:
                        lexer = guess_lexer(raw).name
                    except ValueError:
                        # Fall back to plain text
                        lexer = "text"

                if lexer not in utility.list_languages():
                    log.info("CreateAction.post: a file had an invalid lexer")
                    raise error.ValidationError()

                if not raw:
                    log.info("CreateAction.post: a file had an empty raw")
                    raise error.ValidationError()

                paste.files.append(
                    database.File(raw, lexer, filename if filename else None,
                                  auto_scale))

            # For the first file we will always use the same slug as the paste,
            # since slugs are generated to be unique over both pastes and files
            # this can be done safely.
            paste.files[0].slug = paste.slug

            session.add(paste)
            session.commit()

            # The removal cookie is set for the specific path of the paste it is
            # related to
            self.set_cookie("removal",
                            str(paste.removal),
                            path=f"/{paste.slug}")

            # Send the client to the paste
            self.redirect(f"/{paste.slug}")
Example #2
0
 async def get(self) -> None:
     self.write(utility.list_languages())
Example #3
0
    def test_api_get_lexers(self) -> None:
        response = self.fetch("/json/lexers", method="GET")

        assert response.code == 200
        assert json.loads(response.body) == utility.list_languages()
Example #4
0
    async def post(self) -> None:
        if defensive.ratelimit(self.request, area="create"):
            raise error.RatelimitError()

        try:
            data = tornado.escape.json_decode(self.request.body)
        except json.decoder.JSONDecodeError:
            raise tornado.web.HTTPError(400, "could not parse json body")

        expiry = data.get("expiry")

        if expiry not in configuration.expiries:
            log.info(
                "Paste.post: a paste was submitted with an invalid expiry")
            raise tornado.web.HTTPError(400, "invalid expiry")

        auto_scale = data.get("long", None) is None

        files = data.get("files", [])

        if not files:
            raise tornado.web.HTTPError(400, "no files provided")

        with database.session() as session, utility.SlugContext(
                auto_scale) as slug_context:
            paste = database.Paste(
                next(slug_context),
                configuration.expiries[expiry],
                "v1-api",
            )

            for file in files:
                lexer = file.get("lexer", "")
                content = file.get("content")
                filename = file.get("name")

                if lexer not in utility.list_languages():
                    raise tornado.web.HTTPError(400, "invalid lexer")

                if not content:
                    raise tornado.web.HTTPError(400, "invalid content (empty)")

                try:
                    paste.files.append(
                        database.File(
                            next(slug_context),
                            content,
                            lexer,
                            filename,
                        ))
                except error.ValidationError:
                    raise tornado.web.HTTPError(
                        400, "invalid content (exceeds size limit)")

            if sum(len(f.fmt) for f in paste.files) > configuration.paste_size:
                raise tornado.web.HTTPError(
                    400, "invalid content (exceeds size limit)")

            paste.files[0].slug = paste.slug

            session.add(paste)

            try:
                session.commit()
            except Exception:  # XXX be more precise
                log.warning("%r", slug_context._slugs)
                raise

            # Send the client to the paste
            url_request = self.request.full_url()
            url_paste = urljoin(url_request, f"/{paste.slug}")
            url_removal = urljoin(url_request, f"/remove/{paste.removal}")

            self.write({"link": url_paste, "removal": url_removal})
Example #5
0
    async def get(self) -> None:
        if defensive.ratelimit(self.request, area="read"):
            raise error.RatelimitError()

        self.write(utility.list_languages())
Example #6
0
    def post(self) -> None:  # type: ignore
        """POST handler for the 'web' side of things."""

        expiry = self.get_body_argument("expiry")

        if expiry not in configuration.expiries:
            log.info(
                "CreateAction.post: a paste was submitted with an invalid expiry"
            )
            raise error.ValidationError()

        auto_scale = self.get_body_argument("long", None) is None

        lexers = self.get_body_arguments("lexer")
        raws = self.get_body_arguments("raw", strip=False)
        filenames = self.get_body_arguments("filename")

        if not all([lexers, raws, filenames]):
            # Prevent empty argument lists from making it through
            raise error.ValidationError()

        if not all(raw.strip() for raw in raws):
            # Prevent empty raws from making it through
            raise error.ValidationError()

        if any(len(L) != len(lexers) for L in [lexers, raws, filenames]):
            log.info("CreateAction.post: mismatching argument lists")
            raise error.ValidationError()

        if any(lexer not in utility.list_languages() for lexer in lexers):
            log.info("CreateAction.post: a file had an invalid lexer")
            raise error.ValidationError()

        with database.session() as session, utility.SlugContext(
            auto_scale
        ) as slug_context:
            paste = database.Paste(
                next(slug_context), configuration.expiries[expiry], "web"
            )

            for (lexer, raw, filename) in zip(lexers, raws, filenames):
                paste.files.append(
                    database.File(
                        next(slug_context),
                        raw,
                        lexer,
                        filename if filename else None,
                    )
                )

            if sum(len(f.fmt) for f in paste.files) > configuration.paste_size:
                log.info("CreateAction.post: sum of files was too large")
                raise error.ValidationError()

            # For the first file we will always use the same slug as the paste,
            # since slugs are generated to be unique over both pastes and files
            # this can be done safely.
            paste.files[0].slug = paste.slug

            session.add(paste)
            session.commit()

            # The removal cookie is set for the specific path of the paste it is
            # related to
            self.set_cookie(
                "removal", str(paste.removal), path=f"/{paste.slug}"
            )

            # Send the client to the paste
            self.redirect(f"/{paste.slug}")