Back to Repositories

Testing Duplicator Installer Log Detection in WPScan

This test suite validates the DuplicatorInstallerLog finder functionality in WPScan, focusing on detecting and analyzing installer log files from the Duplicator plugin. The tests cover various log file formats and versions while ensuring proper detection and handling of different response scenarios.

Test Coverage Overview

The test suite provides comprehensive coverage of the DuplicatorInstallerLog finder functionality, examining both positive and negative test cases.

  • Tests various log file formats including PRO and LITE versions
  • Validates response handling for 200 and 404 status codes
  • Verifies content matching logic for different file versions
  • Tests subdirectory detection and request parameter handling

Implementation Analysis

The implementation follows RSpec best practices with a well-structured context-based approach. The tests utilize stub_request for HTTP interaction mocking and leverage shared examples for common scenarios.

  • Uses before blocks for common setup operations
  • Implements context-specific test cases for different file versions
  • Employs RSpec subject and let declarations for clean test organization

Technical Details

  • RSpec for test framework implementation
  • WebMock for HTTP request stubbing
  • Fixture files for different log formats
  • Custom matchers for response validation
  • Apache server context simulation

Best Practices Demonstrated

The test suite exemplifies several testing best practices and patterns for security tool development.

  • Separation of concerns between different test contexts
  • Proper use of fixtures for test data
  • Comprehensive error case handling
  • Clear test organization and naming conventions
  • Efficient use of shared setup and teardown

wpscanteam/wpscan

spec/app/finders/interesting_findings/duplicator_installer_log_spec.rb

            
# frozen_string_literal: true

describe WPScan::Finders::InterestingFindings::DuplicatorInstallerLog do
  subject(:finder) { described_class.new(target) }
  let(:target)     { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
  let(:url)        { 'http://ex.lo/' }
  let(:fixtures)   { FINDERS_FIXTURES.join('interesting_findings', 'duplicator_installer_log') }
  let(:filename)   { 'installer-log.txt' }
  let(:log_url)    { target.url(filename) }

  describe '#aggressive' do
    before do
      expect(target).to receive(:sub_dir).at_least(1).and_return(false)
      expect(target).to receive(:head_or_get_params).and_return(method: :head)
    end

    context 'when not a 200' do
      it 'return nil' do
        stub_request(:head, log_url).to_return(status: 404)

        expect(finder.aggressive).to eql nil
      end
    end

    context 'when a 200' do
      before do
        stub_request(:head, log_url)
        stub_request(:get, log_url).to_return(body: body)
      end

      context 'when the body does not match' do
        let(:body) { '' }

        its(:aggressive) { should be_nil }
      end

      context 'when the body matches' do
        after do
          expect(finder.aggressive).to eql WPScan::Model::DuplicatorInstallerLog.new(
            log_url,
            confidence: 100,
            found_by: described_class::DIRECT_ACCESS
          )
        end

        context 'when old versions of the file' do
          let(:body) { File.read(fixtures.join('old.txt')) }

          it 'returns the InterestingFinding' do
            # handled in after loop above
          end
        end

        context 'when newest versions of the file' do
          context 'when PRO format 1' do
            let(:body) { File.read(fixtures.join('pro.txt')) }

            it 'returns the InterestingFinding' do
              # handled in after loop above
            end
          end

          context 'when PRO format 2' do
            let(:body) { File.read(fixtures.join('pro2.txt')) }

            it 'returns the InterestingFinding' do
              # handled in after loop above
            end
          end

          context 'when LITE' do
            let(:body) { File.read(fixtures.join('lite.txt')) }

            it 'returns the InterestingFinding' do
              # handled in after loop above
            end
          end
        end
      end
    end
  end
end