From 92172d64043cc2bb5c9035030b3285e96b412d83 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Else Date: Mon, 4 Apr 2022 13:07:36 +0200 Subject: [PATCH] Ntfy with custom server and authentication support --- activityPub.go | 2 +- config.go | 3 ++ example-config.yml | 5 +++- go.mod | 6 ++-- go.sum | 12 ++++---- ntfy.go | 19 +++++++++--- ntfy_test.go | 74 +++++++++++++++++++++++++++++++++++----------- 7 files changed, 88 insertions(+), 33 deletions(-) diff --git a/activityPub.go b/activityPub.go index c33cf0f..45ebc3b 100644 --- a/activityPub.go +++ b/activityPub.go @@ -336,7 +336,7 @@ func (a *goBlog) apUndelete(p *post) { // Update "activityPubVersion" parameter to current timestamp in nanoseconds p.Parameters[activityPubVersionParam] = []string{fmt.Sprintf("%d", utcNowNanos())} - a.db.replacePostParam(p.Path, activityPubVersionParam, p.Parameters[activityPubVersionParam]) + _ = a.db.replacePostParam(p.Path, activityPubVersionParam, p.Parameters[activityPubVersionParam]) // Post as new post a.apPost(p) } diff --git a/config.go b/config.go index dd2a9a6..65234ce 100644 --- a/config.go +++ b/config.go @@ -267,6 +267,9 @@ type configNotifications struct { type configNtfy struct { Enabled bool `mapstructure:"enabled"` Topic string `mapstructure:"topic"` + Server string `mapstructure:"server"` + User string `mapstructure:"user"` + Pass string `mapstructure:"pass"` } type configTelegram struct { diff --git a/example-config.yml b/example-config.yml index abf4474..84ab060 100644 --- a/example-config.yml +++ b/example-config.yml @@ -131,7 +131,10 @@ micropub: notifications: ntfy: # Receive notifications using Ntfy.sh enabled: true # Enable it - topic: ntfy.sh/mynotificationstopic # The topic for the notifications + topic: mynotificationstopic # The topic for the notifications + server: https://ntfy.sh # The server to use (default is https://ntfy.sh) + user: myusername # The username to use (optional) + password: mypassword # The password to use (optional) telegram: # Receive notifications via Telegram enabled: true # Enable it chatId: 123456 # Telegram chat ID (usually the user id on Telegram) diff --git a/go.mod b/go.mod index f4ffa51..c64535d 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/alecthomas/chroma v0.10.0 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2 - github.com/carlmjohnson/requests v0.22.1 + github.com/carlmjohnson/requests v0.22.2 github.com/cretz/bine v0.2.0 github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f github.com/dgraph-io/ristretto v0.1.0 @@ -57,8 +57,8 @@ require ( github.com/yuin/goldmark v1.4.11 // master github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38 - golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 - golang.org/x/net v0.0.0-20220325170049-de3da57026de + golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 + golang.org/x/net v0.0.0-20220403103023-749bd193bc2b golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/text v0.3.7 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b diff --git a/go.sum b/go.sum index e6860f4..7f93c87 100644 --- a/go.sum +++ b/go.sum @@ -68,8 +68,8 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8 github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2 h1:t8KYCwSKsOEZBFELI4Pn/phbp38iJ1RRAkDFNin1aak= github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= -github.com/carlmjohnson/requests v0.22.1 h1:YoifpEbpJW4LPRX/+0dJe3vTLducEE9Ib10k6lElIUM= -github.com/carlmjohnson/requests v0.22.1/go.mod h1:Hw4fFOk3xDlHQbNRTGo4oc52TUTpVEq93sNy/H+mrQM= +github.com/carlmjohnson/requests v0.22.2 h1:hccG5g9ITJlnDip54OVa810AkB366kthFjvA90N4owM= +github.com/carlmjohnson/requests v0.22.2/go.mod h1:Hw4fFOk3xDlHQbNRTGo4oc52TUTpVEq93sNy/H+mrQM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= @@ -488,8 +488,8 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s= -golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o= +golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -575,8 +575,8 @@ golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de h1:pZB1TWnKi+o4bENlbzAgLrEbY4RMYmUIRobMcSmfeYc= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0= +golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= diff --git a/ntfy.go b/ntfy.go index e650200..9f430b0 100644 --- a/ntfy.go +++ b/ntfy.go @@ -19,11 +19,22 @@ func (a *goBlog) sendNtfy(cfg *configNtfy, msg string) error { if !cfg.enabled() { return nil } - return requests. - URL(cfg.Topic). + topic := cfg.Topic + if strings.HasPrefix(topic, "ntfy.sh/") { // Old configuration example + topic = strings.TrimPrefix(topic, "ntfy.sh/") + } + server := "https://ntfy.sh" + if cfg.Server != "" { + server = cfg.Server + } + builder := requests. + URL(server + "/" + topic). Client(a.httpClient). UserAgent(appUserAgent). Method(http.MethodPost). - BodyReader(strings.NewReader(msg)). - Fetch(context.Background()) + BodyReader(strings.NewReader(msg)) + if cfg.User != "" { + builder.BasicAuth(cfg.User, cfg.Pass) + } + return builder.Fetch(context.Background()) } diff --git a/ntfy_test.go b/ntfy_test.go index f3a6603..3f05138 100644 --- a/ntfy_test.go +++ b/ntfy_test.go @@ -17,35 +17,73 @@ func Test_ntfySending(t *testing.T) { cfg: createDefaultTestConfig(t), httpClient: fakeClient.Client, } - app.cfg.Notifications = &configNotifications{ - Ntfy: &configNtfy{ - Enabled: true, - Topic: "example.com/topic", - }, - } _ = app.initConfig() _ = app.initDatabase(false) defer app.db.close() app.initComponents(false) - app.sendNotification("Test notification") + t.Run("Default", func(t *testing.T) { + app.cfg.Notifications = &configNotifications{ + Ntfy: &configNtfy{ + Enabled: true, + Topic: "topic", + }, + } - req := fakeClient.req + app.sendNotification("Test notification") - require.NotNil(t, req) - assert.Equal(t, http.MethodPost, req.Method) - assert.Equal(t, "https://example.com/topic", req.URL.String()) + req := fakeClient.req - reqBody, _ := req.GetBody() - reqBodyByte, _ := io.ReadAll(reqBody) + require.NotNil(t, req) + assert.Equal(t, http.MethodPost, req.Method) + assert.Equal(t, "https://ntfy.sh/topic", req.URL.String()) - assert.Equal(t, "Test notification", string(reqBodyByte)) + reqBody, _ := req.GetBody() + reqBodyByte, _ := io.ReadAll(reqBody) - res := fakeClient.res + assert.Equal(t, "Test notification", string(reqBodyByte)) + + res := fakeClient.res + + require.NotNil(t, res) + assert.Equal(t, http.StatusOK, res.StatusCode) + }) + + t.Run("Custom server with Basic Auth", func(t *testing.T) { + app.cfg.Notifications = &configNotifications{ + Ntfy: &configNtfy{ + Enabled: true, + Topic: "topic", + Server: "https://ntfy.example.com", + User: "user", + Pass: "pass", + }, + } + + app.sendNotification("Test notification") + + req := fakeClient.req + + require.NotNil(t, req) + assert.Equal(t, http.MethodPost, req.Method) + assert.Equal(t, "https://ntfy.example.com/topic", req.URL.String()) + + user, pass, _ := req.BasicAuth() + assert.Equal(t, "user", user) + assert.Equal(t, "pass", pass) + + reqBody, _ := req.GetBody() + reqBodyByte, _ := io.ReadAll(reqBody) + + assert.Equal(t, "Test notification", string(reqBodyByte)) + + res := fakeClient.res + + require.NotNil(t, res) + assert.Equal(t, http.StatusOK, res.StatusCode) + }) - require.NotNil(t, res) - assert.Equal(t, http.StatusOK, res.StatusCode) } func Test_ntfyConfig(t *testing.T) { @@ -61,7 +99,7 @@ func Test_ntfyConfig(t *testing.T) { assert.False(t, cfg.enabled()) - cfg.Topic = "example.com/topic" + cfg.Topic = "topic" assert.True(t, cfg.enabled()) }