Просмотр исходного кода

Support encoding any header as RFC 2047

binwiederhier 2 лет назад
Родитель
Сommit
168ad8bf1b
6 измененных файлов с 38 добавлено и 15 удалено
  1. 13 5
      docs/publish.md
  2. 9 2
      docs/releases.md
  3. 5 5
      server/server.go
  4. 9 2
      server/server_test.go
  5. 1 0
      server/types.go
  6. 1 1
      server/util.go

+ 13 - 5
docs/publish.md

@@ -393,8 +393,8 @@ you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`).
 
 !!! info
     ntfy supports UTF-8 in HTTP headers, but [not every library or programming language does](https://www.jmix.io/blog/utf-8-in-http-headers/).
-    If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode the `X-Title` or `X-Message`
-    header as [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2), e.g. `=?UTF-8?B?8J+HqfCfh6o=?=` ([base64](https://en.wikipedia.org/wiki/Base64)),
+    If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode any header (including the title)
+    as [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2), e.g. `=?UTF-8?B?8J+HqfCfh6o=?=` ([base64](https://en.wikipedia.org/wiki/Base64)),
     or `=?UTF-8?Q?=C3=84pfel?=` ([quoted-printable](https://en.wikipedia.org/wiki/Quoted-printable)).
 
 ## Message priority
@@ -619,7 +619,7 @@ them with a comma, e.g. `tag1,tag2,tag3`.
 
 !!! info
     ntfy supports UTF-8 in HTTP headers, but [not every library or programming language does](https://www.jmix.io/blog/utf-8-in-http-headers/).
-    If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode the individual tags
+    If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode the tags header or individual tags
     as [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2), e.g. `tag1,=?UTF-8?B?8J+HqfCfh6o=?=` ([base64](https://en.wikipedia.org/wiki/Base64)),
     or `=?UTF-8?Q?=C3=84pfel?=,tag2` ([quoted-printable](https://en.wikipedia.org/wiki/Quoted-printable)).
 
@@ -1004,9 +1004,11 @@ all the supported fields:
 | `actions`  | -        | *JSON array*                     | *(see [action buttons](#action-buttons))* | Custom [user action buttons](#action-buttons) for notifications       |
 | `click`    | -        | *URL*                            | `https://example.com`                     | Website opened when notification is [clicked](#click-action)          |
 | `attach`   | -        | *URL*                            | `https://example.com/file.jpg`            | URL of an attachment, see [attach via URL](#attach-file-from-url)     |
+| `icon`     | -        | *string*                         | `https://example.com/icon.png`            | URL to use as notification [icon](#icons)                             |
 | `filename` | -        | *string*                         | `file.jpg`                                | File name of the attachment                                           |
 | `delay`    | -        | *string*                         | `30min`, `9am`                            | Timestamp or duration for delayed delivery                            |
 | `email`    | -        | *e-mail address*                 | `phil@example.com`                        | E-mail address for e-mail notifications                               |
+| `call`     | -        | *phone number or 'yes'*          | `+1222334444` or `yes`                    | Phone number to use for [voice call](#phone-calls)                    |
 
 ## Action buttons
 _Supported on:_ :material-android: :material-apple: :material-firefox:
@@ -1139,7 +1141,13 @@ As an example, here's how you can create the above notification using this forma
         ]
     ]));
     ```
- 
+
+!!! info
+    ntfy supports UTF-8 in HTTP headers, but [not every library or programming language does](https://www.jmix.io/blog/utf-8-in-http-headers/).
+    If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode any header (including actions) 
+    as [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2), e.g. `=?UTF-8?B?8J+HqfCfh6o=?=` ([base64](https://en.wikipedia.org/wiki/Base64)),
+    or `=?UTF-8?Q?=C3=84pfel?=` ([quoted-printable](https://en.wikipedia.org/wiki/Quoted-printable)).
+
 #### Using a JSON array
 Alternatively, the same actions can be defined as **JSON array**, if the notification is defined as part of the JSON body 
 (see [publish as JSON](#publish-as-json)):
@@ -3465,7 +3473,7 @@ table in their canonical form.
 
 !!! info
     ntfy supports UTF-8 in HTTP headers, but [not every library or programming language does](https://www.jmix.io/blog/utf-8-in-http-headers/).
-    If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode the `X-Title` or `X-Message`
+    If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode any
     header as [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2), e.g. `=?UTF-8?B?8J+HqfCfh6o=?=` ([base64](https://en.wikipedia.org/wiki/Base64)),
     or `=?UTF-8?Q?=C3=84pfel?=` ([quoted-printable](https://en.wikipedia.org/wiki/Quoted-printable)).
 

+ 9 - 2
docs/releases.md

@@ -28,7 +28,7 @@ if you use promo code `MYTOPIC`). ntfy will always remain open source.
 * Attachments with filenames that are downloaded using a browser will now download with the proper filename ([#726](https://github.com/binwiederhier/ntfy/issues/726), thanks to [@un99known99](https://github.com/un99known99) for reporting, and [@wunter8](https://github.com/wunter8) for fixing)
 * Fix web app i18n issue in account preferences ([#730](https://github.com/binwiederhier/ntfy/issues/730), thanks to [@codebude](https://github.com/codebude) for reporting)
 
-### ntfy server v2.4.0
+## ntfy server v2.4.0
 Released Apr 26, 2023
 
 This release adds a tiny `v1/stats` endpoint to expose how many messages have been published, and adds suport to encode the `X-Title`,
@@ -57,7 +57,7 @@ will always remain open source.
 
 * Swedish (thanks to [@hellbown](https://hosted.weblate.org/user/Shjosan/))
 
-### ntfy server v2.3.1 
+## ntfy server v2.3.1 
 Released March 30, 2023
 
 This release disables server-initiated polling of iOS devices entirely, thereby eliminating the thundering herd problem
@@ -1219,3 +1219,10 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release
 **Additional languages:**
 
 * Swedish (thanks to [@hellbown](https://hosted.weblate.org/user/hellbown/))
+
+### ntfy server v2.6.0 (UNRELEASED)
+
+**Bug fixes + maintenance:**
+
+* Support encoding any header as RFC 2047 ([#737](https://github.com/binwiederhier/ntfy/issues/737), thanks to [@cfouche3005](https://github.com/cfouche3005) for reporting)
+

+ 5 - 5
server/server.go

@@ -876,7 +876,7 @@ func (s *Server) forwardPollRequest(v *visitor, m *message) {
 func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, firebase bool, email, call string, unifiedpush bool, err *errHTTP) {
 	cache = readBoolParam(r, true, "x-cache", "cache")
 	firebase = readBoolParam(r, true, "x-firebase", "firebase")
-	m.Title = maybeDecodeHeader(readParam(r, "x-title", "title", "t"))
+	m.Title = readParam(r, "x-title", "title", "t")
 	m.Click = readParam(r, "x-click", "click")
 	icon := readParam(r, "x-icon", "icon")
 	filename := readParam(r, "x-filename", "filename", "file", "f")
@@ -923,7 +923,7 @@ func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, fi
 	}
 	messageStr := strings.ReplaceAll(readParam(r, "x-message", "message", "m"), "\\n", "\n")
 	if messageStr != "" {
-		m.Message = maybeDecodeHeader(messageStr)
+		m.Message = messageStr
 	}
 	var e error
 	m.Priority, e = util.ParsePriority(readParam(r, "x-priority", "priority", "prio", "p"))
@@ -931,9 +931,6 @@ func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, fi
 		return false, false, "", "", false, errHTTPBadRequestPriorityInvalid
 	}
 	m.Tags = readCommaSeparatedParam(r, "x-tags", "tags", "tag", "ta")
-	for i, t := range m.Tags {
-		m.Tags[i] = maybeDecodeHeader(t)
-	}
 	delayStr := readParam(r, "x-delay", "delay", "x-at", "at", "x-in", "in")
 	if delayStr != "" {
 		if !cache {
@@ -1747,6 +1744,9 @@ func (s *Server) transformBodyJSON(next handleFunc) handleFunc {
 		if m.Delay != "" {
 			r.Header.Set("X-Delay", m.Delay)
 		}
+		if m.Call != "" {
+			r.Header.Set("X-Call", m.Call)
+		}
 		return next(w, r, v)
 	}
 }

+ 9 - 2
server/server_test.go

@@ -2478,18 +2478,25 @@ func TestServer_PublishWithUTF8MimeHeader(t *testing.T) {
 	s := newTestServer(t, newTestConfig(t))
 
 	response := request(t, s, "POST", "/mytopic", "some attachment", map[string]string{
-		"X-Filename": "some attachment.txt",
+		"X-Filename": "some =?UTF-8?q?=C3=A4?=ttachment.txt",
 		"X-Message":  "=?UTF-8?B?8J+HqfCfh6o=?=",
 		"X-Title":    "=?UTF-8?B?bnRmeSDlvojmo5I=?=, no really I mean it! =?UTF-8?Q?This is q=C3=BC=C3=B6ted-print=C3=A4ble.?=",
 		"X-Tags":     "=?UTF-8?B?8J+HqfCfh6o=?=, =?UTF-8?B?bnRmeSDlvojmo5I=?=",
+		"X-Click":    "=?uTf-8?b?aHR0cHM6Ly/wn5KpLmxh?=",
+		"X-Actions":  "http, \"=?utf-8?q?Mettre =C3=A0 jour?=\", \"https://my.tld/webhook/netbird-update\"; =?utf-8?b?aHR0cCwg6L+Z5piv5LiA5Liq5qCH562+LCBodHRwczovL/CfkqkubGE=?=",
 	})
 	require.Equal(t, 200, response.Code)
 	m := toMessage(t, response.Body.String())
 	require.Equal(t, "🇩🇪", m.Message)
 	require.Equal(t, "ntfy 很棒, no really I mean it! This is qüöted-printäble.", m.Title)
-	require.Equal(t, "some attachment.txt", m.Attachment.Name)
+	require.Equal(t, "some ättachment.txt", m.Attachment.Name)
 	require.Equal(t, "🇩🇪", m.Tags[0])
 	require.Equal(t, "ntfy 很棒", m.Tags[1])
+	require.Equal(t, "https://💩.la", m.Click)
+	require.Equal(t, "Mettre à jour", m.Actions[0].Label)
+	require.Equal(t, "http", m.Actions[1].Action)
+	require.Equal(t, "这是一个标签", m.Actions[1].Label)
+	require.Equal(t, "https://💩.la", m.Actions[1].URL)
 }
 
 func TestServer_UpstreamBaseURL_Success(t *testing.T) {

+ 1 - 0
server/types.go

@@ -101,6 +101,7 @@ type publishMessage struct {
 	Attach   string   `json:"attach"`
 	Filename string   `json:"filename"`
 	Email    string   `json:"email"`
+	Call     string   `json:"call"`
 	Delay    string   `json:"delay"`
 }
 

+ 1 - 1
server/util.go

@@ -50,7 +50,7 @@ func readParam(r *http.Request, names ...string) string {
 
 func readHeaderParam(r *http.Request, names ...string) string {
 	for _, name := range names {
-		value := r.Header.Get(name)
+		value := maybeDecodeHeader(r.Header.Get(name))
 		if value != "" {
 			return strings.TrimSpace(value)
 		}