From 8cbb62070e3ae29c402a042aca5198ba1bb1ce9d Mon Sep 17 00:00:00 2001 From: Ringo Hoffmann Date: Sun, 23 May 2021 20:55:16 +0200 Subject: [PATCH] Add content length cap for paste creation endpoint (#8) * add content length cap * add development docker compose stack * Fix paste creation error notification data * Add length cap to hastebin endpoint as well * Mention length cap in Readme Co-authored-by: Lukas Schulte Pelkum --- README.md | 1 + docker-compose.dev.yml | 16 ++++++++++++++++ internal/config/config.go | 2 ++ internal/web/controllers/v1/hastebin_support.go | 8 ++++++++ internal/web/controllers/v1/pastes.go | 8 ++++++++ web/assets/js/buttons.js | 2 +- 6 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 docker-compose.dev.yml diff --git a/README.md b/README.md index 52f3d30..67be1f2 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ Pasty will be available at http://localhost:8080. | `PASTY_DELETION_TOKEN_MASTER` | `` | `string` | Defines the master deletion token which is authorized to delete every paste (even if deletion tokens are disabled) | | `PASTY_DELETION_TOKEN_LENGTH` | `12` | `number` | Defines the length of the deletion token of a paste | | `PASTY_RATE_LIMIT` | `30-M` | `string` | Defines the rate limit of the API (see https://github.com/ulule/limiter#usage) | +| `PASTY_LENGTH_CAP` | `50000` | `number` | Defines the maximum amount of characters a paste is allowed to contain (a value `<= 0` means no limit) | ## AutoDelete Pasty provides an intuitive system to automatically delete pastes after a specific amount of time. You can configure it with the following variables: diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..e0fd785 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,16 @@ +version: "3" + +volumes: + postgres: + +services: + postgres: + image: "postgres:12-alpine" + ports: + - "5432:5432" + volumes: + - "postgres:/var/lib/postgresql/data" + environment: + POSTGRES_PASSWORD: "dev" + POSTGRES_USER: "dev" + POSTGRES_DB: "pasty" diff --git a/internal/config/config.go b/internal/config/config.go index 152daf3..a24999c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -18,6 +18,7 @@ type Config struct { DeletionTokenMaster string DeletionTokenLength int RateLimit string + LengthCap int AutoDelete *AutoDeleteConfig File *FileConfig Postgres *PostgresConfig @@ -76,6 +77,7 @@ func Load() { DeletionTokenMaster: env.MustString("DELETION_TOKEN_MASTER", ""), DeletionTokenLength: env.MustInt("DELETION_TOKEN_LENGTH", 12), RateLimit: env.MustString("RATE_LIMIT", "30-M"), + LengthCap: env.MustInt("LENGTH_CAP", 50_000), AutoDelete: &AutoDeleteConfig{ Enabled: env.MustBool("AUTODELETE", false), Lifetime: env.MustDuration("AUTODELETE_LIFETIME", 720*time.Hour), diff --git a/internal/web/controllers/v1/hastebin_support.go b/internal/web/controllers/v1/hastebin_support.go index 1fc76bc..e5c8283 100644 --- a/internal/web/controllers/v1/hastebin_support.go +++ b/internal/web/controllers/v1/hastebin_support.go @@ -13,6 +13,14 @@ import ( // HastebinSupportHandler handles the legacy hastebin requests func HastebinSupportHandler(ctx *fasthttp.RequestCtx) { + // Check content length before reading body into memory + if config.Current.LengthCap > 0 && + ctx.Request.Header.ContentLength() > config.Current.LengthCap { + ctx.SetStatusCode(fasthttp.StatusBadRequest) + ctx.SetBodyString("request body length overflow") + return + } + // Define the paste content var content string switch string(ctx.Request.Header.ContentType()) { diff --git a/internal/web/controllers/v1/pastes.go b/internal/web/controllers/v1/pastes.go index be95365..ab47448 100644 --- a/internal/web/controllers/v1/pastes.go +++ b/internal/web/controllers/v1/pastes.go @@ -51,6 +51,14 @@ func v1GetPaste(ctx *fasthttp.RequestCtx) { // v1PostPaste handles the 'POST /v1/pastes' endpoint func v1PostPaste(ctx *fasthttp.RequestCtx) { + // Check content length before reading body into memory + if config.Current.LengthCap > 0 && + ctx.Request.Header.ContentLength() > config.Current.LengthCap { + ctx.SetStatusCode(fasthttp.StatusBadRequest) + ctx.SetBodyString("request body length overflow") + return + } + // Unmarshal the body values := make(map[string]string) err := json.Unmarshal(ctx.PostBody(), &values) diff --git a/web/assets/js/buttons.js b/web/assets/js/buttons.js index cfff1ff..682da61 100644 --- a/web/assets/js/buttons.js +++ b/web/assets/js/buttons.js @@ -57,7 +57,7 @@ export function setupButtons() { // Create the paste const response = await api.createPaste(input.value); if (!response.ok) { - notifications.error("Failed creating the paste: " + data + ""); + notifications.error("Failed creating the paste: " + await response.text() + ""); return; } const data = await response.json();