diff --git a/server/server.go b/server/server.go index 1c1950d1..975e2dac 100644 --- a/server/server.go +++ b/server/server.go @@ -131,7 +131,7 @@ const ( newMessageBody = "New message" // Used in poll requests as generic message defaultAttachmentMessage = "You received a file: %s" // Used if message body is empty, and there is an attachment encodingBase64 = "base64" // Used mainly for binary UnifiedPush messages - httpBodyBytesLimit = 32768 // Max number of bytes for a request bodys (unless MessageLimit is higher) + jsonBodyBytesLimit = 32768 // Max number of bytes for a request bodys (unless MessageLimit is higher) unifiedPushTopicPrefix = "up" // Temporarily, we rate limit all "up*" topics based on the subscriber unifiedPushTopicLength = 14 // Length of UnifiedPush topics, including the "up" part messagesHistoryMax = 10 // Number of message count values to keep in memory @@ -1047,7 +1047,7 @@ func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, fi // 6. curl -T file.txt ntfy.sh/mytopic // If file.txt is <= 4096 (message limit) and valid UTF-8, treat it as a message // 7. curl -T file.txt ntfy.sh/mytopic -// If file.txt is > message limit or template && file.txt > message limit*2, treat it as an attachment +// In all other cases, mostly if file.txt is > message limit, treat it as an attachment func (s *Server) handlePublishBody(r *http.Request, v *visitor, m *message, body *util.PeekedReadCloser, template, unifiedpush bool) error { if m.Event == pollRequestEvent { // Case 1 return s.handleBodyDiscard(body) @@ -1095,7 +1095,7 @@ func (s *Server) handleBodyAsTextMessage(m *message, body *util.PeekedReadCloser } func (s *Server) handleBodyAsTemplatedTextMessage(m *message, body *util.PeekedReadCloser) error { - body, err := util.Peek(body, httpBodyBytesLimit) + body, err := util.Peek(body, jsonBodyBytesLimit) if err != nil { return err } else if body.LimitReached { @@ -1113,6 +1113,16 @@ func (s *Server) handleBodyAsTemplatedTextMessage(m *message, body *util.PeekedR return nil } +func replaceGJSONTemplate(template string, source string) string { + matches := templateVarRegex.FindAllStringSubmatch(template, -1) + for _, m := range matches { + if result := gjson.Get(source, m[1]); result.Exists() { + template = strings.ReplaceAll(template, fmt.Sprintf(templateVarFormat, m[1]), result.String()) + } + } + return template +} + func (s *Server) handleBodyAsAttachment(r *http.Request, v *visitor, m *message, body *util.PeekedReadCloser) error { if s.fileCache == nil || s.config.BaseURL == "" || s.config.AttachmentCacheDir == "" { return errHTTPBadRequestAttachmentsDisallowed.With(m) @@ -1163,16 +1173,6 @@ func (s *Server) handleBodyAsAttachment(r *http.Request, v *visitor, m *message, return nil } -func replaceGJSONTemplate(template string, source string) string { - matches := templateVarRegex.FindAllStringSubmatch(template, -1) - for _, m := range matches { - if result := gjson.Get(source, m[1]); result.Exists() { - template = strings.ReplaceAll(template, fmt.Sprintf(templateVarFormat, m[1]), result.String()) - } - } - return template -} - func (s *Server) handleSubscribeJSON(w http.ResponseWriter, r *http.Request, v *visitor) error { encoder := func(msg *message) (string, error) { var buf bytes.Buffer diff --git a/server/server_account.go b/server/server_account.go index e457464d..cb841d07 100644 --- a/server/server_account.go +++ b/server/server_account.go @@ -28,7 +28,7 @@ func (s *Server) handleAccountCreate(w http.ResponseWriter, r *http.Request, v * return errHTTPTooManyRequestsLimitAccountCreation } } - newAccount, err := readJSONWithLimit[apiAccountCreateRequest](r.Body, httpBodyBytesLimit, false) + newAccount, err := readJSONWithLimit[apiAccountCreateRequest](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } @@ -160,7 +160,7 @@ func (s *Server) handleAccountGet(w http.ResponseWriter, r *http.Request, v *vis } func (s *Server) handleAccountDelete(w http.ResponseWriter, r *http.Request, v *visitor) error { - req, err := readJSONWithLimit[apiAccountDeleteRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiAccountDeleteRequest](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } else if req.Password == "" { @@ -192,7 +192,7 @@ func (s *Server) handleAccountDelete(w http.ResponseWriter, r *http.Request, v * } func (s *Server) handleAccountPasswordChange(w http.ResponseWriter, r *http.Request, v *visitor) error { - req, err := readJSONWithLimit[apiAccountPasswordChangeRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiAccountPasswordChangeRequest](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } else if req.Password == "" || req.NewPassword == "" { @@ -210,7 +210,7 @@ func (s *Server) handleAccountPasswordChange(w http.ResponseWriter, r *http.Requ } func (s *Server) handleAccountTokenCreate(w http.ResponseWriter, r *http.Request, v *visitor) error { - req, err := readJSONWithLimit[apiAccountTokenIssueRequest](r.Body, httpBodyBytesLimit, true) // Allow empty body! + req, err := readJSONWithLimit[apiAccountTokenIssueRequest](r.Body, jsonBodyBytesLimit, true) // Allow empty body! if err != nil { return err } @@ -246,7 +246,7 @@ func (s *Server) handleAccountTokenCreate(w http.ResponseWriter, r *http.Request func (s *Server) handleAccountTokenUpdate(w http.ResponseWriter, r *http.Request, v *visitor) error { u := v.User() - req, err := readJSONWithLimit[apiAccountTokenUpdateRequest](r.Body, httpBodyBytesLimit, true) // Allow empty body! + req, err := readJSONWithLimit[apiAccountTokenUpdateRequest](r.Body, jsonBodyBytesLimit, true) // Allow empty body! if err != nil { return err } else if req.Token == "" { @@ -302,7 +302,7 @@ func (s *Server) handleAccountTokenDelete(w http.ResponseWriter, r *http.Request } func (s *Server) handleAccountSettingsChange(w http.ResponseWriter, r *http.Request, v *visitor) error { - newPrefs, err := readJSONWithLimit[user.Prefs](r.Body, httpBodyBytesLimit, false) + newPrefs, err := readJSONWithLimit[user.Prefs](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } @@ -336,7 +336,7 @@ func (s *Server) handleAccountSettingsChange(w http.ResponseWriter, r *http.Requ } func (s *Server) handleAccountSubscriptionAdd(w http.ResponseWriter, r *http.Request, v *visitor) error { - newSubscription, err := readJSONWithLimit[user.Subscription](r.Body, httpBodyBytesLimit, false) + newSubscription, err := readJSONWithLimit[user.Subscription](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } @@ -359,7 +359,7 @@ func (s *Server) handleAccountSubscriptionAdd(w http.ResponseWriter, r *http.Req } func (s *Server) handleAccountSubscriptionChange(w http.ResponseWriter, r *http.Request, v *visitor) error { - updatedSubscription, err := readJSONWithLimit[user.Subscription](r.Body, httpBodyBytesLimit, false) + updatedSubscription, err := readJSONWithLimit[user.Subscription](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } @@ -417,7 +417,7 @@ func (s *Server) handleAccountSubscriptionDelete(w http.ResponseWriter, r *http. // it is already reserved by someone else. func (s *Server) handleAccountReservationAdd(w http.ResponseWriter, r *http.Request, v *visitor) error { u := v.User() - req, err := readJSONWithLimit[apiAccountReservationRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiAccountReservationRequest](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } @@ -532,7 +532,7 @@ func (s *Server) maybeRemoveMessagesAndExcessReservations(r *http.Request, v *vi func (s *Server) handleAccountPhoneNumberVerify(w http.ResponseWriter, r *http.Request, v *visitor) error { u := v.User() - req, err := readJSONWithLimit[apiAccountPhoneNumberVerifyRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiAccountPhoneNumberVerifyRequest](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } else if !phoneNumberRegex.MatchString(req.Number) { @@ -563,7 +563,7 @@ func (s *Server) handleAccountPhoneNumberVerify(w http.ResponseWriter, r *http.R func (s *Server) handleAccountPhoneNumberAdd(w http.ResponseWriter, r *http.Request, v *visitor) error { u := v.User() - req, err := readJSONWithLimit[apiAccountPhoneNumberAddRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiAccountPhoneNumberAddRequest](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } @@ -582,7 +582,7 @@ func (s *Server) handleAccountPhoneNumberAdd(w http.ResponseWriter, r *http.Requ func (s *Server) handleAccountPhoneNumberDelete(w http.ResponseWriter, r *http.Request, v *visitor) error { u := v.User() - req, err := readJSONWithLimit[apiAccountPhoneNumberAddRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiAccountPhoneNumberAddRequest](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } diff --git a/server/server_admin.go b/server/server_admin.go index ec0b69b6..ac295718 100644 --- a/server/server_admin.go +++ b/server/server_admin.go @@ -39,7 +39,7 @@ func (s *Server) handleUsersGet(w http.ResponseWriter, r *http.Request, v *visit } func (s *Server) handleUsersAdd(w http.ResponseWriter, r *http.Request, v *visitor) error { - req, err := readJSONWithLimit[apiUserAddRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiUserAddRequest](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } else if !user.AllowedUsername(req.Username) || req.Password == "" { @@ -72,7 +72,7 @@ func (s *Server) handleUsersAdd(w http.ResponseWriter, r *http.Request, v *visit } func (s *Server) handleUsersDelete(w http.ResponseWriter, r *http.Request, v *visitor) error { - req, err := readJSONWithLimit[apiUserDeleteRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiUserDeleteRequest](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } @@ -94,7 +94,7 @@ func (s *Server) handleUsersDelete(w http.ResponseWriter, r *http.Request, v *vi } func (s *Server) handleAccessAllow(w http.ResponseWriter, r *http.Request, v *visitor) error { - req, err := readJSONWithLimit[apiAccessAllowRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiAccessAllowRequest](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } @@ -115,7 +115,7 @@ func (s *Server) handleAccessAllow(w http.ResponseWriter, r *http.Request, v *vi } func (s *Server) handleAccessReset(w http.ResponseWriter, r *http.Request, v *visitor) error { - req, err := readJSONWithLimit[apiAccessResetRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiAccessResetRequest](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } diff --git a/server/server_payments.go b/server/server_payments.go index 2fb42d31..334301bb 100644 --- a/server/server_payments.go +++ b/server/server_payments.go @@ -115,7 +115,7 @@ func (s *Server) handleAccountBillingSubscriptionCreate(w http.ResponseWriter, r if u.Billing.StripeSubscriptionID != "" { return errHTTPBadRequestBillingSubscriptionExists } - req, err := readJSONWithLimit[apiAccountBillingSubscriptionChangeRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiAccountBillingSubscriptionChangeRequest](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } @@ -245,7 +245,7 @@ func (s *Server) handleAccountBillingSubscriptionUpdate(w http.ResponseWriter, r if u.Billing.StripeSubscriptionID == "" { return errNoBillingSubscription } - req, err := readJSONWithLimit[apiAccountBillingSubscriptionChangeRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiAccountBillingSubscriptionChangeRequest](r.Body, jsonBodyBytesLimit, false) if err != nil { return err } @@ -342,7 +342,7 @@ func (s *Server) handleAccountBillingWebhook(_ http.ResponseWriter, r *http.Requ if stripeSignature == "" { return errHTTPBadRequestBillingRequestInvalid } - body, err := util.Peek(r.Body, httpBodyBytesLimit) + body, err := util.Peek(r.Body, jsonBodyBytesLimit) if err != nil { return err } else if body.LimitReached { diff --git a/server/server_webpush.go b/server/server_webpush.go index cf4929a9..cd41759d 100644 --- a/server/server_webpush.go +++ b/server/server_webpush.go @@ -38,7 +38,7 @@ func init() { } func (s *Server) handleWebPushUpdate(w http.ResponseWriter, r *http.Request, v *visitor) error { - req, err := readJSONWithLimit[apiWebPushUpdateSubscriptionRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiWebPushUpdateSubscriptionRequest](r.Body, jsonBodyBytesLimit, false) if err != nil || req.Endpoint == "" || req.P256dh == "" || req.Auth == "" { return errHTTPBadRequestWebPushSubscriptionInvalid } else if !webPushAllowedEndpointsRegex.MatchString(req.Endpoint) { @@ -66,7 +66,7 @@ func (s *Server) handleWebPushUpdate(w http.ResponseWriter, r *http.Request, v * } func (s *Server) handleWebPushDelete(w http.ResponseWriter, r *http.Request, _ *visitor) error { - req, err := readJSONWithLimit[apiWebPushUpdateSubscriptionRequest](r.Body, httpBodyBytesLimit, false) + req, err := readJSONWithLimit[apiWebPushUpdateSubscriptionRequest](r.Body, jsonBodyBytesLimit, false) if err != nil || req.Endpoint == "" { return errHTTPBadRequestWebPushSubscriptionInvalid }