Compare commits

...

6 Commits

Author SHA1 Message Date
Philipp C. Heckel
3daa590732 Update LICENSE.GPLv2 2021-12-05 12:52:20 -05:00
Philipp C. Heckel
dadb6419ee Update LICENSE 2021-12-05 12:51:08 -05:00
Philipp Heckel
6fbbb0c7b5 Properly handle systemd start/stop during Debian package install, closes #30 2021-12-04 15:32:21 -05:00
Philipp Heckel
07a1fe3acb Add TLS/HTTPS 2021-12-02 08:52:48 -05:00
Philipp Heckel
1e7ae885b4 Update examples 2021-11-29 15:34:29 -05:00
Philipp Heckel
9d37217eba Bump version 2021-11-29 11:52:35 -05:00
14 changed files with 107 additions and 20 deletions

View File

@@ -53,6 +53,8 @@ nfpms:
- src: config/ntfy.service
dst: /lib/systemd/system/ntfy.service
scripts:
postinstall: "scripts/postinst.sh"
preremove: "scripts/prerm.sh"
postremove: "scripts/postrm.sh"
archives:
-

View File

@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Copyright 2021 Philipp C. Heckel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -290,8 +290,8 @@ to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
ntfy
Copyright (C) 2021 Philipp C. Heckel
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -138,13 +138,13 @@ sudo apt install ntfy
**Debian/Ubuntu** (*manual install*)**:**
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.4.8/ntfy_1.4.8_amd64.deb
dpkg -i ntfy_1.4.8_amd64.deb
wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_amd64.deb
dpkg -i ntfy_1.5.0_amd64.deb
```
**Fedora/RHEL/CentOS:**
```bash
rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.4.8/ntfy_1.4.8_amd64.rpm
rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_amd64.rpm
```
**Docker:**
@@ -171,13 +171,13 @@ go get -u heckel.io/ntfy
**Manual install:**
```bash
# x86_64/amd64
wget https://github.com/binwiederhier/ntfy/releases/download/v1.4.8/ntfy_1.4.8_linux_x86_64.tar.gz
wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_x86_64.tar.gz
# armv7
wget https://github.com/binwiederhier/ntfy/releases/download/v1.4.8/ntfy_1.4.8_linux_armv7.tar.gz
wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_armv7.tar.gz
# arm64/v8
wget https://github.com/binwiederhier/ntfy/releases/download/v1.4.8/ntfy_1.4.8_linux_arm64.tar.gz
wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_arm64.tar.gz
# Extract and run
sudo tar -C /usr/bin -zxf ntfy_*.tar.gz ntfy

View File

