diff --git a/pkg/detectors/datadogtoken/datadogtoken.go b/pkg/detectors/datadogtoken/datadogtoken.go index af2c8f0cfba4..c1f737f8a826 100644 --- a/pkg/detectors/datadogtoken/datadogtoken.go +++ b/pkg/detectors/datadogtoken/datadogtoken.go @@ -2,6 +2,7 @@ package datadogtoken import ( "context" + "encoding/json" "net/http" "strings" @@ -30,6 +31,65 @@ var ( apiPat = regexp.MustCompile(detectors.PrefixRegex([]string{"datadog", "dd"}) + `\b([a-zA-Z-0-9]{32})\b`) ) +type userServiceResponse struct { + Data []*user `json:"data"` + Included []*options `json:"included"` +} + +type user struct { + Attributes userAttributes `json:"attributes"` +} + +type userAttributes struct { + Email string `json:"email"` + IsServiceAccount bool `json:"service_account"` + Verified bool `json:"verified"` + Disabled bool `json:"disabled"` +} + +type options struct { + Type string `json:"type"` + Attributes optionAttribute `json:"attributes"` +} + +type optionAttribute struct { + Url string `json:"url"` + Name string `json:"name"` + Disabled bool `json:"disabled"` +} + +func setUserEmails(data []*user, s1 *detectors.Result) { + var emails []string + for _, user := range data { + // filter out non verified emails, disabled emails, service accounts + if user.Attributes.Verified && !user.Attributes.Disabled && !user.Attributes.IsServiceAccount { + emails = append(emails, user.Attributes.Email) + } + } + + if len(emails) == 0 && len(data) > 0 { + emails = append(emails, data[0].Attributes.Email) + } + + s1.ExtraData["user_emails"] = strings.Join(emails, ", ") +} + +func setOrganizationInfo(opt []*options, s1 *detectors.Result) { + var orgs *options + for _, option := range opt { + if option.Type == "orgs" && !option.Attributes.Disabled { + orgs = option + break + } + } + + if orgs != nil { + s1.ExtraData["org_name"] = orgs.Attributes.Name + s1.ExtraData["org_url"] = orgs.Attributes.Url + } + +} + // Keywords are used for efficiently pre-filtering chunks. // Use identifiers in the secret preferably, or the provider name. func (s Scanner) Keywords() []string { @@ -78,6 +138,17 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result defer res.Body.Close() if res.StatusCode >= 200 && res.StatusCode < 300 { s1.Verified = true + var serviceResponse userServiceResponse + if err := json.NewDecoder(res.Body).Decode(&serviceResponse); err == nil { + // setup emails + if len(serviceResponse.Data) > 0 { + setUserEmails(serviceResponse.Data, &s1) + } + // setup organizations + if len(serviceResponse.Included) > 0 { + setOrganizationInfo(serviceResponse.Included, &s1) + } + } } } }