Skip to content
Open
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
50 changes: 37 additions & 13 deletions pkg/providers/teams/teams.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package teams

import (
"bytes"
"fmt"
"net/http"
"strings"

"github.com/containrrr/shoutrrr"
Expand Down Expand Up @@ -43,19 +45,41 @@ func (p *Provider) Send(message, CliFormat string) error {
p.counter++
for _, pr := range p.Teams {
msg := utils.FormatMessage(message, utils.SelectFormat(CliFormat, pr.TeamsFormat), p.counter)
webhookParts := strings.Split(pr.TeamsWebHookURL, "/webhookb2/")
if len(webhookParts) != 2 {
err := fmt.Errorf("teams: invalid webhook url for id: %s ", pr.ID)
TeamsErr = multierr.Append(TeamsErr, err)
}
teamsHost := strings.TrimPrefix(webhookParts[0], "https://")
teamsTokens := strings.ReplaceAll(webhookParts[1], "IncomingWebhook/", "")
url := fmt.Sprintf("teams://%s?host=%s", teamsTokens, teamsHost)
err := shoutrrr.Send(url, msg)
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("failed to send teams notification for id: %s ", pr.ID))
TeamsErr = multierr.Append(TeamsErr, err)
continue
provider := strings.Split(pr.TeamsWebHookURL, "/")[3]

// Deprecated method
if provider == "webhookb2" {
webhookParts := strings.Split(pr.TeamsWebHookURL, "/webhookb2/")
if len(webhookParts) != 2 {
err := fmt.Errorf("teams: invalid webhook url for id: %s ", pr.ID)
TeamsErr = multierr.Append(TeamsErr, err)
}
teamsHost := strings.TrimPrefix(webhookParts[0], "https://")
teamsTokens := strings.ReplaceAll(webhookParts[1], "IncomingWebhook/", "")
url := fmt.Sprintf("teams://%s?host=%s", teamsTokens, teamsHost)
err := shoutrrr.Send(url, msg)
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("failed to send webhook teams notification for id: %s", pr.ID))
TeamsErr = multierr.Append(TeamsErr, err)
continue
}

// New Power Automate method
} else if provider == "workflows" {
htmlMessage := strings.ReplaceAll(msg, "\n", "<br>")
payload := fmt.Sprintf(`{"text": "%s"}`, htmlMessage)
Comment on lines +67 to +70
Copy link

@coderabbitai coderabbitai bot Mar 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve JSON payload creation for better security.

The current implementation has two potential issues:

  1. Simple replacement of newlines with HTML breaks might not handle other HTML special characters
  2. Using string formatting to construct JSON can lead to malformed JSON if the message contains quotes or special characters
- htmlMessage := strings.ReplaceAll(msg, "\n", "<br>")
- payload := fmt.Sprintf(`{"text": "%s"}`, htmlMessage)
+ import "encoding/json"
+ import "html"
+
+ // HTML encode message to escape special characters
+ htmlMessage := html.EscapeString(strings.ReplaceAll(msg, "\n", "<br>"))
+ 
+ // Create payload using proper JSON marshaling
+ type teamsPayload struct {
+     Text string `json:"text"`
+ }
+ payloadObj := teamsPayload{Text: htmlMessage}
+ payloadBytes, err := json.Marshal(payloadObj)
+ if err != nil {
+     err = errors.Wrap(err, fmt.Sprintf("failed to create JSON payload for teams notification id: %s", pr.ID))
+     TeamsErr = multierr.Append(TeamsErr, err)
+     continue
+ }

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dogancanbakir Thanks for confirming! I'm glad you found the suggestion helpful. Let me know if you need any further assistance with the implementation!

(_/)
(^.^)
/>🎯 Bullseye!

resp, err := http.Post(pr.TeamsWebHookURL, "application/json", bytes.NewBuffer([]byte(payload)))
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("failed to send workflow teams notification for id: %s", pr.ID))
TeamsErr = multierr.Append(TeamsErr, err)
continue
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusAccepted {
err = errors.Errorf("failed to send workflow teams notification for id: %s, got status code: %d", pr.ID, resp.StatusCode)
TeamsErr = multierr.Append(TeamsErr, err)
continue
}
}
gologger.Verbose().Msgf("teams notification sent for id: %s", pr.ID)
}
Expand Down
Loading