Files
trufflehog/pkg/output/plain.go
Casey Tran 9ecaf075c5 Update postman metadata (#3852)
* Updated Postman metadata fields to contain location uniqueness and took out the unused fields of global_id, field_name, and variable_type.
* Disabled body scanning for now since the only body that is scanned is the currently selected radio button but secrets can still be saved in the other unselected radio button options.
* Updated link generation for more accuracy.
* Updated tests to not use global constant.
2025-01-30 09:52:47 -06:00

135 lines
4.2 KiB
Go

package output
import (
"encoding/json"
"fmt"
"sort"
"strings"
"sync"
"github.com/fatih/color"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb"
)
var (
yellowPrinter = color.New(color.FgYellow)
greenPrinter = color.New(color.FgHiGreen)
boldGreenPrinter = color.New(color.Bold, color.FgHiGreen)
whitePrinter = color.New(color.FgWhite)
boldWhitePrinter = color.New(color.Bold, color.FgWhite)
cyanPrinter = color.New(color.FgCyan)
)
// PlainPrinter is a printer that prints results in plain text format.
type PlainPrinter struct{ mu sync.Mutex }
func (p *PlainPrinter) Print(_ context.Context, r *detectors.ResultWithMetadata) error {
out := outputFormat{
DetectorType: r.Result.DetectorType.String(),
DecoderType: r.DecoderType.String(),
Verified: r.Result.Verified,
VerificationError: r.Result.VerificationError(),
MetaData: r.SourceMetadata,
Raw: strings.TrimSpace(string(r.Result.Raw)),
DetectorDescription: r.DetectorDescription,
}
meta, err := structToMap(out.MetaData.Data)
if err != nil {
return fmt.Errorf("could not marshal result: %w", err)
}
printer := greenPrinter
p.mu.Lock()
defer p.mu.Unlock()
if out.Verified {
boldGreenPrinter.Print("✅ Found verified result 🐷🔑\n")
} else {
printer = whitePrinter
boldWhitePrinter.Print("Found unverified result 🐷🔑❓\n")
if out.VerificationError != nil {
yellowPrinter.Printf("Verification issue: %s\n", out.VerificationError)
}
}
if r.VerificationFromCache {
cyanPrinter.Print("(Verification info cached)\n")
}
printer.Printf("Detector Type: %s\n", out.DetectorType)
printer.Printf("Decoder Type: %s\n", out.DecoderType)
printer.Printf("Raw result: %s\n", whitePrinter.Sprint(out.Raw))
for k, v := range r.Result.ExtraData {
printer.Printf(
"%s: %v\n",
cases.Title(language.AmericanEnglish).String(k),
v)
}
if r.Result.StructuredData != nil {
for idx, v := range r.Result.StructuredData.GithubSshKey {
printer.Printf("GithubSshKey %d User: %s\n", idx, v.User)
if v.PublicKeyFingerprint != "" {
printer.Printf("GithubSshKey %d Fingerprint: %s\n", idx, v.PublicKeyFingerprint)
}
}
for idx, v := range r.Result.StructuredData.TlsPrivateKey {
printer.Printf("TlsPrivateKey %d Fingerprint: %s\n", idx, v.CertificateFingerprint)
printer.Printf("TlsPrivateKey %d Verification URL: %s\n", idx, v.VerificationUrl)
printer.Printf("TlsPrivateKey %d Expiration: %d\n", idx, v.ExpirationTimestamp)
}
}
aggregateData := make(map[string]any)
var aggregateDataKeys []string
for _, data := range meta {
for k, v := range data {
aggregateDataKeys = append(aggregateDataKeys, k)
aggregateData[k] = v
}
}
sort.Strings(aggregateDataKeys)
for _, k := range aggregateDataKeys {
printer.Printf("%s: %v\n", cases.Title(language.AmericanEnglish).String(k), aggregateData[k])
}
fmt.Println("")
return nil
}
func structToMap(obj any) (m map[string]map[string]any, err error) {
data, err := json.Marshal(obj)
if err != nil {
return
}
err = json.Unmarshal(data, &m)
// Due to PostmanLocationType protobuf field being an enum, we want to be able to assign the string value of the enum to the field without needing to create another Protobuf field.
// To have the "UNKNOWN_POSTMAN = 0" value be assigned correctly to the field, we need to check if the Postman workspace ID is filled since every secret in the Postman source
// should have a valid workspace ID and the 0 value is considered nil for integers.
if m["Postman"]["workspace_uuid"] != nil {
if m["Postman"]["location_type"] == nil {
m["Postman"]["location_type"] = source_metadatapb.PostmanLocationType_UNKNOWN_POSTMAN.String()
} else {
m["Postman"]["location_type"] = obj.(*source_metadatapb.MetaData_Postman).Postman.LocationType.String()
}
}
return
}
type outputFormat struct {
DetectorType,
DecoderType string
Verified bool
VerificationError error
Raw string
*source_metadatapb.MetaData
DetectorDescription string
}