Module: Rex::Ui::Text::DispatcherShell::CommandDispatcher
- Included in:
- Msf::Ui::Console::CommandDispatcher, Post::HWBridge::Ui::Console::CommandDispatcher, Post::Meterpreter::Ui::Console::CommandDispatcher
- Defined in:
- lib/rex/ui/text/dispatcher_shell.rb
Overview
Empty template base class for command dispatchers.
Defined Under Namespace
Modules: ClassMethods
Instance Attribute Summary collapse
-
#shell ⇒ Object
No tab completion items by default.
-
#tab_complete_items ⇒ Object
No tab completion items by default.
Class Method Summary collapse
Instance Method Summary collapse
-
#cmd_help(cmd = nil, *ignored) ⇒ Object
(also: #cmd_?)
Displays the help banner.
- #cmd_help_help ⇒ Object
-
#cmd_help_tabs(str, words) ⇒ Object
Tab completion for the help command.
-
#commands ⇒ Object
Returns nil for an empty set of commands.
-
#deprecated_cmd(method = nil, *args) ⇒ Object
Print a warning that the called command is deprecated and optionally forward to the replacement
method
(useful for when commands are renamed). -
#deprecated_commands ⇒ Object
Returns an empty set of commands.
- #deprecated_help(method = nil) ⇒ Object
-
#docs_dir ⇒ Object
Return the subdir of the ‘documentation/` directory that should be used to find usage documentation.
-
#help_to_s(opts = {}) ⇒ Object
Return a pretty, user-readable table of commands provided by this dispatcher.
-
#initialize(shell) ⇒ Object
Initializes the command dispatcher mixin.
-
#print(msg = '') ⇒ Object
Wraps shell.print.
-
#print_error(msg = '') ⇒ Object
(also: #print_bad)
Wraps shell.print_error.
-
#print_good(msg = '') ⇒ Object
Wraps shell.print_good.
-
#print_line(msg = '') ⇒ Object
Wraps shell.print_line.
-
#print_status(msg = '') ⇒ Object
Wraps shell.print_status.
-
#print_warning(msg = '') ⇒ Object
Wraps shell.print_warning.
-
#tab_complete_directory(str, words) ⇒ Object
Return a list of possible directory for tab completion.
-
#tab_complete_filenames(str, words) ⇒ Object
Provide a generic tab completion for file names.
-
#tab_complete_generic(fmt, str, words) ⇒ Object
Provide a generic tab completion function based on the specification pass as fmt.
-
#tab_complete_source_address ⇒ Object
Return a list of possible source addresses for tab completion.
-
#unknown_command(method, line) ⇒ Symbol?
A callback that can be used to handle unknown commands.
-
#update_prompt(*args) ⇒ Object
Wraps shell.update_prompt.
Instance Attribute Details
#shell ⇒ Object
No tab completion items by default
278 279 280 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 278 def shell @shell end |
#tab_complete_items ⇒ Object
No tab completion items by default
278 279 280 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 278 def tab_complete_items @tab_complete_items end |
Class Method Details
.included(base) ⇒ Object
49 50 51 52 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 49 def self.included(base) # Install class methods so they are inheritable base.extend(ClassMethods) end |
Instance Method Details
#cmd_help(cmd = nil, *ignored) ⇒ Object Also known as: cmd_?
Displays the help banner. With no arguments, this is just a list of all commands grouped by dispatcher. Otherwise, tries to use a method named cmd_#<code>cmd</code>_help for the first dispatcher that has a command named cmd
. If no such method exists, uses cmd
as a regex to compare against each enstacked dispatcher’s name and dumps commands of any that match.
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 172 def cmd_help(cmd=nil, *ignored) if cmd help_found = false cmd_found = false shell.dispatcher_stack.each do |dispatcher| next unless dispatcher.respond_to?(:commands) next if (dispatcher.commands.nil?) next if (dispatcher.commands.length == 0) if dispatcher.respond_to?("cmd_#{cmd}", true) cmd_found = true break unless dispatcher.respond_to?("cmd_#{cmd}_help", true) dispatcher.send("cmd_#{cmd}_help") help_found = true break end end unless cmd_found # We didn't find a cmd, try it as a dispatcher name shell.dispatcher_stack.each do |dispatcher| if dispatcher.name =~ /#{cmd}/i print_line(dispatcher.help_to_s) cmd_found = help_found = true end end end if docs_dir && File.exist?(File.join(docs_dir, cmd + '.md')) print_line print(File.read(File.join(docs_dir, cmd + '.md'))) end print_error("No help for #{cmd}, try -h") if cmd_found and not help_found print_error("No such command") if not cmd_found else print(shell.help_to_s) if docs_dir && File.exist?(File.join(docs_dir + '.md')) print_line print(File.read(File.join(docs_dir + '.md'))) end end end |
#cmd_help_help ⇒ Object
160 161 162 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 160 def cmd_help_help print_line "There's only so much I can do" end |
#cmd_help_tabs(str, words) ⇒ Object
Tab completion for the help command
By default just returns a list of all commands in all dispatchers.
220 221 222 223 224 225 226 227 228 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 220 def cmd_help_tabs(str, words) return [] if words.length > 1 tabs = [] shell.dispatcher_stack.each { |dispatcher| tabs += dispatcher.commands.keys } return tabs end |
#commands ⇒ Object
Returns nil for an empty set of commands.
This method should be overridden to return a Hash with command names for keys and brief help text for values.
68 69 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 68 def commands end |
#deprecated_cmd(method = nil, *args) ⇒ Object
Print a warning that the called command is deprecated and optionally forward to the replacement method
(useful for when commands are renamed).
131 132 133 134 135 136 137 138 139 140 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 131 def deprecated_cmd(method=nil, *args) cmd = caller[0].match(/`cmd_(.*)'/)[1] print_error "The #{cmd} command is DEPRECATED" if cmd == "db_autopwn" print_error "See http://r-7.co/xY65Zr instead" elsif method and self.respond_to?("cmd_#{method}", true) print_error "Use #{method} instead" self.send("cmd_#{method}", *args) end end |
#deprecated_commands ⇒ Object
Returns an empty set of commands.
This method should be overridden if the dispatcher has commands that should be treated as deprecated. Deprecated commands will not show up in help and will not tab-complete, but will still be callable.
78 79 80 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 78 def deprecated_commands [] end |
#deprecated_help(method = nil) ⇒ Object
142 143 144 145 146 147 148 149 150 151 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 142 def deprecated_help(method=nil) cmd = caller[0].match(/`cmd_(.*)_help'/)[1] print_error "The #{cmd} command is DEPRECATED" if cmd == "db_autopwn" print_error "See http://r-7.co/xY65Zr instead" elsif method and self.respond_to?("cmd_#{method}_help", true) print_error "Use 'help #{method}' instead" self.send("cmd_#{method}_help") end end |
#docs_dir ⇒ Object
Return the subdir of the ‘documentation/` directory that should be used to find usage documentation
TODO: get this value from somewhere that doesn’t invert a bunch of dependencies
271 272 273 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 271 def docs_dir File.(File.join(__FILE__, '..', '..', '..', '..', '..', 'documentation', 'cli')) end |
#help_to_s(opts = {}) ⇒ Object
Return a pretty, user-readable table of commands provided by this dispatcher.
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 236 def help_to_s(opts={}) # If this dispatcher has no commands, we can't do anything useful. return "" if commands.nil? or commands.length == 0 # Display the commands tbl = Rex::Text::Table.new( 'Header' => "#{self.name} Commands", 'Indent' => opts['Indent'] || 4, 'Columns' => [ 'Command', 'Description' ], 'ColProps' => { 'Command' => { 'Width' => 12 } }) commands.sort.each { |c| tbl << c } return "\n" + tbl.to_s + "\n" end |
#initialize(shell) ⇒ Object
Initializes the command dispatcher mixin.
57 58 59 60 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 57 def initialize(shell) self.shell = shell self.tab_complete_items = [] end |
#print(msg = '') ⇒ Object
Wraps shell.print
122 123 124 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 122 def print(msg = '') shell.print(msg) end |
#print_error(msg = '') ⇒ Object Also known as: print_bad
Wraps shell.print_error
85 86 87 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 85 def print_error(msg = '') shell.print_error(msg) end |
#print_good(msg = '') ⇒ Object
Wraps shell.print_good
108 109 110 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 108 def print_good(msg = '') shell.print_good(msg) end |
#print_line(msg = '') ⇒ Object
Wraps shell.print_line
101 102 103 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 101 def print_line(msg = '') shell.print_line(msg) end |
#print_status(msg = '') ⇒ Object
Wraps shell.print_status
94 95 96 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 94 def print_status(msg = '') shell.print_status(msg) end |
#print_warning(msg = '') ⇒ Object
Wraps shell.print_warning
115 116 117 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 115 def print_warning(msg = '') shell.print_warning(msg) end |
#tab_complete_directory(str, words) ⇒ Object
Return a list of possible directory for tab completion.
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 299 def tab_complete_directory(str, words) directory = str[-1] == File::SEPARATOR ? str : File.dirname(str) filename = str[-1] == File::SEPARATOR ? '' : File.basename(str) entries = Dir.entries(directory).select { |fp| fp.start_with?(filename) } dirs = entries - ['.', '..'] dirs = dirs.map { |fp| File.join(directory, fp).gsub(/\A\.\//, '') } dirs = dirs.select { |x| File.directory?(x) } dirs = dirs.map { |x| x + File::SEPARATOR } if dirs.length == 1 && dirs[0] != str && dirs[0].end_with?(File::SEPARATOR) # If Readline receives a single value from this function, it will assume we're done with the tab # completing, and add an extra space at the end. # This is annoying if we're recursively tab-traversing our way through subdirectories - # we may want to continue traversing, but MSF will add a space, requiring us to back up to continue # tab-completing our way through successive subdirectories. ::Readline.completion_append_character = nil end if dirs.length == 0 && File.directory?(str) # we've hit the end of the road dirs = [str] end dirs end |
#tab_complete_filenames(str, words) ⇒ Object
Provide a generic tab completion for file names.
If the only completion is a directory, this descends into that directory and continues completions with filenames contained within.
286 287 288 289 290 291 292 293 294 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 286 def tab_complete_filenames(str, words) matches = ::Readline::FILENAME_COMPLETION_PROC.call(str) if matches and matches.length == 1 and File.directory?(matches[0]) dir = matches[0] dir += File::SEPARATOR if dir[-1,1] != File::SEPARATOR matches = ::Readline::FILENAME_COMPLETION_PROC.call(dir) end matches.nil? ? [] : matches end |
#tab_complete_generic(fmt, str, words) ⇒ Object
Provide a generic tab completion function based on the specification pass as fmt. The fmt argument in a hash where values are an array defining how the command should be completed. The first element of the array can be one of:
nil - This argument is a flag and takes no option.
true - This argument takes an option with no suggestions.
:address - This option is a source address.
:bool - This option is a boolean.
:file - This option is a file path.
Array - This option is an array of possible values.
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 336 def tab_complete_generic(fmt, str, words) last_word = words[-1] fmt = fmt.select { |key, value| last_word == key || !words.include?(key) } val = fmt[last_word] return fmt.keys if !val # the last word does not look like a fmtspec arg = val[0] return fmt.keys if !arg # the last word is a fmtspec that takes no argument tabs = [] if arg.to_s.to_sym == :address tabs = tab_complete_source_address elsif arg.to_s.to_sym == :bool tabs = ['true', 'false'] elsif arg.to_s.to_sym == :file tabs = tab_complete_filenames(str, words) elsif arg.kind_of?(Array) tabs = arg.map {|a| a.to_s} end tabs end |
#tab_complete_source_address ⇒ Object
Return a list of possible source addresses for tab completion.
361 362 363 364 365 366 367 368 369 370 371 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 361 def tab_complete_source_address addresses = [Rex::Socket.source_address] # getifaddrs was introduced in 2.1.2 if ::Socket.respond_to?(:getifaddrs) ifaddrs = ::Socket.getifaddrs.select do |ifaddr| ifaddr.addr && ifaddr.addr.ip? end addresses += ifaddrs.map { |ifaddr| ifaddr.addr.ip_address } end addresses end |
#unknown_command(method, line) ⇒ Symbol?
A callback that can be used to handle unknown commands. This can for example, allow a dispatcher to mark a command as being disabled.
380 381 382 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 380 def unknown_command(method, line) nil end |
#update_prompt(*args) ⇒ Object
Wraps shell.update_prompt
156 157 158 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 156 def update_prompt(*args) shell.update_prompt(*args) end |