diff --git a/lib/ronin/exploits/cli/commands/show.rb b/lib/ronin/exploits/cli/commands/show.rb index 0377b0ab..48999da4 100644 --- a/lib/ronin/exploits/cli/commands/show.rb +++ b/lib/ronin/exploits/cli/commands/show.rb @@ -110,6 +110,7 @@ def print_exploit(exploit) end print_params(exploit) + print_exploit_usage(exploit) end # @@ -286,6 +287,48 @@ def print_target(target) puts end + # + # Prints an example `ronin-exploits run` command for the exploit. + # + # @param [Class] exploit + # + # @since 0.2.0 + # + def print_exploit_usage(exploit) + puts "Usage:" + puts + puts " $ #{example_run_command(exploit)}" + puts + end + + # + # Builds an example `ronin-exploits run` command for the exploit. + # + # @param [Class] exploit + # + # @return [String] + # The example `ronin-exploits run` command. + # + # @since 0.2.0 + # + def example_run_command(exploit) + command = ['ronin-exploits', 'run'] + + if options[:file] + command << '-f' << options[:file] + else + command << exploit.id + end + + exploit.params.each_value do |param| + if param.required? && !param.default + command << '-p' << "#{param.name}=#{param_usage(param)}" + end + end + + return command.join(' ') + end + end end end diff --git a/spec/cli/commands/show_spec.rb b/spec/cli/commands/show_spec.rb index 856e5d5d..1645d193 100644 --- a/spec/cli/commands/show_spec.rb +++ b/spec/cli/commands/show_spec.rb @@ -2,6 +2,167 @@ require 'ronin/exploits/cli/commands/show' require_relative 'man_page_example' +require 'ronin/exploits/exploit' + describe Ronin::Exploits::CLI::Commands::Show do include_examples "man_page" + + module TestShowCommand + class ExampleExploit < Ronin::Exploits::Exploit + + id 'exaple_exploit' + + param :foo, String, required: true, desc: 'Foo param' + param :bar, Integer, required: true, desc: 'Bar param' + param :baz, Integer, desc: 'Baz param' + + end + end + + let(:exploit_class) { TestShowCommand::ExampleExploit } + + describe "#print_exploit_usage" do + it "must print 'Usage:' followed by an example 'ronin-exploits build' command" do + expect { + subject.print_exploit_usage(exploit_class) + }.to output( + [ + "Usage:", + "", + " $ ronin-exploits run #{exploit_class.id} -p foo=FOO -p bar=NUM", + "", + "" + ].join($/) + ).to_stdout + end + end + + describe "#example_run_command" do + context "when given a exploit class with no params" do + module TestShowCommand + class ExploitWithNoParams < Ronin::Exploits::Exploit + + id 'exploit_with_no_params' + + end + end + + let(:exploit_class) { TestShowCommand::ExploitWithNoParams } + + it "must return 'ronin-exploits run ...' with the exploit class ID" do + expect(subject.example_run_command(exploit_class)).to eq( + "ronin-exploits run #{exploit_class.id}" + ) + end + end + + context "but the exploit class does have params" do + context "and none of them are required" do + module TestShowCommand + class ExploitWithOptionalParams < Ronin::Exploits::Exploit + + id 'exploit_with_optional_params' + + param :foo, String, desc: 'Foo param' + param :bar, Integer, desc: 'Bar param' + + end + end + + let(:exploit_class) { TestShowCommand::ExploitWithOptionalParams } + + it "must not add any '-p' flags to the 'ronin-exploits build' command" do + expect(subject.example_run_command(exploit_class)).to eq( + "ronin-exploits run #{exploit_class.id}" + ) + end + end + + context "and they all have default values" do + module TestShowCommand + class ExploitWithDefaultParams < Ronin::Exploits::Exploit + + id 'exploit_with_default_params' + + param :foo, String, default: 'foo', + desc: 'Foo param' + + param :bar, Integer, default: 42, + desc: 'Bar param' + + end + end + + let(:exploit_class) { TestShowCommand::ExploitWithDefaultParams } + + it "must not add any '-p' flags to the 'ronin-exploits build' command" do + expect(subject.example_run_command(exploit_class)).to eq( + "ronin-exploits run #{exploit_class.id}" + ) + end + end + + context "and some are required" do + context "but they also have default values" do + module TestShowCommand + class ExploitWithRequiredAndDefaultParams < Ronin::Exploits::Exploit + + id 'exploit_with_required_and_default_params' + + param :foo, String, required: true, + default: 'foo', + desc: 'Foo param' + + param :bar, Integer, required: true, + default: 42, + desc: 'Bar param' + + end + end + + let(:exploit_class) { TestShowCommand::ExploitWithRequiredAndDefaultParams } + + it "must not add any '-p' flags to the 'ronin-exploits build' command" do + expect(subject.example_run_command(exploit_class)).to eq( + "ronin-exploits run #{exploit_class.id}" + ) + end + end + + context "but some are required and have no default values" do + module TestShowCommand + class ExploitWithRequiredParams < Ronin::Exploits::Exploit + + id 'exploit_with_required_params' + + param :foo, String, required: true, desc: 'Foo param' + param :bar, Integer, required: true, desc: 'Bar param' + param :baz, Integer, desc: 'Baz param' + + end + end + + let(:exploit_class) { TestShowCommand::ExploitWithRequiredParams } + + it "must add '-p' flags followed by the param name and usage to the 'ronin-exploits build' command" do + expect(subject.example_run_command(exploit_class)).to eq( + "ronin-exploits run #{exploit_class.id} -p foo=FOO -p bar=NUM" + ) + end + end + end + end + + context "when the exploit is loaded via the '--file' option" do + let(:exploit_file) { 'path/to/exploit.rb' } + + before { subject.options[:file] = exploit_file } + + it "must return a 'ronin-exploits run --file ...' command with the exploit file" do + expect(subject.example_run_command(exploit_class)).to eq( + "ronin-exploits run -f #{exploit_file} -p foo=FOO -p bar=NUM" + ) + end + end + end end