Class: Rex::Parser::Arguments

Inherits:
Object
  • Object
show all
Defined in:
lib/rex/parser/arguments.rb

Overview

This class parses arguments in a getopt style format, kind of. Unfortunately, the default ruby getopt implementation will only work on ARGV, so we can’t use it.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(fmt) ⇒ Arguments

Initializes the format list with an array of formats like:

Arguments.new(

'-z'                => [ has_argument, "some text", "<argument_description>" ],
'-b'                => [ false, "some text"                 ],
['-b']              => [ false, "some text"                 ],
['-x', '--execute'] => [ true, "mixing long and short args" ],
['-t', '--test']    => [ true, "testing custom <opt> value", "<arg_to_test>" ],
['--long-flag']     => [ false, "sample long flag" ]

)



34
35
36
37
38
# File 'lib/rex/parser/arguments.rb', line 34

def initialize(fmt)
  normalised_fmt = fmt.map { |key, | [Array(key), ] }.to_h
  self.fmt = normalised_fmt
  self.longest = normalised_fmt.each_pair.map { |key, value| key.flatten.join(', ') + (value[0] ? ' ' + value[2].to_s : '') }.max_by(&:length)
end

Class Method Details

.from_s(str) ⇒ Object

Takes a string and converts it into an array of arguments.



43
44
45
# File 'lib/rex/parser/arguments.rb', line 43

def self.from_s(str)
  Shellwords.shellwords(str)
end

Instance Method Details

#arg_required?(opt) ⇒ Boolean

Returns:

  • (Boolean)


123
124
125
126
127
128
# File 'lib/rex/parser/arguments.rb', line 123

def arg_required?(opt)
  value = select_value_from_fmt_option(opt)
  return false if value.nil?

  value.first
end

#include?(search) ⇒ Boolean

Returns:

  • (Boolean)


119
120
121
# File 'lib/rex/parser/arguments.rb', line 119

def include?(search)
  fmt.keys.flatten.include?(search)
end

#merge(to_merge) ⇒ Object

Return new Parser object featuring options from the base object and including the options hash that was passed in



135
136
137
138
139
# File 'lib/rex/parser/arguments.rb', line 135

def merge(to_merge)
  return fmt unless to_merge.is_a?(Hash)

  Rex::Parser::Arguments.new(fmt.clone.merge(to_merge))
end

#option_keysObject



130
131
132
# File 'lib/rex/parser/arguments.rb', line 130

def option_keys
  fmt.keys.flatten
end

#parse(args, &_block) ⇒ Object

Parses the supplied arguments into a set of options.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rex/parser/arguments.rb', line 50

def parse(args, &_block)
  skip_next = 0

  args.each_with_index do |arg, idx|
    if skip_next > 0
      skip_next -= 1
      next
    end

    param = nil
    if arg =~ SHORT_FLAG
      # parsing needs to take into account a couple requirements
      #  1. longest `short` flag found in 'arg' should be extracted first
      #    * consider passing the short flag to a tokenizer that returns a list of tokens in order with any invalid tokens
      #  2. any short flag arguments that need an option will consume the next option from the list
      short_args_from_token(arg).each do |letter|
        next unless include?("-#{letter}")

        if arg_required?("-#{letter}")
          skip_next += 1
          param = args[idx + skip_next]
        end

        yield "-#{letter}", idx, param
      end
    elsif arg =~ LONG_FLAG && include?(arg)
      if arg_required?(arg)
        skip_next = 1
        param = args[idx + skip_next]
      end

      # Try to yield the short hand version of our argument if possible
      # This will result in less areas of code that would need to be changed
      to_return = short_arg_from_long_arg(arg)
      if to_return.nil?
        yield arg, idx, param
      else
        yield to_return, idx, param
      end
    else
      # else treat the passed in flag as argument
      yield nil, idx, arg
    end
  end
end

#usageObject

Returns usage information for this parsing context.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/rex/parser/arguments.rb', line 99

def usage
  txt = ["\nOPTIONS:\n"]

  fmt.sort_by { |key, | key.to_s.downcase }.each do |key, val|
    # if the arg takes in a parameter, get parameter string
    opt = val[0] ? " #{val[2]}" : ''

    # Get all arguments for a command
    output = key.join(', ')
    output += opt

    # Left align the fmt options and <opt> string
    aligned_option = "    #{output.ljust(longest.length)}"
    txt << "#{aligned_option}  #{val[1]}"
  end

  txt << ""
  txt.join("\n")
end