Module: Wpxf::Cli::AutoComplete

Included in:
Console
Defined in:
lib/wpxf/cli/auto_complete.rb

Overview

Functionality for configuring auto-complete functionality in Readline lib.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#autocomplete_listObject

Returns the value of attribute autocomplete_list.



118
119
120
# File 'lib/wpxf/cli/auto_complete.rb', line 118

def autocomplete_list
  @autocomplete_list
end

Instance Method Details

#auto_complete_proc(input, list) ⇒ Array?

Process the current CLI input buffer to determine auto-complete options.

Parameters:

  • input (String)

    the current input buffer.

  • list (Array)

    the array of auto-complete options.

Returns:

  • (Array, nil)

    an array of possible commands.



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
109
110
111
112
113
114
115
116
# File 'lib/wpxf/cli/auto_complete.rb', line 68

def auto_complete_proc(input, list)
  res = nil

  # Nothing on this level, so return previous level.
  return res if list.keys.empty?

  # Enumerate each cmd/arg on this level, if there's a match, descend
  # into the next level and update the return value if anything is
  # returned and repeat.
  list.each do |k, v|
    next unless input =~ /^#{k}\s+/i
    res = list.keys
    trimmed_input = input.gsub(/^(#{k}\s+)(.+)/i, '\2')

    # If there wasn't another level of input, return the list from
    # the next level as the suggestions. For example, if `input` is
    # "show " (emphasis on trailing space), then return
    # ["show options", "show exploits"].
    if input.eql?(trimmed_input) && !v.keys.empty?
      res = v.keys.map { |r| input + r }
    else
      # If there was another level of input (e.g. "show o"), descend
      # into that level to find the partial matches (such as "show options").
      descended_res = auto_complete_proc(trimmed_input, v)
      if descended_res
        res = descended_res.grep(/^#{Regexp.escape(trimmed_input)}/)

        # If we have descended, we'll need to prepend the input that
        # we trimmed back into the returned results as to not overwrite
        # the previous levels in STDIN.
        res = res.map { |r| input.gsub(/^(#{k}\s+)(.+)/i, '\1') + r }
      else
        res = res.grep(/^#{Regexp.escape(input)}/)
      end

      break
    end
  end

  # If no full matches were found, check if there are partial matches
  # on the current level, and if so, return the current level as the
  # list of possible values.
  unless res
    grep_res = list.keys.grep(/^#{Regexp.escape(input)}/)
    res = grep_res if grep_res && !grep_res.empty?
  end

  res
end

#build_cmd_listObject



51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/wpxf/cli/auto_complete.rb', line 51

def build_cmd_list
  cmds = {}
  permitted_commands.each { |c| cmds[c] = {} }
  Wpxf::Models::Module.each { |m| cmds['use'][m.path] = {} }
  cmds['show'] = {
    'options' => {},
    'advanced' => {},
    'exploits' => {},
    'auxiliary' => {}
  }
  cmds
end

#build_opts_hashObject



20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/wpxf/cli/auto_complete.rb', line 20

def build_opts_hash
  opts_hash = {}
  return opts_hash unless context

  mod = context.module
  opts = mod.options.map(&:name)
  opts += mod.payload.options.map(&:name) if mod.payload
  opts.each do |o|
    opts_hash[o] = {}
  end

  opts_hash
end

#build_payload_names_hashObject



34
35
36
37
38
39
40
41
# File 'lib/wpxf/cli/auto_complete.rb', line 34

def build_payload_names_hash
  opts_hash = {}
  return opts_hash unless context&.module&.exploit_module?

  opts_hash['payload'] = {}
  Wpxf::Payloads.payload_list.each { |p| opts_hash['payload'][p[:name]] = {} }
  opts_hash
end

#readline_completion_proc(input) ⇒ Object



14
15
16
17
18
# File 'lib/wpxf/cli/auto_complete.rb', line 14

def readline_completion_proc(input)
  res = auto_complete_proc(input, autocomplete_list)
  return [] unless res
  res
end

#refresh_autocomplete_optionsObject



43
44
45
46
47
48
49
# File 'lib/wpxf/cli/auto_complete.rb', line 43

def refresh_autocomplete_options
  opts_hash = build_opts_hash.merge(build_payload_names_hash)

  %w[set unset gset gunset setg unsetg].each do |key|
    autocomplete_list[key] = opts_hash
  end
end

#setup_auto_completeObject



7
8
9
10
11
12
# File 'lib/wpxf/cli/auto_complete.rb', line 7

def setup_auto_complete
  self.autocomplete_list = build_cmd_list
  Readline.completer_word_break_characters = ''
  Readline.completion_append_character = ' '
  Readline.completion_proc = method(:readline_completion_proc)
end