feat(ntfy): support HTTP Basic auth alongside access tokens
CI / Build (windows/amd64) (pull_request) Successful in 22s
CI / Build (linux/amd64) (pull_request) Successful in 22s
CI / Build (linux/arm64) (pull_request) Successful in 21s
CI / Lint (pull_request) Successful in 1m12s
CI / Test (linux/amd64) (pull_request) Successful in 1m18s

Self-hosted ntfy that doesn't expose a token-mint endpoint can still
authenticate over HTTP Basic. Add Username + Password fields to
NtfyConfig; the channel sends 'Authorization: Basic …' when token is
empty and username is set. Token wins when both are configured.

Form-side: two new optional fields next to the access token, with
the same write-only placeholder treatment as smtp_password (blank
on edit means 'keep stored value'). Username is round-tripped on
edit; password is masked.
This commit is contained in:
2026-05-04 22:25:42 +01:00
parent cffad4b4f3
commit feaeff217d
3 changed files with 42 additions and 7 deletions
+17 -4
View File
@@ -79,6 +79,8 @@ type notificationForm struct {
NtfyServerURL string
NtfyTopic string
NtfyAccessToken string
NtfyUsername string
NtfyPassword string
// SMTP sub-fields.
SMTPHost string
@@ -188,6 +190,8 @@ func formFromRequest(r *stdhttp.Request) *notificationForm {
NtfyServerURL: strings.TrimSpace(r.PostForm.Get("ntfy_server_url")),
NtfyTopic: strings.TrimSpace(r.PostForm.Get("ntfy_topic")),
NtfyAccessToken: r.PostForm.Get("ntfy_access_token"),
NtfyUsername: strings.TrimSpace(r.PostForm.Get("ntfy_username")),
NtfyPassword: r.PostForm.Get("ntfy_password"),
SMTPHost: strings.TrimSpace(r.PostForm.Get("smtp_host")),
SMTPPort: strings.TrimSpace(r.PostForm.Get("smtp_port")),
@@ -288,11 +292,19 @@ func buildConfig(f *notificationForm, existing any) (any, error) {
ServerURL: f.NtfyServerURL,
Topic: f.NtfyTopic,
AccessToken: f.NtfyAccessToken,
Username: f.NtfyUsername,
Password: f.NtfyPassword,
}
if existing != nil {
ex, ok := existing.(*notification.NtfyConfig)
if ok && cfg.AccessToken == "" {
cfg.AccessToken = ex.AccessToken
if ex, ok := existing.(*notification.NtfyConfig); ok {
// Blank password on edit means "keep stored value"
// — same write-only treatment as smtp_password.
if cfg.AccessToken == "" {
cfg.AccessToken = ex.AccessToken
}
if cfg.Password == "" {
cfg.Password = ex.Password
}
}
}
return cfg, nil
@@ -479,7 +491,8 @@ func (s *Server) handleUINotificationEditGet(w stdhttp.ResponseWriter, r *stdhtt
if err := s.decryptChannelConfig(*ch, &cfg); err == nil {
f.NtfyServerURL = cfg.ServerURL
f.NtfyTopic = cfg.Topic
// AccessToken is write-only.
f.NtfyUsername = cfg.Username
// AccessToken and Password are write-only.
}
case "smtp":
var cfg notification.SMTPConfig