Add support for long arguments to Rex Parser
This commit is contained in:
parent
950e976f7b
commit
063c3936a9
|
@ -33,22 +33,22 @@ class Core
|
|||
|
||||
# Session command options
|
||||
@@sessions_opts = Rex::Parser::Arguments.new(
|
||||
"-c" => [ true, "Run a command on the session given with -i, or all" ],
|
||||
"-C" => [ true, "Run a Meterpreter Command on the session given with -i, or all" ],
|
||||
"-h" => [ false, "Help banner" ],
|
||||
"-i" => [ true, "Interact with the supplied session ID" ],
|
||||
"-l" => [ false, "List all active sessions" ],
|
||||
"-v" => [ false, "List all active sessions in verbose mode" ],
|
||||
"-d" => [ false, "List all inactive sessions" ],
|
||||
"-q" => [ false, "Quiet mode" ],
|
||||
"-k" => [ true, "Terminate sessions by session ID and/or range" ],
|
||||
"-K" => [ false, "Terminate all sessions" ],
|
||||
"-s" => [ true, "Run a script or module on the session given with -i, or all" ],
|
||||
"-u" => [ true, "Upgrade a shell to a meterpreter session on many platforms" ],
|
||||
"-t" => [ true, "Set a response timeout (default: 15)" ],
|
||||
"-S" => [ true, "Row search filter." ],
|
||||
"-x" => [ false, "Show extended information in the session table" ],
|
||||
"-n" => [ true, "Name or rename a session by ID" ])
|
||||
["-c", "--command"] => [ true, "Run a command on the session given with -i, or all" ],
|
||||
["-C", "--meterpreter-command"] => [ true, "Run a Meterpreter Command on the session given with -i, or all" ],
|
||||
["-h", "--help"] => [ false, "Help banner" ],
|
||||
["-i", "--interact"] => [ true, "Interact with the supplied session ID" ],
|
||||
["-l", "--list-active"] => [ false, "List all active sessions" ],
|
||||
["-v", "--list-verbose"] => [ false, "List all active sessions in verbose mode" ],
|
||||
["-d", "--list-inactive"] => [ false, "List all inactive sessions" ],
|
||||
["-q", "--quiet"] => [ false, "Quiet mode" ],
|
||||
["-k", "--kill"] => [ true, "Terminate sessions by session ID and/or range" ],
|
||||
["-K", "--kill-all"] => [ false, "Terminate all sessions" ],
|
||||
["-s", "--script"] => [ true, "Run a script or module on the session given with -i, or all" ],
|
||||
["-u", "--upgrade"] => [ true, "Upgrade a shell to a meterpreter session on many platforms" ],
|
||||
["-t", "--timeout"] => [ true, "Set a response timeout (default: 15)" ],
|
||||
["-S", "--search"] => [ true, "Row search filter." ],
|
||||
["-x", "--list-extended"] => [ false, "Show extended information in the session table" ],
|
||||
["-n", "--name"] => [ true, "Name or rename a session by ID" ])
|
||||
|
||||
|
||||
@@threads_opts = Rex::Parser::Arguments.new(
|
||||
|
@ -730,7 +730,7 @@ class Core
|
|||
|
||||
def cmd_history_tabs(str, words)
|
||||
return [] if words.length > 1
|
||||
@@history_opts.fmt.keys
|
||||
@@history_opts.option_keys
|
||||
end
|
||||
|
||||
def cmd_sleep_help
|
||||
|
@ -867,10 +867,10 @@ class Core
|
|||
|
||||
def cmd_threads_tabs(str, words)
|
||||
if words.length == 1
|
||||
return @@threads_opts.fmt.keys
|
||||
return @@threads_opts.option_keys
|
||||
end
|
||||
|
||||
if words.length == 2 and (@@threads_opts.fmt[words[1]] || [false])[0]
|
||||
if words.length == 2 && @@threads_opts.include?(words[1]) && @@threads_opts.arg_required?(words[1])
|
||||
return framework.threads.each_index.map{ |idx| idx.to_s }
|
||||
end
|
||||
|
||||
|
@ -1363,54 +1363,54 @@ class Core
|
|||
# Parse the command options
|
||||
@@sessions_opts.parse(args) do |opt, idx, val|
|
||||
case opt
|
||||
when "-q"
|
||||
when "-q", "--quiet"
|
||||
quiet = true
|
||||
# Run a command on all sessions, or the session given with -i
|
||||
when "-c"
|
||||
when "-c", "--command"
|
||||
method = 'cmd'
|
||||
cmds << val if val
|
||||
when "-C"
|
||||
when "-C", "--meterpreter-command"
|
||||
method = 'meterp-cmd'
|
||||
cmds << val if val
|
||||
# Display the list of inactive sessions
|
||||
when "-d"
|
||||
when "-d", "--list-inactive"
|
||||
show_inactive = true
|
||||
method = 'list_inactive'
|
||||
when "-x"
|
||||
when "-x", "--list-extended"
|
||||
show_extended = true
|
||||
when "-v"
|
||||
when "-v", "--list-verbose"
|
||||
verbose = true
|
||||
# Do something with the supplied session identifier instead of
|
||||
# all sessions.
|
||||
when "-i"
|
||||
when "-i", "--interact"
|
||||
sid = val
|
||||
# Display the list of active sessions
|
||||
when "-l"
|
||||
when "-l", "--list-active"
|
||||
show_active = true
|
||||
method = 'list'
|
||||
when "-k"
|
||||
when "-k", "--kill"
|
||||
method = 'kill'
|
||||
sid = val || false
|
||||
when "-K"
|
||||
when "-K", "--kill-all"
|
||||
method = 'killall'
|
||||
# Run a script or module on specified sessions
|
||||
when "-s"
|
||||
when "-s", "--script"
|
||||
unless script
|
||||
method = 'script'
|
||||
script = val
|
||||
end
|
||||
# Upload and exec to the specific command session
|
||||
when "-u"
|
||||
when "-u", "--upgrade"
|
||||
method = 'upexec'
|
||||
sid = val || false
|
||||
# Search for specific session
|
||||
when "-S", "--search"
|
||||
search_term = val
|
||||
# Display help banner
|
||||
when "-h"
|
||||
when "-h", "--help"
|
||||
cmd_sessions_help
|
||||
return false
|
||||
when "-t"
|
||||
when "-t", "--timeout"
|
||||
if val.to_s =~ /^\d+$/
|
||||
response_timeout = val.to_i
|
||||
end
|
||||
|
@ -1713,17 +1713,17 @@ class Core
|
|||
|
||||
def cmd_sessions_tabs(str, words)
|
||||
if words.length == 1
|
||||
return @@sessions_opts.fmt.keys.select { |opt| opt.start_with?(str) }
|
||||
return @@sessions_opts.option_keys.select { |opt| opt.start_with?(str) }
|
||||
end
|
||||
|
||||
case words[-1]
|
||||
when "-i", "-k", "-u"
|
||||
when "-i", "--interact", "-k", "--kill", "-u", "--upgrade"
|
||||
return framework.sessions.keys.map { |k| k.to_s }
|
||||
|
||||
when "-c"
|
||||
when "-c", "--command"
|
||||
# Can't really complete commands hehe
|
||||
|
||||
when "-s"
|
||||
when "-s", "--search"
|
||||
# XXX: Complete scripts
|
||||
|
||||
end
|
||||
|
|
|
@ -144,7 +144,7 @@ class Msf::Ui::Console::CommandDispatcher::Developer
|
|||
def cmd_irb_tabs(_str, words)
|
||||
return [] if words.length > 1
|
||||
|
||||
@@irb_opts.fmt.keys
|
||||
@@irb_opts.option_keys
|
||||
end
|
||||
|
||||
def cmd_pry_help
|
||||
|
|
|
@ -289,9 +289,9 @@ module Msf
|
|||
# at least 1 when tab completion has reached this stage since the command itself has been completed
|
||||
|
||||
def cmd_jobs_tabs(_str, words)
|
||||
return @@jobs_opts.fmt.keys if words.length == 1
|
||||
return @@jobs_opts.option_keys if words.length == 1
|
||||
|
||||
if words.length == 2 && (@@jobs_opts.fmt[words[1]] || [false])[0]
|
||||
if words.length == 2 && @@jobs_opts.include?(words[1]) && @@jobs_opts.arg_required?(words[1])
|
||||
return framework.jobs.keys
|
||||
end
|
||||
|
||||
|
|
|
@ -538,7 +538,7 @@ module Msf
|
|||
|
||||
def cmd_search_tabs(str, words)
|
||||
if words.length == 1
|
||||
return @@search_opts.fmt.keys
|
||||
return @@search_opts.option_keys
|
||||
end
|
||||
|
||||
[]
|
||||
|
|
|
@ -87,7 +87,7 @@ module ModuleActionCommands
|
|||
# at least 1 when tab completion has reached this stage since the command itself has been completed
|
||||
#
|
||||
def cmd_run_tabs(str, words)
|
||||
flags = @@module_opts_with_action_support.fmt.keys
|
||||
flags = @@module_opts_with_action_support.option_keys
|
||||
options = tab_complete_option(active_module, str, words)
|
||||
flags + options
|
||||
end
|
||||
|
|
|
@ -24,18 +24,18 @@ module ModuleArgumentParsing
|
|||
'-q' => [ false, 'Run the module in quiet mode with no output' ]
|
||||
)
|
||||
|
||||
@@module_opts_with_action_support = Rex::Parser::Arguments.new(@@module_opts.fmt.merge(
|
||||
@@module_opts_with_action_support = @@module_opts.merge(
|
||||
'-a' => [ true, 'The action to use. If none is specified, ACTION is used.']
|
||||
))
|
||||
)
|
||||
|
||||
@@exploit_opts = Rex::Parser::Arguments.new(@@module_opts.fmt.merge(
|
||||
@@exploit_opts = @@module_opts.merge(
|
||||
'-e' => [ true, 'The payload encoder to use. If none is specified, ENCODER is used.' ],
|
||||
'-f' => [ false, 'Force the exploit to run regardless of the value of MinimumRank.' ],
|
||||
'-n' => [ true, 'The NOP generator to use. If none is specified, NOP is used.' ],
|
||||
'-p' => [ true, 'The payload to use. If none is specified, PAYLOAD is used.' ],
|
||||
'-t' => [ true, 'The target index to use. If none is specified, TARGET is used.' ],
|
||||
'-z' => [ false, 'Do not interact with the session after successful exploitation.' ]
|
||||
))
|
||||
)
|
||||
|
||||
def parse_check_opts(args)
|
||||
help_cmd = proc do |_result|
|
||||
|
|
|
@ -16,12 +16,17 @@ module Rex
|
|||
# Initializes the format list with an array of formats like:
|
||||
#
|
||||
# Arguments.new(
|
||||
# '-b' => [ false, "some text" ]
|
||||
# '-b' => [ false, "some text" ],
|
||||
# ['-b'] => [ false, "some text" ],
|
||||
# '--sample' => [ false, "sample long arg" ],
|
||||
# '--also-a-sample' => [ false, "sample longer arg" ],
|
||||
# ['-x', '--execute'] => [ true, "mixing long and short args" ]
|
||||
# )
|
||||
#
|
||||
def initialize(fmt)
|
||||
self.fmt = fmt
|
||||
self.longest = fmt.keys.max_by(&:length)
|
||||
normalised_fmt = fmt.map { |key, metadata| [Array(key), metadata] }.to_h
|
||||
self.fmt = normalised_fmt
|
||||
self.longest = normalised_fmt.keys.map { |key| key.flatten.join(', ') }.max_by(&:length)
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -35,6 +40,11 @@ module Rex
|
|||
# Parses the supplied arguments into a set of options.
|
||||
#
|
||||
def parse(args, &_block)
|
||||
# e.g. '-x' or '-xyz'
|
||||
short_flag = /^-[a-zA-Z]+$/
|
||||
# e.g. '--verbose', '--very-verbose' or '--very-very-verbose'
|
||||
long_flag = /^--([a-zA-Z]+)((-[a-zA-Z]+)*)$/
|
||||
|
||||
skip_next = false
|
||||
|
||||
args.each_with_index do |arg, idx|
|
||||
|
@ -43,22 +53,27 @@ module Rex
|
|||
next
|
||||
end
|
||||
|
||||
if arg.length > 1 && arg[0] == '-' && arg[1] != '-'
|
||||
arg.split('').each do |flag|
|
||||
fmt.each_pair do |fmtspec, val|
|
||||
next if fmtspec != "-#{flag}"
|
||||
param = nil
|
||||
if arg =~ short_flag
|
||||
arg.split('')[1..-1].each do |letter|
|
||||
next unless include?("-#{letter}")
|
||||
|
||||
param = nil
|
||||
|
||||
if val[0]
|
||||
param = args[idx + 1]
|
||||
skip_next = true
|
||||
end
|
||||
|
||||
yield fmtspec, idx, param
|
||||
if arg_required?("-#{letter}")
|
||||
param = args[idx + 1]
|
||||
skip_next = true
|
||||
end
|
||||
|
||||
yield "-#{letter}", idx, param
|
||||
end
|
||||
elsif arg =~ long_flag && include?(arg)
|
||||
if arg_required?(arg)
|
||||
param = args[idx + 1]
|
||||
skip_next = true
|
||||
end
|
||||
|
||||
yield arg, idx, param
|
||||
else
|
||||
# else treat the passed in flag as argument
|
||||
yield nil, idx, arg
|
||||
end
|
||||
end
|
||||
|
@ -70,10 +85,15 @@ module Rex
|
|||
def usage
|
||||
txt = ["\nOPTIONS:\n"]
|
||||
|
||||
fmt.sort.each do |entry|
|
||||
fmtspec, val = entry
|
||||
fmt.sort_by { |key, _metadata| key.to_s.downcase }.each do |key, val|
|
||||
opt = val[0] ? " <opt> " : " "
|
||||
txt << " #{fmtspec.ljust(longest.length)}#{opt}#{val[1]}"
|
||||
|
||||
# Get all arguments for a command
|
||||
output = key.join(', ')
|
||||
output += opt
|
||||
|
||||
# Left align the fmt options and <opt> string
|
||||
txt << " #{(output).ljust((longest + opt).length)}#{val[1]}"
|
||||
end
|
||||
|
||||
txt << ""
|
||||
|
@ -81,15 +101,38 @@ module Rex
|
|||
end
|
||||
|
||||
def include?(search)
|
||||
fmt.include?(search)
|
||||
fmt.keys.flatten.include?(search)
|
||||
end
|
||||
|
||||
def arg_required?(opt)
|
||||
fmt[opt][0] if fmt[opt]
|
||||
value = select_value_from_fmt_option(opt)
|
||||
return false if value.nil?
|
||||
|
||||
value.first
|
||||
end
|
||||
|
||||
def option_keys
|
||||
fmt.keys.flatten
|
||||
end
|
||||
|
||||
# Return new Parser object featuring options from the base object and including the options hash that was passed in
|
||||
def merge(to_merge)
|
||||
return fmt unless to_merge.is_a?(Hash)
|
||||
|
||||
Rex::Parser::Arguments.new(fmt.clone.merge(to_merge))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_accessor :fmt # :nodoc:
|
||||
attr_accessor :longest # :nodoc:
|
||||
|
||||
def select_value_from_fmt_option(option)
|
||||
fmt_option = fmt.find { |key, value| value if key.include?(option) }
|
||||
return if fmt_option.nil?
|
||||
|
||||
fmt_option[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -166,7 +166,7 @@ class Console::CommandDispatcher::Core
|
|||
end
|
||||
|
||||
def cmd_pivot_tabs(str, words)
|
||||
return %w[list add remove] + @@pivot_opts.fmt.keys if words.length == 1
|
||||
return %w[list add remove] + @@pivot_opts.option_keys if words.length == 1
|
||||
|
||||
case words[-1]
|
||||
when '-a'
|
||||
|
@ -180,7 +180,7 @@ class Console::CommandDispatcher::Core
|
|||
when '-t'
|
||||
return ['pipe']
|
||||
when 'add', 'remove'
|
||||
return @@pivot_opts.fmt.keys
|
||||
return @@pivot_opts.option_keys
|
||||
end
|
||||
|
||||
[]
|
||||
|
@ -436,7 +436,7 @@ class Console::CommandDispatcher::Core
|
|||
def cmd_channel_tabs(str, words)
|
||||
case words.length
|
||||
when 1
|
||||
@@channel_opts.fmt.keys
|
||||
@@channel_opts.option_keys
|
||||
when 2
|
||||
case words[1]
|
||||
when '-k', '-c', '-i', '-r', '-w'
|
||||
|
@ -558,7 +558,7 @@ class Console::CommandDispatcher::Core
|
|||
|
||||
def cmd_irb_tabs(str, words)
|
||||
return [] if words.length > 1
|
||||
@@irb_opts.fmt.keys
|
||||
@@irb_opts.option_keys
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -645,7 +645,7 @@ class Console::CommandDispatcher::Core
|
|||
|
||||
def cmd_set_timeouts_tabs(str, words)
|
||||
return [] if words.length > 1
|
||||
@@set_timeouts_opts.fmt.keys
|
||||
@@set_timeouts_opts.option_keys
|
||||
end
|
||||
|
||||
def cmd_set_timeouts(*args)
|
||||
|
@ -887,7 +887,7 @@ class Console::CommandDispatcher::Core
|
|||
end
|
||||
|
||||
def cmd_transport_tabs(str, words)
|
||||
return %w[list change add next prev remove] + @@transport_opts.fmt.keys if words.length == 1
|
||||
return %w[list change add next prev remove] + @@transport_opts.option_keys if words.length == 1
|
||||
|
||||
case words[-1]
|
||||
when '-c'
|
||||
|
@ -899,7 +899,7 @@ class Console::CommandDispatcher::Core
|
|||
when '-t'
|
||||
return %w[reverse_tcp reverse_http reverse_https bind_tcp]
|
||||
when 'add', 'remove', 'change'
|
||||
return @@transport_opts.fmt.keys
|
||||
return @@transport_opts.option_keys
|
||||
end
|
||||
|
||||
[]
|
||||
|
|
|
@ -359,7 +359,7 @@ class Console::CommandDispatcher::Stdapi::Net
|
|||
end
|
||||
|
||||
def cmd_route_tabs(str, words)
|
||||
return %w[add delete list] + @@route_opts.fmt.keys if words.length == 1
|
||||
return %w[add delete list] + @@route_opts.option_keys if words.length == 1
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -577,7 +577,7 @@ class Console::CommandDispatcher::Stdapi::Net
|
|||
end
|
||||
|
||||
def cmd_portfwd_tabs(str, words)
|
||||
return %w[add delete list flush] + @@portfwd_opts.fmt.keys if words.length == 1
|
||||
return %w[add delete list flush] + @@portfwd_opts.option_keys if words.length == 1
|
||||
|
||||
case words[-1]
|
||||
when '-L'
|
||||
|
@ -587,7 +587,7 @@ class Console::CommandDispatcher::Stdapi::Net
|
|||
return (1..client.pfservice.each_tcp_relay { |lh, lp, rh, rp, opts| }.length).to_a.map!(&:to_s)
|
||||
end
|
||||
when 'add', 'delete', 'list', 'flush'
|
||||
return @@portfwd_opts.fmt.keys
|
||||
return @@portfwd_opts.option_keys
|
||||
end
|
||||
|
||||
[]
|
||||
|
@ -671,4 +671,3 @@ end
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -37,9 +37,9 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
"-p" => [ false, "Execute process in a pty (if available on target platform)" ],
|
||||
"-s" => [ true, "Execute process in a given session as the session user" ])
|
||||
|
||||
@@execute_opts_with_raw_mode = Rex::Parser::Arguments.new(@@execute_opts.fmt.merge(
|
||||
@@execute_opts_with_raw_mode = @@execute_opts.merge(
|
||||
{ '-r' => [ false, 'Raw mode'] }
|
||||
))
|
||||
)
|
||||
|
||||
#
|
||||
# Options used by the 'shell' command.
|
||||
|
@ -49,9 +49,9 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
"-l" => [ false, "List available shells (/etc/shells)." ],
|
||||
"-t" => [ true, "Spawn a PTY shell (/bin/bash if no argument given)." ]) # ssh(1) -t
|
||||
|
||||
@@shell_opts_with_fully_interactive_shell = Rex::Parser::Arguments.new(@@shell_opts.fmt.merge(
|
||||
@@shell_opts_with_fully_interactive_shell = @@shell_opts.merge(
|
||||
{ '-i' => [ false, 'Drop into a fully interactive shell. (Only used in conjunction with `-t`).'] }
|
||||
))
|
||||
)
|
||||
|
||||
#
|
||||
# Options used by the 'reboot' command.
|
||||
|
@ -298,7 +298,7 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
end
|
||||
|
||||
def cmd_execute_tabs(str, words)
|
||||
return execute_opts.fmt.keys if words.length == 1
|
||||
return execute_opts.option_keys if words.length == 1
|
||||
[]
|
||||
end
|
||||
|
||||
|
@ -310,7 +310,7 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
end
|
||||
|
||||
def cmd_shell_tabs(str, words)
|
||||
return shell_opts.fmt.keys if words.length == 1
|
||||
return shell_opts.option_keys if words.length == 1
|
||||
[]
|
||||
end
|
||||
|
||||
|
@ -819,7 +819,7 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
# Tab completion for the ps command
|
||||
#
|
||||
def cmd_ps_tabs(str, words)
|
||||
return @@ps_opts.fmt.keys if words.length == 1
|
||||
return @@ps_opts.option_keys if words.length == 1
|
||||
|
||||
case words[-1]
|
||||
when '-A'
|
||||
|
@ -1104,7 +1104,7 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
#
|
||||
def cmd_reg_tabs(str, words)
|
||||
if words.length == 1
|
||||
return %w[enumkey createkey deletekey queryclass setval deleteval queryval] + @@reg_opts.fmt.keys
|
||||
return %w[enumkey createkey deletekey queryclass setval deleteval queryval] + @@reg_opts.option_keys
|
||||
end
|
||||
|
||||
case words[-1]
|
||||
|
@ -1123,7 +1123,7 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
when '-w'
|
||||
return %w[32 64]
|
||||
when 'enumkey', 'createkey', 'deletekey', 'queryclass', 'setval', 'deleteval', 'queryval'
|
||||
return @@reg_opts.fmt.keys
|
||||
return @@reg_opts.option_keys
|
||||
end
|
||||
|
||||
[]
|
||||
|
@ -1247,7 +1247,7 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
end
|
||||
|
||||
def cmd_shutdown_tabs(str, words)
|
||||
return @@shutdown_opts.fmt.keys if words.length == 1
|
||||
return @@shutdown_opts.option_keys if words.length == 1
|
||||
|
||||
case words[-1]
|
||||
when '-f'
|
||||
|
@ -1336,7 +1336,7 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|||
# Tab completion for the suspend command
|
||||
#
|
||||
def cmd_suspend_tabs(str, words)
|
||||
return @@suspend_opts.fmt.keys if words.length == 1
|
||||
return @@suspend_opts.option_keys if words.length == 1
|
||||
[]
|
||||
end
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ class Plugin::Alias < Msf::Plugin
|
|||
def cmd_alias_tabs(str, words)
|
||||
if words.length <= 1
|
||||
#puts "1 word or less"
|
||||
return @@alias_opts.fmt.keys + tab_complete_aliases_and_commands
|
||||
return @@alias_opts.option_keys + tab_complete_aliases_and_commands
|
||||
else
|
||||
#puts "more than 1 word"
|
||||
return tab_complete_aliases_and_commands
|
||||
|
|
|
@ -3,10 +3,11 @@ require 'rspec'
|
|||
RSpec.describe Rex::Parser::Arguments do
|
||||
let(:subject) do
|
||||
Rex::Parser::Arguments.new(
|
||||
'-h' => [false, 'Help banner.'],
|
||||
'-j' => [false, 'Run in the context of a job.'],
|
||||
'-o' => [true, 'A comma separated list of options in VAR=VAL format.'],
|
||||
'-q' => [false, 'Run the module in quiet mode with no output']
|
||||
['-h', '--help'] => [false, 'Help banner.'],
|
||||
['-j', '--job'] => [false, 'Run in the context of a job.'],
|
||||
'--long-flag-with-no-corresponding-short-option-name' => [false, 'A long flag with no corresponding short option name'],
|
||||
['-o', '--options'] => [true, 'A comma separated list of options in VAR=VAL format.'],
|
||||
['-q', '--quiet'] => [false, 'Run the module in quiet mode with no output']
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -41,23 +42,89 @@ RSpec.describe Rex::Parser::Arguments do
|
|||
|
||||
it 'ignores unknown flags' do
|
||||
input = ['-a', 'action_name']
|
||||
# Not sure if this flag dropping is intentional behavior
|
||||
expected_yields = [
|
||||
# '-a' is dropped, 'action_name' is used as an argument
|
||||
[nil, 1, 'action_name'],
|
||||
]
|
||||
expect { |b| subject.parse(input, &b) }.to yield_successive_args(*expected_yields)
|
||||
end
|
||||
|
||||
it 'ignores combined flags that do not exist' do
|
||||
it 'treats combined flags that do not exist as an argument' do
|
||||
input = ['-unknown-flags']
|
||||
# Not sure if this flag dropping is intentional behavior
|
||||
expected_yields = [
|
||||
['-o', 0, nil],
|
||||
[nil, 0, '-unknown-flags']
|
||||
]
|
||||
expect { |b| subject.parse(input, &b) }.to yield_successive_args(*expected_yields)
|
||||
end
|
||||
end
|
||||
|
||||
it 'parses a single long flag correctly' do
|
||||
input = ['--help']
|
||||
expected_yields = [
|
||||
['--help', 0, nil]
|
||||
]
|
||||
expect { |b| subject.parse(input, &b) }.to yield_successive_args(*expected_yields)
|
||||
end
|
||||
|
||||
it 'parses multiple long flags correctly' do
|
||||
input = ['--help', '--job']
|
||||
expected_yields = [
|
||||
['--help', 0, nil],
|
||||
['--job', 1, nil]
|
||||
]
|
||||
expect { |b| subject.parse(input, &b) }.to yield_successive_args(*expected_yields)
|
||||
end
|
||||
|
||||
it 'parses a long flag and short flag correctly' do
|
||||
input = ['--help', '-h']
|
||||
expected_yields = [
|
||||
['--help', 0, nil],
|
||||
['-h', 1, nil]
|
||||
]
|
||||
expect { |b| subject.parse(input, &b) }.to yield_successive_args(*expected_yields)
|
||||
end
|
||||
|
||||
it 'parses a short flag when Rex Arguments are in an array correctly' do
|
||||
input = ['-o']
|
||||
expected_yields = [
|
||||
['-o', 0, nil]
|
||||
]
|
||||
expect { |b| subject.parse(input, &b) }.to yield_successive_args(*expected_yields)
|
||||
end
|
||||
|
||||
it 'parses a long flag when in arguments array correctly' do
|
||||
input = ['--options', 'option-arg']
|
||||
expected_yields = [
|
||||
['--options', 0, 'option-arg']
|
||||
]
|
||||
expect { |b| subject.parse(input, &b) }.to yield_successive_args(*expected_yields)
|
||||
end
|
||||
|
||||
it 'parses multiple long flags when in an arguments array correctly' do
|
||||
input = ['--quiet', '--options', 'sample-option']
|
||||
expected_yields = [
|
||||
['--quiet', 0, nil],
|
||||
['--options', 1, 'sample-option']
|
||||
]
|
||||
expect { |b| subject.parse(input, &b) }.to yield_successive_args(*expected_yields)
|
||||
end
|
||||
|
||||
it 'parses a non-existent long flag correctly' do
|
||||
input = ['--ultra-quiet']
|
||||
expected_yields = [
|
||||
[nil, 0, '--ultra-quiet']
|
||||
]
|
||||
expect { |b| subject.parse(input, &b) }.to yield_successive_args(*expected_yields)
|
||||
end
|
||||
|
||||
it 'parses a long flag that is not in an array correctly' do
|
||||
input = ['--long-flag-with-no-corresponding-short-option-name']
|
||||
expected_yields = [
|
||||
['--long-flag-with-no-corresponding-short-option-name', 0, nil]
|
||||
]
|
||||
expect { |b| subject.parse(input, &b) }.to yield_successive_args(*expected_yields)
|
||||
end
|
||||
|
||||
context 'when arguments are supplied' do
|
||||
it 'treats an ip address as an argument' do
|
||||
input = ['127.0.0.1']
|
||||
|
@ -82,15 +149,22 @@ RSpec.describe Rex::Parser::Arguments do
|
|||
]
|
||||
expect { |b| subject.parse(input, &b) }.to yield_successive_args(*expected_yields)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'treats long-form flags as arguments' do
|
||||
input = ['--foo', '123']
|
||||
expected_yields = [
|
||||
[nil, 0, '--foo'],
|
||||
[nil, 1, '123'],
|
||||
]
|
||||
expect { |b| subject.parse(input, &b) }.to yield_successive_args(*expected_yields)
|
||||
end
|
||||
describe '#inspect' do
|
||||
it 'prints usage in a sorted order correctly' do
|
||||
expected_output = <<~EXPECTED
|
||||
|
||||
OPTIONS:
|
||||
|
||||
--long-flag-with-no-corresponding-short-option-name A long flag with no corresponding short option name
|
||||
-h, --help Help banner.
|
||||
-j, --job Run in the context of a job.
|
||||
-o, --options <opt> A comma separated list of options in VAR=VAL format.
|
||||
-q, --quiet Run the module in quiet mode with no output
|
||||
EXPECTED
|
||||
expect(subject.usage).to eq(expected_output)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue