trufflehog/main.go

191 lines
7.2 KiB
Go
Raw Normal View History

package main
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"runtime"
"strconv"
2022-01-20 23:54:35 +00:00
"strings"
2022-01-20 23:54:35 +00:00
"github.com/fatih/color"
"github.com/sirupsen/logrus"
2022-01-20 00:13:59 +00:00
kingpin "gopkg.in/alecthomas/kingpin.v2"
"github.com/trufflesecurity/trufflehog/pkg/common"
"github.com/trufflesecurity/trufflehog/pkg/decoders"
"github.com/trufflesecurity/trufflehog/pkg/engine"
"github.com/trufflesecurity/trufflehog/pkg/output"
2022-01-20 17:43:37 +00:00
"github.com/trufflesecurity/trufflehog/pkg/pb/source_metadatapb"
2022-01-20 00:13:59 +00:00
"github.com/trufflesecurity/trufflehog/pkg/sources/git"
)
func main() {
cli := kingpin.New("TruffleHog", "TruffleHog is a tool for finding credentials.")
debug := cli.Flag("debug", "Run in debug mode").Bool()
jsonOut := cli.Flag("json", "Output in JSON format.").Short('j').Bool()
jsonLegacy := cli.Flag("json-legacy", "Use the pre-v3.0 JSON format. Only works with git, gitlab, and github sources.").Bool()
concurrency := cli.Flag("concurrency", "Number of concurrent workers.").Default(strconv.Itoa(runtime.NumCPU())).Int()
2022-01-19 06:24:56 +00:00
noVerification := cli.Flag("no-verification", "Don't verify the results.").Bool()
// rules := cli.Flag("rules", "Path to file with custom rules.").String()
gitScan := cli.Command("git", "Find credentials in git repositories.")
gitScanURI := gitScan.Arg("uri", "Git repository URL. https:// or file:// schema expected.").Required().String()
gitScanIncludePaths := gitScan.Flag("include_paths", "Path to file with newline separated regexes for files to include in scan.").Short('i').String()
gitScanExcludePaths := gitScan.Flag("exclude_paths", "Path to file with newline separated regexes for files to exclude in scan.").Short('x').String()
// gitScanSinceCommit := gitScan.Flag("since_commit", "Commit to start scan from.").String()
gitScanBranch := gitScan.Flag("branch", "Branch to scan.").String()
// gitScanMaxDepth := gitScan.Flag("max_depth", "Maximum depth of commits to scan.").Int()
gitScan.Flag("allow", "No-op flag for backwards compat.").Bool()
gitScan.Flag("entropy", "No-op flag for backwards compat.").Bool()
gitScan.Flag("regex", "No-op flag for backwards compat.").Bool()
githubScan := cli.Command("github", "Find credentials in GitHub repositories.")
2022-01-20 00:13:59 +00:00
githubScanEndpoint := githubScan.Flag("endpoint", "GitHub endpoint.").Default("https://api.github.com").String()
githubScanRepos := githubScan.Flag("repo", `GitHub repository to scan. You can repeat this flag. Example: "https://github.com/dustin-decker/secretsandstuff"`).Strings()
githubScanOrgs := githubScan.Flag("org", `GitHub organization to scan. You can repeat this flag. Example: "trufflesecurity"`).Strings()
githubScanToken := githubScan.Flag("token", "GitHub token.").String()
gitlabScan := cli.Command("gitlab", "Find credentials in GitLab repositories.")
// gitlabScanTarget := gitlabScan.Arg("target", "GitLab target. Can be a repository, user or organization.").Required().String()
// gitlabScanToken := gitlabScan.Flag("token", "GitLab token.").String()
2022-01-20 00:13:59 +00:00
bitbucketScan := cli.Command("bitbucket", "Find credentials in Bitbucket repositories.")
// bitbucketScanTarget := bitbucketScan.Arg("target", "Bitbucket target. Can be a repository, user or organization.").Required().String()
// bitbucketScanToken := bitbucketScan.Flag("token", "Bitbucket token.").String()
2022-01-20 00:13:59 +00:00
filesystemScan := cli.Command("filesystem", "Find credentials in a filesystem.")
// filesystemScanPath := filesystemScan.Arg("path", "Path to scan.").Required().String()
// filesystemScanRecursive := filesystemScan.Flag("recursive", "Scan recursively.").Short('r').Bool()
// filesystemScanIncludePaths := filesystemScan.Flag("include_paths", "Path to file with newline separated regexes for files to include in scan.").Short('i').String()
// filesystemScanExcludePaths := filesystemScan.Flag("exclude_paths", "Path to file with newline separated regexes for files to exclude in scan.").Short('x').String()
2022-01-20 00:13:59 +00:00
s3Scan := cli.Command("s3", "Find credentials in an S3 bucket.")
cmd := kingpin.MustParse(cli.Parse(os.Args[1:]))
if *jsonOut {
logrus.SetFormatter(&logrus.JSONFormatter{})
}
if *debug {
logrus.SetLevel(logrus.DebugLevel)
} else {
logrus.SetLevel(logrus.InfoLevel)
}
ctx := context.TODO()
e := engine.Start(ctx,
engine.WithConcurrency(*concurrency),
engine.WithDecoders(decoders.DefaultDecoders()...),
2022-01-19 06:24:56 +00:00
engine.WithDetectors(!*noVerification, engine.DefaultDetectors()...),
)
filter, err := common.FilterFromFiles(*gitScanIncludePaths, *gitScanExcludePaths)
if err != nil {
logrus.WithError(err)
}
var repoPath string
switch cmd {
case gitScan.FullCommand():
var remote bool
repoPath, remote, err = git.PrepareRepo(*gitScanURI)
if err != nil || repoPath == "" {
logrus.WithError(err).Fatal("error preparing git repo for scanning")
}
if remote {
defer os.RemoveAll(repoPath)
}
err = e.ScanGit(ctx, repoPath, *gitScanBranch, "HEAD", filter)
if err != nil {
logrus.WithError(err).Fatal("Failed to scan git.")
}
case githubScan.FullCommand():
2022-01-20 00:13:59 +00:00
if len(*githubScanOrgs) == 0 && len(*githubScanRepos) == 0 {
log.Fatal("You must specify at least one organization or repository.")
}
err = e.ScanGitHub(ctx, *githubScanEndpoint, *githubScanRepos, *githubScanOrgs, *githubScanToken, filter, *concurrency)
if err != nil {
logrus.WithError(err).Fatal("Failed to scan git.")
}
case gitlabScan.FullCommand():
log.Fatal("gitlab not implemented")
2022-01-20 00:13:59 +00:00
case bitbucketScan.FullCommand():
log.Fatal("bitbucket not implemented")
case filesystemScan.FullCommand():
log.Fatal("filesystem not implemented")
case s3Scan.FullCommand():
log.Fatal("s3 not implemented")
}
2022-01-20 23:54:35 +00:00
yellowPrinter := color.New(color.FgYellow)
greenPrinter := color.New(color.FgHiGreen)
redPrinter := color.New(color.FgRed)
whitePrinter := color.New(color.FgWhite)
if !*jsonLegacy && !*jsonOut {
fmt.Printf("🐷🔑🐷 TruffleHog. Unearth your secrets. 🐷🔑🐷\n\n")
}
2022-01-20 17:43:37 +00:00
for r := range e.ResultsChan() {
out := outputFormat{
2022-01-20 17:43:37 +00:00
DetectorType: r.Result.DetectorType.String(),
Verified: r.Result.Verified,
MetaData: r.SourceMetadata,
}
switch {
case *jsonLegacy:
legacy := output.ConvertToLegacyJSON(&r, repoPath)
out, err := json.Marshal(legacy)
if err != nil {
logrus.WithError(err).Fatal("could not marshal result")
}
fmt.Println(string(out))
case *jsonOut:
out, err := json.Marshal(r)
if err != nil {
logrus.WithError(err).Fatal("could not marshal result")
}
fmt.Println(string(out))
default:
meta, err := structToMap(out.MetaData.Data)
2022-01-20 17:43:37 +00:00
if err != nil {
logrus.WithError(err).Fatal("could not marshal result")
}
2022-01-20 23:54:35 +00:00
yellowPrinter.Print("Found result 🐷🔑\n")
greenPrinter.Printf("Detector Type: %s\n", out.DetectorType)
if out.Verified {
2022-01-20 23:54:35 +00:00
redPrinter.Print("Verified: true\n")
} else {
whitePrinter.Print("Verified: false\n")
}
for _, data := range meta {
for k, v := range data {
greenPrinter.Printf("%s: %s\n", strings.Title(k), v)
}
}
fmt.Println("")
}
}
2022-01-19 06:24:56 +00:00
logrus.Infof("scanned %d chunks", e.ChunksScanned())
}
2022-01-20 17:43:37 +00:00
2022-01-20 23:54:35 +00:00
func structToMap(obj interface{}) (m map[string]map[string]interface{}, err error) {
2022-01-20 17:43:37 +00:00
data, err := json.Marshal(obj)
if err != nil {
return
}
2022-01-20 23:54:35 +00:00
err = json.Unmarshal(data, &m)
2022-01-20 17:43:37 +00:00
return
}
type outputFormat struct {
DetectorType string
Verified bool
*source_metadatapb.MetaData
}