@@ -18,7 +18,10 @@ import (
func New() *cli.App {
flags := []cli.Flag{
&cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: "/etc/ntfy/config.yml", DefaultText: "/etc/ntfy/config.yml", Usage: "config file"},
altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-http", Aliases: []string{"l"}, EnvVars: []string{"NTFY_LISTEN_HTTP"}, Value: config.DefaultListenHTTP, Usage: "ip:port used to as listen address"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-http", Aliases: []string{"l"}, EnvVars: []string{"NTFY_LISTEN_HTTP"}, Value: config.DefaultListenHTTP, Usage: "ip:port used to as HTTP listen address"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-https", Aliases: []string{"L"}, EnvVars: []string{"NTFY_LISTEN_HTTPS"}, Usage: "ip:port used to as HTTPS listen address"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "key-file", Aliases: []string{"K"}, EnvVars: []string{"NTFY_KEY_FILE"}, Usage: "private key file, if listen-https is set"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "cert-file", Aliases: []string{"E"}, EnvVars: []string{"NTFY_CERT_FILE"}, Usage: "certificate file, if listen-https is set"}),
altsrc.NewStringFlag(&cli.StringFlag{Name: "firebase-key-file", Aliases: []string{"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{"C"}, EnvVars: []string{"NTFY_CACHE_FILE"}, Usage: "cache file used for message caching"}),
altsrc.NewDurationFlag(&cli.DurationFlag{Name: "cache-duration", Aliases: []string{"b"}, EnvVars: []string{"NTFY_CACHE_DURATION"}, Value: config.DefaultCacheDuration, Usage: "buffer messages for this time to allow `since` requests"}),
@@ -50,6 +53,9 @@ func New() *cli.App {
func execRun(c *cli.Context) error {
// Read all the options
listenHTTP := c.String("listen-http")
listenHTTPS := c.String("listen-https")
keyFile := c.String("key-file")
certFile := c.String("cert-file")
firebaseKeyFile := c.String("firebase-key-file")
cacheFile := c.String("cache-file")
cacheDuration := c.Duration("cache-duration")
@@ -70,10 +76,19 @@ func execRun(c *cli.Context) error {
return errors.New("manager interval cannot be lower than five seconds")
} else if cacheDuration < managerInterval {
return errors.New("cache duration cannot be lower than manager interval")
} else if keyFile != "" && !util.FileExists(keyFile) {
return errors.New("if set, key file must exist")
} else if certFile != "" && !util.FileExists(certFile) {
return errors.New("if set, certificate file must exist")
} else if listenHTTPS != "" && (keyFile == "" || certFile == "") {
return errors.New("if listen-https is set, both key-file and cert-file must be set")
}
// Run server
conf := config.New(listenHTTP)
conf.ListenHTTPS = listenHTTPS
conf.KeyFile = keyFile
conf.CertFile = certFile
conf.FirebaseKeyFile = firebaseKeyFile
conf.CacheFile = cacheFile
conf.CacheDuration = cacheDuration

View File

@@ -27,6 +27,9 @@ const (
// Config is the main config struct for the application. Use New to instantiate a default config struct.
type Config struct {
ListenHTTP string
ListenHTTPS string
KeyFile string
CertFile string
FirebaseKeyFile string
CacheFile string
CacheDuration time.Duration
@@ -43,6 +46,9 @@ type Config struct {
func New(listenHTTP string) *Config {
return &Config{
ListenHTTP: listenHTTP,
ListenHTTPS: "",
KeyFile: "",
CertFile: "",
FirebaseKeyFile: "",
CacheFile: "",
CacheDuration: DefaultCacheDuration,

View File

@@ -5,6 +5,21 @@
#
# listen-http: ":80"
# Listen address for the HTTPS web server. If set, you must also set "key-file" and "cert-file".
# Format: <hostname>:<port>
#
# listen-https:
# Path to the private key file for the HTTPS web server. Not used if "listen-https" is not set.
# Format: <filename>
#
# key-file:
# Path to the cert file for the HTTPS web server. Not used if "listen-https" is not set.
# Format: <filename>
#
# cert-file:
# If set, also publish messages to a Firebase Cloud Messaging (FCM) topic for your app.
# This is optional and only required to support Android apps (which don't allow background services anymore).
#

View File

@@ -2,6 +2,8 @@
# This is an example shell script showing how to consume a ntfy.sh topic using
# a simple script. The notify-send command sends any arriving message as a desktop notification.
TOPIC_URL=ntfy.sh/mytopic
while read msg; do
[ -n "$msg" ] && notify-send "$msg"
done < <(stdbuf -i0 -o0 curl -s ntfy.sh/mytopic/raw)
done < <(stdbuf -i0 -o0 curl -s $TOPIC_URL/raw)

View File

@@ -2,6 +2,8 @@
# This is a PAM script hook that shows how to notify you when
# somebody logs into your server. Place at /usr/local/bin/ntfy-ssh-login.sh (with chmod +x!).
TOPIC_URL=ntfy.sh/alerts
if [ "${PAM_TYPE}" = "open_session" ]; then
echo -en "\u26A0\uFE0F SSH login to $(hostname): ${PAM_USER} from ${PAM_RHOST}" | curl -T- ntfy.sh/alerts
curl -H tags:warning -H prio:high -d "SSH login to $(hostname): ${PAM_USER} from ${PAM_RHOST}" "${TOPIC_URL}"
fi

19
scripts/postinst.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/bin/sh
set -e
# Restart systemd service if it was already running. Note that "deb-systemd-invoke try-restart" will
# only act if the service is already running. If it's not running, it's a no-op.
#
# TODO: This is only tested on Debian.
#
if [ "$1" = "configure" ] && [ -d /run/systemd/system ]; then
systemctl --system daemon-reload >/dev/null || true
if systemctl is-active -q ntfy.service; then
echo "Restarting ntfy.service ..."
if [ -x /usr/bin/deb-systemd-invoke ]; then
deb-systemd-invoke try-restart ntfy.service >/dev/null || true
else
systemctl restart ntfy.service >/dev/null || true
fi
fi
fi

View File

@@ -1,6 +1,8 @@
#!/bin/sh
set -eu
systemctl stop ntfy >/dev/null 2>&1 || true
set -e
# Delete the config if package is purged
if [ "$1" = "purge" ]; then
rm -rf /etc/ntfy
echo "Deleting /etc/ntfy ..."
rm -rf /etc/ntfy || true
fi

12
scripts/prerm.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/sh
set -e
# Stop systemd service
if [ -d /run/systemd/system ] && [ "$1" = remove ]; then
echo "Stopping ntfy.service ..."
if [ -x /usr/bin/deb-systemd-invoke ]; then
deb-systemd-invoke stop 'ntfy.service' >/dev/null || true
else
systemctl stop ntfy >/dev/null 2>&1 || true
fi
fi

View File

@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
_ "github.com/mattn/go-sqlite3" // SQLite driver
"log"
"strings"
"time"
)
@@ -210,6 +211,7 @@ func setupNewDB(db *sql.DB) error {
}
func migrateFrom0To1(db *sql.DB) error {
log.Print("Migrating cache database schema: from 0 to 1")
if _, err := db.Exec(migrate0To1AlterMessagesTableQuery); err != nil {
return err
}

View File

@@ -173,13 +173,23 @@ func (s *Server) Run() error {
s.updateStatsAndExpire()
}
}()
return s.listenAndServe()
}
listenStr := fmt.Sprintf("%s/http", s.config.ListenHTTP)
if s.config.ListenHTTPS != "" {
listenStr += fmt.Sprintf(" %s/https", s.config.ListenHTTPS)
}
log.Printf("Listening on %s", listenStr)
func (s *Server) listenAndServe() error {
log.Printf("Listening on %s", s.config.ListenHTTP)
http.HandleFunc("/", s.handle)
return http.ListenAndServe(s.config.ListenHTTP, nil)
errChan := make(chan error)
go func() {
errChan <- http.ListenAndServe(s.config.ListenHTTP, nil)
}()
if s.config.ListenHTTPS != "" {
go func() {
errChan <- http.ListenAndServeTLS(s.config.ListenHTTPS, s.config.CertFile, s.config.KeyFile, nil)
}()
}
return <-errChan
}
func (s *Server) handle(w http.ResponseWriter, r *http.Request) {