Browse Source

Ntfy with custom server and authentication support

master
Jan-Lukas Else 2 months ago
parent
commit
92172d6404
  1. 2
      activityPub.go
  2. 3
      config.go
  3. 5
      example-config.yml
  4. 6
      go.mod
  5. 12
      go.sum
  6. 19
      ntfy.go
  7. 74
      ntfy_test.go

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

3
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 {

5
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)

6
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

12
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=

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

74
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",
},
}
app.sendNotification("Test notification")
req := fakeClient.req
require.NotNil(t, req)
assert.Equal(t, http.MethodPost, req.Method)
assert.Equal(t, "https://ntfy.sh/topic", req.URL.String())
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)
})
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())
req := fakeClient.req
user, pass, _ := req.BasicAuth()
assert.Equal(t, "user", user)
assert.Equal(t, "pass", pass)
require.NotNil(t, req)
assert.Equal(t, http.MethodPost, req.Method)
assert.Equal(t, "https://example.com/topic", req.URL.String())
reqBody, _ := req.GetBody()
reqBodyByte, _ := io.ReadAll(reqBody)
reqBody, _ := req.GetBody()
reqBodyByte, _ := io.ReadAll(reqBody)
assert.Equal(t, "Test notification", string(reqBodyByte))
assert.Equal(t, "Test notification", string(reqBodyByte))
res := fakeClient.res
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())
}

Loading…
Cancel
Save