* Populate SecretParts on single-part detectors
Adds SecretParts: map[string]string{"key": <secret>} to every detector
package that constructs detectors.Result with a single captured secret
value. This is the single-part half of the SecretParts migration (the
linter's common case, ~695 packages).
* Populate SecretParts on multi-part detectors
94 lines
2.6 KiB
Go
94 lines
2.6 KiB
Go
package atera
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
|
|
regexp "github.com/wasilibs/go-re2"
|
|
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detector_typepb"
|
|
)
|
|
|
|
type Scanner struct{}
|
|
|
|
// Ensure the Scanner satisfies the interface at compile time.
|
|
var _ detectors.Detector = (*Scanner)(nil)
|
|
|
|
var (
|
|
client = common.SaneHttpClient()
|
|
|
|
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"atera"}) + `\b([0-9a-z]{32})\b`)
|
|
)
|
|
|
|
// Keywords are used for efficiently pre-filtering chunks.
|
|
// Use identifiers in the secret preferably, or the provider name.
|
|
func (s Scanner) Keywords() []string {
|
|
return []string{"atera"}
|
|
}
|
|
|
|
// FromData will find and optionally verify Atera secrets in a given set of bytes.
|
|
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
dataStr := string(data)
|
|
|
|
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
|
|
for _, match := range matches {
|
|
resMatch := strings.TrimSpace(match[1])
|
|
|
|
s1 := detectors.Result{
|
|
DetectorType: detector_typepb.DetectorType_Atera,
|
|
Raw: []byte(resMatch),
|
|
SecretParts: map[string]string{"key": resMatch},
|
|
}
|
|
|
|
if verify {
|
|
isVerified, err := verifyMatch(ctx, client, resMatch)
|
|
s1.Verified = isVerified
|
|
s1.SetVerificationError(err, resMatch)
|
|
}
|
|
|
|
results = append(results, s1)
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
func verifyMatch(ctx context.Context, client *http.Client, token string) (bool, error) {
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://app.atera.com/api/v3/alerts", http.NoBody)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
req.Header.Add("Accept", "application/json")
|
|
req.Header.Add("X-API-KEY", token)
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
defer func() {
|
|
_, _ = io.Copy(io.Discard, res.Body)
|
|
_ = res.Body.Close()
|
|
}()
|
|
switch res.StatusCode {
|
|
case http.StatusOK:
|
|
return true, nil
|
|
case http.StatusUnauthorized:
|
|
return false, nil
|
|
default:
|
|
return false, fmt.Errorf("unexpected status code %d", res.StatusCode)
|
|
}
|
|
}
|
|
|
|
func (s Scanner) Type() detector_typepb.DetectorType {
|
|
return detector_typepb.DetectorType_Atera
|
|
}
|
|
|
|
func (s Scanner) Description() string {
|
|
return "Atera is an IT management platform that provides remote monitoring and management for IT professionals. Atera API keys can be used to interact with the Atera API to manage alerts, tickets, devices, and more."
|
|
}
|