Testing WordPress Component Enumeration Controller in WPScan
This test suite validates the WPScan enumeration controller functionality, focusing on command-line argument parsing and WordPress component enumeration capabilities. The tests ensure proper handling of plugin, theme, user, and configuration detection modes.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
wpscanteam/wpscan
spec/app/controllers/enumeration_spec.rb
# frozen_string_literal: true
describe WPScan::Controller::Enumeration do
subject(:controller) { described_class.new }
let(:target_url) { 'http://wp.lab/' }
let(:cli_args) { "--url #{target_url}" }
before do
## For the --passwords options
allow_any_instance_of(OptParseValidator::OptPath).to receive(:check_file)
WPScan::ParsedCli.options = rspec_parsed_options(cli_args)
end
describe '#enum_message' do
after { expect(controller.enum_message(type, detection_mode)).to eql @expected }
context 'when type argument is incorrect' do
let(:type) { 'spec' }
let(:detection_mode) { :mixed }
it 'returns nil' do
@expected = nil
end
end
%w[plugins themes].each do |t|
context "type = #{t}" do
let(:type) { t }
let(:detection_mode) { :mixed }
context 'when vulnerable' do
let(:cli_args) { "#{super()} -e v#{type[0]}" }
it 'returns the expected string' do
@expected = "Enumerating Vulnerable #{type.capitalize} (via Passive and Aggressive Methods)"
end
end
context 'when all' do
let(:cli_args) { "#{super()} -e a#{type[0]}" }
let(:detection_mode) { :passive }
it 'returns the expected string' do
@expected = "Enumerating All #{type.capitalize} (via Passive Methods)"
end
end
context 'when most popular' do
let(:cli_args) { "#{super()} -e #{type[0]}" }
let(:detection_mode) { :aggressive }
it 'returns the expected string' do
@expected = "Enumerating Most Popular #{type.capitalize} (via Aggressive Methods)"
end
end
end
end
end
describe '#default_opts' do
context 'when no --enumerate' do
it 'contains the correct version_detection' do
expect(controller.default_opts('plugins')[:version_detection]).to include(mode: :mixed)
end
end
end
describe '#cli_options' do
it 'contains the correct options' do
expect(controller.cli_options.map(&:to_sym)).to eql(
%i[enumerate exclude_content_based
plugins_list plugins_detection plugins_version_all plugins_version_detection plugins_threshold
themes_list themes_detection themes_version_all themes_version_detection themes_threshold
timthumbs_list timthumbs_detection
config_backups_list config_backups_detection
db_exports_list db_exports_detection
medias_detection
users_list users_detection exclude_usernames]
)
end
end
describe '#enum_users' do
before { expect(controller.formatter).to receive(:output).twice }
after { controller.enum_users }
context 'when --enumerate has been supplied' do
let(:cli_args) { "#{super()} -e u1-10" }
it 'calls the target.users with the correct range' do
expect(controller.target).to receive(:users).with(hash_including(range: (1..10)))
end
end
context 'when --passwords supplied but no --username or --usernames' do
let(:cli_args) { "#{super()} --passwords some-file.txt" }
it 'calls the target.users with the default range' do
expect(controller.target).to receive(:users).with(hash_including(range: (1..10)))
end
end
end
describe '#run' do
context 'when no :enumerate' do
before do
expect(controller).to receive(:enum_plugins)
expect(controller).to receive(:enum_config_backups)
expect(WPScan::ParsedCli.plugins_detection).to eql :passive
end
it 'calls enum_plugins and enum_config_backups' do
controller.run
end
context 'when --passwords supplied but no --username or --usernames' do
let(:cli_args) { "#{super()} --passwords some-file.txt" }
it 'calls the enum_users' do
expect(controller).to receive(:enum_users)
controller.run
end
end
end
context 'when :enumerate' do
after { controller.run }
context 'when no option supplied' do
let(:cli_args) { "#{super()} -e" }
it 'calls the correct enum methods' do
%i[plugins themes timthumbs config_backups db_exports users medias].each do |option|
expect(controller).to receive("enum_#{option}".to_sym)
end
end
end
%i[p ap vp].each do |option|
context "when #{option}" do
let(:cli_args) { "#{super()} -e #{option}" }
it 'calls the #enum_plugins' do
expect(controller).to receive(:enum_plugins)
end
end
end
%i[t at vt].each do |option|
context option.to_s do
let(:cli_args) { "#{super()} -e #{option}" }
it 'calls the #enum_themes' do
expect(controller).to receive(:enum_themes)
end
end
end
{ timthumbs: 'tt', config_backups: 'cb', db_exports: 'dbe', medias: 'm', users: 'u' }.each do |option, shortname|
context "when #{option}" do
let(:cli_args) { "#{super()} -e #{shortname}" }
it "calls the ##{option}" do
expect(controller).to receive("enum_#{option}".to_sym)
end
end
end
end
end
end