diff --git a/docs/config.md b/docs/config.md index b15b8022..1893f491 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1333,7 +1333,6 @@ variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`). | `stripe-secret-key` | `NTFY_STRIPE_SECRET_KEY` | *string* | - | Payments: Key used for the Stripe API communication, this enables payments | | `stripe-webhook-key` | `NTFY_STRIPE_WEBHOOK_KEY` | *string* | - | Payments: Key required to validate the authenticity of incoming webhooks from Stripe | | `billing-contact` | `NTFY_BILLING_CONTACT` | *email address* or *website* | - | Payments: Email or website displayed in Upgrade dialog as a billing contact | -| `web-push-enabled` | `NTFY_WEB_PUSH_ENABLED` | *boolean* (`true` or `false`) | - | Web Push: Enable/disable (requires private and public key below). | | `web-push-public-key` | `NTFY_WEB_PUSH_PUBLIC_KEY` | *string* | - | Web Push: Public Key. Run `ntfy webpush generate-keys` to generate | | `web-push-private-key` | `NTFY_WEB_PUSH_PRIVATE_KEY` | *string* | - | Web Push: Private Key. Run `ntfy webpush generate-keys` to generate | | `web-push-subscriptions-file` | `NTFY_WEB_PUSH_SUBSCRIPTIONS_FILE` | *string* | - | Web Push: Subscriptions file | @@ -1430,7 +1429,6 @@ OPTIONS: --enable-metrics, --enable_metrics if set, Prometheus metrics are exposed via the /metrics endpoint (default: false) [$NTFY_ENABLE_METRICS] --metrics-listen-http value, --metrics_listen_http value ip:port used to expose the metrics endpoint (implicitly enables metrics) [$NTFY_METRICS_LISTEN_HTTP] --profile-listen-http value, --profile_listen_http value ip:port used to expose the profiling endpoints (implicitly enables profiling) [$NTFY_PROFILE_LISTEN_HTTP] - --web-push-enabled, --web_push_enabled enable web push (requires public and private key) (default: false) [$NTFY_WEB_PUSH_ENABLED] --web-push-public-key value, --web_push_public_key value public key used for web push notifications [$NTFY_WEB_PUSH_PUBLIC_KEY] --web-push-private-key value, --web_push_private_key value private key used for web push notifications [$NTFY_WEB_PUSH_PRIVATE_KEY] --web-push-subscriptions-file value, --web_push_subscriptions_file value file used to store web push subscriptions [$NTFY_WEB_PUSH_SUBSCRIPTIONS_FILE] diff --git a/docs/static/img/web-push-settings.png b/docs/static/img/web-push-settings.png deleted file mode 100644 index 905d7c3c..00000000 Binary files a/docs/static/img/web-push-settings.png and /dev/null differ diff --git a/docs/static/img/web-subscribe.png b/docs/static/img/web-subscribe.png index 50db6763..ccbd0493 100644 Binary files a/docs/static/img/web-subscribe.png and b/docs/static/img/web-subscribe.png differ diff --git a/docs/subscribe/desktop.md b/docs/subscribe/desktop.md index b9ba02d9..fd9a9297 100644 --- a/docs/subscribe/desktop.md +++ b/docs/subscribe/desktop.md @@ -1,20 +1,17 @@ # Using the web app as an installed web app -While ntfy doesn't have a native desktop app, it is built as a [progressive web app](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps) -and thus can be installed on both desktop and mobile. +While ntfy doesn't have a native desktop app, it is built as a [progressive web app](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps) (PWA) +and thus can be installed on both desktop and mobile. This gives it its own launcher (e.g. shortcut on Windows, app on +macOS, launcher shortcut on Linux) own window, push notifications, and an app badge with the unread notification count. -This gives it its own launcher (e.g. shortcut on Windows, app on macOS, launcher shortcut on Linux) own window, -push notifications, and an app badge with the unread notification count. - -To receive background notifications, either the browser or the installed web app must be open. +To install and register the web app in your operating system, click the "install app" icon in your browser (usually next to the +address bar). To receive background notifications, **either the browser or the installed web app must be open**. Web app installation is supported on Chrome and Edge on desktop, as well as Chrome on Android and Safari on iOS. Look at the [compatibility table](https://caniuse.com/web-app-manifest) for more info. - -
diff --git a/docs/subscribe/web.md b/docs/subscribe/web.md index 465a53ee..1508e99f 100644 --- a/docs/subscribe/web.md +++ b/docs/subscribe/web.md @@ -1,49 +1,21 @@ -# Subscribe from the Web UI +# Subscribe from the web app +The web app lets you subscribe and publish messages to ntfy topics. For ntfy.sh, the web app is available at [ntfy.sh/app](https://ntfy.sh/app). +To subscribe, simply type in the topic name and click the *Subscribe* button. **After subscribing, messages published to the topic +will appear in the web app, and pop up as a notification.** -You can use the Web UI to subscribe to topics as well. Simply type in the topic name and click the *Subscribe* button. - -While subscribing, you have the option to enable background notifications on supported browsers. - -- If background notifications are off: - - This requires an active ntfy tab to be open to receive notifications. These are typically instantaneous, and will - appear as a system notification. If you don't see these, check that your browser is allowed to show notifications - (for example in System Settings on macOS). - - If you don't want to enable background notifications, pinning the ntfy tab on your browser is a good solution to leave - it running. - -- If background notifications are on: - - This uses the [Web Push API](https://caniuse.com/push-api). You don't need an active ntfy tab open, but in some - cases you may need to keep your browser open. - - Background notifications are only supported on the same server hosting the web app. You cannot use another server, - but can instead subscribe on the other server itself. - - If the ntfy app is not opened for more than a week, background notifications will be paused. You can resume them - by opening the app again, and will get a warning notification before they are paused. - - | Browser | Platform | Browser Running | Browser Not Running | Restrictions | - | ------- | -------- | --------------- | ------------------- | ------------------------------------------------------- | - | Chrome | Desktop | ✅ | ❌ | | - | Firefox | Desktop | ✅ | ❌ | | - | Edge | Desktop | ✅ | ❌ | | - | Opera | Desktop | ✅ | ❌ | | - | Safari | Desktop | ✅ | ✅ | requires Safari 16.1, macOS 13 Ventura | - | Chrome | Android | ✅ | ✅ | | - | Safari | iOS | ⚠️ | ⚠️ | requires iOS 16.4, only when app is added to homescreen | - - (Browsers below 1% usage not shown, look at the [Push API](https://caniuse.com/push-api) for more info) +
+ +
+## Publish messages To learn how to send messages, check out the [publishing page](../publish.md).
-
+## Topic reservations If topic reservations are enabled, you can claim ownership over topics and define access to it:
@@ -51,9 +23,29 @@ If topic reservations are enabled, you can claim ownership over topics and defin
-You can set your default choice for new subscriptions (for example synced account subscriptions and the default toggle state) -in the settings page: +## Background notifications +While subscribing, you have the option to enable background notifications on supported browsers (see "Settings" tab). -
- -
+**If background notifications are off (default):** This requires an active ntfy tab to be open to receive notifications. +These are typically instantaneous, and will appear as a system notification. If you don't see these, check that your browser +is allowed to show notifications (for example in System Settings on macOS). If you don't want to enable background notifications, +**pinning the ntfy tab on your browser** is a good solution to leave it running. + +**If background notifications are on:** This uses the [Web Push API](https://caniuse.com/push-api). You don't need an active +ntfy tab open, but in some cases you may need to keep your browser open. Background notifications are only supported on the +same server hosting the web app. You cannot use another server, but can instead subscribe on the other server itself. + +If the ntfy app is not opened for more than a week, background notifications will be paused. You can resume them +by opening the app again, and will get a warning notification before they are paused. + +| Browser | Platform | Browser Running | Browser Not Running | Restrictions | +|---------|----------|-----------------|---------------------|---------------------------------------------------------| +| Chrome | Desktop | ✅ | ❌ | | +| Firefox | Desktop | ✅ | ❌ | | +| Edge | Desktop | ✅ | ❌ | | +| Opera | Desktop | ✅ | ❌ | | +| Safari | Desktop | ✅ | ✅ | requires Safari 16.1, macOS 13 Ventura | +| Chrome | Android | ✅ | ✅ | | +| Safari | iOS | ⚠️ | ⚠️ | requires iOS 16.4, only when app is added to homescreen | + +(Browsers below 1% usage not shown, look at the [Push API](https://caniuse.com/push-api) for more info) diff --git a/server/server_web_push.go b/server/server_web_push.go index dee88f4f..0875b94f 100644 --- a/server/server_web_push.go +++ b/server/server_web_push.go @@ -79,18 +79,18 @@ func (s *Server) handleWebPushDelete(w http.ResponseWriter, r *http.Request, _ * func (s *Server) publishToWebPushEndpoints(v *visitor, m *message) { subscriptions, err := s.webPush.SubscriptionsForTopic(m.Topic) if err != nil { - logvm(v, m).Err(err).Warn("Unable to publish web push messages") + logvm(v, m).Err(err).With(v, m).Warn("Unable to publish web push messages") return } + log.Tag(tagWebPush).With(v, m).Debug("Publishing web push message to %d subscribers", len(subscriptions)) payload, err := json.Marshal(newWebPushPayload(fmt.Sprintf("%s/%s", s.config.BaseURL, m.Topic), m)) if err != nil { - log.Tag(tagWebPush).Err(err).Warn("Unable to marshal expiring payload") + log.Tag(tagWebPush).Err(err).With(v, m).Warn("Unable to marshal expiring payload") return } for _, subscription := range subscriptions { - ctx := log.Context{"endpoint": subscription.Endpoint, "username": subscription.UserID, "topic": m.Topic, "message_id": m.ID} - if err := s.sendWebPushNotification(payload, subscription, &ctx); err != nil { - log.Tag(tagWebPush).Err(err).Fields(ctx).Warn("Unable to publish web push message") + if err := s.sendWebPushNotification(subscription, payload, v, m); err != nil { + log.Tag(tagWebPush).Err(err).With(v, m, subscription).Warn("Unable to publish web push message") } } } @@ -125,9 +125,8 @@ func (s *Server) pruneAndNotifyWebPushSubscriptionsInternal() error { } warningSent := make([]*webPushSubscription, 0) for _, subscription := range subscriptions { - ctx := log.Context{"endpoint": subscription.Endpoint} - if err := s.sendWebPushNotification(payload, subscription, &ctx); err != nil { - log.Tag(tagWebPush).Err(err).Fields(ctx).Warn("Unable to publish expiry imminent warning") + if err := s.sendWebPushNotification(subscription, payload); err != nil { + log.Tag(tagWebPush).Err(err).With(subscription).Warn("Unable to publish expiry imminent warning") continue } warningSent = append(warningSent, subscription) @@ -139,7 +138,8 @@ func (s *Server) pruneAndNotifyWebPushSubscriptionsInternal() error { return nil } -func (s *Server) sendWebPushNotification(message []byte, sub *webPushSubscription, ctx *log.Context) error { +func (s *Server) sendWebPushNotification(sub *webPushSubscription, message []byte, contexters ...log.Contexter) error { + log.Tag(tagWebPush).With(sub).With(contexters...).Debug("Sending web push message") resp, err := webpush.SendNotification(message, sub.ToSubscription(), &webpush.Options{ Subscriber: s.config.WebPushEmailAddress, VAPIDPublicKey: s.config.WebPushPublicKey, @@ -148,18 +148,18 @@ func (s *Server) sendWebPushNotification(message []byte, sub *webPushSubscriptio TTL: int(s.config.CacheDuration.Seconds()), }) if err != nil { - log.Tag(tagWebPush).Err(err).Fields(*ctx).Debug("Unable to publish web push message, removing endpoint") + log.Tag(tagWebPush).With(sub).With(contexters...).Err(err).Debug("Unable to publish web push message, removing endpoint") if err := s.webPush.RemoveSubscriptionsByEndpoint(sub.Endpoint); err != nil { return err } return err } if (resp.StatusCode < 200 || resp.StatusCode > 299) && resp.StatusCode != 429 { - log.Tag(tagWebPush).Fields(*ctx).Field("response_code", resp.StatusCode).Debug("Unable to publish web push message, unexpected response") + log.Tag(tagWebPush).With(sub).With(contexters...).Field("response_code", resp.StatusCode).Debug("Unable to publish web push message, unexpected response") if err := s.webPush.RemoveSubscriptionsByEndpoint(sub.Endpoint); err != nil { return err } - return errHTTPInternalErrorWebPushUnableToPublish.Fields(*ctx) + return errHTTPInternalErrorWebPushUnableToPublish.With(sub).With(contexters...) } return nil } diff --git a/server/types.go b/server/types.go index ba00b690..c2ac7bd4 100644 --- a/server/types.go +++ b/server/types.go @@ -521,3 +521,11 @@ func (w *webPushSubscription) ToSubscription() *webpush.Subscription { }, } } + +func (w *webPushSubscription) Context() log.Context { + return map[string]any{ + "web_push_subscription_id": w.ID, + "web_push_subscription_user_id": w.UserID, + "web_push_subscription_endpoint": w.Endpoint, + } +}