2022-01-13 20:02:24 +00:00
package main
import (
"context"
"encoding/json"
"fmt"
"log"
2022-02-07 18:29:06 +00:00
"net/http"
_ "net/http/pprof"
2022-01-13 20:02:24 +00:00
"os"
"runtime"
"strconv"
2022-02-07 18:29:06 +00:00
"time"
"github.com/felixge/fgprof"
2022-01-13 20:02:24 +00:00
2022-01-27 04:38:31 +00:00
"github.com/go-git/go-git/v5/plumbing"
2022-02-07 18:29:06 +00:00
"github.com/gorilla/mux"
2022-01-13 20:02:24 +00:00
"github.com/sirupsen/logrus"
2022-02-16 01:38:19 +00:00
"gopkg.in/alecthomas/kingpin.v2"
2022-01-20 00:13:59 +00:00
2022-02-10 18:54:33 +00:00
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/decoders"
"github.com/trufflesecurity/trufflehog/v3/pkg/engine"
"github.com/trufflesecurity/trufflehog/v3/pkg/output"
"github.com/trufflesecurity/trufflehog/v3/pkg/sources/git"
2022-01-13 20:02:24 +00:00
)
func main ( ) {
cli := kingpin . New ( "TruffleHog" , "TruffleHog is a tool for finding credentials." )
debug := cli . Flag ( "debug" , "Run in debug mode" ) . Bool ( )
2022-01-19 00:59:18 +00:00
jsonOut := cli . Flag ( "json" , "Output in JSON format." ) . Short ( 'j' ) . Bool ( )
2022-01-20 00:48:37 +00:00
jsonLegacy := cli . Flag ( "json-legacy" , "Use the pre-v3.0 JSON format. Only works with git, gitlab, and github sources." ) . Bool ( )
2022-01-13 20:02:24 +00:00
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 ( )
2022-01-27 04:38:31 +00:00
onlyVerified := cli . Flag ( "only-verified" , "Only output verified results." ) . Bool ( )
2022-01-13 20:02:24 +00:00
// rules := cli.Flag("rules", "Path to file with custom rules.").String()
2022-02-07 18:29:06 +00:00
printAvgDetectorTime := cli . Flag ( "print-avg-detector-time" , "Print the average time spent on each detector." ) . Bool ( )
2022-01-13 20:02:24 +00:00
gitScan := cli . Command ( "git" , "Find credentials in git repositories." )
gitScanURI := gitScan . Arg ( "uri" , "Git repository URL. https:// or file:// schema expected." ) . Required ( ) . String ( )
2022-01-14 20:40:50 +00:00
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 ( )
2022-01-22 00:28:41 +00:00
gitScanSinceCommit := gitScan . Flag ( "since_commit" , "Commit to start scan from." ) . String ( )
2022-01-13 20:02:24 +00:00
gitScanBranch := gitScan . Flag ( "branch" , "Branch to scan." ) . String ( )
2022-01-22 00:28:41 +00:00
gitScanMaxDepth := gitScan . Flag ( "max_depth" , "Maximum depth of commits to scan." ) . Int ( )
2022-01-13 20:02:24 +00:00
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 ( )
2022-02-04 17:52:48 +00:00
githubIncludeForks := githubScan . Flag ( "include_forks" , "Include forks in scan." ) . Bool ( )
2022-01-13 20:02:24 +00:00
2022-01-28 03:24:44 +00:00
gitlabScan := cli . Command ( "gitlab" , "Coming soon. Find credentials in GitLab repositories." )
2022-01-13 20:02:24 +00:00
// gitlabScanTarget := gitlabScan.Arg("target", "GitLab target. Can be a repository, user or organization.").Required().String()
// gitlabScanToken := gitlabScan.Flag("token", "GitLab token.").String()
2022-01-28 03:24:44 +00:00
bitbucketScan := cli . Command ( "bitbucket" , "Coming soon. Find credentials in Bitbucket repositories." )
2022-01-13 20:02:24 +00:00
// bitbucketScanTarget := bitbucketScan.Arg("target", "Bitbucket target. Can be a repository, user or organization.").Required().String()
// bitbucketScanToken := bitbucketScan.Flag("token", "Bitbucket token.").String()
2022-01-28 03:24:44 +00:00
filesystemScan := cli . Command ( "filesystem" , "Coming soon. Find credentials in a filesystem." )
2022-01-13 20:02:24 +00:00
// 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-28 03:24:44 +00:00
s3Scan := cli . Command ( "s3" , "Coming soon. Find credentials in an S3 bucket." )
2022-01-20 00:13:59 +00:00
2022-01-13 20:02:24 +00:00
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 )
}
2022-02-04 03:07:39 +00:00
if * debug {
go func ( ) {
2022-02-07 18:29:06 +00:00
router := mux . NewRouter ( )
router . PathPrefix ( "/debug/pprof" ) . Handler ( http . DefaultServeMux )
router . PathPrefix ( "/debug/fgprof" ) . Handler ( fgprof . Handler ( ) )
2022-02-10 18:54:33 +00:00
logrus . Info ( "starting pprof and fgprof server on :18066 /debug/pprof and /debug/fgprof" )
2022-02-07 18:29:06 +00:00
if err := http . ListenAndServe ( ":18066" , router ) ; err != nil {
2022-02-10 18:54:33 +00:00
logrus . Error ( err )
2022-02-07 18:29:06 +00:00
}
2022-02-04 03:07:39 +00:00
} ( )
}
2022-01-13 20:02:24 +00:00
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 ( ) ... ) ,
2022-01-13 20:02:24 +00:00
)
2022-01-14 20:40:50 +00:00
filter , err := common . FilterFromFiles ( * gitScanIncludePaths , * gitScanExcludePaths )
if err != nil {
logrus . WithError ( err )
}
2022-01-20 00:48:37 +00:00
var repoPath string
2022-01-13 20:02:24 +00:00
switch cmd {
case gitScan . FullCommand ( ) :
2022-01-20 00:48:37 +00:00
var remote bool
repoPath , remote , err = git . PrepareRepo ( * gitScanURI )
2022-01-15 00:07:45 +00:00
if err != nil || repoPath == "" {
logrus . WithError ( err ) . Fatal ( "error preparing git repo for scanning" )
}
if remote {
defer os . RemoveAll ( repoPath )
}
2022-01-22 00:28:41 +00:00
sinceHash := plumbing . NewHash ( * gitScanSinceCommit )
err = e . ScanGit ( ctx , repoPath , * gitScanBranch , "HEAD" , & sinceHash , * gitScanMaxDepth , filter )
2022-01-13 20:02:24 +00:00
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." )
}
2022-02-04 17:52:48 +00:00
err = e . ScanGitHub ( ctx , * githubScanEndpoint , * githubScanRepos , * githubScanOrgs , * githubScanToken , * githubIncludeForks , filter , * concurrency )
2022-01-20 00:13:59 +00:00
if err != nil {
logrus . WithError ( err ) . Fatal ( "Failed to scan git." )
}
2022-01-13 20:02:24 +00:00
case gitlabScan . FullCommand ( ) :
2022-01-28 03:24:44 +00:00
log . Fatal ( "GitLab not implemented. Coming soon." )
2022-01-20 00:13:59 +00:00
case bitbucketScan . FullCommand ( ) :
2022-01-28 03:24:44 +00:00
log . Fatal ( "Bitbucket not implemented. Coming soon." )
2022-01-20 00:13:59 +00:00
case filesystemScan . FullCommand ( ) :
2022-01-28 03:24:44 +00:00
log . Fatal ( "Filesystem not implemented. Coming soon." )
2022-01-20 00:13:59 +00:00
case s3Scan . FullCommand ( ) :
2022-01-28 03:24:44 +00:00
log . Fatal ( "S3 not implemented. Coming soon." )
2022-01-13 20:02:24 +00:00
}
2022-01-20 00:48:37 +00:00
if ! * jsonLegacy && ! * jsonOut {
2022-02-08 17:12:41 +00:00
fmt . Fprintf ( os . Stderr , "🐷🔑🐷 TruffleHog. Unearth your secrets. 🐷🔑🐷\n\n" )
2022-01-20 00:48:37 +00:00
}
2022-01-20 17:43:37 +00:00
2022-01-13 20:02:24 +00:00
for r := range e . ResultsChan ( ) {
2022-01-27 04:38:31 +00:00
if * onlyVerified && ! r . Verified {
continue
}
2022-01-20 17:43:37 +00:00
2022-01-20 00:48:37 +00:00
switch {
case * jsonLegacy :
legacy := output . ConvertToLegacyJSON ( & r , repoPath )
out , err := json . Marshal ( legacy )
2022-01-13 20:02:24 +00:00
if err != nil {
logrus . WithError ( err ) . Fatal ( "could not marshal result" )
}
fmt . Println ( string ( out ) )
2022-01-20 00:48:37 +00:00
case * jsonOut :
out , err := json . Marshal ( r )
if err != nil {
logrus . WithError ( err ) . Fatal ( "could not marshal result" )
}
fmt . Println ( string ( out ) )
default :
2022-01-21 02:14:16 +00:00
output . PrintPlainOutput ( & r )
2022-01-13 20:02:24 +00:00
}
}
2022-01-21 02:14:16 +00:00
logrus . Debugf ( "scanned %d chunks" , e . ChunksScanned ( ) )
2022-02-07 18:29:06 +00:00
if * printAvgDetectorTime {
printAverageDetectorTime ( e )
}
}
func printAverageDetectorTime ( e * engine . Engine ) {
fmt . Fprintln ( os . Stderr , "Average detector time is the measurement of average time spent on each detector when results are returned." )
for detectorName , durations := range e . DetectorAvgTime ( ) {
var total time . Duration
for _ , d := range durations {
total += d
}
avgDuration := total / time . Duration ( len ( durations ) )
fmt . Fprintf ( os . Stderr , "%s: %s\n" , detectorName , avgDuration )
}
2022-01-20 00:48:37 +00:00
}