From c31b9236a1d10b413980934f6b0159e743fc5a93 Mon Sep 17 00:00:00 2001 From: Philipp Born <git@pborn.eu> Date: Wed, 22 Feb 2023 21:14:14 +0100 Subject: [PATCH 1/4] docs: add traccar example --- docs/examples.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/examples.md b/docs/examples.md index 0c892e64..59796372 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -572,4 +572,27 @@ Example `template.html`: Add notification on Rundeck (attachment type must be: `Attached as file to email`):  +## Traccar +This will only work on selfhosted [traccar](https://www.traccar.org/) ([Github](https://github.com/traccar/traccar)) instances, as you need to be able to set `sms.http.*` keys, which is not possible through the UI attributes +The easiest way to integrate traccar with ntfy, is to configure ntfy as the SMS provider for your instance. You then can set your ntfy topic as your account's phone number in traccar. Sending the email notifications to ntfy will not work, as ntfy does not support HTML emails. + +**Caution:** JSON publishing is only possible, when POST-ing to the root URL of the ntfy instance. (see [documentation](publish.md#publish-as-json)) +```xml + <entry key='sms.http.url'>https://ntfy.sh</entry> + <entry key='sms.http.template'> + { + "topic": "{phone}", + "message": "{message}" + } + </entry> +``` +If [access control](config.md#access-control) is enabled, and the target topic does not support anonymous writes, you'll also have to provide an authorization header, for example in form of a privileged token +```xml + <entry key='sms.http.authorization'>Bearer tk_JhbsnoMrgy2FcfHeofv97Pi5uXaZZ</entry> +``` +or by simply providing traccar with a valid username/password combination. +```xml + <entry key='sms.http.user'>phil</entry> + <entry key='sms.http.password'>mypass</entry> +``` From 422ad0cc5dd7b6bdf69fde1b4fc8d143271e2958 Mon Sep 17 00:00:00 2001 From: binwiederhier <pheckel@datto.com> Date: Thu, 23 Feb 2023 10:15:57 -0500 Subject: [PATCH 2/4] UnifiedPush: Treat non-Basic/Bearer `Authorization` header like header was not sent --- docs/releases.md | 3 ++- server/server.go | 13 +++++++++++-- server/server_test.go | 19 +++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/docs/releases.md b/docs/releases.md index 2354f8ee..498266ea 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -2,7 +2,7 @@ Binaries for all releases can be found on the GitHub releases pages for the [ntfy server](https://github.com/binwiederhier/ntfy/releases) and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/releases). -## ntfy server v2.0.2 (UNRELEASED) +## ntfy server v2.1.0 (UNRELEASED) **Features:** @@ -13,6 +13,7 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release **Bug fixes + maintenance:** * Web: Do not disable "Reserve topic" checkbox for admins (no ticket, thanks to @xenrox for reporting) +* UnifiedPush: Treat non-Basic/Bearer `Authorization` header like header was not sent ([#629](https://github.com/binwiederhier/ntfy/issues/629), thanks to [@Boebbele](https://github.com/Boebbele) and [@S1m](https://github.com/S1m) for reporting) **Additional languages:** diff --git a/server/server.go b/server/server.go index c4e07238..10b63607 100644 --- a/server/server.go +++ b/server/server.go @@ -1505,7 +1505,8 @@ func (s *Server) autorizeTopic(next handleFunc, perm user.Permission) handleFunc // maybeAuthenticate reads the "Authorization" header and will try to authenticate the user // if it is set. // -// - If the header is not set, an IP-based visitor is returned +// - If the header is not set or not supported (anything non-Basic and non-Bearer), +// an IP-based visitor is returned // - If the header is set, authenticate will be called to check the username/password (Basic auth), // or the token (Bearer auth), and read the user from the database // @@ -1518,7 +1519,7 @@ func (s *Server) maybeAuthenticate(r *http.Request) (*visitor, error) { header, err := readAuthHeader(r) if err != nil { return vip, err - } else if header == "" { + } else if !supportedAuthHeader(header) { return vip, nil } else if s.userManager == nil { return vip, errHTTPUnauthorized @@ -1563,6 +1564,14 @@ func readAuthHeader(r *http.Request) (string, error) { return value, nil } +// supportedAuthHeader returns true only if the Authorization header value starts +// with "Basic" or "Bearer". In particular, an empty value is not supported, and neither +// are things like "WebPush", or "vapid" (see #629). +func supportedAuthHeader(value string) bool { + value = strings.ToLower(value) + return strings.HasPrefix(value, "basic ") || strings.HasPrefix(value, "bearer ") +} + func (s *Server) authenticateBasicAuth(r *http.Request, value string) (user *user.User, err error) { r.Header.Set("Authorization", value) username, password, ok := r.BasicAuth() diff --git a/server/server_test.go b/server/server_test.go index 4abff399..fddfbba4 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -796,6 +796,25 @@ func TestServer_Auth_ViaQuery(t *testing.T) { require.Equal(t, 401, response.Code) } +func TestServer_Auth_NonBasicHeader(t *testing.T) { + s := newTestServer(t, newTestConfigWithAuthFile(t)) + + response := request(t, s, "PUT", "/mytopic", "test", map[string]string{ + "Authorization": "WebPush not-supported", + }) + require.Equal(t, 200, response.Code) + + response = request(t, s, "PUT", "/mytopic", "test", map[string]string{ + "Authorization": "Bearer supported", + }) + require.Equal(t, 401, response.Code) + + response = request(t, s, "PUT", "/mytopic", "test", map[string]string{ + "Authorization": "basic supported", + }) + require.Equal(t, 401, response.Code) +} + func TestServer_StatsResetter(t *testing.T) { // This tests the stats resetter for // - an anonymous user From ab59d81d08d62879516a552ea9cd4f129535b164 Mon Sep 17 00:00:00 2001 From: binwiederhier <pheckel@datto.com> Date: Thu, 23 Feb 2023 11:42:22 -0500 Subject: [PATCH 3/4] Release notes --- docs/releases.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/releases.md b/docs/releases.md index 498266ea..52d90031 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -15,6 +15,10 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release * Web: Do not disable "Reserve topic" checkbox for admins (no ticket, thanks to @xenrox for reporting) * UnifiedPush: Treat non-Basic/Bearer `Authorization` header like header was not sent ([#629](https://github.com/binwiederhier/ntfy/issues/629), thanks to [@Boebbele](https://github.com/Boebbele) and [@S1m](https://github.com/S1m) for reporting) +**Documentation:** + +* Added example for [Traccar](https://ntfy.sh/docs/examples/#traccar) ([#631](https://github.com/binwiederhier/ntfy/pull/631), thanks to [tamcore](https://github.com/tamcore)) + **Additional languages:** * Arabic (thanks to [@ButterflyOfFire](https://hosted.weblate.org/user/ButterflyOfFire/)) From 697c09e146a5634265ff49ab525dc4a382e7adab Mon Sep 17 00:00:00 2001 From: binwiederhier <pheckel@datto.com> Date: Thu, 23 Feb 2023 14:02:58 -0500 Subject: [PATCH 4/4] Release notes --- docs/releases.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/releases.md b/docs/releases.md index 52d90031..f3275544 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -4,6 +4,10 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release ## ntfy server v2.1.0 (UNRELEASED) +This release now supports sending emails to protected topics, and it ships code to support annual billing cycles (not live yet). +Most importantly, it fixes an issue with UnifiedPush (mostly Mastodon servers) that send an `Authorization` header, which ntfy +rejects with an HTTP 401. + **Features:** * Support for publishing to protected topics via email with access tokens ([#612](https://github.com/binwiederhier/ntfy/pull/621), thanks to [@tamcore](https://github.com/tamcore))