2022-01-13 20:02:24 +00:00
|
|
|
package filesystem
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"io/fs"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
2022-08-10 22:32:49 +00:00
|
|
|
diskbufferreader "github.com/bill-rich/disk-buffer-reader"
|
2022-01-13 20:02:24 +00:00
|
|
|
"github.com/go-errors/errors"
|
|
|
|
log "github.com/sirupsen/logrus"
|
2022-08-10 02:20:02 +00:00
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
"google.golang.org/protobuf/types/known/anypb"
|
|
|
|
|
2022-02-10 18:54:33 +00:00
|
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
2022-08-29 18:45:37 +00:00
|
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
2022-08-03 03:36:21 +00:00
|
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/handlers"
|
2022-02-10 18:54:33 +00:00
|
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb"
|
|
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb"
|
2022-02-16 01:38:19 +00:00
|
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/sanitizer"
|
|
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
2022-01-13 20:02:24 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// These buffer sizes are mainly driven by our largest credential size, which is GCP @ ~2.25KB.
|
|
|
|
// Having a peek size larger than that ensures that we have complete credential coverage in our chunks.
|
2022-08-10 02:20:02 +00:00
|
|
|
BufferSize = 10 * 1024 // 10KB
|
|
|
|
PeekSize = 3 * 1024 // 3KB
|
2022-01-13 20:02:24 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Source struct {
|
|
|
|
name string
|
|
|
|
sourceId int64
|
|
|
|
jobId int64
|
|
|
|
verify bool
|
|
|
|
paths []string
|
|
|
|
aCtx context.Context
|
|
|
|
log *log.Entry
|
|
|
|
sources.Progress
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the Source satisfies the interface at compile time
|
|
|
|
var _ sources.Source = (*Source)(nil)
|
|
|
|
|
|
|
|
// Type returns the type of source.
|
|
|
|
// It is used for matching source types in configuration and job input.
|
|
|
|
func (s *Source) Type() sourcespb.SourceType {
|
|
|
|
return sourcespb.SourceType_SOURCE_TYPE_FILESYSTEM
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Source) SourceID() int64 {
|
|
|
|
return s.sourceId
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Source) JobID() int64 {
|
|
|
|
return s.jobId
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init returns an initialized Filesystem source.
|
2022-08-10 02:20:02 +00:00
|
|
|
func (s *Source) Init(aCtx context.Context, name string, jobId, sourceId int64, verify bool, connection *anypb.Any, _ int) error {
|
2022-01-13 20:02:24 +00:00
|
|
|
s.log = log.WithField("source", s.Type()).WithField("name", name)
|
|
|
|
|
|
|
|
s.aCtx = aCtx
|
|
|
|
s.name = name
|
|
|
|
s.sourceId = sourceId
|
|
|
|
s.jobId = jobId
|
|
|
|
s.verify = verify
|
|
|
|
|
|
|
|
var conn sourcespb.Filesystem
|
2022-08-10 02:20:02 +00:00
|
|
|
if err := anypb.UnmarshalTo(connection, &conn, proto.UnmarshalOptions{}); err != nil {
|
|
|
|
return errors.WrapPrefix(err, "error unmarshalling connection", 0)
|
2022-01-13 20:02:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
s.paths = conn.Directories
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Chunks emits chunks of bytes over a channel.
|
|
|
|
func (s *Source) Chunks(ctx context.Context, chunksChan chan *sources.Chunk) error {
|
|
|
|
for i, path := range s.paths {
|
2022-03-23 21:50:23 +00:00
|
|
|
s.SetProgressComplete(i, len(s.paths), fmt.Sprintf("Path: %s", path), "")
|
2022-01-13 20:02:24 +00:00
|
|
|
|
|
|
|
cleanPath := filepath.Clean(path)
|
|
|
|
done := false
|
|
|
|
go func() {
|
|
|
|
<-ctx.Done()
|
|
|
|
done = true
|
|
|
|
}()
|
|
|
|
|
|
|
|
err := fs.WalkDir(os.DirFS(cleanPath), ".", func(relativePath string, d fs.DirEntry, err error) error {
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
path := filepath.Join(cleanPath, relativePath)
|
|
|
|
|
2022-04-06 01:58:05 +00:00
|
|
|
fileStat, err := os.Stat(path)
|
|
|
|
if err != nil {
|
|
|
|
log.WithError(err).Warnf("unable to stat file: %s", path)
|
2022-04-06 16:48:40 +00:00
|
|
|
return nil
|
2022-04-06 01:58:05 +00:00
|
|
|
}
|
2022-03-16 23:04:10 +00:00
|
|
|
if !fileStat.Mode().IsRegular() {
|
2022-01-13 20:02:24 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
inputFile, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
log.Warn(err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
defer inputFile.Close()
|
2022-10-11 21:18:52 +00:00
|
|
|
log.WithField("file_path", path).Trace("scanning file")
|
2022-01-13 20:02:24 +00:00
|
|
|
|
2022-08-10 22:32:49 +00:00
|
|
|
reReader, err := diskbufferreader.New(inputFile)
|
|
|
|
if err != nil {
|
|
|
|
log.WithError(err).Error("Could not create re-readable reader.")
|
|
|
|
}
|
|
|
|
defer reReader.Close()
|
|
|
|
|
2022-08-03 03:36:21 +00:00
|
|
|
chunkSkel := &sources.Chunk{
|
|
|
|
SourceType: s.Type(),
|
|
|
|
SourceName: s.name,
|
|
|
|
SourceID: s.SourceID(),
|
|
|
|
SourceMetadata: &source_metadatapb.MetaData{
|
|
|
|
Data: &source_metadatapb.MetaData_Filesystem{
|
|
|
|
Filesystem: &source_metadatapb.Filesystem{
|
|
|
|
File: sanitizer.UTF8(path),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Verify: s.verify,
|
|
|
|
}
|
2022-08-10 22:32:49 +00:00
|
|
|
if handlers.HandleFile(reReader, chunkSkel, chunksChan) {
|
2022-08-03 03:36:21 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-08-10 22:32:49 +00:00
|
|
|
if err := reReader.Reset(); err != nil {
|
2022-08-03 03:36:21 +00:00
|
|
|
return err
|
|
|
|
}
|
2022-08-10 22:32:49 +00:00
|
|
|
reReader.Stop()
|
|
|
|
|
2022-08-30 17:24:52 +00:00
|
|
|
for chunkData := range common.ChunkReader(reReader) {
|
2022-08-10 22:32:49 +00:00
|
|
|
chunksChan <- &sources.Chunk{
|
|
|
|
SourceType: s.Type(),
|
|
|
|
SourceName: s.name,
|
|
|
|
SourceID: s.SourceID(),
|
|
|
|
Data: chunkData,
|
|
|
|
SourceMetadata: &source_metadatapb.MetaData{
|
|
|
|
Data: &source_metadatapb.MetaData_Filesystem{
|
|
|
|
Filesystem: &source_metadatapb.Filesystem{
|
|
|
|
File: sanitizer.UTF8(path),
|
2022-01-13 20:02:24 +00:00
|
|
|
},
|
|
|
|
},
|
2022-08-10 22:32:49 +00:00
|
|
|
},
|
|
|
|
Verify: s.verify,
|
2022-01-13 20:02:24 +00:00
|
|
|
}
|
|
|
|
}
|
2022-08-10 22:32:49 +00:00
|
|
|
return nil
|
2022-01-13 20:02:24 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
return errors.New(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if done {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|