Command Mapper maps an external command's options and arguments to Class attributes to allow safely and securely executing commands.
- Supports defining commands as Ruby classes.
- Supports mapping in options and additional arguments.
- Supports common option types:
- Str: string values
- Num: numeric values
- Dec: decimal values
- Hex: hexadecimal values
- Map: maps Ruby values to other String values.
Map::YesNo: mapstrue/falsetoyes/no.Map::EnabledDisabled: Mapstrue/falsetoenabled/disabled.
- Enum: maps a finite set of Symbols to a
finite set of Strings (aka
--opt={foo|bar|baz}values). - List: comma-separated list
(aka
--opt VALUE,...). - KeyValue: maps a Hash or Array to
key:value Strings (aka
--opt KEY:VALUEor--opt KEY=VALUEvalues). - KeyValueList: a key-value list
(aka
--opt KEY:VALUE,...or--opt KEY=VALUE;...values). - InputPath: a path to a pre-existing file or directory
- InputFile: a path to a pre-existing file
- InputDir: a path to a pre-existing directory
- Supports common option types:
- Supports mapping in sub-commands.
- Allows running the command via
IO.popento read the command's output. - Allows running commands with additional environment variables.
- Allows overriding the command name or path to the command.
- Allows running commands via
sudo. - Prevents command injection and option injection.
require'command_mapper/command'## Represents the `grep` command#classGrep < CommandMapper::Commandcommand"grep"dooption"--extended-regexp"option"--fixed-strings"option"--basic-regexp"option"--perl-regexp"option"--regexp",equals: true,value: trueoption"--file",name: :patterns_file,equals: true,value: trueoption"--ignore-case"option"--no-ignore-case"option"--word-regexp"option"--line-regexp"option"--null-data"option"--no-messages"option"--invert-match"option"--version"option"--help"option"--max-count",equals: true,value: {type: Num.new}option"--byte-offset"option"--line-number"option"--line-buffered"option"--with-filename"option"--no-filename"option"--label",equals: true,value: trueoption"--only-matching"option"--quiet"option"--binary-files",equals: true,value: trueoption"--text"option"-I",name: # FIXME: nameoption"--directories",equals: true,value: trueoption"--devices",equals: true,value: trueoption"--recursive"option"--dereference-recursive"option"--include",equals: true,value: trueoption"--exclude",equals: true,value: trueoption"--exclude-from",equals: true,value: trueoption"--exclude-dir",equals: true,value: trueoption"--files-without-match",value: trueoption"--files-with-matches"option"--count"option"--initial-tab"option"--null"option"--before-context",equals: true,value: {type: Num.new}option"--after-context",equals: true,value: {type: Num.new}option"--context",equals: true,value: {type: Num.new}option"--group-separator",equals: true,value: trueoption"--no-group-separator"option"--color",equals: :optional,value: {required: false}option"--colour",equals: :optional,value: {required: false}option"--binary"argument:patternsargument:file,required: false,repeats: trueendendoption"--opt"Define a short option:
option"-o",name: :optDefines an option with a required value:
option"--output",value: {required: true}Defines an option that uses an equals sign (ex: --output=value):
option"--output",equals: true,value: {required: true}Defines an option where the value is embedded into the flag (ex: -Ivalue):
option"-I",value: {required: true},value_in_flag: trueDefines an option that can be specified multiple times:
option"--include-dir",repeats: trueDefines an option that accepts a numeric value:
option"--count",value: {type: Num.new}Define an option that only accepts a range of acceptable values:
option"--count",value: {type: Num.new(range: 1..100)}Defines an option that accepts a comma-separated list:
option"--list",value: {type: List.new}Defines an option that accepts a key=value pair:
option"--param",value: {type: KeyValue.new}Defines an option that accepts a key:value pair:
option"--param",value: {type: KeyValue.new(separator: ':')}Defines an option that accepts a finite number of values:
option"--type",value: {type: Enum[:foo,:bar,:baz]}Custom methods:
deffoo@foo || @barenddeffoo=(value)@foo=casevaluewhenHashthen ...
whenArraythen ...
elsevalue.to_sendendargument:hostDefine an optional argument:
argument:optional_output,required: falseDefine an argument that can be repeated:
argument:files,repeats: trueDefine an argument that accepts an existing file:
argument:file,type: InputFile.newDefine an argument that accepts an existing directory:
argument:dir,type: InputDir.newCustom methods:
deffoo@foo || @barenddeffoo=(value)@foo=casevaluewhenHashthen ...
whenArraythen ...
elsevalue.to_sendendclassPortRange < CommandMapper::Types::Typedefvalidate(value)casevaluewhenIntegertruewhenRangeifvalue.begin.kind_of?(Integer)trueelse[false,"port range can only contain Integers"]endelse[false,"port range must be an Integer or a Range of Integers"]endenddefformat(value)casevaluewhenInteger"#{value}"whenRange"#{value.begin}-#{value.end}"endendendoption:ports,value: {required: true,type: PortRange.new}Keyword arguments:
Grep.run(ignore_case: true,patterns: "foo",file: "file.txt")# ...With a block:
Grep.rundo |grep|
grep.ignore_case=truegrep.patterns="foo"grep.file="file.txt"endOverriding the command name:
Grep.run(...,command_name: 'grep2')Specifying the direct path to the command:
Grep.run(...,command_path: '/path/to/grep')Grep.capture(ignore_case: true,patterns: "foo",file: "file.txt")# => "..."io=Grep.popen(ignore_case: true,patterns: "foo",file: "file.txt")io.each_linedo |line|
# ...endGrep.sudo(patterns: "Error",file: "/var/log/syslog")# Password: # ...moduleGitclassCommand < CommandMapper::Commandcommand'git'dooption"--version"option"--help"option"-C",name: :dir,value: {type: InputDir.new}# ...subcommand:clonedooption"--bare"option"--mirror"option"--depth",value: {type: Num.new}# ...argument:repositoryargument:directory,required: falseend# ...endendendGit::Command.run(clone: {repository: 'https://github.com/user/repo.git'})command_mapper-gen can automatically generate command classes from a command's
--help output and/or man page.
$ gem install command_mapper-gen
$ command_mapper-gen cat
require 'command_mapper/command'
#
# Represents the `cat` command
#
class Cat < CommandMapper::Command
command "cat" do
option "--show-all"
option "--number-nonblank"
option "-e", name: # FIXME: name
option "--show-ends"
option "--number"
option "--squeeze-blank"
option "-t", name: # FIXME: name
option "--show-tabs"
option "-u", name: # FIXME: name
option "--show-nonprinting"
option "--help"
option "--version"
argument :file, required: false, repeats: true
end
end
- ruby-nmap
- ruby-masscan
- ruby-amass
- ruby-yasm
- ruby-ncrack
- ruby-nikto
- ruby-gobuster
- ruby-feroxbuster
- ruby-rustscan
- ruby >= 2.0.0
$ gem install command_mappergem'command_mapper','~> 0.2'gemspec.add_dependency'command_mapper','~> 0.2'Copyright (c) 2021-2022 Hal Brodigan
See {file:LICENSE.txt} for license information.