diff --git a/docs/releases.md b/docs/releases.md index 9ee4fd50..2f0e4585 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -4,14 +4,46 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release ## Current stable releases -| Component | Version | Release date | -|------------------|---------|--------------| -| ntfy server | v2.26.3 | Jul 20, 2026 | -| ntfy Android app | v1.24.0 | Mar 5, 2026 | -| ntfy iOS app | v1.7.0 | May 30, 2026 | +| Component | Version | Release date | +|------------------|---------|---------------| +| ntfy server | v2.26.3 | Jul 20, 2026 | +| ntfy Android app | v1.25.2 | July 23, 2026 | +| ntfy iOS app | v1.7.0 | May 30, 2026 | Please check out the release notes for [upcoming releases](#not-released-yet) below. +## ntfy Android v1.25.2 +Released July 23, 2026 + +This release makes the "connection lost" alert configurable and turns it off by default. Folks did not like it and many reached out +or even gave ntfy bad reviews. I heard you! You can re-enable the alert in the advanced settings. + +The release also tries to be smarter about not retrying the connection at all if the app is in flight mode, or has no network. If there +is no network, ntfy now keeps the foreground service alive and shows a "Waiting for network" notification, then resumes automatically +once connectivity returns. + +Another change related to the networking is that we now force-reconnect when the connection is changed, e.g. during transitions +from Wi-Fi to cellular network, or vice versa. That should allow for faster transitions during hand-overs. + +We also increase the client-side WebSocket ping interval from 1 minute to 3 minutes, which should slightly improve battery life, +especially when paired with increaseing the server-side `keepalive-interval` in your self-hosted server. + +**Features:** + +* Add configurable "Alert when connection is lost" setting, turned off by default ([#1665](https://github.com/binwiederhier/ntfy/issues/1665), [#1662](https://github.com/binwiederhier/ntfy/issues/1662), [#1652](https://github.com/binwiederhier/ntfy/issues/1652), [#1655](https://github.com/binwiederhier/ntfy/issues/1655), thanks to [@tintamarre](https://github.com/tintamarre), [@sjozs](https://github.com/sjozs), [@TheRealOne78](https://github.com/TheRealOne78), and [@DAE51D](https://github.com/DAE51D) for reporting) +* Handle "no network" gracefully: when the device is offline or in airplane mode, ntfy now stops retrying, suppresses the connection-lost alert, and keeps the foreground service alive with a "Waiting for network" notification, resuming instant delivery automatically when connectivity returns ([ntfy-android#165](https://github.com/binwiederhier/ntfy-android/pull/165), thanks to [@tintamarre](https://github.com/tintamarre) for the contribution, and [#1709](https://github.com/binwiederhier/ntfy/issues/1709), thanks to [@isaitgirl](https://github.com/isaitgirl) for reporting) +* Improve battery life by increasing WebSocket client ping interval from 1 min to 3 min, and reconnect instantly on Wi-Fi/cellular/VPN transitions ([ntfy-android#113](https://github.com/binwiederhier/ntfy-android/pull/113), thanks to [@ftilde](https://github.com/ftilde) for the investigation) +* Disable UnifiedPush components when UnifiedPush is disabled in settings ([ntfy-android#168](https://github.com/binwiederhier/ntfy-android/pull/168), thanks to [@p1gp1g](https://github.com/p1gp1g) for the contribution) + +**Bug fixes + maintenance:** + +* Fix the "connection lost" alert briefly disappearing and re-firing when roaming between networks (e.g. Wi-Fi to cellular), by no longer cancelling it during the transient no-network gap of a handover +* Fix the "connection lost" alert repeatedly waking the screen while a server stayed unreachable, by no longer re-posting the alert once it is already showing +* Fix the "connection lost" alert firing late, erratically, or not at all when a connection kept dropping (e.g. a flaky server) rather than being refused outright, by tracking how long the connection has been down independently of whether the drop warrants a UI error +* Undo automatic phone number linking for numbers in message body ([ntfy-android#170](https://github.com/binwiederhier/ntfy-android/pull/170), thanks to [@acortelyou](https://github.com/acortelyou) for the contribution) +* Fix subscription icons disappearing after a few days due to Android clearing cache ([#1322](https://github.com/binwiederhier/ntfy/issues/1322), thanks to [@mcanning](https://github.com/mcanning) for reporting) +* Fix UnifiedPush `failed_reason` being sent as an enum instead of a string, which caused an exception in receiving apps that read it as a string extra ([ntfy-android#182](https://github.com/binwiederhier/ntfy-android/pull/182), thanks to [@p1gp1g](https://github.com/p1gp1g) for the contribution) + ### ntfy server v2.26.3 Released July 20, 2026 @@ -2021,6 +2053,10 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release ### ntfy server v2.27.0 (UNRELEASED) +**Security:** + +* Exclude secrets (Stripe/Twilio/web push keys, SMTP password, provisioned users and tokens) from the config hash served to the web app + **Features:** * Allow logging in with your verified primary email address (in addition to your username), so a password reset no longer leaves you unable to sign in when you only remember the email you signed up with @@ -2030,37 +2066,6 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release * Fix Twilio phone calls and phone number verifications failing silently when Twilio rejected the request, and move the Twilio integration into its own `twilio` package * Move the Prometheus metrics into a dedicated `metrics` package -### ntfy Android v1.25.2 (UNRELEASED) - -This release makes the "connection lost" alert configurable and turns it off by default. Folks did not like it and many reached out -or even gave ntfy bad reviews. I heard you! You can re-enable the alert in the advanced settings. - -The release also tries to be smarter about not retrying the connection at all if the app is in flight mode, or has no network. If there -is no network, ntfy now keeps the foreground service alive and shows a "Waiting for network" notification, then resumes automatically -once connectivity returns. - -Another change related to the networking is that we now force-reconnect when the connection is changed, e.g. during transitions -from Wi-Fi to cellular network, or vice versa. That should allow for faster transitions during hand-overs. - -We also increase the client-side WebSocket ping interval from 1 minute to 3 minutes, which should slightly improve battery life, -especially when paired with increaseing the server-side `keepalive-interval` in your self-hosted server. - -**Features:** - -* Add configurable "Alert when connection is lost" setting, turned off by default ([#1665](https://github.com/binwiederhier/ntfy/issues/1665), [#1662](https://github.com/binwiederhier/ntfy/issues/1662), [#1652](https://github.com/binwiederhier/ntfy/issues/1652), [#1655](https://github.com/binwiederhier/ntfy/issues/1655), thanks to [@tintamarre](https://github.com/tintamarre), [@sjozs](https://github.com/sjozs), [@TheRealOne78](https://github.com/TheRealOne78), and [@DAE51D](https://github.com/DAE51D) for reporting) -* Handle "no network" gracefully: when the device is offline or in airplane mode, ntfy now stops retrying, suppresses the connection-lost alert, and keeps the foreground service alive with a "Waiting for network" notification, resuming instant delivery automatically when connectivity returns ([ntfy-android#165](https://github.com/binwiederhier/ntfy-android/pull/165), thanks to [@tintamarre](https://github.com/tintamarre) for the contribution, and [#1709](https://github.com/binwiederhier/ntfy/issues/1709), thanks to [@isaitgirl](https://github.com/isaitgirl) for reporting) -* Improve battery life by increasing WebSocket client ping interval from 1 min to 3 min, and reconnect instantly on Wi-Fi/cellular/VPN transitions ([ntfy-android#113](https://github.com/binwiederhier/ntfy-android/pull/113), thanks to [@ftilde](https://github.com/ftilde) for the investigation) -* Disable UnifiedPush components when UnifiedPush is disabled in settings ([ntfy-android#168](https://github.com/binwiederhier/ntfy-android/pull/168), thanks to [@p1gp1g](https://github.com/p1gp1g) for the contribution) - -**Bug fixes + maintenance:** - -* Fix the "connection lost" alert briefly disappearing and re-firing when roaming between networks (e.g. Wi-Fi to cellular), by no longer cancelling it during the transient no-network gap of a handover -* Fix the "connection lost" alert repeatedly waking the screen while a server stayed unreachable, by no longer re-posting the alert once it is already showing -* Fix the "connection lost" alert firing late, erratically, or not at all when a connection kept dropping (e.g. a flaky server) rather than being refused outright, by tracking how long the connection has been down independently of whether the drop warrants a UI error -* Undo automatic phone number linking for numbers in message body ([ntfy-android#170](https://github.com/binwiederhier/ntfy-android/pull/170), thanks to [@acortelyou](https://github.com/acortelyou) for the contribution) -* Fix subscription icons disappearing after a few days due to Android clearing cache ([#1322](https://github.com/binwiederhier/ntfy/issues/1322), thanks to [@mcanning](https://github.com/mcanning) for reporting) -* Fix UnifiedPush `failed_reason` being sent as an enum instead of a string, which caused an exception in receiving apps that read it as a string extra ([ntfy-android#182](https://github.com/binwiederhier/ntfy-android/pull/182), thanks to [@p1gp1g](https://github.com/p1gp1g) for the contribution) - ### ntfy iOS app v1.8.0 (UNRELEASED) **Features:** diff --git a/server/config.go b/server/config.go index 8df24da2..b2c169a4 100644 --- a/server/config.go +++ b/server/config.go @@ -130,9 +130,9 @@ type Config struct { AuthFile string AuthStartupQueries string AuthDefault user.Permission - AuthUsers []*user.User + AuthUsers []*user.User `hash:"-"` AuthAccess map[string][]*user.Grant - AuthTokens map[string][]*user.Token + AuthTokens map[string][]*user.Token `hash:"-"` AuthBcryptCost int AuthStatsQueueWriterInterval time.Duration AuthAccessCacheEnabled bool // Enables the in-memory ACL cache (high volume servers only) @@ -153,17 +153,17 @@ type Config struct { FirebasePollInterval time.Duration FirebaseQuotaExceededPenaltyDuration time.Duration UpstreamBaseURL string - UpstreamAccessToken string + UpstreamAccessToken string `hash:"-"` SMTPSenderAddr string SMTPSenderUser string - SMTPSenderPass string + SMTPSenderPass string `hash:"-"` SMTPSenderFrom string SMTPSenderVerify bool SMTPServerListen string SMTPServerDomain string SMTPServerAddrPrefix string TwilioAccount string - TwilioAuthToken string + TwilioAuthToken string `hash:"-"` TwilioPhoneNumber string TwilioCallsBaseURL string TwilioVerifyBaseURL string @@ -198,8 +198,8 @@ type Config struct { BehindProxy bool // If true, the server will trust the proxy client IP header to determine the client IP address (IPv4 and IPv6 supported) ProxyForwardedHeader string // The header field to read the real/client IP address from, if BehindProxy is true, defaults to "X-Forwarded-For" (IPv4 and IPv6 supported) ProxyTrustedPrefixes []netip.Prefix // List of trusted proxy networks (IPv4 or IPv6) that will be stripped from the Forwarded header if BehindProxy is true - StripeSecretKey string - StripeWebhookKey string + StripeSecretKey string `hash:"-"` + StripeWebhookKey string `hash:"-"` StripePriceCacheDuration time.Duration BillingContact string EnableSignup bool // Enable creation of accounts via API and UI @@ -208,7 +208,7 @@ type Config struct { EnableReservations bool // Allow users with role "user" to own/reserve topics EnableMetrics bool AccessControlAllowOrigin string // CORS header field to restrict access from web clients - WebPushPrivateKey string + WebPushPrivateKey string `hash:"-"` WebPushPublicKey string WebPushFile string WebPushEmailAddress string @@ -342,6 +342,10 @@ func (c *Config) Hash() string { for i := 0; i < v.NumField(); i++ { field := v.Field(i) fieldName := t.Field(i).Name + // Secrets must not feed the hash + if t.Field(i).Tag.Get("hash") == "-" { + continue + } // Try to marshal the field and skip if it fails (e.g. *template.Template, netip.Prefix) if b, err := json.Marshal(field.Interface()); err == nil { result += fmt.Sprintf("%s:%s|", fieldName, string(b)) diff --git a/server/config_test.go b/server/config_test.go index 0dae5725..e789d55d 100644 --- a/server/config_test.go +++ b/server/config_test.go @@ -3,6 +3,7 @@ package server_test import ( "github.com/stretchr/testify/assert" "heckel.io/ntfy/v2/server" + "heckel.io/ntfy/v2/user" "testing" ) @@ -11,3 +12,24 @@ func TestConfig_New(t *testing.T) { assert.Equal(t, ":80", c.ListenHTTP) assert.Equal(t, server.DefaultKeepaliveInterval, c.KeepaliveInterval) } + +func TestConfig_HashExcludesSecrets(t *testing.T) { + // The config hash is served to browsers (ConfigHash, for webapp change detection), so + // secret material must not feed it: a weak secret would otherwise be offline-brute-forceable + // against a publicly visible hash. + conf1 := server.NewConfig() + conf2 := server.NewConfig() + conf2.StripeSecretKey = "sk_live_topsecret" + conf2.StripeWebhookKey = "whsec_topsecret" + conf2.TwilioAuthToken = "twilio-auth-token" + conf2.UpstreamAccessToken = "tk_upstream" + conf2.WebPushPrivateKey = "web-push-private-key" + conf2.SMTPSenderPass = "hunter2" + conf2.AuthUsers = []*user.User{{Name: "phil", Hash: "$2a$10$somebcrypthash"}} + conf2.AuthTokens = map[string][]*user.Token{"phil": {{Value: "tk_secrettoken"}}} + assert.Equal(t, conf1.Hash(), conf2.Hash()) + // Non-secret fields must still change the hash + conf3 := server.NewConfig() + conf3.BaseURL = "https://ntfy.example.com" + assert.NotEqual(t, conf1.Hash(), conf3.Hash()) +}