From af569f33d44b7871a0abac8d1a15ca17d622b64f Mon Sep 17 00:00:00 2001 From: Postmodern Date: Wed, 5 Jun 2024 13:41:48 -0700 Subject: [PATCH] Added specs for `CLI::Printing` (issue #38). --- spec/cli/printing_spec.rb | 218 ++++++++++++++++++++++++++++++++++ spec/fixtures/values/cert.crt | 41 +++++++ 2 files changed, 259 insertions(+) create mode 100644 spec/cli/printing_spec.rb create mode 100644 spec/fixtures/values/cert.crt diff --git a/spec/cli/printing_spec.rb b/spec/cli/printing_spec.rb new file mode 100644 index 0000000..b69aa2d --- /dev/null +++ b/spec/cli/printing_spec.rb @@ -0,0 +1,218 @@ +require 'spec_helper' +require 'ronin/recon/cli/printing' +require 'ronin/recon/cli/command' + +describe Ronin::Recon::CLI::Printing do + module TestPrinting + class TestCommand < Ronin::Recon::CLI::Command + include Ronin::Recon::CLI::Printing + end + end + + let(:command_class) { TestPrinting::TestCommand } + subject { command_class.new } + + let(:fixtures_dir) { File.join(__dir__,'..','fixtures') } + + describe "#format_value" do + context "when given a Ronin::Recon::Values::Domain value" do + let(:value) do + Ronin::Recon::Values::Domain.new('example.com') + end + + it "must return 'domain \#{value}'" do + expect(subject.format_value(value)).to eq("domain #{value}") + end + end + + context "when given a Ronin::Recon::Values::Mailserver value" do + let(:value) do + Ronin::Recon::Values::Mailserver.new('smtp.example.com') + end + + it "must return 'mailserver \#{value}'" do + expect(subject.format_value(value)).to eq("mailserver #{value}") + end + end + + context "when given a Ronin::Recon::Values::Nameserver value" do + let(:value) do + Ronin::Recon::Values::Nameserver.new('1.1.1.1') + end + + it "must return 'nameserver \#{value}'" do + expect(subject.format_value(value)).to eq("nameserver #{value}") + end + end + + context "when given a Ronin::Recon::Values::Host value" do + let(:value) do + Ronin::Recon::Values::Host.new('www.example.com') + end + + it "must return 'host \#{value}'" do + expect(subject.format_value(value)).to eq("host #{value}") + end + end + + context "when given a Ronin::Recon::Values::IP value" do + let(:value) do + Ronin::Recon::Values::IP.new('192.168.1.1') + end + + it "must return 'IP address \#{value}'" do + expect(subject.format_value(value)).to eq("IP address #{value}") + end + end + + context "when given a Ronin::Recon::Values::IPRange value" do + let(:value) do + Ronin::Recon::Values::IPRange.new('192.168.1.1/24') + end + + it "must return 'IP range \#{value}'" do + expect(subject.format_value(value)).to eq("IP range #{value}") + end + end + + context "when given a Ronin::Recon::Values::OpenPort value" do + let(:value) do + Ronin::Recon::Values::OpenPort.new( + address, number, host: host, + protocol: protocol, + service: service, + ssl: ssl + ) + end + + context "and when the Ronin::Recon::Values::OpenPort's #protocol is :tcp" do + let(:address) { '192.168.1.1' } + let(:number) { 443 } + let(:host) { 'www.example.com' } + let(:protocol) { :tcp } + let(:service) { 'https' } + let(:ssl) { true } + + it "must return 'open TCP port \#{value}'" do + expect(subject.format_value(value)).to eq("open TCP port #{value}") + end + end + + context "and when the Ronin::Recon::Values::OpenPort's #protocol is :udp" do + let(:address) { '192.168.1.1' } + let(:number) { 53 } + let(:host) { 'www.example.com' } + let(:protocol) { :udp } + let(:service) { 'dns' } + let(:ssl) { false } + + it "must return 'open UDP port \#{value}'" do + expect(subject.format_value(value)).to eq("open UDP port #{value}") + end + end + end + + context "when given a Ronin::Recon::Values::Cert value" do + let(:cert_path) { File.join(fixtures_dir,'values','cert.crt') } + let(:cert) { Ronin::Support::Crypto::Cert.load_file(cert_path) } + let(:value) { Ronin::Recon::Values::Cert.new(cert) } + + it "must return 'SSL/TLS certificate \#{value.subject}'" do + expect(subject.format_value(value)).to eq("SSL/TLS certificate #{value.subject}") + end + end + + context "when given a Ronin::Recon::Values::URL value" do + let(:value) do + Ronin::Recon::Values::URL.new('https://example.com/page.html') + end + + it "must return 'URL \#{value}'" do + expect(subject.format_value(value)).to eq("URL #{value}") + end + end + + context "when given a Ronin::Recon::Values::Website value" do + let(:value) do + Ronin::Recon::Values::Website.new(:https,'example.com',443) + end + + it "must return 'website \#{value}'" do + expect(subject.format_value(value)).to eq("website #{value}") + end + end + + context "when given a Ronin::Recon::Values::Wildcard value" do + let(:value) do + Ronin::Recon::Values::Wildcard.new('*.example.com') + end + + it "must return 'wildcard host name \#{value}'" do + expect(subject.format_value(value)).to eq("wildcard host name #{value}") + end + end + + context "when given another kind of Ronin::Recon::Value object" do + module TestPrinting + class OtherValue < Ronin::Recon::Value + end + end + + let(:value) { TestPrinting::OtherValue.new } + + it do + expect { + subject.format_value(value) + }.to raise_error(NotImplementedError,"value class #{value.class} not supported") + end + end + + context "when given another kind of Object" do + let(:value) { Object.new } + + it do + expect { + subject.format_value(value) + }.to raise_error(NotImplementedError,"value class #{value.class} not supported") + end + end + end + + describe "#print_value" do + let(:stdout) { StringIO.new } + + subject { command_class.new(stdout: stdout) } + + let(:value) { Ronin::Recon::Values::Host.new('www.example.com') } + + context "when STDOUT is a TTY" do + before { expect(stdout).to receive(:tty?).and_return(true) } + + it "must log 'Found new \#{format_value(value)}'" do + expect(subject).to receive(:log_info).with("Found new #{subject.format_value(value)}") + + subject.print_value(value) + end + + context "when given a parent value" do + let(:parent) { Ronin::Recon::Values::Domain.new('example.com') } + + it "must log 'Found new \#{format_value(value)} for \#{format_value(parent)}'" do + expect(subject).to receive(:log_info).with("Found new #{subject.format_value(value)} for #{subject.format_value(parent)}") + + subject.print_value(value,parent) + end + end + end + + context "when STDOUT is not a TTY" do + before { allow(stdout).to receive(:tty?).and_return(false) } + + it "must print the value to STDOUT" do + expect(subject).to receive(:puts).with(value) + + subject.print_value(value) + end + end + end +end diff --git a/spec/fixtures/values/cert.crt b/spec/fixtures/values/cert.crt new file mode 100644 index 0000000..3fe854b --- /dev/null +++ b/spec/fixtures/values/cert.crt @@ -0,0 +1,41 @@ +-----BEGIN CERTIFICATE----- +MIIHRzCCBi+gAwIBAgIQD6pjEJMHvD1BSJJkDM1NmjANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSkwJwYDVQQDEyBE +aWdpQ2VydCBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTAeFw0yMjAzMTQwMDAwMDBa +Fw0yMzAzMTQyMzU5NTlaMIGWMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv +cm5pYTEUMBIGA1UEBxMLTG9zIEFuZ2VsZXMxQjBABgNVBAoMOUludGVybmV0wqBD +b3Jwb3JhdGlvbsKgZm9ywqBBc3NpZ25lZMKgTmFtZXPCoGFuZMKgTnVtYmVyczEY +MBYGA1UEAxMPd3d3LmV4YW1wbGUub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAlV2WY5rlGn1fpwvuBhj0nVBcNxCxkHUG/pJG4HvaJen7YIZ1mLc7 +/P4snOJZiEfwWFTikHNbcUCcYiKG8JkFebZOYMc1U9PiEtVWGU4kuYuxiXpD8oMP +in1B0SgrF7gKfO1//I2weJdAUjgZuXBCPAlhz2EnHddzXUtwm9XuOLO/Y6LATVMs +bp8/lXnfo/bX0UgJ7C0aVqOu07A0Vr6OkPxwWmOvF3cRKhVCM7U4B51KK+IsWRLm +8cVW1IaXjwhGzW7BR6EI3sxCQ4Wnc6HVPSgmomLWWWkIGFPAwcWUB4NC12yhCO5i +W/dxNMWNLMRVtnZAyq6FpZ8wFK6j4OMwMwIDAQABo4ID1TCCA9EwHwYDVR0jBBgw +FoAUt2ui6qiqhIx56rTaD5iyxZV2ufQwHQYDVR0OBBYEFPcqCdAkWxFx7rq+9D4c +PVYSiBa7MIGBBgNVHREEejB4gg93d3cuZXhhbXBsZS5vcmeCC2V4YW1wbGUubmV0 +ggtleGFtcGxlLmVkdYILZXhhbXBsZS5jb22CC2V4YW1wbGUub3Jngg93d3cuZXhh +bXBsZS5jb22CD3d3dy5leGFtcGxlLmVkdYIPd3d3LmV4YW1wbGUubmV0MA4GA1Ud +DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwgY8GA1Ud +HwSBhzCBhDBAoD6gPIY6aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 +VExTUlNBU0hBMjU2MjAyMENBMS00LmNybDBAoD6gPIY6aHR0cDovL2NybDQuZGln +aWNlcnQuY29tL0RpZ2lDZXJ0VExTUlNBU0hBMjU2MjAyMENBMS00LmNybDA+BgNV +HSAENzA1MDMGBmeBDAECAjApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2lj +ZXJ0LmNvbS9DUFMwfwYIKwYBBQUHAQEEczBxMCQGCCsGAQUFBzABhhhodHRwOi8v +b2NzcC5kaWdpY2VydC5jb20wSQYIKwYBBQUHMAKGPWh0dHA6Ly9jYWNlcnRzLmRp +Z2ljZXJ0LmNvbS9EaWdpQ2VydFRMU1JTQVNIQTI1NjIwMjBDQTEtMS5jcnQwCQYD +VR0TBAIwADCCAXwGCisGAQQB1nkCBAIEggFsBIIBaAFmAHUA6D7Q2j71BjUy51co +vIlryQPTy9ERa+zraeF3fW0GvW4AAAF/ip6hdQAABAMARjBEAiAxePNT60Z/vTJT +PVryiGzXrLxCNJQqteULkguBEMbG/gIgR3QwvILJIWAUfvSfJQ/zMmqr2JDanWE8 +uzbC4EWbcwAAdQA1zxkbv7FsV78PrUxtQsu7ticgJlHqP+Eq76gDwzvWTAAAAX+K +nqF8AAAEAwBGMEQCIDspTxwkUBpEoeA+IolNYwOKl9Yxmwk816yd0O2IJPZcAiAV +8TWhoOLiiqGKnY02CdcGXOzAzC7tT6m7OtLAku2+WAB2ALNzdwfhhFD4Y4bWBanc +EQlKeS2xZwwLh9zwAw55NqWaAAABf4qeoYcAAAQDAEcwRQIgKR7qwPLQb6UT2+S7 +w7uQsbsDZfZVX/g8FkBtAltaTpACIQDLdtedRNGNhuzYpB6gmBBydhtSQi5YZLsp +FvaVHpeW1zANBgkqhkiG9w0BAQsFAAOCAQEAqp++XZEbreROTsyPB2RENbStOxM/ +wSnYtKvzQlFJRjvWzx5Bg+ELVy+DaXllB29ZA4xRlIkYED4eXO26PY5PGhSS0yv/ +1JjLp5MOvLcbk6RCQkbZ5bEaa2gqmy5IqS8dKrDj+CCUVIFQLu7X4CB6ey5n+/rY +F6Rb3MoAYu8jr3pY8Hp0DL1NQ/GMAofc464J0vf6NzzSS6sE5UOl0lURDkGHXzio +5XpeTEa4tvo/w0vNQDX/4KRxdArBIIvjVEeE1Ri9UZtAXd1CMBLROqVjmq+QCNYb +0XELBnGQ666tr7pfx9trHniitNEGI6dj87VD+laMUBd7HBtOEGsiDoRSlA== +-----END CERTIFICATE-----