Module: Rex::Ui::Text::Shell
- Includes:
- Text::Color
- Included in:
- DispatcherShell, PseudoShell
- Defined in:
- lib/rex/ui/text/shell.rb,
lib/rex/ui/text/shell/history_manager.rb
Overview
The shell class provides a command-prompt style interface in a generic fashion.
Defined Under Namespace
Modules: InputShell Classes: HistoryManager
Instance Attribute Summary collapse
-
#cont_flag ⇒ Object
readonly
protected
:nodoc:.
-
#cont_prompt ⇒ Object
protected
:nodoc:.
-
#disable_output ⇒ Object
Whether or not output has been disabled.
-
#framework ⇒ Object
Returns the value of attribute framework.
-
#hist_last_saved ⇒ Object
the number of history lines when last saved/loaded.
-
#histfile ⇒ Object
protected
:nodoc:.
-
#history_manager ⇒ Object
Returns the value of attribute history_manager.
-
#input ⇒ Object
The input handle to read user input from.
-
#local_hostname ⇒ Object
protected
:nodoc:.
-
#local_username ⇒ Object
protected
:nodoc:.
-
#log_source ⇒ Object
protected
:nodoc:.
-
#name ⇒ Object
protected
Returns the value of attribute name.
-
#on_command_proc ⇒ Object
Returns the value of attribute on_command_proc.
-
#on_print_proc ⇒ Object
Returns the value of attribute on_print_proc.
-
#output ⇒ Object
The output handle to write output to.
-
#prompt ⇒ Object
Returns the value of attribute prompt.
-
#prompt_char ⇒ Object
Returns the value of attribute prompt_char.
-
#stop_count ⇒ Object
protected
:nodoc:.
-
#stop_flag ⇒ Object
protected
:nodoc:.
-
#tab_complete_proc ⇒ Object
protected
:nodoc:.
Instance Method Summary collapse
-
#_print_prompt(prompt) ⇒ Object
protected
Print the prompt, but do not log it.
-
#format_prompt(str) ⇒ Object
protected
Handle prompt substitutions.
-
#get_input_line ⇒ Object
protected
Get a single line of input, following continuation directives as necessary.
- #init_tab_complete ⇒ Object
-
#init_ui(in_input = nil, in_output = nil) ⇒ Object
Initializes the user interface input/output classes.
-
#initialize(prompt, prompt_char = '>', histfile = nil, framework = nil, name = nil) ⇒ Object
Initializes a shell that has a prompt and can be interacted with.
-
#log_input(buf) ⇒ Object
protected
Writes the supplied input to the log source if one has been registered.
-
#log_output(buf) ⇒ Object
protected
Writes the supplied output to the log source if one has been registered.
-
#parse_line(line) ⇒ Object
protected
Parse a line into an array of arguments.
-
#print(msg = '') ⇒ Object
Prints a raw message to the output handle.
-
#print_error(msg = '') ⇒ Object
(also: #print_bad)
Prints an error message to the output handle.
-
#print_good(msg = '') ⇒ Object
Prints a good message to the output handle.
-
#print_line(msg = '') ⇒ Object
Prints a line of text to the output handle.
-
#print_status(msg = '') ⇒ Object
Prints a status message to the output handle.
-
#print_warning(msg = '') ⇒ Object
Prints a warning message to the output handle.
-
#prompt_yesno(query) ⇒ Object
protected
Prompt the user for input if possible.
-
#reset_ui ⇒ Object
Resets the user interface handles.
-
#run(&block) ⇒ Object
Run the command processing loop.
-
#set_log_source(log_source) ⇒ Object
Sets the log source that should be used for logging input and output.
-
#stop ⇒ Object
Stop processing user input.
-
#stopped? ⇒ Boolean
Checks to see if the shell has stopped.
- #supports_color? ⇒ Boolean protected
-
#tab_complete(str) ⇒ Object
Performs tab completion on the supplied string.
-
#unset_log_source ⇒ Object
Unsets the log source so that logging becomes disabled.
-
#update_prompt(new_prompt = self.prompt, new_prompt_char = self.prompt_char) ⇒ Object
Change the input prompt.
-
#with_history_manager_context ⇒ Object
protected
Executes the yielded block under the context of a new HistoryManager context.
Instance Attribute Details
#cont_flag ⇒ Object (protected)
:nodoc:
510 511 512 |
# File 'lib/rex/ui/text/shell.rb', line 510 def cont_flag @cont_flag end |
#cont_prompt ⇒ Object (protected)
:nodoc:
505 506 507 |
# File 'lib/rex/ui/text/shell.rb', line 505 def cont_prompt @cont_prompt end |
#disable_output ⇒ Object
Whether or not output has been disabled.
280 281 282 |
# File 'lib/rex/ui/text/shell.rb', line 280 def disable_output @disable_output end |
#framework ⇒ Object
Returns the value of attribute framework.
293 294 295 |
# File 'lib/rex/ui/text/shell.rb', line 293 def framework @framework end |
#hist_last_saved ⇒ Object
the number of history lines when last saved/loaded
295 296 297 |
# File 'lib/rex/ui/text/shell.rb', line 295 def hist_last_saved @hist_last_saved end |
#histfile ⇒ Object (protected)
:nodoc:
507 508 509 |
# File 'lib/rex/ui/text/shell.rb', line 507 def histfile @histfile end |
#history_manager ⇒ Object
Returns the value of attribute history_manager.
294 295 296 |
# File 'lib/rex/ui/text/shell.rb', line 294 def history_manager @history_manager end |
#input ⇒ Object
The input handle to read user input from.
284 285 286 |
# File 'lib/rex/ui/text/shell.rb', line 284 def input @input end |
#local_hostname ⇒ Object (protected)
:nodoc:
509 510 511 |
# File 'lib/rex/ui/text/shell.rb', line 509 def local_hostname @local_hostname end |
#local_username ⇒ Object (protected)
:nodoc:
509 510 511 |
# File 'lib/rex/ui/text/shell.rb', line 509 def local_username @local_username end |
#log_source ⇒ Object (protected)
:nodoc:
508 509 510 |
# File 'lib/rex/ui/text/shell.rb', line 508 def log_source @log_source end |
#name ⇒ Object (protected)
Returns the value of attribute name.
511 512 513 |
# File 'lib/rex/ui/text/shell.rb', line 511 def name @name end |
#on_command_proc ⇒ Object
Returns the value of attribute on_command_proc.
291 292 293 |
# File 'lib/rex/ui/text/shell.rb', line 291 def on_command_proc @on_command_proc end |
#on_print_proc ⇒ Object
Returns the value of attribute on_print_proc.
292 293 294 |
# File 'lib/rex/ui/text/shell.rb', line 292 def on_print_proc @on_print_proc end |
#output ⇒ Object
The output handle to write output to.
288 289 290 |
# File 'lib/rex/ui/text/shell.rb', line 288 def output @output end |
#prompt ⇒ Object
Returns the value of attribute prompt.
290 291 292 |
# File 'lib/rex/ui/text/shell.rb', line 290 def prompt @prompt end |
#prompt_char ⇒ Object
Returns the value of attribute prompt_char.
290 291 292 |
# File 'lib/rex/ui/text/shell.rb', line 290 def prompt_char @prompt_char end |
#stop_count ⇒ Object (protected)
:nodoc:
508 509 510 |
# File 'lib/rex/ui/text/shell.rb', line 508 def stop_count @stop_count end |
#stop_flag ⇒ Object (protected)
:nodoc:
505 506 507 |
# File 'lib/rex/ui/text/shell.rb', line 505 def stop_flag @stop_flag end |
#tab_complete_proc ⇒ Object (protected)
:nodoc:
506 507 508 |
# File 'lib/rex/ui/text/shell.rb', line 506 def tab_complete_proc @tab_complete_proc end |
Instance Method Details
#_print_prompt(prompt) ⇒ Object (protected)
Print the prompt, but do not log it.
381 382 383 |
# File 'lib/rex/ui/text/shell.rb', line 381 def _print_prompt(prompt) output.print(prompt) end |
#format_prompt(str) ⇒ Object (protected)
Handle prompt substitutions
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 |
# File 'lib/rex/ui/text/shell.rb', line 414 def format_prompt(str) return str unless framework # find the active session session = framework.sessions.values.find { |session| session.interacting } default = 'unknown' formatted = '' skip_next = false for prefix, spec in str.split('').each_cons(2) do if skip_next skip_next = false next end unless prefix == '%' formatted << prefix skip_next = false next end skip_next = true if spec == 'T' if framework.datastore['PromptTimeFormat'] strftime_format = framework.datastore['PromptTimeFormat'] else strftime_format = ::Time::DATE_FORMATS[:db].to_s end formatted << ::Time.now.strftime(strftime_format).to_s elsif spec == 'W' && framework.db.active formatted << framework.db.workspace.name elsif session sysinfo = session.respond_to?(:sys) ? session.sys.config.sysinfo : nil case spec when 'A' formatted << (sysinfo.nil? ? default : sysinfo['Architecture']) when 'D' formatted << (session.respond_to?(:fs) ? session.fs.dir.getwd(refresh: false) : default) when 'd' formatted << ::Dir.getwd when 'H' formatted << (sysinfo.nil? ? default : sysinfo['Computer']) when 'h' formatted << (self.local_hostname || default).chomp when 'I' formatted << session.tunnel_peer when 'i' formatted << session.tunnel_local when 'M' formatted << session.session_type when 'S' formatted << session.sid.to_s when 'U' formatted << (session.respond_to?(:sys) ? session.sys.config.getuid(refresh: false) : default) when 'u' formatted << (self.local_username || default).chomp else formatted << prefix skip_next = false end else case spec when 'H' formatted << (self.local_hostname || default).chomp when 'J' formatted << framework.jobs.length.to_s when 'U' formatted << (self.local_username || default).chomp when 'S' formatted << framework.sessions.length.to_s when 'L' formatted << Rex::Socket.source_address when 'D' formatted << ::Dir.getwd else formatted << prefix skip_next = false end end end if str.length > 0 && !skip_next formatted << str[-1] end formatted end |
#get_input_line ⇒ Object (protected)
Get a single line of input, following continuation directives as necessary.
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
# File 'lib/rex/ui/text/shell.rb', line 324 def get_input_line line = "\\\n" prompt_needs_reset = false self.cont_flag = false while line =~ /(^|[^\\])\\\s*$/ # Strip \ and all the trailing whitespace line.sub!(/\\\s*/, '') if line.length > 0 # Using update_prompt will overwrite the primary prompt input.prompt = output.update_prompt(self.cont_prompt) self.cont_flag = true prompt_needs_reset = true end output.input = input str = input.pgets if str line << str else line = nil end output.input = nil log_output(input.prompt) end self.cont_flag = false if prompt_needs_reset # The continuation prompt was used so reset the prompt update_prompt end line end |
#init_tab_complete ⇒ Object
66 67 68 69 70 71 72 |
# File 'lib/rex/ui/text/shell.rb', line 66 def init_tab_complete if (self.input and self.input.supports_readline) # Unless cont_flag because there's no tab complete for continuation lines self.input = Input::Readline.new(lambda { |str| tab_complete(str) unless cont_flag }) self.input.output = self.output end end |
#init_ui(in_input = nil, in_output = nil) ⇒ Object
Initializes the user interface input/output classes.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/rex/ui/text/shell.rb', line 77 def init_ui(in_input = nil, in_output = nil) # Initialize the input and output methods self.input = in_input self.output = in_output if (self.input) # Extend the input medium as an input shell if the input medium # isn't intrinsicly a shell. if (self.input.intrinsic_shell? == false) self.input.extend(InputShell) end self.input.output = self.output end end |
#initialize(prompt, prompt_char = '>', histfile = nil, framework = nil, name = nil) ⇒ Object
Initializes a shell that has a prompt and can be interacted with.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/rex/ui/text/shell.rb', line 43 def initialize(prompt, prompt_char = '>', histfile = nil, framework = nil, name = nil) # Set the stop flag to false self.stop_flag = false self.disable_output = false self.stop_count = 0 self.name = name # Initialize the prompt self.cont_prompt = ' > ' self.cont_flag = false self.prompt = prompt self.prompt_char = prompt_char self.histfile = histfile self.hist_last_saved = 0 # Static prompt variables self.local_hostname = ENV['HOSTNAME'] || try_exec('hostname')&.split('.')&.first&.rstrip || ENV['COMPUTERNAME'] self.local_username = ENV['USER'] || try_exec('whoami')&.rstrip || ENV['USERNAME'] self.framework = framework end |
#log_input(buf) ⇒ Object (protected)
Writes the supplied input to the log source if one has been registered.
388 389 390 |
# File 'lib/rex/ui/text/shell.rb', line 388 def log_input(buf) rlog(buf, log_source) if (log_source) end |
#log_output(buf) ⇒ Object (protected)
Writes the supplied output to the log source if one has been registered.
395 396 397 |
# File 'lib/rex/ui/text/shell.rb', line 395 def log_output(buf) rlog(buf, log_source) if (log_source) end |
#parse_line(line) ⇒ Object (protected)
Parse a line into an array of arguments.
364 365 366 367 368 369 370 371 372 373 374 375 376 |
# File 'lib/rex/ui/text/shell.rb', line 364 def parse_line(line) log_input(line) line.gsub!(/(\r|\n)/, '') begin return args = Rex::Parser::Arguments.from_s(line) rescue ::ArgumentError print_error("Parse error: #{$!}") end return [] end |
#print(msg = '') ⇒ Object
Prints a raw message to the output handle.
271 272 273 274 275 |
# File 'lib/rex/ui/text/shell.rb', line 271 def print(msg='') return if (disable_output == true) self.on_print_proc.call(msg) if self.on_print_proc log_output(output.print(msg)) end |
#print_error(msg = '') ⇒ Object Also known as: print_bad
Prints an error message to the output handle.
217 218 219 220 221 222 223 224 |
# File 'lib/rex/ui/text/shell.rb', line 217 def print_error(msg='') return if (output.nil?) return if (msg.nil?) self.on_print_proc.call(msg) if self.on_print_proc # Errors are not subject to disabled output log_output(output.print_error(msg)) end |
#print_good(msg = '') ⇒ Object
Prints a good message to the output handle.
241 242 243 244 245 246 |
# File 'lib/rex/ui/text/shell.rb', line 241 def print_good(msg='') return if (disable_output == true) self.on_print_proc.call(msg) if self.on_print_proc log_output(output.print_good(msg)) end |
#print_line(msg = '') ⇒ Object
Prints a line of text to the output handle.
251 252 253 254 255 256 |
# File 'lib/rex/ui/text/shell.rb', line 251 def print_line(msg='') return if (disable_output == true) self.on_print_proc.call(msg) if self.on_print_proc log_output(output.print_line(msg)) end |
#print_status(msg = '') ⇒ Object
Prints a status message to the output handle.
231 232 233 234 235 236 |
# File 'lib/rex/ui/text/shell.rb', line 231 def print_status(msg='') return if (disable_output == true) self.on_print_proc.call(msg) if self.on_print_proc log_output(output.print_status(msg)) end |
#print_warning(msg = '') ⇒ Object
Prints a warning message to the output handle.
261 262 263 264 265 266 |
# File 'lib/rex/ui/text/shell.rb', line 261 def print_warning(msg='') return if (disable_output == true) self.on_print_proc.call(msg) if self.on_print_proc log_output(output.print_warning(msg)) end |
#prompt_yesno(query) ⇒ Object (protected)
Prompt the user for input if possible. Special edition for use inside commands.
402 403 404 405 406 407 408 409 |
# File 'lib/rex/ui/text/shell.rb', line 402 def prompt_yesno(query) p = "#{query} [y/N]" old_p = [self.prompt, self.prompt_char] update_prompt p, ' ' /^y/i === get_input_line ensure update_prompt *old_p end |
#reset_ui ⇒ Object
Resets the user interface handles.
96 97 98 |
# File 'lib/rex/ui/text/shell.rb', line 96 def reset_ui init_ui end |
#run(&block) ⇒ Object
Run the command processing loop.
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/rex/ui/text/shell.rb', line 124 def run(&block) begin require 'pry' # pry history will not be loaded by default when pry is used as a breakpoint like `binding.pry` Pry.config.history_load = false rescue LoadError # Pry is a development dependency, if not available suppressing history_load can be safely ignored. end with_history_manager_context do begin while true # If the stop flag was set or we've hit EOF, break out break if self.stop_flag || self.stop_count > 1 init_tab_complete update_prompt line = get_input_line # If you have sessions active, this will give you a shot to exit # gracefully. If you really are ambitious, 2 eofs will kick this out if input.eof? || line == nil self.stop_count += 1 next if self.stop_count > 1 if block block.call('quit') elsif respond_to?(:run_single) # PseudoShell does not provide run_single run_single('quit') end # If a block was passed in, pass the line to it. If it returns true, # break out of the shell loop. elsif block break if block.call(line) # Otherwise, call what should be an overridden instance method to # process the line. else run_single(line) self.stop_count = 0 end end # Prevent accidental console quits rescue ::Interrupt output.print("Interrupt: use the 'exit' command to quit\n") retry end end end |
#set_log_source(log_source) ⇒ Object
Sets the log source that should be used for logging input and output.
103 104 105 |
# File 'lib/rex/ui/text/shell.rb', line 103 def set_log_source(log_source) self.log_source = log_source end |
#stop ⇒ Object
Stop processing user input.
180 181 182 |
# File 'lib/rex/ui/text/shell.rb', line 180 def stop self.stop_flag = true end |
#stopped? ⇒ Boolean
Checks to see if the shell has stopped.
187 188 189 |
# File 'lib/rex/ui/text/shell.rb', line 187 def stopped? self.stop_flag end |
#supports_color? ⇒ Boolean (protected)
317 318 319 |
# File 'lib/rex/ui/text/shell.rb', line 317 def supports_color? true end |
#tab_complete(str) ⇒ Object
Performs tab completion on the supplied string.
117 118 119 |
# File 'lib/rex/ui/text/shell.rb', line 117 def tab_complete(str) return tab_complete_proc(str) if (tab_complete_proc) end |
#unset_log_source ⇒ Object
Unsets the log source so that logging becomes disabled.
110 111 112 |
# File 'lib/rex/ui/text/shell.rb', line 110 def unset_log_source set_log_source(nil) end |
#update_prompt(new_prompt = self.prompt, new_prompt_char = self.prompt_char) ⇒ Object
Change the input prompt.
prompt - the actual prompt new_prompt_char the char to append to the prompt
196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/rex/ui/text/shell.rb', line 196 def update_prompt(new_prompt = self.prompt, new_prompt_char = self.prompt_char) if (self.input) p = substitute_colors(new_prompt + ' ' + new_prompt_char + ' ', true) # Save the prompt before any substitutions self.prompt = new_prompt self.prompt_char = new_prompt_char # Set the actual prompt to the saved prompt with any substitutions # or updates from our output driver, be they color or whatever self.input.prompt = self.output.update_prompt(format_prompt(p)) end end |
#with_history_manager_context ⇒ Object (protected)
Executes the yielded block under the context of a new HistoryManager context. The shell’s history will be flushed to disk when no longer interacting with the shell. If no history manager is available, the history will not be persisted.
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/rex/ui/text/shell.rb', line 301 def with_history_manager_context history_manager = self.history_manager || framework&.history_manager return yield unless history_manager begin history_manager.with_context(history_file: histfile, name: name) do self.hist_last_saved = Readline::HISTORY.length yield end ensure history_manager.flush self.hist_last_saved = Readline::HISTORY.length end end |