Hunter Kehoe 2 лет назад
Родитель
Сommit
b80aec90d0
7 измененных файлов с 95 добавлено и 15 удалено
  1. 4 1
      client/client.yml
  2. 2 2
      client/config.go
  3. 6 6
      client/config_test.go
  4. 15 0
      client/options.go
  5. 9 4
      cmd/subscribe.go
  6. 58 2
      cmd/subscribe_test.go
  7. 1 0
      docs/releases.md

+ 4 - 1
client/client.yml

@@ -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:
 

+ 2 - 2
client/config.go

@@ -23,9 +23,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"`
 }

+ 6 - 6
client/config_test.go

@@ -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)
 }

+ 15 - 0
client/options.go

@@ -97,6 +97,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")
@@ -187,3 +192,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
+	}
+}

+ 9 - 4
cmd/subscribe.go

@@ -225,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 {
+	// 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()
+	}
+
 	// check for subscription token then subscription user:pass
-	if s.Token != "" {
-		return client.WithBearerAuth(s.Token)
+	if s.Token != nil && *s.Token != "" {
+		return client.WithBearerAuth(*s.Token)
 	}
-	if s.User != "" && s.Password != nil {
-		return client.WithBasicAuth(s.User, *s.Password)
+	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

+ 58 - 2
cmd/subscribe_test.go

@@ -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()))
 }

+ 1 - 0
docs/releases.md

@@ -1262,6 +1262,7 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release
 
 * 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)
 
 ### ntfy Android app v1.16.1 (UNRELEASED)