Module: Rex::Post::Sql::Ui::Console::InteractiveSqlClient
- Includes:
- Ui::Interactive
- Defined in:
- lib/rex/post/sql/ui/console/interactive_sql_client.rb
Overview
Mixin that is meant to extend a sql client class in a manner that adds interactive capabilities.
Instance Attribute Summary collapse
-
#client_dispatcher ⇒ Object
Returns the value of attribute client_dispatcher.
-
#on_log_proc ⇒ Object
Returns the value of attribute on_log_proc.
Attributes included from Ui::Interactive
#completed, #interacting, #next_session, #on_command_proc, #on_print_proc, #on_run_command_error_proc, #orig_suspend, #orig_usr1, #orig_winch
Attributes included from Ui::Subscriber::Input
Attributes included from Ui::Subscriber::Output
Instance Method Summary collapse
- #_fallback ⇒ Object
-
#_interact ⇒ Object
Interacts with self.
-
#_interact_complete ⇒ Object
We don’t need to do any clean-up when finishing the interaction with the REPL.
-
#_interrupt ⇒ Object
Called when an interrupt is sent.
- #_multiline ⇒ Object
-
#_multiline_with_fallback ⇒ Object
Try getting multi-line input support provided by Reline, fall back to Readline.
-
#_suspend ⇒ Object
Suspends interaction with the interactive REPL interpreter.
- #_winch ⇒ Object
Methods included from Ui::Interactive
#_local_fd, #_remote_fd, #_stream_read_local_write_remote, #_stream_read_remote_write_local, #detach, #handle_suspend, #handle_usr1, #handle_winch, #interact, #interact_stream, #prompt, #prompt_yesno, #restore_suspend, #restore_usr1, #restore_winch
Methods included from Ui::Subscriber
Methods included from Ui::Subscriber::Input
Methods included from Ui::Subscriber::Output
#flush, #print, #print_blank_line, #print_error, #print_good, #print_line, #print_status, #print_warning
Instance Attribute Details
#client_dispatcher ⇒ Object
Returns the value of attribute client_dispatcher.
177 178 179 |
# File 'lib/rex/post/sql/ui/console/interactive_sql_client.rb', line 177 def client_dispatcher @client_dispatcher end |
#on_log_proc ⇒ Object
Returns the value of attribute on_log_proc.
177 178 179 |
# File 'lib/rex/post/sql/ui/console/interactive_sql_client.rb', line 177 def on_log_proc @on_log_proc end |
Instance Method Details
#_fallback ⇒ Object
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/rex/post/sql/ui/console/interactive_sql_client.rb', line 155 def _fallback stop_words = %w[stop s exit e end quit q].freeze line_buffer = [] while (line = ::Readline.readline(prompt = line_buffer.empty? ? 'SQL >> ' : 'SQL *> ', add_history = true)) return { status: :exit, result: nil } unless self.interacting if stop_words.include? line.chomp.downcase self.interacting = false print_status 'Exiting Interactive mode.' return { status: :exit, result: nil } end next if line.empty? line_buffer.append line break if line.end_with? ';' end { status: :success, result: line_buffer.join(' ') } end |
#_interact ⇒ Object
Interacts with self.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/rex/post/sql/ui/console/interactive_sql_client.rb', line 21 def _interact while self.interacting sql_input = _multiline_with_fallback self.interacting = (sql_input[:status] != :exit) if sql_input[:status] == :help client_dispatcher.query_interactive_help end # We need to check that the user is still interacting, i.e. if ctrl+z is triggered when requesting user input break unless (self.interacting && sql_input[:result]) self.on_command_proc.call(sql_input[:result].strip) if self.on_command_proc formatted_query = client_dispatcher.process_query(query: sql_input[:result]) print_status "Executing query: #{formatted_query}" client_dispatcher.cmd_query(formatted_query) end end |
#_interact_complete ⇒ Object
We don’t need to do any clean-up when finishing the interaction with the REPL
60 61 62 |
# File 'lib/rex/post/sql/ui/console/interactive_sql_client.rb', line 60 def _interact_complete # noop end |
#_interrupt ⇒ Object
Called when an interrupt is sent.
44 45 46 |
# File 'lib/rex/post/sql/ui/console/interactive_sql_client.rb', line 44 def _interrupt prompt_yesno('Terminate interactive SQL prompt?') end |
#_multiline ⇒ Object
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 117 118 119 120 121 122 123 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 |
# File 'lib/rex/post/sql/ui/console/interactive_sql_client.rb', line 89 def _multiline begin require 'reline' unless defined?(::Reline) rescue ::LoadError => e elog('Failed to load Reline', e) return { status: :fail, errors: [e] } end stop_words = %w[stop s exit e end quit q].freeze help_words = %w[help h].freeze finished = false help = false begin result = nil prompt_proc_before = ::Reline.prompt_proc ::Reline.prompt_proc = proc { |line_buffer| line_buffer.each_with_index.map { |_line, i| i > 0 ? 'SQL *> ' : 'SQL >> ' } } # We want to do this in a loop # multiline_input is the whole string that the user has input, not just the current line. raw_query = ::Reline.readmultiline('SQL >> ', use_history = true) do |multiline_input| # The user pressed ctrl + c or ctrl + z and wants to background our SQL prompt unless self.interacting result = { status: :exit, result: nil } next true end # When the user has pressed the enter key with no input, don't run any queries; # simply give them a new prompt on a new line. if multiline_input.chomp.empty? result = { status: :success, result: nil } next true end if multiline_input.split.count == 1 # In the case only a stop word was input, exit out of the REPL shell finished = stop_words.include?(multiline_input.split.last) # In the case when only a help word was input call the help command help = help_words.include?(multiline_input.split.last) end finished || help || multiline_input.split.last&.end_with?(';') end rescue ::StandardError => e elog('Failed to get multi-line SQL query from user', e) ensure ::Reline.prompt_proc = prompt_proc_before end if result return result end if help return { status: :help, result: nil } end if finished self.interacting = false print_status 'Exiting Interactive mode.' return { status: :exit, result: nil } end { status: :success, result: raw_query } end |
#_multiline_with_fallback ⇒ Object
Try getting multi-line input support provided by Reline, fall back to Readline.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/rex/post/sql/ui/console/interactive_sql_client.rb', line 69 def _multiline_with_fallback name = session.type query = {} history_file = Msf::Config.history_file_for_session_type(session_type: name, interactive: true) return { status: :fail, errors: ["Unable to get history file for session type: #{name}"] } if history_file.nil? # Multiline (Reline) and fallback (Readline) have separate history contexts as they are two different libraries. framework.history_manager.with_context(history_file: history_file , name: name, input_library: :reline) do query = _multiline end if query[:status] == :fail framework.history_manager.with_context(history_file: history_file, name: name, input_library: :readline) do query = _fallback end end query end |
#_suspend ⇒ Object
Suspends interaction with the interactive REPL interpreter
51 52 53 54 55 |
# File 'lib/rex/post/sql/ui/console/interactive_sql_client.rb', line 51 def _suspend if (prompt_yesno('Background interactive SQL prompt?') == true) self.interacting = false end end |
#_winch ⇒ Object
64 65 66 |
# File 'lib/rex/post/sql/ui/console/interactive_sql_client.rb', line 64 def _winch # noop end |