ruby-qa/lib/rubyqa/runner.rb

111 lines
3.0 KiB
Ruby
Raw Permalink Normal View History

2024-06-29 15:00:22 -04:00
module RubyQA
2024-12-11 11:25:13 -05:00
require 'base64'
2024-06-29 15:00:22 -04:00
class CommandRunner
# Handles creating an interface for running arbitrary commands on a host/target
#
# To basically provide a unified interface to run commands via different methods (ssh, telnet, etc)
# Params:
# - ip
# - hostname (optional)
def initialize (data)
@data = data
verify_data
initialize_runner
end
def verify_data
if @data[:ip].empty?
if not @data[:hostname].empty?
begin
@data[:ip] = Resolv.getaddress(@data[:hostname])
rescue Resolv::ResolvError => error
raise "Host: Hostname provided, but did not resolve to IP"
end
else
raise "Host: No hostname or IP provided"
end
end
client_validations
end
def client_validations
# Handles client specific validations (port-connect test, etc)
end
def exec (command)
run_command(command)
end
def exec_sudo(command)
if @data[:password].empty?
raise "Password was not provided for host"
end
2024-12-11 11:25:13 -05:00
encoded_command = Base64.encode(command)
sudo_command = <<EOT
2024-12-11 11:25:13 -05:00
echo "#{@data[:password]}" | sudo -S bash -c "echo \"#{encoded_command}\" | base64 -d | bash"
2024-06-29 15:00:22 -04:00
EOT
2024-12-11 11:25:13 -05:00
run_command(sudo_command)
2024-06-29 15:00:22 -04:00
end
end
class SSH_Runner < CommandRunner
2024-12-11 11:25:13 -05:00
require 'net/ssh'
2024-06-29 15:00:22 -04:00
def initialize_runner
begin
if @data[:password]
@client = Net::SSH.start(@data[:ip], @data[:user], password: @data[:password])
else
@client = Net::SSH.start(@data[:ip], @data[:user])
end
rescue SocketError
raise "Failed to make ssh client for #{@data[:hostname]}"
end
end
def run_command(command)
@client.exec!(command).strip
end
end
class Telnet_Runner < CommandRunner
require 'net/ssh/telnet'
LOGIN_HANDLER=nil
TELNET_OPTS={
"Timeout" => 10,
"Prompt" => /[$:#]/
}
def initialize_runner
begin
@client = Net::SSH::Telnet.new( "Host" => @data[:ip], "Username" => @data[:user], "Password" => @data[:password])
# Since this is telnet, it doesn't filter out command sequences, so we have to set the PS1/prompt to something
# that is easily matched for filtering purposes
@client.cmd({"String" => "PS1='<filter_line>'; PROMPT_COMMANDS='';", "Match" => /filter_line/})
rescue SocketError
raise "Failed to make ssh client for #{@data[:hostname]}"
end
end
def run_command(command)
output = ""
## Doing intitial command (doesn't send white-space/newline)
lines = Array.new
filter_regex=/(^|#{command}|^\n$)/
output = @client.cmd({"String" => command, "Waittime" => 100, "Match" => /filter_line/})
# Have to clean output since telnet session will return all output, both stdin & stdout.
output = output.split(/\n/).reject do |line|
line.match?(/filter_line/) || line.match(/#{command}/)
end.join("\n")
output
end
2024-06-29 15:00:22 -04:00
end
end