Compare commits

..

1334 Commits

Author SHA1 Message Date
Philipp C. Heckel
a0ebd64461 Merge pull request #1551 from mshafer1/dev/update_link_to_ntfysh-windows
Update link to ntfysh-windows client
2026-01-17 12:20:09 -05:00
Maker By Night
dafd130fe5 Update link to ntfysh-windows client
Since lucas-bortoli marked the original project as archived/abandoned, I intend to continue maintenance on my fork. Therefore, updating the integration link to point to it.
2026-01-17 10:03:29 -06:00
binwiederhier
11e9e1e6a0 Merge branch 'feature/twilio-call-format-file' 2026-01-17 05:00:03 -05:00
binwiederhier
b23f6632b1 Use Go templates, update docs 2026-01-17 04:59:46 -05:00
binwiederhier
6bacf7dafc Works 2026-01-17 04:34:32 -05:00
binwiederhier
0e200b96e0 Merge branch 'main' of github.com:binwiederhier/ntfy into feature/twilio-call-format-file 2026-01-17 03:49:52 -05:00
binwiederhier
3ce56879ae Tidy 2026-01-17 03:49:33 -05:00
binwiederhier
48efdffa57 Fix indent 2026-01-17 03:29:40 -05:00
Philipp C. Heckel
9135bb277b Merge pull request #1534 from Pixelguin/feat/ws-permissions-note
Add troubleshooting steps for "Reconnecting" error on mobile
2026-01-17 03:21:07 -05:00
binwiederhier
711899ad35 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2026-01-17 03:20:47 -05:00
binwiederhier
01435d5fea Bump 2026-01-17 03:20:41 -05:00
Philipp C. Heckel
8ce2188b28 Merge pull request #1536 from binwiederhier/303-update-notifications
Update/delete/clear notifications
2026-01-16 10:10:50 -05:00
binwiederhier
c1ee163cab Remove cache thing 2026-01-16 10:07:09 -05:00
binwiederhier
fcf57a04e1 Move event up 2026-01-16 09:36:27 -05:00
binwiederhier
0ad06e808f Self-review 2026-01-15 22:14:56 -05:00
binwiederhier
2cc4bf7d28 Fix webpush stuff 2026-01-15 21:55:20 -05:00
binwiederhier
5ae3774f19 Refine, docs 2026-01-15 19:06:05 -05:00
binwiederhier
94eb121f38 Docs updates 2026-01-15 13:07:07 -05:00
binwiederhier
e81be48bf3 MOre docs update 2026-01-15 10:32:48 -05:00
binwiederhier
db4a4776d3 Reword 2026-01-15 10:07:05 -05:00
binwiederhier
3d54260f79 Docs 2026-01-15 09:30:37 -05:00
waclaw66
a712d78e4c Translated using Weblate (Czech)
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/cs/
2026-01-15 14:01:47 +01:00
binwiederhier
ea3008c707 Move, add screenshots 2026-01-14 22:18:57 -05:00
binwiederhier
2e39a1329c AI docs, needs work 2026-01-14 21:48:21 -05:00
binwiederhier
ff2b8167b4 Make closing notifications work 2026-01-14 21:17:21 -05:00
binwiederhier
96638b516c Fix service worker handling for updating/deleting 2026-01-14 20:46:18 -05:00
binwiederhier
dd9b36cf0a Fix db crash 2026-01-13 21:29:44 -05:00
binwiederhier
44f20f6b4c Add tests, fix firebase 2026-01-13 20:50:31 -05:00
binwiederhier
a3c16d81f8 Rename to clear 2026-01-13 16:31:13 -05:00
cyberboh
c0a5a1fb35 Translated using Weblate (Indonesian)
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/id/
2026-01-13 10:30:17 +01:00
binwiederhier
b5f24b12dc Merge branch 'main' of github.com:binwiederhier/ntfy into 303-update-notifications 2026-01-12 21:38:55 -05:00
binwiederhier
898a52ec63 Merge branch 'main' of github.com:binwiederhier/ntfy 2026-01-11 09:27:01 -05:00
binwiederhier
7066ba92a6 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2026-01-11 09:26:58 -05:00
binwiederhier
8960459520 Changelog 2026-01-11 09:26:44 -05:00
Kristijan \"Fremen\" Velkovski
f581af6d27 Translated using Weblate (Macedonian)
Currently translated at 23.0% (94 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/mk/
2026-01-11 07:01:51 +00:00
Shoshin Akamine
88016a2549 Translated using Weblate (Japanese)
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ja/
2026-01-11 07:01:49 +00:00
大王叫我来巡山
a7603d1dfb Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/zh_Hans/
2026-01-11 07:01:47 +00:00
Philipp C. Heckel
65e2af9efb Merge pull request #1542 from ecntu/fix-typos
fix typos in docs
2026-01-10 22:29:22 -05:00
Emilio Cantú
090cd720c1 fix typos 2026-01-10 22:03:41 -05:00
binwiederhier
7bc8edf7c3 Bump, release notes 2026-01-10 20:47:59 -05:00
Kristijan \"Fremen\" Velkovski
13768d4289 Translated using Weblate (Macedonian)
Currently translated at 16.4% (67 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/mk/
2026-01-10 05:01:49 +01:00
binwiederhier
37d71051de Refine 2026-01-08 20:57:55 -05:00
binwiederhier
5ad3de2904 Switch to event type 2026-01-08 20:50:23 -05:00
binwiederhier
66ea25c18b Add JSON publishing support 2026-01-08 15:45:50 -05:00
binwiederhier
1ab7ca876c Rename to sequence_id 2026-01-08 14:27:18 -05:00
binwiederhier
fd8cd5ca91 Comment 2026-01-08 13:45:05 -05:00
binwiederhier
7cffbfcd6d Simplify handleNotifications 2026-01-08 13:43:57 -05:00
binwiederhier
dffee9ea7d Remove forJSON 2026-01-08 11:39:32 -05:00
binwiederhier
239959e2a4 Revert some changes; make poller respect deleteAfter pref 2026-01-08 11:19:53 -05:00
binwiederhier
75abf2e245 Delete old messages with SID when new messages arrive 2026-01-08 10:28:02 -05:00
binwiederhier
bfbe73aea3 Update polling 2026-01-07 09:46:08 -05:00
Kristijan \"Fremen\" Velkovski
b3721c1b71 Translated using Weblate (Macedonian)
Currently translated at 14.7% (60 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/mk/
2026-01-07 14:01:52 +00:00
cyberboh
544f7ef1cb Translated using Weblate (Indonesian)
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/id/
2026-01-07 14:01:47 +00:00
binwiederhier
2dd152df3f Manual fixes for AI slop 2026-01-06 18:02:08 -05:00
binwiederhier
2856793eff Deleted 2026-01-06 14:22:55 -05:00
Kristijan \"Fremen\" Velkovski
16bec00b38 Translated using Weblate (Macedonian)
Currently translated at 13.5% (55 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/mk/
2026-01-06 06:01:47 +00:00
binwiederhier
f51e99dc80 Remove modified 2026-01-05 21:55:07 -05:00
binwiederhier
aca9a77498 Remove mtime 2026-01-05 21:14:29 -05:00
binwiederhier
1c2550d749 Merge branch 'main' into 303-update-notifications 2026-01-05 15:34:42 -05:00
Pixelguin
1c32ee7613 Clarify wording 2026-01-05 08:36:56 -08:00
Pixelguin
f356309f70 Clarify up* r/w permissions 2026-01-05 08:13:53 -08:00
Pixelguin
39936a95f8 Add troubleshooting steps for "Reconnecting" error on mobile 2026-01-05 08:11:20 -08:00
binwiederhier
e18d64933f Release notes 2026-01-04 10:57:11 -05:00
josé m.
20ccee5d7d Translated using Weblate (Galician)
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/gl/
2026-01-04 16:01:47 +01:00
binwiederhier
3575abcde3 Restructure contact page 2026-01-02 08:10:34 -05:00
binwiederhier
2cd444ece0 Contact page 2026-01-02 08:05:39 -05:00
binwiederhier
eca1ed4d8d Contact and contributing page 2026-01-02 07:59:02 -05:00
binwiederhier
4ce9508fd3 Privacy policy commit history 2026-01-02 07:44:39 -05:00
binwiederhier
4f9f1292f1 Update privacy policy 2026-01-02 07:35:06 -05:00
binwiederhier
d64376c5ac Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2026-01-01 21:49:37 -05:00
binwiederhier
275487b3fd Release notes 2026-01-01 21:49:26 -05:00
ezn24
9301546e6d Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/zh_Hant/
2026-01-01 20:01:47 +01:00
大王叫我来巡山
49b3c724cf Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/zh_Hans/
2025-12-31 15:03:58 +01:00
Philipp C. Heckel
7091775234 Merge pull request #1527 from cbrake/main
add BRun to list of integrations
2025-12-30 17:24:41 -05:00
Cliff Brake
90667e7176 add BRun to list of integrations 2025-12-30 17:19:07 -05:00
Philipp C. Heckel
414bbb0171 Merge pull request #1509 from mikaeldui/patch-1
Add Ferron reverse proxy example to config.md
2025-12-30 10:12:07 -05:00
binwiederhier
6e6d35157d Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2025-12-30 10:07:05 -05:00
binwiederhier
c0f57a448d Document ?display= parameter, update changelog 2025-12-30 10:06:47 -05:00
Eskuero
b348bce06e Translated using Weblate (Spanish)
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/es/
2025-12-30 13:00:28 +01:00
Priit Jõerüüt
06577c99f2 Translated using Weblate (Estonian)
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/et/
2025-12-30 13:00:27 +01:00
luneth
f48a9aef2c Translated using Weblate (French)
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fr/
2025-12-30 13:00:26 +01:00
Kachelkaiser
293dda3e79 Translated using Weblate (German)
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2025-12-30 13:00:24 +01:00
109247019824
f52b29931f Translated using Weblate (Bulgarian)
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/bg/
2025-12-30 13:00:23 +01:00
Shoshin Akamine
3dea1b12cf Translated using Weblate (Japanese)
Currently translated at 100.0% (407 of 407 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ja/
2025-12-30 13:00:22 +01:00
binwiederhier
d83be77727 Release notes 2025-12-29 21:07:31 -05:00
binwiederhier
6215113c91 Release notes 2025-12-29 16:58:22 -05:00
binwiederhier
954ac89b51 Release notes 2025-12-28 20:20:26 -05:00
binwiederhier
76fbe19fd1 Release notes 2025-12-28 12:48:55 -05:00
binwiederhier
b27c4cf95d Release notes 2025-12-26 13:20:20 -05:00
binwiederhier
d915552788 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2025-12-23 20:23:57 -05:00
binwiederhier
c66ad4d7e3 Merge branch 'main' of github.com:binwiederhier/ntfy 2025-12-23 20:23:55 -05:00
binwiederhier
152a6b96d1 Run go fix 2025-12-23 20:23:48 -05:00
Philipp C. Heckel
f642b09ebf Merge pull request #1501 from aerusso/mrs/nofirebase-fbsend
do not build fbsend with nofirebase
2025-12-23 20:21:19 -05:00
Philipp C. Heckel
ec414d29be Merge pull request #1499 from khazit/patch-1
Add Simple Observability to integrations list
2025-12-23 20:20:29 -05:00
Philipp C. Heckel
0fbd3e33f3 Merge pull request #1518 from faytecCD/patch-1
Fix filter api example
2025-12-23 20:15:14 -05:00
binwiederhier
17870cb471 Fix use of deprecated secrets file 2025-12-21 21:37:55 -05:00
binwiederhier
4e03c96108 Bump release notes 2025-12-21 21:02:02 -05:00
luneth
6cacdd47f2 Translated using Weblate (French)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fr/
2025-12-21 21:00:21 +01:00
binwiederhier
a380860cab Bump 2025-12-20 20:53:18 -05:00
binwiederhier
7f842eaeb1 Release notes 2025-12-20 20:50:11 -05:00
binwiederhier
3e019bfe88 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2025-12-20 20:11:21 -05:00
faytecCD
430135606b Fix filter api example 2025-12-18 16:03:24 +08:00
Philipp C. Heckel
62a79d9802 Merge pull request #1517 from lukestein/lukestein-docs-corrections
Fix formatting in Python example in publish.md
2025-12-17 15:24:08 -05:00
Luke Stein
d9d02dbbc1 Fix formatting in Python example in publish.md 2025-12-17 14:56:59 -05:00
Albert Cervera i Areny
e0a9e3aa56 Translated using Weblate (Catalan)
Currently translated at 3.4% (14 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ca/
2025-12-17 19:00:19 +01:00
Philipp C. Heckel
ce878a5d03 Merge pull request #1505 from eliecharra/patch-1
docs: fix typo on `listen-metrics-http`
2025-12-11 11:16:46 -05:00
Mikael Dúi Bolinder
43fe1b9ad8 Add Ferron reverse proxy example 2025-12-07 17:57:29 +02:00
Elie CHARRA
b59f451c6a docs: fix typo on listen-metrics-http
The correct option is `metrics-listen-http`
2025-12-03 19:41:42 +01:00
Antonio Enrico Russo
693d2d630f do not build fbsend with nofirebase
The nofirebase build tag should remove all build dependencies on
firebase.  The fbsend test tool depends on firebase (and is also only
useful in builds that use firebase).  Hence, disable it.

Signed-off-by: Antonio Enrico Russo <aerusso@aerusso.net>
2025-11-28 09:24:44 -07:00
Ali Benkassou
025c2963a0 Add Simple Observability to integrations list 2025-11-25 17:45:40 +01:00
liilliil
76bf4a3de7 Translated using Weblate (Slavonic (Old Church))
Currently translated at 1.4% (6 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/cu/
2025-11-23 10:51:16 +00:00
liilliil
b7ae47d61c Added translation using Weblate (Slavonic (Old Church)) 2025-11-22 11:05:36 +01:00
liilliil
4fa265ed28 Translated using Weblate (Esperanto)
Currently translated at 0.7% (3 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/eo/
2025-11-22 11:05:36 +01:00
binwiederhier
b531bc95ea Grr 2025-11-16 13:43:18 -05:00
binwiederhier
da6f6f528c Bump install and release notes 2025-11-16 13:39:50 -05:00
binwiederhier
926d8b981b Set "require_login: false" for dev 2025-11-16 13:35:43 -05:00
binwiederhier
997923dd98 Update Android release notes 2025-11-16 12:55:16 -05:00
binwiederhier
8131d0d883 Bump 2025-11-16 12:36:35 -05:00
binwiederhier
a326dc034f Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2025-11-16 11:38:24 -05:00
Philipp C. Heckel
736905c1e8 Merge pull request #1476 from leukosaima/patch-1
Update ntfyrr, add ntailfy in integrations.md
2025-11-16 11:35:43 -05:00
Philipp C. Heckel
857d56c281 Merge pull request #1486 from songe/fix-cropped-card-action
fix: show overflow notification action buttons hidden on small screens
2025-11-16 11:35:10 -05:00
Angie Song
cef61b2c48 fix: show overflow notification action buttons hidden on small screens
by setting `overflow-x: auto`
2025-11-14 15:21:47 -08:00
Philipp C. Heckel
b483891bcb Update README.md 2025-10-30 19:35:55 -04:00
leukosaima
bb9bbdf736 Update ntfyrr, add ntailfy in integrations.md 2025-10-26 13:00:38 -04:00
Priit Jõerüüt
9e1636a3f7 Translated using Weblate (Estonian)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/et/
2025-10-25 15:02:43 +02:00
Kristijan \"Fremen\" Velkovski
315326ffc0 Translated using Weblate (Macedonian)
Currently translated at 12.8% (52 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/mk/
2025-10-22 00:02:49 +02:00
Priit Jõerüüt
65188b1f07 Translated using Weblate (Estonian)
Currently translated at 94.5% (383 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/et/
2025-10-22 00:02:47 +02:00
Philipp C. Heckel
5fefcd1296 Update Warp link in README.md 2025-10-21 09:25:56 -04:00
binwiederhier
4c4a5725d8 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2025-10-21 05:55:09 -04:00
binwiederhier
ab2a686937 Deps 2025-10-21 05:54:17 -04:00
binwiederhier
01bb0eeccd Link Warp in Sponsors section 2025-10-21 05:42:39 -04:00
Philipp C. Heckel
7cabc8bcec Add Warp as sponsor
Added sponsorship section and updated project description.
2025-10-21 05:36:06 -04:00
Ryu Siwoo
95f4e58ca0 Translated using Weblate (Korean)
Currently translated at 46.6% (189 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ko/
2025-10-20 06:51:45 +02:00
109247019824
692a1fa532 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/bg/
2025-10-20 06:51:43 +02:00
Hunter Kehoe
8293a24cf9 update notification text using sid in web app 2025-10-17 22:10:11 -06:00
Hunter Kehoe
83b5470bc5 publish messages with a custom sequence ID 2025-10-17 19:01:41 -06:00
Hunter Kehoe
2aae3577cb add sid, mtime, and deleted to message_cache 2025-10-17 17:39:55 -06:00
Philipp C. Heckel
54ded9db9a Merge pull request #1460 from EifX/fix/healtcheck
docs: fix healthcheck zombie processes
2025-10-13 09:37:23 -04:00
Kristijan \"Fremen\" Velkovski
db2b3a0dd8 Translated using Weblate (Macedonian)
Currently translated at 9.6% (39 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/mk/
2025-10-12 07:15:03 +02:00
Kristijan \"Fremen\" Velkovski
0b4bcf573e Translated using Weblate (Macedonian)
Currently translated at 4.4% (18 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/mk/
2025-10-11 04:07:25 +00:00
ezn24
f9a88f841e Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/zh_Hant/
2025-10-11 04:07:24 +00:00
Kristijan \"Fremen\" Velkovski
c4291cc23e Added translation using Weblate (Macedonian) 2025-10-10 05:07:31 +02:00
Alexander Eifler
fd0595b547 docs: fix healthcheck zombies 2025-10-08 21:52:49 +02:00
Enis Polat
b59e18bed8 Translated using Weblate (Turkish)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/tr/
2025-10-07 18:02:00 +00:00
Liviu Roman
1956ffbf02 Translated using Weblate (Romanian)
Currently translated at 89.3% (362 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ro/
2025-09-29 21:54:06 +02:00
Gringo
e647c68cb9 Translated using Weblate (Italian)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2025-09-29 21:54:05 +02:00
Gringo
53dce3013d Translated using Weblate (Italian)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2025-09-27 01:02:00 +02:00
Philipp C. Heckel
7615aa86ad Change supported platforms for Markdown in publish.md
Updated supported platforms for Markdown formatting.
2025-09-24 20:46:30 -04:00
binwiederhier
07ef3e5656 Release notes 2025-09-23 22:51:06 -04:00
binwiederhier
2804acf0f5 Update repository docs 2025-09-23 22:46:23 -04:00
Philipp C. Heckel
498b632796 Merge pull request #1446 from alexgaudon/add-ntfy-bridge
Added ntfy-bridge to integrations.md
2025-09-23 14:24:30 -04:00
Alex Gaudon
61e496fc4c Save without formatting 2025-09-23 15:11:03 -02:30
Alex Gaudon
83e74b014e Revert "Added ntfy-bridge to integrations.md"
This reverts commit 546c94ba98.
2025-09-23 15:10:46 -02:30
Philipp C. Heckel
364696e059 Remove F-Droid upgrade warning for ntfy
Removed warning about broken ntfy version on F-Droid and related instructions.
2025-09-23 12:34:28 -04:00
Alex Gaudon
546c94ba98 Added ntfy-bridge to integrations.md 2025-09-23 13:06:32 -02:30
binwiederhier
203d739d38 Add certificate fingerprint 2025-09-23 10:12:36 -04:00
cyberboh
89fd37bc2c Translated using Weblate (Indonesian)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/id/
2025-09-22 05:01:59 +02:00
binwiederhier
7856ab5dfb Bump 2025-09-21 19:55:06 -04:00
binwiederhier
773be05bb1 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2025-09-21 19:36:15 -04:00
binwiederhier
c1a6e9a429 Merge branch 'main' of github.com:binwiederhier/ntfy 2025-09-21 19:36:12 -04:00
Philipp C. Heckel
c9a0a40805 Add warning for ntfy 1.17.0 on F-Droid
Added warning about broken ntfy version on F-Droid and provided alternatives for users.
2025-09-20 10:54:06 -04:00
binwiederhier
439049624c Update changelog for Android app 2025-09-19 20:25:50 -04:00
Suthep Yonphimai
a6078037c0 Translated using Weblate (Thai)
Currently translated at 13.3% (54 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/th/
2025-09-16 04:02:11 +02:00
Suthep Yonphimai
9c5c17441f Added translation using Weblate (Thai) 2025-09-15 03:21:11 +02:00
Hoàng Hải
b56d250708 Translated using Weblate (Vietnamese)
Currently translated at 24.4% (99 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/vi/
2025-09-15 03:21:10 +02:00
Priit Jõerüüt
a714fe2618 Translated using Weblate (Estonian)
Currently translated at 79.2% (321 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/et/
2025-09-12 22:01:59 +02:00
Priit Jõerüüt
e863872d0e Translated using Weblate (Estonian)
Currently translated at 75.5% (306 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/et/
2025-09-06 13:01:54 +02:00
LucasMZ
77406f3496 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt_BR/
2025-09-06 13:01:52 +02:00
Philipp C. Heckel
157add4835 Merge pull request #1434 from binwiederhier/require-login
Require login
2025-08-24 21:19:34 -04:00
binwiederhier
50f3563477 Docs 2025-08-24 21:18:28 -04:00
binwiederhier
e08f3670d1 Fix lint 2025-08-24 13:58:57 -04:00
binwiederhier
4f6f45a9c0 Checks 2025-08-24 13:52:04 -04:00
binwiederhier
3de04b27ab Redirect to login page if require-login is enabled 2025-08-24 13:48:19 -04:00
binwiederhier
ec1f97b726 Merge remote-tracking branch 'theatischbein/feat_optional_require_login' into require-login 2025-08-24 13:34:22 -04:00
binwiederhier
569d89e8f8 Require login 2025-08-24 13:33:16 -04:00
binwiederhier
f2f146e39b Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2025-08-24 13:19:49 -04:00
Philipp C. Heckel
18d08298cc Merge pull request #1432 from binwiederhier/http-clipboard
Fix copy to clipboard on HTTP-only hosted sites
2025-08-24 07:46:20 -04:00
binwiederhier
ebb386af58 Release notes 2025-08-24 07:44:06 -04:00
binwiederhier
b105ed6727 Fix copy to clipboard on HTTP-only hosted sites 2025-08-24 07:42:39 -04:00
Philipp C. Heckel
1916376f8d Merge pull request #1428 from Max-Pare/main
fixed typo in "client.yml" comment
2025-08-24 07:11:32 -04:00
Philipp C. Heckel
965110b2c3 Merge pull request #1430 from hxtmdev/patch-1
Fix base64 snippets in Publishing
2025-08-23 10:44:17 -04:00
Daniel Höxtermann
c8ac104043 Fix base64 snippets in Publishing
-w0 is usually needed for longer outputs
2025-08-23 16:34:50 +02:00
Max-Pare
f6bd0a8d51 fixed typo 2025-08-21 00:05:05 +02:00
Philipp C. Heckel
e39498702d Merge pull request #1425 from DerRockWolf/docs/integrations/heartbeat-monitor
feat(docs): add ntfy-heartbeat-monitor to integrations page
2025-08-17 08:47:26 -04:00
RockWolf
9b97067b10 feat(docs): add ntfy-heartbeat-monitor to integrations page 2025-08-17 13:44:57 +02:00
ssantos
f72f0d800f Translated using Weblate (Portuguese)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt/
2025-08-12 18:02:13 +02:00
binwiederhier
5244e0be14 Fix tests 2025-08-09 10:04:57 -04:00
binwiederhier
6eb25f68ac Update password hash docs, add more validation on password hash 2025-08-09 07:34:19 -04:00
Philipp C. Heckel
efe7c3fa70 Merge pull request #1399 from orblivion/patch-1
Add Ntfy for Sandstorm to integrations.md
2025-08-08 22:21:43 +02:00
Philipp C. Heckel
ce4b2ae9a0 Merge pull request #1421 from binwiederhier/message-cache-lock
Message cache lock
2025-08-08 22:19:24 +02:00
binwiederhier
ba86e08ffe Release notes 2025-08-08 16:19:02 -04:00
binwiederhier
2d9e2356b1 Release notes 2025-08-08 16:13:39 -04:00
binwiederhier
fe5c844a21 Add test 2025-08-08 16:10:49 -04:00
binwiederhier
97410db301 Merge remote-tracking branch 'timofej673/main' into message-cache-lock 2025-08-08 16:06:27 -04:00
binwiederhier
887751cd5d Release notes 2025-08-08 15:34:30 -04:00
Philipp C. Heckel
044326068c Merge pull request #1420 from binwiederhier/debian-stripe
WIP: Add build flags to remove Firebase, Stripe & WebPush (for Debian packaging)
2025-08-08 21:27:22 +02:00
binwiederhier
57a51ab2da Fix tests 2025-08-08 15:16:53 -04:00
binwiederhier
998dbd9054 Undo main.go 2025-08-08 15:02:09 -04:00
binwiederhier
a5a55bd43a Move WebPush tests 2025-08-07 18:54:37 +02:00
binwiederhier
00409d834b Add build flag for webpush 2025-08-07 18:31:42 +02:00
binwiederhier
d9ab7cc78d Add "nowebpush" build tag 2025-08-07 17:39:25 +02:00
binwiederhier
99a2ca8802 Add build tags for Firebase 2025-08-07 17:24:57 +02:00
binwiederhier
ea338ae4fa Make it easy to build without Stripe 2025-08-07 16:41:39 +02:00
binwiederhier
32fa8d43c1 Merge branch 'main' into debian-stripe 2025-08-07 15:34:54 +02:00
Philipp C. Heckel
0f166e0a1d Merge pull request #1417 from orblivion/patch-2
Typo in publish.md
2025-08-05 21:13:39 +02:00
Daniel Krol
46e423fc40 Typo in publish.md 2025-08-05 14:39:57 -04:00
Philipp C. Heckel
eac523dcf9 Merge pull request #1413 from wunter8/change-password-provisioned-user
prevent changing a provisioned user's password
2025-08-05 10:19:45 +02:00
binwiederhier
4225ce2f42 Release notes 2025-08-05 10:12:53 +02:00
binwiederhier
d35dfc14d1 Bump release notes and such 2025-08-05 10:09:58 +02:00
binwiederhier
cef228f880 Derp 2025-08-05 10:01:21 +02:00
binwiederhier
bcfb50b35a Disallow changing provisioned user and tokens 2025-08-05 09:59:23 +02:00
binwiederhier
c4c4916bc8 Do not allow changing tokens, user role, or delete users 2025-08-04 22:22:59 +02:00
Hunter Kehoe
81463614c9 prevent changing a provisioned user's password 2025-08-03 16:07:24 -06:00
binwiederhier
15a7f86344 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2025-07-31 12:59:49 +02:00
Philipp C. Heckel
3c1da90f47 Merge pull request #1384 from binwiederhier/predefined-users
Declarative users
2025-07-31 11:42:32 +02:00
binwiederhier
27151d1cac Fix tests 2025-07-31 11:35:21 +02:00
binwiederhier
a1c6dd2085 Comments 2025-07-31 11:28:27 +02:00
binwiederhier
8f930acfb8 Docs 2025-07-31 11:20:03 +02:00
binwiederhier
08d44703c3 Tiny fixes 2025-07-31 10:46:41 +02:00
binwiederhier
82282419fe Self-review 2025-07-31 10:34:02 +02:00
binwiederhier
e290d1307f Tests 2025-07-31 10:26:53 +02:00
binwiederhier
747c5c9fff Docs 2025-07-31 10:08:25 +02:00
binwiederhier
9f987e66fa Make sure tokens are updated instead of deleted/re-added 2025-07-31 08:36:05 +02:00
binwiederhier
b91ff5f0b5 Move stuff to util.go 2025-07-31 07:33:11 +02:00
binwiederhier
23ec7702fc Add "auth-tokens" 2025-07-31 07:08:35 +02:00
timof
f8082d9481 Update message_cache.go 2025-07-30 00:12:45 +04:00
timof
d9ecee7200 Merge branch 'binwiederhier:main' into main 2025-07-28 10:37:31 +04:00
binwiederhier
149c13e9d8 Update config to reference declarative users 2025-07-27 22:38:12 +02:00
binwiederhier
07e9670a09 Fix bug in test 2025-07-27 22:33:29 +02:00
binwiederhier
0e67228605 Docs 2025-07-27 17:18:06 +02:00
binwiederhier
2578236d8d Docs 2025-07-27 17:10:37 +02:00
binwiederhier
fe545423c5 Change to auth-(users|access), upgrade manually added users to provision users 2025-07-27 12:10:16 +02:00
binwiederhier
f3c67f1d71 Refuse to update manually created users 2025-07-27 11:02:34 +02:00
binwiederhier
27b3a89247 Merge branch 'main' of github.com:binwiederhier/ntfy into predefined-users 2025-07-27 10:16:55 +02:00
binwiederhier
1470afb715 Make templateMode more understandable 2025-07-27 10:15:48 +02:00
binwiederhier
b495a744c9 Merge branch 'main' of github.com:binwiederhier/ntfy into predefined-users 2025-07-27 09:36:45 +02:00
Philipp C. Heckel
d2b5917e2b Merge pull request #1404 from wunter8/inline-template-newlines
allow newlines in in-line go templates
2025-07-27 09:36:24 +02:00
binwiederhier
52ca98611c Merge branch 'main' of github.com:binwiederhier/ntfy into predefined-users 2025-07-27 09:33:49 +02:00
தமிழ்நேரம்
1b394e9bb8 Translated using Weblate (Tamil)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ta/
2025-07-27 06:03:34 +00:00
Hunter Kehoe
0d36ab8af3 allow newlines in in-line go templates 2025-07-27 00:01:51 -06:00
binwiederhier
141ddb3a51 Comments 2025-07-26 12:20:11 +02:00
binwiederhier
f99801a2e6 Add "ntfy user hash" 2025-07-26 12:14:21 +02:00
binwiederhier
4457e9e26f Migration 2025-07-26 11:16:33 +02:00
Daniel Krol
4eb7dc563c Add Ntfy for Sandstorm to integrations.md 2025-07-22 18:50:18 -04:00
Philipp C. Heckel
269373d75d Merge pull request #1398 from emmaexe/add-ntfydesktop-integration
[docs] Add Ntfy Desktop to integrations
2025-07-22 12:57:01 +02:00
Emma
ef275ac0c1 Add Ntfy Desktop to integrations 2025-07-22 11:54:06 +02:00
binwiederhier
f59df0f40a Works 2025-07-21 17:44:00 +02:00
timof
214f70e62f Merge branch 'binwiederhier:main' into main 2025-07-21 16:52:25 +04:00
binwiederhier
51af114b2e Merge branch 'main' of github.com:binwiederhier/ntfy into predefined-users 2025-07-21 11:57:14 +02:00
Philipp C. Heckel
83bf9d4d6c Merge pull request #1390 from binwiederhier/template-dir
Advanced message templating: Sprig functions, pre-defined templates, custom templates via `template-dir`
2025-07-21 11:56:28 +02:00
binwiederhier
f298d947bd Bump 2025-07-21 11:46:22 +02:00
binwiederhier
d87d8a2db4 fmt 2025-07-21 11:31:38 +02:00
binwiederhier
50c564d8a2 AI docs 2025-07-21 11:24:58 +02:00
binwiederhier
c807b5db21 Merge branch 'template-dir' of github.com:binwiederhier/ntfy into template-dir 2025-07-21 10:28:40 +02:00
binwiederhier
4d1baae6d0 Refine 2025-07-21 10:28:26 +02:00
binwiederhier
34bc551303 Merge branch 'main' of github.com:binwiederhier/ntfy into template-dir 2025-07-21 10:23:56 +02:00
Philipp C. Heckel
0847a6406e Merge pull request #1395 from wunter8/template-dir
doc corrections
2025-07-21 10:23:47 +02:00
timof
006f73af7d Update message_cache.go
Added lock in add_messages to avoid "database is locked" error
Small code reformatting
2025-07-21 12:02:06 +04:00
Hunter Kehoe
f4a74dac57 doc corrections 2025-07-19 21:51:00 -06:00
binwiederhier
1f34c39eb0 Refactor a little 2025-07-19 22:52:08 +02:00
binwiederhier
8783c86cd6 Fix docs 2025-07-19 22:45:41 +02:00
binwiederhier
892e82ceb8 Remove underscore functions 2025-07-19 22:41:53 +02:00
binwiederhier
8b4834929d Clean code 2025-07-19 22:30:07 +02:00
binwiederhier
f0d5392e9e Self-review 2025-07-19 21:32:05 +02:00
binwiederhier
dde07adbdc Add some limits 2025-07-19 16:46:53 +02:00
binwiederhier
57df16dd62 Remove UUID 2025-07-19 15:44:49 +02:00
binwiederhier
ae62e0d955 Docs docs docs 2025-07-19 15:37:05 +02:00
binwiederhier
4603802f62 WIP 2025-07-16 21:50:29 +02:00
binwiederhier
610792b902 WIP 2025-07-16 20:33:52 +02:00
binwiederhier
b1e935da45 TEmplate dir 2025-07-16 13:49:15 +02:00
binwiederhier
93e14b73bb Tempalte dir 2025-07-16 10:01:59 +02:00
Philipp C. Heckel
81a486adc1 Merge pull request #1388 from KristopherPaulsen/add-missing-quote-on-cli-example
Add missing double-quote to docs so commands work when copy-pasted
2025-07-13 15:56:19 +02:00
Kristopher Paulsen
8bf4727a1c Missing double quote, sneaky little bugger 2025-07-13 09:50:06 -04:00
binwiederhier
2a468493f9 any 2025-07-13 12:45:00 +02:00
binwiederhier
3ac3e2ec7c Merge branch 'main' of github.com:binwiederhier/ntfy into sprig 2025-07-11 13:19:55 +02:00
binwiederhier
fea0f301d2 Sprig funcs 2025-07-11 13:19:31 +02:00
binwiederhier
1ce08a18c0 Bump release notes 2025-07-10 21:17:58 +02:00
binwiederhier
8d6f1eecdf Fix build 2025-07-10 21:06:39 +02:00
binwiederhier
c0b5151bae Predefined users 2025-07-10 20:50:29 +02:00
Hunter Kehoe
650f492d7d make tests happy 2025-07-07 22:47:41 -06:00
Hunter Kehoe
1f2c76e63d copy subset of Sprig template functions 2025-07-07 22:23:32 -06:00
binwiederhier
efef587671 WIP: Predefined users 2025-07-07 22:36:01 +02:00
Philipp C. Heckel
3c8ac4a1e1 Merge pull request #1380 from binwiederhier/ipv6
IPv6 support
2025-07-07 21:25:14 +02:00
binwiederhier
f5247c50f4 Bump 2025-07-07 21:24:43 +02:00
binwiederhier
1edbda4f31 Release notes 2025-07-07 18:34:05 +02:00
binwiederhier
de7b7218e4 Add languages 2025-07-07 18:28:16 +02:00
binwiederhier
19a4e95a3a Docs 2025-07-07 16:49:15 +02:00
binwiederhier
4578835a8f stdin 2025-07-07 11:04:33 +02:00
binwiederhier
aead619dea Merge branch 'main' of github.com:binwiederhier/ntfy into ipv6 2025-07-06 21:52:49 +02:00
Philipp C. Heckel
deeefee8c0 Merge pull request #1382 from srevn/main
Add piping support
2025-07-06 21:52:23 +02:00
Philipp C. Heckel
5e380e147f Merge pull request #1371 from cyb3rko/docs-update
Smaller docs updates
2025-07-06 21:48:52 +02:00
Philipp C. Heckel
ba5c3a164d Merge pull request #1381 from alecthomas/patch-1
docs: add ntfyexec to integrations
2025-07-06 21:48:18 +02:00
srevn
47da3aeea6 fix unbounded read 2025-07-06 17:53:04 +03:00
srevn
9ed96e5d8b Small cosmetic fixes 2025-07-06 16:31:03 +03:00
srevn
04aff72631 Add example and logging 2025-07-06 10:51:28 +03:00
srevn
6fbcd85d17 Add piping support 2025-07-06 10:23:32 +03:00
binwiederhier
8f60294c5b Docs 2025-07-05 22:48:45 +02:00
binwiederhier
677b44ce61 Docs, rename proxy-trusted-(addresses->hosts) 2025-07-05 22:35:26 +02:00
binwiederhier
000248e6aa Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web into ipv6 2025-07-05 21:46:44 +02:00
binwiederhier
359c789c34 Test for visitorID 2025-07-05 13:11:17 +02:00
Alec Thomas
34e9a771ce docs: add ntfyexec to integrations 2025-07-05 17:05:31 +10:00
binwiederhier
60b8588129 Tests 2025-07-04 16:56:35 +02:00
binwiederhier
7eeaeb8398 server.yml update 2025-07-04 16:51:55 +02:00
binwiederhier
c99d8b66c2 Re-order 2025-07-04 10:19:27 +02:00
binwiederhier
960f690dd6 Merge branch 'main' of github.com:binwiederhier/ntfy into ipv6 2025-07-04 10:17:05 +02:00
binwiederhier
54514454bf Works 2025-07-04 10:16:49 +02:00
binwiederhier
d8c8f31846 IPv6 WIP 2025-07-04 07:38:58 +02:00
binwiederhier
5ccc131e73 Derp 2025-07-04 06:41:14 +02:00
Kachelkaiser
ae27c3a5ab Translated using Weblate (German)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2025-06-30 16:08:38 +02:00
Kachelkaiser
48cb816111 Translated using Weblate (German)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2025-06-30 16:08:38 +02:00
Carl Fritze
ff904a5ca6 Translated using Weblate (German)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2025-06-30 16:08:38 +02:00
Priit Jõerüüt
8e7de80353 Translated using Weblate (Estonian)
Currently translated at 67.1% (272 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/et/
2025-06-26 23:01:49 +02:00
huy.phan
9c8a8f8795 Translated using Weblate (Vietnamese)
Currently translated at 20.0% (81 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/vi/
2025-06-26 23:01:47 +02:00
Priit Jõerüüt
df73c6f655 Translated using Weblate (Estonian)
Currently translated at 52.5% (213 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/et/
2025-06-24 18:01:52 +02:00
Kachelkaiser
c1e657db8b Translated using Weblate (German)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2025-06-24 18:01:50 +02:00
Joan
62c8a13ed4 Translated using Weblate (Catalan)
Currently translated at 1.2% (5 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ca/
2025-06-21 13:01:46 +02:00
Joan
994266ab04 Added translation using Weblate (Catalan) 2025-06-20 12:07:37 +02:00
Niko Diamadis
a41e3a1e76 Update App Store badges and remove Docker compose versions 2025-06-20 00:45:42 +02:00
Michael Nowak
16900d2c10 Set twilio-call-format config option in serve command 2025-06-16 15:14:13 +02:00
lazar
86bec660bf Translated using Weblate (Romanian)
Currently translated at 60.2% (244 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ro/
2025-06-08 15:50:23 +02:00
Philipp C. Heckel
30301c8a7f Update README.md 2025-06-07 06:49:22 -04:00
binwiederhier
7b470a7f6f Sponsors 2025-06-07 06:45:43 -04:00
Priit Jõerüüt
9d5891963a Translated using Weblate (Estonian)
Currently translated at 44.1% (179 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/et/
2025-06-03 22:04:33 +02:00
Philipp C. Heckel
de8e3bc2aa Merge pull request #1360 from binwiederhier/client-ip-header
Add custom client IP header
2025-06-01 10:12:34 -04:00
binwiederhier
d3f7aa7008 Self-review 2025-06-01 10:12:06 -04:00
binwiederhier
bbfaf2fc4d Add Forwarded header parsing 2025-06-01 09:57:39 -04:00
binwiederhier
db4ac158e3 Section 2025-05-31 23:09:51 -04:00
binwiederhier
7a33e16945 Cleanup, examples 2025-05-31 23:07:40 -04:00
binwiederhier
eac49feb04 Merge branch 'main' of github.com:binwiederhier/ntfy into client-ip-header 2025-05-31 22:42:40 -04:00
binwiederhier
849884c947 Change to "proxy-forwarded-header" and add "proxy-trusted-addrs" 2025-05-31 22:39:18 -04:00
binwiederhier
2cb4d089ab Merge client ip header 2025-05-31 15:33:21 -04:00
binwiederhier
dc797f8594 Fix release noteFix release notess 2025-05-29 20:35:22 -04:00
binwiederhier
061677a78b Bump version 2025-05-29 20:14:54 -04:00
binwiederhier
b4f15ec9d4 Integrations 2025-05-26 13:41:26 -04:00
binwiederhier
af17661053 Typos, server.yml additions 2025-05-25 20:13:13 -04:00
binwiederhier
635ec88c4f Update release log 2025-05-25 15:28:59 -04:00
Philipp C. Heckel
905f048ab4 Merge pull request #1123 from stendler/json-firebase-cache
feat(server): add Cache and Firebase as keys to JSON publishing
2025-05-25 15:24:51 -04:00
binwiederhier
7f86108379 Update docs 2025-05-25 12:57:02 -04:00
Philipp C. Heckel
425e6d064e Merge pull request #1002 from dandersch/ntfy-client_user_service
Add systemd user service for `ntfy-client.service`
2025-05-25 12:42:51 -04:00
Philipp C. Heckel
ebb61fcccf Merge pull request #1353 from binwiederhier/apns-fix
APNs fix
2025-05-25 12:33:53 -04:00
binwiederhier
9f72eb804d Computers are fast 2025-05-25 12:32:16 -04:00
binwiederhier
42af71e546 Fix test 2025-05-25 12:27:21 -04:00
binwiederhier
df818cfebc Merge branch 'main' of github.com:binwiederhier/ntfy 2025-05-25 12:23:20 -04:00
binwiederhier
0de1990c01 Increase number of access tokens per user to 60 2025-05-25 12:23:02 -04:00
binwiederhier
f40023aa23 APNs fix 2025-05-25 12:09:57 -04:00
Philipp C. Heckel
5765a707fc Merge pull request #1352 from leukosaima/patch-1
Add ntfyrr project to integrations
2025-05-25 06:43:38 -04:00
leukosaima
5eb84f759b Add ntfyrr project 2025-05-25 00:20:55 -04:00
binwiederhier
df7dd9c498 Fix weebpush test 2025-05-24 15:55:02 -04:00
binwiederhier
6fe3913aee Increase Web Push expiration to 55/60 days, update configs 2025-05-24 15:26:25 -04:00
Philipp C. Heckel
0ad9716241 Merge pull request #1212 from KuroSetsuna29/config-webpush-expiry
feat: allow configurable web push expiry duration
2025-05-24 14:57:50 -04:00
binwiederhier
f4c37ccfb9 Bump VIte 2025-05-24 14:22:02 -04:00
Philipp C. Heckel
7182d3a4e5 Merge pull request #1342 from binwiederhier/dependabot/npm_and_yarn/web/multi-4e779676ec
Bump esbuild, vite and vite-plugin-pwa in /web
2025-05-24 14:07:01 -04:00
binwiederhier
eecd3245f0 Release notes 2025-05-24 09:36:16 -04:00
binwiederhier
4dc3b38c95 Allow adding/changing user with password hash via v1/users API 2025-05-24 09:31:57 -04:00
binwiederhier
9edab24d4c Merge branch 'main' of github.com:binwiederhier/ntfy 2025-05-24 09:10:07 -04:00
Philipp C. Heckel
3b627b27b3 Merge pull request #1340 from Tom-Hubrecht/hashed-pwd
user: Allow changing the hashed password directly
2025-05-24 09:10:02 -04:00
binwiederhier
80462f7ee5 Refine user API change 2025-05-24 08:58:44 -04:00
Philipp C. Heckel
65e377ec63 Merge pull request #1267 from wunter8/api-change-user-password
Api change user password
2025-05-24 08:53:28 -04:00
dandersch
45e1707d3b remove systemd user daemon-reload from postinst.sh 2025-05-23 23:00:45 +02:00
dandersch
0581a9e680 remove systemd user service cmds from postinst.sh 2025-05-23 22:52:25 +02:00
Hunter Kehoe
0fb60ae72d test change user password and tier in single request 2025-05-22 20:01:50 -06:00
Hunter Kehoe
e36e4856c9 allow changing password or tier with user PUT 2025-05-22 19:57:57 -06:00
Hunter Kehoe
fa48639517 make POST create user and PUT update user 2025-05-22 19:57:02 -06:00
Hunter Kehoe
2b40ad9a12 make staticcheck happy 2025-05-22 19:57:02 -06:00
Hunter Kehoe
ad7ab18fb7 prevent changing admin passwords 2025-05-22 19:57:02 -06:00
Hunter Kehoe
8f9dafce20 change user password via accounts API 2025-05-22 19:57:00 -06:00
binwiederhier
69cf773834 Fix webpush command 2025-05-22 21:56:28 -04:00
binwiederhier
b2b9891a58 Add Tamil language 2025-05-22 21:43:45 -04:00
Andrea Toska
3bf02d3cd9 Translated using Weblate (Albanian)
Currently translated at 15.0% (61 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/sq/
2025-05-23 03:23:15 +02:00
Priit Jõerüüt
8777990d2d Translated using Weblate (Estonian)
Currently translated at 24.9% (101 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/et/
2025-05-23 03:23:15 +02:00
Tyxiel
70f0e7ccc7 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt_BR/
2025-05-23 03:23:15 +02:00
Max Badran
adfacf820e Translated using Weblate (Ukrainian)
Currently translated at 99.7% (404 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/uk/
2025-05-23 03:23:15 +02:00
András
35e15cfd9d Translated using Weblate (Hungarian)
Currently translated at 53.5% (217 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/hu/
2025-05-23 03:23:15 +02:00
Eero Häkkinen
4e2a884da5 Translated using Weblate (Finnish)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fi/
2025-05-23 03:23:15 +02:00
Eero Häkkinen
29cf4f16d1 Translated using Weblate (Finnish)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fi/
2025-05-23 03:23:15 +02:00
Łukasz Podgórski
609c9fa37d Translated using Weblate (Polish)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pl/
2025-05-23 03:23:15 +02:00
Korab Arifi
2eb5eb3e29 Translated using Weblate (Albanian)
Currently translated at 10.1% (41 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/sq/
2025-05-23 03:23:15 +02:00
Korab Arifi
a92306b181 Added translation using Weblate (Albanian) 2025-05-23 03:23:15 +02:00
OZZY
047cc22dba Translated using Weblate (Arabic)
Currently translated at 88.3% (358 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ar/
2025-05-23 03:23:15 +02:00
Priit Jõerüüt
f31d777b69 Translated using Weblate (Estonian)
Currently translated at 10.6% (43 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/et/
2025-05-23 03:23:15 +02:00
தமிழ்நேரம்
ac983cd9bc Translated using Weblate (Tamil)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ta/
2025-05-23 03:23:15 +02:00
AtomicDude
dd45fd90b7 Translated using Weblate (Romanian)
Currently translated at 56.7% (230 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ro/
2025-05-23 03:23:15 +02:00
தமிழ்நேரம்
e76e6274a3 Added translation using Weblate (Tamil) 2025-05-23 03:23:15 +02:00
Marius Pop
161ce468fe Translated using Weblate (Romanian)
Currently translated at 46.6% (189 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ro/
2025-05-23 03:23:15 +02:00
Danial Behzadi
04df6f1390 Translated using Weblate (Persian)
Currently translated at 13.8% (56 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fa/
2025-05-23 03:23:15 +02:00
Faraz Sadri Alamdari
79852fec59 Translated using Weblate (Persian)
Currently translated at 13.8% (56 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fa/
2025-05-23 03:23:15 +02:00
Danial Behzadi
92de1b5a88 Translated using Weblate (Persian)
Currently translated at 13.8% (56 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fa/
2025-05-23 03:23:15 +02:00
Ihor Kalnytskyi
fc93de9a28 Translated using Weblate (Ukrainian)
Currently translated at 99.7% (404 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/uk/
2025-05-23 03:23:15 +02:00
qtm
ae9fa85676 Translated using Weblate (Russian)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ru/
2025-05-23 03:23:15 +02:00
Christer Solstrand Johannessen
b26666f635 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/nb_NO/
2025-05-23 03:23:15 +02:00
Christer Solstrand Johannessen
70a9301e25 Translated using Weblate (Norwegian Bokmål)
Currently translated at 51.1% (207 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/nb_NO/
2025-05-23 03:23:15 +02:00
Cairo Braga
86c548ae37 Translated using Weblate (Portuguese)
Currently translated at 76.5% (310 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt/
2025-05-23 03:23:15 +02:00
Ed
1e1b2be464 Translated using Weblate (Portuguese)
Currently translated at 76.5% (310 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt/
2025-05-23 03:23:15 +02:00
Cairo Braga
1b8906f1fd Translated using Weblate (Portuguese (Brazil))
Currently translated at 84.1% (341 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt_BR/
2025-05-23 03:23:15 +02:00
Luis Eduardo Brito
b81f7b21a9 Translated using Weblate (Portuguese (Brazil))
Currently translated at 83.9% (340 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt_BR/
2025-05-23 03:23:15 +02:00
K0ntact
db2dc09189 Translated using Weblate (Vietnamese)
Currently translated at 7.1% (29 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/vi/
2025-05-23 03:23:14 +02:00
Shoshin Akamine
5f6b7e6f82 Translated using Weblate (Japanese)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ja/
2025-05-23 03:23:14 +02:00
109247019824
6daf4141c6 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/bg/
2025-05-23 03:23:14 +02:00
Vito0912
41083cfd07 Translated using Weblate (German)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2025-05-23 03:23:14 +02:00
Soaibuzzaman
c03f795508 Added translation using Weblate (Bengali) 2025-05-23 03:23:14 +02:00
Ricardo Vieira
58d7cb8ef8 Translated using Weblate (Portuguese)
Currently translated at 76.2% (309 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt/
2025-05-23 03:23:14 +02:00
Linerly
8acf0f4350 Translated using Weblate (Indonesian)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/id/
2025-05-23 03:23:14 +02:00
Carl Fritze
236b7b7a16 Translated using Weblate (German)
Currently translated at 99.5% (403 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2025-05-23 03:23:14 +02:00
Petri Hämäläinen
871883f6e9 Translated using Weblate (Finnish)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fi/
2025-05-23 03:23:14 +02:00
Malte Saling
a92c8a9ec9 Translated using Weblate (German)
Currently translated at 95.5% (387 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2025-05-23 03:23:14 +02:00
Vito0912
1c6aa49fca Translated using Weblate (German)
Currently translated at 95.3% (386 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2025-05-23 03:23:14 +02:00
githubozaurus
49d258706d Translated using Weblate (Romanian)
Currently translated at 31.1% (126 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ro/
2025-05-23 03:23:14 +02:00
josé m
bbce1200b4 Translated using Weblate (Galician)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/gl/
2025-05-23 03:23:14 +02:00
Stefano Maggi
94d0c5a335 Translated using Weblate (Italian)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2025-05-23 03:23:14 +02:00
Jakob Malchow
7835fc65c4 Translated using Weblate (Italian)
Currently translated at 87.6% (355 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2025-05-23 03:23:14 +02:00
Stefano Maggi
dc6b8ece1e Translated using Weblate (Italian)
Currently translated at 87.6% (355 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2025-05-23 03:23:14 +02:00
josé m
f595dff66f Translated using Weblate (Galician)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/gl/
2025-05-23 03:23:14 +02:00
binwiederhier
0514ea4ac0 Merge branch 'main' of github.com:binwiederhier/ntfy 2025-05-22 20:59:29 -04:00
binwiederhier
1598087e1f Fix tests 2025-05-22 20:58:28 -04:00
Philipp C. Heckel
3709ea689a Merge pull request #1216 from wunter8/since-latest-param
feat: add since=latest subscribe param
2025-05-22 20:57:59 -04:00
Philipp C. Heckel
f4aba12546 Merge branch 'main' into since-latest-param 2025-05-22 20:57:52 -04:00
Philipp C. Heckel
521fe791b0 Merge pull request #1271 from RoboMagus/feat_1174
Add major and minor version tags to docker release flow
2025-05-22 20:51:00 -04:00
binwiederhier
6d15b9face Fix up APNs PR 2025-05-22 20:48:24 -04:00
Philipp C. Heckel
9fbe7804dd Merge pull request #1345 from tr4nt0r/homeassistant_official
Add official Home Assistant integration and async python library
2025-05-22 20:30:18 -04:00
Philipp C. Heckel
faa4dcbcee Merge pull request #1287 from barart/fix-anonymous-read-restriction
Handle anonymous read restrictions by sending a poll_request event
2025-05-22 20:22:58 -04:00
tr4nt0r
ad3e7960ce Add official Home Assistant integration and async python library 2025-05-23 01:31:16 +02:00
Philipp C. Heckel
3234189cd2 Merge pull request #1343 from ptmorris1/patch-2
Add NtfyPwsh integration and blog
2025-05-22 16:51:53 -04:00
Patrick Morris
e64a0bd8c9 Add NtfyPwsh integration and blog 2025-05-22 13:37:54 -05:00
Philipp C. Heckel
97a59f19e0 Merge pull request #1262 from rake5k/markdown-code-scroll
Make markdown code blocks scrollable
2025-05-21 20:57:54 -04:00
binwiederhier
7067d8aa77 Release notes 2025-05-21 20:55:54 -04:00
Philipp C. Heckel
5999653456 Merge pull request #1138 from nogweii/webpush-key-file
Teach ntfy webpush to write the keys to a file
2025-05-21 20:44:44 -04:00
Philipp C. Heckel
9ce6b03450 Merge branch 'main' into webpush-key-file 2025-05-21 20:39:12 -04:00
Philipp C. Heckel
7e916516e0 Merge pull request #1338 from wunter8/websockets-401
Websocket http error codes
2025-05-21 20:26:32 -04:00
Philipp C. Heckel
09c2b4bdca Merge pull request #1239 from thiswillbeyourgithub/integration_toc
docs: add ToC to integrations.md
2025-05-21 20:21:40 -04:00
Philipp C. Heckel
978ee81df3 Merge pull request #1199 from quantum5/ntfy-run
docs: add quantum5/ntfy-run to integrations and examples
2025-05-21 20:19:47 -04:00
Philipp C. Heckel
86f2ab8a55 Merge branch 'main' into ntfy-run 2025-05-21 20:19:39 -04:00
Philipp C. Heckel
e4aff00455 Merge pull request #1234 from ungeskriptet/fix-typo
docs: config.md: fix typo
2025-05-21 20:17:57 -04:00
Philipp C. Heckel
e88f24bae7 Merge pull request #1241 from thiswillbeyourgithub/integration_csv
docs: add integration: Ntfy_CSV_Reminders
2025-05-21 20:16:45 -04:00
Philipp C. Heckel
b4797ef212 Merge branch 'main' into integration_csv 2025-05-21 20:16:35 -04:00
Philipp C. Heckel
2f8c0e4d5d Merge pull request #1224 from dmitrygudkov/patch-1
Update integrations.md: Added EasyMorph
2025-05-21 20:14:07 -04:00
Philipp C. Heckel
56231f9288 Merge branch 'main' into patch-1 2025-05-21 20:13:56 -04:00
Philipp C. Heckel
ef7c7c7b09 Merge pull request #1209 from jim3692/patch-1
Add Clipboard IO to projects
2025-05-21 20:10:51 -04:00
Philipp C. Heckel
88e4b8f0e6 Merge branch 'main' into patch-1 2025-05-21 20:10:43 -04:00
Philipp C. Heckel
090bdd93ba Merge pull request #1187 from 13x1/patch-1
Fix typo
2025-05-21 20:09:18 -04:00
Philipp C. Heckel
790044e899 Merge pull request #1240 from thiswillbeyourgithub/integration_daily_fact
docs: add integration: Daily Fact Ntfy
2025-05-21 20:07:00 -04:00
dependabot[bot]
7aab7d387f Bump esbuild, vite and vite-plugin-pwa in /web
Bumps [esbuild](https://github.com/evanw/esbuild) to 0.25.4 and updates ancestor dependencies [esbuild](https://github.com/evanw/esbuild), [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) and [vite-plugin-pwa](https://github.com/vite-pwa/vite-plugin-pwa). These dependencies need to be updated together.


Updates `esbuild` from 0.18.20 to 0.25.4
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG-2023.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.18.20...v0.25.4)

Updates `vite` from 4.5.14 to 6.3.5
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.3.5/packages/vite)

Updates `vite-plugin-pwa` from 0.15.2 to 1.0.0
- [Release notes](https://github.com/vite-pwa/vite-plugin-pwa/releases)
- [Commits](https://github.com/vite-pwa/vite-plugin-pwa/compare/v0.15.2...v1.0.0)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-version: 0.25.4
  dependency-type: indirect
- dependency-name: vite
  dependency-version: 6.3.5
  dependency-type: direct:development
- dependency-name: vite-plugin-pwa
  dependency-version: 1.0.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-22 00:04:33 +00:00
binwiederhier
a461aafb91 Merge branch 'main' of github.com:binwiederhier/ntfy 2025-05-21 20:02:19 -04:00
binwiederhier
1569c22a65 Fix some broken links in the docs 2025-05-21 20:02:06 -04:00
Philipp C. Heckel
2091ceb4d2 Merge pull request #1248 from pixitha/patch-1
Update quickstart example
2025-05-21 19:50:40 -04:00
Philipp C. Heckel
ec337b5de9 Merge pull request #1296 from sharjeelaziz/add-bashrc-example
Add Terminal Notifications for Long-Running Commands example
2025-05-21 19:33:54 -04:00
Philipp C. Heckel
5a245f889c Merge pull request #1260 from snex/main
add canary in the cage podcast coverage to integrations page
2025-05-21 19:31:27 -04:00
Philipp C. Heckel
ee595067ba Merge pull request #1307 from jlssmt/patch-1
set LABEL org.opencontainers.image.version
2025-05-21 19:24:43 -04:00
Philipp C. Heckel
bd4b5e9e1b Merge pull request #1312 from vkrause/work/vkrause/detect-encrypted-messages-as-unified-push
Consider aes128gcm content encoding as an indicator for UnifiedPush
2025-05-21 19:16:17 -04:00
Philipp C. Heckel
786e588397 Merge pull request #1325 from gitmotion/add-ntfy-me-mcp-integrations-projects
docs: add integration ntfy-me-mcp to integrations.md
2025-05-21 19:15:02 -04:00
Philipp C. Heckel
2dfb53ec53 Merge branch 'main' into add-ntfy-me-mcp-integrations-projects 2025-05-21 19:14:54 -04:00
Philipp C. Heckel
a30c5eb9cf Merge pull request #1310 from biodrone/biodrone/issue1309
docs: correct mountPath for server.yml
2025-05-21 19:13:51 -04:00
Philipp C. Heckel
d96d4b03c7 Merge pull request #1225 from sedlund/docs/fix_typo
docs: publish.md typo
2025-05-21 19:13:23 -04:00
Philipp C. Heckel
3257ce91ef Merge pull request #1264 from brian6932/patch-1
docs: Typo `wep` -> `web`
2025-05-21 19:12:44 -04:00
Philipp C. Heckel
f563b671c8 Merge pull request #1266 from mmatuska/fix/extractIPAddress
server/util.go: fix logic in extractIPAddress()
2025-05-21 19:11:13 -04:00
Philipp C. Heckel
ea1cda5f92 Merge pull request #1299 from cvilsmeier/main
docs: add integration: Monibot
2025-05-21 19:09:49 -04:00
Philipp C. Heckel
36ba27ba09 Merge pull request #1313 from patricksthannon/patch-1
Update integrations.md
2025-05-21 19:09:06 -04:00
Philipp C. Heckel
60eccba2fa Merge pull request #1320 from yassirh/main
docs: Added reference to UptimeObserver integration
2025-05-21 19:07:14 -04:00
Philipp C. Heckel
aec4b97fae Merge pull request #1319 from therobbielee/therobbielee-patch-1
Update integrations.md
2025-05-21 19:06:18 -04:00
Philipp C. Heckel
389ae682a5 Merge pull request #1341 from binwiederhier/security-updates
Security updates
2025-05-21 19:04:26 -04:00
binwiederhier
3f21da7768 Pipelines 2025-05-21 18:55:21 -04:00
binwiederhier
0ad266a495 Derp 2025-05-21 18:53:29 -04:00
binwiederhier
bd192edf1e Release notes 2025-05-21 18:52:45 -04:00
binwiederhier
d1ac8d03e0 Security updates 2025-05-21 18:49:19 -04:00
Tom Hubrecht
44b7c2f198 user: Allow changing the hashed password directly
This adds the detection of `NTFY_PASSWORD_HASH` when creating a user or
changing its passsword so that scripts don't have to manipulate the bare
password.
2025-05-21 16:34:14 +02:00
Hunter Kehoe
cdae5493e2 write http errors to websocket connection instead of always 200 2025-05-14 11:39:18 -06:00
Hunter Kehoe
f110472204 fix typo 2025-05-14 11:20:30 -06:00
Thea Tischbein
03aeb707f2 feat: Add optional web app flag which requires a login for every action 2025-05-05 11:39:53 +02:00
gitmotion
3f1342c05b Add ntfy-me-mcp 2025-04-28 19:25:40 -07:00
Yassir Hannoun
8b95b1a213 docs: Added UptimeObserver integration 2025-04-26 21:13:12 +00:00
Robbie Björk
d4dfd3f657 Update integrations.md
Added alertmanager-ntfy-relay to integrations.md
2025-04-26 00:22:54 +02:00
patricksthannon
c1d718ee68 Update integrations.md
Added InvaderInformant integration to integration list. Thanks!
2025-04-09 09:53:17 -07:00
Volker Krause
bd08a120cd Consider aes128gcm content encoding as an indicator for UnifiedPush
Without this a UnifiedPush/Web Push message with encryption would be
turned into an attachment. That in itself isn't pretty but can still
work, but it requires attachments to be enabled in the first place.
2025-04-07 17:19:44 +02:00
Josh J
c9126e7aa9 docs: correct mountPath for server.yml
Fixed #1309
2025-04-07 09:26:52 +01:00
jlssmt
db9b974e47 set LABEL org.opencontainers.image.version 2025-04-06 11:35:42 +02:00
Christoph Vilsmeier
889a6f03f8 docs: add integration: Monibot 2025-03-25 16:56:47 +01:00
Sharjeel Aziz
6af8d03470 Add Terminal Notifications for Long-Running Commands example
Signed-off-by: Sharjeel Aziz <sharjeel.aziz@gmail.com>
2025-03-19 15:35:46 -04:00
Michael Nowak
950ba1e2e1 Add optional twilio-call-format config option
To be able to set custom TwiML send to the Call API.
2025-03-11 09:45:32 +00:00
barart
6b2cfb1d1d Handle anonymous read restrictions by sending a poll_request event
If a topic does not allow anonymous reads, this change ensures that we send a "poll_request" event instead of relaying the message via Firebase. Additionally, we include generic text in the title and body/message. This way, if the client cannot retrieve the actual message, the user will still receive a notification, prompting them to update the client manually.
2025-03-05 13:04:21 -06:00
RoboMagus
35458230a8 add major and minor version tags to docker release flow 2025-01-30 23:49:22 +01:00
Martin Matuska
bd39cf4b54 server/util.go: fix logic in extractIPAddress() 2025-01-26 00:00:06 +01:00
Brian
f739a3067e docs: Typo wep -> web 2025-01-24 20:28:29 -05:00
Christian Harke
2344eee2c6 Make markdown code blocks scrollable 2025-01-20 22:13:15 +01:00
David Havlicek
5822a2ec41 add canary in the cage podcast coverage to integrations page 2025-01-17 13:26:22 -08:00
Kyle Duren
a49cafbadb more correcting auto-formats 2025-01-06 02:55:03 +00:00
Kyle Duren
0aee6252bb fixing auto-format change 2025-01-06 01:09:40 +00:00
Kyle Duren
0e6a483b2f fixing auto-format change 2025-01-06 01:06:28 +00:00
Kyle Duren
20c014ba8d Adding test and some docs 2025-01-06 00:57:53 +00:00
Kyle Duren
926967b6e7 adding logic to specifcy client-ip header from proxy 2025-01-05 20:29:08 +00:00
Kyle Duren
6345e7f864 Update quickstart example
Just noticed the behind proxy was missing from the example that was supposed to include it.
2025-01-01 22:08:30 -05:00
thiswillbeyourgithub
80bc600ff0 docs: add integration: Ntfy_CSV_Reminders
Signed-off-by: thiswillbeyourgithub
<26625900+thiswillbeyourgithub@users.noreply.github.com>
2024-12-12 17:55:08 +01:00
thiswillbeyourgithub
758828e7aa docs: add integration: Daily Fact Ntfy
Signed-off-by: thiswillbeyourgithub <26625900+thiswillbeyourgithub@users.noreply.github.com>
2024-12-11 12:50:03 +01:00
thiswillbeyourgithub
4c179b7d9d docs: add ToC to integrations.md
Signed-off-by: thiswillbeyourgithub <26625900+thiswillbeyourgithub@users.noreply.github.com>
2024-12-11 12:40:36 +01:00
David Wronek
27398e7d72 docs: config.md: fix typo
Add a missing parenthesis.

Signed-off-by: David Wronek <david@mainlining.org>
2024-12-10 08:42:59 +01:00
Scott Edlund
19f8a35588 docs: publish.md typo 2024-11-23 13:24:24 +07:00
Dmitry Gudkov
8feb0f1a2e Update integrations.md: Added EasyMorph
EasyMorph (https://easymorph.com) is a visual workflow-based data preparation and automation tool. It has 180+ actions, including a dedicated action to send notifications to ntfy as a workflow step.

The proposed link leads to the official help page for the "Send message to ntfy" action.
2024-11-19 21:28:59 -05:00
Hunter Kehoe
9241b0550c feat: add subscribe param 2024-11-04 21:33:35 -07:00
KuroSetsuna29
136b656ccb fix descriptions 2024-11-02 08:50:57 -04:00
KuroSetsuna29
c844c24a16 allow configurable web push expiry duration 2024-11-02 00:46:31 -04:00
jim3692
90f21ba408 Add Clipboard IO to projects 2024-10-30 14:48:32 +02:00
Quantum
b843c69c16 docs: add quantum5/ntfy-run to integrations and examples 2024-10-16 22:00:48 -04:00
binwiederhier
630f2957de Merge branch 'main' of github.com:binwiederhier/ntfy 2024-09-29 13:20:45 -04:00
binwiederhier
d243c22510 Docs, fix lint 2024-09-29 13:20:36 -04:00
Philipp C. Heckel
fbf325a630 Merge pull request #1122 from stendler/docs
update links in integration docs
2024-09-29 13:19:21 -04:00
Philipp C. Heckel
84f421a464 Merge pull request #1175 from Measurity/patch-1
Added note to add ", chain=DOCKER-USER" to the fail2ban jail action if using docker networks
2024-09-29 13:14:26 -04:00
binwiederhier
d38c149263 Docs 2024-09-29 13:12:51 -04:00
Philipp C. Heckel
fc3624cd50 Merge pull request #1141 from pcouy/smtp-sender-date-header
Add Date header to sent e-mails
2024-09-29 12:41:29 -04:00
Philipp C. Heckel
78533e27fe Merge pull request #1133 from Walzen-Group/integrations-wlzntfy
Integrations wlzntfy
2024-09-29 12:40:46 -04:00
Philipp C. Heckel
02e46c1d03 Merge pull request #1137 from ShlomoCode/patch-1
macrodroid supports POST requests
2024-09-29 12:39:25 -04:00
Philipp C. Heckel
81f05b3f15 Merge pull request #1161 from OneWeekNotice/documentation-update
Updating Docs - configuration table, shoutrr, Scrutiny, etc
2024-09-29 12:38:07 -04:00
Philipp C. Heckel
eb700b4b6c Merge pull request #1164 from bishtawi/bishtawi/smtp-auth
Support SMTP Auth Plain for event publishing
2024-09-29 12:30:01 -04:00
Philipp C. Heckel
89c884ab4d Merge pull request #1172 from anirvan/patch-1
Fix typo in cli.md ("subscibe" → "subscribe")
2024-09-29 12:23:26 -04:00
Philipp C. Heckel
0fe0b0c9d7 Merge pull request #1177 from hoho4190/fix-config-md
docs(config.md): remove duplicate comment
2024-09-29 12:22:56 -04:00
binwiederhier
bad3ef43b7 BUmp 2024-09-29 12:22:16 -04:00
lexi
903ef71b6f Fix typo
"Firebase (FCM" -> "Firebase (FCM)"
2024-09-22 11:58:26 +02:00
hoho4190
5726f8e9ba docs(config.md): remove duplicate comment
removed links typed twice
2024-09-03 15:06:46 +09:00
Meas
5b10cd660b Update config.md
Added note to add ", chain=DOCKER-USER" to the fail2ban jail action if using docker networks

By default, the jail action chain is "INPUT", but "FORWARD" is used when using docker networks. "DOCKER-USER", available when using docker, is part of the "FORWARD" chain. Hence the note to use "DOCKER-USER".
2024-08-31 09:06:54 +02:00
Anirvan Chatterjee
333d901661 Fix typo in cli.md ("subscibe" → "subscribe") 2024-08-25 22:19:05 -07:00
Bishtawi
112efaae90 Support SMTP Auth Plain 2024-08-07 17:29:54 -07:00
OneWeekNotice
61bb8a0286 adding Scrutiny project to integrations documentation 2024-07-26 23:16:49 -04:00
OneWeekNotice
be2bebf517 adding logging configurations to Config options table 2024-07-26 23:01:35 -04:00
OneWeekNotice
a4cf40907b removing WATCHTOWER_NOTIFICATIONS as this is Legacy notifications 2024-07-26 22:50:27 -04:00
OneWeekNotice
6562ba6987 adding Watchtower - shoutrrr authentication with auth token utilizing ntfy url 2024-07-26 22:48:14 -04:00
OneWeekNotice
6da554d1e5 adding documentation for caddy WebSockets 2024-07-26 22:43:08 -04:00
Philipp C. Heckel
72f36f8296 Merge pull request #1149 from abhisheksoni27/patch-1
feat: add app store reference
2024-07-19 09:41:55 +02:00
binwiederhier
e8685baf15 Thank you @cdf-eagles for your generous donation 2024-07-19 09:34:14 +02:00
binwiederhier
f8085f8686 Thank you @user8446 for your donation 2024-07-19 09:33:45 +02:00
binwiederhier
3139c13e50 Thank you @chxseh for your donation 2024-07-19 09:33:18 +02:00
binwiederhier
4a2b5676d9 Thank you @wielandp for your donation 2024-07-19 09:32:47 +02:00
binwiederhier
a12195d3c7 Thank you @Proximus888 for your sponsorship 2024-07-19 09:32:03 +02:00
binwiederhier
412e78c4d0 Thank you @suhlig for your sponsorship 2024-07-19 09:31:02 +02:00
binwiederhier
22bdc91630 Thank you @dlt-green for your sponsorship 2024-07-19 09:29:46 +02:00
binwiederhier
e94c2fef52 Thank you @sheetd for your donation 2024-07-19 09:28:36 +02:00
binwiederhier
694363013d Thank you @TheCraiggers for your sponsorship 2024-07-19 09:28:03 +02:00
binwiederhier
fb6a408cca Thank you @avalentic for your donation 2024-07-19 09:26:55 +02:00
binwiederhier
89437019fb Bump 2024-07-19 09:26:44 +02:00
binwiederhier
a095ab56bb Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2024-07-19 09:24:49 +02:00
Jiri Grönroos
92905fd860 Translated using Weblate (Finnish)
Currently translated at 98.5% (399 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fi/
2024-07-16 13:09:10 +00:00
Priit Jõerüüt
01c216d506 Translated using Weblate (Estonian)
Currently translated at 5.9% (24 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/et/
2024-07-15 08:09:25 +02:00
Priit Jõerüüt
999678565b Added translation using Weblate (Estonian) 2024-07-13 23:59:26 +02:00
Abhishek Soni
3454a5ca16 feat: add app store reference 2024-07-12 14:44:30 +05:30
wmbirken
63c96b4e80 Translated using Weblate (Swedish)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/sv/
2024-07-11 15:09:24 +02:00
Pierre Couy
003fec5f83 Add Date header to sent e-mails 2024-06-29 15:31:25 +02:00
Gian Andrea Casavecchia
f0d8f0ad8e Translated using Weblate (Italian)
Currently translated at 78.5% (318 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2024-06-26 10:09:27 +00:00
Nogweii
20cca8e888 update go.sum 2024-06-25 22:59:17 -07:00
Nogweii
49a548252c teach ntfy webpush to write the keys to a file 2024-06-25 22:58:36 -07:00
Shlomo
21dbcf65dc macrodroid supports POST requests 2024-06-24 23:50:56 +03:00
Sam
dee213d90c improve wording 2024-06-16 22:51:35 +02:00
Sam
19b99e8285 better wording 2024-06-16 22:50:08 +02:00
Sam
0c68b6a2c7 Update integrations.md 2024-06-16 22:47:41 +02:00
Sam
76b753062d fix url 2024-06-16 22:47:07 +02:00
Sam
ceec0bc71d Update integrations.md 2024-06-16 22:44:56 +02:00
aaron.frost@gmx.de
6ecd96cf6e Translated using Weblate (German)
Currently translated at 94.8% (384 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2024-06-14 15:09:15 +00:00
waclaw66
8d38672baf Translated using Weblate (Czech)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/cs/
2024-06-06 08:09:13 +02:00
Aiman Jalil
36a149dd7a Translated using Weblate (Malay)
Currently translated at 46.4% (188 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ms/
2024-06-04 05:58:08 +02:00
Aiman Jalil
1249d9473a Translated using Weblate (Malay)
Currently translated at 24.4% (99 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ms/
2024-06-02 22:09:21 +02:00
Ed
5941a8f2a6 Translated using Weblate (Portuguese)
Currently translated at 71.8% (291 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt/
2024-06-02 22:09:20 +02:00
Aiman Jalil
2e8daa962c Added translation using Weblate (Malay) 2024-06-02 12:24:59 +02:00
Ed
3f4d0ef3ea Translated using Weblate (Portuguese)
Currently translated at 59.0% (239 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt/
2024-06-01 21:21:59 +02:00
1024mb
0fba690d02 Translated using Weblate (Spanish)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/es/
2024-06-01 21:21:58 +02:00
stendler
5211d06f2c feat(server): add Cache and Firebase as keys to JSON publishing
https://github.com/binwiederhier/ntfy/issues/1119
2024-05-29 21:23:06 +02:00
stendler
7121d14bfa docs: add more links 2024-05-29 13:02:11 +02:00
stendler
d5a1e38082 docs: fix description of systemd-ntfy-poweronoff 2024-05-29 12:36:55 +02:00
Guilherme Puida
3ad61c4736 Translated using Weblate (Portuguese (Brazil))
Currently translated at 79.5% (322 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt_BR/
2024-05-28 05:09:33 +02:00
binwiederhier
9d3fc20e58 Thank you @madchr1st for your generous donation! 2024-05-18 12:19:33 -04:00
binwiederhier
0be467f809 Thank you @0x45796164 for your sponsorship 2024-05-13 20:46:37 -04:00
binwiederhier
ec75ce0787 Thank you @herzkerl for your sponsorship 2024-05-13 20:41:56 -04:00
binwiederhier
d11b1007ef Bump 2024-05-13 16:11:29 -04:00
binwiederhier
c542dd8c6f Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2024-05-13 16:09:04 -04:00
binwiederhier
37697aed27 Bump 2024-05-13 16:08:46 -04:00
bytequill
4360d157b2 Translated using Weblate (Polish)
Currently translated at 98.7% (400 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pl/
2024-05-12 13:29:15 +02:00
Samuel
c3c4d65f99 Translated using Weblate (Portuguese (Brazil))
Currently translated at 78.2% (317 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt_BR/
2024-05-08 16:07:19 +02:00
binwiederhier
ffd7645c0b Releases 2024-05-07 21:24:39 -04:00
Philipp C. Heckel
043738a475 Merge pull request #1098 from wunter8/patch-6
don't cache config.js
2024-05-07 21:21:39 -04:00
binwiederhier
fb52ad6fdb Thank you @arnbrhm for your donation 2024-05-07 21:20:58 -04:00
binwiederhier
29318f9d61 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2024-05-07 21:18:14 -04:00
binwiederhier
030f7266f7 Do not set rate visitor for non-eligible topics 2024-05-07 21:17:51 -04:00
ButterflyOfFire
9692de1469 Translated using Weblate (Arabic)
Currently translated at 88.1% (357 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ar/
2024-05-05 21:08:13 +02:00
Mohammad Habib
eab90a0275 Translated using Weblate (Arabic)
Currently translated at 85.9% (348 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ar/
2024-05-03 19:07:20 +02:00
Isaac Alves
e6f70f8e41 Translated using Weblate (Portuguese (Brazil))
Currently translated at 76.2% (309 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt_BR/
2024-04-26 21:07:29 +02:00
wunter8
499b0dd839 don't cache config.js 2024-04-25 16:09:27 -06:00
Philipp C. Heckel
31d0c812ce Merge pull request #1082 from wunter8/fix-username-regex
Fix username regex
2024-04-24 16:03:25 -04:00
Philipp C. Heckel
d37f861f6b Merge pull request #1086 from ibacalu/patch-1
docs(integrations): add proxmox-ntfy
2024-04-24 15:58:56 -04:00
binwiederhier
0a49a8d88b Thank you for your donation @Riolku 2024-04-24 14:55:51 -04:00
binwiederhier
b63ef0defb Thank you @rubund for your sponsorship 2024-04-24 14:55:18 -04:00
binwiederhier
f8068ef561 Thank you @IMarkoMC for your sponsorship 2024-04-24 14:54:52 -04:00
binwiederhier
2608687e98 Thank you @spudooli for your donation 2024-04-24 14:54:25 -04:00
binwiederhier
02564a40c7 Thank you @PTR-inc for your sponsorship 2024-04-24 14:53:45 -04:00
binwiederhier
bdd49f4e16 Thank you @afunworm for your sponsorship 2024-04-24 14:52:52 -04:00
binwiederhier
33b603def5 Re-add idx_topic to messages table 2024-04-24 14:38:05 -04:00
binwiederhier
6eff5553b5 Merge branch 'main' of github.com:binwiederhier/ntfy 2024-04-23 20:22:16 -04:00
binwiederhier
7cac03c1ec Bump 2024-04-23 20:22:09 -04:00
Iulian Bacalu
b33918f267 docs(integrations): add proxmox-ntfy
Python script that monitors Proxmox tasks and sends notifications using Ntfy.
More details [here](https://github.com/qtsone/proxmox-ntfy)
2024-04-14 12:24:55 +02:00
Jeroen Bulters
f68ad6acdf Translated using Weblate (Dutch)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/nl/
2024-04-12 11:02:04 +02:00
Alexey Smirnov
a533bf9efb Translated using Weblate (Russian)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ru/
2024-04-12 11:02:04 +02:00
Mohammad Parvin
66ea805cde Translated using Weblate (Persian)
Currently translated at 8.3% (34 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fa/
2024-04-10 11:01:49 +02:00
Mohammad Parvin
7c3b6e4521 Added translation using Weblate (Persian) 2024-04-09 10:33:06 +02:00
Alexander Chekalin
9cb3d056fe Translated using Weblate (Russian)
Currently translated at 97.0% (393 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ru/
2024-04-08 12:02:14 +02:00
Hunter Kehoe
4111bee0c4 fix linting issue 2024-04-07 21:40:24 -06:00
Hunter Kehoe
e4c2b938d3 clean up invalid username code 2024-04-05 08:43:56 -06:00
Hunter Kehoe
fc7cf5933f fix error message for invalid username/password 2024-04-03 21:58:43 -06:00
Hunter Kehoe
e4d22ebd8b allow + in usernames 2024-04-03 21:58:29 -06:00
Fredrik
69d6e0f890 Translated using Weblate (Swedish)
Currently translated at 96.0% (389 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/sv/
2024-04-01 03:02:02 +02:00
grinningmosfet
ecab7fbf65 Translated using Weblate (French)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fr/
2024-04-01 03:02:01 +02:00
Error504TimeOut
75887e4a62 Translated using Weblate (German)
Currently translated at 94.5% (383 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2024-04-01 03:02:00 +02:00
Philipp C. Heckel
130039f5c8 Merge pull request #1071 from truroshan/traccar-example-add-info
Update traccar examples
2024-03-27 12:21:24 -04:00
Roshan Rajak l byteio.ɪn
bec0d4807b Update traccar examples 2024-03-27 18:39:31 +05:30
binwiederhier
5ee62033b5 Bump 2024-03-25 17:21:23 -04:00
binwiederhier
3e02d7b0bb Bump 2024-03-25 17:20:27 -04:00
binwiederhier
290ed1124e Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2024-03-25 17:12:04 -04:00
binwiederhier
fc62682334 Thank you @jceloria for your donation 2024-03-25 09:42:09 -04:00
binwiederhier
28404565d2 Thank you @Circenn5130 for your donation 2024-03-25 09:41:37 -04:00
binwiederhier
f8548e9d46 Thank you @tomroth04 for your donation 2024-03-25 09:41:08 -04:00
Philipp C. Heckel
d90b290cd2 Merge pull request #1066 from binwiederhier/templating-disallow
Disallow certain templates
2024-03-25 09:38:33 -04:00
binwiederhier
21c6776269 Fix linter 2024-03-25 09:34:44 -04:00
binwiederhier
7fed392e0c Disallow certain templates 2024-03-24 23:19:16 -04:00
Philipp C. Heckel
913b59b5e3 Merge pull request #1064 from binwiederhier/templating-3
Message templating
2024-03-24 14:47:32 -04:00
binwiederhier
4692ca7b7f REvert parallel tests 2024-03-24 14:36:14 -04:00
binwiederhier
af16542d02 Removed unused vars 2024-03-24 14:28:10 -04:00
binwiederhier
5511812e30 JSON templating 2024-03-24 14:21:28 -04:00
binwiederhier
547b09a7e5 docs 2024-03-23 14:22:56 -04:00
binwiederhier
b9c176ddba Tests 2024-03-22 22:01:41 -04:00
Philipp C. Heckel
f971377cbb Merge pull request #1062 from theparadox1083/patch-1
Update publish.md (PowerShell 7+ Access Token Example)
2024-03-22 21:43:00 -04:00
binwiederhier
a04f2f9c9a Bla 2024-03-22 20:45:16 -04:00
Patrick
763eafd5dd Update publish.md (PowerShell 7+ Access Token Example)
Corrected PowerShell 7+ Parameter from Authorization to Authentication
Converted Token text to SecureString Inline - token must be of type SecureString
Added comment noting the Token parameter must be a SecureString
2024-03-21 09:38:55 -04:00
binwiederhier
9247dac50d Move things, revert naming 2024-03-20 21:39:17 -04:00
binwiederhier
de65d07518 Simplify(?) templating cases 2024-03-20 21:33:54 -04:00
binwiederhier
1966f80855 Merge branch 'main' into templating 2024-03-20 20:27:12 -04:00
binwiederhier
4b2e38320d BUmp 2024-03-20 20:26:18 -04:00
wunter8
83356f565e remove debug print statement 2024-03-20 10:54:41 -06:00
Hunter Kehoe
7fd5f0b29d allow large HTTP body so long as resulting message is small 2024-03-19 21:56:55 -06:00
Hunter Kehoe
03737dbf5c update docs 2024-03-19 20:55:36 -06:00
Hunter Kehoe
867cf28080 refactor gjson parsing code 2024-03-19 20:30:24 -06:00
Hunter Kehoe
b2eb5b94bd use existing message and title fields for templates 2024-03-18 20:04:40 -06:00
Hunter Kehoe
df7d6baec5 add templating for title and message fields 2024-03-17 21:55:50 -06:00
josé m
a4f5c8dee7 Translated using Weblate (Galician)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/gl/
2024-03-12 13:01:53 +01:00
binwiederhier
4c0ec3f75b Thank you @arthurgleckler for your generous donation 2024-03-10 22:47:19 -04:00
binwiederhier
12bbe9a1ae Thank you @danbartram for your sponsorship 2024-03-10 22:44:43 -04:00
Mazurky
0a589f6242 Translated using Weblate (Slovak)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/sk/
2024-03-10 17:01:44 +01:00
gallegonovato
ab2dd6136e Translated using Weblate (Spanish)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/es/
2024-03-10 17:01:44 +01:00
gallegonovato
4d64515e45 Translated using Weblate (Spanish)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/es/
2024-03-09 16:15:59 +01:00
LiLPandemio
411597ecc2 Translated using Weblate (Spanish)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/es/
2024-03-09 16:15:59 +01:00
Oğuz Ersen
1a426da913 Translated using Weblate (Turkish)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/tr/
2024-03-09 16:15:59 +01:00
Philipp C. Heckel
7936c38feb Update README.md 2024-03-08 12:32:37 -05:00
binwiederhier
d0beaa900f Thank you @stannynuytkens for your sponsorship 2024-03-08 11:12:55 -05:00
Linerly
f4bf8fd9bb Translated using Weblate (Indonesian)
Currently translated at 99.7% (404 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/id/
2024-03-08 07:42:48 +01:00
109247019824
d866cb2fd9 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (405 of 405 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/bg/
2024-03-08 07:42:47 +01:00
binwiederhier
0ab6171962 Blog posts 2024-03-07 23:07:07 -05:00
binwiederhier
b7c2898b9c Thank you @dav23r for your sponsorship 2024-03-07 21:24:33 -05:00
binwiederhier
d155ebb3a4 Thank you @TheTomik1 for your donation 2024-03-07 21:24:07 -05:00
binwiederhier
3d5bb92774 Thank you @Integral-Tech for your sponsorship 2024-03-07 21:23:35 -05:00
binwiederhier
a2f1a45097 Thank you @rwxd for your sponsorship 2024-03-07 21:22:59 -05:00
binwiederhier
b43fff7c7e Thank you @hermannx5 for your donation 2024-03-07 21:22:02 -05:00
binwiederhier
b186c7a324 Thank you for your donation @rxsantos 2024-03-07 21:21:15 -05:00
binwiederhier
e50b6f4075 Thank you @siebej for your donation 2024-03-07 21:19:21 -05:00
binwiederhier
e5342d5eca Thank you @brookmg for your donation 2024-03-07 21:18:55 -05:00
binwiederhier
a25fc1daaa Thank you @dwain-lab for your donation 2024-03-07 21:18:25 -05:00
binwiederhier
6e75108aa9 Thank you @vovayartsev for your sponsorship 2024-03-07 21:17:40 -05:00
binwiederhier
0735a5cb48 Thank you @FrameXX for your donation 2024-03-07 21:17:13 -05:00
binwiederhier
088aede833 Thank you @mursec for your donation 2024-03-07 21:15:58 -05:00
binwiederhier
2119954f67 Thank you @ajay-actuary for your sponsorship 2024-03-07 21:15:00 -05:00
binwiederhier
220b012ae3 Thank you @CataIana for your donation 2024-03-07 21:11:29 -05:00
binwiederhier
e1278a5e92 Thank you @tomershvueli for your donation 2024-03-07 21:10:46 -05:00
binwiederhier
0ae62d36d2 Thank you @zark0s for your sponsorship 2024-03-07 21:10:00 -05:00
binwiederhier
70729edb2b Thank you @Emiliaaah for your donation 2024-03-07 21:09:14 -05:00
binwiederhier
de2f7d3e9b Remove Lemmy 2024-03-07 21:06:46 -05:00
binwiederhier
8c69234e28 Revert Docker user fix 2024-03-07 16:59:42 -05:00
binwiederhier
a9b7c4530b Derp 2024-03-07 16:34:49 -05:00
binwiederhier
76fc015775 Release notes 2024-03-07 16:30:35 -05:00
binwiederhier
ef302d22a9 Avoid panic if user.Current() fails; add logging to "ntfy subscribe" to help figure out what's wrong 2024-03-07 15:56:20 -05:00
Philipp C. Heckel
7ab8ef73a3 Merge pull request #1044 from tripleee/patch-2
Update Danish translations
2024-03-07 15:07:04 -05:00
Philipp C. Heckel
7616b24e30 Merge pull request #1045 from tripleee/patch-3
Update Finnish translations
2024-03-07 15:06:43 -05:00
Philipp C. Heckel
05c1b264f2 Merge pull request #1046 from tripleee/patch-4
Update Norwegian translations
2024-03-07 15:04:43 -05:00
Philipp C. Heckel
35ccfdb8d8 Merge pull request #1043 from tripleee/patch-1
Update Swedish localizations: typo fixes etc
2024-03-07 15:04:01 -05:00
binwiederhier
d744204052 Release notes 2024-03-07 15:01:24 -05:00
binwiederhier
6c3aca4cd6 Merge branch 'main' into cmj2002/main 2024-03-07 14:54:57 -05:00
binwiederhier
d54db74f5a Release notes 2024-03-07 13:08:56 -05:00
binwiederhier
4e1980c2cc Merge branch 'main' into patch-1 2024-03-07 13:05:47 -05:00
Philipp C. Heckel
40f990fffe Merge pull request #1050 from binwiederhier/message-size-limit+delay-limit
Message size limit+delay limit
2024-03-07 13:04:04 -05:00
binwiederhier
8931f25ac5 Ahh 2024-03-07 13:00:39 -05:00
binwiederhier
94f60fb5b8 Lint 2024-03-07 12:53:39 -05:00
binwiederhier
01b397a31a Release notes 2024-03-07 12:50:01 -05:00
binwiederhier
f2cd1edc57 Add some helper for base-url 2024-03-07 12:44:31 -05:00
binwiederhier
243123fd7e Convert duration flags, add docs 2024-03-07 12:22:35 -05:00
binwiederhier
36b33030f3 Add message-{size|delay}-limit 2024-03-07 11:53:12 -05:00
binwiederhier
17709f2fb7 Merge branch 'main' into zhzy0077-patch-1 2024-03-07 10:38:19 -05:00
binwiederhier
a8c17c1856 Release notes 2024-03-07 10:36:56 -05:00
binwiederhier
8ac920d28c Merge branch 'main' of github.com:binwiederhier/ntfy 2024-03-07 10:36:52 -05:00
binwiederhier
239c620707 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2024-03-07 10:36:40 -05:00
Philipp C. Heckel
f2e600d681 Merge pull request #967 from arahja/add_non-root_user_to_containers
Added non-root user to docker images.
2024-03-07 10:33:32 -05:00
Philipp C. Heckel
6486db99fa Merge pull request #1014 from lennart-m/doc/watchtower-example
Docs: Enhance Watchtower example
2024-03-07 10:24:57 -05:00
binwiederhier
766ca05e15 Release notes 2024-03-07 10:24:19 -05:00
binwiederhier
6c41f69db7 Merge branch 'main' into Tom-Hubrecht/main 2024-03-07 10:22:39 -05:00
binwiederhier
cae696c323 Switch to non-deprecated emoji extension in mkdocs 2024-03-07 10:17:43 -05:00
Philipp C. Heckel
42dc8bc3f5 Merge pull request #1049 from binwiederhier/remove-rate-topics
Remove Rate-Topics
2024-03-07 10:17:25 -05:00
binwiederhier
aecf0a5f25 Remove Rate-Topics 2024-03-07 10:07:42 -05:00
Philipp C. Heckel
896a1b007f Merge pull request #1022 from DerRockWolf/patch-1
docs(config.md): fix UnifiedPush links
2024-03-07 08:37:30 -05:00
Philipp C. Heckel
fc5973751a Merge pull request #965 from ksurl/docs-watchtower-token
docs: add shoutrrr auth token url format
2024-03-07 08:36:25 -05:00
Philipp C. Heckel
9ca5133c76 Merge pull request #1001 from UpcraftLP/patch-1
fix apk output path in docs
2024-03-07 08:35:25 -05:00
tripleee
509f59ac3c Update Norwegian translations
* Avoid compound errors
* Typo fix
2024-03-06 19:57:18 +02:00
tripleee
9d8482a119 Update Finnish translations
* Avoid compound errors
* Typo fixes and wording tweaks
2024-03-06 19:48:13 +02:00
tripleee
34343fae02 Update Danish translations
Avoid compound errors
2024-03-06 19:32:24 +02:00
tripleee
1ff6ecf5d8 Update Swedish localizations: typo fixes etc
- Avoid compound errors
- Small wording tweaks
2024-03-06 19:23:00 +02:00
109247019824
f2f7ad8253 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/bg/
2024-02-29 13:02:06 +01:00
109247019824
78de5d4866 Translated using Weblate (Bulgarian)
Currently translated at 98.1% (375 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/bg/
2024-02-27 23:57:45 +01:00
Хусниддин
9449b0b875 Translated using Weblate (Uzbek)
Currently translated at 6.5% (25 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/uz/
2024-02-25 00:02:05 +01:00
Хусниддин
b86c50c60a Added translation using Weblate (Uzbek) 2024-02-23 23:28:55 +01:00
DerRockWolf
34f90facb2 docs(config.md): fix UnifiedPush links 2024-02-09 21:13:59 +00:00
Tom Hubrecht
99a0c72d49 Remove dependence on mkdocs-simple-hooks
Since mkdocs v1.4, the hooks are a native feature
2024-02-05 13:29:55 +01:00
arahja
c4d9e397ab Merge branch 'binwiederhier:main' into add_non-root_user_to_containers 2024-02-02 10:44:16 -06:00
Lennart
3f49f51847 docs: enhance watchtower example
document usage of environment variable WATCHTOWER_NOTIFICATION_SKIP_TITLE for watchtower container so the provided title will not be overwritten
2024-01-30 17:01:36 +01:00
binwiederhier
1d2b759dc0 Bump 2024-01-21 11:27:10 -05:00
binwiederhier
8e62d2af6f Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2024-01-21 11:24:13 -05:00
YMan84
7dfcda9306 Update publish.md with powershell snippet for uploading files 2024-01-15 19:11:55 -05:00
da
b6983e6866 add ntfy-client.service as user service 2024-01-15 22:06:46 +01:00
Up
4cfc64e528 fix docs showing wrong apk path 2024-01-14 10:25:46 +01:00
109247019824
020968961e Translated using Weblate (Bulgarian)
Currently translated at 88.2% (337 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/bg/
2024-01-05 23:06:59 +00:00
Jonne Saloranta
2cfe18c9c8 Translated using Weblate (Finnish)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fi/
2024-01-02 20:09:12 +00:00
Costin Stroie
39dc90e795 Translated using Weblate (Romanian)
Currently translated at 32.4% (124 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ro/
2023-12-31 11:09:05 +01:00
Costin Stroie
fe4101d26c Translated using Weblate (Romanian)
Currently translated at 28.2% (108 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ro/
2023-12-30 10:09:27 +01:00
tinect
80861d33b4 Translated using Weblate (German)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2023-12-30 00:45:43 +01:00
tinect
1383b41062 Translated using Weblate (German)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2023-12-29 01:09:12 +01:00
Panda
99c03b0e83 Translated using Weblate (Danish)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/da/
2023-12-14 00:06:55 +01:00
Philipp C. Heckel
bb4b5d2bc8 Merge pull request #976 from drizzt/patch-1
Fix typo in it.json
2023-12-10 20:19:41 -05:00
M G
4916806298 Added translation using Weblate (Esperanto) 2023-12-10 19:26:48 +01:00
Timothy Redaelli
f350b81da4 Fix typo in it.json 2023-12-09 01:20:48 +01:00
109247019824
1e306e08c9 Translated using Weblate (Bulgarian)
Currently translated at 88.2% (337 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/bg/
2023-12-07 06:05:18 +01:00
binwiederhier
518505fa9d Thank you @beekeeb for your generous sponsorship 2023-12-04 13:27:33 -05:00
binwiederhier
1f4a0601f8 Thank you @tka85 for your generous donation! 2023-12-04 13:25:50 -05:00
binwiederhier
0347fdc192 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-12-04 13:25:07 -05:00
Piotr Icikowski
d207f3ca26 Translated using Weblate (Polish)
Currently translated at 91.8% (351 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pl/
2023-12-03 23:08:22 +01:00
Adam Rahja
f2d6f09671 Added non-root user to docker images. This gives you the ability to run ntfy as a non-root user. resolves #966 2023-11-30 08:08:52 -06:00
ksurl
0f44d20da5 clean up 2023-11-30 00:21:11 +00:00
ksurl
aaf53d5d3f add auth token url format 2023-11-30 00:18:24 +00:00
binwiederhier
154e3945c9 Release notes 2023-11-27 21:56:22 -05:00
binwiederhier
0a82729650 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-11-27 21:56:06 -05:00
Philipp C. Heckel
5876c923a2 Merge pull request #964 from wunter8/patch-5
Update docker compose example
2023-11-27 09:01:24 -05:00
wunter8
a2b56154a7 Update docker compose example
Noticed that this wasn't consistent with the other paths
2023-11-27 06:33:33 -07:00
Cao Mingjun
4b1468cfd8 Web: support pasting images to PublishDialog 2023-11-25 07:39:20 +00:00
Cao Mingjun
00fe639a95 Remove debug logging 2023-11-25 05:22:02 +00:00
Cao Mingjun
94781c89f3 Preview local file before send 2023-11-25 03:39:26 +00:00
Philipp C. Heckel
6e2f9a5bdd Merge pull request #961 from cmj2002/main
Update docker-dev go version
2023-11-24 15:33:47 -05:00
Cao Mingjun
a3312f69fb Web: support pasting images from clipboard 2023-11-24 14:49:56 +00:00
Cao Mingjun
87bcf59bd4 Update docker-dev go version 2023-11-24 14:00:16 +00:00
Caio Facchinato
4817e33942 Translated using Weblate (Portuguese (Brazil))
Currently translated at 74.3% (284 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt_BR/
2023-11-24 06:02:05 +01:00
binwiederhier
141cbad5ad Thank you @ubipo for your sponsorship 2023-11-22 07:19:51 -05:00
binwiederhier
aaa4976c7d Install page 2023-11-19 16:48:19 -05:00
binwiederhier
2525ef71a9 Release notes 2023-11-19 16:42:04 -05:00
binwiederhier
75a2cb9236 A few links 2023-11-19 09:08:49 -05:00
binwiederhier
6b82cb2b7a cache file 2023-11-19 06:55:52 -05:00
binwiederhier
260e24f68b Added Docker Compose docs 2023-11-19 06:49:24 -05:00
binwiederhier
3c8fabe409 Update deps 2023-11-19 05:49:40 -05:00
binwiederhier
1c3ed3ea40 Do not allow empty passwords when creating users 2023-11-19 05:47:41 -05:00
binwiederhier
497f45e5cd Merge branch 'main' of github.com:binwiederhier/ntfy 2023-11-18 21:54:38 -05:00
binwiederhier
f9a411c307 Release notes 2023-11-18 21:54:26 -05:00
binwiederhier
7d755ce604 Add comments and another test to ACL fix 2023-11-18 21:50:01 -05:00
binwiederhier
f64dbcb6b2 Merge branch 'main' into sandman7920/main 2023-11-18 06:28:48 -05:00
Philipp C. Heckel
0b41356179 Merge pull request #949 from cyqsimon/python-pip-override
Allow overriding `python3` & `pip3` binary in Makefile
2023-11-17 05:35:56 -05:00
cyqsimon
0928d99813 Fix mkdocs call 2023-11-17 10:41:16 +08:00
cyqsimon
e724aace49 Allow overriding python3 & pip3 binary in Makefile 2023-11-17 10:13:06 +08:00
binwiederhier
b65044712b Fix linter 2023-11-16 21:04:49 -05:00
binwiederhier
22f48c5ad3 Change mod path 2023-11-16 20:54:58 -05:00
Philipp C. Heckel
1b4d55fb30 Merge pull request #941 from jhotmann/module-version-2
Append /v2 to module so version 2 can be used as a go package
2023-11-16 20:49:57 -05:00
Philipp C. Heckel
ad8b22482b Merge pull request #939 from artemislena/fix-docs-badges
Fix broken badge image links in docs
2023-11-16 20:48:11 -05:00
binwiederhier
780c149c81 Merge branch 'html-emails' 2023-11-16 09:58:51 -05:00
binwiederhier
859a4e4f79 Added another test 2023-11-16 09:58:32 -05:00
Philipp C. Heckel
d0c2b00fbf Merge pull request #693 from binwiederhier/html-emails
WIP: HTML emails
2023-11-16 09:51:45 -05:00
binwiederhier
37091f25a8 Add PR link 2023-11-16 09:51:23 -05:00
binwiederhier
7f1855ad4d It's better than nothing 2023-11-16 09:49:35 -05:00
binwiederhier
b42958de9f Merge branch 'main' of github.com:binwiederhier/ntfy into html-emails 2023-11-16 06:11:00 -05:00
binwiederhier
73eaf7b8b6 Finnish translation 2023-11-16 05:41:41 -05:00
binwiederhier
52361a1c48 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-11-16 05:32:09 -05:00
binwiederhier
9b48d674b4 Merge branch 'main' of github.com:binwiederhier/ntfy 2023-11-16 05:32:05 -05:00
binwiederhier
c0fab933a5 Build docs in venv 2023-11-16 05:31:53 -05:00
binwiederhier
df6d760844 Remove twemoji from docs 2023-11-16 05:22:56 -05:00
Philipp C. Heckel
c6b6c81c83 Merge pull request #947 from wunter8/patch-4
Add JS WebSocket example to docs
2023-11-16 05:18:30 -05:00
wunter8
c2d6e0e316 Include link to websocket example in docs 2023-11-15 09:31:34 -07:00
wunter8
5acc6ad0c4 Add JS websocket example 2023-11-15 09:28:35 -07:00
binwiederhier
a533f352b2 Bump pipelines 2023-11-15 05:55:01 -05:00
binwiederhier
262bb723d9 Thank you @TechMDW for your generous sponsorship 2023-11-15 05:44:02 -05:00
binwiederhier
a97b6de37e Merge branch 'main' of github.com:binwiederhier/ntfy 2023-11-15 05:43:22 -05:00
binwiederhier
9f738e4a85 Thank you @ralhei for your donation 2023-11-15 05:43:11 -05:00
Philipp C. Heckel
8895bd77c1 Merge pull request #944 from wunter8/patch-3
remove broken link in Integrations > Projects+scripts
2023-11-14 11:21:23 -05:00
Philipp C. Heckel
404fd4c720 Merge pull request #945 from vvanouytsel/jetspotter
docs: add jetspotter integration
2023-11-14 11:21:06 -05:00
Vincent Van Ouytsel
058de2d761 docs: add jetspotter integration 2023-11-13 20:22:13 +01:00
wunter8
16d490474d remove broken link 2023-11-13 11:19:19 -07:00
Seppo Lehtimäki
bd2088c480 Translated using Weblate (Finnish)
Currently translated at 95.8% (366 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fi/
2023-11-13 12:03:40 +01:00
Samuele Radici
c42f6289f6 Translated using Weblate (Italian)
Currently translated at 80.8% (309 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2023-11-10 20:35:55 +01:00
Jordan Hotmann
92cfa4040b Append /v2 to module so version 2 can be used as a go package 2023-11-08 13:06:50 -07:00
artemislena
3f3af275e7 T.: Fixed broken links 2023-11-07 20:00:10 +01:00
Seppo Lehtimäki
28c653043e Translated using Weblate (Finnish)
Currently translated at 93.7% (358 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fi/
2023-11-06 12:32:45 +01:00
binwiederhier
abe7275f0c Remove Python version check 2023-11-06 05:55:04 -05:00
binwiederhier
d4af2be7a0 Thank you @pgwiebes for your sponsorship 2023-11-06 05:49:36 -05:00
binwiederhier
8dd4c3e3c0 Bump deps 2023-11-06 05:48:47 -05:00
binwiederhier
af25f164ed Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-11-06 05:32:10 -05:00
Philipp C. Heckel
64ede0f11c Merge pull request #934 from bear/fix-933_macos_client_location
Fix #933 macos client location
2023-11-06 05:16:52 -05:00
Seppo Lehtimäki
d3565c9b87 Added translation using Weblate (Finnish) 2023-11-04 19:39:29 +01:00
binwiederhier
c332c132fa Fix CI 2023-10-29 20:04:37 -04:00
binwiederhier
b3534aecda Format fixes 2023-10-29 19:57:06 -04:00
binwiederhier
8e04912201 Fixing docs links 2023-10-29 12:32:08 -04:00
Philipp C. Heckel
909f9b3d24 Merge pull request #932 from dgtlmoon/changedetection-io
Adding changedetection.io integration guide
2023-10-29 12:18:13 -04:00
binwiederhier
cad38573d7 Thank you for your donation @bahur142 2023-10-29 12:15:20 -04:00
binwiederhier
a3663e43e4 Thank you for your donation @cminter 2023-10-29 12:14:07 -04:00
binwiederhier
6d451785f0 Thank you @richardleach for your sponsorship 2023-10-29 12:13:26 -04:00
binwiederhier
7791901b2d Thank you @bear for your sponsorship. Awesome user name too! 2023-10-29 12:10:35 -04:00
Mike Taylor
2afe1fbeed Update cli.md
Add macOS client location to the options listed
2023-10-28 13:35:52 -04:00
Mike Taylor
e2097e856e Update install.md
Add macOS client.yml location to the list of locations given
2023-10-28 13:33:39 -04:00
dgtlmoon
03e7a3ea65 lower case 2023-10-28 19:08:14 +02:00
dgtlmoon
27f8cc0e52 Adding changedetection.io integration guide 2023-10-28 19:04:56 +02:00
Nikolay Zlatev
1aa82ff06a FullScenario_Default_DenyAll: add user "john" test case
Add new test for user john

The user should have:

"deny" to mytopic_deny*,
  "ro" to mytopic_ro*,
  "rw" to mytopic*,
  "ro" to the rest
2023-10-24 14:02:52 +03:00
Nikolay Zlatev
0ff1f6520a TestMigrationFrom4: move the longest rule on top 2023-10-24 14:02:04 +03:00
Nikolay Zlatev
ff2a354333 TestMigrationFrom1: move the longest rule on top 2023-10-24 14:00:46 +03:00
Nikolay Zlatev
543709336c TestManager_UserManagement: move the longest rule on top 2023-10-24 13:59:39 +03:00
Nikolay Zlatev
afd6d2e0ee Default_DenyAll: move the longest rule on top 2023-10-24 13:57:46 +03:00
Philipp C. Heckel
32efbd5823 Merge pull request #929 from TheBlusky/patch-1
doc/integrations: link to ntfy-android-builder
2023-10-23 20:21:28 -04:00
Dan Lousqui
6dbdabf9fd doc/integrations: link to ntfy-android-builder 2023-10-23 22:15:01 +02:00
Philipp C. Heckel
75d57b9f04 Merge pull request #926 from 0xFOSSMan/main
Added ntfy.fossman.de to docs/integrations.md/Alternative ntfy Servers
2023-10-23 16:05:20 -04:00
Dan Lousqui
554547b431 doc/integrations: link to ntfy-android-builder 2023-10-23 21:22:21 +02:00
FOSSMan
b811da6b83 Added ntfy.fossman.de to docs/integrations.md/Alternative ntfy Servers 2023-10-20 18:42:44 +00:00
binwiederhier
ca6bc1dcb0 Thank you @surfernv for your donation 2023-10-19 07:38:12 -04:00
binwiederhier
7c3fd42a86 Thank you @thomasskou for your donation 2023-10-19 07:33:40 -04:00
binwiederhier
04f12d1e2f Merge branch 'main' of github.com:binwiederhier/ntfy 2023-10-19 07:32:57 -04:00
binwiederhier
c6b8ea90b7 Thank you @YezGotIt for your donation 2023-10-19 07:32:39 -04:00
Philipp C. Heckel
7f8fb8d571 Merge pull request #911 from noman-land/fix-typo
fix: Remove errant word from Action buttons docs
2023-10-19 07:19:58 -04:00
Philipp C. Heckel
f8cfb084e0 Merge pull request #919 from eworm-de/routeros-scripts
doc/integrations: link RouterOS Scripts
2023-10-19 07:19:22 -04:00
binwiederhier
70b084457a Bump deps 2023-10-19 07:18:03 -04:00
binwiederhier
6c12244587 Merge branch 'main' of github.com:binwiederhier/ntfy 2023-10-19 07:15:49 -04:00
binwiederhier
e7c0365079 Changelog 2023-10-19 07:15:42 -04:00
Philipp C. Heckel
43b11de596 Merge pull request #922 from imkero/bugfix/language-with-underline
fix(i18n): correct usage of language str having underline
2023-10-19 07:13:39 -04:00
imkero
ef45ea5a50 fix(i18n): correct usage of language str having underline 2023-10-19 07:48:06 +00:00
Christian Hesse
483edb70bf doc/integrations: link RouterOS Scripts
... which has a module to send notifications to Ntfy.
2023-10-18 09:52:18 +02:00
Rhodri
7516d25bc6 Translated using Weblate (Welsh)
Currently translated at 12.0% (46 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/cy/
2023-10-17 06:06:28 +02:00
PW
2f2918bd3b Translated using Weblate (Chinese (Traditional))
Currently translated at 73.0% (279 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/zh_Hant/
2023-10-17 06:06:27 +02:00
Nikolay Zlatev
7a5572ad7c user.Manager: further improve ACL write/read order
For each user, we should test in order `THE_LONGEST_RULE`->`WRITE_PERMISSION`
2023-10-16 09:41:49 +03:00
Carlos M. Silva
73d2b3363b Translated using Weblate (Portuguese (Brazil))
Currently translated at 57.5% (220 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt_BR/
2023-10-14 21:01:46 +00:00
Nikolay Zlatev
5c9cebf059 user.Manager: fix ACL write, read order
This should fix "read-only access to topic *" being applied before "read-write access to topic _PREFIX_*"
Before this if we have:

ntfy access user "mytopic*" rw
ntfy access user "*" ro

read-only access rule was applied first and user couldn't write to
mytopic*
2023-10-13 15:41:17 +03:00
noman
ba0cc7fbf9 fix: Remove errant word from Action buttons docs 2023-10-08 15:58:29 -04:00
binwiederhier
b7f37138f8 Release notes 2023-10-02 11:49:27 -04:00
Philipp C. Heckel
53a451671c Merge pull request #899 from nihalgonsalves/ng/fix-safari-17-sonoma
fix(pwa): hide install prompt on macOS 14 safari
2023-10-02 11:43:36 -04:00
Philipp C. Heckel
65dff6e8e3 Merge branch 'main' into ng/fix-safari-17-sonoma 2023-10-02 11:42:35 -04:00
Philipp C. Heckel
03a2de961d Merge pull request #900 from nihalgonsalves/ng/remove-firefox-known-issue
docs: remove Firefox-Android known issue
2023-10-02 11:41:56 -04:00
Philipp C. Heckel
b94310a4cc Merge pull request #903 from ohare93/another-ios-shortcut
docs: ios shortcut
2023-10-02 11:41:31 -04:00
Philipp C. Heckel
9c594da847 Merge pull request #902 from Octelly/main
Documentation healthcheck update
2023-10-02 11:41:02 -04:00
Philipp C. Heckel
93e62de3d2 Merge pull request #907 from MaheshBabu11/main
Adding ntfy-java package to libraries built around ntfy
2023-10-02 07:40:56 -04:00
Mahesh Babu
a3efbb3466 Adding ntfy-java package to libraries built around ntfy 2023-10-02 11:27:42 +05:30
Jordan Munch O'Hare
aaf01b98d2 docs: ios shortcut 2023-09-30 16:13:52 +00:00
Octelly
af037b9d70 Update config.md
Field is "healthy", not "health"
2023-09-29 17:50:27 +02:00
Mazurky
5dafd7e4a7 Translated using Weblate (Slovak)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/sk/
2023-09-29 15:00:28 +02:00
Philipp C. Heckel
e2b5f4a9fb Merge pull request #901 from Jawfish/patch-1
Fix typo "aliase" -> "alias"
2023-09-28 07:14:55 -04:00
James Fitzgerald
2e58f0db10 Fix typo "aliase" -> "alias" 2023-09-28 07:01:28 -04:00
binwiederhier
26b31acbae Thank you @dkramer95 for your donation 2023-09-27 23:19:31 -04:00
binwiederhier
66e96244ef Thank you @alexandzors for your donation 2023-09-27 23:16:24 -04:00
Nihal Gonsalves
4dc0183901 docs: remove firefox-android known issue
Closes #789

Firefox released a bug fix with v116.
2023-09-27 23:44:38 +02:00
Nihal Gonsalves
d33eded060 docs: remove Safari sound warning
iOS 17 does indeed play sounds.
2023-09-27 23:43:50 +02:00
Nihal Gonsalves
5913142389 fix: remove deprecated nodesource script 2023-09-27 23:43:50 +02:00
Nihal Gonsalves
66ef28c2e2 fix(pwa): hide install prompt on macos 14 safari 2023-09-27 23:43:50 +02:00
binwiederhier
19c30fc411 Add Alex's post in the install guide 2023-09-24 20:44:57 -04:00
binwiederhier
50bed826d0 Links links links 2023-09-24 20:36:34 -04:00
binwiederhier
b5851dd6d4 Links and blog posts 2023-09-24 18:32:03 -04:00
binwiederhier
ff1ee7d292 Merge branch 'main' of github.com:binwiederhier/ntfy 2023-09-24 18:31:57 -04:00
binwiederhier
9455428048 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-09-24 18:31:52 -04:00
Philipp C. Heckel
0f919f3d49 Merge pull request #895 from binwiederhier/cf-priority
Refined `Priority` header handling
2023-09-24 18:08:45 -04:00
binwiederhier
d556a675e9 Changelog 2023-09-24 18:04:13 -04:00
binwiederhier
bfc1fa5181 Changelog 2023-09-24 18:03:09 -04:00
binwiederhier
d9387dac99 Refine logic 2023-09-24 17:59:23 -04:00
binwiederhier
4818ee57b6 Merge branch 'main' into gusdleon/main 2023-09-24 17:30:04 -04:00
binwiederhier
addb5efebb Release notes 2023-09-24 11:48:26 -04:00
binwiederhier
8adb9ee633 Re-add tzdata to amd64 2023-09-24 11:45:35 -04:00
binwiederhier
418fc98d1a Bump deps 2023-09-24 11:05:21 -04:00
binwiederhier
beffe4a1f2 Thank you @spartan for your sponsorship 2023-09-24 11:02:59 -04:00
Jakob Malchow
ef15b44a1b Translated using Weblate (Italian)
Currently translated at 80.1% (306 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2023-09-20 22:17:49 +02:00
Andrea Guarnaccia
bc802bfc77 Translated using Weblate (Italian)
Currently translated at 80.1% (306 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2023-09-20 22:17:49 +02:00
Federico Nellen
d10a5df3df Translated using Weblate (Italian)
Currently translated at 77.4% (296 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2023-09-19 14:02:05 +00:00
109247019824
b05d27ce45 Translated using Weblate (Bulgarian)
Currently translated at 87.6% (335 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/bg/
2023-09-19 14:02:04 +00:00
Philipp C. Heckel
e61c9fdde9 Merge pull request #887 from wunter8/patch-2
Add instructions for local-only email publishing
2023-09-17 13:07:46 -04:00
wunter8
d2e2791729 Add instructions for local-only email publishing 2023-09-17 10:39:59 -06:00
Mazurky
68a7756621 Translated using Weblate (Slovak)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/sk/
2023-09-10 19:15:07 +02:00
Jose Boullosa
42063cbd5c Translated using Weblate (Galician)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/gl/
2023-09-10 19:15:05 +02:00
josé m
a407a2e0f8 Translated using Weblate (Galician)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/gl/
2023-09-10 19:15:04 +02:00
jonnysemon
6ec1ccf7a3 Translated using Weblate (Arabic)
Currently translated at 85.8% (328 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ar/
2023-09-10 19:15:03 +02:00
Jag_k
044f4182d0 Translated using Weblate (Russian)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ru/
2023-09-10 19:15:02 +02:00
SinecKers
bae30d79c9 Translated using Weblate (Turkish)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/tr/
2023-09-10 19:15:02 +02:00
Christian Meis
25a60969fb Translated using Weblate (German)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2023-09-10 19:15:02 +02:00
binwiederhier
528a67722b Thank you @LuckVintage for your sponsorship 2023-09-10 11:23:18 -04:00
binwiederhier
d29dc95962 Merge branch 'main' of github.com:binwiederhier/ntfy 2023-09-10 11:22:00 -04:00
binwiederhier
fc3d4dcf5e Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-09-10 11:21:56 -04:00
Philipp C. Heckel
3d4218324f Merge pull request #862 from masterujjval/main
readme modified
2023-09-10 15:08:31 +02:00
zhzy0077
6a10bac017 Update template server.yml 2023-09-08 13:21:55 +08:00
Philipp C. Heckel
f6fbb45978 Merge pull request #867 from InvitedToHell/main
Add ios shortcut to the integrations docs
2023-09-06 01:27:40 +02:00
Helly
dee16f543d Add ios shortcut to the integrations docs 2023-09-06 00:52:46 +02:00
jonnysemon
9959d1aa43 Translated using Weblate (Arabic)
Currently translated at 85.6% (327 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ar/
2023-09-05 19:56:20 +02:00
Mazurky
76146c4e74 Translated using Weblate (Slovak)
Currently translated at 45.8% (175 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/sk/
2023-09-04 17:52:06 +02:00
Ron
8a8023fcf8 Translated using Weblate (Chinese (Traditional))
Currently translated at 64.1% (245 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/zh_Hant/
2023-09-04 17:52:04 +02:00
Mattia
4b0d1e448d Translated using Weblate (Italian)
Currently translated at 70.6% (270 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2023-09-04 17:52:03 +02:00
Max Oliver
6748a2f2f3 Translated using Weblate (Portuguese (Brazil))
Currently translated at 57.5% (220 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt_BR/
2023-09-04 17:52:03 +02:00
Bastien S
4c4d772a5f Translated using Weblate (French)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fr/
2023-09-04 17:52:03 +02:00
Gustavo de León
85740d810b Fix cloudflarePriorityIgnore
- Now, only if the header being processed is the "priority" header, the cloudflarePriorityIgnore function is called, solving problems with that header injected by CF
- we make the check with regex now.
2023-09-03 18:55:57 -06:00
binwiederhier
2305ebca24 Add known issues 2023-09-03 09:33:54 -04:00
binwiederhier
59bf388534 FAQ 2023-09-03 07:13:04 -04:00
Philipp C. Heckel
3066b95a6d Merge pull request #863 from VardyNg/main
Completed translations for Traditional Chinese and Simplified Chinese
2023-09-03 12:58:41 +02:00
vardy.ng
1bd77a83bd Updated translation for Traditional and Simplified Chinese, simplified translation for "higher" 2023-09-02 17:34:44 -04:00
vardy.ng
d0b7336da7 completed Traditional Chinese Translation, aligned with Simplified Chinese and English translation 2023-09-02 17:31:07 -04:00
vardy.ng
c80f71bd9b update Simplified Chinese Translation, align with English translation by adding missing keys 2023-09-02 17:30:34 -04:00
vardy.ng
15fa3b7d9f break 中文(Chinese) into 繁體中文(Traditional Chinese, zh_Hant) and 简体中文(Simplified Chinese, zh_Hans) in language drop down 2023-09-02 15:54:29 -04:00
masterujjval
e2d7f2cf29 readme modified 2023-09-02 23:09:53 +05:30
Philipp C. Heckel
3031fb910f Merge pull request #861 from eltociear/patch-1
Update releases.md
2023-09-02 15:40:15 +02:00
Ikko Eltociear Ashimine
d999dbe0a0 Update releases.md
suport -> support
2023-09-02 22:29:45 +09:00
binwiederhier
60d5e66e34 Integration links 2023-09-01 15:36:12 -04:00
binwiederhier
c6964502c4 Thank you @teomarcdhio and @MarcMichalsky for your donation/sponsorship 2023-09-01 15:31:52 -04:00
binwiederhier
ca2633ff82 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-09-01 15:25:42 -04:00
Mazurky
a1625c7f15 Added translation using Weblate (Slovak) 2023-08-31 22:13:26 +02:00
Gustavo de León
30a913c05c Ignore Cloudflare Priority header
With these changes, If the web request contains the new Priority header (RFC 9218), The server will ignore it and continue searching for other headers or query parameters.
2023-08-28 23:20:04 -06:00
josé m
1d02933481 Translated using Weblate (Galician)
Currently translated at 42.4% (162 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/gl/
2023-08-29 06:51:00 +02:00
josé m
62c2ec0614 Translated using Weblate (Galician)
Currently translated at 33.2% (127 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/gl/
2023-08-27 14:54:40 +02:00
binwiederhier
45ca20dec9 Docs 2023-08-26 09:26:54 +02:00
binwiederhier
de362d2322 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-08-26 09:19:16 +02:00
Markus
115e6e9cf8 Translated using Weblate (Norwegian Bokmål)
Currently translated at 51.5% (197 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/nb_NO/
2023-08-25 20:54:02 +02:00
Philipp C. Heckel
f17538b7df Merge pull request #848 from falkheiland/main
Update publish.md
2023-08-22 11:40:38 +02:00
falkheiland
6f68c8cd1f Update publish.md
fixed PowerShell examples
2023-08-22 11:24:35 +02:00
zhzy0077
f565302a0f Fix typo 2023-08-21 11:56:31 +08:00
zhzy0077
6a3f169a47 fix typo. 2023-08-21 11:55:20 +08:00
zhzy0077
6bd8875375 fix typo and update docs 2023-08-21 11:51:48 +08:00
Nguyen Loc
02dd72ba57 Translated using Weblate (Vietnamese)
Currently translated at 4.9% (19 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/vi/
2023-08-19 06:28:28 +02:00
Philipp C. Heckel
63629efae7 Merge pull request #843 from binwiederhier/acl-underscores
Fix ACL issues with underscores
2023-08-18 22:52:01 +02:00
binwiederhier
9015b27803 Release notes 2023-08-18 22:47:36 +02:00
binwiederhier
a5f0670f7f ACLs and underscores, resolves #840 2023-08-18 22:44:52 +02:00
binwiederhier
d7db395016 Release note details 2023-08-17 23:06:52 +02:00
binwiederhier
99eef493d2 Thank you @spirossi for your sponsorship 2023-08-17 22:23:06 +02:00
binwiederhier
0d395249ff Thank you @eenturk for your donation 2023-08-17 22:21:06 +02:00
binwiederhier
5cf1da974a Thank you @skorokithakis for your donation 2023-08-17 22:20:29 +02:00
binwiederhier
2f0ec88f40 Release bump 2023-08-17 22:17:07 +02:00
binwiederhier
d9d3c4a724 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-08-17 22:16:31 +02:00
binwiederhier
bc4d4f424a Pin go-smtp v0.17.0 2023-08-17 22:05:51 +02:00
binwiederhier
67459650d4 Release notes 2023-08-17 21:59:24 +02:00
binwiederhier
c31bce1e2d Merge branch 'main' of github.com:binwiederhier/ntfy 2023-08-17 21:43:05 +02:00
binwiederhier
3e3b556108 Fix excess token deletion bug 2023-08-17 21:42:40 +02:00
Philipp C. Heckel
723daf9497 Merge pull request #819 from nisbet-hubbard/patch-1
Tweak httpd config to use less resources
2023-08-17 21:37:00 +02:00
Erik S
f77958fc35 Translated using Weblate (Russian)
Currently translated at 95.5% (365 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ru/
2023-08-16 06:48:49 +02:00
CaptB
ea9f2c6e35 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/zh_Hans/
2023-08-11 12:51:15 +02:00
Zhiyuan Zheng
3691e59af1 Expose MessageLimit as a configuration 2023-08-11 13:16:53 +08:00
Philipp C. Heckel
7d20238423 Merge pull request #820 from nihalgonsalves/ng/display-external-images
fix: check extension to display external images
2023-08-08 20:47:43 -04:00
Philipp C. Heckel
31131db756 Merge pull request #834 from wunter8/829-empty-userpass-override
fixes #829
2023-08-08 20:44:32 -04:00
Shjosan
17e634c563 Translated using Weblate (Swedish)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/sv/
2023-08-08 11:50:23 +02:00
wunter8
a7dc3d84e0 fix typo 2023-08-07 22:59:24 -06:00
Hunter Kehoe
b80aec90d0 fixes #829 2023-08-06 22:44:55 -06:00
Nguyen Loc
8544733048 Added translation using Weblate (Vietnamese) 2023-08-07 03:58:56 +02:00
binwiederhier
140fdcca81 Thank you @bmcgonag for your sponsorship 2023-08-05 21:13:48 -04:00
Christian Meis
2e08c48742 Translated using Weblate (German)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2023-08-04 17:07:34 +02:00
binwiederhier
4800bb05d2 Thank you @darkmattercoder for your donation 2023-08-03 10:49:04 -04:00
Nihal Gonsalves
384cabede5 feat: check extension to display external images 2023-07-14 13:10:24 +02:00
nisbet-hubbard
4e9eeb1fa1 Add missing note on log file permissions 2023-07-12 20:24:57 +08:00
nisbet-hubbard
a534cc9eca Add server.yml ex. when using proxy
This would help inexperienced sysadmins who may not realise that since TLS terminates at proxy, ntfy is actually listening on a TCP socket that’s using http rather than https.
2023-07-12 20:00:48 +08:00
nisbet-hubbard
e52132c85b Use mod_alias for redirection
It’s a less resource-intensive alternative to mod_rewrite.
2023-07-12 19:48:51 +08:00
nisbet-hubbard
76667ffcf9 Use mod_proxy_http for websocket upgrade
mod_proxy_wstunnel is deprecated as of httpd 2.4.47. It also uses more resources since it relies on mod_rewrite.

See https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#protoupgrade.
2023-07-12 18:18:48 +08:00
binwiederhier
8ba4b72b37 Changelog 2023-07-11 19:46:10 -04:00
Philipp C. Heckel
81e1417ce5 Merge pull request #817 from nihalgonsalves/ng/fix-web-push-i18n
fix(web-push): re-init i18n on each sw message
2023-07-11 19:43:12 -04:00
binwiederhier
c1576b5b19 Blog posts 2023-07-11 09:34:47 -04:00
Nihal Gonsalves
86cc3b9607 chore(build): bump Dockerfile-build go version 2023-07-10 20:14:29 +02:00
Nihal Gonsalves
c7f85e6283 fix(web-push): re-init i18n on each sw message 2023-07-10 20:10:45 +02:00
binwiederhier
6a93dc9d54 Bump packages 2023-07-09 07:51:33 -04:00
binwiederhier
dfd08b337c Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-07-09 07:50:34 -04:00
binwiederhier
2d1f2f319f Changelog, CLI fix 2023-07-09 07:50:00 -04:00
binwiederhier
68f82b9182 Fix wording in tests 2023-07-09 07:36:36 -04:00
Nihal Gonsalves
c8f880c701 Web app: add a “publish as markdown” option 2023-07-09 10:28:07 +02:00
binwiederhier
f2d3f0bdf9 Remove underlines 2023-07-08 22:28:41 -04:00
binwiederhier
9f8c63c7d5 Docs etc 2023-07-08 21:54:54 -04:00
binwiederhier
2b5a1a7a1c Documentation 2023-07-08 21:45:03 -04:00
binwiederhier
499b2fb0d6 Docs, tests 2023-07-08 15:48:08 -04:00
binwiederhier
b7679c7826 Remove setting, add persistence 2023-07-08 15:14:35 -04:00
binwiederhier
ce01a66ff3 Merge remote-tracking branch 'nihalgonsalves/ng/markdown' into markdown 2023-07-07 20:53:15 -04:00
binwiederhier
7582be1a39 Merge branch 'main' into markdown 2023-07-07 20:52:31 -04:00
Nihal Gonsalves
f989fd0743 Web app: implement markdown support 2023-07-06 20:25:20 +02:00
Philipp C. Heckel
097e84aeed Merge pull request #811 from bleetube/ansible_role_ntfy
Add new integration ansible-role-ntfy-alertmanager
2023-07-05 20:43:56 -04:00
Brian Lee
faadb5148f Add new integration ansible-role-ntfy-alertmanager 2023-07-05 14:50:01 -07:00
109247019824
8d9fa31f3d Translated using Weblate (Bulgarian)
Currently translated at 83.7% (320 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/bg/
2023-07-05 22:52:48 +02:00
binwiederhier
56ed4f0515 Blog post 2023-07-05 08:45:26 -04:00
binwiederhier
43981bb675 Merge branch 'main' into markdown 2023-07-04 21:15:08 -04:00
binwiederhier
cd38511ad4 Update deps 2023-07-04 20:52:39 -04:00
binwiederhier
53f13fd811 FAQ 2023-07-04 20:47:19 -04:00
binwiederhier
77cc52e4ac Remove email 2023-07-04 20:11:45 -04:00
binwiederhier
35cb4606f6 FAQ 2023-07-04 20:10:17 -04:00
binwiederhier
d01ed355e0 Changelog 2023-07-04 14:23:44 -04:00
Philipp C. Heckel
495fb24b9a Merge pull request #804 from nimbleghost/rtl
Web app: add RTL support
2023-07-04 14:20:24 -04:00
waclaw66
911fe9e9f8 Translated using Weblate (Czech)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/cs/
2023-07-04 09:52:38 +02:00
nimbleghost
311ffc3672 Format datetimes using i18n lang 2023-07-03 15:24:26 +02:00
nimbleghost
7a1488fcd3 Web app: add RTL support
Ref:

https://mui.com/material-ui/guides/right-to-left
https://m2.material.io/design/usability/bidirectionality.html
2023-07-03 15:24:26 +02:00
Nicola Rizzo
9f255aee25 Translated using Weblate (Italian)
Currently translated at 70.4% (269 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2023-07-02 16:52:40 +02:00
Nicola Rizzo
67603e58bf Translated using Weblate (Italian)
Currently translated at 70.1% (268 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2023-07-01 15:53:21 +02:00
binwiederhier
4267c0d9b6 Update docs 2023-06-30 21:54:27 -04:00
binwiederhier
88eb728fe3 Changelog 2023-06-30 21:51:03 -04:00
binwiederhier
26c835cdd1 Install notes, background change for xs dark mode drawer 2023-06-30 09:58:56 -04:00
binwiederhier
7d3d697a20 Fix goreleaser 2023-06-30 09:30:36 -04:00
binwiederhier
798ee3c23c Merge branch 'main' of github.com:binwiederhier/ntfy 2023-06-30 08:45:44 -04:00
binwiederhier
7581058c93 Bump Go version in pipelines 2023-06-30 08:45:28 -04:00
Philipp C. Heckel
4f0ddfc30d Merge pull request #795 from nimbleghost/pwa-improvements
PWA: Fix reload, Firefox mp3 load, reduce mobile padding
2023-06-30 08:43:19 -04:00
nimbleghost
0b918464c1 Move registerSW out 2023-06-30 08:59:31 +02:00
nimbleghost
57bd37ef2f Fix sidebar colour on mobile 2023-06-29 15:22:59 +02:00
nimbleghost
9fa1288dbc Fix update behaviour 2023-06-29 15:07:18 +02:00
nimbleghost
55eed868fa Reduce padding on mobile / narrow screens 2023-06-29 13:15:06 +02:00
nimbleghost
abb1baeecd Don’t include mp3 due to Firefox sw issue 2023-06-29 13:15:06 +02:00
binwiederhier
5784b07f14 Bump 2023-06-28 20:23:10 -04:00
binwiederhier
8e1e0b3740 Overflow auto 2023-06-28 20:17:49 -04:00
binwiederhier
3f42e0e945 Merge branch 'main' into fix-permission-handling 2023-06-28 20:05:26 -04:00
binwiederhier
9146e439d2 Merge branch 'main' of github.com:binwiederhier/ntfy 2023-06-28 20:03:36 -04:00
binwiederhier
7a14a0b81f Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-06-28 20:03:32 -04:00
Philipp C. Heckel
9247475ab2 Merge pull request #793 from nimbleghost/pwa-action-bar
Make action bar match theme colour when run as PWA
2023-06-28 19:58:41 -04:00
nimbleghost
6b4c04c390 Make action bar match theme colour when run as PWA 2023-06-29 00:22:58 +02:00
nimbleghost
e8216ae9e7 Fix resubscribing when notifications are re-granted
(case: from denied to granted)
2023-06-29 00:02:18 +02:00
nimbleghost
365a0b2832 Fix preferences warnings 2023-06-28 23:38:57 +02:00
Philipp C. Heckel
f78389b6ef Merge pull request #792 from nimbleghost/fix-ntfy-banner
Fix ntfy upgrade banner in dark mode
2023-06-28 15:53:54 -04:00
nimbleghost
0d231d8bd9 Fix snackbars in dark mode 2023-06-28 21:18:04 +02:00
nimbleghost
d838790b8f Fix ntfy upgrade banner in dark mode 2023-06-28 20:43:42 +02:00
nimbleghost
9ce3545901 Fix refreshing things when permission is granted
We refreshed some things but not everything, this makes it more
responsive if you have the settings page open when granting permissions,
for example.
2023-06-28 20:26:54 +02:00
binwiederhier
64ac111d55 Rename UI_MODE to THEME 2023-06-28 13:30:51 -04:00
binwiederhier
e9f170a197 Merge branch 'main' into dark-mode 2023-06-28 13:03:24 -04:00
binwiederhier
e359499e79 Bump install.md 2023-06-28 12:59:30 -04:00
binwiederhier
48a5a55e2f Release notes 2023-06-28 12:54:13 -04:00
nimbleghost
4828e3a691 Add preference 2023-06-28 17:39:44 +02:00
nimbleghost
e607944ad1 Update colors 2023-06-28 17:20:01 +02:00
binwiederhier
d790ad91e2 Bump 2023-06-28 10:58:52 -04:00
nimbleghost
4f39c7c155 Implement dark mode
Resolves #206
2023-06-28 16:52:35 +02:00
怪盗kidou
8db569e8a5 Translated using Weblate (Chinese (Simplified))
Currently translated at 94.5% (361 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/zh_Hans/
2023-06-28 16:52:23 +02:00
binwiederhier
f3932e4b65 Bump deps 2023-06-28 10:38:11 -04:00
Philipp C. Heckel
d40b776205 Merge pull request #788 from nimbleghost/clarify-web-push-other-server
Clarify that web push is not supported on other servers
2023-06-28 10:07:43 -04:00
nimbleghost
9dbac2cb33 Update wording 2023-06-28 15:53:30 +02:00
nimbleghost
9216dbe28a Add Safari IndexedDB known issue 2023-06-28 10:38:02 +02:00
nimbleghost
95cfe16676 Add background notif text to subscribe dialog
only when web push is enabled
2023-06-28 08:57:57 +02:00
nimbleghost
dabb6a481f Add server name to background notification setting 2023-06-28 08:44:05 +02:00
Philipp C. Heckel
d294a692d2 Merge pull request #786 from nimbleghost/web-notif-compat-docs
Add docs detailing web notification support
2023-06-27 20:44:26 -04:00
nimbleghost
0266c707cc Add docs detailing web notification support 2023-06-27 08:28:33 +02:00
Philipp C. Heckel
0b3e268f2c Merge pull request #784 from nimbleghost/pref-responsive
Web app UI: make preferences responsive
2023-06-26 20:45:07 -04:00
binwiederhier
12df164245 Formatting 2023-06-26 20:38:18 -04:00
nimbleghost
d51ca20992 Use dvh for main height
This takes into account browser UI for the viewport calculation
2023-06-26 23:36:04 +02:00
nimbleghost
4a1adaeab2 Make login and sign up form responsive 2023-06-26 23:34:22 +02:00
nimbleghost
fd5bfd161d Web app UI: make preferences responsive 2023-06-26 23:19:58 +02:00
nimbleghost
0c496ca223 Fix iOS prompt 2023-06-26 21:49:53 +02:00
nimbleghost
175ab5ea76 Fix: refresh web push pref on standalone change 2023-06-26 08:56:07 +02:00
binwiederhier
5627097a6c Remove WebPush.js, move to hooks.js; add docblocks 2023-06-25 21:46:26 -04:00
binwiederhier
94fb23ba17 Style changes 2023-06-25 21:10:25 -04:00
binwiederhier
dbd8ed14bf Merge branch 'main' into refresh-pwa-state 2023-06-25 19:24:51 -04:00
binwiederhier
789078e916 Deps 2023-06-25 19:24:22 -04:00
nimbleghost
833293ad77 Set PWA web push enabled on launch instead 2023-06-25 22:00:45 +02:00
nimbleghost
a8d3297c4e Correctly handle standalone (PWA) mode changes
- Also handle notification permission changes
- Remove web push schedule worker since this complicates
  things and doesn’t do _that_ much. We have the reminder
  notification if the user truly doesn’t reload ntfy in
  more than a week.
2023-06-25 21:25:52 +02:00
binwiederhier
532fd3c560 Merge branch 'main' of github.com:binwiederhier/ntfy 2023-06-25 12:58:30 -04:00
binwiederhier
0c937d02df Bump deps 2023-06-25 12:58:18 -04:00
Philipp C. Heckel
8a800a4cb2 Merge pull request #780 from nimbleghost/docs-fix
Update PWA docs
2023-06-25 12:23:59 -04:00
nimbleghost
8f6f97b8e4 Update PWA docs
Clarify that macOS PWA support is limited to Safari on
macOS 14 (releasing Q4 2023).
2023-06-25 17:51:52 +02:00
binwiederhier
79df1c9040 Words 2023-06-25 09:48:12 -04:00
binwiederhier
9a71c3d8dc Shrink images 2023-06-25 09:47:09 -04:00
binwiederhier
74788893e9 Add Safari images 2023-06-25 09:43:51 -04:00
binwiederhier
5c0ecc0250 Cont'd docs 2023-06-24 22:40:40 -04:00
binwiederhier
c0ac2c95ca Cont'd docs 2023-06-24 22:08:57 -04:00
nimbleghost
be4c80e201 Improve web push docs 2023-06-24 20:35:59 +02:00
Philipp C. Heckel
32a110b601 Merge pull request #778 from nimbleghost/pwa-defaults
Default installed PWA to web push enabled
2023-06-24 14:25:22 -04:00
nimbleghost
48d1f7887d Default web push to enabled on PWAs 2023-06-24 20:22:34 +02:00
nimbleghost
dd02267f9b Disable PWA (manifest) when web push is disabled 2023-06-24 20:11:10 +02:00
binwiederhier
142a297552 typo 2023-06-24 14:10:33 -04:00
binwiederhier
9aeea4d9fa Fix text 2023-06-24 13:45:29 -04:00
binwiederhier
e8ecd6b006 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-06-24 13:34:21 -04:00
ayuyydev
71b961d3f3 Translated using Weblate (Chinese (Traditional))
Currently translated at 57.0% (218 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/zh_Hant/
2023-06-24 16:51:13 +02:00
binwiederhier
271056a4aa The last commit 2023-06-20 21:46:09 -04:00
binwiederhier
141565d9d2 Merge branch 'main' into pwa 2023-06-20 21:23:42 -04:00
binwiederhier
c400c5571f Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-06-20 21:23:34 -04:00
binwiederhier
d266579be1 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web into pwa 2023-06-20 21:22:35 -04:00
Oğuz Ersen
f61c67e6be Translated using Weblate (Turkish)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/tr/
2023-06-20 19:49:30 +02:00
nimbleghost
5f6d753cb7 Remove navigation fallback for all except app root 2023-06-19 21:45:55 +02:00
nimbleghost
8211b4cc24 Fix: add v1 to navigation fallback denylist
This is required for the Stripe redirection flow
2023-06-19 21:28:40 +02:00
nimbleghost
000a3e005c Improve dynamic webmanifest setup 2023-06-19 20:41:41 +02:00
nimbleghost
d7aacb8b24 Fix PWA for non-root web roots 2023-06-19 10:58:15 +02:00
binwiederhier
6615aea5dc Fix grant button in language files 2023-06-18 20:29:08 -04:00
binwiederhier
27a4e58fb1 Merge branch 'main' into pwa 2023-06-18 20:24:47 -04:00
binwiederhier
4c7dc4c1ba Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-06-18 20:24:20 -04:00
nimbleghost
5ce78660cf Doc fixes (2) 2023-06-18 22:42:19 +02:00
nimbleghost
89f5cc577e Doc fixes 2023-06-18 21:17:49 +02:00
binwiederhier
dc7dd836c6 web-push-startup-queries 2023-06-18 14:20:22 -04:00
binwiederhier
88c6b4adae Rename web-push-subscriptions-file to web-push-file 2023-06-17 21:57:47 -04:00
binwiederhier
020996ea04 Minor changes 2023-06-17 21:51:04 -04:00
nimbleghost
30a8f66db2 Reorder start/stopWorkers 2023-06-17 22:32:24 +02:00
nimbleghost
9ba733d4e0 Add a reload button to error boundary
There are sometimes edge cases on iOS which cause the app to crash,
it’s good to have a reload button as there’s no browser chrome (reload,
back, forward) in an iOS standalone PWA.
2023-06-17 22:15:02 +02:00
nimbleghost
fafe478e5c Sync localStorage to indexedDB on startup 2023-06-17 22:08:25 +02:00
nimbleghost
b7bb4459f9 Check for image mimetype first
URL heuristic is the second check if there is no mime
2023-06-17 21:53:45 +02:00
nimbleghost
3cd61d8278 Add web push delete test 2023-06-17 21:44:21 +02:00
nimbleghost
2d45e397a7 Add disabled web push test 2023-06-17 21:40:08 +02:00
binwiederhier
ff7e894e4c Add more tests, change endpoint 2023-06-17 14:44:55 -04:00
Philipp C. Heckel
7db25d71dd Merge pull request #774 from skittlesvampir/patch-1
Update Docker-Compose Version in install.md
2023-06-17 07:54:57 -04:00
skittlesvampir
2283cc4ce6 Update Docker-Compose Version in install.md
According to https://docs.docker.com/compose/compose-file/compose-file-v2/#healthcheck, 'start_period' is only supported since version 2.3
2023-06-17 12:19:51 +02:00
binwiederhier
341e84f643 Limit number of webpush subscriptions per subscriber IP 2023-06-16 21:59:07 -04:00
binwiederhier
c43a1166e2 Docs, mostly 2023-06-16 16:55:42 -04:00
binwiederhier
6e95d62726 Cosmetic changess 2023-06-15 22:25:05 -04:00
nimbleghost
b197ea3ab6 Use the same notification pipeline everywhere
This means less duplication and `actions` support for all
notifications.
2023-06-15 00:43:18 +02:00
nimbleghost
fa418eef16 Update develop.md sw docs
turns out http://localhost runs service workers just fine on all desktop
browsers 🤷
2023-06-15 00:42:26 +02:00
nimbleghost
83eb4c39e5 Add i18n to service worker 2023-06-14 20:58:58 +02:00
nimbleghost
2dcad150eb Add missing await 2023-06-14 20:58:24 +02:00
nimbleghost
eebe4f8920 Refactor and document sw.js file 2023-06-14 20:47:56 +02:00
binwiederhier
4dc89f6bc5 Tiny fixes 2023-06-14 13:31:34 -04:00
binwiederhier
9403873a7b Re-increate Dexie version number 2023-06-14 13:08:35 -04:00
binwiederhier
ad36f5db46 Merge branch 'main' into pwa 2023-06-14 11:20:49 -04:00
binwiederhier
e96e35b40b Newly created access tokens are now lowercase only 2023-06-14 11:20:29 -04:00
binwiederhier
aeb60735dc Wording 2023-06-14 11:02:54 -04:00
nimbleghost
67948d0767 Remove stray console.log 2023-06-14 14:52:09 +02:00
nimbleghost
e2120bc66d Improve WebPushEnabled conditional display 2023-06-14 14:33:35 +02:00
nimbleghost
67b9d2eaf6 Add missing await 2023-06-14 14:31:34 +02:00
binwiederhier
7083ed9f6b Move websocketSubscriptions to useConnectionListeners 2023-06-14 08:18:55 -04:00
binwiederhier
790fd43369 Tiny changes 2023-06-14 08:04:16 -04:00
binwiederhier
6b38499bdc Revert alert text and button, and warning 2023-06-13 22:03:00 -04:00
binwiederhier
cf050cc289 Merge branch 'pwa' of github.com:nimbleghost/ntfy into pwa 2023-06-13 21:54:23 -04:00
nimbleghost
390d42c607 Format & fix lint 2023-06-13 14:02:54 +02:00
nimbleghost
8ccfa5c3fb Fix session replica behaviour (merge with session)
The harder-to-refactor parts are the places where exists/username/token
are called within a React component. However, `resetAndRedirect` and
`store` are already called from async contexts, so adding an `await`
is simple.

This thus merges the logic, keeping localStorage for the components to
call, but making sure reset/store behaviour works correctly for the
replica.
2023-06-13 14:00:51 +02:00
Laur
8073bb4e24 Translated using Weblate (Romanian)
Currently translated at 26.7% (102 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ro/
2023-06-13 11:52:47 +02:00
binwiederhier
9e19183471 Merge branch 'main' into pwa 2023-06-12 21:13:16 -04:00
binwiederhier
ae3e8a0094 Blog post 2023-06-12 21:13:05 -04:00
binwiederhier
2d0c043dfd Derp 2023-06-12 21:03:49 -04:00
binwiederhier
a8def0aed2 Make allowed endpoints a list of patterns 2023-06-12 21:01:43 -04:00
binwiederhier
4e44b034bd Merge branch 'main' of github.com:binwiederhier/ntfy into pwa 2023-06-12 19:38:17 -04:00
binwiederhier
e6c83b6efb Add Lemmy, etc. 2023-06-12 08:48:51 -04:00
binwiederhier
1dbcfe3c6e Thank you @KevinWang15 for your donation 2023-06-10 21:11:48 -04:00
binwiederhier
58992fc795 Make DELETE endpoint, add different UI description 2023-06-10 21:09:01 -04:00
binwiederhier
eb220544a3 Change wording in prefs based on setting 2023-06-10 20:51:24 -04:00
binwiederhier
9d5556c7f5 Rename things, add comments 2023-06-10 20:42:02 -04:00
binwiederhier
1abcc88fce Add subscription_topic table, change updated_at type to INT, split expire function 2023-06-09 23:17:48 -04:00
binwiederhier
2e8292a65f No real changes, just renames 2023-06-09 14:32:34 -04:00
nimbleghost
4704b2a0e4 Set default TTL for web push to the cache duration 2023-06-09 11:32:44 +02:00
nimbleghost
9e4eafe8d5 Format 2023-06-09 10:03:11 +02:00
binwiederhier
966ffe1669 More refactor 2023-06-08 23:09:38 -04:00
binwiederhier
9d38aeb863 Docs in server.yml, schemaVersion table, refactoring 2023-06-08 21:45:52 -04:00
binwiederhier
d3ac976d05 Remove web-push-(enabled|duration*), change endpoint, other cosmetic changes 2023-06-08 14:30:19 -04:00
nimbleghost
4ce6fdcc5a Implement http actions in service worker
These are only supported in Chrome-based browsers via the service worker
and not for regular desktop notifications.
2023-06-08 20:12:41 +02:00
binwiederhier
75a4b5bd88 Small refactor 2023-06-08 12:20:12 -04:00
nimbleghost
2f5acee798 Call pushManager.subscribe only if enabled 2023-06-08 10:55:11 +02:00
nimbleghost
46798ac322 Make web push toggle global 2023-06-08 10:46:51 +02:00
nimbleghost
a8db08c7d4 Use attachment URL for image & add timestamp 2023-06-07 21:57:23 +02:00
nimbleghost
f3db0e083e Add release notes 2023-06-07 21:57:22 +02:00
nimbleghost
18edff9afe Add TODO comment about Safari 17 PWA 2023-06-07 21:09:13 +02:00
nimbleghost
03aa67ed68 Remove webPushDefaultEnabled 2023-06-07 21:09:13 +02:00
nimbleghost
46f34ca1e3 Add push service allowlist and topic limit 2023-06-07 21:09:13 +02:00
nimbleghost
0f0074cbab Implement push subscription expiry 2023-06-07 21:09:13 +02:00
nimbleghost
47ad024ec7 Simplify web push UX and updates
- Use a single endpoint
- Use a declarative web push sync hook. This thus handles all edge cases
  that had to be manually handled before: logout, login, account sync,
  etc.
- Simplify UX: browser notifications are always enabled (unless denied),
  web push toggle only shows up if permissions are already granted.
2023-06-07 20:38:21 +02:00
nimbleghost
4944e3ae4b Remove webPushEndpoint from indexeddb
Rely directly on getting it from the browser
2023-06-07 20:38:21 +02:00
nimbleghost
7aa3d8f59b Hide web push toggles if disabled on server 2023-06-07 20:38:21 +02:00
nimbleghost
0c25425346 Use readJSONWithLimit for web push sub/unsub 2023-06-07 20:38:21 +02:00
nimbleghost
4648f83669 Format emojis in the service worker directly 2023-06-07 20:38:21 +02:00
nimbleghost
44913c1668 Replace if err-nil-Fatal check with require.Nil 2023-06-07 20:38:21 +02:00
binwiederhier
20c7650e51 server.yml update 2023-06-07 20:38:21 +02:00
binwiederhier
e8139ad655 Move web-push-config endpoint to config.js 2023-06-07 20:38:21 +02:00
binwiederhier
9e0687e142 Random tiny changes 2023-06-07 20:38:21 +02:00
binwiederhier
7f3e4b5f47 Move stuff to server_web_push.go 2023-06-07 20:38:21 +02:00
binwiederhier
7b23158e0a Cosmetic changes 2023-06-07 20:38:21 +02:00
nimbleghost
f94bb1aa30 Improve web push docs 2023-06-07 20:38:21 +02:00
nimbleghost
a9fef387fa Add web push tests 2023-06-07 20:38:21 +02:00
nimbleghost
ff5c854192 Add PWA, service worker and Web Push
- Use new notification request/opt-in flow for push
- Implement unsubscribing
- Implement muting
- Implement emojis in title
- Add iOS specific PWA warning
- Don’t use websockets when web push is enabled
- Fix duplicate notifications
- Implement default web push setting
- Implement changing subscription type
- Implement web push subscription refresh
- Implement web push notification click
2023-06-07 20:38:20 +02:00
binwiederhier
733ef4664b Deps 2023-06-07 13:24:41 -04:00
binwiederhier
e89c62174d Merge branch 'main' of github.com:binwiederhier/ntfy 2023-06-07 13:24:26 -04:00
binwiederhier
78e437057c Update deps 2023-06-07 13:24:15 -04:00
binwiederhier
7cdd86c99f Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-06-07 13:22:19 -04:00
binwiederhier
c045f4d21f Integrations 2023-06-07 13:22:12 -04:00
Philipp C. Heckel
c65b83a6f5 Merge pull request #767 from binwiederhier/dependabot/npm_and_yarn/web/vite-4.3.9
Bump vite from 4.3.8 to 4.3.9 in /web
2023-06-06 09:10:05 -04:00
Shoshin Akamine
2b2753be21 Translated using Weblate (Japanese)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ja/
2023-06-06 09:51:44 +02:00
dependabot[bot]
fe3db1375a Bump vite from 4.3.8 to 4.3.9 in /web
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.3.8 to 4.3.9.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v4.3.9/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-06 02:43:04 +00:00
JULIANE LEITE
2e9eff69d7 Translated using Weblate (Portuguese (Brazil))
Currently translated at 50.2% (192 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt_BR/
2023-06-04 03:51:46 +02:00
binwiederhier
f58c1e4c84 Fix previous fix 2023-06-01 16:01:39 -04:00
binwiederhier
dc8932cd95 Fix segault in ntfy pub 2023-06-01 14:08:51 -04:00
binwiederhier
04cc71af90 .gitignore 2023-06-01 13:56:32 -04:00
binwiederhier
44d189179d Merge branch 'main' of github.com:binwiederhier/ntfy 2023-05-31 15:36:21 -04:00
binwiederhier
d084a415f3 Do not forward UP messages to upstream 2023-05-31 15:36:02 -04:00
Philipp C. Heckel
953efbee47 Merge pull request #759 from nimbleghost/fix-race-condition
Fix account sync race condition
2023-05-31 14:21:14 -04:00
binwiederhier
807f24723d Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-05-31 13:57:10 -04:00
nimbleghost
453bf435b0 Fix account sync race condition 2023-05-31 19:37:29 +02:00
arjan-s
ca25b80bfb Translated using Weblate (Dutch)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/nl/
2023-05-31 09:52:20 +02:00
Shjosan
afb585e6fd Translated using Weblate (Swedish)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/sv/
2023-05-29 00:51:22 +02:00
Andrew
2e7f474775 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/uk/
2023-05-29 00:51:21 +02:00
gallegonovato
bd39072596 Translated using Weblate (Spanish)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/es/
2023-05-29 00:51:20 +02:00
binwiederhier
7d46f1eed9 Merge branch 'main' into markdown 2023-05-26 21:15:38 -04:00
binwiederhier
b222541ea8 Merge branch 'main' of github.com:binwiederhier/ntfy 2023-05-26 21:06:14 -04:00
Philipp C. Heckel
1368dae849 Merge pull request #754 from nimbleghost/docker-local-build
Add a way to use Docker for building everything
2023-05-26 19:14:35 -04:00
iTentalce
578ccf1643 Translated using Weblate (Czech)
Currently translated at 96.0% (367 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/cs/
2023-05-27 00:51:08 +02:00
Linerly
217c660ba0 Translated using Weblate (Indonesian)
Currently translated at 100.0% (382 of 382 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/id/
2023-05-27 00:51:08 +02:00
nimbleghost
11f8984127 Add a way to use Docker for building everything
I’d like to test #751 on my own instance, but installing all the build
dependencies on my server isn’t ideal - having this script in the repo
would make it possible to simply point my compose file to the git repo
and have it build the Linux binary itself.

Note that it uses a somewhat “inefficient” builder step, i.e. not
combining steps together to reduce layers, as it uses a multi-stage
build to have a lean final image. This makes it easier to re-build if
something needs to change, as the cache is used more optimally.

For example, if only some go files change, most of the build is already
cached and only the go step gets re-run.

The more “efficient” builder step would look like this, but would have
to build the docs, web app and go CLI for any change in any file:

```Dockerfile
FROM golang:1.19-bullseye as builder

RUN apt-get update && \
    curl -fsSL https://deb.nodesource.com/setup_18.x | bash && \
    apt-get install -y \
    build-essential \
    nodejs \
    python3-pip

WORKDIR /app
ADD . .

RUN make web docs cli-linux-server
```
2023-05-26 22:22:21 +02:00
nimbleghost
232c889ce3 Use apt-get in makefile
`apt` is for interactive shell usage, using it in a script results in a
warning as the CLI interface is not stable

> WARNING: apt does not have a stable CLI interface.
> Use with caution in scripts.
2023-05-26 21:14:59 +02:00
Kalil Maciel
02524ca101 Translated using Weblate (Portuguese)
Currently translated at 59.8% (228 of 381 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/pt/
2023-05-25 15:24:44 +02:00
Rogelio Dominguez
38bd4f3ce3 Translated using Weblate (Spanish)
Currently translated at 100.0% (381 of 381 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/es/
2023-05-25 15:24:44 +02:00
Philipp C. Heckel
3101f93d22 Merge pull request #750 from nimbleghost/web-improvements
Fix suppressed eslint issues
2023-05-25 08:03:03 -04:00
nimbleghost
da17e4ee8a Make small code style improvements 2023-05-25 07:17:05 +02:00
nimbleghost
d178be7576 Fix param reassignment issue 2023-05-25 07:17:05 +02:00
nimbleghost
4d90e32fe9 Use es6 destructuring swap for shuffling 2023-05-25 07:17:05 +02:00
nimbleghost
9056d68fc9 Make async for loops performant using Promise.all 2023-05-25 07:17:05 +02:00
binwiederhier
c16da26780 Release notes 2023-05-24 22:28:26 -04:00
binwiederhier
c50633d990 Deps 2023-05-24 22:18:10 -04:00
binwiederhier
517341b5d7 Re-add @emotion due to build errors 2023-05-24 22:15:46 -04:00
binwiederhier
e1dd0c64e2 Merge branch 'main' into switch-to-vite 2023-05-24 21:59:14 -04:00
binwiederhier
e7bf165934 Formatting 2023-05-24 21:59:04 -04:00
binwiederhier
a90bd4cd06 Formatting, npm update 2023-05-24 21:44:12 -04:00
binwiederhier
d1e59fe08c Merge branch 'main' into switch-to-vite 2023-05-24 21:37:28 -04:00
binwiederhier
6bb5274d83 Release notes 2023-05-24 21:34:25 -04:00
binwiederhier
b7c121e78e Revert inputProps things 2023-05-24 21:32:15 -04:00
binwiederhier
1251a4adab Merge branch 'main' into add-eslint 2023-05-24 21:31:53 -04:00
binwiederhier
4cacc02520 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-05-24 20:37:47 -04:00
binwiederhier
7812eb9d19 WIP: Markdown 2023-05-24 20:37:27 -04:00
nimbleghost
d625a003b8 Use esm mui imports for Vite compatibility
See: https://github.com/mui/material-ui/issues/31835#issuecomment-1153393901
2023-05-24 22:16:10 +02:00
nimbleghost
e21327cec5 Add vite
Changes according to Vite defaults:

- Move index.html to root
- Replace `%PUBLIC_URL%` with plain `/`
2023-05-24 22:16:10 +02:00
nimbleghost
7ccc5be9b4 Fix jsx key issue 2023-05-24 21:10:09 +02:00
nimbleghost
9ebeb7f12f Fix mui inputProps 2023-05-24 21:08:33 +02:00
Andrew
d3be1fa359 Translated using Weblate (Ukrainian)
Currently translated at 92.9% (354 of 381 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/uk/
2023-05-24 16:49:12 +02:00
Enzo Salson
e3d530cb90 Translated using Weblate (French)
Currently translated at 97.3% (371 of 381 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/fr/
2023-05-24 16:49:11 +02:00
nimbleghost
951c90763a Add eslint commits to .git-blame-ignore-revs 2023-05-24 12:58:49 +02:00
nimbleghost
59011c8a32 Make manual eslint fixes
These are safe fixes, more complicated fixes can be done separately
(just disabled those errors for now).

- Reorder declarations to fix `no-use-before-define`
- Rename parameters for `no-shadow`
- Remove unused parameters, functions, imports
- Switch from `++` and `—` to `+= 1` and `-= 1` for `no-unary`
- Use object spreading instead of parameter reassignment in auth utils
- Use `window.location` instead of `location` global
- Use inline JSX strings instead of unescaped values
-
2023-05-24 12:58:48 +02:00
nimbleghost
8319f1cf26 Run eslint autofixes 2023-05-24 12:51:53 +02:00
nimbleghost
f558b4dbe9 Add .jsx filename extension
(This is also required for Vite later)
2023-05-24 12:51:53 +02:00
nimbleghost
d7eb1206fe Add eslint with eslint-config-airbnb 2023-05-24 12:51:52 +02:00
binwiederhier
fa29da1a32 Release notes 2023-05-23 20:19:17 -04:00
binwiederhier
a64e365add Update .git-blame-ignore-revs 2023-05-23 20:18:03 -04:00
binwiederhier
c87549e71a Width, again 2023-05-23 20:16:29 -04:00
binwiederhier
ca5d736a71 Line width 2023-05-23 19:29:47 -04:00
binwiederhier
2e27f58963 Merge branch 'main' into add-prettier 2023-05-23 19:23:58 -04:00
binwiederhier
6f230a796e Release notes 2023-05-23 19:23:34 -04:00
Philipp C. Heckel
9e44db78a2 Merge pull request #745 from nimbleghost/update-actions
Update GitHub Actions
2023-05-23 19:17:12 -04:00
nimbleghost
a859ed9f58 Add .git-blame-ignore-revs 2023-05-23 21:13:49 +02:00
nimbleghost
6f6a2d1f69 Run prettier 2023-05-23 21:13:17 +02:00
nimbleghost
206ea312bf Add prettier 2023-05-23 21:12:25 +02:00
nimbleghost
3f8784c8a8 Move checkout up since the cache needs lockfiles 2023-05-23 21:03:58 +02:00
nimbleghost
1761ec0207 Move react-scripts to devDependencies 2023-05-23 20:52:56 +02:00
nimbleghost
ceedca4e27 Update GitHub Actions
- Use the newest versions to solve the deprecation warning
- Remove the cache step as the newest go and node actions have built-in
  caching
- Add the official actions@github.com email address
2023-05-23 20:50:20 +02:00
binwiederhier
ffbf288c9b Merge branch 'main' of github.com:binwiederhier/ntfy 2023-05-23 14:24:16 -04:00
binwiederhier
f8a00dd411 Fix test 2023-05-23 14:24:11 -04:00
Philipp C. Heckel
6a5b5b3763 Merge pull request #743 from nimbleghost/remove-unused-packages
[web] remove unused @emotion packages
2023-05-23 14:19:02 -04:00
nimbleghost
6bd4c8fb71 [web] remove unused @emotion packages 2023-05-23 20:16:38 +02:00
binwiederhier
df2872bebd Merge branch 'main' of github.com:binwiederhier/ntfy 2023-05-23 13:21:12 -04:00
binwiederhier
0393145f42 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-05-23 13:21:05 -04:00
binwiederhier
da06ae4485 Clarify error message for poll requests 2023-05-23 13:20:43 -04:00
Philipp C. Heckel
e10442f6ca Merge pull request #739 from ksurl/token-query-param
docs: generating query param for access token
2023-05-22 21:23:21 -04:00
ksurl
5379474c41 add docs for generating query param for access token 2023-05-23 01:20:56 +00:00
binwiederhier
168ad8bf1b Support encoding any header as RFC 2047 2023-05-21 20:56:56 -04:00
Linerly
89cf84b63e Translated using Weblate (Indonesian)
Currently translated at 100.0% (381 of 381 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/id/
2023-05-22 00:52:00 +02:00
binwiederhier
b3a299ce22 You rock Jonathan. Thank you for your sponsorship @jonathan-kosgei 2023-05-21 17:27:24 -04:00
binwiederhier
7838b253b4 Android release notes 2023-05-21 17:26:29 -04:00
Andrew
7140f18574 Translated using Weblate (Ukrainian)
Currently translated at 77.9% (297 of 381 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/uk/
2023-05-20 14:50:45 +02:00
Shoshin Akamine
5345b9063c Translated using Weblate (Japanese)
Currently translated at 93.9% (358 of 381 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/ja/
2023-05-20 14:50:45 +02:00
binwiederhier
4ad0fb1f57 Fix docs ToC parsing issue 2023-05-19 09:25:25 -04:00
binwiederhier
57eabd3aa5 Thank you @darkdragon-001 for your donation 2023-05-18 15:08:40 -04:00
binwiederhier
df8b18bbb1 Logo in rpm file 2023-05-18 13:51:58 -04:00
binwiederhier
3b3e6ac2cd Rename twilio-from-number to twilio-phone-number 2023-05-18 13:32:27 -04:00
binwiederhier
8ddfd2459d config.js 2023-05-18 13:19:46 -04:00
binwiederhier
25d3a66f91 Upstream access token 2023-05-18 13:08:10 -04:00
binwiederhier
f13a654fe8 Phone number dropdown 2023-05-18 12:04:21 -04:00
binwiederhier
3e594ec210 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-05-18 11:22:01 -04:00
Christian Meis
3cdd300f1c Translated using Weblate (German)
Currently translated at 100.0% (381 of 381 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/de/
2023-05-18 17:21:56 +02:00
binwiederhier
af540f0cf7 Bump deps 2023-05-18 10:13:32 -04:00
Philipp C. Heckel
8753bc0283 Merge pull request #734 from nimbleghost/patch-1
Add native arrsuite & shoutrrr docs
2023-05-18 10:12:21 -04:00
binwiederhier
e3b86bc812 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-05-18 09:59:02 -04:00
Jakob Malchow
db9a4f8dee Translated using Weblate (Italian)
Currently translated at 73.1% (261 of 357 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/it/
2023-05-18 12:51:55 +02:00
nimbleghost
f23d09f83f Also update shoutrrr docs 2023-05-18 12:31:38 +02:00
nimbleghost
0c1cec2ae6 Add note about arrsuite and ntfy
Radarr, Sonarr v4, and Prowlarr no longer _require_ the use of custom shell scripts as they have native support.
2023-05-18 12:04:13 +02:00
Philipp C. Heckel
b154ce5b0c Merge pull request #717 from binwiederhier/twilio
Twilio
2023-05-17 11:23:09 -04:00
binwiederhier
fc1087a42b The last one 2023-05-17 11:19:48 -04:00
binwiederhier
92c384374a More self-review 2023-05-17 10:58:28 -04:00
binwiederhier
ac029c389e Self-review 2023-05-17 10:39:15 -04:00
binwiederhier
79a3259c86 Language file 2023-05-16 22:30:38 -04:00
binwiederhier
2c81773d01 Add call verification 2023-05-16 22:27:48 -04:00
binwiederhier
496d6e74b0 Staticcheck 2023-05-16 15:12:18 -04:00
binwiederhier
5e18ced7d2 Docs 2023-05-16 15:02:53 -04:00
binwiederhier
7c574d73de Cont'd Twilio stuff 2023-05-16 14:15:58 -04:00
binwiederhier
deb4f24856 Cont'd, getting there 2023-05-15 22:06:43 -04:00
binwiederhier
4b9e0c5c38 Phone number verification in publishing 2023-05-15 20:42:43 -04:00
binwiederhier
69b01bc468 Merge branch 'main' into twilio 2023-05-15 20:02:51 -04:00
binwiederhier
f998d4d2ad Fix web app i18n issue in account preferences 2023-05-15 19:49:34 -04:00
binwiederhier
ed0c1abd2f Tiny web app fixes 2023-05-15 13:37:30 -04:00
binwiederhier
04b7b4284a Merge branch 'main' of github.com:binwiederhier/ntfy 2023-05-15 11:05:29 -04:00
binwiederhier
6e21bb742f Bump deps 2023-05-15 11:03:19 -04:00
binwiederhier
e17cf676f4 Release notes 2023-05-15 10:58:37 -04:00
binwiederhier
f14f0aaa26 Add tests for users, slightly change API a bit 2023-05-15 10:42:24 -04:00
Philipp C. Heckel
fae5e7ead6 Merge pull request #731 from l-x/woodpecker-ntfy
Add woodpecker-ntfy plugin to integrations.md
2023-05-15 06:28:15 -04:00
Alexander Wühr
4fdbd42f50 Add woodpecker-ntfy plugin to integrations.md 2023-05-15 12:14:23 +02:00
binwiederhier
4f4165f46f Merge branch 'main' into access-api 2023-05-14 20:43:07 -04:00
Philipp C. Heckel
8f87e9008b Merge pull request #728 from wunter8/attachment-filename
set attachment filename when download through browser
2023-05-14 14:15:31 -04:00
binwiederhier
7c69b96fc7 Release notes 2023-05-14 13:39:31 -04:00
Philipp C. Heckel
5b7c500ca8 Merge pull request #725 from adamantike/misc/migrate-mailer-emoji-json-to-map
Convert mailer_emoji JSON file to map
2023-05-14 13:37:26 -04:00
Hunter Kehoe
028f3aad14 release notes 2023-05-14 11:23:58 -06:00
Hunter Kehoe
4fa0655438 set attachment filename when download through browser 2023-05-14 11:19:49 -06:00
binwiederhier
97fc287b78 User endpoint 2023-05-13 22:07:54 -04:00
binwiederhier
625b13280f WIP: Access API 2023-05-13 14:39:31 -04:00
binwiederhier
539ba43cd1 WIP twilio 2023-05-13 12:26:14 -04:00
Michael Manganiello
49bd6129ff Convert mailer_emoji JSON file to map
This fixes a pending TODO comment regarding inefficient tags to emojis
mapping, by requiring a full scan over emoji aliases to determine
matches.

Instead, now the JSON file is a map, with aliases as keys, and emojis as
values. The script to convert the file with Python was:

```python
import json

with open("./mailer_emoji.json", "r", encoding="utf-8") as f:
    content = json.load(f)

emoji_map = {}
for emoji in content:
    for alias in emoji["aliases"]:
        if alias in emoji_map:
            print("WARNING: Duplicate alias:", alias)
            continue
        emoji_map[alias] = str(emoji["emoji"])

sorted_emoji_map = {k: emoji_map[k] for k in sorted(emoji_map)}

with open("./mailer_emoji_map.json", "w", encoding="utf-8") as f:
    json.dump(sorted_emoji_map, f, indent=4, ensure_ascii=False)
```
2023-05-13 11:43:47 -03:00
binwiederhier
cea434a57c WIP Twilio 2023-05-12 21:47:41 -04:00
binwiederhier
214efbde36 Merge branch 'main' into twilio 2023-05-12 20:02:32 -04:00
binwiederhier
bd81aef1c9 Merge branch 'main' of github.com:binwiederhier/ntfy 2023-05-12 20:02:21 -04:00
binwiederhier
c1db1e4df7 Thank you @CreativeWarlock for your sponsorship 2023-05-12 20:02:00 -04:00
binwiederhier
f99159ee5b WIP calls, remove SMS 2023-05-12 20:01:12 -04:00
Philipp C. Heckel
d674e0280a Merge pull request #721 from adamantike/fix/containsAll-false-positive
Fix false positive in ContainsAll function
2023-05-12 09:50:14 -04:00
Michael Manganiello
ebd4367dda Fix false positive in ContainsAll function
As the `ContainsAll` is working with a match counter, it could return
a false positive when the `haystack` slice contains duplicate elements.

This can be checked with the included testing scenario, with
`haystack = [1, 1]` and `needles = [1, 2]`. Iterating over the haystack
to check for items to be present in needles will increase the match
counter to 2, even if `2` is not present in the first slice.
2023-05-12 09:51:47 -03:00
binwiederhier
d4767caf30 Verify 2023-05-11 13:50:10 -04:00
binwiederhier
a26a6be62b Merge branch 'main' into twilio 2023-05-10 14:18:55 -04:00
binwiederhier
f4e6874ff0 Formatting 2023-05-09 20:57:09 -04:00
binwiederhier
53750e42c5 Limits 2023-05-09 20:45:08 -04:00
binwiederhier
97fe5c3219 Integration list rearrange 2023-05-09 14:34:58 -04:00
Philipp C. Heckel
8b1e9336e7 Merge pull request #616 from bt90/update_integrations
Update integrations
2023-05-09 10:00:33 -04:00
binwiederhier
4b7681b311 Thank you @oaustegard for your sponsorship 2023-05-09 09:39:20 -04:00
binwiederhier
3c2d9040df Changelog 2023-05-09 09:38:43 -04:00
Philipp C. Heckel
931d3ced09 Merge pull request #719 from Aerion/decode-quoted-printable
Add quoted-printable decoding to smtp server
2023-05-09 09:37:27 -04:00
binwiederhier
559f09e7be WIP Docs 2023-05-09 09:33:01 -04:00
Guillaume Taquet Gasperini
5b8520b4e0 Add quoted-printable decoding to smtp server
Some e-mails are sent using quoted-printable encoding [0], resulting in
notifications with weird characters.

This commit adds support for this encoding, resulting in the following:

**Before**
```
A
=3D=3D=3D=3D=3D
B
=3D=3D=3D=3D=3D
C
```

**After**
```
A
=====
B
=====
C
```

[0] https://www.rfc-editor.org/rfc/rfc2045.html
2023-05-08 10:54:34 +02:00
binwiederhier
eb0805a470 Update web app with SMS and calls stuff 2023-05-07 22:28:07 -04:00
binwiederhier
7677c50b0e Merge branch 'main' into twilio 2023-05-07 12:17:37 -04:00
binwiederhier
5bc51eefd9 Bump deps 2023-05-07 12:17:25 -04:00
binwiederhier
23c1983d3d Thanks you @andrejarrell for your donation 2023-05-07 12:00:19 -04:00
binwiederhier
f9e2d6ddcb Add limiters and database changes 2023-05-07 11:59:15 -04:00
binwiederhier
113b7c8a08 Metrics, tests 2023-05-06 14:23:48 -04:00
binwiederhier
fa2c09316c Merge branch 'main' into twilio 2023-05-05 20:15:22 -04:00
binwiederhier
1b98ea2f99 Add Kris' install video link 2023-05-05 20:14:59 -04:00
binwiederhier
3863357207 WIP 2023-05-05 20:14:46 -04:00
binwiederhier
1c0162c434 WIP: Twilio 2023-05-05 16:22:54 -04:00
binwiederhier
63f295a41d Merge branch 'main' of github.com:binwiederhier/ntfy 2023-05-04 13:38:50 -04:00
binwiederhier
683f6811aa Integrations 2023-05-04 13:38:38 -04:00
Philipp C. Heckel
b9add76697 Update README.md 2023-05-02 15:13:48 -04:00
Philipp C. Heckel
9d42f9a598 Update README.md 2023-05-02 15:10:16 -04:00
binwiederhier
6edc7cf29b Release notes 2023-05-02 14:19:56 -04:00
binwiederhier
c997e4911a Fix test and retry 2023-05-02 14:16:59 -04:00
Philipp C. Heckel
9eb94a565d Merge pull request #713 from dropdevrahul/issue-712
fix: removes an issue with topic.Subscribe function not checking dupl…
2023-05-02 13:44:14 -04:00
binwiederhier
d14c4df846 Fix readmFix readmee 2023-05-02 13:40:19 -04:00
Rahul Tyagi
d2fa768151 fix: removes an issue with topic.Subscribe function not checking duplicate ID 2023-05-02 21:40:27 +05:30
binwiederhier
6ad3b2e802 Remove old homepage 2023-05-01 11:58:49 -04:00
binwiederhier
98671ac695 Merge branch 'main' of https://hosted.weblate.org/git/ntfy/web 2023-04-29 13:09:44 -04:00
binwiederhier
bce305514c Update banner in docs 2023-04-29 13:09:25 -04:00
binwiederhier
16dcb54442 Thank you @ScrumpyJack for your sponsorship 2023-04-28 09:04:24 -04:00
binwiederhier
0a5c21172c Update web app og: tag 2023-04-28 09:04:07 -04:00
arjan-s
70d66b7b53 Translated using Weblate (Dutch)
Currently translated at 100.0% (357 of 357 strings)

Translation: ntfy/Web app
Translate-URL: https://hosted.weblate.org/projects/ntfy/web/nl/
2023-04-27 23:51:47 +02:00
binwiederhier
0dedbcda35 Replace favicon 2023-04-27 13:08:24 -04:00
binwiederhier
4a8ed8e65f I don't understand. 2023-04-26 12:36:00 -04:00
binwiederhier
95c4490285 Update changelog 2023-04-26 12:23:06 -04:00
binwiederhier
8a0be007c9 Bump 2023-04-26 12:16:42 -04:00
binwiederhier
ef467d00ae Bump 2023-04-26 12:01:15 -04:00
binwiederhier
918b4e3d61 Thank you @Twisterado for your donation 2023-04-24 13:08:32 -04:00
binwiederhier
59a5077713 Add RFC 2047 encoding support for tags 2023-04-24 13:00:14 -04:00
binwiederhier
d88dbbc90f WIP 2023-04-02 13:59:26 -04:00
bt90
93344bcd69 Add JSON publishing section 2023-02-24 17:06:24 +00:00
bt90
e3d6f692e8 Add mailrise 2023-02-24 17:05:24 +00:00
bt90
7b29bf9f42 Add watchtower 2023-02-24 17:05:04 +00:00
365 changed files with 58780 additions and 23980 deletions

3
.dockerignore Normal file
View File

@@ -0,0 +1,3 @@
dist
*/node_modules
Dockerfile*

11
.git-blame-ignore-revs Normal file
View File

@@ -0,0 +1,11 @@
# https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view
# Run prettier (https://github.com/binwiederhier/ntfy/pull/746)
6f6a2d1f693070bf72e89d86748080e4825c9164
c87549e71a10bc789eac8036078228f06e515a8e
ca5d736a7169eb6b4b0d849e061d5bf9565dcc53
2e27f58963feb9e4d1c573d4745d07770777fa7d
# Run eslint (https://github.com/binwiederhier/ntfy/pull/748)
f558b4dbe9bb5b9e0e87fada1215de2558353173
8319f1cf26113167fb29fe12edaff5db74caf35f

BIN
.github/images/logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View File

Before

Width:  |  Height:  |  Size: 297 KiB

After

Width:  |  Height:  |  Size: 297 KiB

View File

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 225 KiB

View File

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 128 KiB

View File

Before

Width:  |  Height:  |  Size: 224 KiB

After

Width:  |  Height:  |  Size: 224 KiB

View File

Before

Width:  |  Height:  |  Size: 473 KiB

After

Width:  |  Height:  |  Size: 473 KiB

View File

@@ -1,39 +1,24 @@
name: build
on: [push, pull_request]
on: [ push, pull_request ]
jobs:
build:
runs-on: ubuntu-latest
steps:
-
name: Install Go
uses: actions/setup-go@v2
- name: Checkout code
uses: actions/checkout@v3
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: '1.19.x'
-
name: Install node
uses: actions/setup-node@v2
go-version: '1.24.x'
- name: Install node
uses: actions/setup-node@v3
with:
node-version: '18'
-
name: Checkout code
uses: actions/checkout@v2
-
name: Cache Go and npm modules
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/go/bin
~/.npm
web/node_modules
key: ${{ runner.os }}-ntfy-${{ hashFiles('go.sum', 'web/package.lock') }}
restore-keys: ${{ runner.os }}-ntfy-
-
name: Install dependencies
node-version: '20'
cache: 'npm'
cache-dependency-path: './web/package-lock.json'
- name: Install dependencies
run: make build-deps-ubuntu
-
name: Build all the things
- name: Build all the things
run: make build
-
name: Print build results and checksums
- name: Print build results and checksums
run: make cli-build-results

View File

@@ -30,7 +30,7 @@ jobs:
run: |
cd build/ntfy-docs.github.io
git config user.name "GitHub Actions Bot"
git config user.email "<>"
git config user.email "<actions@github.com>"
git add docs/
git commit -m "Updated docs"
git push origin main

View File

@@ -7,44 +7,28 @@ jobs:
release:
runs-on: ubuntu-latest
steps:
-
name: Install Go
uses: actions/setup-go@v2
- name: Checkout code
uses: actions/checkout@v3
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: '1.19.x'
-
name: Install node
uses: actions/setup-node@v2
go-version: '1.24.x'
- name: Install node
uses: actions/setup-node@v3
with:
node-version: '18'
-
name: Checkout code
uses: actions/checkout@v2
-
name: Cache Go and npm modules
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/go/bin
~/.npm
web/node_modules
key: ${{ runner.os }}-ntfy-${{ hashFiles('go.sum', 'web/package.lock') }}
restore-keys: ${{ runner.os }}-ntfy-
-
name: Docker login
node-version: '20'
cache: 'npm'
cache-dependency-path: './web/package-lock.json'
- name: Docker login
uses: docker/login-action@v2
with:
username: ${{ github.repository_owner }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
-
name: Install dependencies
- name: Install dependencies
run: make build-deps-ubuntu
-
name: Build and publish
- name: Build and publish
run: make release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
name: Print build results and checksums
- name: Print build results and checksums
run: make cli-build-results

View File

@@ -1,48 +1,30 @@
name: test
on: [push, pull_request]
on: [ push, pull_request ]
jobs:
test:
runs-on: ubuntu-latest
steps:
-
name: Install Go
uses: actions/setup-go@v2
- name: Checkout code
uses: actions/checkout@v3
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: '1.19.x'
-
name: Install node
uses: actions/setup-node@v2
go-version: '1.24.x'
- name: Install node
uses: actions/setup-node@v3
with:
node-version: '18'
-
name: Checkout code
uses: actions/checkout@v2
-
name: Cache Go and npm modules
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/go/bin
~/.npm
web/node_modules
key: ${{ runner.os }}-ntfy-${{ hashFiles('go.sum', 'web/package.lock') }}
restore-keys: ${{ runner.os }}-ntfy-
-
name: Install dependencies
node-version: '20'
cache: 'npm'
cache-dependency-path: './web/package-lock.json'
- name: Install dependencies
run: make build-deps-ubuntu
-
name: Build docs (required for tests)
- name: Build docs (required for tests)
run: make docs
-
name: Build web app (required for tests)
- name: Build web app (required for tests)
run: make web
-
name: Run tests, formatting, vetting and linting
- name: Run tests, formatting, vetting and linting
run: make check
-
name: Run coverage
- name: Run coverage
run: make coverage
-
name: Upload coverage to codecov.io
- name: Upload coverage to codecov.io
run: make coverage-upload

4
.gitignore vendored
View File

@@ -1,4 +1,5 @@
dist/
dev-dist/
build/
.idea/
.vscode/
@@ -12,3 +13,6 @@ secrets/
node_modules/
.DS_Store
__pycache__
web/dev-dist/
venv/
cmd/key-file.yaml

View File

@@ -1,76 +1,70 @@
version: 2
before:
hooks:
- go mod download
- go mod tidy
builds:
-
id: ntfy_linux_amd64
- id: ntfy_linux_amd64
binary: ntfy
env:
- CGO_ENABLED=1 # required for go-sqlite3
tags: [sqlite_omit_load_extension,osusergo,netgo]
tags: [ sqlite_omit_load_extension,osusergo,netgo ]
ldflags:
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [linux]
goarch: [amd64]
-
id: ntfy_linux_armv6
goos: [ linux ]
goarch: [ amd64 ]
- id: ntfy_linux_armv6
binary: ntfy
env:
- CGO_ENABLED=1 # required for go-sqlite3
- CC=arm-linux-gnueabi-gcc # apt install gcc-arm-linux-gnueabi
tags: [sqlite_omit_load_extension,osusergo,netgo]
tags: [ sqlite_omit_load_extension,osusergo,netgo ]
ldflags:
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [linux]
goarch: [arm]
goarm: [6]
-
id: ntfy_linux_armv7
goos: [ linux ]
goarch: [ arm ]
goarm: [ 6 ]
- id: ntfy_linux_armv7
binary: ntfy
env:
- CGO_ENABLED=1 # required for go-sqlite3
- CC=arm-linux-gnueabi-gcc # apt install gcc-arm-linux-gnueabi
tags: [sqlite_omit_load_extension,osusergo,netgo]
tags: [ sqlite_omit_load_extension,osusergo,netgo ]
ldflags:
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [linux]
goarch: [arm]
goarm: [7]
-
id: ntfy_linux_arm64
goos: [ linux ]
goarch: [ arm ]
goarm: [ 7 ]
- id: ntfy_linux_arm64
binary: ntfy
env:
- CGO_ENABLED=1 # required for go-sqlite3
- CC=aarch64-linux-gnu-gcc # apt install gcc-aarch64-linux-gnu
tags: [sqlite_omit_load_extension,osusergo,netgo]
tags: [ sqlite_omit_load_extension,osusergo,netgo ]
ldflags:
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [linux]
goarch: [arm64]
-
id: ntfy_windows_amd64
goos: [ linux ]
goarch: [ arm64 ]
- id: ntfy_windows_amd64
binary: ntfy
env:
- CGO_ENABLED=0 # explicitly disable, since we don't need go-sqlite3
tags: [noserver] # don't include server files
tags: [ noserver ] # don't include server files
ldflags:
- "-X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [windows]
goarch: [amd64]
-
id: ntfy_darwin_all
goos: [ windows ]
goarch: [ amd64 ]
- id: ntfy_darwin_all
binary: ntfy
env:
- CGO_ENABLED=0 # explicitly disable, since we don't need go-sqlite3
tags: [noserver] # don't include server files
tags: [ noserver ] # don't include server files
ldflags:
- "-X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [darwin]
goarch: [amd64, arm64] # will be combined to "universal binary" (see below)
goos: [ darwin ]
goarch: [ amd64, arm64 ] # will be combined to "universal binary" (see below)
nfpms:
-
package_name: ntfy
- package_name: ntfy
homepage: https://heckel.io/ntfy
maintainer: Philipp C. Heckel <philipp.heckel@gmail.com>
description: Simple pub-sub notification service
@@ -90,6 +84,8 @@ nfpms:
type: "config|noreplace"
- src: client/ntfy-client.service
dst: /lib/systemd/system/ntfy-client.service
- src: client/user/ntfy-client.service
dst: /lib/systemd/user/ntfy-client.service
- dst: /var/cache/ntfy
type: dir
- dst: /var/cache/ntfy/attachments
@@ -97,16 +93,15 @@ nfpms:
- dst: /var/lib/ntfy
type: dir
- dst: /usr/share/ntfy/logo.png
src: web/public/static/img/ntfy.png
src: web/public/static/images/ntfy.png
scripts:
preinstall: "scripts/preinst.sh"
postinstall: "scripts/postinst.sh"
preremove: "scripts/prerm.sh"
postremove: "scripts/postrm.sh"
archives:
-
id: ntfy_linux
builds:
- id: ntfy_linux
ids:
- ntfy_linux_amd64
- ntfy_linux_armv6
- ntfy_linux_armv7
@@ -119,40 +114,32 @@ archives:
- server/ntfy.service
- client/client.yml
- client/ntfy-client.service
replacements:
amd64: x86_64
-
id: ntfy_windows
builds:
- client/user/ntfy-client.service
- id: ntfy_windows
ids:
- ntfy_windows_amd64
format: zip
formats: [ zip ]
wrap_in_directory: true
files:
- LICENSE
- README.md
- client/client.yml
replacements:
amd64: x86_64
-
id: ntfy_darwin
builds:
- id: ntfy_darwin
ids:
- ntfy_darwin_all
wrap_in_directory: true
files:
- LICENSE
- README.md
- client/client.yml
replacements:
darwin: macOS
universal_binaries:
-
id: ntfy_darwin_all
- id: ntfy_darwin_all
replace: true
name_template: ntfy
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Tag }}-next"
version_template: "{{ .Tag }}-next"
changelog:
sort: asc
filters:
@@ -170,14 +157,14 @@ dockers:
- image_templates:
- &arm64v8_image "binwiederhier/ntfy:{{ .Tag }}-arm64v8"
use: buildx
dockerfile: Dockerfile
dockerfile: Dockerfile-arm
goarch: arm64
build_flag_templates:
- "--platform=linux/arm64/v8"
- image_templates:
- &armv7_image "binwiederhier/ntfy:{{ .Tag }}-armv7"
use: buildx
dockerfile: Dockerfile
dockerfile: Dockerfile-arm
goarch: arm
goarm: 7
build_flag_templates:
@@ -185,7 +172,7 @@ dockers:
- image_templates:
- &armv6_image "binwiederhier/ntfy:{{ .Tag }}-armv6"
use: buildx
dockerfile: Dockerfile
dockerfile: Dockerfile-arm
goarch: arm
goarm: 6
build_flag_templates:
@@ -203,3 +190,15 @@ docker_manifests:
- *arm64v8_image
- *armv7_image
- *armv6_image
- name_template: "binwiederhier/ntfy:v{{ .Major }}"
image_templates:
- *amd64_image
- *arm64v8_image
- *armv7_image
- *armv6_image
- name_template: "binwiederhier/ntfy:v{{ .Major }}.{{ .Minor }}"
image_templates:
- *amd64_image
- *arm64v8_image
- *armv7_image
- *armv6_image

View File

@@ -9,6 +9,7 @@ LABEL org.opencontainers.image.licenses="Apache-2.0, GPL-2.0"
LABEL org.opencontainers.image.title="ntfy"
LABEL org.opencontainers.image.description="Send push notifications to your phone or desktop using PUT/POST"
RUN apk add --no-cache tzdata
COPY ntfy /usr/bin
EXPOSE 80/tcp

18
Dockerfile-arm Normal file
View File

@@ -0,0 +1,18 @@
FROM alpine
LABEL org.opencontainers.image.authors="philipp.heckel@gmail.com"
LABEL org.opencontainers.image.url="https://ntfy.sh/"
LABEL org.opencontainers.image.documentation="https://docs.ntfy.sh/"
LABEL org.opencontainers.image.source="https://github.com/binwiederhier/ntfy"
LABEL org.opencontainers.image.vendor="Philipp C. Heckel"
LABEL org.opencontainers.image.licenses="Apache-2.0, GPL-2.0"
LABEL org.opencontainers.image.title="ntfy"
LABEL org.opencontainers.image.description="Send push notifications to your phone or desktop using PUT/POST"
# Alpine does not support adding "tzdata" on ARM anymore, see
# https://github.com/binwiederhier/ntfy/issues/894
COPY ntfy /usr/bin
EXPOSE 80/tcp
ENTRYPOINT ["ntfy"]

62
Dockerfile-build Normal file
View File

@@ -0,0 +1,62 @@
FROM golang:1.24-bullseye as builder
ARG VERSION=dev
ARG COMMIT=unknown
ARG NODE_MAJOR=18
RUN apt-get update && apt-get install -y \
build-essential ca-certificates curl gnupg \
&& mkdir -p /etc/apt/keyrings \
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" >> /etc/apt/sources.list.d/nodesource.list \
&& apt-get update \
&& apt-get install -y \
python3-pip \
python3-venv \
nodejs \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
ADD Makefile .
# docs
ADD ./requirements.txt .
RUN make docs-deps
ADD ./mkdocs.yml .
ADD ./docs ./docs
RUN make docs-build
# web
ADD ./web/package.json ./web/package-lock.json ./web/
RUN make web-deps
ADD ./web ./web
RUN make web-build
# cli & server
ADD go.mod go.sum main.go ./
ADD ./client ./client
ADD ./cmd ./cmd
ADD ./log ./log
ADD ./server ./server
ADD ./user ./user
ADD ./util ./util
RUN make VERSION=$VERSION COMMIT=$COMMIT cli-linux-server
FROM alpine
ARG VERSION=dev
LABEL org.opencontainers.image.authors="philipp.heckel@gmail.com"
LABEL org.opencontainers.image.url="https://ntfy.sh/"
LABEL org.opencontainers.image.documentation="https://docs.ntfy.sh/"
LABEL org.opencontainers.image.source="https://github.com/binwiederhier/ntfy"
LABEL org.opencontainers.image.vendor="Philipp C. Heckel"
LABEL org.opencontainers.image.licenses="Apache-2.0, GPL-2.0"
LABEL org.opencontainers.image.title="ntfy"
LABEL org.opencontainers.image.description="Send push notifications to your phone or desktop using PUT/POST"
LABEL org.opencontainers.image.version="$VERSION"
COPY --from=builder /app/dist/ntfy_linux_server/ntfy /usr/bin/ntfy
EXPOSE 80/tcp
ENTRYPOINT ["ntfy"]

View File

@@ -1,4 +1,6 @@
MAKEFLAGS := --jobs=1
PYTHON := python3
PIP := pip3
VERSION := $(shell git describe --tag)
COMMIT := $(shell git rev-parse --short HEAD)
@@ -31,10 +33,16 @@ help:
@echo " make cli-darwin-server - Build client & server (no GoReleaser, current arch, macOS)"
@echo " make cli-client - Build client only (no GoReleaser, current arch, Linux/macOS/Windows)"
@echo
@echo "Build dev Docker:"
@echo " make docker-dev - Build client & server for current architecture using Docker only"
@echo
@echo "Build web app:"
@echo " make web - Build the web app"
@echo " make web-deps - Install web app dependencies (npm install the universe)"
@echo " make web-build - Actually build the web app"
@echo " make web-lint - Run eslint on the web app"
@echo " make web-fmt - Run prettier on the web app"
@echo " make web-fmt-check - Run prettier on the web app, but don't change anything"
@echo
@echo "Build documentation:"
@echo " make docs - Build the documentation"
@@ -80,40 +88,45 @@ build: web docs cli
update: web-deps-update cli-deps-update docs-deps-update
docker pull alpine
docker-dev:
docker build \
--file ./Dockerfile-build \
--tag binwiederhier/ntfy:$(VERSION) \
--tag binwiederhier/ntfy:dev \
--build-arg VERSION=$(VERSION) \
--build-arg COMMIT=$(COMMIT) \
./
# Ubuntu-specific
build-deps-ubuntu:
sudo apt update
sudo apt install -y \
sudo apt-get update
sudo apt-get install -y \
curl \
gcc-aarch64-linux-gnu \
gcc-arm-linux-gnueabi \
python3 \
python3-venv \
jq
which pip3 || sudo apt install -y python3-pip
which pip3 || sudo apt-get install -y python3-pip
# Documentation
docs: docs-deps docs-build
docs-build: .PHONY
@if ! /bin/echo -e "import sys\nif sys.version_info < (3,8):\n exit(1)" | python3; then \
if which python3.8; then \
echo "python3.8 $(shell which mkdocs) build"; \
python3.8 $(shell which mkdocs) build; \
else \
echo "ERROR: Python version too low. mkdocs-material needs >= 3.8"; \
exit 1; \
fi; \
else \
echo "mkdocs build"; \
mkdocs build; \
fi
docs-venv: .PHONY
$(PYTHON) -m venv ./venv
docs-deps: .PHONY
pip3 install -r requirements.txt
docs-build: docs-venv
(. venv/bin/activate && $(PYTHON) -m mkdocs build)
docs-deps: docs-venv
(. venv/bin/activate && $(PIP) install -r requirements.txt)
docs-deps-update: .PHONY
pip3 install -r requirements.txt --upgrade
(. venv/bin/activate && $(PIP) install -r requirements.txt --upgrade)
# Web app
@@ -127,8 +140,7 @@ web-build:
&& rm -rf ../server/site \
&& mv build ../server/site \
&& rm \
../server/site/config.js \
../server/site/asset-manifest.json
../server/site/config.js
web-deps:
cd web && npm install
@@ -137,6 +149,14 @@ web-deps:
web-deps-update:
cd web && npm update
web-fmt:
cd web && npm run format
web-fmt-check:
cd web && npm run format:check
web-lint:
cd web && npm run lint
# Main server/client build
@@ -200,7 +220,7 @@ cli-deps-static-sites:
touch server/docs/index.html server/site/app.html
cli-deps-all:
go install github.com/goreleaser/goreleaser@latest
go install github.com/goreleaser/goreleaser/v2@latest
cli-deps-gcc-armv6-armv7:
which arm-linux-gnueabi-gcc || { echo "ERROR: ARMv6/ARMv7 cross compiler not installed. On Ubuntu, run: apt install gcc-arm-linux-gnueabi"; exit 1; }
@@ -212,7 +232,7 @@ cli-deps-update:
go get -u
go install honnef.co/go/tools/cmd/staticcheck@latest
go install golang.org/x/lint/golint@latest
go install github.com/goreleaser/goreleaser@latest
go install github.com/goreleaser/goreleaser/v2@latest
cli-build-results:
cat dist/config.yaml
@@ -226,7 +246,7 @@ cli-build-results:
# Test/check targets
check: test fmt-check vet lint staticcheck
check: test web-fmt-check fmt-check vet web-lint lint staticcheck
test: .PHONY
go test $(shell go list ./... | grep -vE 'ntfy/(test|examples|tools)')
@@ -253,7 +273,7 @@ coverage-upload:
# Lint/formatting targets
fmt:
fmt: web-fmt
gofmt -s -w .
fmt-check:
@@ -281,7 +301,7 @@ release: clean cli-deps release-checks docs web check
goreleaser release --clean
release-snapshot: clean cli-deps docs web check
goreleaser release --snapshot --skip-publish --clean
goreleaser release --snapshot --clean
release-checks:
$(eval LATEST_TAG := $(shell git describe --abbrev=0 --tags | cut -c2-))

163
README.md
View File

@@ -1,15 +1,27 @@
![ntfy](web/public/static/img/ntfy.png)
<div align="center" markdown="1">
<sup>Special thanks to:</sup>
<br>
<br>
<a href="https://go.warp.dev/ntfy">
<img alt="Warp sponsorship" width="400" src="https://raw.githubusercontent.com/warpdotdev/brand-assets/refs/heads/main/Github/Sponsor/Warp-Github-LG-02.png">
</a>
### [Warp, built for coding with multiple AI agents.](https://go.warp.dev/ntfy)
[Available for MacOS, Linux, & Windows](https://go.warp.dev/ntfy)<br>
</div>
<hr>
![ntfy](web/public/static/images/ntfy.png)
# ntfy.sh | Send push notifications to your phone or desktop via PUT/POST
[![Release](https://img.shields.io/github/release/binwiederhier/ntfy.svg?color=success&style=flat-square)](https://github.com/binwiederhier/ntfy/releases/latest)
[![Go Reference](https://pkg.go.dev/badge/heckel.io/ntfy.svg)](https://pkg.go.dev/heckel.io/ntfy)
[![Go Reference](https://pkg.go.dev/badge/heckel.io/ntfy.svg)](https://pkg.go.dev/heckel.io/ntfy/v2)
[![Tests](https://github.com/binwiederhier/ntfy/workflows/test/badge.svg)](https://github.com/binwiederhier/ntfy/actions)
[![Go Report Card](https://goreportcard.com/badge/github.com/binwiederhier/ntfy)](https://goreportcard.com/report/github.com/binwiederhier/ntfy)
[![codecov](https://codecov.io/gh/binwiederhier/ntfy/branch/main/graph/badge.svg?token=A597KQ463G)](https://codecov.io/gh/binwiederhier/ntfy)
[![Discord](https://img.shields.io/discord/874398661709295626?label=Discord)](https://discord.gg/cT7ECsZj9w)
[![Matrix](https://img.shields.io/matrix/ntfy:matrix.org?label=Matrix)](https://matrix.to/#/#ntfy:matrix.org)
[![Matrix space](https://img.shields.io/matrix/ntfy-space:matrix.org?label=Matrix+space)](https://matrix.to/#/#ntfy-space:matrix.org)
[![Reddit](https://img.shields.io/reddit/subreddit-subscribers/ntfy?color=%23317f6f&label=-%20r%2Fntfy&style=social)](https://www.reddit.com/r/ntfy/)
[![Healthcheck](https://healthchecks.io/badge/68b65976-b3b0-4102-aec9-980921/kcoEgrLY.svg)](https://ntfy.statuspage.io/)
[![Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod)](https://gitpod.io/#https://github.com/binwiederhier/ntfy)
@@ -18,18 +30,24 @@ notification service. With ntfy, you can **send notifications to your phone or d
**without having to sign up or pay any fees**. If you'd like to run your own instance of the service, you can easily do
so since ntfy is open source.
You can access the free version of ntfy at **[ntfy.sh](https://ntfy.sh)**. There is also an [open source Android app](https://github.com/binwiederhier/ntfy-android)
You can access the free version of ntfy at **[ntfy.sh](https://ntfy.sh)**. There is also an [open-source Android app](https://github.com/binwiederhier/ntfy-android)
available on [Google Play](https://play.google.com/store/apps/details?id=io.heckel.ntfy) or [F-Droid](https://f-droid.org/en/packages/io.heckel.ntfy/),
as well as an [open source iOS app](https://github.com/binwiederhier/ntfy-ios) available on the [App Store](https://apps.apple.com/us/app/ntfy/id1625396347).
<p>
<img src="web/public/static/img/screenshot-curl.png" height="180">
<img src="web/public/static/img/screenshot-web-detail.png" height="180">
<img src="web/public/static/img/screenshot-phone-main.jpg" height="180">
<img src="web/public/static/img/screenshot-phone-detail.jpg" height="180">
<img src="web/public/static/img/screenshot-phone-notification.jpg" height="180">
<img src=".github/images/screenshot-curl.png" height="180">
<img src=".github/images/screenshot-web-detail.png" height="180">
<img src=".github/images/screenshot-phone-main.jpg" height="180">
<img src=".github/images/screenshot-phone-detail.jpg" height="180">
<img src=".github/images/screenshot-phone-notification.jpg" height="180">
</p>
## [ntfy Pro](https://ntfy.sh/app) 💸 🎉
I now offer paid plans for [ntfy.sh](https://ntfy.sh/) if you don't want to self-host, or you want to support the development of
ntfy (→ [Purchase via web app](https://ntfy.sh/app)). You can **buy a plan for as low as $5/month**.
You can also donate via [GitHub Sponsors](https://github.com/sponsors/binwiederhier), and [Liberapay](https://liberapay.com/ntfy).
I would be very humbled by your sponsorship. ❤️
## **[Documentation](https://ntfy.sh/docs/)**
[Getting started](https://ntfy.sh/docs/) |
@@ -38,35 +56,33 @@ as well as an [open source iOS app](https://github.com/binwiederhier/ntfy-ios) a
[Install / Self-hosting](https://ntfy.sh/docs/install/) |
[Building](https://ntfy.sh/docs/develop/)
## Chat / forum
## Chat/forum
There are a few ways to get in touch with me and/or the rest of the community. Feel free to use any of these methods. Whatever
works best for you:
* [Discord server](https://discord.gg/cT7ECsZj9w) - direct chat with the community
* [Matrix room #ntfy](https://matrix.to/#/#ntfy:matrix.org) (+ [Matrix space](https://matrix.to/#/#ntfy-space:matrix.org)) - same chat, bridged from Discord
* [Reddit r/ntfy](https://www.reddit.com/r/ntfy/) - asynchronous forum (_new as of October 2022_)
* [GitHub issues](https://github.com/binwiederhier/ntfy/issues) - questions, features, bugs
* [Email](https://heckel.io/about) - reach me directly (_I usually prefer the other methods_)
## Announcements / beta testers
## Announcements/beta testers
For announcements of new releases and cutting-edge beta versions, please subscribe to the [ntfy.sh/announcements](https://ntfy.sh/announcements)
topic. If you'd like to test the iOS app, join [TestFlight](https://testflight.apple.com/join/P1fFnAm9). For Android betas,
join Discord/Matrix (I'll eventually make a testing channel in Google Play).
## Contributing
I welcome any and all contributions. Just create a PR or an issue. For larger features/ideas, please reach out
on Discord/Matrix first to see if I'd accept them. To contribute code, check out the [build instructions](https://ntfy.sh/docs/develop/)
for the server and the Android app. Or, if you'd like to help translate 🇩🇪 🇺🇸 🇧🇬, you can start immediately in
[Hosted Weblate](https://hosted.weblate.org/projects/ntfy/).
<a href="https://hosted.weblate.org/engage/ntfy/">
<img src="https://hosted.weblate.org/widgets/ntfy/-/multi-blue.svg" alt="Translation status" />
</a>
## Sponsors
I have just very recently started accepting donations via [GitHub Sponsors](https://github.com/sponsors/binwiederhier),
and [Liberapay](https://liberapay.com/ntfy). I would be humbled if you helped me carry the server and developer
account costs. Even small donations are very much appreciated. A big fat **Thank You** to the folks already sponsoring ntfy:
If you'd like to support the ntfy maintainers, please consider donating to [GitHub Sponsors](https://github.com/sponsors/binwiederhier) or
and [Liberapay](https://liberapay.com/ntfy). We would be humbled if you helped carry the server and developer
account costs. Even small donations are very much appreciated.
Thank you to our commercial sponsors, who help keep the service running and the development going:
<a href="https://m.do.co/c/442b929528db"><img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px"></a>
<a href="https://www.magicbell.com/?utm_source=ntfy"><img src="assets/sponsors/magicbell.png" width="180px"></a>
<a href="https://go.warp.dev/ntfy"><img src="https://raw.githubusercontent.com/warpdotdev/brand-assets/refs/heads/main/Logos/Warp-Wordmark-Black.png" width="160px"></a>
And a big fat **Thank You** to the individuals who have sponsored ntfy in the past, or are still sponsoring ntfy:
<a href="https://github.com/neutralinsomniac"><img src="https://github.com/neutralinsomniac.png" width="40px" /></a>
<a href="https://github.com/aspyct"><img src="https://github.com/aspyct.png" width="40px" /></a>
@@ -131,14 +147,97 @@ account costs. Even small donations are very much appreciated. A big fat **Thank
<a href="https://github.com/johman10"><img src="https://github.com/johman10.png" width="40px" /></a>
<a href="https://github.com/R-Gld"><img src="https://github.com/R-Gld.png" width="40px" /></a>
<a href="https://github.com/FingerlessGlov3s"><img src="https://github.com/FingerlessGlov3s.png" width="40px" /></a>
<a href="https://github.com/Twisterado"><img src="https://github.com/Twisterado.png" width="40px" /></a>
<a href="https://github.com/ScrumpyJack"><img src="https://github.com/ScrumpyJack.png" width="40px" /></a>
<a href="https://github.com/andrejarrell"><img src="https://github.com/andrejarrell.png" width="40px" /></a>
<a href="https://github.com/oaustegard"><img src="https://github.com/oaustegard.png" width="40px" /></a>
<a href="https://github.com/CreativeWarlock"><img src="https://github.com/CreativeWarlock.png" width="40px" /></a>
<a href="https://github.com/darkdragon-001"><img src="https://github.com/darkdragon-001.png" width="40px" /></a>
<a href="https://github.com/jonathan-kosgei"><img src="https://github.com/jonathan-kosgei.png" width="40px" /></a>
<a href="https://github.com/KevinWang15"><img src="https://github.com/KevinWang15.png" width="40px" /></a>
<a href="https://github.com/darkmattercoder"><img src="https://github.com/darkmattercoder.png" width="40px" /></a>
<a href="https://github.com/bmcgonag"><img src="https://github.com/bmcgonag.png" width="40px" /></a>
<a href="https://github.com/skorokithakis"><img src="https://github.com/skorokithakis.png" width="40px" /></a>
<a href="https://github.com/eenturk"><img src="https://github.com/eenturk.png" width="40px" /></a>
<a href="https://github.com/spirossi"><img src="https://github.com/spirossi.png" width="40px" /></a>
<a href="https://github.com/teomarcdhio"><img src="https://github.com/teomarcdhio.png" width="40px" /></a>
<a href="https://github.com/MarcMichalsky"><img src="https://github.com/MarcMichalsky.png" width="40px" /></a>
<a href="https://github.com/LuckVintage"><img src="https://github.com/LuckVintage.png" width="40px" /></a>
<a href="https://github.com/spartan"><img src="https://github.com/spartan.png" width="40px" /></a>
<a href="https://github.com/alexandzors"><img src="https://github.com/alexandzors.png" width="40px" /></a>
<a href="https://github.com/dkramer95"><img src="https://github.com/dkramer95.png" width="40px" /></a>
<a href="https://github.com/YezGotIt"><img src="https://github.com/YezGotIt.png" width="40px" /></a>
<a href="https://github.com/thomasskou"><img src="https://github.com/thomasskou.png" width="40px" /></a>
<a href="https://github.com/surfernv"><img src="https://github.com/surfernv.png" width="40px" /></a>
<a href="https://github.com/richardleach"><img src="https://github.com/richardleach.png" width="40px" /></a>
<a href="https://github.com/bear"><img src="https://github.com/bear.png" width="40px" /></a>
<a href="https://github.com/cminter"><img src="https://github.com/cminter.png" width="40px" /></a>
<a href="https://github.com/bahur142"><img src="https://github.com/bahur142.png" width="40px" /></a>
<a href="https://github.com/pgwiebes"><img src="https://github.com/pgwiebes.png" width="40px" /></a>
<a href="https://github.com/ralhei"><img src="https://github.com/ralhei.png" width="40px" /></a>
<a href="https://github.com/TechMDW"><img src="https://github.com/TechMDW.png" width="40px" /></a>
<a href="https://github.com/ubipo"><img src="https://github.com/ubipo.png" width="40px" /></a>
<a href="https://github.com/tka85"><img src="https://github.com/tka85.png" width="40px" /></a>
<a href="https://github.com/beekeeb"><img src="https://github.com/beekeeb.png" width="40px" /></a>
<a href="https://github.com/Emiliaaah"><img src="https://github.com/Emiliaaah.png" width="40px" /></a>
<a href="https://github.com/zark0s"><img src="https://github.com/zark0s.png" width="40px" /></a>
<a href="https://github.com/tomershvueli"><img src="https://github.com/tomershvueli.png" width="40px" /></a>
<a href="https://github.com/CataIana"><img src="https://github.com/CataIana.png" width="40px" /></a>
<a href="https://github.com/ajay-actuary"><img src="https://github.com/ajay-actuary.png" width="40px" /></a>
<a href="https://github.com/mursec"><img src="https://github.com/mursec.png" width="40px" /></a>
<a href="https://github.com/FrameXX"><img src="https://github.com/FrameXX.png" width="40px" /></a>
<a href="https://github.com/vovayartsev"><img src="https://github.com/vovayartsev.png" width="40px" /></a>
<a href="https://github.com/dwain-lab"><img src="https://github.com/dwain-lab.png" width="40px" /></a>
<a href="https://github.com/brookmg"><img src="https://github.com/brookmg.png" width="40px" /></a>
<a href="https://github.com/siebej"><img src="https://github.com/siebej.png" width="40px" /></a>
<a href="https://github.com/rxsantos"><img src="https://github.com/rxsantos.png" width="40px" /></a>
<a href="https://github.com/hermannx5"><img src="https://github.com/hermannx5.png" width="40px" /></a>
<a href="https://github.com/rwxd"><img src="https://github.com/rwxd.png" width="40px" /></a>
<a href="https://github.com/Integral-Tech"><img src="https://github.com/Integral-Tech.png" width="40px" /></a>
<a href="https://github.com/TheTomik1"><img src="https://github.com/TheTomik1.png" width="40px" /></a>
<a href="https://github.com/dav23r"><img src="https://github.com/dav23r.png" width="40px" /></a>
<a href="https://github.com/stannynuytkens"><img src="https://github.com/stannynuytkens.png" width="40px" /></a>
<a href="https://github.com/danbartram"><img src="https://github.com/danbartram.png" width="40px" /></a>
<a href="https://github.com/arthurgleckler"><img src="https://github.com/arthurgleckler.png" width="40px" /></a>
<a href="https://github.com/tomroth04"><img src="https://github.com/tomroth04.png" width="40px" /></a>
<a href="https://github.com/Circenn5130"><img src="https://github.com/Circenn5130.png" width="40px" /></a>
<a href="https://github.com/jceloria"><img src="https://github.com/jceloria.png" width="40px" /></a>
<a href="https://github.com/afunworm"><img src="https://github.com/afunworm.png" width="40px" /></a>
<a href="https://github.com/PTR-inc"><img src="https://github.com/PTR-inc.png" width="40px" /></a>
<a href="https://github.com/spudooli"><img src="https://github.com/spudooli.png" width="40px" /></a>
<a href="https://github.com/IMarkoMC"><img src="https://github.com/IMarkoMC.png" width="40px" /></a>
<a href="https://github.com/rubund"><img src="https://github.com/rubund.png" width="40px" /></a>
<a href="https://github.com/Riolku"><img src="https://github.com/Riolku.png" width="40px" /></a>
<a href="https://github.com/arnbrhm"><img src="https://github.com/arnbrhm.png" width="40px" /></a>
<a href="https://github.com/herzkerl"><img src="https://github.com/herzkerl.png" width="40px" /></a>
<a href="https://github.com/0x45796164"><img src="https://github.com/0x45796164.png" width="40px" /></a>
<a href="https://github.com/madchr1st"><img src="https://github.com/madchr1st.png" width="40px" /></a>
<a href="https://github.com/avalentic"><img src="https://github.com/avalentic.png" width="40px" /></a>
<a href="https://github.com/TheCraiggers"><img src="https://github.com/TheCraiggers.png" width="40px" /></a>
<a href="https://github.com/sheetd"><img src="https://github.com/sheetd.png" width="40px" /></a>
<a href="https://github.com/dlt-green"><img src="https://github.com/dlt-green.png" width="40px" /></a>
<a href="https://github.com/suhlig"><img src="https://github.com/suhlig.png" width="40px" /></a>
<a href="https://github.com/Proximus888"><img src="https://github.com/Proximus888.png" width="40px" /></a>
<a href="https://github.com/wielandp"><img src="https://github.com/wielandp.png" width="40px" /></a>
<a href="https://github.com/chxseh"><img src="https://github.com/chxseh.png" width="40px" /></a>
<a href="https://github.com/user8446"><img src="https://github.com/user8446.png" width="40px" /></a>
<a href="https://github.com/cdf-eagles"><img src="https://github.com/cdf-eagles.png" width="40px" /></a>
I'd also like to thank JetBrains for providing their awesome [IntelliJ IDEA](https://www.jetbrains.com/idea/) to me for free,
and [DigitalOcean](https://m.do.co/c/442b929528db) (*referral link*) for supporting the project:
## Contributing
I welcome any contributions. Just create a PR or an issue. For larger features/ideas, please reach out
on Discord/Matrix first to see if I'd accept them. To contribute code, check out the [build instructions](https://ntfy.sh/docs/develop/)
for the server and the Android app. Or, if you'd like to help translate 🇩🇪 🇺🇸 🇧🇬, you can start immediately in
[Hosted Weblate](https://hosted.weblate.org/projects/ntfy/).
<a href="https://m.do.co/c/442b929528db"><img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px"></a>
<a href="https://hosted.weblate.org/engage/ntfy/">
<img src="https://hosted.weblate.org/widgets/ntfy/-/multi-blue.svg" alt="Translation status" />
</a>
## Code of Conduct
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for
everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity
and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste,
color, religion, or sexual identity and orientation.
**We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.**
@@ -148,7 +247,7 @@ _Please be sure to read the complete [Code of Conduct](CODE_OF_CONDUCT.md)._
Made with ❤️ by [Philipp C. Heckel](https://heckel.io).
The project is dual licensed under the [Apache License 2.0](LICENSE) and the [GPLv2 License](LICENSE.GPLv2).
Third party libraries and resources:
Third-party libraries and resources:
* [github.com/urfave/cli](https://github.com/urfave/cli) (MIT) is used to drive the CLI
* [Mixkit sounds](https://mixkit.co/free-sound-effects/notification/) (Mixkit Free License) are used as notification sounds
* [Sounds from notificationsounds.com](https://notificationsounds.com) (Creative Commons Attribution) are used as notification sounds
@@ -168,3 +267,5 @@ Third party libraries and resources:
* [Regex for auto-linking](https://github.com/bryanwoods/autolink-js) (MIT) is used to highlight links (the library is not used)
* [Statically linking go-sqlite3](https://www.arp242.net/static-go.html)
* [Linked tabs in mkdocs](https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/#linked-tabs)
* [webpush-go](https://github.com/SherClockHolmes/webpush-go) (MIT) is used to send web push notifications
* [Sprig](https://github.com/Masterminds/sprig) (MIT) is used to add template parsing functions

View File

@@ -6,5 +6,7 @@ As of today, I only support the latest version of ntfy. Please make sure you sta
## Reporting a Vulnerability
Please report severe security issues privately via ntfy@heckel.io, [Discord](https://discord.gg/cT7ECsZj9w),
or [Matrix](https://matrix.to/#/#ntfy:matrix.org) (my username is `binwiederhier`).
Please report security vulnerabilities privately via email to [security@mail.ntfy.sh](mailto:security@mail.ntfy.sh).
You can also reach me on [Discord](https://discord.gg/cT7ECsZj9w) or [Matrix](https://matrix.to/#/#ntfy:matrix.org)
(my username is `binwiederhier`).

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -7,27 +7,29 @@ import (
"encoding/json"
"errors"
"fmt"
"heckel.io/ntfy/log"
"heckel.io/ntfy/util"
"heckel.io/ntfy/v2/log"
"heckel.io/ntfy/v2/util"
"io"
"net/http"
"regexp"
"strings"
"sync"
"time"
)
// Event type constants
const (
MessageEvent = "message"
KeepaliveEvent = "keepalive"
OpenEvent = "open"
PollRequestEvent = "poll_request"
// MessageEvent identifies a message event
MessageEvent = "message"
)
const (
maxResponseBytes = 4096
)
var (
topicRegex = regexp.MustCompile(`^[-_A-Za-z0-9]{1,64}$`) // Same as in server/server.go
)
// Client is the ntfy client that can be used to publish and subscribe to ntfy topics
type Client struct {
Messages chan *Message
@@ -96,8 +98,14 @@ func (c *Client) Publish(topic, message string, options ...PublishOption) (*Mess
// To pass title, priority and tags, check out WithTitle, WithPriority, WithTagsList, WithDelay, WithNoCache,
// WithNoFirebase, and the generic WithHeader.
func (c *Client) PublishReader(topic string, body io.Reader, options ...PublishOption) (*Message, error) {
topicURL := c.expandTopicURL(topic)
req, _ := http.NewRequest("POST", topicURL, body)
topicURL, err := c.expandTopicURL(topic)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", topicURL, body)
if err != nil {
return nil, err
}
for _, option := range options {
if err := option(req); err != nil {
return nil, err
@@ -133,11 +141,14 @@ func (c *Client) PublishReader(topic string, body io.Reader, options ...PublishO
// By default, all messages will be returned, but you can change this behavior using a SubscribeOption.
// See WithSince, WithSinceAll, WithSinceUnixTime, WithScheduled, and the generic WithQueryParam.
func (c *Client) Poll(topic string, options ...SubscribeOption) ([]*Message, error) {
topicURL, err := c.expandTopicURL(topic)
if err != nil {
return nil, err
}
ctx := context.Background()
messages := make([]*Message, 0)
msgChan := make(chan *Message)
errChan := make(chan error)
topicURL := c.expandTopicURL(topic)
log.Debug("%s Polling from topic", util.ShortTopicURL(topicURL))
options = append(options, WithPoll())
go func() {
@@ -166,15 +177,18 @@ func (c *Client) Poll(topic string, options ...SubscribeOption) ([]*Message, err
// Example:
//
// c := client.New(client.NewConfig())
// subscriptionID := c.Subscribe("mytopic")
// subscriptionID, _ := c.Subscribe("mytopic")
// for m := range c.Messages {
// fmt.Printf("New message: %s", m.Message)
// }
func (c *Client) Subscribe(topic string, options ...SubscribeOption) string {
func (c *Client) Subscribe(topic string, options ...SubscribeOption) (string, error) {
topicURL, err := c.expandTopicURL(topic)
if err != nil {
return "", err
}
c.mu.Lock()
defer c.mu.Unlock()
subscriptionID := util.RandomString(10)
topicURL := c.expandTopicURL(topic)
log.Debug("%s Subscribing to topic", util.ShortTopicURL(topicURL))
ctx, cancel := context.WithCancel(context.Background())
c.subscriptions[subscriptionID] = &subscription{
@@ -183,7 +197,7 @@ func (c *Client) Subscribe(topic string, options ...SubscribeOption) string {
cancel: cancel,
}
go handleSubscribeConnLoop(ctx, c.Messages, topicURL, subscriptionID, options...)
return subscriptionID
return subscriptionID, nil
}
// Unsubscribe unsubscribes from a topic that has been previously subscribed to using the unique
@@ -199,31 +213,16 @@ func (c *Client) Unsubscribe(subscriptionID string) {
sub.cancel()
}
// UnsubscribeAll unsubscribes from a topic that has been previously subscribed with Subscribe.
// If there are multiple subscriptions matching the topic, all of them are unsubscribed from.
//
// A topic can be either a full URL (e.g. https://myhost.lan/mytopic), a short URL which is then prepended https://
// (e.g. myhost.lan -> https://myhost.lan), or a short name which is expanded using the default host in the
// config (e.g. mytopic -> https://ntfy.sh/mytopic).
func (c *Client) UnsubscribeAll(topic string) {
c.mu.Lock()
defer c.mu.Unlock()
topicURL := c.expandTopicURL(topic)
for _, sub := range c.subscriptions {
if sub.topicURL == topicURL {
delete(c.subscriptions, sub.ID)
sub.cancel()
}
}
}
func (c *Client) expandTopicURL(topic string) string {
func (c *Client) expandTopicURL(topic string) (string, error) {
if strings.HasPrefix(topic, "http://") || strings.HasPrefix(topic, "https://") {
return topic
return topic, nil
} else if strings.Contains(topic, "/") {
return fmt.Sprintf("https://%s", topic)
return fmt.Sprintf("https://%s", topic), nil
}
return fmt.Sprintf("%s/%s", c.config.DefaultHost, topic)
if !topicRegex.MatchString(topic) {
return "", fmt.Errorf("invalid topic name: %s", topic)
}
return fmt.Sprintf("%s/%s", c.config.DefaultHost, topic), nil
}
func handleSubscribeConnLoop(ctx context.Context, msgChan chan *Message, topicURL, subcriptionID string, options ...SubscribeOption) {

View File

@@ -7,7 +7,10 @@
# Default credentials will be used with "ntfy publish" and "ntfy subscribe" if no other credentials are provided.
# You can set a default token to use or a default user:password combination, but not both. For an empty password,
# use empty double-quotes ("")
# use empty double-quotes ("").
#
# To override the default user:password combination or default token for a particular subscription (e.g., to send
# no Authorization header), set the user:pass/token for the subscription to empty double-quotes ("").
# default-token:
@@ -18,7 +21,7 @@
# default-command:
# Subscriptions to topics and their actions. This option is primarily used by the systemd service,
# or if you cann "ntfy subscribe --from-config" directly.
# or if you can "ntfy subscribe --from-config" directly.
#
# Example:
# subscribe:

View File

@@ -3,9 +3,9 @@ package client_test
import (
"fmt"
"github.com/stretchr/testify/require"
"heckel.io/ntfy/client"
"heckel.io/ntfy/log"
"heckel.io/ntfy/test"
"heckel.io/ntfy/v2/client"
"heckel.io/ntfy/v2/log"
"heckel.io/ntfy/v2/test"
"os"
"testing"
"time"
@@ -21,7 +21,7 @@ func TestClient_Publish_Subscribe(t *testing.T) {
defer test.StopServer(t, s, port)
c := client.New(newTestConfig(port))
subscriptionID := c.Subscribe("mytopic")
subscriptionID, _ := c.Subscribe("mytopic")
time.Sleep(time.Second)
msg, err := c.Publish("mytopic", "some message")

View File

@@ -2,6 +2,7 @@ package client
import (
"gopkg.in/yaml.v2"
"heckel.io/ntfy/v2/log"
"os"
)
@@ -23,9 +24,9 @@ type Config struct {
// Subscribe is the struct for a Subscription within Config
type Subscribe struct {
Topic string `yaml:"topic"`
User string `yaml:"user"`
User *string `yaml:"user"`
Password *string `yaml:"password"`
Token string `yaml:"token"`
Token *string `yaml:"token"`
Command string `yaml:"command"`
If map[string]string `yaml:"if"`
}
@@ -44,6 +45,7 @@ func NewConfig() *Config {
// LoadConfig loads the Client config from a yaml file
func LoadConfig(filename string) (*Config, error) {
log.Debug("Loading client config from %s", filename)
b, err := os.ReadFile(filename)
if err != nil {
return nil, err

View File

@@ -2,7 +2,7 @@ package client_test
import (
"github.com/stretchr/testify/require"
"heckel.io/ntfy/client"
"heckel.io/ntfy/v2/client"
"os"
"path/filepath"
"testing"
@@ -37,7 +37,7 @@ subscribe:
require.Equal(t, 4, len(conf.Subscribe))
require.Equal(t, "no-command-with-auth", conf.Subscribe[0].Topic)
require.Equal(t, "", conf.Subscribe[0].Command)
require.Equal(t, "phil", conf.Subscribe[0].User)
require.Equal(t, "phil", *conf.Subscribe[0].User)
require.Equal(t, "mypass", *conf.Subscribe[0].Password)
require.Equal(t, "echo-this", conf.Subscribe[1].Topic)
require.Equal(t, `echo "Message received: $message"`, conf.Subscribe[1].Command)
@@ -67,7 +67,7 @@ subscribe:
require.Equal(t, 1, len(conf.Subscribe))
require.Equal(t, "no-command-with-auth", conf.Subscribe[0].Topic)
require.Equal(t, "", conf.Subscribe[0].Command)
require.Equal(t, "phil", conf.Subscribe[0].User)
require.Equal(t, "phil", *conf.Subscribe[0].User)
require.Equal(t, "", *conf.Subscribe[0].Password)
}
@@ -91,7 +91,7 @@ subscribe:
require.Equal(t, 1, len(conf.Subscribe))
require.Equal(t, "no-command-with-auth", conf.Subscribe[0].Topic)
require.Equal(t, "", conf.Subscribe[0].Command)
require.Equal(t, "phil", conf.Subscribe[0].User)
require.Equal(t, "phil", *conf.Subscribe[0].User)
require.Nil(t, conf.Subscribe[0].Password)
}
@@ -113,7 +113,7 @@ subscribe:
require.Equal(t, 1, len(conf.Subscribe))
require.Equal(t, "no-command-with-auth", conf.Subscribe[0].Topic)
require.Equal(t, "", conf.Subscribe[0].Command)
require.Equal(t, "phil", conf.Subscribe[0].User)
require.Equal(t, "phil", *conf.Subscribe[0].User)
require.Nil(t, conf.Subscribe[0].Password)
}
@@ -134,7 +134,7 @@ subscribe:
require.Equal(t, "tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2", conf.DefaultToken)
require.Equal(t, 1, len(conf.Subscribe))
require.Equal(t, "mytopic", conf.Subscribe[0].Topic)
require.Equal(t, "", conf.Subscribe[0].User)
require.Nil(t, conf.Subscribe[0].User)
require.Nil(t, conf.Subscribe[0].Password)
require.Equal(t, "", conf.Subscribe[0].Token)
require.Nil(t, conf.Subscribe[0].Token)
}

View File

@@ -2,7 +2,7 @@ package client
import (
"fmt"
"heckel.io/ntfy/util"
"heckel.io/ntfy/v2/util"
"net/http"
"strings"
"time"
@@ -72,11 +72,27 @@ func WithAttach(attach string) PublishOption {
return WithHeader("X-Attach", attach)
}
// WithMarkdown instructs the server to interpret the message body as Markdown
func WithMarkdown() PublishOption {
return WithHeader("X-Markdown", "yes")
}
// WithTemplate instructs the server to use a specific template for the message. If templateName is is "yes" or "1",
// the server will interpret the message and title as a template.
func WithTemplate(templateName string) PublishOption {
return WithHeader("X-Template", templateName)
}
// WithFilename sets a filename for the attachment, and/or forces the HTTP body to interpreted as an attachment
func WithFilename(filename string) PublishOption {
return WithHeader("X-Filename", filename)
}
// WithSequenceID sets a sequence ID for the message, allowing updates to existing notifications
func WithSequenceID(sequenceID string) PublishOption {
return WithHeader("X-Sequence-ID", sequenceID)
}
// WithEmail instructs the server to also send the message to the given e-mail address
func WithEmail(email string) PublishOption {
return WithHeader("X-Email", email)
@@ -92,6 +108,11 @@ func WithBearerAuth(token string) PublishOption {
return WithHeader("Authorization", fmt.Sprintf("Bearer %s", token))
}
// WithEmptyAuth clears the Authorization header
func WithEmptyAuth() PublishOption {
return RemoveHeader("Authorization")
}
// WithNoCache instructs the server not to cache the message server-side
func WithNoCache() PublishOption {
return WithHeader("X-Cache", "no")
@@ -182,3 +203,13 @@ func WithQueryParam(param, value string) RequestOption {
return nil
}
}
// RemoveHeader is a generic option to remove a header from a request
func RemoveHeader(header string) RequestOption {
return func(r *http.Request) error {
if header != "" {
delete(r.Header, header)
}
return nil
}
}

View File

@@ -0,0 +1,10 @@
[Unit]
Description=ntfy client
After=network.target
[Service]
ExecStart=/usr/bin/ntfy subscribe --config "%h/.config/ntfy/client.yml" --from-config
Restart=on-failure
[Install]
WantedBy=default.target

View File

@@ -6,8 +6,8 @@ import (
"errors"
"fmt"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/user"
"heckel.io/ntfy/util"
"heckel.io/ntfy/v2/user"
"heckel.io/ntfy/v2/util"
)
func init() {
@@ -105,8 +105,10 @@ func changeAccess(c *cli.Context, manager *user.Manager, username string, topic
return err
}
u, err := manager.User(username)
if err == user.ErrUserNotFound {
if errors.Is(err, user.ErrUserNotFound) {
return fmt.Errorf("user %s does not exist", username)
} else if err != nil {
return err
} else if u.Role == user.RoleAdmin {
return fmt.Errorf("user %s is an admin user, access control entries have no effect", username)
}
@@ -114,13 +116,13 @@ func changeAccess(c *cli.Context, manager *user.Manager, username string, topic
return err
}
if permission.IsReadWrite() {
fmt.Fprintf(c.App.ErrWriter, "granted read-write access to topic %s\n\n", topic)
fmt.Fprintf(c.App.Writer, "granted read-write access to topic %s\n\n", topic)
} else if permission.IsRead() {
fmt.Fprintf(c.App.ErrWriter, "granted read-only access to topic %s\n\n", topic)
fmt.Fprintf(c.App.Writer, "granted read-only access to topic %s\n\n", topic)
} else if permission.IsWrite() {
fmt.Fprintf(c.App.ErrWriter, "granted write-only access to topic %s\n\n", topic)
fmt.Fprintf(c.App.Writer, "granted write-only access to topic %s\n\n", topic)
} else {
fmt.Fprintf(c.App.ErrWriter, "revoked all access to topic %s\n\n", topic)
fmt.Fprintf(c.App.Writer, "revoked all access to topic %s\n\n", topic)
}
return showUserAccess(c, manager, username)
}
@@ -138,7 +140,7 @@ func resetAllAccess(c *cli.Context, manager *user.Manager) error {
if err := manager.ResetAccess("", ""); err != nil {
return err
}
fmt.Fprintln(c.App.ErrWriter, "reset access for all users")
fmt.Fprintln(c.App.Writer, "reset access for all users")
return nil
}
@@ -146,7 +148,7 @@ func resetUserAccess(c *cli.Context, manager *user.Manager, username string) err
if err := manager.ResetAccess(username, ""); err != nil {
return err
}
fmt.Fprintf(c.App.ErrWriter, "reset access for user %s\n\n", username)
fmt.Fprintf(c.App.Writer, "reset access for user %s\n\n", username)
return showUserAccess(c, manager, username)
}
@@ -154,7 +156,7 @@ func resetUserTopicAccess(c *cli.Context, manager *user.Manager, username string
if err := manager.ResetAccess(username, topic); err != nil {
return err
}
fmt.Fprintf(c.App.ErrWriter, "reset access for user %s and topic %s\n\n", username, topic)
fmt.Fprintf(c.App.Writer, "reset access for user %s and topic %s\n\n", username, topic)
return showUserAccess(c, manager, username)
}
@@ -175,7 +177,7 @@ func showAllAccess(c *cli.Context, manager *user.Manager) error {
func showUserAccess(c *cli.Context, manager *user.Manager, username string) error {
users, err := manager.User(username)
if err == user.ErrUserNotFound {
if errors.Is(err, user.ErrUserNotFound) {
return fmt.Errorf("user %s does not exist", username)
} else if err != nil {
return err
@@ -193,34 +195,42 @@ func showUsers(c *cli.Context, manager *user.Manager, users []*user.User) error
if u.Tier != nil {
tier = u.Tier.Name
}
fmt.Fprintf(c.App.ErrWriter, "user %s (role: %s, tier: %s)\n", u.Name, u.Role, tier)
provisioned := ""
if u.Provisioned {
provisioned = ", server config"
}
fmt.Fprintf(c.App.Writer, "user %s (role: %s, tier: %s%s)\n", u.Name, u.Role, tier, provisioned)
if u.Role == user.RoleAdmin {
fmt.Fprintf(c.App.ErrWriter, "- read-write access to all topics (admin role)\n")
fmt.Fprintf(c.App.Writer, "- read-write access to all topics (admin role)\n")
} else if len(grants) > 0 {
for _, grant := range grants {
if grant.Allow.IsReadWrite() {
fmt.Fprintf(c.App.ErrWriter, "- read-write access to topic %s\n", grant.TopicPattern)
} else if grant.Allow.IsRead() {
fmt.Fprintf(c.App.ErrWriter, "- read-only access to topic %s\n", grant.TopicPattern)
} else if grant.Allow.IsWrite() {
fmt.Fprintf(c.App.ErrWriter, "- write-only access to topic %s\n", grant.TopicPattern)
grantProvisioned := ""
if grant.Provisioned {
grantProvisioned = " (server config)"
}
if grant.Permission.IsReadWrite() {
fmt.Fprintf(c.App.Writer, "- read-write access to topic %s%s\n", grant.TopicPattern, grantProvisioned)
} else if grant.Permission.IsRead() {
fmt.Fprintf(c.App.Writer, "- read-only access to topic %s%s\n", grant.TopicPattern, grantProvisioned)
} else if grant.Permission.IsWrite() {
fmt.Fprintf(c.App.Writer, "- write-only access to topic %s%s\n", grant.TopicPattern, grantProvisioned)
} else {
fmt.Fprintf(c.App.ErrWriter, "- no access to topic %s\n", grant.TopicPattern)
fmt.Fprintf(c.App.Writer, "- no access to topic %s%s\n", grant.TopicPattern, grantProvisioned)
}
}
} else {
fmt.Fprintf(c.App.ErrWriter, "- no topic-specific permissions\n")
fmt.Fprintf(c.App.Writer, "- no topic-specific permissions\n")
}
if u.Name == user.Everyone {
access := manager.DefaultAccess()
if access.IsReadWrite() {
fmt.Fprintln(c.App.ErrWriter, "- read-write access to all (other) topics (server config)")
fmt.Fprintln(c.App.Writer, "- read-write access to all (other) topics (server config)")
} else if access.IsRead() {
fmt.Fprintln(c.App.ErrWriter, "- read-only access to all (other) topics (server config)")
fmt.Fprintln(c.App.Writer, "- read-only access to all (other) topics (server config)")
} else if access.IsWrite() {
fmt.Fprintln(c.App.ErrWriter, "- write-only access to all (other) topics (server config)")
fmt.Fprintln(c.App.Writer, "- write-only access to all (other) topics (server config)")
} else {
fmt.Fprintln(c.App.ErrWriter, "- no access to any (other) topics (server config)")
fmt.Fprintln(c.App.Writer, "- no access to any (other) topics (server config)")
}
}
}

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/server"
"heckel.io/ntfy/test"
"heckel.io/ntfy/v2/server"
"heckel.io/ntfy/v2/test"
"testing"
)
@@ -13,9 +13,9 @@ func TestCLI_Access_Show(t *testing.T) {
s, conf, port := newTestServerWithAuth(t)
defer test.StopServer(t, s, port)
app, _, _, stderr := newTestApp()
app, _, stdout, _ := newTestApp()
require.Nil(t, runAccessCommand(app, conf))
require.Contains(t, stderr.String(), "user * (role: anonymous, tier: none)\n- no topic-specific permissions\n- no access to any (other) topics (server config)")
require.Contains(t, stdout.String(), "user * (role: anonymous, tier: none)\n- no topic-specific permissions\n- no access to any (other) topics (server config)")
}
func TestCLI_Access_Grant_And_Publish(t *testing.T) {
@@ -30,7 +30,7 @@ func TestCLI_Access_Grant_And_Publish(t *testing.T) {
require.Nil(t, runAccessCommand(app, conf, "ben", "sometopic", "read"))
require.Nil(t, runAccessCommand(app, conf, "everyone", "announcements", "read"))
app, _, _, stderr := newTestApp()
app, _, stdout, _ := newTestApp()
require.Nil(t, runAccessCommand(app, conf))
expected := `user phil (role: admin, tier: none)
- read-write access to all topics (admin role)
@@ -41,7 +41,7 @@ user * (role: anonymous, tier: none)
- read-only access to topic announcements
- no access to any (other) topics (server config)
`
require.Equal(t, expected, stderr.String())
require.Equal(t, expected, stdout.String())
// See if access permissions match
app, _, _, _ = newTestApp()

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"github.com/urfave/cli/v2"
"github.com/urfave/cli/v2/altsrc"
"heckel.io/ntfy/log"
"heckel.io/ntfy/v2/log"
"os"
"regexp"
)

View File

@@ -4,8 +4,8 @@ import (
"bytes"
"encoding/json"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/client"
"heckel.io/ntfy/log"
"heckel.io/ntfy/v2/client"
"heckel.io/ntfy/v2/log"
"os"
"strings"
"testing"

View File

@@ -5,7 +5,7 @@ import (
"github.com/urfave/cli/v2"
"github.com/urfave/cli/v2/altsrc"
"gopkg.in/yaml.v2"
"heckel.io/ntfy/util"
"heckel.io/ntfy/v2/util"
"os"
)

View File

@@ -4,9 +4,9 @@ import (
"errors"
"fmt"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/client"
"heckel.io/ntfy/log"
"heckel.io/ntfy/util"
"heckel.io/ntfy/v2/client"
"heckel.io/ntfy/v2/log"
"heckel.io/ntfy/v2/util"
"io"
"os"
"os/exec"
@@ -31,7 +31,10 @@ var flagsPublish = append(
&cli.StringFlag{Name: "icon", Aliases: []string{"i"}, EnvVars: []string{"NTFY_ICON"}, Usage: "URL to use as notification icon"},
&cli.StringFlag{Name: "actions", Aliases: []string{"A"}, EnvVars: []string{"NTFY_ACTIONS"}, Usage: "actions JSON array or simple definition"},
&cli.StringFlag{Name: "attach", Aliases: []string{"a"}, EnvVars: []string{"NTFY_ATTACH"}, Usage: "URL to send as an external attachment"},
&cli.BoolFlag{Name: "markdown", Aliases: []string{"md"}, EnvVars: []string{"NTFY_MARKDOWN"}, Usage: "Message is formatted as Markdown"},
&cli.StringFlag{Name: "template", Aliases: []string{"tpl"}, EnvVars: []string{"NTFY_TEMPLATE"}, Usage: "use templates to transform JSON message body"},
&cli.StringFlag{Name: "filename", Aliases: []string{"name", "n"}, EnvVars: []string{"NTFY_FILENAME"}, Usage: "filename for the attachment"},
&cli.StringFlag{Name: "sequence-id", Aliases: []string{"sequence_id", "sid", "S"}, EnvVars: []string{"NTFY_SEQUENCE_ID"}, Usage: "sequence ID for updating notifications"},
&cli.StringFlag{Name: "file", Aliases: []string{"f"}, EnvVars: []string{"NTFY_FILE"}, Usage: "file to upload as an attachment"},
&cli.StringFlag{Name: "email", Aliases: []string{"mail", "e"}, EnvVars: []string{"NTFY_EMAIL"}, Usage: "also send to e-mail address"},
&cli.StringFlag{Name: "user", Aliases: []string{"u"}, EnvVars: []string{"NTFY_USER"}, Usage: "username[:password] used to auth against the server"},
@@ -68,6 +71,8 @@ Examples:
ntfy pub --icon="http://some.tld/icon.png" 'Icon!' # Send notification with custom icon
ntfy pub --attach="http://some.tld/file.zip" files # Send ZIP archive from URL as attachment
ntfy pub --file=flower.jpg flowers 'Nice!' # Send image.jpg as attachment
ntfy pub -S my-id mytopic 'Update me' # Send with sequence ID for updates
echo 'message' | ntfy publish mytopic # Send message from stdin
ntfy pub -u phil:mypass secret Psst # Publish with username/password
ntfy pub --wait-pid 1234 mytopic # Wait for process 1234 to exit before publishing
ntfy pub --wait-cmd mytopic rsync -av ./ /tmp/a # Run command and publish after it completes
@@ -95,7 +100,10 @@ func execPublish(c *cli.Context) error {
icon := c.String("icon")
actions := c.String("actions")
attach := c.String("attach")
markdown := c.Bool("markdown")
template := c.String("template")
filename := c.String("filename")
sequenceID := c.String("sequence-id")
file := c.String("file")
email := c.String("email")
user := c.String("user")
@@ -140,9 +148,18 @@ func execPublish(c *cli.Context) error {
if attach != "" {
options = append(options, client.WithAttach(attach))
}
if markdown {
options = append(options, client.WithMarkdown())
}
if template != "" {
options = append(options, client.WithTemplate(template))
}
if filename != "" {
options = append(options, client.WithFilename(filename))
}
if sequenceID != "" {
options = append(options, client.WithSequenceID(sequenceID))
}
if email != "" {
options = append(options, client.WithEmail(email))
}
@@ -249,6 +266,15 @@ func parseTopicMessageCommand(c *cli.Context) (topic string, message string, com
if c.String("message") != "" {
message = c.String("message")
}
if message == "" && isStdinRedirected() {
var data []byte
data, err = io.ReadAll(io.LimitReader(c.App.Reader, 1024*1024))
if err != nil {
log.Debug("Failed to read from stdin: %s", err.Error())
return
}
message = strings.TrimSpace(string(data))
}
return
}
@@ -307,3 +333,12 @@ func runAndWaitForCommand(command []string) (message string, err error) {
log.Debug("Command succeeded after %s: %s", runtime, prettyCmd)
return fmt.Sprintf("Command succeeded after %s: %s", runtime, prettyCmd), nil
}
func isStdinRedirected() bool {
stat, err := os.Stdin.Stat()
if err != nil {
log.Debug("Failed to stat stdin: %s", err.Error())
return false
}
return (stat.Mode() & os.ModeCharDevice) == 0
}

View File

@@ -3,8 +3,8 @@ package cmd
import (
"fmt"
"github.com/stretchr/testify/require"
"heckel.io/ntfy/test"
"heckel.io/ntfy/util"
"heckel.io/ntfy/v2/test"
"heckel.io/ntfy/v2/util"
"net/http"
"net/http/httptest"
"os"

View File

@@ -1,5 +1,4 @@
//go:build darwin || linux || dragonfly || freebsd || netbsd || openbsd
// +build darwin linux dragonfly freebsd netbsd openbsd
package cmd

View File

@@ -5,37 +5,34 @@ package cmd
import (
"errors"
"fmt"
"github.com/stripe/stripe-go/v74"
"heckel.io/ntfy/user"
"io/fs"
"math"
"net"
"net/netip"
"net/url"
"os"
"os/signal"
"strings"
"syscall"
"text/template"
"time"
"heckel.io/ntfy/log"
"github.com/urfave/cli/v2"
"github.com/urfave/cli/v2/altsrc"
"heckel.io/ntfy/server"
"heckel.io/ntfy/util"
"heckel.io/ntfy/v2/log"
"heckel.io/ntfy/v2/payments"
"heckel.io/ntfy/v2/server"
"heckel.io/ntfy/v2/user"
"heckel.io/ntfy/v2/util"
)
func init() {
commands = append(commands, cmdServe)
}
const (
defaultServerConfigFile = "/etc/ntfy/server.yml"
)
var flagsServe = append(
append([]cli.Flag{}, flagsDefault...),
&cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: defaultServerConfigFile, DefaultText: defaultServerConfigFile, Usage: "config file"},
&cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: server.DefaultConfigFile, Usage: "config file"},
altsrc.NewStringFlag(&cli.StringFlag{Name: "base-url", Aliases: []string{"base_url", "B"}, EnvVars: []string{"NTFY_BASE_URL"}, Usage: "externally visible base URL for this host (e.g. https://ntfy.sh)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-http", Aliases: []string{"listen_http", "l"}, EnvVars: []string{"NTFY_LISTEN_HTTP"}, Value: server.DefaultListenHTTP, Usage: "ip:port used as HTTP listen address"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-https", Aliases: []string{"listen_https", "L"}, EnvVars: []string{"NTFY_LISTEN_HTTPS"}, Usage: "ip:port used as HTTPS listen address"}),
@@ -45,25 +42,31 @@ var flagsServe = append(
altsrc.NewStringFlag(&cli.StringFlag{Name: "cert-file", Aliases: []string{"cert_file", "E"}, EnvVars: []string{"NTFY_CERT_FILE"}, Usage: "certificate file, if listen-https is set"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "firebase-key-file", Aliases: []string{"firebase_key_file", "F"}, EnvVars: []string{"NTFY_FIREBASE_KEY_FILE"}, Usage: "Firebase credentials file; if set additionally publish to FCM topic"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "cache-file", Aliases: []string{"cache_file", "C"}, EnvVars: []string{"NTFY_CACHE_FILE"}, Usage: "cache file used for message caching"}),
altsrc.NewDurationFlag(&cli.DurationFlag{Name: "cache-duration", Aliases: []string{"cache_duration", "b"}, EnvVars: []string{"NTFY_CACHE_DURATION"}, Value: server.DefaultCacheDuration, Usage: "buffer messages for this time to allow `since` requests"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "cache-duration", Aliases: []string{"cache_duration", "b"}, EnvVars: []string{"NTFY_CACHE_DURATION"}, Value: util.FormatDuration(server.DefaultCacheDuration), Usage: "buffer messages for this time to allow `since` requests"}),
altsrc.NewIntFlag(&cli.IntFlag{Name: "cache-batch-size", Aliases: []string{"cache_batch_size"}, EnvVars: []string{"NTFY_BATCH_SIZE"}, Usage: "max size of messages to batch together when writing to message cache (if zero, writes are synchronous)"}),
altsrc.NewDurationFlag(&cli.DurationFlag{Name: "cache-batch-timeout", Aliases: []string{"cache_batch_timeout"}, EnvVars: []string{"NTFY_CACHE_BATCH_TIMEOUT"}, Usage: "timeout for batched async writes to the message cache (if zero, writes are synchronous)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "cache-batch-timeout", Aliases: []string{"cache_batch_timeout"}, EnvVars: []string{"NTFY_CACHE_BATCH_TIMEOUT"}, Value: util.FormatDuration(server.DefaultCacheBatchTimeout), Usage: "timeout for batched async writes to the message cache (if zero, writes are synchronous)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "cache-startup-queries", Aliases: []string{"cache_startup_queries"}, EnvVars: []string{"NTFY_CACHE_STARTUP_QUERIES"}, Usage: "queries run when the cache database is initialized"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-file", Aliases: []string{"auth_file", "H"}, EnvVars: []string{"NTFY_AUTH_FILE"}, Usage: "auth database file used for access control"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-startup-queries", Aliases: []string{"auth_startup_queries"}, EnvVars: []string{"NTFY_AUTH_STARTUP_QUERIES"}, Usage: "queries run when the auth database is initialized"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-default-access", Aliases: []string{"auth_default_access", "p"}, EnvVars: []string{"NTFY_AUTH_DEFAULT_ACCESS"}, Value: "read-write", Usage: "default permissions if no matching entries in the auth database are found"}),
altsrc.NewStringSliceFlag(&cli.StringSliceFlag{Name: "auth-users", Aliases: []string{"auth_users"}, EnvVars: []string{"NTFY_AUTH_USERS"}, Usage: "pre-provisioned declarative users"}),
altsrc.NewStringSliceFlag(&cli.StringSliceFlag{Name: "auth-access", Aliases: []string{"auth_access"}, EnvVars: []string{"NTFY_AUTH_ACCESS"}, Usage: "pre-provisioned declarative access control entries"}),
altsrc.NewStringSliceFlag(&cli.StringSliceFlag{Name: "auth-tokens", Aliases: []string{"auth_tokens"}, EnvVars: []string{"NTFY_AUTH_TOKENS"}, Usage: "pre-provisioned declarative access tokens"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "attachment-cache-dir", Aliases: []string{"attachment_cache_dir"}, EnvVars: []string{"NTFY_ATTACHMENT_CACHE_DIR"}, Usage: "cache directory for attached files"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "attachment-total-size-limit", Aliases: []string{"attachment_total_size_limit", "A"}, EnvVars: []string{"NTFY_ATTACHMENT_TOTAL_SIZE_LIMIT"}, DefaultText: "5G", Usage: "limit of the on-disk attachment cache"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "attachment-file-size-limit", Aliases: []string{"attachment_file_size_limit", "Y"}, EnvVars: []string{"NTFY_ATTACHMENT_FILE_SIZE_LIMIT"}, DefaultText: "15M", Usage: "per-file attachment size limit (e.g. 300k, 2M, 100M)"}),
altsrc.NewDurationFlag(&cli.DurationFlag{Name: "attachment-expiry-duration", Aliases: []string{"attachment_expiry_duration", "X"}, EnvVars: []string{"NTFY_ATTACHMENT_EXPIRY_DURATION"}, Value: server.DefaultAttachmentExpiryDuration, DefaultText: "3h", Usage: "duration after which uploaded attachments will be deleted (e.g. 3h, 20h)"}),
altsrc.NewDurationFlag(&cli.DurationFlag{Name: "keepalive-interval", Aliases: []string{"keepalive_interval", "k"}, EnvVars: []string{"NTFY_KEEPALIVE_INTERVAL"}, Value: server.DefaultKeepaliveInterval, Usage: "interval of keepalive messages"}),
altsrc.NewDurationFlag(&cli.DurationFlag{Name: "manager-interval", Aliases: []string{"manager_interval", "m"}, EnvVars: []string{"NTFY_MANAGER_INTERVAL"}, Value: server.DefaultManagerInterval, Usage: "interval of for message pruning and stats printing"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "attachment-total-size-limit", Aliases: []string{"attachment_total_size_limit", "A"}, EnvVars: []string{"NTFY_ATTACHMENT_TOTAL_SIZE_LIMIT"}, Value: util.FormatSize(server.DefaultAttachmentTotalSizeLimit), Usage: "limit of the on-disk attachment cache"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "attachment-file-size-limit", Aliases: []string{"attachment_file_size_limit", "Y"}, EnvVars: []string{"NTFY_ATTACHMENT_FILE_SIZE_LIMIT"}, Value: util.FormatSize(server.DefaultAttachmentFileSizeLimit), Usage: "per-file attachment size limit (e.g. 300k, 2M, 100M)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "attachment-expiry-duration", Aliases: []string{"attachment_expiry_duration", "X"}, EnvVars: []string{"NTFY_ATTACHMENT_EXPIRY_DURATION"}, Value: util.FormatDuration(server.DefaultAttachmentExpiryDuration), Usage: "duration after which uploaded attachments will be deleted (e.g. 3h, 20h)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "template-dir", Aliases: []string{"template_dir"}, EnvVars: []string{"NTFY_TEMPLATE_DIR"}, Value: server.DefaultTemplateDir, Usage: "directory to load named message templates from"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "keepalive-interval", Aliases: []string{"keepalive_interval", "k"}, EnvVars: []string{"NTFY_KEEPALIVE_INTERVAL"}, Value: util.FormatDuration(server.DefaultKeepaliveInterval), Usage: "interval of keepalive messages"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "manager-interval", Aliases: []string{"manager_interval", "m"}, EnvVars: []string{"NTFY_MANAGER_INTERVAL"}, Value: util.FormatDuration(server.DefaultManagerInterval), Usage: "interval of for message pruning and stats printing"}),
altsrc.NewStringSliceFlag(&cli.StringSliceFlag{Name: "disallowed-topics", Aliases: []string{"disallowed_topics"}, EnvVars: []string{"NTFY_DISALLOWED_TOPICS"}, Usage: "topics that are not allowed to be used"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "web-root", Aliases: []string{"web_root"}, EnvVars: []string{"NTFY_WEB_ROOT"}, Value: "app", Usage: "sets web root to landing page (home), web app (app) or disabled (disable)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "web-root", Aliases: []string{"web_root"}, EnvVars: []string{"NTFY_WEB_ROOT"}, Value: "/", Usage: "sets root of the web app (e.g. /, or /app), or disables it (disable)"}),
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-signup", Aliases: []string{"enable_signup"}, EnvVars: []string{"NTFY_ENABLE_SIGNUP"}, Value: false, Usage: "allows users to sign up via the web app, or API"}),
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-login", Aliases: []string{"enable_login"}, EnvVars: []string{"NTFY_ENABLE_LOGIN"}, Value: false, Usage: "allows users to log in via the web app, or API"}),
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-reservations", Aliases: []string{"enable_reservations"}, EnvVars: []string{"NTFY_ENABLE_RESERVATIONS"}, Value: false, Usage: "allows users to reserve topics (if their tier allows it)"}),
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "require-login", Aliases: []string{"require_login"}, EnvVars: []string{"NTFY_REQUIRE_LOGIN"}, Value: false, Usage: "all actions via the web app requires a login"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "upstream-base-url", Aliases: []string{"upstream_base_url"}, EnvVars: []string{"NTFY_UPSTREAM_BASE_URL"}, Value: "", Usage: "forward poll request to an upstream server, this is needed for iOS push notifications for self-hosted servers"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "upstream-access-token", Aliases: []string{"upstream_access_token"}, EnvVars: []string{"NTFY_UPSTREAM_ACCESS_TOKEN"}, Value: "", Usage: "access token to use for the upstream server; needed only if upstream rate limits are exceeded or upstream server requires auth"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-addr", Aliases: []string{"smtp_sender_addr"}, EnvVars: []string{"NTFY_SMTP_SENDER_ADDR"}, Usage: "SMTP server address (host:port) for outgoing emails"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-user", Aliases: []string{"smtp_sender_user"}, EnvVars: []string{"NTFY_SMTP_SENDER_USER"}, Usage: "SMTP user (if e-mail sending is enabled)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-pass", Aliases: []string{"smtp_sender_pass"}, EnvVars: []string{"NTFY_SMTP_SENDER_PASS"}, Usage: "SMTP password (if e-mail sending is enabled)"}),
@@ -71,24 +74,42 @@ var flagsServe = append(
altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-server-listen", Aliases: []string{"smtp_server_listen"}, EnvVars: []string{"NTFY_SMTP_SERVER_LISTEN"}, Usage: "SMTP server address (ip:port) for incoming emails, e.g. :25"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-server-domain", Aliases: []string{"smtp_server_domain"}, EnvVars: []string{"NTFY_SMTP_SERVER_DOMAIN"}, Usage: "SMTP domain for incoming e-mail, e.g. ntfy.sh"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-server-addr-prefix", Aliases: []string{"smtp_server_addr_prefix"}, EnvVars: []string{"NTFY_SMTP_SERVER_ADDR_PREFIX"}, Usage: "SMTP email address prefix for topics to prevent spam (e.g. 'ntfy-')"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "twilio-account", Aliases: []string{"twilio_account"}, EnvVars: []string{"NTFY_TWILIO_ACCOUNT"}, Usage: "Twilio account SID, used for phone calls, e.g. AC123..."}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "twilio-auth-token", Aliases: []string{"twilio_auth_token"}, EnvVars: []string{"NTFY_TWILIO_AUTH_TOKEN"}, Usage: "Twilio auth token"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "twilio-phone-number", Aliases: []string{"twilio_phone_number"}, EnvVars: []string{"NTFY_TWILIO_PHONE_NUMBER"}, Usage: "Twilio number to use for outgoing calls"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "twilio-verify-service", Aliases: []string{"twilio_verify_service"}, EnvVars: []string{"NTFY_TWILIO_VERIFY_SERVICE"}, Usage: "Twilio Verify service ID, used for phone number verification"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "twilio-call-format", Aliases: []string{"twilio_call_format"}, EnvVars: []string{"NTFY_TWILIO_CALL_FORMAT"}, Usage: "Twilio/TwiML format string for phone calls"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "message-size-limit", Aliases: []string{"message_size_limit"}, EnvVars: []string{"NTFY_MESSAGE_SIZE_LIMIT"}, Value: util.FormatSize(server.DefaultMessageSizeLimit), Usage: "size limit for the message (see docs for limitations)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "message-delay-limit", Aliases: []string{"message_delay_limit"}, EnvVars: []string{"NTFY_MESSAGE_DELAY_LIMIT"}, Value: util.FormatDuration(server.DefaultMessageDelayMax), Usage: "max duration a message can be scheduled into the future"}),
altsrc.NewIntFlag(&cli.IntFlag{Name: "global-topic-limit", Aliases: []string{"global_topic_limit", "T"}, EnvVars: []string{"NTFY_GLOBAL_TOPIC_LIMIT"}, Value: server.DefaultTotalTopicLimit, Usage: "total number of topics allowed"}),
altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-subscription-limit", Aliases: []string{"visitor_subscription_limit"}, EnvVars: []string{"NTFY_VISITOR_SUBSCRIPTION_LIMIT"}, Value: server.DefaultVisitorSubscriptionLimit, Usage: "number of subscriptions per visitor"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "visitor-attachment-total-size-limit", Aliases: []string{"visitor_attachment_total_size_limit"}, EnvVars: []string{"NTFY_VISITOR_ATTACHMENT_TOTAL_SIZE_LIMIT"}, Value: "100M", Usage: "total storage limit used for attachments per visitor"}),
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "visitor-subscriber-rate-limiting", Aliases: []string{"visitor_subscriber_rate_limiting"}, EnvVars: []string{"NTFY_VISITOR_SUBSCRIBER_RATE_LIMITING"}, Value: false, Usage: "enables subscriber-based rate limiting"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "visitor-attachment-total-size-limit", Aliases: []string{"visitor_attachment_total_size_limit"}, EnvVars: []string{"NTFY_VISITOR_ATTACHMENT_TOTAL_SIZE_LIMIT"}, Value: util.FormatSize(server.DefaultVisitorAttachmentTotalSizeLimit), Usage: "total storage limit used for attachments per visitor"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "visitor-attachment-daily-bandwidth-limit", Aliases: []string{"visitor_attachment_daily_bandwidth_limit"}, EnvVars: []string{"NTFY_VISITOR_ATTACHMENT_DAILY_BANDWIDTH_LIMIT"}, Value: "500M", Usage: "total daily attachment download/upload bandwidth limit per visitor"}),
altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-request-limit-burst", Aliases: []string{"visitor_request_limit_burst"}, EnvVars: []string{"NTFY_VISITOR_REQUEST_LIMIT_BURST"}, Value: server.DefaultVisitorRequestLimitBurst, Usage: "initial limit of requests per visitor"}),
altsrc.NewDurationFlag(&cli.DurationFlag{Name: "visitor-request-limit-replenish", Aliases: []string{"visitor_request_limit_replenish"}, EnvVars: []string{"NTFY_VISITOR_REQUEST_LIMIT_REPLENISH"}, Value: server.DefaultVisitorRequestLimitReplenish, Usage: "interval at which burst limit is replenished (one per x)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "visitor-request-limit-replenish", Aliases: []string{"visitor_request_limit_replenish"}, EnvVars: []string{"NTFY_VISITOR_REQUEST_LIMIT_REPLENISH"}, Value: util.FormatDuration(server.DefaultVisitorRequestLimitReplenish), Usage: "interval at which burst limit is replenished (one per x)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "visitor-request-limit-exempt-hosts", Aliases: []string{"visitor_request_limit_exempt_hosts"}, EnvVars: []string{"NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS"}, Value: "", Usage: "hostnames and/or IP addresses of hosts that will be exempt from the visitor request limit"}),
altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-message-daily-limit", Aliases: []string{"visitor_message_daily_limit"}, EnvVars: []string{"NTFY_VISITOR_MESSAGE_DAILY_LIMIT"}, Value: server.DefaultVisitorMessageDailyLimit, Usage: "max messages per visitor per day, derived from request limit if unset"}),
altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-email-limit-burst", Aliases: []string{"visitor_email_limit_burst"}, EnvVars: []string{"NTFY_VISITOR_EMAIL_LIMIT_BURST"}, Value: server.DefaultVisitorEmailLimitBurst, Usage: "initial limit of e-mails per visitor"}),
altsrc.NewDurationFlag(&cli.DurationFlag{Name: "visitor-email-limit-replenish", Aliases: []string{"visitor_email_limit_replenish"}, EnvVars: []string{"NTFY_VISITOR_EMAIL_LIMIT_REPLENISH"}, Value: server.DefaultVisitorEmailLimitReplenish, Usage: "interval at which burst limit is replenished (one per x)"}),
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "visitor-subscriber-rate-limiting", Aliases: []string{"visitor_subscriber_rate_limiting"}, EnvVars: []string{"NTFY_VISITOR_SUBSCRIBER_RATE_LIMITING"}, Value: false, Usage: "enables subscriber-based rate limiting"}),
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "behind-proxy", Aliases: []string{"behind_proxy", "P"}, EnvVars: []string{"NTFY_BEHIND_PROXY"}, Value: false, Usage: "if set, use X-Forwarded-For header to determine visitor IP address (for rate limiting)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "visitor-email-limit-replenish", Aliases: []string{"visitor_email_limit_replenish"}, EnvVars: []string{"NTFY_VISITOR_EMAIL_LIMIT_REPLENISH"}, Value: util.FormatDuration(server.DefaultVisitorEmailLimitReplenish), Usage: "interval at which burst limit is replenished (one per x)"}),
altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-prefix-bits-ipv4", Aliases: []string{"visitor_prefix_bits_ipv4"}, EnvVars: []string{"NTFY_VISITOR_PREFIX_BITS_IPV4"}, Value: server.DefaultVisitorPrefixBitsIPv4, Usage: "number of bits of the IPv4 address to use for rate limiting (default: 32, full address)"}),
altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-prefix-bits-ipv6", Aliases: []string{"visitor_prefix_bits_ipv6"}, EnvVars: []string{"NTFY_VISITOR_PREFIX_BITS_IPV6"}, Value: server.DefaultVisitorPrefixBitsIPv6, Usage: "number of bits of the IPv6 address to use for rate limiting (default: 64, /64 subnet)"}),
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "behind-proxy", Aliases: []string{"behind_proxy", "P"}, EnvVars: []string{"NTFY_BEHIND_PROXY"}, Value: false, Usage: "if set, use forwarded header (e.g. X-Forwarded-For, X-Client-IP) to determine visitor IP address (for rate limiting)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "proxy-forwarded-header", Aliases: []string{"proxy_forwarded_header"}, EnvVars: []string{"NTFY_PROXY_FORWARDED_HEADER"}, Value: "X-Forwarded-For", Usage: "use specified header to determine visitor IP address (for rate limiting)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "proxy-trusted-hosts", Aliases: []string{"proxy_trusted_hosts"}, EnvVars: []string{"NTFY_PROXY_TRUSTED_HOSTS"}, Value: "", Usage: "comma-separated list of trusted IP addresses, hosts, or CIDRs to remove from forwarded header"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "stripe-secret-key", Aliases: []string{"stripe_secret_key"}, EnvVars: []string{"NTFY_STRIPE_SECRET_KEY"}, Value: "", Usage: "key used for the Stripe API communication, this enables payments"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "stripe-webhook-key", Aliases: []string{"stripe_webhook_key"}, EnvVars: []string{"NTFY_STRIPE_WEBHOOK_KEY"}, Value: "", Usage: "key required to validate the authenticity of incoming webhooks from Stripe"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "billing-contact", Aliases: []string{"billing_contact"}, EnvVars: []string{"NTFY_BILLING_CONTACT"}, Value: "", Usage: "e-mail or website to display in upgrade dialog (only if payments are enabled)"}),
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-metrics", Aliases: []string{"enable_metrics"}, EnvVars: []string{"NTFY_ENABLE_METRICS"}, Value: false, Usage: "if set, Prometheus metrics are exposed via the /metrics endpoint"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "metrics-listen-http", Aliases: []string{"metrics_listen_http"}, EnvVars: []string{"NTFY_METRICS_LISTEN_HTTP"}, Usage: "ip:port used to expose the metrics endpoint (implicitly enables metrics)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "profile-listen-http", Aliases: []string{"profile_listen_http"}, EnvVars: []string{"NTFY_PROFILE_LISTEN_HTTP"}, Usage: "ip:port used to expose the profiling endpoints (implicitly enables profiling)"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "web-push-public-key", Aliases: []string{"web_push_public_key"}, EnvVars: []string{"NTFY_WEB_PUSH_PUBLIC_KEY"}, Usage: "public key used for web push notifications"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "web-push-private-key", Aliases: []string{"web_push_private_key"}, EnvVars: []string{"NTFY_WEB_PUSH_PRIVATE_KEY"}, Usage: "private key used for web push notifications"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "web-push-file", Aliases: []string{"web_push_file"}, EnvVars: []string{"NTFY_WEB_PUSH_FILE"}, Usage: "file used to store web push subscriptions"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "web-push-email-address", Aliases: []string{"web_push_email_address"}, EnvVars: []string{"NTFY_WEB_PUSH_EMAIL_ADDRESS"}, Usage: "e-mail address of sender, required to use browser push services"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "web-push-startup-queries", Aliases: []string{"web_push_startup_queries"}, EnvVars: []string{"NTFY_WEB_PUSH_STARTUP_QUERIES"}, Usage: "queries run when the web push database is initialized"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "web-push-expiry-duration", Aliases: []string{"web_push_expiry_duration"}, EnvVars: []string{"NTFY_WEB_PUSH_EXPIRY_DURATION"}, Value: util.FormatDuration(server.DefaultWebPushExpiryDuration), Usage: "automatically expire unused subscriptions after this time"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "web-push-expiry-warning-duration", Aliases: []string{"web_push_expiry_warning_duration"}, EnvVars: []string{"NTFY_WEB_PUSH_EXPIRY_WARNING_DURATION"}, Value: util.FormatDuration(server.DefaultWebPushExpiryWarningDuration), Usage: "send web push warning notification after this time before expiring unused subscriptions"}),
)
var cmdServe = &cli.Command{
@@ -116,7 +137,7 @@ func execServe(c *cli.Context) error {
// Read all the options
config := c.String("config")
baseURL := c.String("base-url")
baseURL := strings.TrimSuffix(c.String("base-url"), "/")
listenHTTP := c.String("listen-http")
listenHTTPS := c.String("listen-https")
listenUnix := c.String("listen-unix")
@@ -124,26 +145,39 @@ func execServe(c *cli.Context) error {
keyFile := c.String("key-file")
certFile := c.String("cert-file")
firebaseKeyFile := c.String("firebase-key-file")
webPushPrivateKey := c.String("web-push-private-key")
webPushPublicKey := c.String("web-push-public-key")
webPushFile := c.String("web-push-file")
webPushEmailAddress := c.String("web-push-email-address")
webPushStartupQueries := c.String("web-push-startup-queries")
webPushExpiryDurationStr := c.String("web-push-expiry-duration")
webPushExpiryWarningDurationStr := c.String("web-push-expiry-warning-duration")
cacheFile := c.String("cache-file")
cacheDuration := c.Duration("cache-duration")
cacheDurationStr := c.String("cache-duration")
cacheStartupQueries := c.String("cache-startup-queries")
cacheBatchSize := c.Int("cache-batch-size")
cacheBatchTimeout := c.Duration("cache-batch-timeout")
cacheBatchTimeoutStr := c.String("cache-batch-timeout")
authFile := c.String("auth-file")
authStartupQueries := c.String("auth-startup-queries")
authDefaultAccess := c.String("auth-default-access")
authUsersRaw := c.StringSlice("auth-users")
authAccessRaw := c.StringSlice("auth-access")
authTokensRaw := c.StringSlice("auth-tokens")
attachmentCacheDir := c.String("attachment-cache-dir")
attachmentTotalSizeLimitStr := c.String("attachment-total-size-limit")
attachmentFileSizeLimitStr := c.String("attachment-file-size-limit")
attachmentExpiryDuration := c.Duration("attachment-expiry-duration")
keepaliveInterval := c.Duration("keepalive-interval")
managerInterval := c.Duration("manager-interval")
attachmentExpiryDurationStr := c.String("attachment-expiry-duration")
templateDir := c.String("template-dir")
keepaliveIntervalStr := c.String("keepalive-interval")
managerIntervalStr := c.String("manager-interval")
disallowedTopics := c.StringSlice("disallowed-topics")
webRoot := c.String("web-root")
enableSignup := c.Bool("enable-signup")
enableLogin := c.Bool("enable-login")
requireLogin := c.Bool("require-login")
enableReservations := c.Bool("enable-reservations")
upstreamBaseURL := c.String("upstream-base-url")
upstreamAccessToken := c.String("upstream-access-token")
smtpSenderAddr := c.String("smtp-sender-addr")
smtpSenderUser := c.String("smtp-sender-user")
smtpSenderPass := c.String("smtp-sender-pass")
@@ -151,18 +185,29 @@ func execServe(c *cli.Context) error {
smtpServerListen := c.String("smtp-server-listen")
smtpServerDomain := c.String("smtp-server-domain")
smtpServerAddrPrefix := c.String("smtp-server-addr-prefix")
twilioAccount := c.String("twilio-account")
twilioAuthToken := c.String("twilio-auth-token")
twilioPhoneNumber := c.String("twilio-phone-number")
twilioVerifyService := c.String("twilio-verify-service")
twilioCallFormat := c.String("twilio-call-format")
messageSizeLimitStr := c.String("message-size-limit")
messageDelayLimitStr := c.String("message-delay-limit")
totalTopicLimit := c.Int("global-topic-limit")
visitorSubscriptionLimit := c.Int("visitor-subscription-limit")
visitorSubscriberRateLimiting := c.Bool("visitor-subscriber-rate-limiting")
visitorAttachmentTotalSizeLimitStr := c.String("visitor-attachment-total-size-limit")
visitorAttachmentDailyBandwidthLimitStr := c.String("visitor-attachment-daily-bandwidth-limit")
visitorRequestLimitBurst := c.Int("visitor-request-limit-burst")
visitorRequestLimitReplenish := c.Duration("visitor-request-limit-replenish")
visitorRequestLimitReplenishStr := c.String("visitor-request-limit-replenish")
visitorRequestLimitExemptHosts := util.SplitNoEmpty(c.String("visitor-request-limit-exempt-hosts"), ",")
visitorMessageDailyLimit := c.Int("visitor-message-daily-limit")
visitorEmailLimitBurst := c.Int("visitor-email-limit-burst")
visitorEmailLimitReplenish := c.Duration("visitor-email-limit-replenish")
visitorEmailLimitReplenishStr := c.String("visitor-email-limit-replenish")
visitorPrefixBitsIPv4 := c.Int("visitor-prefix-bits-ipv4")
visitorPrefixBitsIPv6 := c.Int("visitor-prefix-bits-ipv6")
behindProxy := c.Bool("behind-proxy")
proxyForwardedHeader := c.String("proxy-forwarded-header")
proxyTrustedHosts := util.SplitNoEmpty(c.String("proxy-trusted-hosts"), ",")
stripeSecretKey := c.String("stripe-secret-key")
stripeWebhookKey := c.String("stripe-webhook-key")
billingContact := c.String("billing-contact")
@@ -170,9 +215,79 @@ func execServe(c *cli.Context) error {
enableMetrics := c.Bool("enable-metrics") || metricsListenHTTP != ""
profileListenHTTP := c.String("profile-listen-http")
// Convert durations
cacheDuration, err := util.ParseDuration(cacheDurationStr)
if err != nil {
return fmt.Errorf("invalid cache duration: %s", cacheDurationStr)
}
cacheBatchTimeout, err := util.ParseDuration(cacheBatchTimeoutStr)
if err != nil {
return fmt.Errorf("invalid cache batch timeout: %s", cacheBatchTimeoutStr)
}
attachmentExpiryDuration, err := util.ParseDuration(attachmentExpiryDurationStr)
if err != nil {
return fmt.Errorf("invalid attachment expiry duration: %s", attachmentExpiryDurationStr)
}
keepaliveInterval, err := util.ParseDuration(keepaliveIntervalStr)
if err != nil {
return fmt.Errorf("invalid keepalive interval: %s", keepaliveIntervalStr)
}
managerInterval, err := util.ParseDuration(managerIntervalStr)
if err != nil {
return fmt.Errorf("invalid manager interval: %s", managerIntervalStr)
}
messageDelayLimit, err := util.ParseDuration(messageDelayLimitStr)
if err != nil {
return fmt.Errorf("invalid message delay limit: %s", messageDelayLimitStr)
}
visitorRequestLimitReplenish, err := util.ParseDuration(visitorRequestLimitReplenishStr)
if err != nil {
return fmt.Errorf("invalid visitor request limit replenish: %s", visitorRequestLimitReplenishStr)
}
visitorEmailLimitReplenish, err := util.ParseDuration(visitorEmailLimitReplenishStr)
if err != nil {
return fmt.Errorf("invalid visitor email limit replenish: %s", visitorEmailLimitReplenishStr)
}
webPushExpiryDuration, err := util.ParseDuration(webPushExpiryDurationStr)
if err != nil {
return fmt.Errorf("invalid web push expiry duration: %s", webPushExpiryDurationStr)
}
webPushExpiryWarningDuration, err := util.ParseDuration(webPushExpiryWarningDurationStr)
if err != nil {
return fmt.Errorf("invalid web push expiry warning duration: %s", webPushExpiryWarningDurationStr)
}
// Convert sizes to bytes
messageSizeLimit, err := util.ParseSize(messageSizeLimitStr)
if err != nil {
return fmt.Errorf("invalid message size limit: %s", messageSizeLimitStr)
}
attachmentTotalSizeLimit, err := util.ParseSize(attachmentTotalSizeLimitStr)
if err != nil {
return fmt.Errorf("invalid attachment total size limit: %s", attachmentTotalSizeLimitStr)
}
attachmentFileSizeLimit, err := util.ParseSize(attachmentFileSizeLimitStr)
if err != nil {
return fmt.Errorf("invalid attachment file size limit: %s", attachmentFileSizeLimitStr)
}
visitorAttachmentTotalSizeLimit, err := util.ParseSize(visitorAttachmentTotalSizeLimitStr)
if err != nil {
return fmt.Errorf("invalid visitor attachment total size limit: %s", visitorAttachmentTotalSizeLimitStr)
}
visitorAttachmentDailyBandwidthLimit, err := util.ParseSize(visitorAttachmentDailyBandwidthLimitStr)
if err != nil {
return fmt.Errorf("invalid visitor attachment daily bandwidth limit: %s", visitorAttachmentDailyBandwidthLimitStr)
} else if visitorAttachmentDailyBandwidthLimit > math.MaxInt {
return fmt.Errorf("config option visitor-attachment-daily-bandwidth-limit must be lower than %d", math.MaxInt)
}
// Check values
if firebaseKeyFile != "" && !util.FileExists(firebaseKeyFile) {
return errors.New("if set, FCM key file must exist")
} else if firebaseKeyFile != "" && !server.FirebaseAvailable {
return errors.New("cannot set firebase-key-file, support for Firebase is not available (nofirebase)")
} else if webPushPublicKey != "" && (webPushPrivateKey == "" || webPushFile == "" || webPushEmailAddress == "" || baseURL == "") {
return errors.New("if web push is enabled, web-push-private-key, web-push-public-key, web-push-file, web-push-email-address, and base-url should be set. run 'ntfy webpush keys' to generate keys")
} else if keepaliveInterval < 5*time.Second {
return errors.New("keepalive interval cannot be lower than five seconds")
} else if managerInterval < 5*time.Second {
@@ -191,12 +306,15 @@ func execServe(c *cli.Context) error {
return errors.New("if smtp-server-listen is set, smtp-server-domain must also be set")
} else if attachmentCacheDir != "" && baseURL == "" {
return errors.New("if attachment-cache-dir is set, base-url must also be set")
} else if baseURL != "" && !strings.HasPrefix(baseURL, "http://") && !strings.HasPrefix(baseURL, "https://") {
return errors.New("if set, base-url must start with http:// or https://")
} else if baseURL != "" && strings.HasSuffix(baseURL, "/") {
return errors.New("if set, base-url must not end with a slash (/)")
} else if !util.Contains([]string{"app", "home", "disable"}, webRoot) {
return errors.New("if set, web-root must be 'home' or 'app'")
} else if baseURL != "" {
u, err := url.Parse(baseURL)
if err != nil {
return fmt.Errorf("if set, base-url must be a valid URL, e.g. https://ntfy.mydomain.com: %v", err)
} else if u.Scheme != "http" && u.Scheme != "https" {
return errors.New("if set, base-url must be a valid URL starting with http:// or https://, e.g. https://ntfy.mydomain.com")
} else if u.Path != "" {
return fmt.Errorf("if set, base-url must not have a path (%s), as hosting ntfy on a sub-path is not supported, e.g. https://ntfy.mydomain.com", u.Path)
}
} else if upstreamBaseURL != "" && !strings.HasPrefix(upstreamBaseURL, "http://") && !strings.HasPrefix(upstreamBaseURL, "https://") {
return errors.New("if set, upstream-base-url must start with http:// or https://")
} else if upstreamBaseURL != "" && strings.HasSuffix(upstreamBaseURL, "/") {
@@ -205,63 +323,93 @@ func execServe(c *cli.Context) error {
return errors.New("if upstream-base-url is set, base-url must also be set")
} else if upstreamBaseURL != "" && baseURL != "" && baseURL == upstreamBaseURL {
return errors.New("base-url and upstream-base-url cannot be identical, you'll likely want to set upstream-base-url to https://ntfy.sh, see https://ntfy.sh/docs/config/#ios-instant-notifications")
} else if authFile == "" && (enableSignup || enableLogin || enableReservations || stripeSecretKey != "") {
return errors.New("cannot set enable-signup, enable-login, enable-reserve-topics, or stripe-secret-key if auth-file is not set")
} else if authFile == "" && (enableSignup || enableLogin || requireLogin || enableReservations || stripeSecretKey != "") {
return errors.New("cannot set enable-signup, enable-login, require-login, enable-reserve-topics, or stripe-secret-key if auth-file is not set")
} else if enableSignup && !enableLogin {
return errors.New("cannot set enable-signup without also setting enable-login")
} else if requireLogin && !enableLogin {
return errors.New("cannot set require-login without also setting enable-login")
} else if !payments.Available && (stripeSecretKey != "" || stripeWebhookKey != "") {
return errors.New("cannot set stripe-secret-key or stripe-webhook-key, support for payments is not available in this build (nopayments)")
} else if stripeSecretKey != "" && (stripeWebhookKey == "" || baseURL == "") {
return errors.New("if stripe-secret-key is set, stripe-webhook-key and base-url must also be set")
} else if twilioAccount != "" && (twilioAuthToken == "" || twilioPhoneNumber == "" || twilioVerifyService == "" || baseURL == "" || authFile == "") {
return errors.New("if twilio-account is set, twilio-auth-token, twilio-phone-number, twilio-verify-service, base-url, and auth-file must also be set")
} else if messageSizeLimit > server.DefaultMessageSizeLimit {
log.Warn("message-size-limit is greater than 4K, this is not recommended and largely untested, and may lead to issues with some clients")
if messageSizeLimit > 5*1024*1024 {
return errors.New("message-size-limit cannot be higher than 5M")
}
} else if !server.WebPushAvailable && (webPushPrivateKey != "" || webPushPublicKey != "" || webPushFile != "") {
return errors.New("cannot enable WebPush, support is not available in this build (nowebpush)")
} else if webPushExpiryWarningDuration > 0 && webPushExpiryWarningDuration > webPushExpiryDuration {
return errors.New("web push expiry warning duration cannot be higher than web push expiry duration")
} else if behindProxy && proxyForwardedHeader == "" {
return errors.New("if behind-proxy is set, proxy-forwarded-header must also be set")
} else if visitorPrefixBitsIPv4 < 1 || visitorPrefixBitsIPv4 > 32 {
return errors.New("visitor-prefix-bits-ipv4 must be between 1 and 32")
} else if visitorPrefixBitsIPv6 < 1 || visitorPrefixBitsIPv6 > 128 {
return errors.New("visitor-prefix-bits-ipv6 must be between 1 and 128")
}
webRootIsApp := webRoot == "app"
enableWeb := webRoot != "disable"
// Backwards compatibility
if webRoot == "app" {
webRoot = "/"
} else if webRoot == "home" {
webRoot = "/app"
} else if webRoot == "disable" {
webRoot = ""
} else if !strings.HasPrefix(webRoot, "/") {
webRoot = "/" + webRoot
}
// Default auth permissions
// Convert default auth permission, read provisioned users
authDefault, err := user.ParsePermission(authDefaultAccess)
if err != nil {
return errors.New("if set, auth-default-access must start set to 'read-write', 'read-only', 'write-only' or 'deny-all'")
}
authUsers, err := parseUsers(authUsersRaw)
if err != nil {
return err
}
authAccess, err := parseAccess(authUsers, authAccessRaw)
if err != nil {
return err
}
authTokens, err := parseTokens(authUsers, authTokensRaw)
if err != nil {
return err
}
// Special case: Unset default
if listenHTTP == "-" {
listenHTTP = ""
}
// Convert sizes to bytes
attachmentTotalSizeLimit, err := parseSize(attachmentTotalSizeLimitStr, server.DefaultAttachmentTotalSizeLimit)
if err != nil {
return err
}
attachmentFileSizeLimit, err := parseSize(attachmentFileSizeLimitStr, server.DefaultAttachmentFileSizeLimit)
if err != nil {
return err
}
visitorAttachmentTotalSizeLimit, err := parseSize(visitorAttachmentTotalSizeLimitStr, server.DefaultVisitorAttachmentTotalSizeLimit)
if err != nil {
return err
}
visitorAttachmentDailyBandwidthLimit, err := parseSize(visitorAttachmentDailyBandwidthLimitStr, server.DefaultVisitorAttachmentDailyBandwidthLimit)
if err != nil {
return err
} else if visitorAttachmentDailyBandwidthLimit > math.MaxInt {
return fmt.Errorf("config option visitor-attachment-daily-bandwidth-limit must be lower than %d", math.MaxInt)
}
// Resolve hosts
visitorRequestLimitExemptIPs := make([]netip.Prefix, 0)
visitorRequestLimitExemptPrefixes := make([]netip.Prefix, 0)
for _, host := range visitorRequestLimitExemptHosts {
ips, err := parseIPHostPrefix(host)
prefixes, err := parseIPHostPrefix(host)
if err != nil {
log.Warn("cannot resolve host %s: %s, ignoring visitor request exemption", host, err.Error())
continue
}
visitorRequestLimitExemptIPs = append(visitorRequestLimitExemptIPs, ips...)
visitorRequestLimitExemptPrefixes = append(visitorRequestLimitExemptPrefixes, prefixes...)
}
// Parse trusted prefixes
trustedProxyPrefixes := make([]netip.Prefix, 0)
for _, host := range proxyTrustedHosts {
prefixes, err := parseIPHostPrefix(host)
if err != nil {
return fmt.Errorf("cannot resolve trusted proxy host %s: %s", host, err.Error())
}
trustedProxyPrefixes = append(trustedProxyPrefixes, prefixes...)
}
// Stripe things
if stripeSecretKey != "" {
stripe.EnableTelemetry = false // Whoa!
stripe.Key = stripeSecretKey
payments.Setup(stripeSecretKey)
}
// Add default forbidden topics
@@ -286,15 +434,20 @@ func execServe(c *cli.Context) error {
conf.AuthFile = authFile
conf.AuthStartupQueries = authStartupQueries
conf.AuthDefault = authDefault
conf.AuthUsers = authUsers
conf.AuthAccess = authAccess
conf.AuthTokens = authTokens
conf.AttachmentCacheDir = attachmentCacheDir
conf.AttachmentTotalSizeLimit = attachmentTotalSizeLimit
conf.AttachmentFileSizeLimit = attachmentFileSizeLimit
conf.AttachmentExpiryDuration = attachmentExpiryDuration
conf.TemplateDir = templateDir
conf.KeepaliveInterval = keepaliveInterval
conf.ManagerInterval = managerInterval
conf.DisallowedTopics = disallowedTopics
conf.WebRootIsApp = webRootIsApp
conf.WebRoot = webRoot
conf.UpstreamBaseURL = upstreamBaseURL
conf.UpstreamAccessToken = upstreamAccessToken
conf.SMTPSenderAddr = smtpSenderAddr
conf.SMTPSenderUser = smtpSenderUser
conf.SMTPSenderPass = smtpSenderPass
@@ -302,28 +455,52 @@ func execServe(c *cli.Context) error {
conf.SMTPServerListen = smtpServerListen
conf.SMTPServerDomain = smtpServerDomain
conf.SMTPServerAddrPrefix = smtpServerAddrPrefix
conf.TwilioAccount = twilioAccount
conf.TwilioAuthToken = twilioAuthToken
conf.TwilioPhoneNumber = twilioPhoneNumber
conf.TwilioVerifyService = twilioVerifyService
if twilioCallFormat != "" {
tmpl, err := template.New("twiml").Parse(twilioCallFormat)
if err != nil {
return fmt.Errorf("failed to parse twilio-call-format template: %w", err)
}
conf.TwilioCallFormat = tmpl
}
conf.MessageSizeLimit = int(messageSizeLimit)
conf.MessageDelayMax = messageDelayLimit
conf.TotalTopicLimit = totalTopicLimit
conf.VisitorSubscriptionLimit = visitorSubscriptionLimit
conf.VisitorSubscriberRateLimiting = visitorSubscriberRateLimiting
conf.VisitorAttachmentTotalSizeLimit = visitorAttachmentTotalSizeLimit
conf.VisitorAttachmentDailyBandwidthLimit = visitorAttachmentDailyBandwidthLimit
conf.VisitorRequestLimitBurst = visitorRequestLimitBurst
conf.VisitorRequestLimitReplenish = visitorRequestLimitReplenish
conf.VisitorRequestExemptIPAddrs = visitorRequestLimitExemptIPs
conf.VisitorRequestExemptPrefixes = visitorRequestLimitExemptPrefixes
conf.VisitorMessageDailyLimit = visitorMessageDailyLimit
conf.VisitorEmailLimitBurst = visitorEmailLimitBurst
conf.VisitorEmailLimitReplenish = visitorEmailLimitReplenish
conf.VisitorSubscriberRateLimiting = visitorSubscriberRateLimiting
conf.VisitorPrefixBitsIPv4 = visitorPrefixBitsIPv4
conf.VisitorPrefixBitsIPv6 = visitorPrefixBitsIPv6
conf.BehindProxy = behindProxy
conf.ProxyForwardedHeader = proxyForwardedHeader
conf.ProxyTrustedPrefixes = trustedProxyPrefixes
conf.StripeSecretKey = stripeSecretKey
conf.StripeWebhookKey = stripeWebhookKey
conf.BillingContact = billingContact
conf.EnableWeb = enableWeb
conf.EnableSignup = enableSignup
conf.EnableLogin = enableLogin
conf.RequireLogin = requireLogin
conf.EnableReservations = enableReservations
conf.EnableMetrics = enableMetrics
conf.MetricsListenHTTP = metricsListenHTTP
conf.ProfileListenHTTP = profileListenHTTP
conf.WebPushPrivateKey = webPushPrivateKey
conf.WebPushPublicKey = webPushPublicKey
conf.WebPushFile = webPushFile
conf.WebPushEmailAddress = webPushEmailAddress
conf.WebPushStartupQueries = webPushStartupQueries
conf.WebPushExpiryDuration = webPushExpiryDuration
conf.WebPushExpiryWarningDuration = webPushExpiryWarningDuration
conf.Version = c.App.Version
// Set up hot-reloading of config
@@ -332,25 +509,14 @@ func execServe(c *cli.Context) error {
// Run server
s, err := server.New(conf)
if err != nil {
log.Fatal(err.Error())
log.Fatal("%s", err.Error())
} else if err := s.Run(); err != nil {
log.Fatal(err.Error())
log.Fatal("%s", err.Error())
}
log.Info("Exiting.")
return nil
}
func parseSize(s string, defaultValue int64) (v int64, err error) {
if s == "" {
return defaultValue, nil
}
v, err = util.ParseSize(s)
if err != nil {
return 0, err
}
return v, nil
}
func sigHandlerConfigReload(config string) {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGHUP)
@@ -368,7 +534,7 @@ func sigHandlerConfigReload(config string) {
}
func parseIPHostPrefix(host string) (prefixes []netip.Prefix, err error) {
// Try parsing as prefix, e.g. 10.0.1.0/24
// Try parsing as prefix, e.g. 10.0.1.0/24 or 2001:db8::/32
prefix, err := netip.ParsePrefix(host)
if err == nil {
prefixes = append(prefixes, prefix.Masked())
@@ -392,6 +558,112 @@ func parseIPHostPrefix(host string) (prefixes []netip.Prefix, err error) {
return
}
func parseUsers(usersRaw []string) ([]*user.User, error) {
users := make([]*user.User, 0)
for _, userLine := range usersRaw {
parts := strings.Split(userLine, ":")
if len(parts) != 3 {
return nil, fmt.Errorf("invalid auth-users: %s, expected format: 'name:hash:role'", userLine)
}
username := strings.TrimSpace(parts[0])
passwordHash := strings.TrimSpace(parts[1])
role := user.Role(strings.TrimSpace(parts[2]))
if !user.AllowedUsername(username) {
return nil, fmt.Errorf("invalid auth-users: %s, username invalid", userLine)
} else if err := user.ValidPasswordHash(passwordHash, user.DefaultUserPasswordBcryptCost); err != nil {
return nil, fmt.Errorf("invalid auth-users: %s, password hash invalid, %s", userLine, err.Error())
} else if !user.AllowedRole(role) {
return nil, fmt.Errorf("invalid auth-users: %s, role %s is not allowed, allowed roles are 'admin' or 'user'", userLine, role)
}
users = append(users, &user.User{
Name: username,
Hash: passwordHash,
Role: role,
Provisioned: true,
})
}
return users, nil
}
func parseAccess(users []*user.User, accessRaw []string) (map[string][]*user.Grant, error) {
access := make(map[string][]*user.Grant)
for _, accessLine := range accessRaw {
parts := strings.Split(accessLine, ":")
if len(parts) != 3 {
return nil, fmt.Errorf("invalid auth-access: %s, expected format: 'user:topic:permission'", accessLine)
}
username := strings.TrimSpace(parts[0])
if username == userEveryone {
username = user.Everyone
}
u, exists := util.Find(users, func(u *user.User) bool {
return u.Name == username
})
if username != user.Everyone {
if !exists {
return nil, fmt.Errorf("invalid auth-access: %s, user %s is not provisioned", accessLine, username)
} else if !user.AllowedUsername(username) {
return nil, fmt.Errorf("invalid auth-access: %s, username %s invalid", accessLine, username)
} else if u.Role != user.RoleUser {
return nil, fmt.Errorf("invalid auth-access: %s, user %s is not a regular user, only regular users can have ACL entries", accessLine, username)
}
}
topic := strings.TrimSpace(parts[1])
if !user.AllowedTopicPattern(topic) {
return nil, fmt.Errorf("invalid auth-access: %s, topic pattern %s invalid", accessLine, topic)
}
permission, err := user.ParsePermission(strings.TrimSpace(parts[2]))
if err != nil {
return nil, fmt.Errorf("invalid auth-access: %s, permission %s invalid, %s", accessLine, parts[2], err.Error())
}
if _, exists := access[username]; !exists {
access[username] = make([]*user.Grant, 0)
}
access[username] = append(access[username], &user.Grant{
TopicPattern: topic,
Permission: permission,
Provisioned: true,
})
}
return access, nil
}
func parseTokens(users []*user.User, tokensRaw []string) (map[string][]*user.Token, error) {
tokens := make(map[string][]*user.Token)
for _, tokenLine := range tokensRaw {
parts := strings.Split(tokenLine, ":")
if len(parts) < 2 || len(parts) > 3 {
return nil, fmt.Errorf("invalid auth-tokens: %s, expected format: 'user:token[:label]'", tokenLine)
}
username := strings.TrimSpace(parts[0])
_, exists := util.Find(users, func(u *user.User) bool {
return u.Name == username
})
if !exists {
return nil, fmt.Errorf("invalid auth-tokens: %s, user %s is not provisioned", tokenLine, username)
} else if !user.AllowedUsername(username) {
return nil, fmt.Errorf("invalid auth-tokens: %s, username %s invalid", tokenLine, username)
}
token := strings.TrimSpace(parts[1])
if !user.ValidToken(token) {
return nil, fmt.Errorf("invalid auth-tokens: %s, token %s invalid, use 'ntfy token generate' to generate a random token", tokenLine, token)
}
var label string
if len(parts) > 2 {
label = parts[2]
}
if _, exists := tokens[username]; !exists {
tokens[username] = make([]*user.Token, 0)
}
tokens[username] = append(tokens[username], &user.Token{
Value: token,
Label: label,
Provisioned: true,
})
}
return tokens, nil
}
func reloadLogLevel(inputSource altsrc.InputSourceContext) error {
newLevelStr, err := inputSource.String("log-level")
if err != nil {

View File

@@ -12,13 +12,461 @@ import (
"github.com/gorilla/websocket"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"heckel.io/ntfy/client"
"heckel.io/ntfy/test"
"heckel.io/ntfy/util"
"heckel.io/ntfy/v2/client"
"heckel.io/ntfy/v2/test"
"heckel.io/ntfy/v2/user"
"heckel.io/ntfy/v2/util"
)
func init() {
rand.Seed(time.Now().UnixMilli())
func TestParseUsers_Success(t *testing.T) {
tests := []struct {
name string
input []string
expected []*user.User
}{
{
name: "single user",
input: []string{"alice:$2a$10$320YlQeaMghYZsvtu9jzfOQZS32FysWY/T9qu5NWqcIh.DN.u5P5S:user"},
expected: []*user.User{
{
Name: "alice",
Hash: "$2a$10$320YlQeaMghYZsvtu9jzfOQZS32FysWY/T9qu5NWqcIh.DN.u5P5S",
Role: user.RoleUser,
Provisioned: true,
},
},
},
{
name: "multiple users with different roles",
input: []string{
"alice:$2a$10$320YlQeaMghYZsvtu9jzfOQZS32FysWY/T9qu5NWqcIh.DN.u5P5S:user",
"bob:$2a$10$jIcuBWcbxd6oW1aPvoJ5iOShzu3/UJ2kSxKbTZtDypG06nBflQagq:admin",
},
expected: []*user.User{
{
Name: "alice",
Hash: "$2a$10$320YlQeaMghYZsvtu9jzfOQZS32FysWY/T9qu5NWqcIh.DN.u5P5S",
Role: user.RoleUser,
Provisioned: true,
},
{
Name: "bob",
Hash: "$2a$10$jIcuBWcbxd6oW1aPvoJ5iOShzu3/UJ2kSxKbTZtDypG06nBflQagq",
Role: user.RoleAdmin,
Provisioned: true,
},
},
},
{
name: "empty input",
input: []string{},
expected: []*user.User{},
},
{
name: "user with special characters in name",
input: []string{"alice.test+123@example.com:$2a$10$RYUYAsl5zOnAIp6fH7BPX.Eug0rUfEUk92r8WiVusb0VK.vGojWBe:user"},
expected: []*user.User{
{
Name: "alice.test+123@example.com",
Hash: "$2a$10$RYUYAsl5zOnAIp6fH7BPX.Eug0rUfEUk92r8WiVusb0VK.vGojWBe",
Role: user.RoleUser,
Provisioned: true,
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := parseUsers(tt.input)
require.NoError(t, err)
require.Len(t, result, len(tt.expected))
for i, expectedUser := range tt.expected {
assert.Equal(t, expectedUser.Name, result[i].Name)
assert.Equal(t, expectedUser.Hash, result[i].Hash)
assert.Equal(t, expectedUser.Role, result[i].Role)
assert.Equal(t, expectedUser.Provisioned, result[i].Provisioned)
}
})
}
}
func TestParseUsers_Errors(t *testing.T) {
tests := []struct {
name string
input []string
error string
}{
{
name: "invalid format - too few parts",
input: []string{"alice:hash"},
error: "invalid auth-users: alice:hash, expected format: 'name:hash:role'",
},
{
name: "invalid format - too many parts",
input: []string{"alice:hash:role:extra"},
error: "invalid auth-users: alice:hash:role:extra, expected format: 'name:hash:role'",
},
{
name: "invalid username",
input: []string{"alice@#$%:$2a$10$320YlQeaMghYZsvtu9jzfOQZS32FysWY/T9qu5NWqcIh.DN.u5P5S:user"},
error: "invalid auth-users: alice@#$%:$2a$10$320YlQeaMghYZsvtu9jzfOQZS32FysWY/T9qu5NWqcIh.DN.u5P5S:user, username invalid",
},
{
name: "invalid password hash - wrong prefix",
input: []string{"alice:plaintext:user"},
error: "invalid auth-users: alice:plaintext:user, password hash invalid, password hash must be a bcrypt hash, use 'ntfy user hash' to generate",
},
{
name: "invalid role",
input: []string{"alice:$2a$10$320YlQeaMghYZsvtu9jzfOQZS32FysWY/T9qu5NWqcIh.DN.u5P5S:invalid"},
error: "invalid auth-users: alice:$2a$10$320YlQeaMghYZsvtu9jzfOQZS32FysWY/T9qu5NWqcIh.DN.u5P5S:invalid, role invalid is not allowed, allowed roles are 'admin' or 'user'",
},
{
name: "empty username",
input: []string{":$2a$10$320YlQeaMghYZsvtu9jzfOQZS32FysWY/T9qu5NWqcIh.DN.u5P5S:user"},
error: "invalid auth-users: :$2a$10$320YlQeaMghYZsvtu9jzfOQZS32FysWY/T9qu5NWqcIh.DN.u5P5S:user, username invalid",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := parseUsers(tt.input)
require.Error(t, err)
require.Nil(t, result)
assert.Contains(t, err.Error(), tt.error)
})
}
}
func TestParseAccess_Success(t *testing.T) {
users := []*user.User{
{Name: "alice", Role: user.RoleUser},
{Name: "bob", Role: user.RoleUser},
}
tests := []struct {
name string
users []*user.User
input []string
expected map[string][]*user.Grant
}{
{
name: "single access entry",
users: users,
input: []string{"alice:mytopic:read-write"},
expected: map[string][]*user.Grant{
"alice": {
{
TopicPattern: "mytopic",
Permission: user.PermissionReadWrite,
Provisioned: true,
},
},
},
},
{
name: "multiple access entries for same user",
users: users,
input: []string{
"alice:topic1:read-only",
"alice:topic2:write-only",
},
expected: map[string][]*user.Grant{
"alice": {
{
TopicPattern: "topic1",
Permission: user.PermissionRead,
Provisioned: true,
},
{
TopicPattern: "topic2",
Permission: user.PermissionWrite,
Provisioned: true,
},
},
},
},
{
name: "access for everyone",
users: users,
input: []string{"everyone:publictopic:read-only"},
expected: map[string][]*user.Grant{
user.Everyone: {
{
TopicPattern: "publictopic",
Permission: user.PermissionRead,
Provisioned: true,
},
},
},
},
{
name: "wildcard topic pattern",
users: users,
input: []string{"alice:topic*:read-write"},
expected: map[string][]*user.Grant{
"alice": {
{
TopicPattern: "topic*",
Permission: user.PermissionReadWrite,
Provisioned: true,
},
},
},
},
{
name: "empty input",
users: users,
input: []string{},
expected: map[string][]*user.Grant{},
},
{
name: "deny-all permission",
users: users,
input: []string{"alice:secretopic:deny-all"},
expected: map[string][]*user.Grant{
"alice": {
{
TopicPattern: "secretopic",
Permission: user.PermissionDenyAll,
Provisioned: true,
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := parseAccess(tt.users, tt.input)
require.NoError(t, err)
assert.Equal(t, tt.expected, result)
})
}
}
func TestParseAccess_Errors(t *testing.T) {
users := []*user.User{
{Name: "alice", Role: user.RoleUser},
{Name: "admin", Role: user.RoleAdmin},
}
tests := []struct {
name string
users []*user.User
input []string
error string
}{
{
name: "invalid format - too few parts",
users: users,
input: []string{"alice:topic"},
error: "invalid auth-access: alice:topic, expected format: 'user:topic:permission'",
},
{
name: "invalid format - too many parts",
users: users,
input: []string{"alice:topic:read:extra"},
error: "invalid auth-access: alice:topic:read:extra, expected format: 'user:topic:permission'",
},
{
name: "user not provisioned",
users: users,
input: []string{"charlie:topic:read"},
error: "invalid auth-access: charlie:topic:read, user charlie is not provisioned",
},
{
name: "admin user cannot have ACL entries",
users: users,
input: []string{"admin:topic:read"},
error: "invalid auth-access: admin:topic:read, user admin is not a regular user, only regular users can have ACL entries",
},
{
name: "invalid topic pattern",
users: users,
input: []string{"alice:topic-with-invalid-chars!:read"},
error: "invalid auth-access: alice:topic-with-invalid-chars!:read, topic pattern topic-with-invalid-chars! invalid",
},
{
name: "invalid permission",
users: users,
input: []string{"alice:topic:invalid-permission"},
error: "invalid auth-access: alice:topic:invalid-permission, permission invalid-permission invalid",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := parseAccess(tt.users, tt.input)
require.Error(t, err)
require.Nil(t, result)
assert.Contains(t, err.Error(), tt.error)
})
}
}
func TestParseTokens_Success(t *testing.T) {
users := []*user.User{
{Name: "alice"},
{Name: "bob"},
}
tests := []struct {
name string
users []*user.User
input []string
expected map[string][]*user.Token
}{
{
name: "single token without label",
users: users,
input: []string{"alice:tk_abcdefghijklmnopqrstuvwxyz123"},
expected: map[string][]*user.Token{
"alice": {
{
Value: "tk_abcdefghijklmnopqrstuvwxyz123",
Label: "",
Provisioned: true,
},
},
},
},
{
name: "single token with label",
users: users,
input: []string{"alice:tk_abcdefghijklmnopqrstuvwxyz123:My Phone"},
expected: map[string][]*user.Token{
"alice": {
{
Value: "tk_abcdefghijklmnopqrstuvwxyz123",
Label: "My Phone",
Provisioned: true,
},
},
},
},
{
name: "multiple tokens for same user",
users: users,
input: []string{
"alice:tk_abcdefghijklmnopqrstuvwxyz123:Phone",
"alice:tk_zyxwvutsrqponmlkjihgfedcba987:Laptop",
},
expected: map[string][]*user.Token{
"alice": {
{
Value: "tk_abcdefghijklmnopqrstuvwxyz123",
Label: "Phone",
Provisioned: true,
},
{
Value: "tk_zyxwvutsrqponmlkjihgfedcba987",
Label: "Laptop",
Provisioned: true,
},
},
},
},
{
name: "tokens for multiple users",
users: users,
input: []string{
"alice:tk_abcdefghijklmnopqrstuvwxyz123:Phone",
"bob:tk_zyxwvutsrqponmlkjihgfedcba987:Tablet",
},
expected: map[string][]*user.Token{
"alice": {
{
Value: "tk_abcdefghijklmnopqrstuvwxyz123",
Label: "Phone",
Provisioned: true,
},
},
"bob": {
{
Value: "tk_zyxwvutsrqponmlkjihgfedcba987",
Label: "Tablet",
Provisioned: true,
},
},
},
},
{
name: "empty input",
users: users,
input: []string{},
expected: map[string][]*user.Token{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := parseTokens(tt.users, tt.input)
require.NoError(t, err)
assert.Equal(t, tt.expected, result)
})
}
}
func TestParseTokens_Errors(t *testing.T) {
users := []*user.User{
{Name: "alice"},
}
tests := []struct {
name string
users []*user.User
input []string
error string
}{
{
name: "invalid format - too few parts",
users: users,
input: []string{"alice"},
error: "invalid auth-tokens: alice, expected format: 'user:token[:label]'",
},
{
name: "invalid format - too many parts",
users: users,
input: []string{"alice:token:label:extra:parts"},
error: "invalid auth-tokens: alice:token:label:extra:parts, expected format: 'user:token[:label]'",
},
{
name: "user not provisioned",
users: users,
input: []string{"charlie:tk_abcdefghijklmnopqrstuvwxyz123"},
error: "invalid auth-tokens: charlie:tk_abcdefghijklmnopqrstuvwxyz123, user charlie is not provisioned",
},
{
name: "invalid token format",
users: users,
input: []string{"alice:invalid-token"},
error: "invalid auth-tokens: alice:invalid-token, token invalid-token invalid, use 'ntfy token generate' to generate a random token",
},
{
name: "token too short",
users: users,
input: []string{"alice:tk_short"},
error: "invalid auth-tokens: alice:tk_short, token tk_short invalid, use 'ntfy token generate' to generate a random token",
},
{
name: "token without prefix",
users: users,
input: []string{"alice:abcdefghijklmnopqrstuvwxyz12345"},
error: "invalid auth-tokens: alice:abcdefghijklmnopqrstuvwxyz12345, token abcdefghijklmnopqrstuvwxyz12345 invalid, use 'ntfy token generate' to generate a random token",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := parseTokens(tt.users, tt.input)
require.Error(t, err)
require.Nil(t, result)
assert.Contains(t, err.Error(), tt.error)
})
}
}
func TestCLI_Serve_Unix_Curl(t *testing.T) {

View File

@@ -4,9 +4,9 @@ import (
"errors"
"fmt"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/client"
"heckel.io/ntfy/log"
"heckel.io/ntfy/util"
"heckel.io/ntfy/v2/client"
"heckel.io/ntfy/v2/log"
"heckel.io/ntfy/v2/util"
"os"
"os/exec"
"os/user"
@@ -72,7 +72,7 @@ ntfy subscribe TOPIC COMMAND
$NTFY_TITLE $title, $t Message title
$NTFY_PRIORITY $priority, $prio, $p Message priority (1=min, 5=max)
$NTFY_TAGS $tags, $tag, $ta Message tags (comma separated list)
$NTFY_RAW $raw Raw JSON message
$NTFY_RAW $raw Raw JSON message
Examples:
ntfy sub mytopic 'notify-send "$m"' # Execute command for incoming messages
@@ -194,7 +194,10 @@ func doSubscribe(c *cli.Context, cl *client.Client, conf *client.Config, topic,
topicOptions = append(topicOptions, auth)
}
subscriptionID := cl.Subscribe(s.Topic, topicOptions...)
subscriptionID, err := cl.Subscribe(s.Topic, topicOptions...)
if err != nil {
return err
}
if s.Command != "" {
cmds[subscriptionID] = s.Command
} else if conf.DefaultCommand != "" {
@@ -204,7 +207,10 @@ func doSubscribe(c *cli.Context, cl *client.Client, conf *client.Config, topic,
}
}
if topic != "" {
subscriptionID := cl.Subscribe(topic, options...)
subscriptionID, err := cl.Subscribe(topic, options...)
if err != nil {
return err
}
cmds[subscriptionID] = command
}
for m := range cl.Messages {
@@ -219,12 +225,17 @@ func doSubscribe(c *cli.Context, cl *client.Client, conf *client.Config, topic,
}
func maybeAddAuthHeader(s client.Subscribe, conf *client.Config) client.SubscribeOption {
// check for subscription token then subscription user:pass
if s.Token != "" {
return client.WithBearerAuth(s.Token)
// if an explicit empty token or empty user:pass is given, exit without auth
if (s.Token != nil && *s.Token == "") || (s.User != nil && *s.User == "" && s.Password != nil && *s.Password == "") {
return client.WithEmptyAuth()
}
if s.User != "" && s.Password != nil {
return client.WithBasicAuth(s.User, *s.Password)
// check for subscription token then subscription user:pass
if s.Token != nil && *s.Token != "" {
return client.WithBearerAuth(*s.Token)
}
if s.User != nil && *s.User != "" && s.Password != nil {
return client.WithBasicAuth(*s.User, *s.Password)
}
// if no subscription token nor subscription user:pass, check for default token then default user:pass
@@ -299,28 +310,43 @@ func loadConfig(c *cli.Context) (*client.Config, error) {
if filename != "" {
return client.LoadConfig(filename)
}
configFile := defaultClientConfigFile()
if s, _ := os.Stat(configFile); s != nil {
return client.LoadConfig(configFile)
configFile, err := defaultClientConfigFile()
if err != nil {
log.Warn("Could not determine default client config file: %s", err.Error())
} else {
if s, _ := os.Stat(configFile); s != nil {
return client.LoadConfig(configFile)
}
log.Debug("Config file %s not found", configFile)
}
log.Debug("Loading default config")
return client.NewConfig(), nil
}
//lint:ignore U1000 Conditionally used in different builds
func defaultClientConfigFileUnix() string {
u, _ := user.Current()
func defaultClientConfigFileUnix() (string, error) {
u, err := user.Current()
if err != nil {
return "", fmt.Errorf("could not determine current user: %w", err)
}
configFile := clientRootConfigFileUnixAbsolute
if u.Uid != "0" {
homeDir, _ := os.UserConfigDir()
return filepath.Join(homeDir, clientUserConfigFileUnixRelative)
homeDir, err := os.UserConfigDir()
if err != nil {
return "", fmt.Errorf("could not determine user config dir: %w", err)
}
return filepath.Join(homeDir, clientUserConfigFileUnixRelative), nil
}
return configFile
return configFile, nil
}
//lint:ignore U1000 Conditionally used in different builds
func defaultClientConfigFileWindows() string {
homeDir, _ := os.UserConfigDir()
return filepath.Join(homeDir, clientUserConfigFileWindowsRelative)
func defaultClientConfigFileWindows() (string, error) {
homeDir, err := os.UserConfigDir()
if err != nil {
return "", fmt.Errorf("could not determine user config dir: %w", err)
}
return filepath.Join(homeDir, clientUserConfigFileWindowsRelative), nil
}
func logMessagePrefix(m *client.Message) string {

View File

@@ -11,6 +11,6 @@ var (
scriptLauncher = []string{"sh", "-c"}
)
func defaultClientConfigFile() string {
func defaultClientConfigFile() (string, error) {
return defaultClientConfigFileUnix()
}

View File

@@ -330,7 +330,7 @@ default-token: tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2
app, _, stdout, _ := newTestApp()
require.Nil(t, app.Run([]string{"ntfy", "subscribe", "--poll", "--config=" + filename, "mytopic"}))
require.Nil(t, app.Run([]string{"ntfy", "subscribe", "--poll", "--from-config", "--config=" + filename, "mytopic"}))
require.Equal(t, message, strings.TrimSpace(stdout.String()))
}
@@ -355,7 +355,63 @@ default-password: mypass
app, _, stdout, _ := newTestApp()
require.Nil(t, app.Run([]string{"ntfy", "subscribe", "--poll", "--config=" + filename, "mytopic"}))
require.Nil(t, app.Run([]string{"ntfy", "subscribe", "--poll", "--from-config", "--config=" + filename, "mytopic"}))
require.Equal(t, message, strings.TrimSpace(stdout.String()))
}
func TestCLI_Subscribe_Override_Default_UserPass_With_Empty_UserPass(t *testing.T) {
message := `{"id":"RXIQBFaieLVr","time":124,"expires":1124,"event":"message","topic":"mytopic","message":"triggered"}`
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/mytopic/json", r.URL.Path)
require.Equal(t, "", r.Header.Get("Authorization"))
w.WriteHeader(http.StatusOK)
w.Write([]byte(message))
}))
defer server.Close()
filename := filepath.Join(t.TempDir(), "client.yml")
require.Nil(t, os.WriteFile(filename, []byte(fmt.Sprintf(`
default-host: %s
default-user: philipp
default-password: mypass
subscribe:
- topic: mytopic
user: ""
password: ""
`, server.URL)), 0600))
app, _, stdout, _ := newTestApp()
require.Nil(t, app.Run([]string{"ntfy", "subscribe", "--poll", "--from-config", "--config=" + filename}))
require.Equal(t, message, strings.TrimSpace(stdout.String()))
}
func TestCLI_Subscribe_Override_Default_Token_With_Empty_Token(t *testing.T) {
message := `{"id":"RXIQBFaieLVr","time":124,"expires":1124,"event":"message","topic":"mytopic","message":"triggered"}`
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/mytopic/json", r.URL.Path)
require.Equal(t, "", r.Header.Get("Authorization"))
w.WriteHeader(http.StatusOK)
w.Write([]byte(message))
}))
defer server.Close()
filename := filepath.Join(t.TempDir(), "client.yml")
require.Nil(t, os.WriteFile(filename, []byte(fmt.Sprintf(`
default-host: %s
default-token: tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2
subscribe:
- topic: mytopic
token: ""
`, server.URL)), 0600))
app, _, stdout, _ := newTestApp()
require.Nil(t, app.Run([]string{"ntfy", "subscribe", "--poll", "--from-config", "--config=" + filename}))
require.Equal(t, message, strings.TrimSpace(stdout.String()))
}

View File

@@ -13,6 +13,6 @@ var (
scriptLauncher = []string{"sh", "-c"}
)
func defaultClientConfigFile() string {
func defaultClientConfigFile() (string, error) {
return defaultClientConfigFileUnix()
}

View File

@@ -10,6 +10,6 @@ var (
scriptLauncher = []string{"cmd.exe", "/Q", "/C"}
)
func defaultClientConfigFile() string {
func defaultClientConfigFile() (string, error) {
return defaultClientConfigFileWindows()
}

View File

@@ -6,8 +6,8 @@ import (
"errors"
"fmt"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/user"
"heckel.io/ntfy/util"
"heckel.io/ntfy/v2/user"
"heckel.io/ntfy/v2/util"
)
func init() {
@@ -18,6 +18,7 @@ const (
defaultMessageLimit = 5000
defaultMessageExpiryDuration = "12h"
defaultEmailLimit = 20
defaultCallLimit = 0
defaultReservationLimit = 3
defaultAttachmentFileSizeLimit = "15M"
defaultAttachmentTotalSizeLimit = "100M"
@@ -48,6 +49,7 @@ var cmdTier = &cli.Command{
&cli.Int64Flag{Name: "message-limit", Value: defaultMessageLimit, Usage: "daily message limit"},
&cli.StringFlag{Name: "message-expiry-duration", Value: defaultMessageExpiryDuration, Usage: "duration after which messages are deleted"},
&cli.Int64Flag{Name: "email-limit", Value: defaultEmailLimit, Usage: "daily email limit"},
&cli.Int64Flag{Name: "call-limit", Value: defaultCallLimit, Usage: "daily phone call limit"},
&cli.Int64Flag{Name: "reservation-limit", Value: defaultReservationLimit, Usage: "topic reservation limit"},
&cli.StringFlag{Name: "attachment-file-size-limit", Value: defaultAttachmentFileSizeLimit, Usage: "per-attachment file size limit"},
&cli.StringFlag{Name: "attachment-total-size-limit", Value: defaultAttachmentTotalSizeLimit, Usage: "total size limit of attachments for the user"},
@@ -91,6 +93,7 @@ Examples:
&cli.Int64Flag{Name: "message-limit", Usage: "daily message limit"},
&cli.StringFlag{Name: "message-expiry-duration", Usage: "duration after which messages are deleted"},
&cli.Int64Flag{Name: "email-limit", Usage: "daily email limit"},
&cli.Int64Flag{Name: "call-limit", Usage: "daily phone call limit"},
&cli.Int64Flag{Name: "reservation-limit", Usage: "topic reservation limit"},
&cli.StringFlag{Name: "attachment-file-size-limit", Usage: "per-attachment file size limit"},
&cli.StringFlag{Name: "attachment-total-size-limit", Usage: "total size limit of attachments for the user"},
@@ -179,7 +182,7 @@ func execTierAdd(c *cli.Context) error {
}
if tier, _ := manager.Tier(code); tier != nil {
if c.Bool("ignore-exists") {
fmt.Fprintf(c.App.ErrWriter, "tier %s already exists (exited successfully)\n", code)
fmt.Fprintf(c.App.Writer, "tier %s already exists (exited successfully)\n", code)
return nil
}
return fmt.Errorf("tier %s already exists", code)
@@ -215,6 +218,7 @@ func execTierAdd(c *cli.Context) error {
MessageLimit: c.Int64("message-limit"),
MessageExpiryDuration: messageExpiryDuration,
EmailLimit: c.Int64("email-limit"),
CallLimit: c.Int64("call-limit"),
ReservationLimit: c.Int64("reservation-limit"),
AttachmentFileSizeLimit: attachmentFileSizeLimit,
AttachmentTotalSizeLimit: attachmentTotalSizeLimit,
@@ -230,7 +234,7 @@ func execTierAdd(c *cli.Context) error {
if err != nil {
return err
}
fmt.Fprintf(c.App.ErrWriter, "tier added\n\n")
fmt.Fprintf(c.App.Writer, "tier added\n\n")
printTier(c, tier)
return nil
}
@@ -267,6 +271,9 @@ func execTierChange(c *cli.Context) error {
if c.IsSet("email-limit") {
tier.EmailLimit = c.Int64("email-limit")
}
if c.IsSet("call-limit") {
tier.CallLimit = c.Int64("call-limit")
}
if c.IsSet("reservation-limit") {
tier.ReservationLimit = c.Int64("reservation-limit")
}
@@ -308,7 +315,7 @@ func execTierChange(c *cli.Context) error {
if err := manager.UpdateTier(tier); err != nil {
return err
}
fmt.Fprintf(c.App.ErrWriter, "tier updated\n\n")
fmt.Fprintf(c.App.Writer, "tier updated\n\n")
printTier(c, tier)
return nil
}
@@ -328,7 +335,7 @@ func execTierDel(c *cli.Context) error {
if err := manager.RemoveTier(code); err != nil {
return err
}
fmt.Fprintf(c.App.ErrWriter, "tier %s removed\n", code)
fmt.Fprintf(c.App.Writer, "tier %s removed\n", code)
return nil
}
@@ -352,15 +359,16 @@ func printTier(c *cli.Context, tier *user.Tier) {
if tier.StripeMonthlyPriceID != "" && tier.StripeYearlyPriceID != "" {
prices = fmt.Sprintf("%s / %s", tier.StripeMonthlyPriceID, tier.StripeYearlyPriceID)
}
fmt.Fprintf(c.App.ErrWriter, "tier %s (id: %s)\n", tier.Code, tier.ID)
fmt.Fprintf(c.App.ErrWriter, "- Name: %s\n", tier.Name)
fmt.Fprintf(c.App.ErrWriter, "- Message limit: %d\n", tier.MessageLimit)
fmt.Fprintf(c.App.ErrWriter, "- Message expiry duration: %s (%d seconds)\n", tier.MessageExpiryDuration.String(), int64(tier.MessageExpiryDuration.Seconds()))
fmt.Fprintf(c.App.ErrWriter, "- Email limit: %d\n", tier.EmailLimit)
fmt.Fprintf(c.App.ErrWriter, "- Reservation limit: %d\n", tier.ReservationLimit)
fmt.Fprintf(c.App.ErrWriter, "- Attachment file size limit: %s\n", util.FormatSize(tier.AttachmentFileSizeLimit))
fmt.Fprintf(c.App.ErrWriter, "- Attachment total size limit: %s\n", util.FormatSize(tier.AttachmentTotalSizeLimit))
fmt.Fprintf(c.App.ErrWriter, "- Attachment expiry duration: %s (%d seconds)\n", tier.AttachmentExpiryDuration.String(), int64(tier.AttachmentExpiryDuration.Seconds()))
fmt.Fprintf(c.App.ErrWriter, "- Attachment daily bandwidth limit: %s\n", util.FormatSize(tier.AttachmentBandwidthLimit))
fmt.Fprintf(c.App.ErrWriter, "- Stripe prices (monthly/yearly): %s\n", prices)
fmt.Fprintf(c.App.Writer, "tier %s (id: %s)\n", tier.Code, tier.ID)
fmt.Fprintf(c.App.Writer, "- Name: %s\n", tier.Name)
fmt.Fprintf(c.App.Writer, "- Message limit: %d\n", tier.MessageLimit)
fmt.Fprintf(c.App.Writer, "- Message expiry duration: %s (%d seconds)\n", tier.MessageExpiryDuration.String(), int64(tier.MessageExpiryDuration.Seconds()))
fmt.Fprintf(c.App.Writer, "- Email limit: %d\n", tier.EmailLimit)
fmt.Fprintf(c.App.Writer, "- Phone call limit: %d\n", tier.CallLimit)
fmt.Fprintf(c.App.Writer, "- Reservation limit: %d\n", tier.ReservationLimit)
fmt.Fprintf(c.App.Writer, "- Attachment file size limit: %s\n", util.FormatSizeHuman(tier.AttachmentFileSizeLimit))
fmt.Fprintf(c.App.Writer, "- Attachment total size limit: %s\n", util.FormatSizeHuman(tier.AttachmentTotalSizeLimit))
fmt.Fprintf(c.App.Writer, "- Attachment expiry duration: %s (%d seconds)\n", tier.AttachmentExpiryDuration.String(), int64(tier.AttachmentExpiryDuration.Seconds()))
fmt.Fprintf(c.App.Writer, "- Attachment daily bandwidth limit: %s\n", util.FormatSizeHuman(tier.AttachmentBandwidthLimit))
fmt.Fprintf(c.App.Writer, "- Stripe prices (monthly/yearly): %s\n", prices)
}

View File

@@ -3,8 +3,8 @@ package cmd
import (
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/server"
"heckel.io/ntfy/test"
"heckel.io/ntfy/v2/server"
"heckel.io/ntfy/v2/test"
"testing"
)
@@ -12,21 +12,21 @@ func TestCLI_Tier_AddListChangeDelete(t *testing.T) {
s, conf, port := newTestServerWithAuth(t)
defer test.StopServer(t, s, port)
app, _, _, stderr := newTestApp()
app, _, stdout, _ := newTestApp()
require.Nil(t, runTierCommand(app, conf, "add", "--name", "Pro", "--message-limit", "1234", "pro"))
require.Contains(t, stderr.String(), "tier added\n\ntier pro (id: ti_")
require.Contains(t, stdout.String(), "tier added\n\ntier pro (id: ti_")
err := runTierCommand(app, conf, "add", "pro")
require.NotNil(t, err)
require.Equal(t, "tier pro already exists", err.Error())
app, _, _, stderr = newTestApp()
app, _, stdout, _ = newTestApp()
require.Nil(t, runTierCommand(app, conf, "list"))
require.Contains(t, stderr.String(), "tier pro (id: ti_")
require.Contains(t, stderr.String(), "- Name: Pro")
require.Contains(t, stderr.String(), "- Message limit: 1234")
require.Contains(t, stdout.String(), "tier pro (id: ti_")
require.Contains(t, stdout.String(), "- Name: Pro")
require.Contains(t, stdout.String(), "- Message limit: 1234")
app, _, _, stderr = newTestApp()
app, _, stdout, _ = newTestApp()
require.Nil(t, runTierCommand(app, conf, "change",
"--message-limit=999",
"--message-expiry-duration=2d",
@@ -40,18 +40,18 @@ func TestCLI_Tier_AddListChangeDelete(t *testing.T) {
"--stripe-yearly-price-id=price_992",
"pro",
))
require.Contains(t, stderr.String(), "- Message limit: 999")
require.Contains(t, stderr.String(), "- Message expiry duration: 48h")
require.Contains(t, stderr.String(), "- Email limit: 91")
require.Contains(t, stderr.String(), "- Reservation limit: 98")
require.Contains(t, stderr.String(), "- Attachment file size limit: 100.0 MB")
require.Contains(t, stderr.String(), "- Attachment expiry duration: 24h")
require.Contains(t, stderr.String(), "- Attachment total size limit: 10.0 GB")
require.Contains(t, stderr.String(), "- Stripe prices (monthly/yearly): price_991 / price_992")
require.Contains(t, stdout.String(), "- Message limit: 999")
require.Contains(t, stdout.String(), "- Message expiry duration: 48h")
require.Contains(t, stdout.String(), "- Email limit: 91")
require.Contains(t, stdout.String(), "- Reservation limit: 98")
require.Contains(t, stdout.String(), "- Attachment file size limit: 100.0 MB")
require.Contains(t, stdout.String(), "- Attachment expiry duration: 24h")
require.Contains(t, stdout.String(), "- Attachment total size limit: 10.0 GB")
require.Contains(t, stdout.String(), "- Stripe prices (monthly/yearly): price_991 / price_992")
app, _, _, stderr = newTestApp()
app, _, stdout, _ = newTestApp()
require.Nil(t, runTierCommand(app, conf, "remove", "pro"))
require.Contains(t, stderr.String(), "tier pro removed")
require.Contains(t, stdout.String(), "tier pro removed")
}
func runTierCommand(app *cli.App, conf *server.Config, args ...string) error {

View File

@@ -6,8 +6,8 @@ import (
"errors"
"fmt"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/user"
"heckel.io/ntfy/util"
"heckel.io/ntfy/v2/user"
"heckel.io/ntfy/v2/util"
"net/netip"
"time"
)
@@ -72,6 +72,15 @@ Example:
This is a server-only command. It directly reads from user.db as defined in the server config
file server.yml. The command only works if 'auth-file' is properly defined.`,
},
{
Name: "generate",
Usage: "Generates a random token",
Action: execTokenGenerate,
Description: `Randomly generate a token to be used in provisioned tokens.
This command only generates the token value, but does not persist it anywhere.
The output can be used in the 'auth-tokens' config option.`,
},
},
Description: `Manage access tokens for individual users.
@@ -112,19 +121,19 @@ func execTokenAdd(c *cli.Context) error {
return err
}
u, err := manager.User(username)
if err == user.ErrUserNotFound {
if errors.Is(err, user.ErrUserNotFound) {
return fmt.Errorf("user %s does not exist", username)
} else if err != nil {
return err
}
token, err := manager.CreateToken(u.ID, label, expires, netip.IPv4Unspecified())
token, err := manager.CreateToken(u.ID, label, expires, netip.IPv4Unspecified(), false)
if err != nil {
return err
}
if expires.Unix() == 0 {
fmt.Fprintf(c.App.ErrWriter, "token %s created for user %s, never expires\n", token.Value, u.Name)
fmt.Fprintf(c.App.Writer, "token %s created for user %s, never expires\n", token.Value, u.Name)
} else {
fmt.Fprintf(c.App.ErrWriter, "token %s created for user %s, expires %v\n", token.Value, u.Name, expires.Format(time.UnixDate))
fmt.Fprintf(c.App.Writer, "token %s created for user %s, expires %v\n", token.Value, u.Name, expires.Format(time.UnixDate))
}
return nil
}
@@ -141,7 +150,7 @@ func execTokenDel(c *cli.Context) error {
return err
}
u, err := manager.User(username)
if err == user.ErrUserNotFound {
if errors.Is(err, user.ErrUserNotFound) {
return fmt.Errorf("user %s does not exist", username)
} else if err != nil {
return err
@@ -149,7 +158,7 @@ func execTokenDel(c *cli.Context) error {
if err := manager.RemoveToken(u.ID, token); err != nil {
return err
}
fmt.Fprintf(c.App.ErrWriter, "token %s for user %s removed\n", token, username)
fmt.Fprintf(c.App.Writer, "token %s for user %s removed\n", token, username)
return nil
}
@@ -165,7 +174,7 @@ func execTokenList(c *cli.Context) error {
var users []*user.User
if username != "" {
u, err := manager.User(username)
if err == user.ErrUserNotFound {
if errors.Is(err, user.ErrUserNotFound) {
return fmt.Errorf("user %s does not exist", username)
} else if err != nil {
return err
@@ -183,15 +192,15 @@ func execTokenList(c *cli.Context) error {
if err != nil {
return err
} else if len(tokens) == 0 && username != "" {
fmt.Fprintf(c.App.ErrWriter, "user %s has no access tokens\n", username)
fmt.Fprintf(c.App.Writer, "user %s has no access tokens\n", username)
return nil
} else if len(tokens) == 0 {
continue
}
usersWithTokens++
fmt.Fprintf(c.App.ErrWriter, "user %s\n", u.Name)
fmt.Fprintf(c.App.Writer, "user %s\n", u.Name)
for _, t := range tokens {
var label, expires string
var label, expires, provisioned string
if t.Label != "" {
label = fmt.Sprintf(" (%s)", t.Label)
}
@@ -200,11 +209,19 @@ func execTokenList(c *cli.Context) error {
} else {
expires = fmt.Sprintf("expires %s", t.Expires.Format(time.RFC822))
}
fmt.Fprintf(c.App.ErrWriter, "- %s%s, %s, accessed from %s at %s\n", t.Value, label, expires, t.LastOrigin.String(), t.LastAccess.Format(time.RFC822))
if t.Provisioned {
provisioned = " (server config)"
}
fmt.Fprintf(c.App.Writer, "- %s%s, %s, accessed from %s at %s%s\n", t.Value, label, expires, t.LastOrigin.String(), t.LastAccess.Format(time.RFC822), provisioned)
}
}
if usersWithTokens == 0 {
fmt.Fprintf(c.App.ErrWriter, "no users with tokens\n")
fmt.Fprintf(c.App.Writer, "no users with tokens\n")
}
return nil
}
func execTokenGenerate(c *cli.Context) error {
fmt.Fprintln(c.App.Writer, user.GenerateToken())
return nil
}

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/server"
"heckel.io/ntfy/test"
"heckel.io/ntfy/v2/server"
"heckel.io/ntfy/v2/test"
"regexp"
"testing"
)
@@ -14,28 +14,28 @@ func TestCLI_Token_AddListRemove(t *testing.T) {
s, conf, port := newTestServerWithAuth(t)
defer test.StopServer(t, s, port)
app, stdin, _, stderr := newTestApp()
app, stdin, stdout, _ := newTestApp()
stdin.WriteString("mypass\nmypass")
require.Nil(t, runUserCommand(app, conf, "add", "phil"))
require.Contains(t, stderr.String(), "user phil added with role user")
require.Contains(t, stdout.String(), "user phil added with role user")
app, _, _, stderr = newTestApp()
app, _, stdout, _ = newTestApp()
require.Nil(t, runTokenCommand(app, conf, "add", "phil"))
require.Regexp(t, `token tk_.+ created for user phil, never expires`, stderr.String())
require.Regexp(t, `token tk_.+ created for user phil, never expires`, stdout.String())
app, _, _, stderr = newTestApp()
app, _, stdout, _ = newTestApp()
require.Nil(t, runTokenCommand(app, conf, "list", "phil"))
require.Regexp(t, `user phil\n- tk_.+, never expires, accessed from 0.0.0.0 at .+`, stderr.String())
require.Regexp(t, `user phil\n- tk_.+, never expires, accessed from 0.0.0.0 at .+`, stdout.String())
re := regexp.MustCompile(`tk_\w+`)
token := re.FindString(stderr.String())
token := re.FindString(stdout.String())
app, _, _, stderr = newTestApp()
app, _, stdout, _ = newTestApp()
require.Nil(t, runTokenCommand(app, conf, "remove", "phil", token))
require.Regexp(t, fmt.Sprintf("token %s for user phil removed", token), stderr.String())
require.Regexp(t, fmt.Sprintf("token %s for user phil removed", token), stdout.String())
app, _, _, stderr = newTestApp()
app, _, stdout, _ = newTestApp()
require.Nil(t, runTokenCommand(app, conf, "list"))
require.Equal(t, "no users with tokens\n", stderr.String())
require.Equal(t, "no users with tokens\n", stdout.String())
}
func runTokenCommand(app *cli.App, conf *server.Config, args ...string) error {

View File

@@ -6,13 +6,14 @@ import (
"crypto/subtle"
"errors"
"fmt"
"heckel.io/ntfy/user"
"heckel.io/ntfy/v2/server"
"heckel.io/ntfy/v2/user"
"os"
"strings"
"github.com/urfave/cli/v2"
"github.com/urfave/cli/v2/altsrc"
"heckel.io/ntfy/util"
"heckel.io/ntfy/v2/util"
)
const (
@@ -25,7 +26,7 @@ func init() {
var flagsUser = append(
append([]cli.Flag{}, flagsDefault...),
&cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: defaultServerConfigFile, DefaultText: defaultServerConfigFile, Usage: "config file"},
&cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: server.DefaultConfigFile, DefaultText: server.DefaultConfigFile, Usage: "config file"},
altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-file", Aliases: []string{"auth_file", "H"}, EnvVars: []string{"NTFY_AUTH_FILE"}, Usage: "auth database file used for access control"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-default-access", Aliases: []string{"auth_default_access", "p"}, EnvVars: []string{"NTFY_AUTH_DEFAULT_ACCESS"}, Value: "read-write", Usage: "default permissions if no matching entries in the auth database are found"}),
)
@@ -42,7 +43,7 @@ var cmdUser = &cli.Command{
Name: "add",
Aliases: []string{"a"},
Usage: "Adds a new user",
UsageText: "ntfy user add [--role=admin|user] USERNAME\nNTFY_PASSWORD=... ntfy user add [--role=admin|user] USERNAME",
UsageText: "ntfy user add [--role=admin|user] USERNAME\nNTFY_PASSWORD=... ntfy user add [--role=admin|user] USERNAME\nNTFY_PASSWORD_HASH=... ntfy user add [--role=admin|user] USERNAME",
Action: execUserAdd,
Flags: []cli.Flag{
&cli.StringFlag{Name: "role", Aliases: []string{"r"}, Value: string(user.RoleUser), Usage: "user role"},
@@ -55,12 +56,13 @@ granted otherwise by the auth-default-access setting). An admin user has read an
topics.
Examples:
ntfy user add phil # Add regular user phil
ntfy user add --role=admin phil # Add admin user phil
NTFY_PASSWORD=... ntfy user add phil # Add user, using env variable to set password (for scripts)
ntfy user add phil # Add regular user phil
ntfy user add --role=admin phil # Add admin user phil
NTFY_PASSWORD=... ntfy user add phil # Add user, using env variable to set password (for scripts)
NTFY_PASSWORD_HASH=... ntfy user add phil # Add user, using env variable to set password hash (for scripts)
You may set the NTFY_PASSWORD environment variable to pass the password. This is useful if
you are creating users via scripts.
You may set the NTFY_PASSWORD environment variable to pass the password, or NTFY_PASSWORD_HASH to pass
directly the bcrypt hash. This is useful if you are creating users via scripts.
`,
},
{
@@ -79,7 +81,7 @@ Example:
Name: "change-pass",
Aliases: []string{"chp"},
Usage: "Changes a user's password",
UsageText: "ntfy user change-pass USERNAME\nNTFY_PASSWORD=... ntfy user change-pass USERNAME",
UsageText: "ntfy user change-pass USERNAME\nNTFY_PASSWORD=... ntfy user change-pass USERNAME\nNTFY_PASSWORD_HASH=... ntfy user change-pass USERNAME",
Action: execUserChangePass,
Description: `Change the password for the given user.
@@ -89,10 +91,10 @@ it twice.
Example:
ntfy user change-pass phil
NTFY_PASSWORD=.. ntfy user change-pass phil
NTFY_PASSWORD_HASH=.. ntfy user change-pass phil
You may set the NTFY_PASSWORD environment variable to pass the new password. This is
useful if you are updating users via scripts.
You may set the NTFY_PASSWORD environment variable to pass the new password or NTFY_PASSWORD_HASH to pass
directly the bcrypt hash. This is useful if you are updating users via scripts.
`,
},
{
@@ -131,6 +133,22 @@ as messages per day, attachment file sizes, etc.
Example:
ntfy user change-tier phil pro # Change tier to "pro" for user "phil"
ntfy user change-tier phil - # Remove tier from user "phil" entirely
`,
},
{
Name: "hash",
Usage: "Create password hash for a predefined user",
UsageText: "ntfy user hash",
Action: execUserHash,
Description: `Asks for a password and creates a bcrypt password hash.
This command is useful to create a password hash for a user, which can then be used
for predefined users in the server config file, in auth-users.
Example:
$ ntfy user hash
(asks for password and confirmation)
$2a$10$YLiO8U21sX1uhZamTLJXHuxgVC0Z/GKISibrKCLohPgtG7yIxSk4C
`,
},
{
@@ -174,7 +192,12 @@ variable to pass the new password. This is useful if you are creating/updating u
func execUserAdd(c *cli.Context) error {
username := c.Args().Get(0)
role := user.Role(c.String("role"))
password := os.Getenv("NTFY_PASSWORD")
password, hashed := os.LookupEnv("NTFY_PASSWORD_HASH")
if !hashed {
password = os.Getenv("NTFY_PASSWORD")
}
if username == "" {
return errors.New("username expected, type 'ntfy user add --help' for help")
} else if username == userEveryone || username == user.Everyone {
@@ -188,7 +211,7 @@ func execUserAdd(c *cli.Context) error {
}
if user, _ := manager.User(username); user != nil {
if c.Bool("ignore-exists") {
fmt.Fprintf(c.App.ErrWriter, "user %s already exists (exited successfully)\n", username)
fmt.Fprintf(c.App.Writer, "user %s already exists (exited successfully)\n", username)
return nil
}
return fmt.Errorf("user %s already exists", username)
@@ -198,13 +221,12 @@ func execUserAdd(c *cli.Context) error {
if err != nil {
return err
}
password = p
}
if err := manager.AddUser(username, password, role); err != nil {
if err := manager.AddUser(username, password, role, hashed); err != nil {
return err
}
fmt.Fprintf(c.App.ErrWriter, "user %s added with role %s\n", username, role)
fmt.Fprintf(c.App.Writer, "user %s added with role %s\n", username, role)
return nil
}
@@ -219,19 +241,23 @@ func execUserDel(c *cli.Context) error {
if err != nil {
return err
}
if _, err := manager.User(username); err == user.ErrUserNotFound {
if _, err := manager.User(username); errors.Is(err, user.ErrUserNotFound) {
return fmt.Errorf("user %s does not exist", username)
}
if err := manager.RemoveUser(username); err != nil {
return err
}
fmt.Fprintf(c.App.ErrWriter, "user %s removed\n", username)
fmt.Fprintf(c.App.Writer, "user %s removed\n", username)
return nil
}
func execUserChangePass(c *cli.Context) error {
username := c.Args().Get(0)
password := os.Getenv("NTFY_PASSWORD")
password, hashed := os.LookupEnv("NTFY_PASSWORD_HASH")
if !hashed {
password = os.Getenv("NTFY_PASSWORD")
}
if username == "" {
return errors.New("username expected, type 'ntfy user change-pass --help' for help")
} else if username == userEveryone || username == user.Everyone {
@@ -241,7 +267,7 @@ func execUserChangePass(c *cli.Context) error {
if err != nil {
return err
}
if _, err := manager.User(username); err == user.ErrUserNotFound {
if _, err := manager.User(username); errors.Is(err, user.ErrUserNotFound) {
return fmt.Errorf("user %s does not exist", username)
}
if password == "" {
@@ -250,10 +276,10 @@ func execUserChangePass(c *cli.Context) error {
return err
}
}
if err := manager.ChangePassword(username, password); err != nil {
if err := manager.ChangePassword(username, password, hashed); err != nil {
return err
}
fmt.Fprintf(c.App.ErrWriter, "changed password for user %s\n", username)
fmt.Fprintf(c.App.Writer, "changed password for user %s\n", username)
return nil
}
@@ -269,13 +295,26 @@ func execUserChangeRole(c *cli.Context) error {
if err != nil {
return err
}
if _, err := manager.User(username); err == user.ErrUserNotFound {
if _, err := manager.User(username); errors.Is(err, user.ErrUserNotFound) {
return fmt.Errorf("user %s does not exist", username)
}
if err := manager.ChangeRole(username, role); err != nil {
return err
}
fmt.Fprintf(c.App.ErrWriter, "changed role for user %s to %s\n", username, role)
fmt.Fprintf(c.App.Writer, "changed role for user %s to %s\n", username, role)
return nil
}
func execUserHash(c *cli.Context) error {
password, err := readPasswordAndConfirm(c)
if err != nil {
return err
}
hash, err := user.HashPassword(password)
if err != nil {
return fmt.Errorf("failed to hash password: %w", err)
}
fmt.Fprintln(c.App.Writer, hash)
return nil
}
@@ -293,19 +332,19 @@ func execUserChangeTier(c *cli.Context) error {
if err != nil {
return err
}
if _, err := manager.User(username); err == user.ErrUserNotFound {
if _, err := manager.User(username); errors.Is(err, user.ErrUserNotFound) {
return fmt.Errorf("user %s does not exist", username)
}
if tier == tierReset {
if err := manager.ResetTier(username); err != nil {
return err
}
fmt.Fprintf(c.App.ErrWriter, "removed tier from user %s\n", username)
fmt.Fprintf(c.App.Writer, "removed tier from user %s\n", username)
} else {
if err := manager.ChangeTier(username, tier); err != nil {
return err
}
fmt.Fprintf(c.App.ErrWriter, "changed tier for user %s to %s\n", username, tier)
fmt.Fprintf(c.App.Writer, "changed tier for user %s to %s\n", username, tier)
}
return nil
}
@@ -335,7 +374,15 @@ func createUserManager(c *cli.Context) (*user.Manager, error) {
if err != nil {
return nil, errors.New("if set, auth-default-access must start set to 'read-write', 'read-only', 'write-only' or 'deny-all'")
}
return user.NewManager(authFile, authStartupQueries, authDefault, user.DefaultUserPasswordBcryptCost, user.DefaultUserStatsQueueWriterInterval)
authConfig := &user.Config{
Filename: authFile,
StartupQueries: authStartupQueries,
DefaultAccess: authDefault,
ProvisionEnabled: false, // Hack: Do not re-provision users on manager initialization
BcryptCost: user.DefaultUserPasswordBcryptCost,
QueueWriterInterval: user.DefaultUserStatsQueueWriterInterval,
}
return user.NewManager(authConfig)
}
func readPasswordAndConfirm(c *cli.Context) (string, error) {
@@ -343,6 +390,8 @@ func readPasswordAndConfirm(c *cli.Context) (string, error) {
password, err := util.ReadPassword(c.App.Reader)
if err != nil {
return "", err
} else if len(password) == 0 {
return "", errors.New("password cannot be empty")
}
fmt.Fprintf(c.App.ErrWriter, "\r%s\rconfirm: ", strings.Repeat(" ", 25))
confirm, err := util.ReadPassword(c.App.Reader)

View File

@@ -3,9 +3,9 @@ package cmd
import (
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/server"
"heckel.io/ntfy/test"
"heckel.io/ntfy/user"
"heckel.io/ntfy/v2/server"
"heckel.io/ntfy/v2/test"
"heckel.io/ntfy/v2/user"
"os"
"path/filepath"
"testing"
@@ -15,20 +15,20 @@ func TestCLI_User_Add(t *testing.T) {
s, conf, port := newTestServerWithAuth(t)
defer test.StopServer(t, s, port)
app, stdin, _, stderr := newTestApp()
app, stdin, stdout, _ := newTestApp()
stdin.WriteString("mypass\nmypass")
require.Nil(t, runUserCommand(app, conf, "add", "phil"))
require.Contains(t, stderr.String(), "user phil added with role user")
require.Contains(t, stdout.String(), "user phil added with role user")
}
func TestCLI_User_Add_Exists(t *testing.T) {
s, conf, port := newTestServerWithAuth(t)
defer test.StopServer(t, s, port)
app, stdin, _, stderr := newTestApp()
app, stdin, stdout, _ := newTestApp()
stdin.WriteString("mypass\nmypass")
require.Nil(t, runUserCommand(app, conf, "add", "phil"))
require.Contains(t, stderr.String(), "user phil added with role user")
require.Contains(t, stdout.String(), "user phil added with role user")
app, stdin, _, _ = newTestApp()
stdin.WriteString("mypass\nmypass")
@@ -41,10 +41,10 @@ func TestCLI_User_Add_Admin(t *testing.T) {
s, conf, port := newTestServerWithAuth(t)
defer test.StopServer(t, s, port)
app, stdin, _, stderr := newTestApp()
app, stdin, stdout, _ := newTestApp()
stdin.WriteString("mypass\nmypass")
require.Nil(t, runUserCommand(app, conf, "add", "--role=admin", "phil"))
require.Contains(t, stderr.String(), "user phil added with role admin")
require.Contains(t, stdout.String(), "user phil added with role admin")
}
func TestCLI_User_Add_Password_Mismatch(t *testing.T) {
@@ -60,19 +60,27 @@ func TestCLI_User_Add_Password_Mismatch(t *testing.T) {
func TestCLI_User_ChangePass(t *testing.T) {
s, conf, port := newTestServerWithAuth(t)
conf.AuthUsers = []*user.User{
{Name: "philuser", Hash: "$2a$10$U4WSIYY6evyGmZaraavM2e2JeVG6EMGUKN1uUwufUeeRd4Jpg6cGC", Role: user.RoleUser}, // philuser:philpass
}
defer test.StopServer(t, s, port)
// Add user
app, stdin, _, stderr := newTestApp()
app, stdin, stdout, _ := newTestApp()
stdin.WriteString("mypass\nmypass")
require.Nil(t, runUserCommand(app, conf, "add", "phil"))
require.Contains(t, stderr.String(), "user phil added with role user")
require.Contains(t, stdout.String(), "user phil added with role user")
// Change pass
app, stdin, _, stderr = newTestApp()
app, stdin, stdout, _ = newTestApp()
stdin.WriteString("newpass\nnewpass")
require.Nil(t, runUserCommand(app, conf, "change-pass", "phil"))
require.Contains(t, stderr.String(), "changed password for user phil")
require.Contains(t, stdout.String(), "changed password for user phil")
// Cannot change provisioned user's pass
app, stdin, _, _ = newTestApp()
stdin.WriteString("newpass\nnewpass")
require.Error(t, runUserCommand(app, conf, "change-pass", "philuser"))
}
func TestCLI_User_ChangeRole(t *testing.T) {
@@ -80,15 +88,15 @@ func TestCLI_User_ChangeRole(t *testing.T) {
defer test.StopServer(t, s, port)
// Add user
app, stdin, _, stderr := newTestApp()
app, stdin, stdout, _ := newTestApp()
stdin.WriteString("mypass\nmypass")
require.Nil(t, runUserCommand(app, conf, "add", "phil"))
require.Contains(t, stderr.String(), "user phil added with role user")
require.Contains(t, stdout.String(), "user phil added with role user")
// Change role
app, _, _, stderr = newTestApp()
app, _, stdout, _ = newTestApp()
require.Nil(t, runUserCommand(app, conf, "change-role", "phil", "admin"))
require.Contains(t, stderr.String(), "changed role for user phil to admin")
require.Contains(t, stdout.String(), "changed role for user phil to admin")
}
func TestCLI_User_Delete(t *testing.T) {
@@ -96,15 +104,15 @@ func TestCLI_User_Delete(t *testing.T) {
defer test.StopServer(t, s, port)
// Add user
app, stdin, _, stderr := newTestApp()
app, stdin, stdout, _ := newTestApp()
stdin.WriteString("mypass\nmypass")
require.Nil(t, runUserCommand(app, conf, "add", "phil"))
require.Contains(t, stderr.String(), "user phil added with role user")
require.Contains(t, stdout.String(), "user phil added with role user")
// Delete user
app, _, _, stderr = newTestApp()
app, _, stdout, _ = newTestApp()
require.Nil(t, runUserCommand(app, conf, "del", "phil"))
require.Contains(t, stderr.String(), "user phil removed")
require.Contains(t, stdout.String(), "user phil removed")
// Delete user again (does not exist)
app, _, _, _ = newTestApp()

69
cmd/webpush.go Normal file
View File

@@ -0,0 +1,69 @@
//go:build !noserver && !nowebpush
package cmd
import (
"fmt"
"os"
"github.com/SherClockHolmes/webpush-go"
"github.com/urfave/cli/v2"
"github.com/urfave/cli/v2/altsrc"
)
var flagsWebPush = append(
[]cli.Flag{},
altsrc.NewStringFlag(&cli.StringFlag{Name: "output-file", Aliases: []string{"f"}, Usage: "write VAPID keys to this file"}),
)
func init() {
commands = append(commands, cmdWebPush)
}
var cmdWebPush = &cli.Command{
Name: "webpush",
Usage: "Generate keys, in the future manage web push subscriptions",
UsageText: "ntfy webpush [keys]",
Category: categoryServer,
Subcommands: []*cli.Command{
{
Action: generateWebPushKeys,
Name: "keys",
Usage: "Generate VAPID keys to enable browser background push notifications",
UsageText: "ntfy webpush keys",
Category: categoryServer,
Flags: flagsWebPush,
},
},
}
func generateWebPushKeys(c *cli.Context) error {
privateKey, publicKey, err := webpush.GenerateVAPIDKeys()
if err != nil {
return err
}
if outputFile := c.String("output-file"); outputFile != "" {
contents := fmt.Sprintf(`---
web-push-public-key: %s
web-push-private-key: %s
`, publicKey, privateKey)
err = os.WriteFile(outputFile, []byte(contents), 0660)
if err != nil {
return err
}
_, err = fmt.Fprintf(c.App.Writer, "Web Push keys written to %s.\n", outputFile)
} else {
_, err = fmt.Fprintf(c.App.Writer, `Web Push keys generated. Add the following lines to your config file:
web-push-public-key: %s
web-push-private-key: %s
web-push-file: /var/cache/ntfy/webpush.db # or similar
web-push-email-address: <email address>
See https://ntfy.sh/docs/config/#web-push for details.
`, publicKey, privateKey)
}
return err
}

34
cmd/webpush_test.go Normal file
View File

@@ -0,0 +1,34 @@
package cmd
import (
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
"heckel.io/ntfy/v2/server"
)
func TestCLI_WebPush_GenerateKeys(t *testing.T) {
app, _, stdout, _ := newTestApp()
require.Nil(t, runWebPushCommand(app, server.NewConfig(), "keys"))
require.Contains(t, stdout.String(), "Web Push keys generated.")
}
func TestCLI_WebPush_WriteKeysToFile(t *testing.T) {
tempDir := t.TempDir()
t.Chdir(tempDir)
app, _, stdout, _ := newTestApp()
require.Nil(t, runWebPushCommand(app, server.NewConfig(), "keys", "--output-file=key-file.yaml"))
require.Contains(t, stdout.String(), "Web Push keys written to key-file.yaml")
require.FileExists(t, filepath.Join(tempDir, "key-file.yaml"))
}
func runWebPushCommand(app *cli.App, conf *server.Config, args ...string) error {
webPushArgs := []string{
"ntfy",
"--log-level=ERROR",
"webpush",
}
return app.Run(append(webPushArgs, args...))
}

View File

@@ -1,4 +1,3 @@
version: "2.1"
services:
ntfy:
image: binwiederhier/ntfy
@@ -14,4 +13,3 @@ services:
ports:
- 80:80
restart: unless-stopped

View File

@@ -32,11 +32,11 @@
<path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"></path>
</svg>
</button>
If you like ntfy, please consider sponsoring it via <a target="_blank" href="https://github.com/sponsors/binwiederhier"><strong>GitHub Sponsors</strong></a>
If you like ntfy, please consider sponsoring me via <a target="_blank" href="https://github.com/sponsors/binwiederhier"><strong>GitHub Sponsors</strong></a>
or <a target="_blank" href="https://en.liberapay.com/ntfy/"><strong>Liberapay</strong></a>
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 36 36" class="twemoji md-footer-custom-text">
<path fill="#DD2E44" d="M35.885 11.833c0-5.45-4.418-9.868-9.867-9.868-3.308 0-6.227 1.633-8.018 4.129-1.791-2.496-4.71-4.129-8.017-4.129-5.45 0-9.868 4.417-9.868 9.868 0 .772.098 1.52.266 2.241C1.751 22.587 11.216 31.568 18 34.034c6.783-2.466 16.249-11.447 17.617-19.959.17-.721.268-1.469.268-2.242z"/>
</svg>
</svg>, or subscribing to <a target="_blank" href="https://ntfy.sh/app"><strong>ntfy Pro</strong></a>.
<script>
announceBarKey = 'announce-bar-closed-sponsor';
document.getElementById('announce-bar-close').addEventListener('click', (e) => {

File diff suppressed because it is too large Load Diff

46
docs/contact.md Normal file
View File

@@ -0,0 +1,46 @@
# Contact
This service is run by [Philipp C. Heckel](https://heckel.io). There are several ways to get in touch with me and the
ntfy community. Please choose the appropriate channel based on your needs.
## Support
### Community support
For general questions, feature discussions, and community help, please use one of these public channels:
| Channel | Link | Description |
|-------------------|--------------------------------------------------------------------------------------|------------------------------------------------------------|
| **Discord** | [discord.gg/cT7ECsZj9w](https://discord.gg/cT7ECsZj9w) | Real-time chat with the community (I'm `binwiederhier`) |
| **Matrix** | [#ntfy:matrix.org](https://matrix.to/#/#ntfy:matrix.org) | Bridged from Discord, same community (I'm `binwiederhier`) |
| **Matrix Space** | [#ntfy-space:matrix.org](https://matrix.to/#/#ntfy-space:matrix.org) | Matrix space with all ntfy rooms |
| **GitHub Issues** | [github.com/binwiederhier/ntfy/issues](https://github.com/binwiederhier/ntfy/issues) | Bug reports and feature requests |
!!! info "Why public channels?"
Answering questions in public channels benefits the entire community. Other users can learn from the
discussion, and answers can be referenced later. This is much more scalable than 1-on-1 support.
### Paid support
If you are subscribed to a [ntfy Pro](https://ntfy.sh/#pricing) plan, you are entitled to priority support
via the following channels:
| Channel | Contact | Description |
|-----------------------|-----------------------------------------------------|------------------------------------------|
| **General Support** | [support@mail.ntfy.sh](mailto:support@mail.ntfy.sh) | Direct email support for Pro subscribers |
| **Billing Inquiries** | [billing@mail.ntfy.sh](mailto:support@mail.ntfy.sh) | Inquire about billing issues |
| **Discord/Matrix** | Mention your Pro status | Priority responses in community channels |
Please include your ntfy.sh username when contacting support so we can verify your subscription status.
## Security issues
If you discover a security vulnerability, please report it responsibly via [security@mail.ntfy.sh](mailto:security@mail.ntfy.sh). See also: [SECURITY.md](https://github.com/binwiederhier/ntfy/blob/main/SECURITY.md).
## Other inquiries
For questions about our [privacy policy](privacy.md), data handling, or to exercise your data rights
(access, deletion, etc.), please email [privacy@mail.ntfy.sh](mailto:privacy@mail.ntfy.sh).
For business inquiries, partnerships, press, or other general questions that don't fit the categories above, please
use [contact@mail.ntfy.sh](mailto:contact@mail.ntfy.sh).

43
docs/contributing.md Normal file
View File

@@ -0,0 +1,43 @@
# Contributing
Thank you for your interest in contributing to ntfy! There are many ways to help, whether you're a developer,
translator, or just an enthusiastic user.
## Code contributions
If you'd like to contribute code to ntfy:
1. Check out the [development guide](develop.md) to set up your environment
2. Look at [open issues](https://github.com/binwiederhier/ntfy/issues) for ideas, or propose your own
3. For larger features or architectural changes, please reach out on [Discord/Matrix](contact.md) first to discuss
before investing significant time
4. Submit a pull request on GitHub
All contributions are welcome, from small bug fixes to major features.
## Translations
Help make ntfy accessible to users around the world! We use Hosted Weblate for translations:
- **Weblate**: [hosted.weblate.org/projects/ntfy](https://hosted.weblate.org/projects/ntfy/)
You can start translating immediately without any coding knowledge.
## Documentation
Found a typo? Want to improve the docs? Documentation contributions are very welcome:
- Edit any page directly on GitHub using the edit button
- Submit a pull request with your improvements
## Bug reports and feature requests
- **GitHub Issues**: [github.com/binwiederhier/ntfy/issues](https://github.com/binwiederhier/ntfy/issues)
Please search existing issues before creating a new one to avoid duplicates.
## Code of Conduct
Please be respectful and constructive in all interactions. See the
[Code of Conduct](https://github.com/binwiederhier/ntfy/blob/main/CODE_OF_CONDUCT.md) for details.

View File

@@ -1,4 +1,4 @@
# Deprecation notices
# Deprecations and breaking changes
This page is used to list deprecation notices for ntfy. Deprecated commands and options will be
**removed after 1-3 months** from the time they were deprecated. How long the feature is deprecated
before the behavior is changed depends on the severity of the change, and how prominent the feature is.

View File

@@ -2,7 +2,7 @@
Hurray 🥳 🎉, you are interested in writing code for ntfy! **That's awesome.** 😎
I tried my very best to write up detailed instructions, but if at any point in time you run into issues, don't
hesitate to **contact me on [Discord](https://discord.gg/cT7ECsZj9w) or [Matrix](https://matrix.to/#/#ntfy:matrix.org)**.
hesitate to reach out via one of the channels listed on the [contact page](contact.md).
## ntfy server
The ntfy server source code is available [on GitHub](https://github.com/binwiederhier/ntfy). The codebase for the
@@ -16,7 +16,7 @@ server consists of three components:
* **The documentation** is generated by [MkDocs](https://www.mkdocs.org/) and [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/),
which is written in [Python](https://www.python.org/). You'll need Python and MkDocs (via `pip`) only if you want to
build the docs.
* **The web app** is written in [React](https://reactjs.org/), using [MUI](https://mui.com/). It uses [Create React App](https://create-react-app.dev/)
* **The web app** is written in [React](https://reactjs.org/), using [MUI](https://mui.com/). It uses [Vite](https://vitejs.dev/)
to build the production build. If you want to modify the web app, you need [nodejs](https://nodejs.org/en/) (for `npm`)
and install all the 100,000 dependencies (*sigh*).
@@ -163,6 +163,15 @@ $ make release-snapshot
During development, you may want to be more picky and build only certain things. Here are a few examples.
### Build a Docker image only for Linux
This is useful to test the final build with web app, docs, and server without any dependencies locally
``` shell
$ make docker-dev
$ docker run --rm -p 80:80 binwiederhier/ntfy:dev serve
```
### Build the ntfy binary
To build only the `ntfy` binary **without the web app or documentation**, use the `make cli-...` targets:
@@ -232,6 +241,41 @@ $ cd web
$ npm start
```
### Testing Web Push locally
Reference: <https://stackoverflow.com/questions/34160509/options-for-testing-service-workers-via-http>
#### With the dev servers
1. Get web push keys `go run main.go webpush keys`
2. Run the server with web push enabled
```sh
go run main.go \
--log-level debug \
serve \
--web-push-public-key KEY \
--web-push-private-key KEY \
--web-push-email-address <email> \
--web-push-file=/tmp/webpush.db
```
3. In `web/public/config.js`:
- Set `base_url` to `http://localhost`, This is required as web push can only be used with the server matching the `base_url`.
- Set the `web_push_public_key` correctly.
4. Run `npm run start`
#### With a built package
1. Run `make web-build`
2. Run the server (step 2 above)
3. Open <http://localhost/>
### Build the docs
The sources for the docs live in `docs/`. Similarly to the web app, you can simply run `make docs` to build the
documentation. As long as you have `mkdocs` installed (see above), this should work fine:
@@ -319,7 +363,7 @@ To build your own version with Firebase, you must:
* And change `app_base_url` in [values.xml](https://github.com/binwiederhier/ntfy-android/blob/main/app/src/main/res/values/values.xml)
* Then run:
```
# To build an unsigned .apk (app/build/outputs/apk/play/*.apk)
# To build an unsigned .apk (app/build/outputs/apk/play/release/*.apk)
./gradlew assemblePlayRelease
# To build a bundle .aab (app/play/release/*.aab)
@@ -340,7 +384,7 @@ strictly based off of my development on this app. There may be other versions of
### Apple setup
!!! info
Along with this step, the [PLIST Deployment](#plist-deployment-and-configuration) step is also required
Along with this step, the [PLIST Deployment](#plist-config) step is also required
for these changes to take effect in the iOS app.
1. [Create a new key in Apple Developer Member Center](https://developer.apple.com/account/resources/authkeys/add)
@@ -385,7 +429,7 @@ steps:
### XCode setup
1. Follow step 4 of [https://firebase.google.com/docs/ios/setup](Add Firebase to your Apple project) to install the
1. Follow step 4 of [Add Firebase to your Apple project](https://firebase.google.com/docs/ios/setup) to install the
`firebase-ios-sdk` in XCode, if it's not already present - you can select any packages in addition to Firebase Core / Firebase Messaging
1. Similarly, install the SQLite.swift package dependency in XCode
1. When running the debug build, ensure XCode is pointed to the connected iOS device - registering for push notifications does not work in the iOS simulators
@@ -397,6 +441,6 @@ To have instant notifications/better notification delivery when using firebase,
1. In XCode, find the NTFY app target. **Not** the NSE app target.
1. Find the Asset/ folder in the project navigator
1. Drag the `GoogleService-Info.plist` file into the Asset/ folder that you get from the firebase console. It can be
found in the "Project settings" > "General" > "Your apps" with a button labled "GoogleService-Info.plist"
found in the "Project settings" > "General" > "Your apps" with a button labeled "GoogleService-Info.plist"
After that, you should be all set!

View File

@@ -2,9 +2,9 @@
<!-- This file was generated by scripts/emoji-convert.sh -->
You can [tag messages](../publish/#tags-emojis) with emojis 🥳 🎉 and other relevant strings. Matching tags are automatically
You can [tag messages](publish.md#tags-emojis) with emojis 🥳 🎉 and other relevant strings. Matching tags are automatically
converted to emojis. This is a reference of all supported emojis. To learn more about the feature, please refer to the
[tagging and emojis page](../publish/#tags-emojis).
[tagging and emojis page](publish.md#tags-emojis).
<table class="remove-md-box emoji-table"><tr>

View File

@@ -16,7 +16,7 @@ I started adding notifications pretty much all of my scripts. Typically, I just
directly to the command I'm running. The following example will either send <i>Laptop backup succeeded</i>
or ⚠️ <i>Laptop backup failed</i> directly to my phone:
```
``` bash
rsync -a root@laptop /backups/laptop \
&& zfs snapshot ... \
&& curl -H prio:low -d "Laptop backup succeeded" ntfy.sh/backups \
@@ -26,11 +26,17 @@ rsync -a root@laptop /backups/laptop \
Here's one for the history books. I desperately want the `github.com/ntfy` organization, but all my tickets with
GitHub have been hopeless. In case it ever becomes available, I want to know immediately.
``` cron
```
# Check github/ntfy user
*/6 * * * * if curl -s https://api.github.com/users/ntfy | grep "Not Found"; then curl -d "github.com/ntfy is available" -H "Tags: tada" -H "Prio: high" ntfy.sh/my-alerts; fi
```
You can also use [`ntfy-run`](https://github.com/quantum5/ntfy-run) to send the output of your cronjob in the
notification, so that you know exactly why it failed:
```
0 0 * * * ntfy-run -n https://ntfy.sh/backups --success-priority low --failure-tags warning ~/backup-computer
```
## Low disk space alerts
Here's a simple cronjob that I use to alert me when the disk space on the root disk is running low. It's simple, but
@@ -135,28 +141,64 @@ You can send a message during a workflow run with curl. Here is an example sendi
${{ secrets.NTFY_URL }}
```
## Changedetection.io
ntfy is an excellent choice for getting notifications when a website has a change sent to your mobile (or desktop),
[changedetection.io](https://changedetection.io) or on GitHub ([dgtlmoon/changedetection.io](https://github.com/dgtlmoon/changedetection.io))
uses [apprise](https://github.com/caronc/apprise) library for notification integrations.
To add any ntfy(s) notification to a website change simply add the [ntfy style URL](https://github.com/caronc/apprise/wiki/Notify_ntfy)
to the notification list.
For example `ntfy://{topic}` or `ntfy://{user}:{password}@{host}:{port}/{topics}`
In your changedetection.io installation, click `Edit` > `Notifications` on a single website watch (or group) then add
the special ntfy Apprise Notification URL to the Notification List.
![ntfy alerts on website change](static/img/cdio-setup.jpg)
## Watchtower (shoutrrr)
You can use [shoutrrr](https://github.com/containrrr/shoutrrr) generic webhook support to send
You can use [shoutrrr](https://containrrr.dev/shoutrrr/latest/services/ntfy/) to send
[Watchtower](https://github.com/containrrr/watchtower/) notifications to your ntfy topic.
Example docker-compose.yml:
``` yaml
services:
watchtower:
image: containrrr/watchtower
environment:
- WATCHTOWER_NOTIFICATIONS=shoutrrr
- WATCHTOWER_NOTIFICATION_URL=generic+https://ntfy.sh/my_watchtower_topic?title=WatchtowerUpdates
- WATCHTOWER_NOTIFICATION_SKIP_TITLE=True
- WATCHTOWER_NOTIFICATION_URL=ntfy://ntfy.sh/my_watchtower_topic?title=WatchtowerUpdates
```
The environment variable `WATCHTOWER_NOTIFICATION_SKIP_TITLE` is required to prevent Watchtower from [replacing the `title` query parameter](https://containrrr.dev/watchtower/notifications/#settings). If omitted, the provided notification title will not be used.
Or, if you only want to send notifications using shoutrrr:
```
shoutrrr send -u "generic+https://ntfy.sh/my_watchtower_topic?title=WatchtowerUpdates" -m "testMessage"
shoutrrr send -u "ntfy://ntfy.sh/my_watchtower_topic?title=WatchtowerUpdates" -m "testMessage"
```
Authentication tokens are also supported:
- (Recommended) Ntfy url format (replace the domain, topic and token with your own):
```
ntfy://:TOKEN@DOMAIN/TOPIC
```
- Generic webhook and authorization header using this url format (replace the domain, topic and token with your own):
```
generic+https://DOMAIN/TOPIC?@authorization=Bearer+TOKEN`
```
## Sonarr, Radarr, Lidarr, Readarr, Prowlarr, SABnzbd
It's possible to use custom scripts for all the *arr services, plus SABnzbd. Notifications for downloads, warnings, grabs etc.
Some simple bash scripts to achieve this are kindly provided in [nickexyz's repository](https://github.com/nickexyz/ntfy-shellscripts).
<!-- Sonarr v4 is in beta as of May 2023, should be updated to remove v3 reference when stable -->
Radarr, Prowlarr, and Sonarr v4 support ntfy natively under Settings > Connect.
Sonarr v3, Readarr, and SABnzbd support custom scripts for downloads, warnings, grabs, etc.
Some simple bash scripts to achieve this are kindly provided in [nickexyz's ntfy-shellscripts repository](https://github.com/nickexyz/ntfy-shellscripts).
## Node-RED
You can use the HTTP request node to send messages with [Node-RED](https://nodered.org), some examples:
@@ -577,6 +619,8 @@ This will only work on selfhosted [traccar](https://www.traccar.org/) ([Github](
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.
**Info:** Add a phone number to your traccar account not in device, as otherwise it will not try to send SMS.
**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>
@@ -596,3 +640,56 @@ or by simply providing traccar with a valid username/password combination.
<entry key='sms.http.user'>phil</entry>
<entry key='sms.http.password'>mypass</entry>
```
## Terminal Notifications for Long-Running Commands
This example provides a simple way to send notifications using [ntfy.sh](https://ntfy.sh) when a terminal command completes. It includes success or failure indicators based on the command's exit status.
Store your ntfy.sh bearer token securely if access control is enabled:
```sh
echo "your_bearer_token_here" > ~/.ntfy_token
chmod 600 ~/.ntfy_token
```
Add the following function and alias to your `.bashrc` or `.bash_profile`:
```sh
# Function for alert notifications using ntfy.sh
notify_via_ntfy() {
local exit_status=$? # Capture the exit status before doing anything else
local token=$(< ~/.ntfy_token) # Securely read the token
local status_icon="$([ $exit_status -eq 0 ] && echo magic_wand || echo warning)"
local last_command=$(history | tail -n1 | sed -e 's/^[[:space:]]*[0-9]\{1,\}[[:space:]]*//' -e 's/[;&|][[:space:]]*alert$//')
curl -s -X POST "https://n.example.dev/alerts" \
-H "Authorization: Bearer $token" \
-H "Title: Terminal" \
-H "X-Priority: 3" \
-H "Tags: $status_icon" \
-d "Command: $last_command (Exit: $exit_status)"
echo "Tags: $status_icon"
echo "$last_command (Exit: $exit_status)"
}
# Add an "alert" alias for long running commands using ntfy.sh
alias alert='notify_via_ntfy'
```
Now you can run any long-running command and append `alert` to notify when it completes:
```sh
sleep 10; alert
```
![ntfy notifications on mobile device](static/img/mobile-screenshot-notification.png)
**Notification Sent** with a success 🪄 (`magic_wand`) or failure ⚠️ (`warning`) tag.
To test failure notifications:
```sh
false; alert # Always fails (exit 1)
ls --invalid; alert # Invalid option
cat nonexistent_file; alert # File not found
```

View File

@@ -76,7 +76,29 @@ However, if you still want to disable it, you can do so with the `web-root: disa
Think of the ntfy web app like an Android/iOS app. It is freely available and accessible to anyone, yet useless without
a proper backend. So as long as you secure your backend with ACLs, exposing the ntfy web app to the Internet is harmless.
## If topic names are public, could I not just brute force them?
If you don't have [ACLs set up](config.md#access-control), the topic name is your password, it says so everywhere. If you
choose a easy-to-guess/dumb topic name, people will be able to guess it. If you choose a randomly generated topic name,
the topic is as good as a good password.
As for brute forcing: It's not possible to brute force a ntfy server for very long, as you'll get quickly rate limited.
In the default configuration, you'll be able to do 60 requests as a burst, and then 1 request per 10 seconds. Assuming you
choose a random 10 digit topic name using only A-Z, a-z, 0-9, _ and -, there are 64^10 possible topic names. Even if you
could do hundreds of requests per seconds (which you cannot), it would take many years to brute force a topic name.
For ntfy.sh, there's even a fail2ban in place which will ban your IP pretty quickly.
## Where can I donate?
I have just very recently started accepting donations via [GitHub Sponsors](https://github.com/sponsors/binwiederhier).
I would be humbled if you helped me carry the server and developer account costs. Even small donations are very much
appreciated.
## Can I email you? Can I DM you on Discord/Matrix?
For community support, please use the public channels listed on the [contact page](contact.md). I generally
**do not respond to direct messages** about ntfy, unless you are paying for a [ntfy Pro](https://ntfy.sh/#pricing)
plan (see [paid support](contact.md#paid-support)), or you are inquiring about business
opportunities (see [other inquiries](contact.md#other-inquiries)).
I am sorry, but answering individual questions about ntfy on a 1-on-1 basis is not scalable. Answering your questions
in public forums benefits others, since I can link to the discussion at a later point in time, or other users
may be able to help out. I hope you understand.

View File

@@ -1,6 +1,7 @@
import os
import shutil
def copy_fonts(config, **kwargs):
site_dir = config['site_dir']
shutil.copytree('docs/static/fonts', os.path.join(site_dir, 'get'))
def on_post_build(config, **kwargs):
site_dir = config["site_dir"]
shutil.copytree("docs/static/fonts", os.path.join(site_dir, "get"))

View File

@@ -3,11 +3,11 @@ ntfy lets you **send push notifications to your phone or desktop via scripts fro
or POST requests. I use it to notify myself when scripts fail, or long-running commands complete.
## Step 1: Get the app
<a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy"><img src="../../static/img/badge-googleplay.png"></a>
<a href="https://f-droid.org/en/packages/io.heckel.ntfy/"><img src="../../static/img/badge-fdroid.png"></a>
<a href="https://apps.apple.com/us/app/ntfy/id1625396347"><img src="../../static/img/badge-appstore.png"></a>
<a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy"><img width="170" src="static/img/badge-googleplay.png"></a>
<a href="https://f-droid.org/en/packages/io.heckel.ntfy/"><img width="170" src="static/img/badge-fdroid.png"></a>
<a href="https://apps.apple.com/us/app/ntfy/id1625396347"><img width="150" src="static/img/badge-appstore.png"></a>
To [receive notifications on your phone](subscribe/phone.md), install the app, either via Google Play or F-Droid.
To [receive notifications on your phone](subscribe/phone.md), install the app, either via Google Play, App Store or F-Droid.
Once installed, open it and subscribe to a topic of your choosing. Topics don't have to explicitly be created, so just
pick a name and use it later when you [publish a message](publish.md). Note that **topic names are public, so it's wise
to choose something that cannot be guessed easily.**

View File

@@ -14,62 +14,72 @@ We support amd64, armv7 and arm64.
1. Install ntfy using one of the methods described below
2. Then (optionally) edit `/etc/ntfy/server.yml` for the server (Linux only, see [configuration](config.md) or [sample server.yml](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml))
3. Or (optionally) create/edit `~/.config/ntfy/client.yml` (for the non-root user) or `/etc/ntfy/client.yml` (for the root user), see [sample client.yml](https://github.com/binwiederhier/ntfy/blob/main/client/client.yml))
3. Or (optionally) create/edit `~/.config/ntfy/client.yml` (for the non-root user), `~/Library/Application Support/ntfy/client.yml` (for the macOS non-root user), or `/etc/ntfy/client.yml` (for the root user), see [sample client.yml](https://github.com/binwiederhier/ntfy/blob/main/client/client.yml))
To run the ntfy server, then just run `ntfy serve` (or `systemctl start ntfy` when using the deb/rpm).
To send messages, use `ntfy publish`. To subscribe to topics, use `ntfy subscribe` (see [subscribing via CLI](subscribe/cli.md)
for details).
If you like tutorials, check out :simple-youtube: [Kris Occhipinti's ntfy install guide](https://www.youtube.com/watch?v=bZzqrX05mNU) on YouTube, or
[Alex's Docker-based setup guide](https://blog.alexsguardian.net/posts/2023/09/12/selfhosting-ntfy/). Both are great
resources to get started. _I am not affiliated with Kris or Alex, I just liked their video/post._
## Linux binaries
Please check out the [releases page](https://github.com/binwiederhier/ntfy/releases) for binaries and
deb/rpm packages.
=== "x86_64/amd64"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_x86_64.tar.gz
tar zxvf ntfy_2.3.1_linux_x86_64.tar.gz
sudo cp -a ntfy_2.3.1_linux_x86_64/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.3.1_linux_x86_64/{client,server}/*.yml /etc/ntfy
wget https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_linux_amd64.tar.gz
tar zxvf ntfy_2.15.0_linux_amd64.tar.gz
sudo cp -a ntfy_2.15.0_linux_amd64/ntfy /usr/local/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.15.0_linux_amd64/{client,server}/*.yml /etc/ntfy
sudo ntfy serve
```
=== "armv6"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_armv6.tar.gz
tar zxvf ntfy_2.3.1_linux_armv6.tar.gz
sudo cp -a ntfy_2.3.1_linux_armv6/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.3.1_linux_armv6/{client,server}/*.yml /etc/ntfy
wget https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_linux_armv6.tar.gz
tar zxvf ntfy_2.15.0_linux_armv6.tar.gz
sudo cp -a ntfy_2.15.0_linux_armv6/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.15.0_linux_armv6/{client,server}/*.yml /etc/ntfy
sudo ntfy serve
```
=== "armv7/armhf"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_armv7.tar.gz
tar zxvf ntfy_2.3.1_linux_armv7.tar.gz
sudo cp -a ntfy_2.3.1_linux_armv7/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.3.1_linux_armv7/{client,server}/*.yml /etc/ntfy
wget https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_linux_armv7.tar.gz
tar zxvf ntfy_2.15.0_linux_armv7.tar.gz
sudo cp -a ntfy_2.15.0_linux_armv7/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.15.0_linux_armv7/{client,server}/*.yml /etc/ntfy
sudo ntfy serve
```
=== "arm64"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_arm64.tar.gz
tar zxvf ntfy_2.3.1_linux_arm64.tar.gz
sudo cp -a ntfy_2.3.1_linux_arm64/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.3.1_linux_arm64/{client,server}/*.yml /etc/ntfy
wget https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_linux_arm64.tar.gz
tar zxvf ntfy_2.15.0_linux_arm64.tar.gz
sudo cp -a ntfy_2.15.0_linux_arm64/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_2.15.0_linux_arm64/{client,server}/*.yml /etc/ntfy
sudo ntfy serve
```
## Debian/Ubuntu repository
Installation via Debian repository:
!!! info
As of September 2025, **the official ntfy.sh Debian/Ubuntu repository has moved to [archive.ntfy.sh](https://archive.ntfy.sh/apt)**.
The old repository [archive.heckel.io](https://archive.heckel.io/apt) is still available for now, but will likely
go away soon. I suspect I will phase it out some time in early 2026.
Installation via Debian/Ubuntu repository (fingerprint `55BA 774A 6F5E E674 31E4 6B7C CFDB 962D 4F1E C4AF`):
=== "x86_64/amd64"
```bash
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg
sudo curl -L -o /etc/apt/keyrings/ntfy.gpg https://archive.ntfy.sh/apt/keyring.gpg
sudo apt install apt-transport-https
sudo sh -c "echo 'deb [arch=amd64 signed-by=/etc/apt/keyrings/archive.heckel.io.gpg] https://archive.heckel.io/apt debian main' \
> /etc/apt/sources.list.d/archive.heckel.io.list"
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/ntfy.gpg] https://archive.ntfy.sh/apt stable main" \
| sudo tee /etc/apt/sources.list.d/ntfy.list
sudo apt update
sudo apt install ntfy
sudo systemctl enable ntfy
@@ -79,10 +89,10 @@ Installation via Debian repository:
=== "armv7/armhf"
```bash
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg
sudo curl -L -o /etc/apt/keyrings/ntfy.gpg https://archive.ntfy.sh/apt/keyring.gpg
sudo apt install apt-transport-https
sudo sh -c "echo 'deb [arch=armhf signed-by=/etc/apt/keyrings/archive.heckel.io.gpg] https://archive.heckel.io/apt debian main' \
> /etc/apt/sources.list.d/archive.heckel.io.list"
echo "deb [arch=armhf signed-by=/etc/apt/keyrings/ntfy.gpg] https://archive.ntfy.sh/apt stable main" \
| sudo tee /etc/apt/sources.list.d/ntfy.list
sudo apt update
sudo apt install ntfy
sudo systemctl enable ntfy
@@ -92,10 +102,10 @@ Installation via Debian repository:
=== "arm64"
```bash
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg
sudo curl -L -o /etc/apt/keyrings/ntfy.gpg https://archive.ntfy.sh/apt/keyring.gpg
sudo apt install apt-transport-https
sudo sh -c "echo 'deb [arch=arm64 signed-by=/etc/apt/keyrings/archive.heckel.io.gpg] https://archive.heckel.io/apt debian main' \
> /etc/apt/sources.list.d/archive.heckel.io.list"
echo "deb [arch=arm64 signed-by=/etc/apt/keyrings/ntfy.gpg] https://archive.ntfy.sh/apt stable main" \
| sudo tee /etc/apt/sources.list.d/ntfy.list
sudo apt update
sudo apt install ntfy
sudo systemctl enable ntfy
@@ -106,7 +116,7 @@ Manually installing the .deb file:
=== "x86_64/amd64"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_amd64.deb
wget https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_linux_amd64.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
@@ -114,7 +124,7 @@ Manually installing the .deb file:
=== "armv6"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_armv6.deb
wget https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_linux_armv6.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
@@ -122,7 +132,7 @@ Manually installing the .deb file:
=== "armv7/armhf"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_armv7.deb
wget https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_linux_armv7.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
@@ -130,7 +140,7 @@ Manually installing the .deb file:
=== "arm64"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_arm64.deb
wget https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_linux_arm64.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
@@ -140,34 +150,36 @@ Manually installing the .deb file:
=== "x86_64/amd64"
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_amd64.rpm
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_linux_amd64.rpm
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "armv6"
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_armv6.rpm
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_linux_armv6.rpm
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "armv7/armhf"
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_armv7.rpm
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_linux_armv7.rpm
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "arm64"
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_linux_arm64.rpm
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_linux_arm64.rpm
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
## Arch Linux
ntfy can be installed using an [AUR package](https://aur.archlinux.org/packages/ntfysh-bin/). You can use an [AUR helper](https://wiki.archlinux.org/title/AUR_helpers) like `paru`, `yay` or others to download, build and install ntfy and keep it up to date.
ntfy can be installed using an [AUR package](https://aur.archlinux.org/packages/ntfysh-bin/).
You can use an [AUR helper](https://wiki.archlinux.org/title/AUR_helpers) like `paru`, `yay` or others to download,
build and install ntfy and keep it up to date.
```
paru -S ntfysh-bin
```
@@ -189,18 +201,18 @@ NixOS also supports [declarative setup of the ntfy server](https://search.nixos.
## macOS
The [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) is supported on macOS as well.
To install, please [download the tarball](https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_macOS_all.tar.gz),
To install, please [download the tarball](https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_darwin_all.tar.gz),
extract it and place it somewhere in your `PATH` (e.g. `/usr/local/bin/ntfy`).
If run as `root`, ntfy will look for its config at `/etc/ntfy/client.yml`. For all other users, it'll look for it at
`~/Library/Application Support/ntfy/client.yml` (sample included in the tarball).
```bash
curl -L https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_macOS_all.tar.gz > ntfy_2.3.1_macOS_all.tar.gz
tar zxvf ntfy_2.3.1_macOS_all.tar.gz
sudo cp -a ntfy_2.3.1_macOS_all/ntfy /usr/local/bin/ntfy
curl -L https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_darwin_all.tar.gz > ntfy_2.15.0_darwin_all.tar.gz
tar zxvf ntfy_2.15.0_darwin_all.tar.gz
sudo cp -a ntfy_2.15.0_darwin_all/ntfy /usr/local/bin/ntfy
mkdir ~/Library/Application\ Support/ntfy
cp ntfy_2.3.1_macOS_all/client/client.yml ~/Library/Application\ Support/ntfy/client.yml
cp ntfy_2.15.0_darwin_all/client/client.yml ~/Library/Application\ Support/ntfy/client.yml
ntfy --help
```
@@ -215,10 +227,9 @@ simply run:
brew install ntfy
```
## Windows
The [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) is supported on Windows as well.
To install, please [download the latest ZIP](https://github.com/binwiederhier/ntfy/releases/download/v2.3.1/ntfy_2.3.1_windows_x86_64.zip),
To install, please [download the latest ZIP](https://github.com/binwiederhier/ntfy/releases/download/v2.15.0/ntfy_2.15.0_windows_amd64.zip),
extract it and place the `ntfy.exe` binary somewhere in your `%Path%`.
The default path for the client config file is at `%AppData%\ntfy\client.yml` (not created automatically, sample in the ZIP file).
@@ -274,8 +285,6 @@ docker run \
Using docker-compose with non-root user and healthchecks enabled:
```yaml
version: "2.1"
services:
ntfy:
image: binwiederhier/ntfy
@@ -297,6 +306,7 @@ services:
retries: 3
start_period: 40s
restart: unless-stopped
init: true # needed, if healthcheck is used. Prevents zombie processes
```
If using a non-root user when running the docker version, be sure to chown the server.yml, user.db, and cache.db files and attachments directory to the same uid/gid.
@@ -315,7 +325,6 @@ The setup for Kubernetes is very similar to that for Docker, and requires a fair
are a few options to mix and match, including a deployment without a cache file, a stateful set with a persistent cache, and a standalone
unmanned pod.
=== "deployment"
```yaml
apiVersion: apps/v1
@@ -534,7 +543,7 @@ kubectl apply -k /ntfy
cpu: 150m
memory: 150Mi
volumeMounts:
- mountPath: /etc/ntfy/server.yml
- mountPath: /etc/ntfy
subPath: server.yml
name: config-volume # generated vie configMapGenerator from kustomization file
- mountPath: /var/cache/ntfy

View File

@@ -4,26 +4,21 @@ There are quite a few projects that work with ntfy, integrate ntfy, or have been
I've added a ⭐ to projects or posts that have a significant following, or had a lot of interaction by the community.
## Public ntfy servers
## Table of Contents
Here's a list of public ntfy servers. As of right now, there is only one official server. The others are provided by the
ntfy community. Thanks to everyone running a public server. **You guys rock!**
| URL | Country |
|---------------------------------------------------|--------------------|
| [ntfy.sh](https://ntfy.sh/) (*Official*) | 🇺🇸 United States |
| [ntfy.tedomum.net](https://ntfy.tedomum.net/) | 🇫🇷 France |
| [ntfy.jae.fi](https://ntfy.jae.fi/) | 🇫🇮 Finland |
| [ntfy.adminforge.de](https://ntfy.adminforge.de/) | 🇩🇪 Germany |
| [ntfy.envs.net](https://ntfy.envs.net) | 🇩🇪 Germany |
| [ntfy.mzte.de](https://ntfy.mzte.de/) | 🇩🇪 Germany |
| [ntfy.hostux.net](https://ntfy.hostux.net/) | 🇫🇷 France |
Please be aware that **server operators can log your messages**. The project also cannot guarantee the reliability
and uptime of third party servers, so use of each server is **at your own discretion**.
- [Official integrations](#official-integrations)
- [Integration via HTTP/SMTP/etc.](#integration-via-httpsmtpetc)
- [UnifiedPush integrations](#unifiedpush-integrations)
- [Libraries](#libraries)
- [CLIs + GUIs](#clis-guis)
- [Projects + scripts](#projects-scripts)
- [Blog + forum posts](#blog-forum-posts)
- [Alternative ntfy servers](#alternative-ntfy-servers)
## Official integrations
- [changedetection.io](https://changedetection.io) ⭐ - Website change detection and notification
- [Home Assistant](https://www.home-assistant.io/integrations/ntfy) ⭐ - Home Assistant is an open-source platform for automating and controlling smart home devices.
- [Healthchecks.io](https://healthchecks.io/) ⭐ - Online service for monitoring regularly running tasks such as cron jobs
- [Apprise](https://github.com/caronc/apprise/wiki/Notify_ntfy) ⭐ - Push notifications that work with just about every platform
- [Uptime Kuma](https://uptime.kuma.pet/) ⭐ - A self-hosted monitoring tool
@@ -34,13 +29,31 @@ and uptime of third party servers, so use of each server is **at your own discre
- [Gatus](https://gatus.io/) ⭐ - Automated service health dashboard
- [Automatisch](https://automatisch.io/) ⭐ - Open source Zapier alternative / workflow automation tool
- [FlexGet](https://flexget.com/Plugins/Notifiers/ntfysh) ⭐ - Multipurpose automation tool for all of your media
- [Shoutrrr](https://containrrr.dev/shoutrrr/v0.7/services/ntfy/) ⭐ - Notification library for gophers and their furry friends.
- [Shoutrrr](https://containrrr.dev/shoutrrr/v0.8/services/ntfy/) ⭐ - Notification library for gophers and their furry friends.
- [Netdata](https://learn.netdata.cloud/docs/alerts-and-notifications/notifications/agent-alert-notifications/ntfy) ⭐ - Real-time performance monitoring
- [Deployer](https://github.com/deployphp/deployer) ⭐ - PHP deployment tool
- [Scrt.link](https://scrt.link/) - Share a secret
- [Platypush](https://docs.platypush.tech/platypush/plugins/ntfy.html) - Automation platform aimed to run on any device that can run Python
- [diun](https://crazymax.dev/diun/) - Docker Image Update Notifier
- [Cloudron](https://www.cloudron.io/store/sh.ntfy.cloudronapp.html) - Platform that makes it easy to manage web apps on your server
- [Xitoring](https://xitoring.com/docs/notifications/notification-roles/ntfy/) - Server and Uptime monitoring
- [HetrixTools](https://docs.hetrixtools.com/ntfy-sh-notifications/) - Uptime monitoring
- [EasyMorph](https://help.easymorph.com/doku.php?id=transformations:sendntfymessage) - Visual data transformation and automation tool
- [Monibot](https://monibot.io/) - Monibot monitors your websites, servers and applications and notifies you if something goes wrong.
- [Miniflux](https://miniflux.app/docs/ntfy.html) - Minimalist and opinionated feed reader
- [Beszel](https://beszel.dev/guide/notifications/ntfy) - Server monitoring platform
- [Simple Observability](https://simpleobservability.com/docs/alerts/ntfy) - Server monitoring and observability platform
## Integration via HTTP/SMTP/etc.
- [Watchtower](https://containrrr.dev/watchtower/) ⭐ - Automating Docker container base image updates (see [integration example](examples.md#watchtower-shoutrrr))
- [Jellyfin](https://jellyfin.org/) ⭐ - The Free Software Media System (see [integration example](examples.md#))
- [Overseerr](https://docs.overseerr.dev/using-overseerr/notifications/webhooks) ⭐ - a request management and media discovery tool for Plex (see [integration example](examples.md#jellyseerroverseerr-webhook))
- [Tautulli](https://github.com/Tautulli/Tautulli) ⭐ - Monitoring and tracking tool for Plex (integration [via webhook](https://github.com/Tautulli/Tautulli/wiki/Notification-Agents-Guide#webhook))
- [Mailrise](https://github.com/YoRyan/mailrise) - An SMTP gateway (integration via [Apprise](https://github.com/caronc/apprise/wiki/Notify_ntfy))
- [Proxmox-Ntfy](https://github.com/qtsone/proxmox-ntfy) - Python script that monitors Proxmox tasks and sends notifications using the Ntfy service.
- [Scrutiny](https://github.com/AnalogJ/scrutiny) - WebUI for smartd S.M.A.R.T monitoring. Scrutiny includes shoutrrr/ntfy integration ([see integration README](https://github.com/AnalogJ/scrutiny?tab=readme-ov-file#notifications))
- [UptimeObserver](https://uptimeobserver.com) - Uptime Monitoring tool for Websites, APIs, SSL Certificates, DNS, Domain Names and Ports. [Integration Guide](https://support.uptimeobserver.com/integrations/ntfy/)
## [UnifiedPush](https://unifiedpush.org/users/apps/) integrations
@@ -65,16 +78,26 @@ and uptime of third party servers, so use of each server is **at your own discre
- [ntfy-for-delphi](https://github.com/hazzelnuts/ntfy-for-delphi) - A friendly library to push instant notifications ntfy (Delphi)
- [ntfy](https://github.com/ffflorian/ntfy) - Send notifications over ntfy (JS)
- [ntfy_dart](https://github.com/jr1221/ntfy_dart) - Dart wrapper around the ntfy API (Dart)
- [gotfy](https://github.com/AnthonyHewins/gotfy) - A Go wrapper for the ntfy API (Go)
- [symfony/ntfy-notifier](https://symfony.com/components/NtfyNotifier) ⭐ - Symfony Notifier integration for ntfy (PHP)
- [ntfy-java](https://github.com/MaheshBabu11/ntfy-java/) - A Java package to interact with a ntfy server (Java)
- [aiontfy](https://github.com/tr4nt0r/aiontfy) - Asynchronous client library for publishing and subscribing to ntfy (Python)
## CLIs + GUIs
- [ntfy.sh.sh](https://github.com/mininmobile/ntfy.sh.sh) - Run scripts on ntfy.sh events
- [ntfy Desktop client](https://codeberg.org/zvava/ntfy-desktop) - Cross-platform desktop application for ntfy
- [ntfy-desktop](https://codeberg.org/zvava/ntfy-desktop) - Cross-platform desktop application for ntfy
- [ntfy-desktop](https://github.com/Aetherinox/ntfy-desktop) - Desktop client for Windows, Linux, and MacOS with push notifications
- [ntfy svelte front-end](https://github.com/novatorem/Ntfy) - Front-end built with svelte
- [wio-ntfy-ticker](https://github.com/nachotp/wio-ntfy-ticker) - Ticker display for a ntfy.sh topic
- [ntfysh-windows](https://github.com/lucas-bortoli/ntfysh-windows) - A ntfy client for Windows Desktop
- [ntfysh-windows](https://github.com/mshafer1/ntfysh-windows) - A ntfy client for Windows Desktop
- [ntfyr](https://github.com/haxwithaxe/ntfyr) - A simple commandline tool to send notifications to ntfy
- [ntfy.py](https://github.com/ioqy/ntfy-client-python) - ntfy.py is a simple nfty.sh client for sending notifications
- [wlzntfy](https://github.com/Walzen-Group/ntfy-toaster) - A minimalistic, receive-only toast notification client for Windows 11
- [Ntfy_CSV_Reminders](https://github.com/thiswillbeyourgithub/Ntfy_CSV_Reminders) - A Python tool that sends random-timing phone notifications for recurring tasks by using daily probability checks based on CSV-defined frequencies.
- [Daily Fact Ntfy](https://github.com/thiswillbeyourgithub/Daily_Fact_Ntfy) - Generate [llm](https://github.com/simonw/llm) generated fact every day about any topic you're interested in.
- [ntfyexec](https://github.com/alecthomas/ntfyexec) - Send a notification through ntfy.sh if a command fails
- [Ntfy Desktop](https://github.com/emmaexe/ntfyDesktop) - Fully featured desktop client for Linux, built with Qt and C++.
## Projects + scripts
@@ -83,12 +106,12 @@ and uptime of third party servers, so use of each server is **at your own discre
- [Grafana-to-ntfy](https://gitlab.com/Saibe1111/grafana-to-ntfy) - Grafana-to-ntfy alerts channel (Node Js)
- [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)
- [alertmanager-ntfy-relay](https://github.com/therobbielee/alertmanager-ntfy-relay) - ntfy.sh relay for Alertmanager (Go)
- [QuickStatus](https://github.com/corneliusroot/QuickStatus) - A shell script to alert to any immediate problems upon login (Shell)
- [ntfy.el](https://github.com/shombando/ntfy) - Send notifications from Emacs (Emacs)
- [backup-projects](https://gist.github.com/anthonyaxenov/826ba65abbabd5b00196bc3e6af76002) - Stupidly simple backup script for own projects (Shell)
- [grav-plugin-whistleblower](https://github.com/Himmlisch-Studios/grav-plugin-whistleblower) - Grav CMS plugin to get notifications via ntfy (PHP)
- [ntfy-server-status](https://github.com/filip2cz/ntfy-server-status) - Checking if server is online and reporting through ntfy (C)
- [borg-based backup](https://github.com/davidhi7/backup) - Simple borg-based backup script with notifications based on ntfy.sh or Discord webhooks (Python/Shell)
- [ntfy.sh *arr script](https://github.com/agent-squirrel/nfty-arr-script) - Quick and hacky script to get sonarr/radarr to notify the ntfy.sh service (Shell)
- [website-watcher](https://github.com/muety/website-watcher) - A small tool to watch websites for changes (with XPath support) (Python)
- [siteeagle](https://github.com/tpanum/siteeagle) - A small Python script to monitor websites and notify changes (Python)
@@ -114,6 +137,7 @@ and uptime of third party servers, so use of each server is **at your own discre
- [ntfy_on_a_chip](https://github.com/gergepalfi/ntfy_on_a_chip) - ESP8266 and ESP32 client code to communicate with ntfy
- [ntfy-sdk](https://github.com/yukibtc/ntfy-sdk) - ntfy client library to send notifications (Rust)
- [ntfy_ynh](https://github.com/YunoHost-Apps/ntfy_ynh) - ntfy app for YunoHost
- [woodpecker-ntfy](https://codeberg.org/l-x/woodpecker-ntfy)- Woodpecker CI plugin for sending ntfy notfication from a pipeline (Go)
- [drone-ntfy](https://github.com/Clortox/drone-ntfy) - Drone.io plugin for sending ntfy notifications from a pipeline (Shell)
- [ignition-ntfy-module](https://github.com/Kyvis-Labs/ignition-ntfy-module) - Adds support for sending notifications via a ntfy server to Ignition (Java)
- [maubot-ntfy](https://gitlab.com/999eagle/maubot-ntfy) - Matrix bot to subscribe to ntfy topics and send messages to Matrix (Python)
@@ -128,9 +152,85 @@ and uptime of third party servers, so use of each server is **at your own discre
- [notify](https://github.com/guanguans/notify) - 推送通知 (PHP)
- [zpool-events](https://github.com/maglar0/zpool-events) - Notify on ZFS pool events (Python)
- [ntfyd](https://github.com/joachimschmidt557/ntfyd) - ntfy desktop daemon (Zig)
- [ntfy-browser](https://github.com/johman10/ntfy-browser) - browser extension to receive notifications without having the page open (TypeScript)
- [ntfy-electron](https://github.com/xdpirate/ntfy-electron) - Electron wrapper for the ntfy web app (JS)
- [systemd-ntfy-poweronoff](https://github.com/stendler/systemd-ntfy-poweronoff) - Systemd services to send notifications on system startup, shutdown and service failure
- [msgdrop](https://github.com/jbrubake/msgdrop) - Send and receive encrypted messages (Bash)
- [vigilant](https://github.com/VerifiedJoseph/vigilant) - Monitor RSS/ATOM and JSON feeds, and send push notifications on new entries (PHP)
- [ansible-role-ntfy-alertmanager](https://github.com/bleetube/ansible-role-ntfy-alertmanager) - Ansible role to install xenrox/ntfy-alertmanager
- [NtfyMe-Blender](https://github.com/NotNanook/NtfyMe-Blender) - Blender addon to send notifications to NtfyMe (Python)
- [ntfy-ios-url-share](https://www.icloud.com/shortcuts/be8a7f49530c45f79733cfe3e41887e6) - An iOS shortcut that lets you share URLs easily and quickly.
- [ntfy-ios-filesharing](https://www.icloud.com/shortcuts/fe948d151b2e4ae08fb2f9d6b27d680b) - An iOS shortcut that lets you share files from your share feed to a topic of your choice.
- [systemd-ntfy](https://hackage.haskell.org/package/systemd-ntfy) - monitor a set of systemd services an send a notification to ntfy.sh whenever their status changes
- [RouterOS Scripts](https://git.eworm.de/cgit/routeros-scripts/about/) - a collection of scripts for MikroTik RouterOS
- [ntfy-android-builder](https://github.com/TheBlusky/ntfy-android-builder) - Script for building ntfy-android with custom Firebase configuration (Docker/Shell)
- [jetspotter](https://github.com/vvanouytsel/jetspotter) - send notifications when planes are spotted near you (Go)
- [monitoring_ntfy](https://www.drupal.org/project/monitoring_ntfy) - Drupal monitoring Ntfy.sh integration (PHP/Drupal)
- [Notify](https://flathub.org/apps/com.ranfdev.Notify) - Native GTK4 client for ntfy (Rust)
- [notify-via-ntfy](https://exchange.checkmk.com/p/notify-via-ntfy) - Checkmk plugin to send notifications via ntfy (Python)
- [ntfy-java](https://github.com/MaheshBabu11/ntfy-java/) - A Java package to interact with a ntfy server (Java)
- [container-update-check](https://github.com/stendler/container-update-check) - Scripts to check and notify if a podman or docker container image can be updated (Podman/Shell)
- [ignition-combustion-template](https://github.com/stendler/ignition-combustion-template) - Templates and scripts to generate a configuration to automatically setup a system on first boot. Including systemd-ntfy-poweronoff (Shell)
- [ntfy-run](https://github.com/quantum5/ntfy-run) - Tool to run a command, capture its output, and send it to ntfy (Rust)
- [Clipboard IO](https://github.com/jim3692/clipboard-io) - End to end encrypted clipboard
- [ntfy-me-mcp](https://github.com/gitmotion/ntfy-me-mcp) - An ntfy MCP server for sending/fetching ntfy notifications to your self-hosted ntfy server from AI Agents (supports secure token auth & more - use with npx or docker!) (Node/Typescript)
- [InvaderInformant](https://github.com/patricksthannon/InvaderInformant) - Script for Mac OS systems that monitors new or dropped connections to your network using ntfy (Shell)
- [NtfyPwsh](https://github.com/ptmorris1/NtfyPwsh) - PowerShell module to help send messages to ntfy (PowerShell)
- [ntfyrr](https://github.com/leukosaima/ntfyrr) - Overseerr and Maintainerr webhook notification to ntfy helper service (C#)
- [ntfy for Sandstorm](https://apps.sandstorm.io/app/c6rk81r4qk6dm3k04x1kxmyccqewhh4npuxeyg1xrpfypn2ddy0h) - ntfy app for the Sandstorm platform
- [ntfy-heartbeat-monitor](https://codeberg.org/RockWolf/ntfy-heartbeat-monitor) - Application for implementing heartbeat monitoring/alerting by utilizing ntfy
- [ntfy-bridge](https://github.com/AlexGaudon/ntfy-bridge) - An application to bridge Discord messages (or webhooks) to ntfy.
- [ntailfy](https://github.com/leukosaima/ntailfy) - ntfy notifications when Tailscale devices connect/disconnect (Go)
- [BRun](https://github.com/cbrake/brun) - Native Linux automation platform connecting triggers to actions without containers (Go)
## Blog + forum posts
- [Device notifications via HTTP with ntfy](https://alistairshepherd.uk/writing/ntfy/) - alistairshepherd.uk - 6/2025
- [Notifications about (almost) anything with ntfy.sh](https://hamatti.org/posts/notifications-about-almost-anything-with-ntfy-sh/) - hamatti.org - 6/2025
- [I set up a self-hosted notification service for everything, and I'll never look back](https://www.xda-developers.com/set-up-self-hosted-notification-service/) ⭐ - xda-developers.com - 5/2025
- [How to Set Up Ntfy: Self-Hosted Push Notifications Made Easy](https://www.youtube.com/watch?v=wDJDiAYZ3H0) - youtube.com (sass drew) - 1/2025
- [The NTFY is a game-changer FREE solution for IT people](https://www.youtube.com/watch?v=NtlztHT-sRw) - youtube.com (Valters Tech Turf) - 1/2025
- [Notify: A Powerful Tool for Real-Time Notifications (ntfy.sh)](https://www.youtube.com/watch?v=XXTTeVfGBz0) - youtube.com (LinuxCloudHacks) - 12/2025
- [Push notifications with ntfy and n8n](https://www.youtube.com/watch?v=DKG1R3xYvwQ) - youtube.com (Oskar) - 10/2024
- [Setup ntfy for selfhosted notifications with Cloudflare Tunnel](https://medium.com/@svenvanginkel/setup-ntfy-for-selfhosted-notifications-with-cloudflare-tunnel-e342f470177d) - medium.com (Sven van Ginkel) - 10/2024
- [Self-Host NTFY - How It Works & Easy Setup Guide](https://www.youtube.com/watch?v=79wHc_jfrJE) ⭐ - youtube.com (Techdox)- 9/2024
- [ntfy / Emacs Lisp](https://speechcode.com/blog/ntfy/) - speechcode.com - 3/2024
- [Boost Your Productivity with ntfy.sh: The Ultimate Notification Tool for Command-Line Users](https://dev.to/archetypal/boost-your-productivity-with-ntfysh-the-ultimate-notification-tool-for-command-line-users-iil) - dev.to - 3/2024
- [Nextcloud Talk (F-Droid version) notifications using ntfy (ntfy.sh)](https://www.youtube.com/watch?v=0a6PpfN5PD8) - youtube.com - 2/2024
- [ZFS and SMART Warnings via Ntfy](https://rair.dev/zfs-smart-ntfy/) - rair.dev - 2/2024
- [Automating Security Camera Notifications With Home Assistant and Ntfy](https://runtimeterror.dev/automating-camera-notifications-home-assistant-ntfy/) ⭐ - runtimeterror.dev - 2/2024
- [Ntfy: self-hosted notification service](https://medium.com/@williamdonze/ntfy-self-hosted-notification-service-0f3eada6e657) ⭐ - williamdonze.medium.com - 1/2024
- [Lets Supercharge Snowflake Alerts with Cool ntfy Open-source Notifications!](https://sarathi-data-ml-cloud.medium.com/lets-supercharge-snowflake-alerts-with-cool-ntfy-open-source-notifications-296da442c331) - sarathi-data-ml-cloud.medium.com - 1/2024
- [Setting up NTFY with Ngnix-Proxy-Manager, authentication and Ansible notifications](https://random-it-blog.de/rocky-linux/setting-up-ntfy-with-ngnix-proxy-manager-authentication-and-ansible-notifications/) - random-it-blog.de - 12/2023
- [Introducing the Monitoring Ntfy.sh Integration Module: Real-time Notifications for Drupal Monitoring](https://cyberschorsch.dev/drupal/introducing-monitoring-ntfysh-integration-module-real-time-notifications-drupal-monitoring) - cyberschorsch.dev - 11/2023
- [How to install Ntfy.sh on CasaOS using BigBearCasaOS](https://www.youtube.com/watch?v=wSWhtSNwTd8) - youtube.com - 10/2023
- [Podman Update Notifications via Ntfy](https://rair.dev/podman-update-notifications-ntfy/) - rair.dev - 9/2023
- [Easy Push Notifications With ntfy.sh](https://runtimeterror.dev/easy-push-notifications-with-ntfy/) ⭐ - runtimeterror.dev - 9/2023
- [Ntfy: Your Ultimate Push Notification Powerhouse!](https://kkamalesh117.medium.com/ntfy-your-ultimate-push-notification-powerhouse-1968c070f1d1) - kkamalesh117.medium.com - 9/2023
- [Installing Self Host NTFY On Linux Using Docker Container](https://www.pinoylinux.org/topicsplus/containers/installing-self-host-ntfy-on-linux-using-docker-container/) - pinoylinux.org - 9/2023
- [Homelab Notifications with ntfy](https://blog.alexsguardian.net/posts/2023/09/12/selfhosting-ntfy/) ⭐ - alexsguardian.net - 9/2023
- [Why NTFY is the Ultimate Push Notification Tool for Your Needs](https://osintph.medium.com/why-ntfy-is-the-ultimate-push-notification-tool-for-your-needs-e767421c84c5) - osintph.medium.com - 9/2023
- [Supercharge Your Alerts: Ntfy — The Ultimate Push Notification Solution](https://medium.com/spring-boot/supercharge-your-alerts-ntfy-the-ultimate-push-notification-solution-a3dda79651fe) - spring-boot.medium.com - 9/2023
- [Deploy Ntfy using Docker](https://www.linkedin.com/pulse/deploy-ntfy-mohamed-sharfy/) - linkedin.com - 9/2023
- [Send Notifications With Ntfy for New WordPress Posts](https://www.activepieces.com/blog/ntfy-notifications-for-wordpress-new-posts) - activepieces.com - 9/2023
- [Get Ntfy Notifications About New Zendesk Ticket](https://www.activepieces.com/blog/ntfy-notifications-about-new-zendesk-tickets) - activepieces.com - 9/2023
- [Set reminder for recurring events using ntfy & Cron](https://www.youtube.com/watch?v=J3O4aQ-EcYk) - youtube.com - 9/2023
- [ntfy - Installation and full configuration setup](https://www.youtube.com/watch?v=QMy14rGmpFI) - youtube.com - 9/2023
- [How to install Ntfy.sh on Portainer / Docker Compose](https://www.youtube.com/watch?v=utD9GNbAwyg) - youtube.com - 9/2023
- [ntfy - Push-Benachrichtigungen // Push Notifications](https://www.youtube.com/watch?v=LE3vRPPqZOU) - youtube.com - 9/2023
- [Podman Update Notifications via Ntfy](https://rair.dev/podman-upadte-notifications-ntfy/) - rair.dev - 9/2023
- [How to Send Alerts From Raspberry Pi Pico W to a Phone or Tablet](https://www.tomshardware.com/how-to/send-alerts-raspberry-pi-pico-w-to-mobile-device) - tomshardware.com - 8/2023
- [NetworkChunk - how did I NOT know about this?](https://www.youtube.com/watch?v=poDIT2ruQ9M) ⭐ - youtube.com - 8/2023
- [NTFY - Command-Line Notifications](https://academy.networkchuck.com/blog/ntfy/) - academy.networkchuck.com - 8/2023
- [Open Source Push Notifications! Get notified of any event you can imagine. Triggers abound!](https://www.youtube.com/watch?v=WJgwWXt79pE) ⭐ - youtube.com - 8/2023
- [How to install and self host an Ntfy server on Linux](https://linuxconfig.org/how-to-install-and-self-host-an-ntfy-server-on-linux) - linuxconfig.org - 7/2023
- [Basic website monitoring using cronjobs and ntfy.sh](https://burkhardt.dev/2023/website-monitoring-cron-ntfy/) - burkhardt.dev - 6/2023
- [Pingdom alternative in one line of curl through ntfy.sh](https://piqoni.bearblog.dev/uptime-monitoring-in-one-line-of-curl/) - bearblog.dev - 6/2023
- [#OpenSourceDiscovery 78: ntfy.sh](https://opensourcedisc.substack.com/p/opensourcediscovery-78-ntfysh) - opensourcedisc.substack.com - 6/2023
- [ntfy: des notifications instantanées](https://blogmotion.fr/diy/ntfy-notification-push-domotique-20708) - blogmotion.fr - 5/2023
- [桌面通知ntfy](https://www.cnblogs.com/xueweihan/archive/2023/05/04/17370060.html) - cnblogs.com - 5/2023
- [ntfy.sh - Open source push notifications via PUT/POST](https://lobste.rs/s/5drapz/ntfy_sh_open_source_push_notifications) - lobste.rs - 5/2023
- [Install ntfy Inside Docker Container in Linux](https://lindevs.com/install-ntfy-inside-docker-container-in-linux) - lindevs.com - 4/2023
- [ntfy.sh](https://neo-sahara.com/wp/2023/03/25/ntfy-sh/) - neo-sahara.com - 3/2023
- [Using Ntfy to send and receive push notifications - Samuel Rosa de Oliveria - Delphicon 2023](https://www.youtube.com/watch?v=feu0skpI9QI) - youtube.com - 3/2023
- [ntfy: własny darmowy system powiadomień](https://sprawdzone.it/ntfy-wlasny-darmowy-system-powiadomien/) - sprawdzone.it - 3/2023
@@ -150,6 +250,7 @@ and uptime of third party servers, so use of each server is **at your own discre
- [NTFY - système de notification hyper simple et complet](https://www.youtube.com/watch?v=UieZYWVVgA4) - youtube.com - 12/2022
- [ntfy.sh](https://paramdeo.com/til/ntfy-sh) - paramdeo.com - 11/2022
- [Using ntfy to warn me when my computer is discharging](https://ulysseszh.github.io/programming/2022/11/28/ntfy-warn-discharge.html) - ulysseszh.github.io - 11/2022
- [Enabling SSH Login Notifications using Ntfy](https://paramdeo.com/blog/enabling-ssh-login-notifications-using-ntfy) - paramdeo.com - 11/2022
- [ntfy - Push Notification Service](https://dizzytech.de/posts/ntfy/) - dizzytech.de - 11/2022
- [Console #132](https://console.substack.com/p/console-132) ⭐ - console.substack.com - 11/2022
- [How to make my phone buzz*](https://evbogue.com/howtomakemyphonebuzz) - evbogue.com - 11/2022
@@ -190,3 +291,24 @@ and uptime of third party servers, so use of each server is **at your own discre
- [ntfy otro sistema de notificaciones pub-sub simple basado en HTTP](https://ugeek.github.io/blog/post/2021-11-05-ntfy-sh-otro-sistema-de-notificaciones-pub-sub-simple-basado-en-http.html) - ugeek.github.io - 11/2021
- [Show HN: A tool to send push notifications to your phone, written in Go](https://news.ycombinator.com/item?id=29715464) ⭐ - news.ycombinator.com - 12/2021
- [Reddit selfhostable post](https://www.reddit.com/r/selfhosted/comments/qxlsm9/my_open_source_notification_android_app_and/) ⭐ - reddit.com - 11/2021
- [ntfy on The Canary in the Cage Podcast](https://odysee.com/@TheCanaryInTheCage:b/The-Canary-in-the-Cage-Episode-42:1?r=4gitYjTacQqPEjf22874USecDQYJ5y5E&t=3062) - odysee.com - 1/2025
- [NtfyPwsh - A PowerShell Module to Send Ntfy Messages](https://ptmorris1.github.io/posts/NtfyPwsh/) - github.io - 5/2025
## Alternative ntfy servers
Here's a list of public ntfy servers. As of right now, there is only one official server. The others are provided by the
ntfy community. Thanks to everyone running a public server. **You guys rock!**
| URL | Country |
|---------------------------------------------------|--------------------|
| [ntfy.sh](https://ntfy.sh/) (*Official*) | 🇺🇸 United States |
| [ntfy.tedomum.net](https://ntfy.tedomum.net/) | 🇫🇷 France |
| [ntfy.jae.fi](https://ntfy.jae.fi/) | 🇫🇮 Finland |
| [ntfy.adminforge.de](https://ntfy.adminforge.de/) | 🇩🇪 Germany |
| [ntfy.envs.net](https://ntfy.envs.net) | 🇩🇪 Germany |
| [ntfy.mzte.de](https://ntfy.mzte.de/) | 🇩🇪 Germany |
| [ntfy.hostux.net](https://ntfy.hostux.net/) | 🇫🇷 France |
| [ntfy.fossman.de](https://ntfy.fossman.de/) | 🇩🇪 Germany |
Please be aware that **server operators can log your messages**. The project also cannot guarantee the reliability
and uptime of third party servers, so use of each server is **at your own discretion**.

View File

@@ -1,5 +1,5 @@
# Known issues
This is an incomplete list of known issues with the ntfy server, Android app, and iOS app. You can find a complete
This is an incomplete list of known issues with the ntfy server, web app, Android app, and iOS app. You can find a complete
list [on GitHub](https://github.com/binwiederhier/ntfy/labels/%F0%9F%AA%B2%20bug), but I thought it may be helpful
to have the prominent ones here to link to.
@@ -26,3 +26,18 @@ Be sure that in your selfhosted server:
* Set `upstream-base-url: "https://ntfy.sh"` (**not your own hostname!**)
* Ensure that the URL you set in `base-url` **matches exactly** what you set the Default Server in iOS to
## iOS app seeing "New message", but not real message content
If you see `New message` notifications on iOS, your iPhone can likely not talk to your self-hosted server. Be sure that
your iOS device and your ntfy server are either on the same network, or that your phone can actually reach the server.
Turn on tracing/debugging on the server (via `log-level: trace` or `log-level: debug`, see [troubleshooting](troubleshooting.md)),
and read docs on [iOS instant notifications](https://docs.ntfy.sh/config/#ios-instant-notifications).
## Safari does not play sounds for web push notifications
Safari does not support playing sounds for web push notifications, and treats them all as silent. This will be fixed with
iOS 17 / Safari 17, which will be released later in 2023.
## PWA on iOS sometimes crashes with an IndexedDB error (see [#787](https://github.com/binwiederhier/ntfy/issues/787))
When resuming the installed PWA from the background, it sometimes crashes with an error from IndexedDB/Dexie, due to a
[WebKit bug]( https://bugs.webkit.org/show_bug.cgi?id=197050). A reload will fix it until a permanent fix is found.

View File

@@ -1,12 +1,194 @@
# Privacy policy
I love free software, and I'm doing this because it's fun. I have no bad intentions, and **I will
never monetize or sell your information, and this service and software will always stay free and open.**
**Last updated:** January 2, 2026
Neither the server nor the app record any personal information, or share any of the messages and topics with
any outside service. All data is exclusively used to make the service function properly. The only external service
I use is Firebase Cloud Messaging (FCM) service, which is required to provide instant Android notifications (see
[FAQ](faq.md) for details). To avoid FCM altogether, download the F-Droid version.
This privacy policy describes how ntfy ("we", "us", or "our") collects, uses, and handles your information
when you use the ntfy.sh service, web app, and mobile applications (Android and iOS).
For debugging purposes, the ntfy server may temporarily log request paths, remote IP addresses or even topics
or messages, though typically this is turned off.
## Our commitment to privacy
We love free software, and we're doing this because it's fun. We have no bad intentions, and **we will
never monetize or sell your information**. The ntfy service and software will always stay free and open source.
If you don't trust us or your messages are sensitive, you can [self-host your own ntfy server](install.md).
## Information we collect
### Account information (optional)
If you create an account on ntfy.sh, we collect:
- **Username** - A unique identifier you choose
- **Password** - Stored as a secure bcrypt hash (we never store your plaintext password)
- **Email address** - Only if you subscribe to a paid plan (for billing purposes)
- **Phone number** - Only if you enable the phone call notification feature (verified via SMS/call)
You can use ntfy without creating an account. Anonymous usage is fully supported.
### Messages and notifications
- **Message content** - Messages you publish are temporarily cached on our servers (default: 12 hours) to support
message polling and to overcome client network disruptions. Messages are deleted after the cache duration expires.
- **Attachments** - File attachments are temporarily stored (default: 3 hours) and then automatically deleted.
- **Topic names** - The topic names you publish to or subscribe to are processed by our servers.
### Technical information
- **IP addresses** - Used for rate limiting to prevent abuse. May be temporarily logged for debugging purposes,
though this is typically turned off.
- **Access tokens** - If you create access tokens, we store the token value, an optional label, last access time,
and the IP address of the last access.
- **Web push subscriptions** - If you enable browser notifications, we store your browser's push subscription
endpoint to deliver notifications.
### Billing information (paid plans only)
If you subscribe to a paid plan, payment processing is handled by Stripe. We store:
- Stripe customer ID
- Subscription status and billing period
We do not store your credit card numbers or payment details directly. These are handled entirely by Stripe.
## Third-party services
To provide the ntfy.sh service, we use the following third-party services:
### Firebase Cloud Messaging (FCM)
We use Google's Firebase Cloud Messaging to deliver push notifications to Android and iOS devices. When you
receive a notification through the mobile apps (Google Play or App Store versions):
- Message metadata and content may be transmitted through Google's FCM infrastructure
- Google's [privacy policy](https://policies.google.com/privacy) applies to their handling of this data
**To avoid FCM entirely:** Download the [F-Droid version](https://f-droid.org/en/packages/io.heckel.ntfy/) of
the Android app and use a self-hosted server, or use the instant delivery feature with your own server.
### Twilio (phone calls)
If you use the phone call notification feature (`X-Call` header), we use Twilio to:
- Make voice calls to your verified phone number
- Send SMS or voice calls for phone number verification
Your phone number is shared with Twilio to deliver these services. Twilio's
[privacy policy](https://www.twilio.com/legal/privacy) applies.
### Amazon SES (email delivery)
If you use the email notification feature (`X-Email` header), we use Amazon Simple Email Service (SES) to
deliver emails. The recipient email address and message content are transmitted through Amazon's infrastructure.
Amazon's [privacy policy](https://aws.amazon.com/privacy/) applies.
### Stripe (payments)
If you subscribe to a paid plan, payments are processed by Stripe. Your payment information is handled directly
by Stripe and is subject to Stripe's [privacy policy](https://stripe.com/privacy).
Note: We have explicitly disabled Stripe's telemetry features in our integration.
### Web push providers
If you enable browser notifications in the ntfy web app, push messages are delivered through your browser
vendor's push service:
- Google (Chrome)
- Mozilla (Firefox)
- Apple (Safari)
- Microsoft (Edge)
Your browser's push subscription endpoint is shared with these providers to deliver notifications.
## Mobile applications
### Android app
The Android app is available from two sources:
- **Google Play Store** - Uses Firebase Cloud Messaging for push notifications. Firebase Analytics is
**explicitly disabled** in our app.
- **F-Droid** - Does not include any Google services or Firebase. Uses a foreground service to maintain
a direct connection to the server.
The Android app stores the following data locally on your device:
- Subscribed topics and their settings
- Cached notifications
- User credentials (if you add a server with authentication)
- Application logs (for debugging, stored locally only)
### iOS app
The iOS app uses Firebase Cloud Messaging (via Apple Push Notification service) to deliver notifications.
The app stores the following data locally on your device:
- Subscribed topics
- Cached notifications
- User credentials (if configured)
## Web application
The ntfy web app is a static website that stores all data locally in your browser:
- **IndexedDB** - Stores your subscriptions and cached notifications
- **Local Storage** - Stores your preferences and session information
No cookies are used for tracking. The web app does not have a backend beyond the ntfy API.
## Data retention
| Data type | Retention period |
|------------------------|---------------------------------------------------|
| Messages | 12 hours (configurable by server operators) |
| Attachments | 3 hours (configurable by server operators) |
| User accounts | Until you delete your account |
| Access tokens | Until you revoke them or delete your account |
| Phone numbers | Until you remove them or delete your account |
| Web push subscriptions | 60 days of inactivity, then automatically removed |
| Server logs | Varies; debugging logs are typically temporary |
## Self-hosting
If you prefer complete control over your data, you can [self-host your own ntfy server](install.md).
When self-hosting:
- You control all data storage and retention
- You can choose whether to use Firebase, Twilio, email delivery, or any other integrations
- No data is shared with ntfy.sh or any third party (unless you configure those integrations)
The server and all apps are fully open source:
- Server: [github.com/binwiederhier/ntfy](https://github.com/binwiederhier/ntfy)
- Android app: [github.com/binwiederhier/ntfy-android](https://github.com/binwiederhier/ntfy-android)
- iOS app: [github.com/binwiederhier/ntfy-ios](https://github.com/binwiederhier/ntfy-ios)
## Data security
- All connections to ntfy.sh are encrypted using TLS/HTTPS
- Passwords are hashed using bcrypt before storage
- Access tokens are generated using cryptographically secure random values
- The server does not log message content by default
## Your rights
You have the right to:
- **Access** - View your account information and data
- **Delete** - Delete your account and associated data via the web app
- **Export** - Your messages are available via the API while cached
To delete your account, use the account settings in the web app or contact us.
## Changes to this policy
We may update this privacy policy from time to time. Changes will be posted on this page with an updated
"Last updated" date. You may also review all changes in the [Git history](https://github.com/binwiederhier/ntfy/commits/main/docs/privacy.md).
For significant changes, we may provide additional notice on Discord/Matrix or through the
[announcements](https://ntfy.sh/announcements) ntfy topic.
## Contact
For privacy-related inquiries, please email [privacy@mail.ntfy.sh](mailto:privacy@mail.ntfy.sh).
For all other contact options, see the [contact page](contact.md).

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,457 @@
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.3.1
## Current stable releases
| Component | Version | Release date |
|------------------|---------|--------------|
| ntfy server | v2.15.0 | Nov 16, 2025 |
| ntfy Android app | v1.21.1 | Jan 6, 2025 |
| ntfy iOS app | v1.3 | Nov 26, 2023 |
Please check out the release notes for [upcoming releases](#not-released-yet) below.
## ntfy Android app v1.21.1
Released January 6, 2026
This is the first feature release in a long time. After all the SDK updates, fixes to comply with the Google Play policies
and the framework updates, this release ships a lot of highly requested features: Sending messages through the app (WhatsApp-style),
support for passing headers to your proxy, an in-app language switcher, and more.
If you are waiting for a feature, please 👍 the corresponding [GitHub issue](https://github.com/binwiederhier/ntfy/issues?q=is%3Aissue%20state%3Aopen%20sort%3Areactions-%2B1-desc).
If you like ntfy, please consider purchasing [ntfy Pro](https://ntfy.sh/app) to support us.
**Features:**
* Allow publishing messages through the message bar and publish dialog ([#98](https://github.com/binwiederhier/ntfy/issues/98), [ntfy-android#144](https://github.com/binwiederhier/ntfy-android/pull/144))
* Define custom HTTP headers to support authenticated proxies, tunnels and SSO ([ntfy-android#116](https://github.com/binwiederhier/ntfy-android/issues/116), [#1018](https://github.com/binwiederhier/ntfy/issues/1018), [ntfy-android#132](https://github.com/binwiederhier/ntfy-android/pull/132), [ntfy-android#146](https://github.com/binwiederhier/ntfy-android/pull/146), thanks to [@CrazyWolf13](https://github.com/CrazyWolf13))
* Implement UnifiedPush "raise to foreground" requirement ([ntfy-android#98](https://github.com/binwiederhier/ntfy-android/pull/98), [ntfy-android#148](https://github.com/binwiederhier/ntfy-android/pull/148), thanks to [@p1gp1g](https://github.com/p1gp1g))
* Language selector to allow overriding the system language ([#1508](https://github.com/binwiederhier/ntfy/issues/1508), [ntfy-android#145](https://github.com/binwiederhier/ntfy-android/pull/145), thanks to [@hudsonm62](https://github.com/hudsonm62) for reporting)
* Highlight phone numbers and email addresses in notifications ([#957](https://github.com/binwiederhier/ntfy/issues/957), [ntfy-android#71](https://github.com/binwiederhier/ntfy-android/pull/71), thanks to [@brennenputh](https://github.com/brennenputh), and [@XylenSky](https://github.com/XylenSky) for reporting)
* Support for port and display name in [ntfy://](subscribe/phone.md#ntfy-links) links ([ntfy-android#130](https://github.com/binwiederhier/ntfy-android/pull/130), thanks to [@godovski](https://github.com/godovski))
**Bug fixes + maintenance:**
* Add support for (technically incorrect) 'image/jpg' MIME type ([ntfy-android#142](https://github.com/binwiederhier/ntfy-android/pull/142), thanks to [@Murilobeluco](https://github.com/Murilobeluco))
* Unify "copy to clipboard" notifications, use Android 13 style ([ntfy-android#61](https://github.com/binwiederhier/ntfy-android/pull/61), thanks to [@thgoebel](https://github.com/thgoebel))
* Fix crash in user add dialog (onAddUser)
* Fix ForegroundServiceDidNotStartInTimeException (attempt 2, see [#1520](https://github.com/binwiederhier/ntfy/issues/1520))
* Hide "Exact alarms" setting if battery optimization exemption has been granted ([#1456](https://github.com/binwiederhier/ntfy/issues/1456), thanks for reporting [@HappyLer](https://github.com/HappyLer))
## ntfy Android app v1.20.0
Released December 28, 2025
This is the last pure maintenance release for now. It'll bring all dependencies and library version to the latest version,
and fixes some crashes. I had to drop support for about 4,000 devices (only ~200 installations), because the libraries
themselves do not support SDK 21 anymore, which was the previous minimum SDK version (Android 5, 2014). Now the minimum
SDK version is 26 (Android 8, 2017).
**Bug fixes + maintenance:**
* Updated dependencies, minimum SDK version to 26, clean up legacy code, upgrade Gradle ([ntfy-android#140](https://github.com/binwiederhier/ntfy-android/pull/140),
thanks to [@cyb3rko](https://github.com/cyb3rko) for the implementation)
* Updated target SDK version to 36 (Android 8, 2017)
* Fixed ForegroundServiceDidNotStartInTimeException ([#1520](https://github.com/binwiederhier/ntfy/issues/1520))
* Fixed crashes with redrawing the list when temporarily muted topics expire
## ntfy Android app v1.19.4
Released December 21, 2025
This release upgrades the Android app to use [Material 3](https://m3.material.io/) design components and adds the
ability to use [dynamic colors](https://developer.android.com/develop/ui/views/theming/dynamic-colors).
**This was a lot of work** and I want to thank [@Bnyro](https://github.com/Bnyro) and [@cyb3rko](https://github.com/cyb3rko) for implementing this. You guys rock!
**Features:**
* Moved the user interface to Material 3 and added dynamic color support ([#580](https://github.com/binwiederhier/ntfy/issues/580),
[ntfy-android#56](https://github.com/binwiederhier/ntfy-android/pull/56), [ntfy-android#126](https://github.com/binwiederhier/ntfy-android/pull/126),
[ntfy-android#135](https://github.com/binwiederhier/ntfy-android/pull/135), thanks to [@Bnyro](https://github.com/Bnyro)
and [@cyb3rko](https://github.com/cyb3rko) for the implementation, and to [@RokeJulianLockhart](https://github.com/RokeJulianLockhart) for reporting)
## ntfy Android app v1.18.0
Released December 4, 2025
**Features:**
* Added GIF support for preview images ([ntfy-android#76](https://github.com/binwiederhier/ntfy-android/pull/76)/[#532](https://github.com/binwiederhier/ntfy/issues/532), thanks to [@MichaelArkh](https://github.com/MichaelArkh) and [@dimatx](https://github.com/dimatx) for reporting)
* Added WebP support for preview images ([ntfy-android#81](https://github.com/binwiederhier/ntfy-android/pull/81)/[ntfy-android#80](https://github.com/binwiederhier/ntfy-android/issues/80), thanks to [@jokakilla](https://github.com/jokakilla))
* Added UnifiedPush distributor selection support ([#137](https://github.com/binwiederhier/ntfy-android/pull/137), thanks to [@p1gp1g](https://github.com/p1gp1g))
**Bug fixes + maintenance:**
* Remove REQUEST_INSTALL_PACKAGES permission ([#684](https://github.com/binwiederhier/ntfy/issues/684))
* Request to ignore battery optimizations before receiving subscription ([ntfy-android#97](https://github.com/binwiederhier/ntfy-android/pull/97), thanks to [@p1gp1g](https://github.com/p1gp1g))
## ntfy server v2.15.0
Released Nov 16, 2025
This release adds a `require-login` flag to topics, which forces users to log in before they can
use the web app. This is useful for self-hosters and will obviously not be enabled on ntfy.sh.
**Features:**
* Add `require-login` flag to redirect to login page if not logged in ([#1434](https://github.com/binwiederhier/ntfy/pull/1434)/[#238](https://github.com/binwiederhier/ntfy/issues/238)/[#1329](https://github.com/binwiederhier/ntfy/pull/1329), thanks to [@theatischbein](https://github.com/theatischbein) for implementing most of this)
**Bug fixes + maintenance:**
* The official ntfy.sh Debian/Ubuntu repository has moved to [archive.ntfy.sh](https://archive.ntfy.sh) ([#1357](https://github.com/binwiederhier/ntfy/issues/1357)/[#1401](https://github.com/binwiederhier/ntfy/issues/1401), thanks to [@skibbipl](https://github.com/skibbipl) and [@lduesing](https://github.com/lduesing) for reporting)
* Add mutex around message cache writes to avoid `database locked` errors ([#1397](https://github.com/binwiederhier/ntfy/pull/1397), [#1391](https://github.com/binwiederhier/ntfy/issues/1391), thanks to [@timofej673](https://github.com/timofej673))
* Add build tags `nopayments`, `nofirebase` and `nowebpush` to allow excluding external dependencies, useful for
packaging in Debian ([#1420](https://github.com/binwiederhier/ntfy/pull/1420), discussion in [#1258](https://github.com/binwiederhier/ntfy/issues/1258), thanks to [@thekhalifa](https://github.com/thekhalifa) for packaging ntfy for Debian/Ubuntu)
* Make copying tokens, phone numbers, etc. possible on HTTP ([#1432](https://github.com/binwiederhier/ntfy/pull/1432)/[#1408](https://github.com/binwiederhier/ntfy/issues/1408)/[#1295](https://github.com/binwiederhier/ntfy/issues/1295), thanks to [@EdwinKM](https://github.com/EdwinKM), [@xxl6097](https://github.com/xxl6097) for reporting)
## ntfy Android app v1.17.13
Released October 21, 2025
This release makes changes to comply with the Google Play policies. See [#1463](https://github.com/binwiederhier/ntfy/issues/1463)
or [ef57cd1](https://github.com/binwiederhier/ntfy-android/commit/ef57cd1374118b3e4d7a7ab496afe337e714fff7) for details.
The policies do not allow directly or indirectly linking to paid plans or donation links that do not go through Google Play.
**Changes:**
* Remove the "Donate" button from menu (all variants)
* Change default display name from "ntfy.sh/mytopic" to "mytopic" (all variants)
* Remove links to ntfy docs and issue tracker (Play variant only)
* Remove how-to links to ntfy.sh in a few places (Play variant only)
* Remove "Copy topic address" from subscription menu (Play variant only)
## ntfy Android app v1.17.8
Released September 23, 2025
This is largely a maintenance update to ensure the SDK is up-to-date.
**Features:**
* Markdown is now rendered if "Markdown: yes" was passed ([#310](https://github.com/binwiederhier/ntfy/issues/310), thanks to [@NiNiyas](https://github.com/NiNiyas) for reporting)
* You can now disable UnifiedPush so ntfy does not act as a UnifiedPush distributor ([#646](https://github.com/binwiederhier/ntfy/issues/646), thanks to [@ollien](https://github.com/ollien) for reporting and to [@wunter8](https://github.com/wunter8) for implementing)
**Bug fixes + maintenance:**
* UnifiedPush subscriptions now include the `Rate-Topics` header to facilitate subscriber-based billing ([#652](https://github.com/binwiederhier/ntfy/issues/652), thanks to [@wunter8](https://github.com/wunter8))
* Subscriptions without icons no longer appear to use another subscription's icon ([#634](https://github.com/binwiederhier/ntfy/issues/634), thanks to [@topcaser](https://github.com/topcaser) for reporting and to [@wunter8](https://github.com/wunter8) for fixing)
* Bumped all dependencies to the latest versions (no ticket)
## ntfy server v2.14.0
Released August 5, 2025
This release adds support for [declarative users](config.md#users-via-the-config), [declarative ACL entries](config.md#acl-entries-via-the-config) and [declarative tokens](config.md#tokens-via-the-config). This allows you to define users, ACL entries and tokens in the config file, which is useful for static deployments or deployments that use a configuration management system.
It also adds support for [pre-defined templates](publish.md#pre-defined-templates) and [custom templates](publish.md#custom-templates) for enhanced JSON webhook support, as well as advanced [template functions](publish.md#template-functions) based on the [Sprig](https://github.com/Masterminds/sprig) functions.
❤️ If you like ntfy, **please consider sponsoring me** via [GitHub Sponsors](https://github.com/sponsors/binwiederhier), [Liberapay](https://en.liberapay.com/ntfy/), Bitcoin (`1626wjrw3uWk9adyjCfYwafw4sQWujyjn8`), or by buying a [paid plan via the web app](https://ntfy.sh/app). ntfy
will always remain open source.
**Features:**
* [Declarative users](config.md#users-via-the-config), [declarative ACL entries](config.md#acl-entries-via-the-config) and [declarative tokens](config.md#tokens-via-the-config) ([#464](https://github.com/binwiederhier/ntfy/issues/464), [#1384](https://github.com/binwiederhier/ntfy/pull/1384), [#1413](https://github.com/binwiederhier/ntfy/pull/1413), thanks to [pinpox](https://github.com/pinpox) for reporting, to [@wunter8](https://github.com/wunter8) for reviewing and implementing parts of it)
* [Pre-defined templates](publish.md#pre-defined-templates) and [custom templates](publish.md#custom-templates) for enhanced JSON webhook support ([#1390](https://github.com/binwiederhier/ntfy/pull/1390))
* Support of advanced [template functions](publish.md#template-functions) based on the [Sprig](https://github.com/Masterminds/sprig) library ([#1121](https://github.com/binwiederhier/ntfy/issues/1121), thanks to [@davidatkinsondoyle](https://github.com/davidatkinsondoyle) for reporting, to [@wunter8](https://github.com/wunter8) for implementing, and to the Sprig team for their work)
## ntfy server v2.13.0
Released July 10, 2025
This is a relatively small release, mainly to support IPv6 and to add more sophisticated
proxy header support. Quick reminder that if you like ntfy, **please consider sponsoring us**
via [GitHub Sponsors](https://github.com/sponsors/binwiederhier) and [Liberapay](https://en.liberapay.com/ntfy/), or buying a [paid plan via the web app](https://ntfy.sh/app).
ntfy will always remain open source.
**Features:**
* Full [IPv6 support](config.md#ipv6-support) for ntfy and the official ntfy.sh server ([#519](https://github.com/binwiederhier/ntfy/issues/519)/[#1380](https://github.com/binwiederhier/ntfy/pull/1380)/[ansible#4](https://github.com/binwiederhier/ntfy-ansible/pull/4))
* Support `X-Client-IP`, `X-Real-IP`, `Forwarded` headers for [rate limiting](config.md#ip-based-rate-limiting) via `proxy-forwarded-header` and `proxy-trusted-hosts` ([#1360](https://github.com/binwiederhier/ntfy/pull/1360)/[#1252](https://github.com/binwiederhier/ntfy/pull/1252), thanks to [@pixitha](https://github.com/pixitha))
* Add STDIN support for `ntfy publish` ([#1382](https://github.com/binwiederhier/ntfy/pull/1382), thanks to [@srevn](https://github.com/srevn))
**Languages**
* Update new languages from Weblate. Thanks to all the contributors!
* Added Estonian (Esti), Galician (Galego), Romanian (Română), Slovak (Slovenčina) as new languages to the web app
## ntfy server v2.12.0
Released May 29, 2025
This is mainly a maintenance release that updates dependencies, though since it's been over a year, there are a few
new features and bug fixes as well.
Thanks to everyone who contributed to this release, and special thanks to [@wunter8](https://github.com/wunter8) for his continued
user support in Discord/Matrix/GitHub! You rock, man!
**Features:**
* Add username/password auth to email publishing ([#1164](https://github.com/binwiederhier/ntfy/pull/1164), thanks to [@bishtawi](https://github.com/bishtawi))
* Write VAPID keys to file in `ntfy webpush --output-file` ([#1138](https://github.com/binwiederhier/ntfy/pull/1138), thanks to [@nogweii](https://github.com/nogweii))
* Add Docker major/minor version to image tags ([#1271](https://github.com/binwiederhier/ntfy/pull/1271), thanks to [@RoboMagus](https://github.com/RoboMagus))
* Add `latest` subscription param for grabbing just the most recent message ([#1216](https://github.com/binwiederhier/ntfy/pull/1216), thanks to [@wunter8](https://github.com/wunter8))
* Allow using `NTFY_PASSWORD_HASH` in `ntfy user` command instead of raw password ([#1340](https://github.com/binwiederhier/ntfy/pull/1340), thanks to [@Tom-Hubrecht](https://github.com/Tom-Hubrecht) for implementing)
* You can now change passwords via `v1/users` API ([#1267](https://github.com/binwiederhier/ntfy/pull/1267), thanks to [@wunter8](https://github.com/wunter8) for implementing)
* Make WebPush subscription warning/expiry configurable, increase default to 55/60 days ([#1212](https://github.com/binwiederhier/ntfy/pull/1212), thanks to [@KuroSetsuna29](https://github.com/KuroSetsuna29))
* Support [systemd user service](https://docs.ntfy.sh/subscribe/cli/#using-the-systemd-service) `ntfy-client.service` ([#1002](https://github.com/binwiederhier/ntfy/pull/1002), thanks to [@dandersch](https://github.com/dandersch))
**Bug fixes + maintenance:**
* Security updates for dependencies and Docker images ([#1341](https://github.com/binwiederhier/ntfy/pull/1341))
* Upgrade to Vite 6 ([#1342](https://github.com/binwiederhier/ntfy/pull/1342), thanks Dependabot)
* Fix iOS delivery issues for read-protected topics ([#1207](https://github.com/binwiederhier/ntfy/pull/1287), thanks a lot to [@barart](https://github.com/barart)!)
* Add `Date` header to outgoing emails to avoid rejection ([#1141](https://github.com/binwiederhier/ntfy/pull/1141), thanks to [@pcouy](https://github.com/pcouy))
* Fix IP address parsing when behind a proxy ([#1266](https://github.com/binwiederhier/ntfy/pull/1266), thanks to [@mmatuska](https://github.com/mmatuska))
* Make sure UnifiedPush messages are not treated as attachments ([#1312](https://github.com/binwiederhier/ntfy/pull/1312), thanks to [@vkrause](https://github.com/vkrause))
* Add OCI image version to Docker image ([#1307](https://github.com/binwiederhier/ntfy/pull/1307), thanks to [@jlssmt](https://github.com/jlssmt))
* WebSocket returning incorrect HTTP error code ([#1338](https://github.com/binwiederhier/ntfy/pull/1338) / [#1337](https://github.com/binwiederhier/ntfy/pull/1337), thanks to [@wunter8](https://github.com/wunter8) for debugging and implementing)
* Make Markdown in the web app scrollable horizontally ([#1262](https://github.com/binwiederhier/ntfy/pull/1262), thanks to [@rake5k](https://github.com/rake5k) for fixing)
* Make sure WebPush subscription topics are actually deleted (no ticket)
* Increase the number of access tokens per user to 60 ([#1308](https://github.com/binwiederhier/ntfy/issues/1308))
* Allow specifying `cache` and `firebase` via JSON publishing ([#1119](https://github.com/binwiederhier/ntfy/issues/1119)/[#1123](https://github.com/binwiederhier/ntfy/pull/1123), thanks to [@stendler](https://github.com/stendler))
**Documentation:**
* Lots of new integrations and projects. Amazing!
* [ntfy-me-mcp](https://github.com/gitmotion/ntfy-me-mcp)
* [UptimeObserver](https://uptimeobserver.com)
* [alertmanager-ntfy-relay](https://github.com/therobbielee/alertmanager-ntfy-relay)
* [Monibot](https://monibot.io/)
* [Daily_Fact_Ntfy](https://github.com/thiswillbeyourgithub/Daily_Fact_Ntfy)
* [EasyMorph](https://help.easymorph.com/doku.php?id=transformations:sendntfymessage)
* [ntfy-run](https://github.com/quantum5/ntfy-run)
* [Clipboard IO](https://github.com/jim3692/clipboard-io)
* [ntfy-me-mcp](https://github.com/gitmotion/ntfy-me-mcp)
* [InvaderInformant](https://github.com/patricksthannon/InvaderInformant)
* Various docs updates ([#1161](https://github.com/binwiederhier/ntfy/pull/1161), thanks to [@OneWeekNotice](https://github.com/OneWeekNotice))
* Typo in config docs ([#1177](https://github.com/binwiederhier/ntfy/pull/1177), thanks to [@hoho4190](https://github.com/hoho4190))
* Typo in CLI docs ([#1172](https://github.com/binwiederhier/ntfy/pull/1172), thanks to [@anirvan](https://github.com/anirvan))
* Correction about MacroDroid ([#1137](https://github.com/binwiederhier/ntfy/pull/1137), thanks to [@ShlomoCode](https://github.com/ShlomoCode))
* Note about fail2ban in Docker ([#1175](https://github.com/binwiederhier/ntfy/pull/1175)), thanks to [@Measurity](https://github.com/Measurity))
* Lots of other tiny docs updates, thanks to everyone who contributed!
**Languages**
* Update new languages from Weblate. Thanks to all the contributors!
* Added Tamil (தமிழ்) as a new language to the web app
## ntfy server v2.11.0
Released May 13, 2024
This is a tiny release that fixes a database index issue that caused performance issues on ntfy.sh. It also fixes a bug
in the rate visitor logic that caused rate visitors to be assigned to seemingly random topics. Nothing major this time.
❤️ Quick reminder that if you like ntfy, **please consider sponsoring us** via [GitHub Sponsors](https://github.com/sponsors/binwiederhier)
and [Liberapay](https://en.liberapay.com/ntfy/), or buying a [paid plan via the web app](https://ntfy.sh/app). ntfy will always remain open source.
**Bug fixes + maintenance:**
* Re-add database index `idx_topic` to the `messages` table to fix performance issues on ntfy.sh (no ticket, big thanks to [@tcaputi](https://github.com/tcaputi) for finding this issue)
* Do not set rate visitor for non-eligible topics (no ticket)
* Do not cache `config.js` ([#1098](https://github.com/binwiederhier/ntfy/pull/1098), thanks to [@wunter8](https://github.com/wunter8))
## ntfy server v2.10.0
Released Mar 27, 2024
This release adds support for **message templating** in the ntfy server, which allows you to include a message and/or
title template that will be filled with values from a JSON body (e.g. `curl -gd '{"alert":"Disk space low"}' "ntfy.sh/mytopic?tpl=1&m={{.alert}}"`).
This is great for services that let you specify a webhook URL but do not let you change the webhook body (such as GitHub, or Grafana).
**Features:**
* [Message templating](publish.md#message-templating): You can now include a message and/or title template that will be filled with values from a JSON body ([#724](https://github.com/binwiederhier/ntfy/issues/724), thanks to [@wunter8](https://github.com/wunter8) for implementing)
## ntfy server v2.9.0
Released Mar 7, 2024
A small release after a long pause (lots of day job work). This release adds for **larger messages** and **longer
message delays** in scheduled delivery messages. The web app also now supports pasting images from the clipboard. Other
than that, only a few bug fixes and documentation updates, and a teeny tiny breaking change 😬.
!!! info
⚠️ **Breaking change**: The `Rate-Topics` header was removed due to a [DoS issue](https://github.com/binwiederhier/ntfy/issues/1048). This only affects
installations with `visitor-subscriber-rate-limiting: true`, which is not the default and likely very rarely used.
Normally I'd never remove a feature, but this is a security issue, and likely affects almost nobody.
**Features:**
* Support for larger message delays with `message-delay-limit` (see [message limits](config.md#message-limits), [#1050](https://github.com/binwiederhier/ntfy/pull/1050)/[#1019](https://github.com/binwiederhier/ntfy/issues/1019), thanks to [@MrChadMWood](https://github.com/MrChadMWood) for reporting)
* Support for larger message body sizes with `message-size-limit` (use at your own risk, see [message limits](config.md#message-limits), [#836](https://github.com/binwiederhier/ntfy/pull/836)/[#1050](https://github.com/binwiederhier/ntfy/pull/1050), thanks to [@zhzy0077](https://github.com/zhzy0077) for implementing this, and to [@nkjshlsqja7331](https://github.com/nkjshlsqja7331) for reporting)
* Web app: You can now paste images into the message bar or publish dialog ([#963](https://github.com/binwiederhier/ntfy/pull/963)/[#572](https://github.com/binwiederhier/ntfy/issues/572), thanks to [@cmj2002](https://github.com/cmj2002) for implementing, and [@rounakdatta](https://github.com/rounakdatta) for reporting)
**Bug fixes + maintenance:**
* ⚠️ Remove `Rate-Topics` header due to DoS security issue if `visitor-subscriber-rate-limiting: true` ([#1048](https://github.com/binwiederhier/ntfy/issues/1048))
**Documentation:**
* Remove `mkdocs-simple-hooks` ([#1016](https://github.com/binwiederhier/ntfy/pull/1016), thanks to [@Tom-Hubrecht](https://github.com/Tom-Hubrecht))
* Update Watchtower example ([#1014](https://github.com/binwiederhier/ntfy/pull/1014), thanks to [@lennart-m](https://github.com/lennart-m))
* Fix dead links ([#1022](https://github.com/binwiederhier/ntfy/pull/1022), thanks to [@DerRockWolf](https://github.com/DerRockWolf))
* PowerShell file upload example ([#1004](https://github.com/binwiederhier/ntfy/pull/1004), thanks to [@YMan84](https://github.com/YMan84))
## ntfy iOS app v1.3
Released Nov 26, 2023
This release (hopefully) fixes the issues with the iOS UI not updating properly when new notifications arrive, as well
as notifications not being received (anymore) after previously working. Both issues have been annoying and known bugs
for a long time, and I hope that they are finally fixed.
Many thanks to [@tcaputi](https://github.com/tcaputi) for fixing the issues, and to the anonymous donor for sponsoring these fixes.
**Bug fixes:**
* UI not updating properly ([#267](https://github.com/binwiederhier/ntfy/issues/267)/[#402](https://github.com/binwiederhier/ntfy/issues/402), thanks to [@tcaputi](https://github.com/tcaputi))
## ntfy server v2.8.0
Released November 19, 2023
This release brings a handful of random bug fixes: two unrelated access control list fixes, a fix around web app crashes
for languages with underscores in the language code (e.g. `zh_Hant`, `zh_Hans`, `pt_BR`, ...), a workaround for the
`Priority` header (often used in Cloudflare setups), and support among others support for HTML-only emails (finally),
web app crash fixes
**Bug fixes + maintenance:**
* Support for HTML-only emails ([#690](https://github.com/binwiederhier/ntfy/issues/690)/[#693](https://github.com/binwiederhier/ntfy/pull/693), thanks to [@teastrainer](https://github.com/teastrainer) and [@CrazyWolf13](https://github.com/CrazyWolf13) for reporting)
* Fix ACL issue with topic patterns containing underscores ([#840](https://github.com/binwiederhier/ntfy/issues/840), thanks to [@Joe-0237](https://github.com/Joe-0237) for reporting)
* Fix ACL issue with order of read/write rules ([#914](https://github.com/binwiederhier/ntfy/issues/914)/[#917](https://github.com/binwiederhier/ntfy/pull/917), thanks to [@sandman7920](https://github.com/sandman7920))
* Re-add `tzdata` to Docker images for amd64 image ([#894](https://github.com/binwiederhier/ntfy/issues/894), [#307](https://github.com/binwiederhier/ntfy/pull/307))
* Add special logic to ignore `Priority` header if it resembles an RFC 9218 value ([#851](https://github.com/binwiederhier/ntfy/pull/851)/[#895](https://github.com/binwiederhier/ntfy/pull/895), thanks to [@gusdleon](https://github.com/gusdleon), see also [#351](https://github.com/binwiederhier/ntfy/issues/351), [#353](https://github.com/binwiederhier/ntfy/issues/353), [#461](https://github.com/binwiederhier/ntfy/issues/461))
* PWA: hide install prompt on macOS 14 Safari ([#899](https://github.com/binwiederhier/ntfy/pull/899), thanks to [@nihalgonsalves](https://github.com/nihalgonsalves))
* Fix web app crash in Edge for languages with underline in locale ([#922](https://github.com/binwiederhier/ntfy/pull/922)/[#912](https://github.com/binwiederhier/ntfy/issues/912)/[#852](https://github.com/binwiederhier/ntfy/issues/852), thanks to [@imkero](https://github.com/imkero))
**Additional languages:**
* Finnish (thanks to [@Seppo](https://hosted.weblate.org/user/Seppo/))
## ntfy server v2.7.0
Released August 17, 2023
This release ships Markdown support for the web app (not in the Android app yet), and adds support for
right-to-left languages (RTL) in the web app. It also fixes a few issues around date/time formatting,
internationalization support, a CLI auth bug.
Furthermore, it fixes a security issue around access tokens getting erroneously deleted for other users
in a specific scenario. This was a denial-of-service-type security issue, since it **effectively allowed a
single user to deny access to all other users of a ntfy instance**. Please note that while tokens were
erroneously deleted, **nobody but the token owner ever had access to it.** Please refer to [the ticket](https://github.com/binwiederhier/ntfy/issues/838)
for details. **Please upgrade your ntfy instance if you run a multi-user system.**
**Features:**
* Add support for [Markdown formatting](publish.md#markdown-formatting) in web app ([#310](https://github.com/binwiederhier/ntfy/issues/310), thanks to [@nihalgonsalves](https://github.com/nihalgonsalves))
* Add support for right-to-left languages (RTL) in the web app ([#663](https://github.com/binwiederhier/ntfy/issues/663), thanks to [@nimbleghost](https://github.com/nimbleghost))
**Security:** ⚠️
* Fixes issue with access tokens getting deleted ([#838](https://github.com/binwiederhier/ntfy/issues/838))
**Bug fixes + maintenance:**
* Fix issues with date/time with different locales ([#700](https://github.com/binwiederhier/ntfy/issues/700), thanks to [@nimbleghost](https://github.com/nimbleghost))
* Re-init i18n on each service worker message to avoid missing translations ([#817](https://github.com/binwiederhier/ntfy/pull/817), thanks to [@nihalgonsalves](https://github.com/nihalgonsalves))
* You can now unset the default user:pass/token in `client.yml` for an individual subscription to remove the Authorization header ([#829](https://github.com/binwiederhier/ntfy/issues/829), thanks to [@tomeon](https://github.com/tomeon) for reporting and to [@wunter8](https://github.com/wunter8) for fixing)
**Documentation:**
* Update docs for Apache config ([#819](https://github.com/binwiederhier/ntfy/pull/819), thanks to [@nisbet-hubbard](https://github.com/nisbet-hubbard))
## ntfy server v2.6.2
Released June 30, 2023
With this release, the ntfy web app now contains a **[progressive web app](subscribe/pwa.md) (PWA)
with Web Push support**, which means you'll be able to **install the ntfy web app on your desktop or phone** similar
to a native app (__even on iOS!__ 🥳). Installing the PWA gives ntfy web its own launcher, a standalone window,
push notifications, and an app badge with the unread notification count. Note that for self-hosted servers,
[Web Push](config.md#web-push) must be configured.
On top of that, this release also brings **dark mode** 🧛🌙 to the web app.
🙏 A huge thanks for this release goes to [@nimbleghost](https://github.com/nimbleghost), for basically implementing the
Web Push / PWA and dark mode feature by himself. I'm really grateful for your contributions.
❤️ If you like ntfy, **please consider sponsoring us** via [GitHub Sponsors](https://github.com/sponsors/binwiederhier)
and [Liberapay](https://en.liberapay.com/ntfy/), or buying a [paid plan via the web app](https://ntfy.sh/app) (20% off
if you use promo code `MYTOPIC`). ntfy will always remain open source.
**Features:**
* The web app now supports Web Push, and is installable as a [progressive web app (PWA)](https://docs.ntfy.sh/subscribe/pwa/) on Chrome, Edge, Android, and iOS ([#751](https://github.com/binwiederhier/ntfy/pull/751), thanks to [@nimbleghost](https://github.com/nimbleghost))
* Support for dark mode in the web app ([#206](https://github.com/binwiederhier/ntfy/issues/206), thanks to [@nimbleghost](https://github.com/nimbleghost))
**Bug fixes:**
* Support encoding any header as RFC 2047 ([#737](https://github.com/binwiederhier/ntfy/issues/737), thanks to [@cfouche3005](https://github.com/cfouche3005) for reporting)
* Do not forward poll requests for UnifiedPush messages (no ticket, thanks to NoName for reporting)
* Fix `ntfy pub %` segfaulting ([#760](https://github.com/binwiederhier/ntfy/issues/760), thanks to [@clesmian](https://github.com/clesmian) for reporting)
* Newly created access tokens are now lowercase only to fully support `<topic>+<token>@<domain>` email syntax ([#773](https://github.com/binwiederhier/ntfy/issues/773), thanks to gingervitiz for reporting)
* The .1 release fixes a few visual issues with dark mode, and other web app updates ([#791](https://github.com/binwiederhier/ntfy/pull/791), [#793](https://github.com/binwiederhier/ntfy/pull/793), [#792](https://github.com/binwiederhier/ntfy/pull/792), thanks to [@nimbleghost](https://github.com/nimbleghost))
* The .2 release fixes issues with the service worker in Firefox and adds automatic service worker updates ([#795](https://github.com/binwiederhier/ntfy/pull/795), thanks to [@nimbleghost](https://github.com/nimbleghost))
**Maintenance:**
* Improved GitHub Actions flow ([#745](https://github.com/binwiederhier/ntfy/pull/745), thanks to [@nimbleghost](https://github.com/nimbleghost))
* Web: Add JS formatter "prettier" ([#746](https://github.com/binwiederhier/ntfy/pull/746), thanks to [@nimbleghost](https://github.com/nimbleghost))
* Web: Add eslint with eslint-config-airbnb ([#748](https://github.com/binwiederhier/ntfy/pull/748), thanks to [@nimbleghost](https://github.com/nimbleghost))
* Web: Switch to Vite ([#749](https://github.com/binwiederhier/ntfy/pull/749), thanks to [@nimbleghost](https://github.com/nimbleghost))
**Changes in tarball/zip naming:**
Due to a [change in GoReleaser](https://goreleaser.com/deprecations/#archivesreplacements), some of the binary release
archives now have slightly different names. My apologies if this causes issues in the downstream projects that use ntfy:
- `ntfy_v${VERSION}_windows_x86_64.zip` -> `ntfy_v${VERSION}_windows_amd64.zip`
- `ntfy_v${VERSION}_linux_x86_64.tar.gz` -> `ntfy_v${VERSION}_linux_amd64.tar.gz`
- `ntfy_v${VERSION}_macOS_all.tar.gz` -> `ntfy_v${VERSION}_darwin_all.tar.gz`
## ntfy server v2.5.0
Released May 18, 2023
This release brings a number of new features, including support for text-to-speech style [phone calls](publish.md#phone-calls),
an admin API to manage users and ACL (currently in beta, and hence undocumented), and support for authorized access to
upstream servers via the `upstream-access-token` config option.
❤️ If you like ntfy, **please consider sponsoring me** via [GitHub Sponsors](https://github.com/sponsors/binwiederhier)
and [Liberapay](https://en.liberapay.com/ntfy/), or by buying a [paid plan via the web app](https://ntfy.sh/app) (20% off
if you use promo code `MYTOPIC`). ntfy will always remain open source.
**Features:**
* Support for text-to-speech style [phone calls](publish.md#phone-calls) using the `X-Call` header (no ticket)
* Admin API to manage users and ACL, `v1/users` + `v1/users/access` (intentionally undocumented as of now, [#722](https://github.com/binwiederhier/ntfy/issues/722), thanks to [@CreativeWarlock](https://github.com/CreativeWarlock) for sponsoring this ticket)
* Added `upstream-access-token` config option to allow authorized access to upstream servers (no ticket)
**Bug fixes + maintenance:**
* Removed old ntfy website from ntfy entirely (no ticket)
* Make emoji lookup for emails more efficient ([#725](https://github.com/binwiederhier/ntfy/pull/725), thanks to [@adamantike](https://github.com/adamantike))
* Fix potential subscriber ID clash ([#712](https://github.com/binwiederhier/ntfy/issues/712), thanks to [@peterbourgon](https://github.com/peterbourgon) for reporting, and [@dropdevrahul](https://github.com/dropdevrahul) for fixing)
* Support for `quoted-printable` in incoming emails ([#719](https://github.com/binwiederhier/ntfy/pull/719), thanks to [@Aerion](https://github.com/Aerion))
* 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
Released Apr 26, 2023
This release adds a tiny `v1/stats` endpoint to expose how many messages have been published, and adds support to encode the `X-Title`,
`X-Message` and `X-Tags` header as RFC 2047. It's a pretty small release, and mainly enables the release of the new ntfy.sh website.
❤️ If you like ntfy, **please consider sponsoring me** via [GitHub Sponsors](https://github.com/sponsors/binwiederhier)
and [Liberapay](https://en.liberapay.com/ntfy/), or by buying a [paid plan via the web app](https://ntfy.sh/app). ntfy
will always remain open source.
**Features:**
* [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) can now be installed via Homebrew (thanks to [@Moulick](https://github.com/Moulick))
* Added `v1/stats` endpoint to expose messages stats (no ticket)
* Support [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2) encoded headers (no ticket, honorable mention to [mqttwarn](https://github.com/jpmens/mqttwarn/pull/638) and [@amotl](https://github.com/amotl))
**Bug fixes + maintenance:**
* Hide country flags on Windows ([#606](https://github.com/binwiederhier/ntfy/issues/606), thanks to [@cmeis](https://github.com/cmeis) for reporting, and to [@pokej6](https://github.com/pokej6) for fixing it)
* `ntfy sub` now uses default auth credentials as defined in `client.yml` ([#698](https://github.com/binwiederhier/ntfy/issues/698), thanks to [@CrimsonFez](https://github.com/CrimsonFez) for reporting, and to [@wunter8](https://github.com/wunter8) for fixing it)
**Documentation:**
* Updated PowerShell examples ([#697](https://github.com/binwiederhier/ntfy/pull/697), thanks to [@Natfan](https://github.com/Natfan))
**Additional languages:**
* Swedish (thanks to [@hellbown](https://hosted.weblate.org/user/Shjosan/))
## 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
@@ -465,7 +915,7 @@ minute or so, due to competing stats gathering (personal installations will like
**Features:**
* Add `cache-startup-queries` option to allow custom [SQLite performance tuning](config.md#wal-for-message-cache) (no ticket)
* Add `cache-startup-queries` option to allow custom [SQLite performance tuning](config.md#message-cache) (no ticket)
* ntfy CLI can now [wait for a command or PID](subscribe/cli.md#wait-for-pidcommand) before publishing ([#263](https://github.com/binwiederhier/ntfy/issues/263), thanks to the [original ntfy](https://github.com/dschep/ntfy) for the idea)
* Trace: Log entire HTTP request to simplify debugging (no ticket)
* Allow setting user password via `NTFY_PASSWORD` env variable ([#327](https://github.com/binwiederhier/ntfy/pull/327), thanks to [@Kenix3](https://github.com/Kenix3))
@@ -1139,7 +1589,7 @@ Released Dec 28, 2021
**Features & bug fixes:**
* [Publish messages via e-mail](ntfy.sh/docs/publish/#e-mail-publishing) #66
* [Publish messages via e-mail](publish.md#e-mail-publishing) #66
* Server-side work to support [unifiedpush.org](https://unifiedpush.org) #64
* Fixing the Santa bug #65
@@ -1149,38 +1599,31 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release
## Not released yet
### ntfy Android app v1.16.1 (UNRELEASED)
### ntfy server v2.16.x (UNRELEASED)
**Features:**
* You can now disable UnifiedPush so ntfy does not act as a UnifiedPush distributor ([#646](https://github.com/binwiederhier/ntfy/issues/646), thanks to [@ollien](https://github.com/ollien) for reporting and to [@wunter8](https://github.com/wunter8) for implementing)
* Support for [updating and deleting notifications](publish.md#updating-deleting-notifications) ([#303](https://github.com/binwiederhier/ntfy/issues/303), [#1536](https://github.com/binwiederhier/ntfy/pull/1536),
[ntfy-android#151](https://github.com/binwiederhier/ntfy-android/pull/151), thanks to [@wunter8](https://github.com/wunter8) for the initial implementation)
* Support for a [custom Twilio call format](config.md#phone-calls) ([#1289](https://github.com/binwiederhier/ntfy/pull/1289), thanks to [@mmichaa](https://github.com/mmichaa) for the initial implementation)
**Bug fixes + maintenance:**
* UnifiedPush subscriptions now include the `Rate-Topics` header to facilitate subscriber-based billing ([#652](https://github.com/binwiederhier/ntfy/issues/652), thanks to [@wunter8](https://github.com/wunter8))
* Subscriptions without icons no longer appear to use another subscription's icon ([#634](https://github.com/binwiederhier/ntfy/issues/634), thanks to [@topcaser](https://github.com/topcaser) for reporting and to [@wunter8](https://github.com/wunter8) for fixing)
**Additional languages:**
* Swedish (thanks to [@hellbown](https://hosted.weblate.org/user/hellbown/))
### ntfy server v2.4.0 (UNRELEASED)
### ntfy Android app v1.22.x (UNRELEASED)
**Features:**
* [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) can now be installed via Homebrew (thanks to [@Moulick](https://github.com/Moulick))
* Added `v1/stats` endpoint to expose messages stats (no ticket)
* Support [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2) encoded headers (no ticket, honorable mention to [mqttwarn](https://github.com/jpmens/mqttwarn/pull/638) and [@amotl](https://github.com/amotl))
* Support for [updating and deleting notifications](publish.md#updating-deleting-notifications)
([#303](https://github.com/binwiederhier/ntfy/issues/303), [#1536](https://github.com/binwiederhier/ntfy/pull/1536),
[ntfy-android#151](https://github.com/binwiederhier/ntfy-android/pull/151), thanks to [@wunter8](https://github.com/wunter8)
for the initial implementation)
* Support for self-signed certs and client certs for mTLS ([#215](https://github.com/binwiederhier/ntfy/issues/215),
[#530](https://github.com/binwiederhier/ntfy/issues/530), [ntfy-android#149](https://github.com/binwiederhier/ntfy-android/pull/149),
thanks to [@cyb3rko](https://github.com/cyb3rko) for reviewing)
* Connection error dialog to help diagnose connection issues
**Bug fixes + maintenance:**
* Hide country flags on Windows ([#606](https://github.com/binwiederhier/ntfy/issues/606), thanks to [@cmeis](https://github.com/cmeis) for reporting, and to [@pokej6](https://github.com/pokej6) for fixing it)
* `ntfy sub` now uses default auth credentials as defined in `client.yml` ([#698](https://github.com/binwiederhier/ntfy/issues/698), thanks to [@CrimsonFez](https://github.com/CrimsonFez) for reporting, and to [@wunter8](https://github.com/wunter8) for fixing it)
**Documentation:**
* Updated PowerShell examples ([#697](https://github.com/binwiederhier/ntfy/pull/697), thanks to [@Natfan](https://github.com/Natfan))
**Additional languages:**
* Swedish (thanks to [@hellbown](https://hosted.weblate.org/user/Shjosan/))
* Use server-specific user for attachment downloads ([#1529](https://github.com/binwiederhier/ntfy/issues/1529),
thanks to [@ManInDark](https://github.com/ManInDark) for reporting and testing)
* Fix crash in sharing dialog (thanks to [@rogeliodh](https://github.com/rogeliodh))
* Fix crash when exiting multi-delete in detail view
* Fix potential crashes with icon downloader and backuper

BIN
docs/static/audio/ntfy-phone-call.mp3 vendored Normal file

Binary file not shown.

BIN
docs/static/audio/ntfy-phone-call.ogg vendored Normal file

Binary file not shown.

View File

@@ -1,10 +1,10 @@
:root > * {
--md-primary-fg-color: #338574;
--md-primary-fg-color: #338574;
--md-primary-fg-color--light: #338574;
--md-primary-fg-color--dark: #338574;
--md-footer-bg-color: #353744;
--md-text-font: "Roboto";
--md-code-font: "Roboto Mono";
--md-primary-fg-color--dark: #338574;
--md-footer-bg-color: #353744;
--md-text-font: "Roboto";
--md-code-font: "Roboto Mono";
}
.md-header__button.md-logo :is(img, svg) {
@@ -34,7 +34,7 @@ figure img, figure video {
}
header {
background: linear-gradient(150deg, rgba(51,133,116,1) 0%, rgba(86,189,168,1) 100%);
background: linear-gradient(150deg, rgba(51, 133, 116, 1) 0%, rgba(86, 189, 168, 1) 100%);
}
body[data-md-color-scheme="default"] header {
@@ -93,7 +93,7 @@ figure video {
.screenshots img {
max-height: 230px;
max-width: 300px;
max-width: 350px;
margin: 3px;
border-radius: 5px;
filter: drop-shadow(2px 2px 2px #ddd);
@@ -107,7 +107,7 @@ figure video {
opacity: 0;
visibility: hidden;
position: fixed;
left:0;
left: 0;
right: 0;
top: 0;
bottom: 0;
@@ -119,7 +119,7 @@ figure video {
}
.lightbox.show {
background-color: rgba(0,0,0, 0.75);
background-color: rgba(0, 0, 0, 0.75);
opacity: 1;
visibility: visible;
z-index: 1000;

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
docs/static/img/cdio-setup.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

BIN
docs/static/img/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
docs/static/img/pwa-badge.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
docs/static/img/pwa-install.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
docs/static/img/pwa.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
docs/static/img/web-markdown.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

BIN
docs/static/img/web-phone-verify.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Some files were not shown because too many files have changed in this diff Show More