mirror of
https://github.com/grafana/grafana.git
synced 2025-02-12 00:25:46 -06:00
89 lines
2.2 KiB
Go
89 lines
2.2 KiB
Go
|
package secretscan
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"net/http"
|
||
|
|
||
|
"github.com/google/uuid"
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
// webHookClient is a client for sending leak notifications.
|
||
|
type webHookClient struct {
|
||
|
httpClient *http.Client
|
||
|
version string
|
||
|
url string
|
||
|
}
|
||
|
|
||
|
var ErrInvalidWebHookStatusCode = errors.New("invalid webhook status code")
|
||
|
|
||
|
func newWebHookClient(url, version string) *webHookClient {
|
||
|
return &webHookClient{
|
||
|
version: version,
|
||
|
url: url,
|
||
|
httpClient: &http.Client{
|
||
|
Transport: nil,
|
||
|
CheckRedirect: nil,
|
||
|
Jar: nil,
|
||
|
Timeout: timeout,
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (wClient *webHookClient) Notify(ctx context.Context,
|
||
|
token *Token, tokenName string, revoked bool,
|
||
|
) error {
|
||
|
revokedMsg := ""
|
||
|
if revoked {
|
||
|
revokedMsg = " Grafana has revoked this token"
|
||
|
}
|
||
|
|
||
|
// create request body
|
||
|
values := map[string]interface{}{
|
||
|
"alert_uid": uuid.NewString(),
|
||
|
"title": "SecretScan Alert: Grafana Token leaked",
|
||
|
"image_url": "https://images.pexels.com/photos/5119737/pexels-photo-5119737.jpeg?auto=compress&cs=tinysrgb&w=300", //nolint
|
||
|
"state": "alerting",
|
||
|
"link_to_upstream_details": token.URL,
|
||
|
"message": "Token of type " +
|
||
|
token.Type + " with name " +
|
||
|
tokenName + " has been publicly exposed in " +
|
||
|
token.URL + "." + revokedMsg,
|
||
|
}
|
||
|
|
||
|
jsonValue, err := json.Marshal(values)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "failed to marshal webhook request")
|
||
|
}
|
||
|
|
||
|
// Build URL
|
||
|
// Create request for secretscan server
|
||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost,
|
||
|
wClient.url, bytes.NewReader(jsonValue))
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "failed to make http request")
|
||
|
}
|
||
|
|
||
|
// Set headers
|
||
|
req.Header.Set("Content-Type", "application/json")
|
||
|
req.Header.Set("Accept", "application/json")
|
||
|
req.Header.Set("User-Agent", "grafana-secretscan-webhook-client/"+wClient.version)
|
||
|
|
||
|
// make http POST request to check for leaked tokens.
|
||
|
resp, err := wClient.httpClient.Do(req)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "failed to webhook request")
|
||
|
}
|
||
|
|
||
|
defer func() { _ = resp.Body.Close() }()
|
||
|
|
||
|
if resp.StatusCode != http.StatusOK {
|
||
|
return fmt.Errorf("%w. status code %s", ErrInvalidWebHookStatusCode, resp.Status)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|