Class: HEITT::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/cli/cli.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCLI

Returns a new instance of CLI.



10
11
12
13
14
15
16
17
18
19
# File 'lib/cli/cli.rb', line 10

def initialize
  @inputs = []
  @extended = false
  @verbose = false
  @output = ""
  @json = false
  @database = ""
  @show_regex_match = false
  @min_entropy = 3.5
end

Instance Attribute Details

#databaseObject

Returns the value of attribute database.



8
9
10
# File 'lib/cli/cli.rb', line 8

def database
  @database
end

#extendedObject

Returns the value of attribute extended.



8
9
10
# File 'lib/cli/cli.rb', line 8

def extended
  @extended
end

#inputsObject

Returns the value of attribute inputs.



8
9
10
# File 'lib/cli/cli.rb', line 8

def inputs
  @inputs
end

#jsonObject

Returns the value of attribute json.



8
9
10
# File 'lib/cli/cli.rb', line 8

def json
  @json
end

#min_entropyObject

Returns the value of attribute min_entropy.



8
9
10
# File 'lib/cli/cli.rb', line 8

def min_entropy
  @min_entropy
end

#outputObject

Returns the value of attribute output.



8
9
10
# File 'lib/cli/cli.rb', line 8

def output
  @output
end

#show_regex_matchObject

Returns the value of attribute show_regex_match.



8
9
10
# File 'lib/cli/cli.rb', line 8

def show_regex_match
  @show_regex_match
end

#verboseObject

Returns the value of attribute verbose.



8
9
10
# File 'lib/cli/cli.rb', line 8

def verbose
  @verbose
end

Instance Method Details

#parse!Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/cli/cli.rb', line 22

def parse!
  OptionParser.new do |opts|   
    opts.banner = ""
    opts.program_name = "heitt"
    opts.separator "#{header("=========================================================================")}"
    opts.separator "#{header("HEITT  v#{HEITT::VERSION} - Hash Extraction, Identification & Triage Tool")}"
    opts.separator "#{header("=========================================================================")}"
    opts.separator ""
    opts.separator "Extract and identify hashes from any input."
    opts.separator "Input may be hash string, a file or read from stin"
    opts.separator ""
    opts.separator "Usage: heitt [<INPUT(S)>] [OPTIONS]"
    opts.separator ""
    opts.separator "ARGUMENTS:"
    opts.separator "    [<INPUT(S)>]                     Hash string or filepath"
    opts.separator ""
    opts.separator "GENERAL OPTIONS:"
    opts.on("-h", "--help", "Show this help message and exit"){puts opts; exit}
    opts.on("-v", "--version", "Show version information"){puts "heitt v#{HEITT::VERSION} by jobotow (#{HEITT::GITHUB})"}
    opts.separator ""

    opts.separator ""
    opts.separator "OUTPUT OPTIONS:"
    opts.on("-V", "--verbose", "Show description and notes for each candidate") {@verbose = true}
    opts.on("-j", "--json","Output in json format") {@json = true}
    opts.on("-o", "--output FILEPATH", String, "File to write output to") {|v| @output = v}

    opts.separator ""
    opts.separator "FILTERING OPTIONS:"
    opts.on("-e", "--extended", "Show extended candidates") {@extended = true}
    opts.on("-r", "--regex-match", "Show regex-matched candidates") {@show_regex_match = true}
    opts.on("-E", "--min-entropy FLOAT", Float, "Minimum entropy threshold[default: 3.5]") {|v| puts "MIN ENTROPY: #{v}"; @min_entropy = v}

    opts.separator ""
    opts.separator "DATABASE OPTIONS:"
    opts.on("-D", "--database FILEPATH", String, "Use custom database") {|v| @database = v}

    opts.separator ""
    opts.separator "EXAMPLES:"
    opts.separator "    heitt b1946ac92492d2347c6235b4d2611184"
    opts.separator "    heitt auth.log"
    opts.separator "    heitt auth.log --json --output result.json"
    opts.separator "    heitt auth.log --extended --regex-match"
    opts.separator "    heitt auth.log --min-entropy 4.0"
    opts.separator "    cat auth.log | heitt "
    opts.separator ""
    opts.separator ""
    opts.separator "NOTES:"
    opts.separator "    JSON format is default when output is redirected or piped."
    opts.separator "    Regex-match candidates are hidden by default, use '-r' to show."
    opts.separator "    Running without input starts interactive mode."
    opts.separator "#{header("=========================================================================")}"
    opts.separator "#{header("END OF HELP")}"
    opts.separator "#{header("=========================================================================")}"
  end.parse!

  @inputs = if ARGV.empty?
    if $stdin.tty?
      # Interactive mode
      puts "#{header("=== HEITT INTERACTIVE MODE ====\n")}"
      puts "Enter a hash or file"
      loop do
        print "heitt> "
        input = $stdin.gets&.strip
        break if input.nil? || input.empty?
        results = HEITT::Scanner.scan(input, min_entropy: @min_entropy)
        groups = HEITT::Grouper.group(results)
        format = @json ? :json : :tree
        output = case format
        when :json
          HEITT::Formatter.json(groups, extended: @extended, show_regex_match: @show_regex_match)
        else
          HEITT::Formatter.tree(groups, extended: @extended, show_regex_match: @show_regex_match)
        end
        puts output
        puts ""
      end
    else
      [$stdin.read]
    end

    
  else
    ARGV.dup
  end
  self
end

#runObject



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/cli/cli.rb', line 110

def run 
  database = @database.empty? ? HEITT::DATABASE : load_custom_database(@database)
  
  format = @json || !$stdout.tty? ? :json : :tree
  output = @inputs.map do |input|
    results = HEITT::Scanner.scan(input, database: database, min_entropy: @min_entropy)
    groups = HEITT::Grouper.group(results)

    case format
    when :json
      HEITT::Formatter.json(groups, extended: @extended, show_regex_match: @show_regex_match)
    else
      HEITT::Formatter.tree(groups, extended: @extended, show_regex_match: @show_regex_match)
    end
  end.join("\n")

  unless @output.empty?
    File.write(@output, output)
  else
    puts output
  end
end