Adding upstream version 0.8.9.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
3b2c48b5e4
commit
c0c4addb85
285 changed files with 25880 additions and 0 deletions
148
pkg/services/gotify/gotify.go
Normal file
148
pkg/services/gotify/gotify.go
Normal file
|
@ -0,0 +1,148 @@
|
|||
package gotify
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/nicholas-fedor/shoutrrr/pkg/format"
|
||||
"github.com/nicholas-fedor/shoutrrr/pkg/services/standard"
|
||||
"github.com/nicholas-fedor/shoutrrr/pkg/types"
|
||||
"github.com/nicholas-fedor/shoutrrr/pkg/util/jsonclient"
|
||||
)
|
||||
|
||||
const (
|
||||
// HTTPTimeout defines the HTTP client timeout in seconds.
|
||||
HTTPTimeout = 10
|
||||
TokenLength = 15
|
||||
// TokenChars specifies the valid characters for a Gotify token.
|
||||
TokenChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_"
|
||||
)
|
||||
|
||||
// ErrInvalidToken indicates an invalid Gotify token format or content.
|
||||
var ErrInvalidToken = errors.New("invalid gotify token")
|
||||
|
||||
// Service implements a Gotify notification service.
|
||||
type Service struct {
|
||||
standard.Standard
|
||||
Config *Config
|
||||
pkr format.PropKeyResolver
|
||||
httpClient *http.Client
|
||||
client jsonclient.Client
|
||||
}
|
||||
|
||||
// Initialize configures the service with a URL and logger.
|
||||
//
|
||||
//nolint:gosec
|
||||
func (service *Service) Initialize(configURL *url.URL, logger types.StdLogger) error {
|
||||
service.SetLogger(logger)
|
||||
service.Config = &Config{
|
||||
Title: "Shoutrrr notification",
|
||||
}
|
||||
service.pkr = format.NewPropKeyResolver(service.Config)
|
||||
|
||||
err := service.Config.SetURL(configURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
service.httpClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
// InsecureSkipVerify disables TLS certificate verification when true.
|
||||
// This is set to Config.DisableTLS to support HTTP or self-signed certificate setups,
|
||||
// but it reduces security by allowing potential man-in-the-middle attacks.
|
||||
InsecureSkipVerify: service.Config.DisableTLS,
|
||||
},
|
||||
},
|
||||
Timeout: HTTPTimeout * time.Second,
|
||||
}
|
||||
if service.Config.DisableTLS {
|
||||
service.Log("Warning: TLS verification is disabled, making connections insecure")
|
||||
}
|
||||
|
||||
service.client = jsonclient.NewWithHTTPClient(service.httpClient)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetID returns the identifier for this service.
|
||||
func (service *Service) GetID() string {
|
||||
return Scheme
|
||||
}
|
||||
|
||||
// isTokenValid checks if a Gotify token meets length and character requirements.
|
||||
// Rules are based on Gotify's token validation logic.
|
||||
func isTokenValid(token string) bool {
|
||||
if len(token) != TokenLength || token[0] != 'A' {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, c := range token {
|
||||
if !strings.ContainsRune(TokenChars, c) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// buildURL constructs the Gotify API URL with scheme, host, path, and token.
|
||||
func buildURL(config *Config) (string, error) {
|
||||
token := config.Token
|
||||
if !isTokenValid(token) {
|
||||
return "", fmt.Errorf("%w: %q", ErrInvalidToken, token)
|
||||
}
|
||||
|
||||
scheme := "https"
|
||||
if config.DisableTLS {
|
||||
scheme = "http" // Use HTTP if TLS is disabled
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s://%s%s/message?token=%s", scheme, config.Host, config.Path, token), nil
|
||||
}
|
||||
|
||||
// Send delivers a notification message to Gotify.
|
||||
func (service *Service) Send(message string, params *types.Params) error {
|
||||
if params == nil {
|
||||
params = &types.Params{}
|
||||
}
|
||||
|
||||
config := service.Config
|
||||
if err := service.pkr.UpdateConfigFromParams(config, params); err != nil {
|
||||
service.Logf("Failed to update params: %v", err)
|
||||
}
|
||||
|
||||
postURL, err := buildURL(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
request := &messageRequest{
|
||||
Message: message,
|
||||
Title: config.Title,
|
||||
Priority: config.Priority,
|
||||
}
|
||||
response := &messageResponse{}
|
||||
|
||||
err = service.client.Post(postURL, request, response)
|
||||
if err != nil {
|
||||
errorRes := &responseError{}
|
||||
if service.client.ErrorResponse(err, errorRes) {
|
||||
return errorRes
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to send notification to Gotify: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetHTTPClient returns the HTTP client for testing purposes.
|
||||
func (service *Service) GetHTTPClient() *http.Client {
|
||||
return service.httpClient
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue