Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions notifier/discord/discord.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
const (
requestTimeout = 10 * time.Second
responseBodyLimit = 256 << 10
userAgent = "DiscordBot (https://github.com/we11adam/uddns, 1.0)"
)

type Discord struct {
Expand Down Expand Up @@ -93,6 +94,7 @@ func (d *Discord) newHTTPClient() (*resty.Client, error) {
SetTimeout(requestTimeout).
SetResponseBodyLimit(responseBodyLimit).
SetHeader("Content-Type", "application/json").
SetHeader("User-Agent", userAgent).
SetBaseURL(webhookURL)

if d.Proxy != "" {
Expand Down Expand Up @@ -127,24 +129,24 @@ func (d *Discord) Notify(ctx context.Context, notification notifier.Notification
},
}).Post("")
if err != nil {
return redact.Error(err, d.Token)
return d.redactError(err)
}

switch resp.StatusCode() {
case http.StatusOK, http.StatusNoContent:
return nil
case http.StatusTooManyRequests:
return fmt.Errorf("Discord API request failed, rate limited, retry after %s", resp.Header().Get("Retry-After"))
return d.redactError(fmt.Errorf("Discord API request failed, rate limited, retry after %s", resp.Header().Get("Retry-After")))
}
apiResp := apiResponse{}
decodeErr := json.Unmarshal(resp.Body(), &apiResp)
if !resp.IsSuccess() {
return d.apiError(resp.StatusCode(), apiResp)
return d.redactError(d.apiError(resp.StatusCode(), apiResp))
}
if decodeErr != nil {
return redact.Error(fmt.Errorf("failed to decode Discord API response: %w", decodeErr), d.Token)
return d.redactError(fmt.Errorf("failed to decode Discord API response: %w", decodeErr))
}
return d.apiError(resp.StatusCode(), apiResp)
return d.redactError(d.apiError(resp.StatusCode(), apiResp))
}

func (d *Discord) apiError(statusCode int, response apiResponse) error {
Expand All @@ -153,3 +155,7 @@ func (d *Discord) apiError(statusCode int, response apiResponse) error {
}
return fmt.Errorf("Discord API request failed: HTTP status %d, code %d, message %q", statusCode, response.Code, response.Message)
}

func (d *Discord) redactError(err error) error {
return redact.Error(err, d.Token, d.URL)
}
20 changes: 20 additions & 0 deletions notifier/discord/discord_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ func TestClientBaseURL(t *testing.T) {
if baseURL != tt.wantBase {
t.Errorf("New() BaseURL = %v, want %v", baseURL, tt.wantBase)
}
if got := client.hc.Header.Get("User-Agent"); got != userAgent {
t.Errorf("New() User-Agent = %q, want %q", got, userAgent)
}
}
})
}
Expand All @@ -111,6 +114,23 @@ func TestNotifyRedactTokenFromTransportError(t *testing.T) {
testutil.AssertTokenRedacted(t, err.Error(), token)
}

func TestNotifyRedactsTokenFromURLTransportError(t *testing.T) {
token := "discord-webhook-token"
discord, err := New(&Discord{
URL: "https://discord.com/api/webhooks/123456/" + token,
})
if err != nil {
t.Fatalf("failed to create Discord client: %v", err)
}
discord.hc.SetTransport(failingTransport{message: "request failed"})

err = discord.Notify(context.Background(), notifier.Notification{Message: "test"})
if err == nil {
t.Fatal("expected transport error")
}
testutil.AssertTokenRedacted(t, err.Error(), token)
}

func TestNotifyDiscordAPIResponse(t *testing.T) {
token := "discord+/token =secret"
tests := []struct {
Expand Down