From 6fbcd85d17568fed75d847c563f75d04bdaf51ca Mon Sep 17 00:00:00 2001 From: srevn Date: Sun, 6 Jul 2025 10:23:32 +0300 Subject: [PATCH 1/4] Add piping support --- cmd/publish.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cmd/publish.go b/cmd/publish.go index aaec35e9..89475fbd 100644 --- a/cmd/publish.go +++ b/cmd/publish.go @@ -254,6 +254,16 @@ func parseTopicMessageCommand(c *cli.Context) (topic string, message string, com if c.String("message") != "" { message = c.String("message") } + + // If no message provided and stdin has data, read from stdin + if message == "" && stdinHasData() { + var stdinBytes []byte + stdinBytes, err = io.ReadAll(c.App.Reader) + if err != nil { + return + } + message = strings.TrimSpace(string(stdinBytes)) + } return } @@ -312,3 +322,11 @@ 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 stdinHasData() bool { + stat, err := os.Stdin.Stat() + if err != nil { + return false + } + return (stat.Mode() & os.ModeCharDevice) == 0 +} From 04aff72631b1b23a7a327cee097023211bed009e Mon Sep 17 00:00:00 2001 From: srevn Date: Sun, 6 Jul 2025 10:51:28 +0300 Subject: [PATCH 2/4] Add example and logging --- cmd/publish.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/publish.go b/cmd/publish.go index 89475fbd..1d04b537 100644 --- a/cmd/publish.go +++ b/cmd/publish.go @@ -69,6 +69,7 @@ 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 + 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 @@ -260,6 +261,7 @@ func parseTopicMessageCommand(c *cli.Context) (topic string, message string, com var stdinBytes []byte stdinBytes, err = io.ReadAll(c.App.Reader) if err != nil { + log.Debug("Failed to read from stdin: %v", err) return } message = strings.TrimSpace(string(stdinBytes)) @@ -326,6 +328,7 @@ func runAndWaitForCommand(command []string) (message string, err error) { func stdinHasData() bool { stat, err := os.Stdin.Stat() if err != nil { + log.Debug("Failed to stat stdin: %v", err) return false } return (stat.Mode() & os.ModeCharDevice) == 0 From 9ed96e5d8b16944d40a6e2e6a2ddf924112a2fc5 Mon Sep 17 00:00:00 2001 From: srevn Date: Sun, 6 Jul 2025 16:31:03 +0300 Subject: [PATCH 3/4] Small cosmetic fixes --- cmd/publish.go | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/cmd/publish.go b/cmd/publish.go index 1d04b537..d1ccf79a 100644 --- a/cmd/publish.go +++ b/cmd/publish.go @@ -255,16 +255,14 @@ func parseTopicMessageCommand(c *cli.Context) (topic string, message string, com if c.String("message") != "" { message = c.String("message") } - - // If no message provided and stdin has data, read from stdin - if message == "" && stdinHasData() { - var stdinBytes []byte - stdinBytes, err = io.ReadAll(c.App.Reader) + if message == "" && isStdinRedirected() { + var bytes []byte + bytes, err = io.ReadAll(c.App.Reader) if err != nil { - log.Debug("Failed to read from stdin: %v", err) + log.Debug("Failed to read from stdin: %s", err.Error()) return } - message = strings.TrimSpace(string(stdinBytes)) + message = strings.TrimSpace(string(bytes)) } return } @@ -325,10 +323,10 @@ func runAndWaitForCommand(command []string) (message string, err error) { return fmt.Sprintf("Command succeeded after %s: %s", runtime, prettyCmd), nil } -func stdinHasData() bool { +func isStdinRedirected() bool { stat, err := os.Stdin.Stat() if err != nil { - log.Debug("Failed to stat stdin: %v", err) + log.Debug("Failed to stat stdin: %s", err.Error()) return false } return (stat.Mode() & os.ModeCharDevice) == 0 From 47da3aeea6ab36cbe7f5990282bb1028334ba8c6 Mon Sep 17 00:00:00 2001 From: srevn Date: Sun, 6 Jul 2025 17:53:04 +0300 Subject: [PATCH 4/4] fix unbounded read --- cmd/publish.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/publish.go b/cmd/publish.go index d1ccf79a..c15761ab 100644 --- a/cmd/publish.go +++ b/cmd/publish.go @@ -256,13 +256,13 @@ func parseTopicMessageCommand(c *cli.Context) (topic string, message string, com message = c.String("message") } if message == "" && isStdinRedirected() { - var bytes []byte - bytes, err = io.ReadAll(c.App.Reader) + 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(bytes)) + message = strings.TrimSpace(string(data)) } return }