directory.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. package detect
  2. import (
  3. "io"
  4. "os"
  5. "strings"
  6. "github.com/h2non/filetype"
  7. "github.com/rs/zerolog/log"
  8. "github.com/zricethezav/gitleaks/v8/report"
  9. "github.com/zricethezav/gitleaks/v8/sources"
  10. )
  11. func (d *Detector) DetectFiles(paths <-chan sources.ScanTarget) ([]report.Finding, error) {
  12. for pa := range paths {
  13. d.Sema.Go(func() error {
  14. logger := log.With().Str("path", pa.Path).Logger()
  15. log.Trace().Msgf("Scanning path: %s", pa)
  16. f, err := os.Open(pa.Path)
  17. if err != nil {
  18. return err
  19. }
  20. defer f.Close()
  21. // Get file size
  22. fileInfo, err := f.Stat()
  23. if err != nil {
  24. return err
  25. }
  26. fileSize := fileInfo.Size()
  27. if d.MaxTargetMegaBytes > 0 {
  28. rawLength := fileSize / 1000000
  29. if rawLength > int64(d.MaxTargetMegaBytes) {
  30. logger.Debug().
  31. Int64("size", rawLength).
  32. Msgf("Skipping file: exceeds --max-target-megabytes")
  33. return nil
  34. }
  35. }
  36. // Buffer to hold file chunks
  37. buf := make([]byte, chunkSize)
  38. totalLines := 0
  39. for {
  40. n, err := f.Read(buf)
  41. if err != nil && err != io.EOF {
  42. return err
  43. }
  44. if n == 0 {
  45. break
  46. }
  47. // TODO: optimization could be introduced here
  48. mimetype, err := filetype.Match(buf[:n])
  49. if err != nil {
  50. return err
  51. }
  52. if mimetype.MIME.Type == "application" {
  53. return nil // skip binary files
  54. }
  55. // Count the number of newlines in this chunk
  56. linesInChunk := strings.Count(string(buf[:n]), "\n")
  57. totalLines += linesInChunk
  58. fragment := Fragment{
  59. Raw: string(buf[:n]),
  60. FilePath: pa.Path,
  61. }
  62. if pa.Symlink != "" {
  63. fragment.SymlinkFile = pa.Symlink
  64. }
  65. for _, finding := range d.Detect(fragment) {
  66. // need to add 1 since line counting starts at 1
  67. finding.StartLine += (totalLines - linesInChunk) + 1
  68. finding.EndLine += (totalLines - linesInChunk) + 1
  69. d.addFinding(finding)
  70. }
  71. }
  72. return nil
  73. })
  74. }
  75. if err := d.Sema.Wait(); err != nil {
  76. return d.findings, err
  77. }
  78. return d.findings, nil
  79. }