diff --git a/server/errors.go b/server/errors.go index 695da85..0c85f56 100644 --- a/server/errors.go +++ b/server/errors.go @@ -40,14 +40,16 @@ var ( errHTTPBadRequestAttachmentsExpiryBeforeDelivery = &errHTTP{40015, http.StatusBadRequest, "invalid request: attachment expiry before delayed delivery date", "https://ntfy.sh/docs/publish/#scheduled-delivery"} errHTTPBadRequestWebSocketsUpgradeHeaderMissing = &errHTTP{40016, http.StatusBadRequest, "invalid request: client not using the websocket protocol", "https://ntfy.sh/docs/subscribe/api/#websockets"} errHTTPBadRequestJSONInvalid = &errHTTP{40017, http.StatusBadRequest, "invalid request: request body must be message JSON", "https://ntfy.sh/docs/publish/#publish-as-json"} - errHTTPNotFound = &errHTTP{40401, http.StatusNotFound, "page not found", ""} + errHTTPNotFound = &errHTTP{40401, http.StatusNotFound, "not found", ""} + errHTTPNotFoundMessageID = &errHTTP{40402, http.StatusNotFound, "not found: unable to find message with this ID", "https://ntfy.sh/docs/publish/#updating-messages"} // FIXME LINK errHTTPUnauthorized = &errHTTP{40101, http.StatusUnauthorized, "unauthorized", "https://ntfy.sh/docs/publish/#authentication"} errHTTPForbidden = &errHTTP{40301, http.StatusForbidden, "forbidden", "https://ntfy.sh/docs/publish/#authentication"} errHTTPTooManyRequestsLimitRequests = &errHTTP{42901, http.StatusTooManyRequests, "limit reached: too many requests, please be nice", "https://ntfy.sh/docs/publish/#limitations"} errHTTPTooManyRequestsLimitEmails = &errHTTP{42902, http.StatusTooManyRequests, "limit reached: too many emails, please be nice", "https://ntfy.sh/docs/publish/#limitations"} errHTTPTooManyRequestsLimitSubscriptions = &errHTTP{42903, http.StatusTooManyRequests, "limit reached: too many active subscriptions, please be nice", "https://ntfy.sh/docs/publish/#limitations"} errHTTPTooManyRequestsLimitTotalTopics = &errHTTP{42904, http.StatusTooManyRequests, "limit reached: the total number of topics on the server has been reached, please contact the admin", "https://ntfy.sh/docs/publish/#limitations"} - errHTTPTooManyRequestsAttachmentBandwidthLimit = &errHTTP{42905, http.StatusTooManyRequests, "too many requests: daily bandwidth limit reached", "https://ntfy.sh/docs/publish/#limitations"} + errHTTPTooManyRequestsAttachmentBandwidthLimit = &errHTTP{42905, http.StatusTooManyRequests, "limit reached: daily bandwidth limit reached, please be nice", "https://ntfy.sh/docs/publish/#limitations"} + errHTTPTooManyRequestsUpdatingTooQuickly = &errHTTP{42906, http.StatusTooManyRequests, "limit reached: too many consecutive message updates", "https://ntfy.sh/docs/publish/#updating-messages"} // FIXME LINK errHTTPInternalError = &errHTTP{50001, http.StatusInternalServerError, "internal server error", ""} errHTTPInternalErrorInvalidFilePath = &errHTTP{50002, http.StatusInternalServerError, "internal server error: invalid file path", ""} ) diff --git a/server/server.go b/server/server.go index 0347e26..0ef6d89 100644 --- a/server/server.go +++ b/server/server.go @@ -395,14 +395,18 @@ func (s *Server) handlePublish(w http.ResponseWriter, r *http.Request, v *visito if err != nil { return err } - updated := messageID != "" var m *message - if updated { + update := messageID != "" + if update { m, err = s.messageCache.Message(t.ID, messageID) if err != nil { - return err //errors.New("message does not exist") + return errHTTPNotFoundMessageID } - m.Updated = time.Now().Unix() + newUpdated := time.Now().Unix() + if newUpdated <= m.Updated { + return errHTTPTooManyRequestsUpdatingTooQuickly + } + m.Updated = newUpdated } else { m = newDefaultMessage(t.ID, "") } @@ -441,7 +445,7 @@ func (s *Server) handlePublish(w http.ResponseWriter, r *http.Request, v *visito }() } if cache { - if updated { + if update { if err := s.messageCache.UpdateMessage(m); err != nil { return err } diff --git a/server/server_firebase.go b/server/server_firebase.go index 827fec4..58d94c2 100644 --- a/server/server_firebase.go +++ b/server/server_firebase.go @@ -72,6 +72,7 @@ func toFirebaseMessage(m *message, auther auth.Auther) (*messaging.Message, erro data = map[string]string{ "id": m.ID, "time": fmt.Sprintf("%d", m.Time), + "updated": fmt.Sprintf("%d", m.Updated), "event": m.Event, "topic": m.Topic, "priority": fmt.Sprintf("%d", m.Priority), diff --git a/server/types.go b/server/types.go index d003df2..0ab357f 100644 --- a/server/types.go +++ b/server/types.go @@ -20,9 +20,11 @@ const ( // message represents a message published to a topic type message struct { - ID string `json:"id"` // Random message ID - Time int64 `json:"time"` // Unix time in seconds - Event string `json:"event"` // One of the above + ID string `json:"id"` // Random message ID + Time int64 `json:"time"` // Unix time in seconds + Updated int64 `json:"updated,omitempty"` // Set if updated, unix time in seconds + Deleted int64 `json:"deleted,omitempty"` // Set if deleted, unix time in seconds + Event string `json:"event"` // One of the above Topic string `json:"topic"` Priority int `json:"priority,omitempty"` Tags []string `json:"tags,omitempty"` @@ -31,8 +33,6 @@ type message struct { Title string `json:"title,omitempty"` Message string `json:"message,omitempty"` Encoding string `json:"encoding,omitempty"` // Empty for raw UTF-8, or "base64" for encoded bytes - Updated int64 `json:"updated,omitempty"` // Set if updated, unix time in seconds - Deleted int64 `json:"deleted,omitempty"` // Set if deleted, unix time in seconds } type attachment struct {