Store Sender IP in DB for delayed messages

This commit is contained in:
Philipp Heckel 2022-05-31 21:39:19 -04:00
parent 8283b6be97
commit f9284a098a
7 changed files with 73 additions and 42 deletions

View file

@ -67,7 +67,7 @@ type Config struct {
KeepaliveInterval time.Duration KeepaliveInterval time.Duration
ManagerInterval time.Duration ManagerInterval time.Duration
WebRootIsApp bool WebRootIsApp bool
AtSenderInterval time.Duration DelayedSenderInterval time.Duration
FirebaseKeepaliveInterval time.Duration FirebaseKeepaliveInterval time.Duration
FirebasePollInterval time.Duration FirebasePollInterval time.Duration
FirebaseQuotaLimitPenaltyDuration time.Duration FirebaseQuotaLimitPenaltyDuration time.Duration
@ -120,7 +120,7 @@ func NewConfig() *Config {
MessageLimit: DefaultMessageLengthLimit, MessageLimit: DefaultMessageLengthLimit,
MinDelay: DefaultMinDelay, MinDelay: DefaultMinDelay,
MaxDelay: DefaultMaxDelay, MaxDelay: DefaultMaxDelay,
AtSenderInterval: DefaultAtSenderInterval, DelayedSenderInterval: DefaultAtSenderInterval,
FirebaseKeepaliveInterval: DefaultFirebaseKeepaliveInterval, FirebaseKeepaliveInterval: DefaultFirebaseKeepaliveInterval,
FirebasePollInterval: DefaultFirebasePollInterval, FirebasePollInterval: DefaultFirebasePollInterval,
FirebaseQuotaLimitPenaltyDuration: DefaultFirebaseQuotaLimitPenaltyDuration, FirebaseQuotaLimitPenaltyDuration: DefaultFirebaseQuotaLimitPenaltyDuration,

View file

@ -36,7 +36,7 @@ const (
attachment_size INT NOT NULL, attachment_size INT NOT NULL,
attachment_expires INT NOT NULL, attachment_expires INT NOT NULL,
attachment_url TEXT NOT NULL, attachment_url TEXT NOT NULL,
attachment_owner TEXT NOT NULL, sender TEXT NOT NULL,
encoding TEXT NOT NULL, encoding TEXT NOT NULL,
published INT NOT NULL published INT NOT NULL
); );
@ -45,37 +45,37 @@ const (
COMMIT; COMMIT;
` `
insertMessageQuery = ` insertMessageQuery = `
INSERT INTO messages (mid, time, topic, message, title, priority, tags, click, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, attachment_owner, encoding, published) INSERT INTO messages (mid, time, topic, message, title, priority, tags, click, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding, published)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
` `
pruneMessagesQuery = `DELETE FROM messages WHERE time < ? AND published = 1` pruneMessagesQuery = `DELETE FROM messages WHERE time < ? AND published = 1`
selectRowIDFromMessageID = `SELECT id FROM messages WHERE topic = ? AND mid = ?` selectRowIDFromMessageID = `SELECT id FROM messages WHERE topic = ? AND mid = ?`
selectMessagesSinceTimeQuery = ` selectMessagesSinceTimeQuery = `
SELECT mid, time, topic, message, title, priority, tags, click, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, attachment_owner, encoding SELECT mid, time, topic, message, title, priority, tags, click, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding
FROM messages FROM messages
WHERE topic = ? AND time >= ? AND published = 1 WHERE topic = ? AND time >= ? AND published = 1
ORDER BY time, id ORDER BY time, id
` `
selectMessagesSinceTimeIncludeScheduledQuery = ` selectMessagesSinceTimeIncludeScheduledQuery = `
SELECT mid, time, topic, message, title, priority, tags, click, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, attachment_owner, encoding SELECT mid, time, topic, message, title, priority, tags, click, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding
FROM messages FROM messages
WHERE topic = ? AND time >= ? WHERE topic = ? AND time >= ?
ORDER BY time, id ORDER BY time, id
` `
selectMessagesSinceIDQuery = ` selectMessagesSinceIDQuery = `
SELECT mid, time, topic, message, title, priority, tags, click, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, attachment_owner, encoding SELECT mid, time, topic, message, title, priority, tags, click, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding
FROM messages FROM messages
WHERE topic = ? AND id > ? AND published = 1 WHERE topic = ? AND id > ? AND published = 1
ORDER BY time, id ORDER BY time, id
` `
selectMessagesSinceIDIncludeScheduledQuery = ` selectMessagesSinceIDIncludeScheduledQuery = `
SELECT mid, time, topic, message, title, priority, tags, click, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, attachment_owner, encoding SELECT mid, time, topic, message, title, priority, tags, click, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding
FROM messages FROM messages
WHERE topic = ? AND (id > ? OR published = 0) WHERE topic = ? AND (id > ? OR published = 0)
ORDER BY time, id ORDER BY time, id
` `
selectMessagesDueQuery = ` selectMessagesDueQuery = `
SELECT mid, time, topic, message, title, priority, tags, click, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, attachment_owner, encoding SELECT mid, time, topic, message, title, priority, tags, click, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, encoding
FROM messages FROM messages
WHERE time <= ? AND published = 0 WHERE time <= ? AND published = 0
ORDER BY time, id ORDER BY time, id
@ -84,13 +84,13 @@ const (
selectMessagesCountQuery = `SELECT COUNT(*) FROM messages` selectMessagesCountQuery = `SELECT COUNT(*) FROM messages`
selectMessageCountForTopicQuery = `SELECT COUNT(*) FROM messages WHERE topic = ?` selectMessageCountForTopicQuery = `SELECT COUNT(*) FROM messages WHERE topic = ?`
selectTopicsQuery = `SELECT topic FROM messages GROUP BY topic` selectTopicsQuery = `SELECT topic FROM messages GROUP BY topic`
selectAttachmentsSizeQuery = `SELECT IFNULL(SUM(attachment_size), 0) FROM messages WHERE attachment_owner = ? AND attachment_expires >= ?` selectAttachmentsSizeQuery = `SELECT IFNULL(SUM(attachment_size), 0) FROM messages WHERE sender = ? AND attachment_expires >= ?`
selectAttachmentsExpiredQuery = `SELECT mid FROM messages WHERE attachment_expires > 0 AND attachment_expires < ?` selectAttachmentsExpiredQuery = `SELECT mid FROM messages WHERE attachment_expires > 0 AND attachment_expires < ?`
) )
// Schema management queries // Schema management queries
const ( const (
currentSchemaVersion = 6 currentSchemaVersion = 7
createSchemaVersionTableQuery = ` createSchemaVersionTableQuery = `
CREATE TABLE IF NOT EXISTS schemaVersion ( CREATE TABLE IF NOT EXISTS schemaVersion (
id INT PRIMARY KEY, id INT PRIMARY KEY,
@ -173,6 +173,11 @@ const (
migrate5To6AlterMessagesTableQuery = ` migrate5To6AlterMessagesTableQuery = `
ALTER TABLE messages ADD COLUMN actions TEXT NOT NULL DEFAULT(''); ALTER TABLE messages ADD COLUMN actions TEXT NOT NULL DEFAULT('');
` `
// 6 -> 7
migrate6To7AlterMessagesTableQuery = `
ALTER TABLE messages RENAME COLUMN attachment_owner TO sender;
`
) )
type messageCache struct { type messageCache struct {
@ -225,7 +230,7 @@ func (c *messageCache) AddMessage(m *message) error {
} }
published := m.Time <= time.Now().Unix() published := m.Time <= time.Now().Unix()
tags := strings.Join(m.Tags, ",") tags := strings.Join(m.Tags, ",")
var attachmentName, attachmentType, attachmentURL, attachmentOwner string var attachmentName, attachmentType, attachmentURL string
var attachmentSize, attachmentExpires int64 var attachmentSize, attachmentExpires int64
if m.Attachment != nil { if m.Attachment != nil {
attachmentName = m.Attachment.Name attachmentName = m.Attachment.Name
@ -233,7 +238,6 @@ func (c *messageCache) AddMessage(m *message) error {
attachmentSize = m.Attachment.Size attachmentSize = m.Attachment.Size
attachmentExpires = m.Attachment.Expires attachmentExpires = m.Attachment.Expires
attachmentURL = m.Attachment.URL attachmentURL = m.Attachment.URL
attachmentOwner = m.Attachment.Owner
} }
var actionsStr string var actionsStr string
if len(m.Actions) > 0 { if len(m.Actions) > 0 {
@ -259,7 +263,7 @@ func (c *messageCache) AddMessage(m *message) error {
attachmentSize, attachmentSize,
attachmentExpires, attachmentExpires,
attachmentURL, attachmentURL,
attachmentOwner, m.Sender,
m.Encoding, m.Encoding,
published, published,
) )
@ -371,8 +375,8 @@ func (c *messageCache) Prune(olderThan time.Time) error {
return err return err
} }
func (c *messageCache) AttachmentBytesUsed(owner string) (int64, error) { func (c *messageCache) AttachmentBytesUsed(sender string) (int64, error) {
rows, err := c.db.Query(selectAttachmentsSizeQuery, owner, time.Now().Unix()) rows, err := c.db.Query(selectAttachmentsSizeQuery, sender, time.Now().Unix())
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -415,7 +419,7 @@ func readMessages(rows *sql.Rows) ([]*message, error) {
for rows.Next() { for rows.Next() {
var timestamp, attachmentSize, attachmentExpires int64 var timestamp, attachmentSize, attachmentExpires int64
var priority int var priority int
var id, topic, msg, title, tagsStr, click, actionsStr, attachmentName, attachmentType, attachmentURL, attachmentOwner, encoding string var id, topic, msg, title, tagsStr, click, actionsStr, attachmentName, attachmentType, attachmentURL, sender, encoding string
err := rows.Scan( err := rows.Scan(
&id, &id,
&timestamp, &timestamp,
@ -431,7 +435,7 @@ func readMessages(rows *sql.Rows) ([]*message, error) {
&attachmentSize, &attachmentSize,
&attachmentExpires, &attachmentExpires,
&attachmentURL, &attachmentURL,
&attachmentOwner, &sender,
&encoding, &encoding,
) )
if err != nil { if err != nil {
@ -455,7 +459,6 @@ func readMessages(rows *sql.Rows) ([]*message, error) {
Size: attachmentSize, Size: attachmentSize,
Expires: attachmentExpires, Expires: attachmentExpires,
URL: attachmentURL, URL: attachmentURL,
Owner: attachmentOwner,
} }
} }
messages = append(messages, &message{ messages = append(messages, &message{
@ -470,6 +473,7 @@ func readMessages(rows *sql.Rows) ([]*message, error) {
Click: click, Click: click,
Actions: actions, Actions: actions,
Attachment: att, Attachment: att,
Sender: sender,
Encoding: encoding, Encoding: encoding,
}) })
} }
@ -516,6 +520,8 @@ func setupCacheDB(db *sql.DB) error {
return migrateFrom4(db) return migrateFrom4(db)
} else if schemaVersion == 5 { } else if schemaVersion == 5 {
return migrateFrom5(db) return migrateFrom5(db)
} else if schemaVersion == 6 {
return migrateFrom6(db)
} }
return fmt.Errorf("unexpected schema version found: %d", schemaVersion) return fmt.Errorf("unexpected schema version found: %d", schemaVersion)
} }
@ -599,5 +605,16 @@ func migrateFrom5(db *sql.DB) error {
if _, err := db.Exec(updateSchemaVersion, 6); err != nil { if _, err := db.Exec(updateSchemaVersion, 6); err != nil {
return err return err
} }
return migrateFrom6(db)
}
func migrateFrom6(db *sql.DB) error {
log.Print("Migrating cache database schema: from 6 to 7")
if _, err := db.Exec(migrate6To7AlterMessagesTableQuery); err != nil {
return err
}
if _, err := db.Exec(updateSchemaVersion, 7); err != nil {
return err
}
return nil // Update this when a new version is added return nil // Update this when a new version is added
} }

View file

@ -281,39 +281,39 @@ func testCacheAttachments(t *testing.T, c *messageCache) {
expires1 := time.Now().Add(-4 * time.Hour).Unix() expires1 := time.Now().Add(-4 * time.Hour).Unix()
m := newDefaultMessage("mytopic", "flower for you") m := newDefaultMessage("mytopic", "flower for you")
m.ID = "m1" m.ID = "m1"
m.Sender = "1.2.3.4"
m.Attachment = &attachment{ m.Attachment = &attachment{
Name: "flower.jpg", Name: "flower.jpg",
Type: "image/jpeg", Type: "image/jpeg",
Size: 5000, Size: 5000,
Expires: expires1, Expires: expires1,
URL: "https://ntfy.sh/file/AbDeFgJhal.jpg", URL: "https://ntfy.sh/file/AbDeFgJhal.jpg",
Owner: "1.2.3.4",
} }
require.Nil(t, c.AddMessage(m)) require.Nil(t, c.AddMessage(m))
expires2 := time.Now().Add(2 * time.Hour).Unix() // Future expires2 := time.Now().Add(2 * time.Hour).Unix() // Future
m = newDefaultMessage("mytopic", "sending you a car") m = newDefaultMessage("mytopic", "sending you a car")
m.ID = "m2" m.ID = "m2"
m.Sender = "1.2.3.4"
m.Attachment = &attachment{ m.Attachment = &attachment{
Name: "car.jpg", Name: "car.jpg",
Type: "image/jpeg", Type: "image/jpeg",
Size: 10000, Size: 10000,
Expires: expires2, Expires: expires2,
URL: "https://ntfy.sh/file/aCaRURL.jpg", URL: "https://ntfy.sh/file/aCaRURL.jpg",
Owner: "1.2.3.4",
} }
require.Nil(t, c.AddMessage(m)) require.Nil(t, c.AddMessage(m))
expires3 := time.Now().Add(1 * time.Hour).Unix() // Future expires3 := time.Now().Add(1 * time.Hour).Unix() // Future
m = newDefaultMessage("another-topic", "sending you another car") m = newDefaultMessage("another-topic", "sending you another car")
m.ID = "m3" m.ID = "m3"
m.Sender = "1.2.3.4"
m.Attachment = &attachment{ m.Attachment = &attachment{
Name: "another-car.jpg", Name: "another-car.jpg",
Type: "image/jpeg", Type: "image/jpeg",
Size: 20000, Size: 20000,
Expires: expires3, Expires: expires3,
URL: "https://ntfy.sh/file/zakaDHFW.jpg", URL: "https://ntfy.sh/file/zakaDHFW.jpg",
Owner: "1.2.3.4",
} }
require.Nil(t, c.AddMessage(m)) require.Nil(t, c.AddMessage(m))
@ -327,7 +327,7 @@ func testCacheAttachments(t *testing.T, c *messageCache) {
require.Equal(t, int64(5000), messages[0].Attachment.Size) require.Equal(t, int64(5000), messages[0].Attachment.Size)
require.Equal(t, expires1, messages[0].Attachment.Expires) require.Equal(t, expires1, messages[0].Attachment.Expires)
require.Equal(t, "https://ntfy.sh/file/AbDeFgJhal.jpg", messages[0].Attachment.URL) require.Equal(t, "https://ntfy.sh/file/AbDeFgJhal.jpg", messages[0].Attachment.URL)
require.Equal(t, "1.2.3.4", messages[0].Attachment.Owner) require.Equal(t, "1.2.3.4", messages[0].Sender)
require.Equal(t, "sending you a car", messages[1].Message) require.Equal(t, "sending you a car", messages[1].Message)
require.Equal(t, "car.jpg", messages[1].Attachment.Name) require.Equal(t, "car.jpg", messages[1].Attachment.Name)
@ -335,7 +335,7 @@ func testCacheAttachments(t *testing.T, c *messageCache) {
require.Equal(t, int64(10000), messages[1].Attachment.Size) require.Equal(t, int64(10000), messages[1].Attachment.Size)
require.Equal(t, expires2, messages[1].Attachment.Expires) require.Equal(t, expires2, messages[1].Attachment.Expires)
require.Equal(t, "https://ntfy.sh/file/aCaRURL.jpg", messages[1].Attachment.URL) require.Equal(t, "https://ntfy.sh/file/aCaRURL.jpg", messages[1].Attachment.URL)
require.Equal(t, "1.2.3.4", messages[1].Attachment.Owner) require.Equal(t, "1.2.3.4", messages[1].Sender)
size, err := c.AttachmentBytesUsed("1.2.3.4") size, err := c.AttachmentBytesUsed("1.2.3.4")
require.Nil(t, err) require.Nil(t, err)

View file

@ -443,7 +443,7 @@ func (s *Server) handlePublish(w http.ResponseWriter, r *http.Request, v *visito
if s.mailer != nil && email != "" && !delayed { if s.mailer != nil && email != "" && !delayed {
go s.sendEmail(v, m, email) go s.sendEmail(v, m, email)
} }
if s.config.UpstreamBaseURL != "" { if s.config.UpstreamBaseURL != "" && !delayed {
go s.forwardPollRequest(v, m) go s.forwardPollRequest(v, m)
} }
if cache { if cache {
@ -484,7 +484,10 @@ func (s *Server) forwardPollRequest(v *visitor, m *message) {
return return
} }
req.Header.Set("X-Poll-ID", m.ID) req.Header.Set("X-Poll-ID", m.ID)
response, err := http.DefaultClient.Do(req) var httpClient = &http.Client{
Timeout: time.Second * 10,
}
response, err := httpClient.Do(req)
if err != nil { if err != nil {
log.Printf("[%s] FWD - Unable to forward poll request: %v", v.ip, err.Error()) log.Printf("[%s] FWD - Unable to forward poll request: %v", v.ip, err.Error())
return return
@ -566,6 +569,7 @@ func (s *Server) parsePublishParams(r *http.Request, v *visitor, m *message) (ca
return false, false, "", false, errHTTPBadRequestDelayTooLarge return false, false, "", false, errHTTPBadRequestDelayTooLarge
} }
m.Time = delay.Unix() m.Time = delay.Unix()
m.Sender = v.ip // Important for rate limiting
} }
actionsStr := readParam(r, "x-actions", "actions", "action") actionsStr := readParam(r, "x-actions", "actions", "action")
if actionsStr != "" { if actionsStr != "" {
@ -661,7 +665,7 @@ func (s *Server) handleBodyAsAttachment(r *http.Request, v *visitor, m *message,
m.Attachment = &attachment{} m.Attachment = &attachment{}
} }
var ext string var ext string
m.Attachment.Owner = v.ip // Important for attachment rate limiting m.Sender = v.ip // Important for attachment rate limiting
m.Attachment.Expires = time.Now().Add(s.config.AttachmentExpiryDuration).Unix() m.Attachment.Expires = time.Now().Add(s.config.AttachmentExpiryDuration).Unix()
m.Attachment.Type, ext = util.DetectContentType(body.PeekedBytes, m.Attachment.Name) m.Attachment.Type, ext = util.DetectContentType(body.PeekedBytes, m.Attachment.Name)
m.Attachment.URL = fmt.Sprintf("%s/file/%s%s", s.config.BaseURL, m.ID, ext) m.Attachment.URL = fmt.Sprintf("%s/file/%s%s", s.config.BaseURL, m.ID, ext)
@ -1081,7 +1085,7 @@ func (s *Server) runManager() {
func (s *Server) runDelayedSender() { func (s *Server) runDelayedSender() {
for { for {
select { select {
case <-time.After(s.config.AtSenderInterval): case <-time.After(s.config.DelayedSenderInterval):
if err := s.sendDelayedMessages(); err != nil { if err := s.sendDelayedMessages(); err != nil {
log.Printf("error sending scheduled messages: %s", err.Error()) log.Printf("error sending scheduled messages: %s", err.Error())
} }
@ -1118,7 +1122,7 @@ func (s *Server) sendDelayedMessages() error {
return err return err
} }
for _, m := range messages { for _, m := range messages {
v := s.visitorFromIP("0.0.0.0") // FIXME: get message owner!! v := s.visitorFromIP(m.Sender)
if err := s.sendDelayedMessage(v, m); err != nil { if err := s.sendDelayedMessage(v, m); err != nil {
log.Printf("error sending delayed message: %s", err.Error()) log.Printf("error sending delayed message: %s", err.Error())
} }
@ -1131,14 +1135,18 @@ func (s *Server) sendDelayedMessage(v *visitor, m *message) error {
defer s.mu.Unlock() defer s.mu.Unlock()
t, ok := s.topics[m.Topic] // If no subscribers, just mark message as published t, ok := s.topics[m.Topic] // If no subscribers, just mark message as published
if ok { if ok {
if err := t.Publish(v, m); err != nil { go func() {
return fmt.Errorf("unable to publish message %s to topic %s: %v", m.ID, m.Topic, err.Error()) // We do not rate-limit messages here, since we've rate limited them in the PUT/POST handler
} if err := t.Publish(v, m); err != nil {
log.Printf("unable to publish message %s to topic %s: %v", m.ID, m.Topic, err.Error())
}
}()
} }
if s.firebase != nil { // Firebase subscribers may not show up in topics map if s.firebase != nil { // Firebase subscribers may not show up in topics map
if err := s.firebase(v, m); err != nil { go s.sendToFirebase(v, m)
return fmt.Errorf("unable to publish to Firebase: %v", err.Error()) }
} if s.config.UpstreamBaseURL != "" {
go s.forwardPollRequest(v, m)
} }
if err := s.messageCache.MarkPublished(m); err != nil { if err := s.messageCache.MarkPublished(m); err != nil {
return err return err

View file

@ -119,7 +119,6 @@ func TestToFirebaseMessage_Message_Normal_Allowed(t *testing.T) {
Size: 12345, Size: 12345,
Expires: 98765543, Expires: 98765543,
URL: "https://example.com/file.jpg", URL: "https://example.com/file.jpg",
Owner: "some-owner",
} }
fbm, err := toFirebaseMessage(m, &testAuther{Allow: true}) fbm, err := toFirebaseMessage(m, &testAuther{Allow: true})
require.Nil(t, err) require.Nil(t, err)

View file

@ -264,7 +264,7 @@ func TestServer_PublishNoCache(t *testing.T) {
func TestServer_PublishAt(t *testing.T) { func TestServer_PublishAt(t *testing.T) {
c := newTestConfig(t) c := newTestConfig(t)
c.MinDelay = time.Second c.MinDelay = time.Second
c.AtSenderInterval = 100 * time.Millisecond c.DelayedSenderInterval = 100 * time.Millisecond
s := newTestServer(t, c) s := newTestServer(t, c)
response := request(t, s, "PUT", "/mytopic", "a message", map[string]string{ response := request(t, s, "PUT", "/mytopic", "a message", map[string]string{
@ -283,6 +283,13 @@ func TestServer_PublishAt(t *testing.T) {
messages = toMessages(t, response.Body.String()) messages = toMessages(t, response.Body.String())
require.Equal(t, 1, len(messages)) require.Equal(t, 1, len(messages))
require.Equal(t, "a message", messages[0].Message) require.Equal(t, "a message", messages[0].Message)
require.Equal(t, "", messages[0].Sender) // Never return the sender!
messages, err := s.messageCache.Messages("mytopic", sinceAllMessages, true)
require.Nil(t, err)
require.Equal(t, 1, len(messages))
require.Equal(t, "a message", messages[0].Message)
require.Equal(t, "9.9.9.9", messages[0].Sender) // It's stored in the DB though!
} }
func TestServer_PublishAtWithCacheError(t *testing.T) { func TestServer_PublishAtWithCacheError(t *testing.T) {
@ -1019,7 +1026,7 @@ func TestServer_PublishAttachment(t *testing.T) {
require.Equal(t, int64(5000), msg.Attachment.Size) require.Equal(t, int64(5000), msg.Attachment.Size)
require.GreaterOrEqual(t, msg.Attachment.Expires, time.Now().Add(179*time.Minute).Unix()) // Almost 3 hours require.GreaterOrEqual(t, msg.Attachment.Expires, time.Now().Add(179*time.Minute).Unix()) // Almost 3 hours
require.Contains(t, msg.Attachment.URL, "http://127.0.0.1:12345/file/") require.Contains(t, msg.Attachment.URL, "http://127.0.0.1:12345/file/")
require.Equal(t, "", msg.Attachment.Owner) // Should never be returned require.Equal(t, "", msg.Sender) // Should never be returned
require.FileExists(t, filepath.Join(s.config.AttachmentCacheDir, msg.ID)) require.FileExists(t, filepath.Join(s.config.AttachmentCacheDir, msg.ID))
path := strings.TrimPrefix(msg.Attachment.URL, "http://127.0.0.1:12345") path := strings.TrimPrefix(msg.Attachment.URL, "http://127.0.0.1:12345")
@ -1048,7 +1055,7 @@ func TestServer_PublishAttachmentShortWithFilename(t *testing.T) {
require.Equal(t, int64(21), msg.Attachment.Size) require.Equal(t, int64(21), msg.Attachment.Size)
require.GreaterOrEqual(t, msg.Attachment.Expires, time.Now().Add(3*time.Hour).Unix()) require.GreaterOrEqual(t, msg.Attachment.Expires, time.Now().Add(3*time.Hour).Unix())
require.Contains(t, msg.Attachment.URL, "http://127.0.0.1:12345/file/") require.Contains(t, msg.Attachment.URL, "http://127.0.0.1:12345/file/")
require.Equal(t, "", msg.Attachment.Owner) // Should never be returned require.Equal(t, "", msg.Sender) // Should never be returned
require.FileExists(t, filepath.Join(s.config.AttachmentCacheDir, msg.ID)) require.FileExists(t, filepath.Join(s.config.AttachmentCacheDir, msg.ID))
path := strings.TrimPrefix(msg.Attachment.URL, "http://127.0.0.1:12345") path := strings.TrimPrefix(msg.Attachment.URL, "http://127.0.0.1:12345")
@ -1075,7 +1082,7 @@ func TestServer_PublishAttachmentExternalWithoutFilename(t *testing.T) {
require.Equal(t, "", msg.Attachment.Type) require.Equal(t, "", msg.Attachment.Type)
require.Equal(t, int64(0), msg.Attachment.Size) require.Equal(t, int64(0), msg.Attachment.Size)
require.Equal(t, int64(0), msg.Attachment.Expires) require.Equal(t, int64(0), msg.Attachment.Expires)
require.Equal(t, "", msg.Attachment.Owner) require.Equal(t, "", msg.Sender)
// Slightly unrelated cross-test: make sure we don't add an owner for external attachments // Slightly unrelated cross-test: make sure we don't add an owner for external attachments
size, err := s.messageCache.AttachmentBytesUsed("127.0.0.1") size, err := s.messageCache.AttachmentBytesUsed("127.0.0.1")
@ -1096,7 +1103,7 @@ func TestServer_PublishAttachmentExternalWithFilename(t *testing.T) {
require.Equal(t, "", msg.Attachment.Type) require.Equal(t, "", msg.Attachment.Type)
require.Equal(t, int64(0), msg.Attachment.Size) require.Equal(t, int64(0), msg.Attachment.Size)
require.Equal(t, int64(0), msg.Attachment.Expires) require.Equal(t, int64(0), msg.Attachment.Expires)
require.Equal(t, "", msg.Attachment.Owner) require.Equal(t, "", msg.Sender)
} }
func TestServer_PublishAttachmentBadURL(t *testing.T) { func TestServer_PublishAttachmentBadURL(t *testing.T) {

View file

@ -32,6 +32,7 @@ type message struct {
Actions []*action `json:"actions,omitempty"` Actions []*action `json:"actions,omitempty"`
Attachment *attachment `json:"attachment,omitempty"` Attachment *attachment `json:"attachment,omitempty"`
PollID string `json:"poll_id,omitempty"` PollID string `json:"poll_id,omitempty"`
Sender string `json:"-"` // IP address of uploader, used for rate limiting
Encoding string `json:"encoding,omitempty"` // empty for raw UTF-8, or "base64" for encoded bytes Encoding string `json:"encoding,omitempty"` // empty for raw UTF-8, or "base64" for encoded bytes
} }
@ -41,7 +42,6 @@ type attachment struct {
Size int64 `json:"size,omitempty"` Size int64 `json:"size,omitempty"`
Expires int64 `json:"expires,omitempty"` Expires int64 `json:"expires,omitempty"`
URL string `json:"url"` URL string `json:"url"`
Owner string `json:"-"` // IP address of uploader, used for rate limiting
} }
type action struct { type action struct {