Compare commits
12 Commits
v2.0.0
...
http-respo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db1a1fec0c | ||
|
|
7fb6f794e5 | ||
|
|
df68b0cb43 | ||
|
|
ca49fd1161 | ||
|
|
bb3f17ada2 | ||
|
|
d18c61f0da | ||
|
|
92cfc04024 | ||
|
|
2d0ce79011 | ||
|
|
c6e091a754 | ||
|
|
c8c16eb8e6 | ||
|
|
c815b183d4 | ||
|
|
6451762508 |
@@ -1179,9 +1179,9 @@ variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`).
|
|||||||
| `visitor-request-limit-exempt-hosts` | `NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS` | *comma-separated host/IP list* | - | Rate limiting: List of hostnames and IPs to be exempt from request rate limiting |
|
| `visitor-request-limit-exempt-hosts` | `NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS` | *comma-separated host/IP list* | - | Rate limiting: List of hostnames and IPs to be exempt from request rate limiting |
|
||||||
| `visitor-subscription-limit` | `NTFY_VISITOR_SUBSCRIPTION_LIMIT` | *number* | 30 | Rate limiting: Number of subscriptions per visitor (IP address) |
|
| `visitor-subscription-limit` | `NTFY_VISITOR_SUBSCRIPTION_LIMIT` | *number* | 30 | Rate limiting: Number of subscriptions per visitor (IP address) |
|
||||||
| `web-root` | `NTFY_WEB_ROOT` | `app`, `home` or `disable` | `app` | Sets web root to landing page (home), web app (app) or disables the web app entirely (disable) |
|
| `web-root` | `NTFY_WEB_ROOT` | `app`, `home` or `disable` | `app` | Sets web root to landing page (home), web app (app) or disables the web app entirely (disable) |
|
||||||
| `enable-signup` | `NTFY_SIGNUP` | *boolean* (`true` or `false`) | `false` | Allows users to sign up via the web app, or API |
|
| `enable-signup` | `NTFY_ENABLE_SIGNUP` | *boolean* (`true` or `false`) | `false` | Allows users to sign up via the web app, or API |
|
||||||
| `enable-login` | `NTFY_LOGIN` | *boolean* (`true` or `false`) | `false` | Allows users to log in via the web app, or API |
|
| `enable-login` | `NTFY_ENABLE_LOGIN` | *boolean* (`true` or `false`) | `false` | Allows users to log in via the web app, or API |
|
||||||
| `enable-reservations` | `NTFY_RESERVATIONS` | *boolean* (`true` or `false`) | `false` | Allows users to reserve topics (if their tier allows it) |
|
| `enable-reservations` | `NTFY_ENABLE_RESERVATIONS` | *boolean* (`true` or `false`) | `false` | Allows users to reserve topics (if their tier allows it) |
|
||||||
| `stripe-secret-key` | `NTFY_STRIPE_SECRET_KEY` | *string* | - | Payments: Key used for the Stripe API communication, this enables payments |
|
| `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 |
|
| `stripe-webhook-key` | `NTFY_STRIPE_WEBHOOK_KEY` | *string* | - | Payments: Key required to validate the authenticity of incoming webhooks from Stripe |
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ and uptime of third party servers, so use of each server is **at your own discre
|
|||||||
## Projects + scripts
|
## Projects + scripts
|
||||||
|
|
||||||
- [Grafana-to-ntfy](https://github.com/kittyandrew/grafana-to-ntfy) - Grafana-to-ntfy alerts channel (Rust)
|
- [Grafana-to-ntfy](https://github.com/kittyandrew/grafana-to-ntfy) - Grafana-to-ntfy alerts channel (Rust)
|
||||||
|
- [Grafana-ntfy-webhook-integration](https://github.com/academo/grafana-alerting-ntfy-webhook-integration) - Integrates Grafana alerts webhooks (Go)
|
||||||
- [ntfy-long-zsh-command](https://github.com/robfox92/ntfy-long-zsh-command) - Notifies you once a long-running command completes (zsh)
|
- [ntfy-long-zsh-command](https://github.com/robfox92/ntfy-long-zsh-command) - Notifies you once a long-running command completes (zsh)
|
||||||
- [ntfy-shellscripts](https://github.com/nickexyz/ntfy-shellscripts) - A few scripts for the ntfy project (Shell)
|
- [ntfy-shellscripts](https://github.com/nickexyz/ntfy-shellscripts) - A few scripts for the ntfy project (Shell)
|
||||||
- [QuickStatus](https://github.com/corneliusroot/QuickStatus) - A shell script to alert to any immediate problems upon login (Shell)
|
- [QuickStatus](https://github.com/corneliusroot/QuickStatus) - A shell script to alert to any immediate problems upon login (Shell)
|
||||||
@@ -114,6 +115,7 @@ and uptime of third party servers, so use of each server is **at your own discre
|
|||||||
## Blog + forum posts
|
## Blog + forum posts
|
||||||
|
|
||||||
- [Video: Simple Push Notifications ntfy](https://www.youtube.com/watch?v=u9EcWrsjE20) ⭐ - youtube.com - 2/2023
|
- [Video: Simple Push Notifications ntfy](https://www.youtube.com/watch?v=u9EcWrsjE20) ⭐ - youtube.com - 2/2023
|
||||||
|
- [Use ntfy.sh with Home Assistant](https://diecknet.de/en/2023/02/12/ntfy-sh-with-homeassistant/) - diecknet.de - 2/2023
|
||||||
- [On installe Ntfy sur Synology Docker](https://www.maison-et-domotique.com/140356-serveur-notification-jeedom-ntfy-synology-docker/) - maison-et-domotique.co - 1/2023
|
- [On installe Ntfy sur Synology Docker](https://www.maison-et-domotique.com/140356-serveur-notification-jeedom-ntfy-synology-docker/) - maison-et-domotique.co - 1/2023
|
||||||
- [January 2023 Developer Update](https://community.nodebb.org/topic/16908/january-2023-developer-update) - nodebb.org - 1/2023
|
- [January 2023 Developer Update](https://community.nodebb.org/topic/16908/january-2023-developer-update) - nodebb.org - 1/2023
|
||||||
- [Comment envoyer des notifications push sur votre téléphone facilement et gratuitement?](https://korben.info/notifications-push-telephone.html) - 1/2023
|
- [Comment envoyer des notifications push sur votre téléphone facilement et gratuitement?](https://korben.info/notifications-push-telephone.html) - 1/2023
|
||||||
|
|||||||
@@ -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)
|
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).
|
and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/releases).
|
||||||
|
|
||||||
## ntfy server v2.0.0 (UNRELEASED)
|
## ntfy server v2.0.0
|
||||||
Released February 16, 2023
|
Released February 16, 2023
|
||||||
|
|
||||||
This is the biggest ntfy server release I've ever done 🥳 . Lots of new and exciting features.
|
This is the biggest ntfy server release I've ever done 🥳 . Lots of new and exciting features.
|
||||||
|
|||||||
@@ -291,6 +291,7 @@ func (s *Server) closeDatabases() {
|
|||||||
|
|
||||||
// handle is the main entry point for all HTTP requests
|
// handle is the main entry point for all HTTP requests
|
||||||
func (s *Server) handle(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handle(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w = newHTTPResponseWriter(w) // Avoid logging "superfluous response.WriteHeader call" warning
|
||||||
v, err := s.maybeAuthenticate(r) // Note: Always returns v, even when error is returned
|
v, err := s.maybeAuthenticate(r) // Note: Always returns v, even when error is returned
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.handleError(w, r, v, err)
|
s.handleError(w, r, v, err)
|
||||||
|
|||||||
@@ -1498,7 +1498,7 @@ func TestServer_PublishAttachmentTooLargeBodyVisitorAttachmentTotalSizeLimit(t *
|
|||||||
c.VisitorAttachmentTotalSizeLimit = 10000
|
c.VisitorAttachmentTotalSizeLimit = 10000
|
||||||
s := newTestServer(t, c)
|
s := newTestServer(t, c)
|
||||||
|
|
||||||
response := request(t, s, "PUT", "/mytopic", util.RandomString(5000), nil)
|
response := request(t, s, "PUT", "/mytopic", "text file!"+util.RandomString(4990), nil)
|
||||||
msg := toMessage(t, response.Body.String())
|
msg := toMessage(t, response.Body.String())
|
||||||
require.Equal(t, 200, response.Code)
|
require.Equal(t, 200, response.Code)
|
||||||
require.Equal(t, "You received a file: attachment.txt", msg.Message)
|
require.Equal(t, "You received a file: attachment.txt", msg.Message)
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"heckel.io/ntfy/util"
|
"heckel.io/ntfy/util"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func readBoolParam(r *http.Request, defaultValue bool, names ...string) bool {
|
func readBoolParam(r *http.Request, defaultValue bool, names ...string) bool {
|
||||||
@@ -85,3 +88,57 @@ func readJSONWithLimit[T any](r io.ReadCloser, limit int, allowEmpty bool) (*T,
|
|||||||
}
|
}
|
||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type httpResponseWriter struct {
|
||||||
|
w http.ResponseWriter
|
||||||
|
headerWritten bool
|
||||||
|
mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type httpResponseWriterWithHijacker struct {
|
||||||
|
httpResponseWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ http.ResponseWriter = (*httpResponseWriter)(nil)
|
||||||
|
var _ http.Flusher = (*httpResponseWriter)(nil)
|
||||||
|
var _ http.Hijacker = (*httpResponseWriterWithHijacker)(nil)
|
||||||
|
|
||||||
|
func newHTTPResponseWriter(w http.ResponseWriter) http.ResponseWriter {
|
||||||
|
if _, ok := w.(http.Hijacker); ok {
|
||||||
|
return &httpResponseWriterWithHijacker{httpResponseWriter: httpResponseWriter{w: w}}
|
||||||
|
}
|
||||||
|
return &httpResponseWriter{w: w}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *httpResponseWriter) Header() http.Header {
|
||||||
|
return w.w.Header()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *httpResponseWriter) Write(bytes []byte) (int, error) {
|
||||||
|
w.mu.Lock()
|
||||||
|
w.headerWritten = true
|
||||||
|
w.mu.Unlock()
|
||||||
|
return w.w.Write(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *httpResponseWriter) WriteHeader(statusCode int) {
|
||||||
|
w.mu.Lock()
|
||||||
|
if w.headerWritten {
|
||||||
|
w.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.headerWritten = true
|
||||||
|
w.mu.Unlock()
|
||||||
|
w.w.WriteHeader(statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *httpResponseWriter) Flush() {
|
||||||
|
if f, ok := w.w.(http.Flusher); ok {
|
||||||
|
f.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *httpResponseWriterWithHijacker) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
|
h, _ := w.w.(http.Hijacker)
|
||||||
|
return h.Hijack()
|
||||||
|
}
|
||||||
|
|||||||
45
web/public/static/langs/ar.json
Normal file
45
web/public/static/langs/ar.json
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"action_bar_logo_alt": "شعار ntfy",
|
||||||
|
"action_bar_settings": "اﻹعدادات",
|
||||||
|
"action_bar_clear_notifications": "محو كافة الإشعارات",
|
||||||
|
"action_bar_unsubscribe": "إلغاء الاشتراك",
|
||||||
|
"message_bar_show_dialog": "إظهار مربع حوار النشر",
|
||||||
|
"message_bar_publish": "نشر الرسالة",
|
||||||
|
"nav_topics_title": "المواضيع التي تم الاشتراك فيها",
|
||||||
|
"nav_button_all_notifications": "كافة الإشعارات",
|
||||||
|
"nav_button_settings": "اﻹعدادات",
|
||||||
|
"nav_button_documentation": "الدليل",
|
||||||
|
"nav_button_publish_message": "نشر الإشعار",
|
||||||
|
"nav_button_subscribe": "اشترك في الموضوع",
|
||||||
|
"nav_button_connecting": "جارٍ الاتصال",
|
||||||
|
"alert_grant_title": "تم تعطيل الإشعارات",
|
||||||
|
"alert_grant_description": "امنح متصفحك الإذن لعرض إشعارات سطح المكتب.",
|
||||||
|
"notifications_list": "قائمة الإشعارات",
|
||||||
|
"notifications_list_item": "إشعار",
|
||||||
|
"notifications_mark_read": "وضع علامة كمقروء",
|
||||||
|
"notifications_tags": "الوسوم",
|
||||||
|
"notifications_priority_x": "الأولوية {{priority}}",
|
||||||
|
"notifications_new_indicator": "إشعار جديد",
|
||||||
|
"notifications_attachment_image": "صورة مرفقة",
|
||||||
|
"notifications_attachment_copy_url_button": "نسخ عنوان URL",
|
||||||
|
"notifications_attachment_open_title": "انتقل إلى {{url}}",
|
||||||
|
"notifications_attachment_link_expires": "تنتهي صلاحية الرابط {{date}}",
|
||||||
|
"notifications_attachment_link_expired": "انتهت صلاحية رابط التنزيل",
|
||||||
|
"notifications_attachment_file_image": "ملف الصورة",
|
||||||
|
"notifications_attachment_file_video": "ملف فيديو",
|
||||||
|
"notifications_attachment_file_audio": "ملف صوتي",
|
||||||
|
"notifications_attachment_file_app": "ملف تطبيق Android",
|
||||||
|
"notifications_attachment_file_document": "وثيقة أخرى",
|
||||||
|
"notifications_click_copy_url_button": "نسخ الرابط",
|
||||||
|
"notifications_click_open_button": "فتح الرابط",
|
||||||
|
"notifications_actions_open_url_title": "انتقل إلى {{url}}",
|
||||||
|
"notifications_actions_not_supported": "هذا الإجراء غير مدعوم في تطبيق الويب",
|
||||||
|
"action_bar_send_test_notification": "إرسال إشعار للاختبار",
|
||||||
|
"action_bar_show_menu": "عرض القائمة",
|
||||||
|
"message_bar_type_message": "اكتب رسالة هنا",
|
||||||
|
"alert_not_supported_title": "الإشعارات غير مدعومة",
|
||||||
|
"alert_not_supported_description": "الإشعارات غير مدعومة في متصفحك.",
|
||||||
|
"message_bar_error_publishing": "خطأ أثناء نشر الإشعار",
|
||||||
|
"notifications_delete": "حذف",
|
||||||
|
"notifications_copied_to_clipboard": "تم نسخه إلى الحافظة"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user