ntfy/server/types.go

168 lines
4.2 KiB
Go
Raw Normal View History

package server
2021-10-29 20:58:14 +03:00
import (
"heckel.io/ntfy/util"
2022-01-16 07:17:46 +03:00
"net/http"
2021-10-29 20:58:14 +03:00
"time"
)
// List of possible events
const (
openEvent = "open"
keepaliveEvent = "keepalive"
messageEvent = "message"
pollRequestEvent = "poll_request"
2021-10-29 20:58:14 +03:00
)
const (
2022-02-26 23:57:10 +03:00
messageIDLength = 12
)
// message represents a message published to a topic
type message struct {
2022-01-03 01:56:12 +03:00
ID string `json:"id"` // Random message ID
Time int64 `json:"time"` // 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"`
2022-01-05 02:25:49 +03:00
Click string `json:"click,omitempty"`
Attachment *attachment `json:"attachment,omitempty"`
2022-01-03 01:56:12 +03:00
Title string `json:"title,omitempty"`
Message string `json:"message,omitempty"`
2022-01-17 21:28:07 +03:00
Encoding string `json:"encoding,omitempty"` // empty for raw UTF-8, or "base64" for encoded bytes
2022-01-03 01:56:12 +03:00
}
type attachment struct {
Name string `json:"name"`
Type string `json:"type,omitempty"`
Size int64 `json:"size,omitempty"`
Expires int64 `json:"expires,omitempty"`
URL string `json:"url"`
Owner string `json:"-"` // IP address of uploader, used for rate limiting
}
// messageEncoder is a function that knows how to encode a message
type messageEncoder func(msg *message) (string, error)
// newMessage creates a new message with the current timestamp
2021-10-29 20:58:14 +03:00
func newMessage(event, topic, msg string) *message {
return &message{
2021-11-28 00:12:08 +03:00
ID: util.RandomString(messageIDLength),
Time: time.Now().Unix(),
Event: event,
Topic: topic,
Priority: 0,
Tags: nil,
Title: "",
Message: msg,
}
}
// newOpenMessage is a convenience method to create an open message
2021-10-29 20:58:14 +03:00
func newOpenMessage(topic string) *message {
return newMessage(openEvent, topic, "")
}
// newKeepaliveMessage is a convenience method to create a keepalive message
2021-10-29 20:58:14 +03:00
func newKeepaliveMessage(topic string) *message {
return newMessage(keepaliveEvent, topic, "")
}
// newDefaultMessage is a convenience method to create a notification message
2021-10-29 20:58:14 +03:00
func newDefaultMessage(topic, msg string) *message {
return newMessage(messageEvent, topic, msg)
}
2022-01-16 07:17:46 +03:00
2022-02-26 23:57:10 +03:00
func validMessageID(s string) bool {
return util.ValidRandomString(s, messageIDLength)
}
type sinceMarker struct {
time time.Time
id string
}
2022-01-16 07:17:46 +03:00
2022-02-26 23:57:10 +03:00
func newSinceTime(timestamp int64) sinceMarker {
return sinceMarker{time.Unix(timestamp, 0), ""}
}
func newSinceID(id string) sinceMarker {
return sinceMarker{time.Unix(0, 0), id}
}
func (t sinceMarker) IsAll() bool {
2022-01-16 07:17:46 +03:00
return t == sinceAllMessages
}
2022-02-26 23:57:10 +03:00
func (t sinceMarker) IsNone() bool {
2022-01-16 07:17:46 +03:00
return t == sinceNoMessages
}
2022-02-26 23:57:10 +03:00
func (t sinceMarker) IsID() bool {
return t.id != ""
}
func (t sinceMarker) Time() time.Time {
return t.time
}
func (t sinceMarker) ID() string {
return t.id
2022-01-16 07:17:46 +03:00
}
var (
2022-02-26 23:57:10 +03:00
sinceAllMessages = sinceMarker{time.Unix(0, 0), ""}
sinceNoMessages = sinceMarker{time.Unix(1, 0), ""}
2022-01-16 07:17:46 +03:00
)
type queryFilter struct {
Message string
Title string
Tags []string
Priority []int
}
func parseQueryFilters(r *http.Request) (*queryFilter, error) {
messageFilter := readParam(r, "x-message", "message", "m")
titleFilter := readParam(r, "x-title", "title", "t")
tagsFilter := util.SplitNoEmpty(readParam(r, "x-tags", "tags", "tag", "ta"), ",")
priorityFilter := make([]int, 0)
for _, p := range util.SplitNoEmpty(readParam(r, "x-priority", "priority", "prio", "p"), ",") {
priority, err := util.ParsePriority(p)
if err != nil {
return nil, err
}
priorityFilter = append(priorityFilter, priority)
}
return &queryFilter{
Message: messageFilter,
Title: titleFilter,
Tags: tagsFilter,
Priority: priorityFilter,
}, nil
}
func (q *queryFilter) Pass(msg *message) bool {
if msg.Event != messageEvent {
return true // filters only apply to messages
}
if q.Message != "" && msg.Message != q.Message {
return false
}
if q.Title != "" && msg.Title != q.Title {
return false
}
messagePriority := msg.Priority
if messagePriority == 0 {
messagePriority = 3 // For query filters, default priority (3) is the same as "not set" (0)
}
if len(q.Priority) > 0 && !util.InIntList(q.Priority, messagePriority) {
return false
}
if len(q.Tags) > 0 && !util.InStringListAll(msg.Tags, q.Tags) {
return false
}
return true
}