Class: PWN::Plugins::REPL::AIConsole::Keyboard
- Inherits:
-
Object
- Object
- PWN::Plugins::REPL::AIConsole::Keyboard
- Defined in:
- lib/pwn/plugins/repl/ai_console.rb
Overview
Read a duplicated terminal rather than stdin, which belongs to tools.
Constant Summary collapse
- KEYS =
{ "\e[A" => :up, "\e[B" => :down, "\e[C" => :right, "\e[D" => :left, "\eOA" => :up, "\eOB" => :down, "\eOC" => :right, "\eOD" => :left, "\e[H" => :home, "\e[F" => :end, "\eOH" => :home, "\eOF" => :end, "\e[1~" => :home, "\e[4~" => :end, "\e[3~" => :delete, "\e[5~" => :page_up, "\e[6~" => :page_down, "\e[13;2u" => :newline, "\e[27;2;13~" => :newline, "\e[200~" => :paste_start, "\e[201~" => :paste_end }.freeze
Instance Method Summary collapse
- #call ⇒ Object
- #cursor_key ⇒ Object
- #decode_character ⇒ Object
-
#initialize(source) ⇒ Keyboard
constructor
A new instance of Keyboard.
Constructor Details
#initialize(source) ⇒ Keyboard
Returns a new instance of Keyboard.
116 117 118 119 |
# File 'lib/pwn/plugins/repl/ai_console.rb', line 116 def initialize(source) @source = source @buffer = +''.b end |
Instance Method Details
#call ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/pwn/plugins/repl/ai_console.rb', line 121 def call if @source.wait_readable(@buffer.empty? ? 0.04 : 0) chunk = @source.read_nonblock(4096, exception: false) return :eof if chunk.nil? && @buffer.empty? @buffer << chunk if chunk.is_a?(String) end return if @buffer.empty? match = KEYS.keys.find { |key| @buffer.start_with?(key) } return KEYS.fetch(@buffer.slice!(0, match.bytesize)) if match cursor = cursor_key return cursor unless cursor == :pending return if KEYS.keys.any? { |key| key.start_with?(@buffer) } && @source.wait_readable(0.04) decode_character end |
#cursor_key ⇒ Object
140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/pwn/plugins/repl/ai_console.rb', line 140 def cursor_key match = @buffer.match(/\A\e\[([0-9;]*)([ABCDHF])/) return :pending unless match return :pending if KEYS.keys.any? { |key| key.start_with?(match[0]) && key != match[0] } @buffer.slice!(0, match[0].bytesize) modifier = match[1].split(';')[1].to_i return if modifier > 1 { 'A' => :up, 'B' => :down, 'C' => :right, 'D' => :left, 'H' => :home, 'F' => :end }[match[2]] end |
#decode_character ⇒ Object
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/pwn/plugins/repl/ai_console.rb', line 152 def decode_character lead = @buffer.getbyte(0) size = case lead when 0..127 then 1 when 194..223 then 2 when 224..239 then 3 when 240..244 then 4 else 0 end prefix = @buffer.bytes.take(size) valid = size.positive? && prefix.drop(1).all? { |byte| byte.between?(128, 191) } second = prefix[1] valid &&= !(second && ((lead == 224 && second < 160) || (lead == 237 && second > 159) || (lead == 240 && second < 144) || (lead == 244 && second > 143))) if valid return if @buffer.bytesize < size return @buffer.slice!(0, size).force_encoding(Encoding::UTF_8) end @buffer.slice!(0, 1) '�' end |