HELLO v3!!!

This commit is contained in:
Ryan Dewhurst
2018-09-26 21:12:01 +02:00
parent 28b9c15256
commit d268a86795
1871 changed files with 988118 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
require 'spec_helper'
describe WPScan::Controller::Aliases do
subject(:controller) { described_class.new }
let(:target_url) { 'http://ex.lo/' }
let(:parsed_options) { rspec_parsed_options(cli_args) }
let(:cli_args) { "--url #{target_url}" }
before do
WPScan::Browser.reset
described_class.parsed_options = parsed_options
end
describe '#cli_options' do
its(:cli_options) { should_not be_empty }
its(:cli_options) { should be_a Array }
it 'contains to correct options' do
expect(controller.cli_options.map(&:to_sym)).to eq %i[stealthy]
end
end
describe 'parsed_options' do
context 'when no --stealthy supplied' do
its(:parsed_options) { should eql parsed_options }
end
context 'when --stealthy supplied' do
let(:cli_args) { "#{super()} --stealthy" }
it 'contains the correct options' do
expect(controller.parsed_options).to include(
random_user_agent: true, detection_mode: :passive, plugins_version_detection: :passive
)
end
end
end
end

View File

@@ -0,0 +1,271 @@
require 'spec_helper'
describe WPScan::Controller::Core do
subject(:core) { described_class.new }
let(:target_url) { 'http://ex.lo/' }
let(:parsed_options) { rspec_parsed_options(cli_args) }
let(:cli_args) { "--url #{target_url}" }
before do
WPScan::Browser.reset
described_class.reset
described_class.parsed_options = parsed_options
end
describe '#cli_options' do
its(:cli_options) { should_not be_empty }
its(:cli_options) { should be_a Array }
it 'contains to correct options' do
cli_options = core.cli_options
expect(cli_options.map(&:to_sym)).to include(:url, :server, :force, :update)
# Ensures the :url is the first one and is correctly setup
expect(cli_options.first.to_sym).to eql :url
expect(cli_options.first.required_unless).to match_array %i[update help version]
end
end
describe '#load_server_module' do
after do
expect(core.target).to receive(:server).and_return(@stubbed_server)
expect(core.load_server_module).to eql @expected
[core.target, WPScan::WpItem.new(target_url, core.target)].each do |instance|
expect(instance).to respond_to(:directory_listing?)
expect(instance).to respond_to(:directory_listing_entries)
# The below doesn't work, the module would have to be removed from the class
# TODO: find a way to test this
# expect(instance.server).to eql @expected if instance.is_a? WPScan::WpItem
end
end
context 'when no --server supplied' do
%i[Apache IIS Nginx].each do |server|
it "loads the #{server} module and returns :#{server}" do
@stubbed_server = server
@expected = server
end
end
end
context 'when --server' do
%i[apache iis nginx].each do |server|
context "when #{server}" do
let(:cli_args) { "#{super()} --server #{server}" }
it "loads the #{server.capitalize} module and returns :#{server}" do
@stubbed_server = [:Apache, nil, :IIS, :Nginx].sample
@expected = server == :iis ? :IIS : server.to_s.camelize.to_sym
end
end
end
end
end
describe '#update_db_required?' do
context 'when missing files' do
before { expect(core.local_db).to receive(:missing_files?).ordered.and_return(true) }
context 'when --no-update' do
let(:cli_args) { "#{super()} --no-update" }
it 'raises an error' do
expect { core.update_db_required? }. to raise_error(WPScan::MissingDatabaseFile)
end
end
context 'otherwise' do
its(:update_db_required?) { should eql true }
end
end
context 'when not missing files' do
before { expect(core.local_db).to receive(:missing_files?).ordered.and_return(false) }
context 'when --update' do
let(:cli_args) { "#{super()} --update" }
its(:update_db_required?) { should eql true }
end
context 'when --no-update' do
let(:cli_args) { "#{super()} --no-update" }
its(:update_db_required?) { should eql false }
end
context 'when user_interation (i.e cli output)' do
let(:cli_args) { "#{super()} --format cli" }
context 'when the db is up-to-date' do
before { expect(core.local_db).to receive(:outdated?).and_return(false) }
its(:update_db_required?) { should eql false }
end
context 'when the db is outdated' do
before do
expect(core.local_db).to receive(:outdated?).ordered.and_return(true)
expect(core.formatter).to receive(:output).with('@notice', hash_including(:msg), 'core').ordered
expect($stdout).to receive(:write).ordered # for the print()
end
context 'when a positive answer' do
before { expect(Readline).to receive(:readline).and_return('Yes').ordered }
its(:update_db_required?) { should eql true }
end
context 'when a negative answer' do
before { expect(Readline).to receive(:readline).and_return('no').ordered }
its(:update_db_required?) { should eql false }
end
end
end
context 'when no user_interation' do
let(:cli_args) { "#{super()} --format json" }
its(:update_db_required?) { should eql false }
end
end
end
describe '#before_scan' do
before do
stub_request(:get, target_url)
expect(core.formatter).to receive(:output).with('banner', hash_including(verbose: nil), 'core')
expect(core).to receive(:update_db_required?).and_return(false) unless parsed_options[:update]
end
context 'when --update' do
before do
expect(core.formatter).to receive(:output)
.with('db_update_started', hash_including(verbose: nil), 'core').ordered
expect_any_instance_of(WPScan::DB::Updater).to receive(:update)
expect(core.formatter).to receive(:output)
.with('db_update_finished', hash_including(verbose: nil), 'core').ordered
end
context 'when the --url is not supplied' do
let(:cli_args) { '--update' }
it 'calls the formatter when started and finished to update the db and exit' do
expect { core.before_scan }.to raise_error(SystemExit)
end
end
context 'when --url is supplied' do
let(:cli_args) { "#{super()} --update" }
before do
expect(core).to receive(:load_server_module)
expect(core.target).to receive(:wordpress?).and_return(true)
end
it 'calls the formatter when started and finished to update the db' do
expect { core.before_scan }.to_not raise_error
end
end
end
context 'when a redirect occurs' do
before do
stub_request(:any, target_url)
expect(core.target).to receive(:homepage_res)
.at_least(1)
.and_return(Typhoeus::Response.new(effective_url: redirection, body: ''))
end
context 'to the wp-admin/install.php' do
let(:redirection) { "#{target_url}wp-admin/install.php" }
it 'calls the formatter with the correct parameters and exit' do
expect(core.formatter).to receive(:output)
.with('not_fully_configured', hash_including(url: redirection), 'core').ordered
# TODO: Would be cool to be able to test the exit code
expect { core.before_scan }.to raise_error(SystemExit)
end
end
context 'to something else' do
let(:redirection) { 'http://g.com/' }
it 'raises an error' do
expect { core.before_scan }.to raise_error(CMSScanner::HTTPRedirectError)
end
end
context 'to another path with the wp-admin/install.php in the query' do
let(:redirection) { "#{target_url}index.php?a=/wp-admin/install.php" }
context 'when wordpress' do
it 'does not raise an error' do
expect(core.target).to receive(:wordpress?).and_return(true)
expect { core.before_scan }.to_not raise_error
end
end
context 'when not wordpress' do
it 'raises an error' do
expect(core.target).to receive(:wordpress?).and_return(false)
expect { core.before_scan }.to raise_error(WPScan::NotWordPressError)
end
end
end
end
context 'when hosted on wordpress.com' do
let(:target_url) { 'http://ex.wordpress.com' }
before { expect(core).to receive(:load_server_module) }
it 'raises an error' do
expect { core.before_scan }.to raise_error(WPScan::WordPressHostedError)
end
end
context 'when wordpress' do
before do
expect(core).to receive(:load_server_module)
expect(core.target).to receive(:wordpress?).and_return(true)
end
it 'does not raise any error' do
expect { core.before_scan }.to_not raise_error
end
end
context 'when not wordpress' do
before do
expect(core).to receive(:load_server_module)
expect(core.target).to receive(:wordpress?).and_return(false)
end
context 'when no --force' do
it 'raises an error' do
expect { core.before_scan }.to raise_error(WPScan::NotWordPressError)
end
end
context 'when --force' do
let(:cli_args) { "#{super()} --force" }
it 'does not raise any error' do
expect { core.before_scan }.to_not raise_error
end
end
end
end
end

View File

@@ -0,0 +1,45 @@
require 'spec_helper'
describe WPScan::Controller::CustomDirectories do
subject(:controller) { described_class.new }
let(:target_url) { 'http://ex.lo/' }
let(:parsed_options) { rspec_parsed_options(cli_args) }
let(:cli_args) { "--url #{target_url}" }
before do
WPScan::Browser.reset
described_class.parsed_options = parsed_options
end
describe '#cli_options' do
its(:cli_options) { should_not be_empty }
its(:cli_options) { should be_a Array }
it 'contains to correct options' do
expect(controller.cli_options.map(&:to_sym)).to eq %i[wp_content_dir wp_plugins_dir]
end
end
describe '#before_scan' do
context 'when the content_dir is not found and not supply' do
before { expect(controller.target).to receive(:content_dir) }
let(:exception) do
'Unable to identify the wp-content dir, please supply it with --wp-content-dir'
end
it 'raises an exception' do
expect { controller.before_scan }.to raise_error(exception)
end
end
context 'when content_dir found/supplied' do
let(:cli_args) { "#{super()} --wp-content-dir wp-content" }
it 'does not raise any error' do
expect { controller.before_scan }.to_not raise_error
expect(controller.target.content_dir).to eq parsed_options[:wp_content_dir]
end
end
end
end

View File

@@ -0,0 +1,180 @@
require 'spec_helper'
describe WPScan::Controller::Enumeration do
subject(:controller) { described_class.new }
let(:target_url) { 'http://wp.lab/' }
let(:parsed_options) { rspec_parsed_options(cli_args) }
let(:cli_args) { "--url #{target_url}" }
before do
WPScan::Browser.reset
## For the --passwords options
allow_any_instance_of(OptParseValidator::OptPath).to receive(:check_file)
described_class.parsed_options = parsed_options
end
describe '#enum_message' do
after { expect(controller.enum_message(type)).to eql @expected }
context 'when type argument is incorrect' do
let(:type) { 'spec' }
it 'returns nil' do
@expected = nil
end
end
%w[plugins themes].each do |t|
context "type = #{t}" do
let(:type) { t }
context 'when vulnerable' do
let(:cli_args) { "#{super()} -e v#{type[0]}" }
it 'returns the expected string' do
@expected = "Enumerating Vulnerable #{type.capitalize}"
end
end
context 'when all' do
let(:cli_args) { "#{super()} -e a#{type[0]}" }
it 'returns the expected string' do
@expected = "Enumerating All #{type.capitalize}"
end
end
context 'when most popular' do
let(:cli_args) { "#{super()} -e #{type[0]}" }
it 'returns the expected string' do
@expected = "Enumerating Most Popular #{type.capitalize}"
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
themes_list themes_detection themes_version_all themes_version_detection
timthumbs_list timthumbs_detection
config_backups_list config_backups_detection
db_exports_list db_exports_detection
medias_detection
users_list users_detection]
)
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 '#before_scan' do
it 'creates the Dynamic Finders' do
expect(WPScan::DB::DynamicFinders::Plugin).to receive(:create_versions_finders)
expect(WPScan::DB::DynamicFinders::Theme).to receive(:create_versions_finders)
controller.before_scan
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(parsed_options[: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

View File

@@ -0,0 +1,169 @@
require 'spec_helper'
describe WPScan::Controller::PasswordAttack do
subject(:controller) { described_class.new }
let(:target_url) { 'http://ex.lo/' }
let(:parsed_options) { rspec_parsed_options(cli_args) }
let(:cli_args) { "--url #{target_url}" }
before do
WPScan::Browser.reset
described_class.parsed_options = parsed_options
end
describe '#cli_options' do
its(:cli_options) { should_not be_empty }
its(:cli_options) { should be_a Array }
it 'contains to correct options' do
expect(controller.cli_options.map(&:to_sym))
.to eq(%i[passwords usernames multicall_max_passwords password_attack])
end
end
describe '#users' do
context 'when no --usernames' do
it 'calles target.users' do
expect(controller.target).to receive(:users)
controller.users
end
end
context 'when --usernames' do
let(:cli_args) { "#{super()} --usernames admin,editor" }
it 'returns an array with the users' do
expected = %w[admin editor].reduce([]) do |a, e|
a << CMSScanner::User.new(e)
end
expect(controller.users).to eql expected
end
end
end
describe '#passwords' do
xit
end
describe '#run' do
context 'when no --passwords is supplied' do
it 'does not run the attacker' do
expect(controller.run).to eql nil
end
end
end
describe '#attacker' do
context 'when --password-attack provided' do
let(:cli_args) { "#{super()} --password-attack #{attack}" }
context 'when wp-login' do
let(:attack) { 'wp-login' }
it 'returns the correct object' do
expect(controller.attacker).to be_a WPScan::Finders::Passwords::WpLogin
expect(controller.attacker.target).to be_a WPScan::Target
end
end
context 'when xmlrpc' do
before do
expect(controller.target).to receive(:xmlrpc).and_return(WPScan::XMLRPC.new("#{target_url}/xmlrpc.php"))
end
context 'when single xmlrpc' do
let(:attack) { 'xmlrpc' }
it 'returns the correct object' do
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPC
expect(controller.attacker.target).to be_a WPScan::XMLRPC
end
end
context 'when xmlrpc-multicall' do
let(:attack) { 'xmlrpc-multicall' }
it 'returns the correct object' do
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPCMulticall
expect(controller.attacker.target).to be_a WPScan::XMLRPC
end
end
end
end
context 'when automatic detection' do
before { expect(controller.target).to receive(:xmlrpc).and_return(xmlrpc) }
context 'when xmlrpc not found' do
let(:xmlrpc) { nil }
it 'returns the WpLogin' do
expect(controller.attacker).to be_a WPScan::Finders::Passwords::WpLogin
expect(controller.attacker.target).to be_a WPScan::Target
end
end
context 'when xmlrpc not enabled' do
let(:xmlrpc) { WPScan::XMLRPC.new("#{target_url}/xmlrpc.php") }
it 'returns the WpLogin' do
expect(xmlrpc).to receive(:enabled?).and_return(false)
expect(controller.attacker).to be_a WPScan::Finders::Passwords::WpLogin
expect(controller.attacker.target).to be_a WPScan::Target
end
end
context 'when xmlrpc enabled' do
let(:xmlrpc) { WPScan::XMLRPC.new("#{target_url}/xmlrpc.php") }
before { expect(xmlrpc).to receive(:enabled?).and_return(true) }
context 'when wp.getUsersBlogs methods not available' do
it 'returns the WpLogin' do
expect(xmlrpc).to receive(:available_methods).and_return(%w[m1 m2])
expect(controller.attacker).to be_a WPScan::Finders::Passwords::WpLogin
expect(controller.attacker.target).to be_a WPScan::Target
end
end
context 'when wp.getUsersBlogs method evailable' do
before { expect(xmlrpc).to receive(:available_methods).and_return(%w[wp.getUsersBlogs m2]) }
context 'when WP version not found' do
it 'returns the XMLRPC' do
expect(controller.target).to receive(:wp_version).and_return(false)
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPC
expect(controller.attacker.target).to be_a WPScan::XMLRPC
end
end
context 'when WP version found' do
before { expect(controller.target).to receive(:wp_version).and_return(wp_version) }
context 'when WP < 4.4' do
let(:wp_version) { WPScan::WpVersion.new('3.8.1') }
it 'returns the XMLRPCMulticall' do
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPCMulticall
expect(controller.attacker.target).to be_a WPScan::XMLRPC
end
end
context 'when WP >= 4.4' do
let(:wp_version) { WPScan::WpVersion.new('4.4') }
it 'returns the XMLRPC' do
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPC
expect(controller.attacker.target).to be_a WPScan::XMLRPC
end
end
end
end
end
end
end
end

View File

@@ -0,0 +1,85 @@
require 'spec_helper'
def it_calls_the_formatter_with_the_correct_parameter(version)
it 'calls the formatter with the correct parameter' do
expect(controller.formatter).to receive(:output)
.with('version', hash_including(version: version), 'wp_version')
end
end
describe WPScan::Finders::WpVersionFinders do
subject(:finders) { described_class.new }
describe 'filter_findings' do
context 'when super returns false (nothing found)' do
before do
expect_any_instance_of(WPScan::Finders::UniqueFinders).to receive(:filter_findings).and_return(false)
end
its(:filter_findings) { should be false }
end
end
end
describe WPScan::Controller::WpVersion do
subject(:controller) { described_class.new }
let(:target_url) { 'http://ex.lo/' }
let(:parsed_options) { rspec_parsed_options(cli_args) }
let(:cli_args) { "--url #{target_url}" }
before do
WPScan::Browser.reset
described_class.parsed_options = parsed_options
end
describe '#cli_options' do
its(:cli_options) { should_not be_empty }
its(:cli_options) { should be_a Array }
it 'contains to correct options' do
expect(controller.cli_options.map(&:to_sym)).to eq %i[wp_version_all wp_version_detection]
end
end
describe '#run' do
before do
expect(controller.target).to receive(:wp_version)
.with(
hash_including(
mode: parsed_options[:wp_version_detection] || parsed_options[:detection_mode],
confidence_threshold: parsed_options[:wp_version_all] ? 0 : 100
)
).and_return(stubbed)
end
after { controller.run }
%i[mixed passive aggressive].each do |mode|
context "when --detection-mode #{mode}" do
let(:cli_args) { "#{super()} --detection-mode #{mode}" }
[WPScan::WpVersion.new('4.0')].each do |version|
context "when version = #{version}" do
let(:stubbed) { version }
it_calls_the_formatter_with_the_correct_parameter(version)
end
end
end
end
context 'when --wp-version-all supplied' do
let(:cli_args) { "#{super()} --wp-version-all" }
let(:stubbed) { WPScan::WpVersion.new('3.9.1') }
it_calls_the_formatter_with_the_correct_parameter(WPScan::WpVersion.new('3.9.1'))
end
context 'when --wp-version-detection mode supplied' do
let(:cli_args) { "#{super()} --detection-mode mixed --wp-version-detection passive" }
let(:stubbed) { WPScan::WpVersion.new('4.4') }
it_calls_the_formatter_with_the_correct_parameter(WPScan::WpVersion.new('4.4'))
end
end
end

View File

@@ -0,0 +1,52 @@
require 'spec_helper'
describe WPScan::Finders::ConfigBackups::KnownFilenames do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'config_backups') }
let(:opts) { { list: File.join(WPScan::DB_DIR, 'config_backups.txt') } }
describe '#aggressive' do
before do
expect(target).to receive(:sub_dir).at_least(1).and_return(false)
expect(target).to receive(:homepage_or_404?).at_least(1).and_return(false)
finder.potential_urls(opts).each_key do |url|
stub_request(:get, url).to_return(status: 404)
end
end
context 'when all files are 404s' do
it 'returns an empty array' do
expect(finder.aggressive(opts)).to eql []
end
end
context 'when some files exist' do
let(:files) { ['%23wp-config.php%23', 'wp-config.bak'] }
let(:config_backup) { File.read(File.join(fixtures, 'wp-config.php')) }
before do
files.each do |file|
stub_request(:get, "#{url}#{file}").to_return(body: config_backup)
end
end
it 'returns the expected Array<ConfigBackup>' do
expected = []
files.each do |file|
url = "#{target.url}#{file}"
expected << WPScan::ConfigBackup.new(
url,
confidence: 100,
found_by: described_class::DIRECT_ACCESS
)
end
expect(finder.aggressive(opts)).to eql expected
end
end
end
end

View File

@@ -0,0 +1,13 @@
require 'spec_helper'
describe WPScan::Finders::ConfigBackups::Base do
subject(:config_backups) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
describe '#finders' do
it 'contains the expected finders' do
expect(config_backups.finders.map { |f| f.class.to_s.demodulize }).to eq %w[KnownFilenames]
end
end
end

View File

@@ -0,0 +1,69 @@
require 'spec_helper'
describe WPScan::Finders::DbExports::KnownLocations do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/aa/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'db_exports') }
let(:opts) { { list: File.join(WPScan::DB_DIR, 'db_exports.txt') } }
describe '#potential_urls' do
before do
expect(target).to receive(:sub_dir).at_least(1).and_return(false)
end
it 'replace {domain_name} by its value' do
expect(finder.potential_urls(opts).keys).to eql %w[
http://ex.lo/aa/ex.sql
http://ex.lo/aa/wordpress.sql
http://ex.lo/aa/backup/ex.zip
http://ex.lo/aa/backup/mysql.sql
http://ex.lo/aa/backups/ex.sql.gz
http://ex.lo/aa/backups/db_backup.sql
]
end
end
describe '#aggressive' do
before do
expect(target).to receive(:sub_dir).at_least(1).and_return(false)
expect(target).to receive(:homepage_or_404?).at_least(1).and_return(false)
finder.potential_urls(opts).each_key do |url|
stub_request(:get, url).to_return(status: 404)
end
end
context 'when all files are 404s' do
it 'returns an empty array' do
expect(finder.aggressive(opts)).to eql []
end
end
context 'when some files exist' do
let(:files) { %w[ex.sql backups/db_backup.sql] }
let(:db_export) { File.read(File.join(fixtures, 'dump.sql')) }
before do
files.each do |file|
stub_request(:get, "#{url}#{file}").to_return(body: db_export)
end
end
it 'returns the expected Array<DbExport>' do
expected = []
files.each do |file|
url = "#{target.url}#{file}"
expected << WPScan::DbExport.new(
url,
confidence: 100,
found_by: described_class::DIRECT_ACCESS
)
end
expect(finder.aggressive(opts)).to eql expected
end
end
end
end

View File

@@ -0,0 +1,13 @@
require 'spec_helper'
describe WPScan::Finders::DbExports::Base do
subject(:db_exports) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
describe '#finders' do
it 'contains the expected finders' do
expect(db_exports.finders.map { |f| f.class.to_s.demodulize }).to eq %w[KnownLocations]
end
end
end

View File

@@ -0,0 +1,64 @@
require 'spec_helper'
describe WPScan::Finders::InterestingFindings::BackupDB 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) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'backup_db') }
let(:wp_content) { 'wp-content' }
let(:dir_url) { target.url("#{wp_content}/backup-db/") }
before { expect(target).to receive(:content_dir).at_least(1).and_return(wp_content) }
describe '#aggressive' do
before { stub_request(:get, dir_url).to_return(status: status, body: body) }
let(:body) { '' }
context 'when not a 200 or 403' do
let(:status) { 404 }
its(:aggressive) { should be_nil }
end
context 'when 200 and matching the homepage' do
before { expect(target).to receive(:homepage_or_404?).and_return(true) }
let(:status) { 200 }
its(:aggressive) { should be_nil }
end
context 'when 200 or 403' do
before { expect(target).to receive(:homepage_or_404?).and_return(false) }
let(:status) { 200 }
after do
found = finder.aggressive
expect(found).to eql WPScan::InterestingFinding.new(
dir_url,
confidence: 70,
found_by: described_class::DIRECT_ACCESS
)
expect(found.interesting_entries).to eq @expected_entries
end
context 'when no directory listing' do
it 'returns an empty interesting_findings attribute' do
@expected_entries = []
end
end
context 'when directory listing enabled' do
let(:body) { File.read(File.join(fixtures, 'dir_listing.html')) }
it 'returns the expected interesting_findings attribute' do
@expected_entries = %w[sqldump.sql test.txt]
end
end
end
end
end

View File

@@ -0,0 +1,34 @@
require 'spec_helper'
describe WPScan::Finders::InterestingFindings::DebugLog do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'debug_log') }
let(:wp_content) { 'wp-content' }
let(:log_url) { target.url("#{wp_content}/debug.log") }
before { expect(target).to receive(:content_dir).at_least(1).and_return(wp_content) }
describe '#aggressive' do
before { stub_request(:get, log_url).to_return(body: body) }
context 'when empty file' do
let(:body) { '' }
its(:aggressive) { should be_nil }
end
context 'when a log file' do
let(:body) { File.read(File.join(fixtures, 'debug.log')) }
it 'returns the InterestingFinding' do
expect(finder.aggressive).to eql WPScan::InterestingFinding.new(
log_url,
confidence: 100,
found_by: described_class::DIRECT_ACCESS
)
end
end
end
end

View File

@@ -0,0 +1,35 @@
require 'spec_helper'
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) { File.join(FINDERS_FIXTURES, '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)
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
let(:body) { File.read(File.join(fixtures, filename)) }
it 'returns the InterestingFinding' do
expect(finder.aggressive).to eql WPScan::InterestingFinding.new(
log_url,
confidence: 100,
found_by: described_class::DIRECT_ACCESS
)
end
end
end
end

View File

@@ -0,0 +1,12 @@
require 'spec_helper'
describe WPScan::Finders::InterestingFindings::EmergencyPwdResetScript 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) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'emergency_pwd_reset_script') }
describe '#aggressive' do
xit
end
end

View File

@@ -0,0 +1,37 @@
require 'spec_helper'
describe WPScan::Finders::InterestingFindings::FullPathDisclosure do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'fpd') }
let(:file_url) { target.url('wp-includes/rss-functions.php') }
describe '#aggressive' do
before do
expect(target).to receive(:sub_dir).at_least(1).and_return(false)
stub_request(:get, file_url).to_return(body: body)
end
context 'when empty file' do
let(:body) { '' }
its(:aggressive) { should be_nil }
end
context 'when a log file' do
let(:body) { File.read(File.join(fixtures, 'rss_functions.php')) }
it 'returns the InterestingFinding' do
found = finder.aggressive
expect(found).to eql WPScan::InterestingFinding.new(
file_url,
confidence: 100,
found_by: described_class::DIRECT_ACCESS
)
expect(found.interesting_entries).to eql %w[/blog/wp-includes/rss-functions.php]
end
end
end
end

View File

@@ -0,0 +1,16 @@
require 'spec_helper'
describe WPScan::Finders::InterestingFindings::MuPlugins 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) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'mu_plugins') }
describe '#passive' do
xit
end
describe '#aggressive' do
xit
end
end

View File

@@ -0,0 +1,12 @@
require 'spec_helper'
describe WPScan::Finders::InterestingFindings::Multisite 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) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'multisite') }
describe '#aggressive' do
xit
end
end

View File

@@ -0,0 +1,46 @@
require 'spec_helper'
describe WPScan::Finders::InterestingFindings::Readme do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'readme') }
describe '#aggressive' do
before do
expect(target).to receive(:sub_dir).at_least(1).and_return(false)
finder.potential_files.each do |file|
stub_request(:get, target.url(file)).to_return(status: 404)
end
end
context 'when no file present' do
its(:aggressive) { should be_nil }
end
# TODO: case when multiple files are present ? (should return only the first one found)
context 'when a file exists' do
let(:file) { finder.potential_files.sample }
let(:readme) { File.read(File.join(fixtures, 'readme-3.9.2.html')) }
before { stub_request(:get, target.url(file)).to_return(body: readme) }
it 'returns the expected InterestingFinding' do
expected = WPScan::InterestingFinding.new(
target.url(file),
confidence: 100,
found_by: described_class::DIRECT_ACCESS
)
expect(finder.aggressive).to eql expected
end
end
end
describe '#potential_files' do
it 'does not contain duplicates' do
expect(finder.potential_files.flatten.uniq.length).to eql finder.potential_files.length
end
end
end

View File

@@ -0,0 +1,12 @@
require 'spec_helper'
describe WPScan::Finders::InterestingFindings::Registration 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) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'registration') }
describe '#aggressive' do
xit
end
end

View File

@@ -0,0 +1,12 @@
require 'spec_helper'
describe WPScan::Finders::InterestingFindings::TmmDbMigrate 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) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'tmm_db_migrate') }
describe '#aggressive' do
xit
end
end

View File

@@ -0,0 +1,13 @@
require 'spec_helper'
describe WPScan::Finders::InterestingFindings::UploadDirectoryListing 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) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'upload_directory_listing') }
let(:wp_content) { 'wp-content' }
describe '#aggressive' do
xit
end
end

View File

@@ -0,0 +1,50 @@
require 'spec_helper'
describe WPScan::Finders::InterestingFindings::UploadSQLDump 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) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'upload_sql_dump') }
let(:wp_content) { 'wp-content' }
describe '#aggressive' do
before { expect(target).to receive(:content_dir).at_least(1).and_return(wp_content) }
after { expect(finder.aggressive).to eql @expected }
context 'when not a 200' do
it 'returns nil' do
stub_request(:get, finder.dump_url).to_return(status: 404)
@expected = nil
end
end
context 'when a 200' do
before do
stub_request(:get, finder.dump_url)
.to_return(status: 200, body: File.read(File.join(fixtures, fixture)))
end
context 'when the body does not match a SQL dump' do
let(:fixture) { 'not_sql.txt' }
it 'returns nil' do
@expected = nil
end
end
context 'when the body matches a SQL dump' do
let(:fixture) { 'dump.sql' }
it 'returns the interesting findings' do
@expected = WPScan::InterestingFinding.new(
finder.dump_url,
confidence: 100,
found_by: described_class::DIRECT_ACCESS
)
end
end
end
end
end

View File

@@ -0,0 +1,21 @@
require 'spec_helper'
describe WPScan::Finders::InterestingFindings::Base do
subject(:files) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
describe '#finders' do
let(:expected) do
%w[
Readme DebugLog FullPathDisclosure
Multisite MuPlugins Registration UploadDirectoryListing TmmDbMigrate
UploadSQLDump
]
end
it 'contains the expected finders' do
expect(files.finders.map { |f| f.class.to_s.demodulize }).to include(*expected)
end
end
end

View File

@@ -0,0 +1,58 @@
require 'spec_helper'
describe WPScan::Finders::MainTheme::CssStyle do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'main_theme', 'css_style') }
describe '#passive' do
after do
stub_request(:get, url).to_return(body: File.read(File.join(fixtures, fixture)))
expect(finder.passive).to eql @expected
end
context 'when no in scope style' do
let(:fixture) { 'no_in_scope_style.html' }
it 'returns nil' do
@expected = nil
end
end
context 'when in scope style' do
before do
expect(target).to receive(:content_dir).at_least(1).and_return('wp-content')
stub_request(:get, /.*.css/)
end
context 'when in a link href' do
let(:fixture) { 'link_href.html' }
it 'returns the expected theme' do
@expected = WPScan::Theme.new(
'twentyfifteen',
target,
found_by: 'Css Style (Passive Detection)',
confidence: 70,
style_url: 'http://wp.lab/wp-content/themes/twentyfifteen/style.css?ver=4.1.1'
)
end
end
context 'when in the style code' do
let(:fixture) { 'style_code.html' }
it 'returns the expected theme' do
@expected = WPScan::Theme.new(
'custom',
target,
found_by: 'Css Style (Passive Detection)',
confidence: 70,
style_url: 'http://wp.lab/wp-content/themes/custom/style.css'
)
end
end
end
end
end

View File

@@ -0,0 +1,35 @@
require 'spec_helper'
describe WPScan::Finders::MainTheme::UrlsInHomepage do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'main_theme', 'urls_in_homepage') }
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
let(:type) { 'themes' }
let(:uniq_links) { false }
let(:uniq_codes) { false }
let(:expected_from_links) { %w[twentyfifteen twentyfifteen twentyfifteen yolo] }
let(:expected_from_codes) { %w[test yolo] }
end
describe '#passive' do
before do
stub_request(:get, /.*.css/)
stub_request(:get, target.url).to_return(body: File.read(File.join(fixtures, 'found.html')))
end
it 'returns the expected Themes' do
@expected = []
{ 'twentyfifteen' => 6, 'yolo' => 4, 'test' => 2 }.each do |slug, confidence|
@expected << WPScan::Theme.new(
slug, target, found_by: 'Urls In Homepage (Passive Detection)', confidence: confidence
)
end
expect(finder.passive).to eql @expected
end
end
end

View File

@@ -0,0 +1,39 @@
require 'spec_helper'
describe WPScan::Finders::MainTheme::WooFrameworkMetaGenerator do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'main_theme', 'woo_framework_meta_generator') }
describe '#passive' do
after do
stub_request(:get, url).to_return(body: File.read(File.join(fixtures, @file)))
expect(finder.passive).to eql @expected
end
context 'when no Woo generator' do
it 'returns nil' do
@file = 'no_woo_generator.html'
@expected = nil
end
end
context 'when Woo generator' do
before do
expect(target).to receive(:content_dir).at_least(1).and_return('wp-content')
stub_request(:get, "#{url}wp-content/themes/Merchant/style.css")
end
it 'returns the expected theme' do
@file = 'woo_generator.html'
@expected = WPScan::Theme.new(
'Merchant', target,
found_by: 'Woo Framework Meta Generator (Passive Detection)',
confidence: 80
)
end
end
end
end

View File

@@ -0,0 +1,14 @@
require 'spec_helper'
describe WPScan::Finders::MainTheme::Base do
subject(:main_theme) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
describe '#finders' do
it 'contains the expected finders' do
expect(main_theme.finders.map { |f| f.class.to_s.demodulize })
.to eq %w[CssStyle WooFrameworkMetaGenerator UrlsInHomepage]
end
end
end

View File

@@ -0,0 +1,21 @@
require 'spec_helper'
describe WPScan::Finders::Medias::AttachmentBruteForcing do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'medias', 'attachment_brute_forcing') }
describe '#aggressive' do
xit
end
describe '#target_urls' do
it 'returns the expected urls' do
expect(finder.target_urls(range: (1..2))).to eql(
url + '?attachment_id=1' => 1,
url + '?attachment_id=2' => 2
)
end
end
end

View File

@@ -0,0 +1,13 @@
require 'spec_helper'
describe WPScan::Finders::Medias::Base do
subject(:media) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
describe '#finders' do
it 'contains the expected finders' do
expect(media.finders.map { |f| f.class.to_s.demodulize }).to eq %w[AttachmentBruteForcing]
end
end
end

View File

@@ -0,0 +1,116 @@
require 'spec_helper'
describe WPScan::Finders::PluginVersion::Readme do
subject(:finder) { described_class.new(plugin) }
let(:plugin) { WPScan::Plugin.new('spec', target) }
let(:target) { WPScan::Target.new('http://wp.lab/') }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'plugin_version', 'readme') }
def version(number, found_by, confidence)
WPScan::Version.new(
number,
found_by: format('Readme - %s (Aggressive Detection)', found_by),
confidence: confidence,
interesting_entries: [readme_url]
)
end
def stable_tag(number)
version(number, 'Stable Tag', 80)
end
def changelog_section(number)
version(number, 'ChangeLog Section', 50)
end
describe '#aggressive' do
before { expect(target).to receive(:content_dir).and_return('wp-content') }
after do
stub_request(:get, /.*/).to_return(status: 404)
stub_request(:get, readme_url).to_return(body: File.read(File.join(fixtures, @file)))
expect(finder.aggressive).to eql @expected
end
let(:readme_url) { plugin.url(WPScan::WpItem::READMES.sample) }
context 'when no version' do
it 'returns nil' do
@file = 'no_version.txt'
@expected = nil
end
end
context 'when the stable tag does not contain numbers' do
it 'returns nil' do
@file = 'aa-health-calculator.txt'
@expected = nil
end
end
context 'when empty changelog section' do
it 'returns nil' do
@file = 'all-in-one-facebook.txt'
@expected = nil
end
end
context 'when no changelog section' do
it 'returns nil' do
@file = 'blog-reordering.txt'
@expected = nil
end
end
context 'when leaked from the stable tag' do
it 'returns the expected versions' do
@file = 'simple-login-lockdown-0.4.txt'
@expected = [stable_tag('0.4'), changelog_section('04')]
end
end
context 'when leaked from the version' do
it 'returns it' do
@file = 'wp-photo-plus-5.1.15.txt'
@expected = [stable_tag('5.1.15')]
end
end
context 'when version is in a release date format' do
it 'detects and returns it' do
@file = 's2member.txt'
@expected = [stable_tag('141007')]
end
end
context 'when version contains letters' do
it 'returns it' do
@file = 'beta1.txt'
@expected = [stable_tag('2.0.0-beta1')]
end
end
context 'when parsing the changelog for version numbers' do
{
'changelog_version' => '1.3',
'wp_polls' => '2.64',
'nextgen_gallery' => '2.0.66.33',
'wp_user_frontend' => '1.2.3',
'my_calendar' => '2.1.5',
'nextgen_gallery_2' => '1.9.13',
'advanced-most-recent-posts-mod' => '1.6.5.2',
'a-lead-capture-contact-form-and-tab-button-by-awebvoicecom' => '3.1',
'backup-scheduler' => '1.5.9',
'release_date_slash' => '1.0.4'
}. each do |file, version_number|
context "whith #{file}.txt" do
it 'returns the expected version' do
@file = "#{file}.txt"
@expected = [changelog_section(version_number)]
end
end
end
end
end
end

View File

@@ -0,0 +1,46 @@
require 'spec_helper'
# If this file is tested alone (rspec path-to-this-file), then there will be an error about
# constants not being intilialized. This is due to the Dynamic Finders.
describe WPScan::Finders::PluginVersion::Base do
subject(:plugin_version) { described_class.new(plugin) }
let(:plugin) { WPScan::Plugin.new(slug, target) }
let(:target) { WPScan::Target.new('http://wp.lab/') }
let(:default_finders) { %w[Readme] }
describe '#finders' do
after do
expect(target).to receive(:content_dir).and_return('wp-content')
expect(plugin_version.finders.map { |f| f.class.to_s.demodulize }).to match_array @expected
end
context 'when no related specific finders' do
let(:slug) { 'spec' }
it 'contains the default finders' do
@expected = default_finders
end
end
# Dynamic Version Finders are not tested here, they are in
# spec/lib/finders/dynamic_finder/plugin_versions_spec
context 'when specific finders' do
let(:specific) do
{
# None so far
}
end
WPScan::DB::DynamicFinders::Plugin.versions_finders_configs.each do |plugin_slug, configs|
context "when #{plugin_slug} plugin" do
let(:slug) { plugin_slug }
it 'contains the expected finders (default + specific + the dynamic ones)' do
@expected = default_finders + [*specific[plugin_slug]] + configs.keys
end
end
end
end
end
end

View File

@@ -0,0 +1,13 @@
require 'spec_helper'
describe WPScan::Finders::Plugins::BodyPattern do
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
let(:expected_all) { df_expected_all['plugins'] }
let(:item_class) { WPScan::Plugin }
end
end

View File

@@ -0,0 +1,13 @@
require 'spec_helper'
describe WPScan::Finders::Plugins::Comment do
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
let(:expected_all) { df_expected_all['plugins'] }
let(:item_class) { WPScan::Plugin }
end
end

View File

@@ -0,0 +1,15 @@
require 'spec_helper'
describe WPScan::Finders::Plugins::ConfigParser do
xit
# it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
# subject(:finder) { described_class.new(target) }
# let(:target) { WPScan::Target.new(url) }
# let(:url) { 'http://wp.lab/' }
# let(:fixtures) { File.join(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
#
# let(:expected_all) { df_expected_all['plugins'] }
# let(:item_class) { WPScan::Plugin }
# end
end

View File

@@ -0,0 +1,45 @@
require 'spec_helper'
describe WPScan::Finders::Plugins::HeaderPattern do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
def plugin(slug)
WPScan::Plugin.new(slug, target)
end
describe '#passive' do
after do
stub_request(:get, target.url).to_return(headers: headers)
found = finder.passive
expect(found).to match_array @expected
expect(found.first.found_by).to eql 'Header Pattern (Passive Detection)' unless found.empty?
end
context 'when empty headers' do
let(:headers) { {} }
it 'returns an empty array' do
@expected = []
end
end
context 'when headers' do
before { expect(target).to receive(:content_dir).and_return('wp-content') }
let(:headers) { JSON.parse(File.read(File.join(fixtures, 'header_pattern_passive_all.html'))) }
it 'returns the expected plugins' do
@expected = []
WPScan::DB::DynamicFinders::Plugin.passive_header_pattern_finder_configs.each_key do |slug|
@expected << plugin(slug)
end
end
end
end
end

View File

@@ -0,0 +1,13 @@
require 'spec_helper'
describe WPScan::Finders::Plugins::JavascriptVar do
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
let(:expected_all) { df_expected_all['plugins'] }
let(:item_class) { WPScan::Plugin }
end
end

View File

@@ -0,0 +1,12 @@
require 'spec_helper'
describe WPScan::Finders::Plugins::KnownLocations do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'plugins', 'known_locations') }
describe '#aggressive' do
xit
end
end

View File

@@ -0,0 +1,16 @@
require 'spec_helper'
describe WPScan::Finders::Plugins::QueryParameter do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
describe '#passive' do
its(:passive) { should be nil }
end
describe '#aggressive' do
xit
end
end

View File

@@ -0,0 +1,27 @@
require 'spec_helper'
describe WPScan::Finders::Plugins::UrlsInHomepage do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'plugins', 'urls_in_homepage') }
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
let(:type) { 'plugins' }
let(:uniq_links) { true }
let(:uniq_codes) { true }
let(:expected_from_links) { (1..4).map { |i| "dl-#{i}" } }
let(:expected_from_codes) { (1..6).map { |i| "dc-#{i}" } }
end
describe '#passive' do
before do
stub_request(:get, finder.target.url)
.to_return(body: File.read(File.join(fixtures, 'found.html')))
expect(finder.target).to receive(:content_dir).at_least(1).and_return('wp-content')
end
xit
end
end

View File

@@ -0,0 +1,13 @@
require 'spec_helper'
describe WPScan::Finders::Plugins::Xpath do
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
let(:expected_all) { df_expected_all['plugins'] }
let(:item_class) { WPScan::Plugin }
end
end

View File

@@ -0,0 +1,14 @@
require 'spec_helper'
describe WPScan::Finders::Plugins::Base do
subject(:plugins) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
describe '#finders' do
it 'contains the expected finders' do
expect(plugins.finders.map { |f| f.class.to_s.demodulize })
.to eq %w[UrlsInHomepage HeaderPattern Comment Xpath BodyPattern JavascriptVar KnownLocations]
end
end
end

View File

@@ -0,0 +1,98 @@
require 'spec_helper'
describe WPScan::Finders::ThemeVersion::Style do
subject(:finder) { described_class.new(theme) }
let(:theme) { WPScan::Theme.new('spec', target) }
let(:target) { WPScan::Target.new('http://wp.lab/') }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'theme_version', 'style') }
before :all do
Typhoeus::Config.cache = WPScan::Cache::Typhoeus.new(File.join(SPECS, 'cache'))
end
before do
expect(target).to receive(:content_dir).at_least(1).and_return('wp-content')
stub_request(:get, /.*.css/).and_return(body: defined?(style_body) ? style_body : '')
end
describe '#passive' do
before { expect(finder).to receive(:cached_style?).and_return(cached?) }
after { finder.passive }
context 'when the style_url request has been cached' do
let(:cached?) { true }
it 'calls the style_version' do
expect(finder).to receive(:style_version)
end
end
context 'when the style_url request has not been cached' do
let(:cached?) { false }
it 'returns nil' do
expect(finder).to_not receive(:style_version)
end
end
end
describe '#aggressive' do
before { expect(finder).to receive(:cached_style?).and_return(cached?) }
after { finder.aggressive }
context 'when the style_url request has been cached' do
let(:cached?) { true }
it 'returns nil' do
expect(finder).to_not receive(:style_version)
end
end
context 'when the style_url request has not been cached' do
let(:cached?) { false }
it 'calls the style_version' do
expect(finder).to receive(:style_version)
end
end
end
describe '#cached_style?' do
it 'calls the Cache with the correct arguments' do
expected = Typhoeus::Request.new(
theme.style_url,
finder.browser.default_request_params.merge(method: :get)
)
expect(Typhoeus::Config.cache).to receive(:get) { |arg| expect(arg).to eql expected }
finder.cached_style?
end
end
describe '#style_version' do
{
'inline' => '1.5.1',
'firefart' => '1.0.0',
'tralling_quote' => '1.3',
'no_version_tag' => nil,
'trunk_version' => nil,
'no_version' => nil
}.each do |file, expected_version|
context "when #{file}" do
let(:style_body) { File.new(File.join(fixtures, "#{file}.css")) }
it 'returns the expected version' do
expected = if expected_version
WPScan::Version.new(
expected_version,
confidence: 80,
interesting_entries: ["#{theme.style_url}, Version: #{expected_version}"]
)
end
expect(finder.style_version).to eql expected
end
end
end
end
end

View File

@@ -0,0 +1,41 @@
require 'spec_helper'
describe WPScan::Finders::ThemeVersion::WooFrameworkMetaGenerator do
subject(:finder) { described_class.new(theme) }
let(:theme) { WPScan::Theme.new(slug, target) }
let(:target) { WPScan::Target.new('http://wp.lab/') }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'theme_version', 'woo_framework_meta_generator') }
before do
expect(target).to receive(:content_dir).and_return('wp-content')
stub_request(:get, /\.css\z/)
end
describe '#passive' do
after do
stub_request(:get, target.url).to_return(body: File.read(File.join(fixtures, 'editorial-1.3.5.html')))
expect(finder.passive).to eql @expected
end
context 'when the theme slug does not match' do
let(:slug) { 'spec' }
it 'returns nil' do
@expected = nil
end
end
context 'when the theme slug matches' do
let(:slug) { 'Editorial' }
it 'return the expected version' do
@expected = WPScan::Version.new(
'1.3.5',
found_by: 'Woo Framework Meta Generator (Passive Detection)',
confidence: 80
)
end
end
end
end

View File

@@ -0,0 +1,35 @@
require 'spec_helper'
describe WPScan::Finders::ThemeVersion::Base do
subject(:theme_version) { described_class.new(theme) }
let(:theme) { WPScan::Plugin.new(slug, target) }
let(:target) { WPScan::Target.new('http://wp.lab/') }
let(:slug) { 'spec' }
let(:default_finders) { %w[Style WooFrameworkMetaGenerator] }
describe '#finders' do
after do
expect(target).to receive(:content_dir).and_return('wp-content')
expect(theme_version.finders.map { |f| f.class.to_s.demodulize }).to eql @expected
end
context 'when no related specific finders' do
it 'contains the default finders' do
@expected = default_finders
end
end
context 'when specific finders' do
{
}.each do |theme_slug, specific_finders|
context "when #{theme_slug} theme" do
let(:slug) { theme_slug }
it 'contains the expected finders' do
@expected = default_finders + specific_finders
end
end
end
end
end
end

View File

@@ -0,0 +1,12 @@
require 'spec_helper'
describe WPScan::Finders::Themes::KnownLocations do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'themes', 'known_locations') }
describe '#aggressive' do
xit
end
end

View File

@@ -0,0 +1,20 @@
require 'spec_helper'
describe WPScan::Finders::Themes::UrlsInHomepage do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'themes', 'urls_in_homepage') }
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
let(:type) { 'themes' }
let(:uniq_links) { true }
let(:uniq_codes) { true }
let(:expected_from_links) { %w[dl-1] }
let(:expected_from_codes) { %w[dc-1] }
end
describe '#passive' do
xit
end
end

View File

@@ -0,0 +1,14 @@
require 'spec_helper'
describe WPScan::Finders::Themes::Base do
subject(:themes) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
describe '#finders' do
it 'contains the expected finders' do
expect(themes.finders.map { |f| f.class.to_s.demodulize })
.to eq %w[UrlsInHomepage KnownLocations]
end
end
end

View File

@@ -0,0 +1,36 @@
require 'spec_helper'
describe WPScan::Finders::TimthumbVersion::BadRequest do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Timthumb.new(url) }
let(:url) { 'http://ex.lo/timthumb.php' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'timthumb_version', 'bad_request') }
describe '#aggressive' do
before { stub_request(:get, url).to_return(body: File.read(File.join(fixtures, file))) }
after { expect(finder.aggressive).to eql @expected }
context 'when no version' do
let(:file) { 'no_version.php' }
it 'returns nil' do
@expected = nil
end
end
context 'when a version' do
let(:file) { '2.8.14.php' }
it 'returns the expected version' do
@expected = WPScan::Version.new(
'2.8.14',
confidence: 90,
found_by: 'Bad Request (Aggressive Detection)',
interesting_entries: [
"#{url}, TimThumb version : 2.8.14"
]
)
end
end
end
end

View File

@@ -0,0 +1,13 @@
require 'spec_helper'
describe WPScan::Finders::TimthumbVersion::Base do
subject(:timthumb_version) { described_class.new(target) }
let(:target) { WPScan::Timthumb.new(url) }
let(:url) { 'http://ex.lo/timthumb.php' }
describe '#finders' do
it 'contains the expected finders' do
expect(timthumb_version.finders.map { |f| f.class.to_s.demodulize }).to eq %w[BadRequest]
end
end
end

View File

@@ -0,0 +1,12 @@
require 'spec_helper'
describe WPScan::Finders::Timthumbs::KnownLocations do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'timthumbs', 'known_locations') }
describe '#aggressive' do
xit
end
end

View File

@@ -0,0 +1,13 @@
require 'spec_helper'
describe WPScan::Finders::Timthumbs::Base do
subject(:timthumb) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
describe '#finders' do
it 'contains the expected finders' do
expect(timthumb.finders.map { |f| f.class.to_s.demodulize }).to eq %w[KnownLocations]
end
end
end

View File

@@ -0,0 +1,62 @@
require 'spec_helper'
describe WPScan::Finders::Users::AuthorIdBruteForcing do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'users', 'author_id_brute_forcing') }
describe '#aggressive' do
xit
end
describe '#target_urls' do
it 'returns the correct URLs' do
expect(finder.target_urls(range: (1..2))).to eql(
url + '?author=1' => 1,
url + '?author=2' => 2
)
end
end
describe '#potential_username' do
[
'4.1.1', '4.1.1-permalink',
'3.0', '3.0-permalink',
'2.9.2', '2.9.2-permalink'
].each do |file|
it "returns 'admin' from #{file}.html" do
body = File.read(File.join(fixtures, "#{file}.html"))
res = Typhoeus::Response.new(body: body)
expect(finder.username_from_response(res)).to eql 'admin'
end
end
end
describe '#display_name_from_body' do
context 'when display name' do
[
'4.1.1', '4.1.1-permalink',
'3.0', '3.0-permalink',
'2.9.2', '2.9.2-permalink'
].each do |file|
it "returns 'admin display_name' from #{file}.html" do
body = File.read(File.join(fixtures, "#{file}.html"))
expect(finder.display_name_from_body(body)).to eql 'admin display_name'
end
end
end
context 'when no display_name' do
['4.1.1', '3.0', '2.9.2'].each do |file|
it "returns nil for #{file}-empty.html" do
body = File.read(File.join(fixtures, "#{file}-empty.html"))
expect(finder.display_name_from_body(body)).to eql nil
end
end
end
end
end

View File

@@ -0,0 +1,27 @@
require 'spec_helper'
describe WPScan::Finders::Users::AuthorPosts do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'users', 'author_posts') }
describe '#passive' do
xit
end
describe '#potential_usernames' do
it 'returns the expected usernames' do
res = Typhoeus::Response.new(body: File.read(File.join(fixtures, 'potential_usernames.html')))
results = finder.potential_usernames(res)
expect(results).to eql([
['admin', 'Author Pattern', 100],
['admin display_name', 'Display Name', 30],
['editor', 'Author Pattern', 100],
['editor', 'Display Name', 30]
])
end
end
end

View File

@@ -0,0 +1,32 @@
require 'spec_helper'
describe WPScan::Finders::Users::LoginErrorMessages do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'users', 'login_error_messages') }
describe '#aggressive' do
xit
end
describe '#usernames' do
let(:opts) { { found: [] } }
after { expect(subject.usernames(opts)).to eql @expected }
context 'when no :list provided' do
it 'returns an empty list' do
@expected = []
end
end
context 'when :list provided' do
let(:opts) { super().merge(list: %w[u1 u2]) }
it 'returns the expected array' do
@expected = opts[:list]
end
end
end
end

View File

@@ -0,0 +1,12 @@
require 'spec_helper'
describe WPScan::Finders::Users::OembedApi do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'users', 'oembed_api') }
describe '#aggressive' do
xit
end
end

View File

@@ -0,0 +1,102 @@
require 'spec_helper'
describe WPScan::Finders::Users::RSSGenerator do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
let(:fixtures) { Pathname.new(FINDERS_FIXTURES).join('users', 'rss_generator') }
let(:rss_fixture) { File.read(fixtures.join('feed.xml')) }
describe '#passive, #aggressive' do
before do
allow(target).to receive(:sub_dir).and_return(false)
stub_request(:get, target.url).to_return(body: File.read(homepage_fixture))
end
context 'when no RSS link in homepage' do
let(:homepage_fixture) { fixtures.join('homepage_no_links.html') }
its(:passive) { should eql [] }
it 'returns the expected from #aggressive' do
stub_request(:get, target.url('feed/')).to_return(body: rss_fixture)
stub_request(:get, target.url('comments/feed/'))
stub_request(:get, target.url('feed/rss/'))
stub_request(:get, target.url('feed/rss2/'))
expect(finder.aggressive).to eql [
CMSScanner::User.new(
'admin',
confidence: 50,
found_by: 'Rss Generator (Aggressive Detection)'
),
CMSScanner::User.new(
'Aa Días-Gildés',
confidence: 50,
found_by: 'Rss Generator (Aggressive Detection)'
)
]
end
end
context 'when RSS link in homepage' do
let(:homepage_fixture) { File.join(fixtures, 'homepage_links.html') }
it 'returns the expected from #passive' do
stub_request(:get, target.url('feed/')).to_return(body: rss_fixture)
expect(finder.passive).to eql [
CMSScanner::User.new(
'admin',
confidence: 50,
found_by: 'Rss Generator (Passive Detection)'
),
CMSScanner::User.new(
'Aa Días-Gildés',
confidence: 50,
found_by: 'Rss Generator (Passive Detection)'
)
]
end
context 'when :mixed mode' do
it 'avoids checking existing URL/s from #passive' do
stub_request(:get, target.url('comments/feed/')).to_return(body: rss_fixture)
expect(finder.aggressive(mode: :mixed)).to eql [
CMSScanner::User.new(
'admin',
confidence: 50,
found_by: 'Rss Generator (Aggressive Detection)'
),
CMSScanner::User.new(
'Aa Días-Gildés',
confidence: 50,
found_by: 'Rss Generator (Aggressive Detection)'
)
]
end
end
context 'when no mode' do
it 'checks the first URL detected from the URLs' do
stub_request(:get, target.url('feed/')).to_return(body: rss_fixture)
expect(finder.aggressive).to eql [
CMSScanner::User.new(
'admin',
confidence: 50,
found_by: 'Rss Generator (Aggressive Detection)'
),
CMSScanner::User.new(
'Aa Días-Gildés',
confidence: 50,
found_by: 'Rss Generator (Aggressive Detection)'
)
]
end
end
end
end
end

View File

@@ -0,0 +1,47 @@
require 'spec_helper'
describe WPScan::Finders::Users::WpJsonApi do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { File.join(FINDERS_FIXTURES, 'users', 'wp_json_api') }
describe '#aggressive' do
before do
# allow(target).to receive(:content_dir).and_return('wp-content')
allow(target).to receive(:sub_dir).and_return(false)
stub_request(:get, finder.api_url).to_return(body: body)
end
context 'when not a JSON response' do
let(:body) { '' }
its(:aggressive) { should eql([]) }
end
context 'when a JSON response' do
context 'when unauthorised' do
let(:body) { File.read(File.join(fixtures, '401.json')) }
its(:aggressive) { should eql([]) }
end
context 'when limited exposure (WP >= 4.7.1)' do
let(:body) { File.read(File.join(fixtures, '4.7.2.json')) }
it 'returns the expected array of users' do
users = finder.aggressive
expect(users.size).to eql 1
user = users.first
expect(user.id).to eql 1
expect(user.username).to eql 'admin'
expect(user.confidence).to eql 100
expect(user.interesting_entries).to eql ['http://wp.lab/wp-json/wp/v2/users/']
end
end
end
end
end

View File

@@ -0,0 +1,14 @@
require 'spec_helper'
describe WPScan::Finders::Users::Base do
subject(:user) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
describe '#finders' do
it 'contains the expected finders' do
expect(user.finders.map { |f| f.class.to_s.demodulize })
.to eq %w[AuthorPosts WpJsonApi OembedApi RSSGenerator AuthorIdBruteForcing LoginErrorMessages]
end
end
end

View File

@@ -0,0 +1,97 @@
require 'spec_helper'
describe WPScan::Finders::WpVersion::AtomGenerator 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) { Pathname.new(FINDERS_FIXTURES).join('wp_version', 'atom_generator') }
let(:atom_fixture) { File.read(fixtures.join('feed', 'atom')) }
describe '#passive, #aggressive' do
before do
allow(target).to receive(:sub_dir).and_return(false)
stub_request(:get, target.url).to_return(body: File.read(homepage_fixture))
end
context 'when no atom links in homepage' do
let(:homepage_fixture) { fixtures.join('no_links.html') }
its(:passive) { should eql [] }
it 'returns the expected from #aggressive' do
stub_request(:get, target.url('feed/atom/')).to_return(body: atom_fixture)
stub_request(:get, target.url('?feed=atom'))
expect(finder.aggressive).to eql [
WPScan::WpVersion.new(
'4.0',
confidence: 80,
found_by: 'Atom Generator (Aggressive Detection)',
interesting_entries: [
"#{target.url('feed/atom/')}, Match: '<generator uri=\"https://wordpress.org/\" version=\"4.0\">" \
"WordPress</generator>'"
]
)
]
end
end
context 'when atom links in homepage' do
let(:homepage_fixture) { File.join(fixtures, 'links.html') }
it 'returns the expected from #passive' do
stub_request(:get, target.url('?feed=atom')).to_return(body: atom_fixture)
expect(finder.passive).to eql [
WPScan::WpVersion.new(
'4.0',
confidence: 80,
found_by: 'Atom Generator (Passive Detection)',
interesting_entries: [
"#{target.url('?feed=atom')}, Match: '<generator uri=\"https://wordpress.org/\" version=\"4.0\">" \
"WordPress</generator>'"
]
)
]
end
context 'when :mixed mode' do
it 'avoids checking existing URL/s from #passive' do
stub_request(:get, target.url('feed/atom/')).to_return(body: atom_fixture)
expect(finder.aggressive(mode: :mixed)).to eql [
WPScan::WpVersion.new(
'4.0',
confidence: 80,
found_by: 'Atom Generator (Aggressive Detection)',
interesting_entries: [
"#{target.url('feed/atom/')}, Match: '<generator uri=\"https://wordpress.org/\" version=\"4.0\">" \
"WordPress</generator>'"
]
)
]
end
end
context 'when no mode' do
it 'checks all the URLs' do
stub_request(:get, target.url('feed/atom/')).to_return(body: atom_fixture)
stub_request(:get, target.url('?feed=atom'))
expect(finder.aggressive).to eql [
WPScan::WpVersion.new(
'4.0',
confidence: 80,
found_by: 'Atom Generator (Aggressive Detection)',
interesting_entries: [
"#{target.url('feed/atom/')}, Match: '<generator uri=\"https://wordpress.org/\" version=\"4.0\">" \
"WordPress</generator>'"
]
)
]
end
end
end
end
end

View File

@@ -0,0 +1,10 @@
require 'spec_helper'
describe WPScan::Finders::WpVersion::RDFGenerator 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) { File.join(FINDERS_FIXTURES, 'wp_version', 'rdf_generator') }
xit
end

View File

@@ -0,0 +1,49 @@
require 'spec_helper'
describe WPScan::Finders::WpVersion::Readme 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) { File.join(FINDERS_FIXTURES, 'wp_version', 'readme') }
let(:readme_url) { url + 'readme.html' }
describe '#aggressive' do
before { stub_request(:get, readme_url).to_return(body: File.read(File.join(fixtures, file))) }
after do
expect(target).to receive(:sub_dir).and_return(false)
expect(finder.aggressive).to eql @expected
end
context 'when no version' do
let(:file) { 'no_version.html' }
it 'returns nil' do
@expected = nil
end
end
context 'when invalid version number' do
let(:file) { 'invalid.html' }
it 'returns nil' do
@expected = nil
end
end
context 'when present and valid' do
let(:file) { '4.0.html' }
it 'returns the expected version' do
@expected = WPScan::WpVersion.new(
'4.0',
confidence: 90,
found_by: 'Readme (Aggressive Detection)',
interesting_entries: [
"#{readme_url}, Match: 'Version 4.0'"
]
)
end
end
end
end

View File

@@ -0,0 +1,10 @@
require 'spec_helper'
describe WPScan::Finders::WpVersion::RSSGenerator 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) { File.join(FINDERS_FIXTURES, 'wp_version', 'rss_generator') }
xit
end

View File

@@ -0,0 +1,10 @@
require 'spec_helper'
describe WPScan::Finders::WpVersion::UniqueFingerprinting 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) { File.join(FINDERS_FIXTURES, 'wp_version', 'unique_fingerprinting') }
xit
end

View File

@@ -0,0 +1,25 @@
require 'spec_helper'
# If this file is tested alone (rspec path-to-this-file), then there will be an error about
# constants not being intilialized. This is due to the Dynamic Finders.
describe WPScan::Finders::WpVersion::Base do
subject(:wp_version) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://ex.lo/' }
describe '#finders' do
let(:expected) { %w[RSSGenerator AtomGenerator RDFGenerator Readme UniqueFingerprinting] }
let(:expected_dynamic_finders) { WPScan::DB::DynamicFinders::Wordpress.versions_finders_configs.keys }
it 'contains the expected finders' do
finders = wp_version.finders.map { |f| f.class.to_s.demodulize }
expect(finders).to match_array expected + expected_dynamic_finders
expect(finders.first).to eql 'RSSGenerator'
expect(finders.last).to eql 'UniqueFingerprinting'
end
end
end

View File

@@ -0,0 +1,9 @@
require 'spec_helper'
describe WPScan::InterestingFinding do
it_behaves_like WPScan::References do
subject(:finding) { described_class.new('http://e.org/file.php', opts) }
let(:opts) { { references: references } }
let(:references) { {} }
end
end

View File

@@ -0,0 +1,10 @@
require 'spec_helper'
describe WPScan::Media do
subject(:media) { described_class.new(url) }
let(:url) { 'http://e.oeg/?attachment_id=2' }
describe '#new' do
its(:url) { should eql url }
end
end

View File

@@ -0,0 +1,192 @@
require 'spec_helper'
describe WPScan::Plugin do
subject(:plugin) { described_class.new(slug, blog, opts) }
let(:slug) { 'spec' }
let(:blog) { WPScan::Target.new('http://wp.lab/') }
let(:opts) { {} }
before { expect(blog).to receive(:content_dir).and_return('wp-content') }
describe '#new' do
its(:url) { should eql 'http://wp.lab/wp-content/plugins/spec/' }
end
describe '#version' do
after do
expect(WPScan::Finders::PluginVersion::Base).to receive(:find).with(plugin, @expected_opts)
plugin.version(version_opts)
end
let(:default_opts) { {} }
context 'when no :detection_mode' do
context 'when no :mode opt supplied' do
let(:version_opts) { { something: 'k' } }
it 'calls the finder with the correct parameters' do
@expected_opts = version_opts
end
end
context 'when :mode supplied' do
let(:version_opts) { { mode: :passive } }
it 'calls the finder with the correct parameters' do
@expected_opts = default_opts.merge(mode: :passive)
end
end
end
context 'when :detection_mode' do
let(:opts) { super().merge(mode: :passive) }
context 'when no :mode' do
let(:version_opts) { {} }
it 'calls the finder without mode' do
@expected_opts = version_opts
end
end
context 'when :mode' do
let(:version_opts) { { mode: :mixed } }
it 'calls the finder with the :mixed mode' do
@expected_opts = default_opts.merge(mode: :mixed)
end
end
end
end
describe '#latest_version, #last_updated, #popular' do
context 'when none' do
let(:slug) { 'vulnerable-not-popular' }
its(:latest_version) { should be_nil }
its(:last_updated) { should be_nil }
its(:popular?) { should be false }
end
context 'when values' do
let(:slug) { 'no-vulns-popular' }
its(:latest_version) { should eql WPScan::Version.new('2.0') }
its(:last_updated) { should eql '2015-05-16T00:00:00.000Z' }
its(:popular?) { should be true }
end
end
describe '#outdated?' do
context 'when last_version' do
let(:slug) { 'no-vulns-popular' }
context 'when no version' do
before { expect(plugin).to receive(:version).at_least(1).and_return(nil) }
its(:outdated?) { should eql false }
end
context 'when version' do
before { expect(plugin).to receive(:version).at_least(1).and_return(WPScan::Version.new(version_number)) }
context 'when version < last_version' do
let(:version_number) { '1.2' }
its(:outdated?) { should eql true }
end
context 'when version >= last_version' do
let(:version_number) { '3.0' }
its(:outdated?) { should eql false }
end
end
end
context 'when no last_version' do
let(:slug) { 'vulnerable-not-popular' }
context 'when no version' do
before { expect(plugin).to receive(:version).at_least(1).and_return(nil) }
its(:outdated?) { should eql false }
end
context 'when version' do
before { expect(plugin).to receive(:version).at_least(1).and_return(WPScan::Version.new('1.0')) }
its(:outdated?) { should eql false }
end
end
end
describe '#vulnerabilities' do
after do
expect(plugin.vulnerabilities).to eq @expected
expect(plugin.vulnerable?).to eql @expected.empty? ? false : true
end
context 'when plugin not in the DB' do
let(:slug) { 'not-in-db' }
it 'returns an empty array' do
@expected = []
end
end
context 'when in the DB' do
context 'when no vulnerabilities' do
let(:slug) { 'no-vulns-popular' }
it 'returns an empty array' do
@expected = []
end
end
context 'when vulnerabilities' do
let(:slug) { 'vulnerable-not-popular' }
let(:all_vulns) do
[
WPScan::Vulnerability.new(
'First Vuln',
{ wpvulndb: '1' },
'LFI',
'6.3.10'
),
WPScan::Vulnerability.new('No Fixed In', wpvulndb: '2')
]
end
context 'when no plugin version' do
before { expect(plugin).to receive(:version).at_least(1).and_return(false) }
it 'returns all the vulnerabilities' do
@expected = all_vulns
end
end
context 'when plugin version' do
before { expect(plugin).to receive(:version).at_least(1).and_return(WPScan::Version.new(number)) }
context 'when < to a fixed_in' do
let(:number) { '5.0' }
it 'returns it' do
@expected = all_vulns
end
end
context 'when >= to a fixed_in' do
let(:number) { '6.3.10' }
it 'does not return it ' do
@expected = [all_vulns.last]
end
end
end
end
end
end
end

View File

@@ -0,0 +1,165 @@
require 'spec_helper'
describe WPScan::Theme do
subject(:theme) { described_class.new(slug, blog, opts) }
let(:slug) { 'spec' }
let(:blog) { WPScan::Target.new('http://wp.lab/') }
let(:opts) { {} }
let(:fixtures) { File.join(FIXTURES, 'models', 'theme') }
before { expect(blog).to receive(:content_dir).at_least(1).and_return('wp-content') }
describe '#new' do
before do
stub_request(:get, /.*\.css\z/)
.to_return(body: File.read(File.join(fixtures, 'style.css')))
end
its(:url) { should eql 'http://wp.lab/wp-content/themes/spec/' }
its(:style_url) { should eql 'http://wp.lab/wp-content/themes/spec/style.css' }
its(:style_name) { should eql 'Twenty Fifteen' }
its(:style_uri) { should eql 'https://wordpress.org/themes/twentyfifteen' }
its(:author) { should eql 'the WordPress team' }
its(:author_uri) { should eql nil }
its(:template) { should eql nil }
its(:description) { should eql 'Our 2015 default theme is clean, blog-focused.' }
its(:license) { should eql 'GNU General Public License v2 or later' }
its(:license_uri) { should eql 'http://www.gnu.org/licenses/gpl-2.0.html' }
its(:tags) { should eql 'black, blue, gray, pink, purple, white, yellow.' }
its(:text_domain) { should eql 'twentyfifteen' }
context 'when opts[:style_url]' do
let(:opts) { super().merge(style_url: 'http://wp.lab/wp-content/themes/spec/custom.css') }
its(:style_url) { should eql opts[:style_url] }
end
end
describe '#version' do
after do
stub_request(:get, /.*\.css\z/)
.to_return(body: File.read(File.join(fixtures, 'style.css')))
expect(WPScan::Finders::ThemeVersion::Base).to receive(:find).with(theme, @expected_opts)
theme.version(version_opts)
end
let(:default_opts) { {} }
context 'when no :detection_mode' do
context 'when no :mode opt supplied' do
let(:version_opts) { { something: 'k' } }
it 'calls the finder with the correct parameters' do
@expected_opts = version_opts
end
end
context 'when :mode supplied' do
let(:version_opts) { { mode: :passive } }
it 'calls the finder with the correct parameters' do
@expected_opts = default_opts.merge(mode: :passive)
end
end
end
context 'when :detection_mode' do
let(:opts) { super().merge(mode: :passive) }
context 'when no :mode' do
let(:version_opts) { {} }
it 'calls the finder without mode' do
@expected_opts = version_opts
end
end
context 'when :mode' do
let(:version_opts) { { mode: :mixed } }
it 'calls the finder with the :mixed mode' do
@expected_opts = default_opts.merge(mode: :mixed)
end
end
end
end
describe '#vulnerabilities' do
xit
end
describe '#parent_theme' do
before do
stub_request(:get, blog.url('wp-content/themes/spec/style.css'))
.to_return(body: File.read(File.join(fixtures, main_theme)))
end
context 'when no template' do
let(:main_theme) { 'style.css' }
it 'returns nil' do
expect(theme.parent_theme).to eql nil
end
end
context 'when a template' do
let(:main_theme) { 'child_style.css' }
let(:parent_url) { blog.url('wp-content/themes/twentyfourteen/custom.css') }
before do
stub_request(:get, parent_url)
.to_return(body: File.read(File.join(fixtures, 'style.css')))
end
%w[child_style windows_line_endings].each do |fixture|
context "when #{fixture}" do
let(:main_theme) { "#{fixture}.css" }
it 'returns the expected theme' do
parent = theme.parent_theme
expect(parent).to eql described_class.new(
'twentyfourteen', blog,
style_url: parent_url,
confidence: 100,
found_by: 'Parent Themes (Passive Detection)'
)
expect(parent.style_url).to eql parent_url
end
end
end
end
end
describe '#parent_themes' do
xit
end
describe '#==' do
before { stub_request(:get, /.*\.css\z/) }
context 'when default style' do
it 'returns true when equal' do
expect(theme == described_class.new(slug, blog, opts)).to be true
end
it 'returns false when not equal' do
expect(theme == described_class.new(slug, blog, opts.merge(style_url: 'spec.css'))).to be false
end
end
context 'when custom style' do
let(:opts) { super().merge(style_url: 'spec.css') }
it 'returns true when equal' do
expect(theme == described_class.new(slug, blog, opts.merge(style_url: 'spec.css'))).to be true
end
it 'returns false when not equal' do
expect(theme == described_class.new(slug, blog, opts.merge(style_url: 'spec2.css'))).to be false
end
end
end
end

View File

@@ -0,0 +1,126 @@
require 'spec_helper'
describe WPScan::Timthumb do
subject(:timthumb) { described_class.new(url, opts) }
let(:url) { 'http://wp.lab/wp-content/timthumb.php' }
let(:fixtures) { File.join(FIXTURES, 'models', 'timthumb') }
let(:opts) { {} }
describe '#new' do
its(:url) { should eql url }
end
# The fact that the finders should only be called once is handled by the
# vulnerabilities, vulnerable? specs below
describe '#version' do
after do
expect(WPScan::Finders::TimthumbVersion::Base).to receive(:find).with(timthumb, @expected_opts)
timthumb.version(version_opts)
end
context 'when no :version_detection' do
context 'when no :mode opt supplied' do
let(:version_opts) { { something: 'k' } }
it 'calls the finder with the correct parameters' do
@expected_opts = version_opts
end
end
context 'when :mode supplied' do
let(:version_opts) { { mode: :passive } }
it 'calls the finder with the correct parameters' do
@expected_opts = { mode: :passive }
end
end
end
context 'when :version_detection' do
let(:opts) { super().merge(mode: :passive) }
context 'when no :mode' do
let(:version_opts) { {} }
it 'calls the finder with the :passive mode' do
@expected_opts = version_opts
end
end
context 'when :mode' do
let(:version_opts) { { mode: :mixed } }
it 'calls the finder with the :mixed mode' do
@expected_opts = { mode: :mixed }
end
end
end
end
describe '#webshot_enabled?' do
before do
stub_request(:get, /#{timthumb.url}\?src=.*&webshot=1/i)
.to_return(body: File.read(File.join(fixtures, fixture)))
end
context 'when enabled' do
let(:fixture) { '2.8.13_webshot_enabled.html' }
its(:webshot_enabled?) { should eql true }
end
context 'when disabled' do
let(:fixture) { '2.8.13_webshot_disabled.html' }
its(:webshot_enabled?) { should eql false }
end
end
describe '#vulnerabilities, #vulnerable?' do
before { expect(WPScan::Finders::TimthumbVersion::Base).to receive(:find).and_return(version) }
context 'when no version' do
let(:version) { false }
its(:vulnerabilities) { should eq([timthumb.rce_webshot_vuln, timthumb.rce_132_vuln]) }
it { should be_vulnerable }
end
context 'when version' do
let(:version) { WPScan::Version.new(version_number) }
context 'when version >= 2.8.14' do
let(:version_number) { '2.8.14' }
its(:vulnerabilities) { should eq([]) }
it { should_not be_vulnerable }
end
context 'when version < 1.33' do
let(:version_number) { '1.20' }
its(:vulnerabilities) { should eq([timthumb.rce_132_vuln]) }
it { should be_vulnerable }
end
context 'when version > 1.35 and < 2.8.13' do
let(:version_number) { '2.8.10' }
context 'when webshot enabled' do
before { expect(timthumb).to receive(:webshot_enabled?).and_return(true) }
its(:vulnerabilities) { should eq([timthumb.rce_webshot_vuln]) }
it { should be_vulnerable }
end
context 'when webshot disabled' do
before { expect(timthumb).to receive(:webshot_enabled?).and_return(false) }
its(:vulnerabilities) { should eq([]) }
it { should_not be_vulnerable }
end
end
end
end
end

View File

@@ -0,0 +1,130 @@
require 'spec_helper'
describe WPScan::WpItem do
subject(:wp_item) { described_class.new(slug, blog, opts) }
let(:slug) { 'test_item' }
let(:blog) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:opts) { {} }
its(:blog) { should eql blog }
describe '#new' do
context 'when no opts' do
its(:slug) { should eql slug }
its(:detection_opts) { should eql(mode: nil) }
its(:version_detection_opts) { should eql({}) }
end
context 'when :mode' do
let(:opts) { super().merge(mode: :passive, version_detection: { mode: :aggressive }) }
its(:detection_opts) { should eql(mode: :passive) }
its(:version_detection_opts) { should eql(mode: :aggressive) }
end
context 'when the slug contains encoded chars' do
let(:slug) { 'theme%212%23a' }
its(:slug) { should eql 'theme!2#a' }
end
end
describe '#url' do
context 'when no opts[:url]' do
its(:url) { should eql nil }
end
context 'when opts[:url]' do
let(:opts) { super().merge(url: item_url) }
let(:item_url) { "#{url}item/" }
context 'when path given' do
it 'appends it' do
expect(wp_item.url('path')).to eql "#{item_url}path"
end
end
it 'encodes the path' do
expect(wp_item.url('#t#')).to eql "#{item_url}%23t%23"
expect(wp_item.url('t .txt')).to eql "#{item_url}t%20.txt"
end
end
end
describe '#==' do
context 'when the same slug' do
it 'returns true' do
other = described_class.new(slug, blog)
expect(wp_item == other).to be true
end
end
context 'when another object' do
it 'returns false' do
expect(wp_item == 'string').to be false
end
end
context 'when different slugs' do
it 'returns false' do
other = described_class.new('another', blog)
expect(wp_item == other).to be false
end
end
end
describe '#latest_version' do
# Handled in plugin_spec / theme_spec
end
describe '#popular?' do
# Handled in plugin_spec / theme_spec
end
describe '#last_updated' do
# Handled in plugin_spec / theme_spec
end
describe '#outdated?' do
# Handled in plugin_spec / theme_spec
end
describe '#to_s' do
its(:to_s) { should eql slug }
end
describe '#classify' do
its(:classify) { should eql :TestItem }
context 'when it starts with a digit' do
let(:slug) { '2test' }
its(:classify) { should eql :D_2test }
context 'when a digit and -' do
let(:slug) { '23-test' }
its(:classify) { should eql :D_23Test }
end
end
end
describe '#readme_url' do
xit
end
describe '#changelog_url' do
xit
end
describe '#directory_listing?' do
xit
end
describe '#error_log?' do
xit
end
end

View File

@@ -0,0 +1,89 @@
require 'spec_helper'
describe WPScan::WpVersion do
describe '#new' do
context 'when invalid number' do
it 'raises an error' do
expect { described_class.new('aa') }.to raise_error WPScan::InvalidWordPressVersion
end
end
context 'when valid number' do
it 'create the instance' do
version = described_class.new(4.0)
expect(version).to be_a described_class
expect(version.number).to eql '4.0'
end
end
end
describe '.all' do
it 'returns the correct values' do
expect(described_class.all).to eql %w[4.4 4.0 3.9.1 3.8.2 3.8.1 3.8]
end
end
describe '.valid?' do
after { expect(described_class.valid?(@number)).to eq @expected }
it 'returns false' do
@number = 'aaa'
@expected = false
end
it 'returns true' do
@number = '4.0'
@expected = true
end
end
describe '#vulnerabilities' do
subject(:version) { described_class.new(number) }
context 'when no vulns' do
let(:number) { '4.4' }
its(:vulnerabilities) { should eql([]) }
end
context 'when vulnerable' do
after do
expect(version.vulnerabilities).to eq @expected
expect(version).to be_vulnerable
end
context 'when a signle vuln' do
let(:number) { '3.8' }
it 'returns the expected result' do
@expected = [WPScan::Vulnerability.new(
'WP 3.8 - Vuln 1',
{ url: %w[url-4], osvdb: %w[11], wpvulndb: '3' },
'AUTHBYPASS'
)]
end
end
context 'when multiple vulns' do
let(:number) { '3.8.1' }
it 'returns the expected results' do
@expected = [
WPScan::Vulnerability.new(
'WP 3.8.1 - Vuln 1',
{ wpvulndb: '1' },
'SQLI'
),
WPScan::Vulnerability.new(
'WP 3.8.1 - Vuln 2',
{ url: %w[url-2 url-3], osvdb: %w[10], cve: %w[2014-0166], wpvulndb: '2' },
nil,
'3.8.2'
)
]
end
end
end
end
end

View File

@@ -0,0 +1,9 @@
require 'spec_helper'
describe WPScan::XMLRPC do
subject(:xml_rpc) { described_class.new('http//e.org/xmlrpc.php') }
describe '#references' do
its(:references) { should_not be_empty }
end
end

37
spec/app/views_spec.rb Normal file
View File

@@ -0,0 +1,37 @@
require 'spec_helper'
describe 'App::Views' do
let(:target_url) { 'http://ex.lo/' }
let(:target) { WPScan::Target.new(target_url) }
let(:fixtures) { File.join(SPECS, 'output') }
# CliNoColour is used to test the CLI output to avoid the painful colours
# in the expected output.
%i[JSON CliNoColour].each do |formatter|
context "when #{formatter}" do
it_behaves_like 'App::Views::WpVersion'
it_behaves_like 'App::Views::MainTheme'
it_behaves_like 'App::Views::Enumeration'
let(:parsed_options) { { url: target_url, format: formatter.to_s.underscore.dasherize } }
before do
controller.class.parsed_options = parsed_options
# Resets the formatter to ensure the correct one is loaded
controller.class.class_variable_set(:@@formatter, nil)
end
after do
view_filename = defined?(expected_view) ? expected_view : view
view_filename = "#{view_filename}.#{formatter.to_s.underscore.downcase}"
controller_dir = controller.class.to_s.demodulize.underscore.downcase
expected_output = File.read(File.join(fixtures, controller_dir, view_filename))
expect($stdout).to receive(:puts).with(expected_output)
controller.output(view, @tpl_vars)
controller.formatter.beautify # Mandatory to be able to test formatter such as JSON
end
end
end
end

4
spec/cache/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

3
spec/fixtures/db/config_backups.txt vendored Normal file
View File

@@ -0,0 +1,3 @@
#wp-config.php#
wp-config.bak
wp-config.txt

6
spec/fixtures/db/db_exports.txt vendored Normal file
View File

@@ -0,0 +1,6 @@
{domain_name}.sql
wordpress.sql
backup/{domain_name}.zip
backup/mysql.sql
backups/{domain_name}.sql.gz
backups/db_backup.sql

25726
spec/fixtures/db/dynamic_finders.yml vendored Normal file

File diff suppressed because it is too large Load Diff

25
spec/fixtures/db/plugins.json vendored Normal file
View File

@@ -0,0 +1,25 @@
{
"no-vulns-popular": {
"vulnerabilities": [],
"popular": true,
"latest_version": "2.0",
"last_updated": "2015-05-16T00:00:00.000Z"
},
"vulnerable-not-popular": {
"latest_version": null,
"last_updated": null,
"popular": false,
"vulnerabilities" : [
{
"title" : "First Vuln",
"fixed_in" : "6.3.10",
"id" : 1,
"vuln_type": "LFI"
},
{
"title": "No Fixed In",
"id": 2
}
]
}
}

48
spec/fixtures/db/themes.json vendored Normal file
View File

@@ -0,0 +1,48 @@
{
"no-vulns-popular": {
"popular": true,
"latest_version": "2.0",
"last_updated": "2015-05-16T00:00:00.000Z",
"vulnerabilities": []
},
"dignitas-themes": {
"popular": true,
"latest_version": null,
"last_updated": null,
"vulnerabilities" : [
{
"created_at" : "2015-03-05T19:25:59.000Z",
"updated_at" : "2015-03-05T19:37:47.000Z",
"references": {
"url" : [
"http://research.evex.pw/?vuln=6",
"http://packetstormsecurity.com/files/130652/"
]
},
"title" : "Dignitas 1.1.9 - Privilage Escalation",
"id" : 7825,
"vuln_type" : "AUTHBYPASS"
}
]
},
"yaaburnee-themes": {
"popular": false,
"latest_version": null,
"last_updated": null,
"vulnerabilities" : [
{
"created_at" : "2015-03-05T19:25:44.000Z",
"updated_at" : "2015-03-05T19:41:14.000Z",
"references": {
"url" : [
"http://research.evex.pw/?vuln=6",
"http://packetstormsecurity.com/files/130652/"
]
},
"title" : "Ya'aburnee 1.0.7 - Privilage Escalation",
"id" : 7824,
"vuln_type" : "AUTHBYPASS"
}
]
}
}

3
spec/fixtures/db/user-agents.txt vendored Normal file
View File

@@ -0,0 +1,3 @@
# Coments should be ignored
UA-1
UA-2

42
spec/fixtures/db/wordpresses.json vendored Normal file
View File

@@ -0,0 +1,42 @@
{
"3.8.1": {
"vulnerabilities" : [
{
"created_at" : "2014-08-01T10:58:19.000Z",
"updated_at" : "2014-09-16T13:52:17.000Z",
"title" : "WP 3.8.1 - Vuln 1",
"id" : 1,
"vuln_type" : "SQLI",
"published_date" : null,
"fixed_in" : null
},
{
"references" : {
"cve" : ["2014-0166"],
"osvdb" : ["10"],
"url" : ["url-2","url-3"]
},
"fixed_in" : "3.8.2",
"created_at" : "2014-08-01T10:58:19.000Z",
"updated_at" : "2014-09-16T13:53:11.000Z",
"id" : 2,
"title" : "WP 3.8.1 - Vuln 2"
}
]
},
"3.8": {
"vulnerabilities" : [
{
"references": {
"url" : ["url-4"],
"osvdb" : ["11"]
},
"created_at" : "2014-08-01T10:58:19.000Z",
"updated_at" : "2014-09-16T15:45:26.000Z",
"title" : "WP 3.8 - Vuln 1",
"id" : 3,
"vuln_type" : "AUTHBYPASS"
}
]
}
}

9
spec/fixtures/db/wp_fingerprints.json vendored Normal file
View File

@@ -0,0 +1,9 @@
{
"path-1": {
"hash-1": ["4.0", "3.8"],
"hash-2": ["4.4"]
},
"path-2": {
"hash-3": ["3.8.1", "3.8.2", "3.9.1"]
}
}

32374
spec/fixtures/dynamic_finders/expected.yml vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,156 @@
<div class="row" id="kb-amz-version">
<div class="col-sm-12">
<h4>2.1.1</h4>
<ul style="list-style-type: disc;">
<li>
Security fix, thanks to Ricardo
</li>
</ul>
<h4>2.0.2</h4>
<h4>2.1.0</h4>
<ul style="list-style-type: disc;">
<li>
Maintenance release
</li>
</ul>
<h4>2.0.2</h4>
<ul style="list-style-type: disc;">
<li>
Css fixes
</li>
</ul>
<h4>2.0.1</h4>
<ul style="list-style-type: disc;">
<li>
Import optimization
</li>
</ul>
<h4>2.0.0</h4>
<ul style="list-style-type: disc;">
<li>
Product Variants and Product Versions are here!<br/>
Examples added.<br/>
2kb Amazon Network for products fast sync<br/>
</li>
</ul>
<h4>1.2.0</h4>
<ul style="list-style-type: disc;">
<li>
Usability changes:<br/>
Delay between requests option added to reduce Amazon API warnings<br/>
Last cron run label on dashboard added<br/>
<br/><br/>
Programming changes:<br/>
Many hooks added<br/>
Default no item image accepts attributes<br/>
Similar Products warning fixed
</li>
</ul>
<h4>1.1.8</h4>
<ul style="list-style-type: disc;">
<li>Bug fix - Mobile layout for listing.</li>
</ul>
<h4>1.1.6, 1.1.7</h4>
<ul style="list-style-type: disc;">
<li>Bugs fixing</li>
</ul>
<h4>1.1.5</h4>
<ul style="list-style-type: disc;">
<li>New Option - delete product(post) on quantity = 0</li>
<li>New Action - Delete All Products That Have post_status = pending And KbAmzOfferSummary.TotalNew <= 0'</li>
<li>Added Default Product Image in the listings.</li>
<li>Added Popover on checkout button: if product is not sellable with the affiliate program, direct product link will be provided.</li>
<li>Added Plugin Experience Program (Optional)</li>
</ul>
<h4>1.1.4</h4>
<ul style="list-style-type: disc;">
<li>Fixed bug when listing products with no quantity left. kb_amz_list_products now lists only products (posts) with post_status = publish be default, which can be changed.</li>
</ul>
<h4>1.1.3</h4>
<ul style="list-style-type: disc;">
<li>Fixed bug for creating multiple checkout pages.</li>
<li>Fixed bug with listing price option. Now showing listing price and discounted price.</li>
<li>Admin widgets css update.</li>
<li><a href="?page=kbAmz&kbAction=info">Documentation</a> added.</li>
</ul>
<h4>1.1.2</h4>
<ul style="list-style-type: disc;">
<li>Listing price add when 'Show the original price of the product.' options is enabled.</li>
<li>Disabled store widgets filters on product post page.</li>
</ul>
<h4>1.1.1</h4>
<ul style="list-style-type: disc;">
<li>Amazon Iframe Reviews added. You can test and provide feedback to complete this functionality.</li>
<li>Fixed bug when using product images directly from Amazon and not displaying outside the product page. Thanks to alamandeh for reporting it.</li>
<li>Fixed bug when pagination is disabled for one listing on multiple product listings.</li>
<li>Fixed admin import search form same parameters after submit bug.</li>
<li>Fixed bug for custom themes when having thumbnail size (class) on the listing page.</li>
</ul>
<h4>1.1.0</h4>
<ul style="list-style-type: disc;">
<li>Import timeout increased from default 30sec. to 90 sec.</li>
<li>Added pagination on the <a href="?page=kbAmz&kbAction=importBySearch">search page</a>.</li>
</ul>
<h4>1.0.9</h4>
<ul style="list-style-type: disc;">
<li>kb_amz_list_products shortcode accept short code parameters with php code. Ex. [kb_amz_list_products attribute_value="<? date('Y-m-d', time() - 3600); ?>"].</li>
</ul>
<h4>1.0.8</h4>
<ul style="list-style-type: disc;">
<li>India is added to the import categories list thanks to Mr.Parmar.</li>
</ul>
<h4>1.0.7</h4>
<ul style="list-style-type: disc;">
<li>Short Codes bug fixed - all shortcodes use '_' instead of '-'.</li>
<li>Added option for featured content in [kb_amz_list_products featured="Yes" featured_content_length="150"]. Content is loaded from the_excerpt or the product description.</li>
<li>Bug fixed when using [kb_amz_list_products] in product shortcode content. (product is excluded from the query).</li>
</ul>
<h4>1.0.6</h4>
<ul style="list-style-type: disc;">
<li>Category accept functions in [kb_amz_list_products] and items_per_row added.</li>
<li>Dashboard published products message added.</li>
</ul>
<h4>1.0.5</h4>
<ul style="list-style-type: disc;">
<li>Category fix in [kb_amz_list_products]</li>
</ul>
<h4>1.0.4</h4>
<ul style="list-style-type: disc;">
<li>Some bugs got fixed. Thank you for your support.</li>
</ul>
<h4>1.0.3</h4>
<ul style="list-style-type: disc;">
<li>New Option = Download Images. This option allows you to store only the link of product`s images. This will save you space and time to import.</li>
<li>Maintenance fixes.</li>
<li>lib/KbAmazonImage</li>
<li>lib/KbAmazonImages</li>
</ul>
</div>
<div class="col-sm-12">
<h4>1.0.2</h4>
<ul style="list-style-type: disc;">
<li>Dashboard info update - products counts, products to download, products to sync, time to sync.</li>
</ul>
</div>
<div class="col-sm-12">
<h4>1.0.1</h4>
<ul style="list-style-type: disc;">
<li>Front scripts are no longer loaded in admin.</li>
<li>Products -> Short Codes, restore default content shortcodes. Option to replace content shortcode with the product content insuring better SEO and editability.</li>
</ul>
</div>
<div class="col-sm-12">
<h4>1.0.0</h4>
<ul style="list-style-type: disc;">
<li>First public version of the plugin</li>
<li>Import products by amazon - ASIN, Search, Url Import (beta)</li>
<li>Product attributes management and attributes restriction</li>
<li>All products short codes management</li>
<li>Cron job for similar products import and price update</li>
<li><a href="?page=kbAmz&kbAction=productsShortCodes">Shortcodes</a></li>
<li>Widgets for products filtering - Slider and Attributes filter</li>
<li>Automatic products growing. Using similar products, this plugin will download products without you need to do anything.</li>
</ul>
</div>
</div>

View File

@@ -0,0 +1,13 @@
{
"name": "algori-360-image-cgb-guten-block",
"version": "1.0.0",
"private": true,
"scripts": {
"start": "cgb-scripts start",
"build": "cgb-scripts build",
"eject": "cgb-scripts eject"
},
"dependencies": {
"cgb-scripts": "1.9.8"
}
}

View File

@@ -0,0 +1,13 @@
{
"name": "algori-360-video-cgb-guten-block",
"version": "1.0.0",
"private": true,
"scripts": {
"start": "cgb-scripts start",
"build": "cgb-scripts build",
"eject": "cgb-scripts eject"
},
"dependencies": {
"cgb-scripts": "1.9.8"
}
}

View File

@@ -0,0 +1,45 @@
{
"name": "404-solution",
"version": "2.5.4",
"description": "The 404 Solution Plugin.",
"main": "Gulpfile.js",
"dependencies": {
"autoprefixer": "^6.3.1",
"css-mqpacker": "^4.0.0",
"del": "^2.2.0",
"glob": "^6.0.4",
"gulp": "^3.9.1",
"gulp-cheerio": "^0.6.2",
"gulp-concat": "^2.6.0",
"gulp-cssnano": "^2.1.0",
"gulp-imagemin": "^2.4.0",
"gulp-notify": "^2.2.0",
"gulp-plumber": "^1.1.0",
"gulp-postcss": "^6.1.0",
"gulp-rename": "^1.2.2",
"gulp-sass": "^2.2.0",
"gulp-sass-lint": "^1.1.1",
"gulp-sort": "^1.1.1",
"gulp-sourcemaps": "^1.6.0",
"gulp-uglify": "^1.5.2",
"gulp-util": "^3.0.7",
"gulp-wp-pot": "^1.1.1"
},
"devDependencies": {},
"scripts": {
"test": "echo \"No test specified\""
},
"repository": {
"type": "git",
"url": "git+thtps://github.com/aaron13100/404solution"
},
"keywords": [
"plugin"
],
"author": "Aaron J",
"license": "GPL-3.0",
"bugs": {
"url": "https://github.com/aaron13100/404solution/issues"
},
"homepage": "https://github.com/aaron13100/404solution"
}

View File

@@ -0,0 +1,8 @@
msgid ""
msgstr ""
"Project-Id-Version: LayerSlider WP v4.5.5\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: 2013-06-26 22:23:20+0000\n"
"Last-Translator: \n"
"Language-Team: \n"

View File

@@ -0,0 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: LayerSlider WP 5.2.0\n"
"POT-Creation-Date: 2014-08-15 00:06+0100\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"

View File

@@ -0,0 +1,28 @@
{
"name": "abovethefold",
"version": "2.9.2",
"description": "Above The Fold Optimization",
"author": {
"name": "info@pagespeed.pro",
"email": "info@pagespeed.pro",
"web": "pagespeed.pro"
},
"engines": {
"node": "~0.10"
},
"dependencies": {
"jquery": "^3.1.1",
"jsoneditor": "5.9.5",
"lazyloadxt": "1.1.0",
"webfontloader": "^1.6.28"
},
"devDependencies": {
"grunt": "latest",
"grunt-closure-compiler": "latest",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-cssmin": "latest",
"grunt-contrib-uglify": "latest",
"matchdep": "latest",
"merge": "^1.2.0"
}
}

View File

@@ -0,0 +1,808 @@
# Copyright (C) 2018 Academic Blogger's Toolkit 4.13.0
# This file is distributed under the same license as the Academic Blogger's Toolkit 4.13.0 package.
msgid ""
msgstr ""
"Project-Id-Version: Academic Blogger's Toolkit 4.13.0\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language-Team: Derek P Sifford <dereksifford@gmail.com>\n"
"Last-Translator: Derek P Sifford <dereksifford@gmail.com>\n"
"Report-Msgid-Bugs-To: https://github.com/dsifford/academic-bloggers-toolkit/issues\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: academic-bloggers-toolkit.php:100
msgid "Plugin Settings"
msgstr ""
#: academic-bloggers-toolkit.php:117
msgid "Donate"
msgstr ""
#: php/class-backend.php:72
msgid "Notice"
msgstr ""
#: php/class-backend.php:73
msgid "Rich editing must be enabled to use the Academic Blogger's Toolkit plugin"
msgstr ""
#: php/class-backend.php:131
msgid "Reference List"
msgstr ""
#: php/class-options.php:71, php/class-options.php:138
msgid "Academic Blogger's Toolkit Options"
msgstr ""
#: php/class-options.php:72
msgid "Academic Blogger's Toolkit"
msgstr ""
#: php/class-options.php:84
msgid "You do not have sufficient permissions to access this page."
msgstr ""
#: php/fieldmaps.php:16, php/i18n.php:49
msgid "Bill"
msgstr ""
#: php/fieldmaps.php:20, php/fieldmaps.php:74, php/fieldmaps.php:258, php/fieldmaps.php:352, php/fieldmaps.php:398, php/fieldmaps.php:488, php/fieldmaps.php:554, php/fieldmaps.php:591, php/fieldmaps.php:653, php/fieldmaps.php:717, php/fieldmaps.php:775, php/fieldmaps.php:826, php/fieldmaps.php:894, php/fieldmaps.php:941
msgid "Title"
msgstr ""
#: php/fieldmaps.php:25
msgid "Bill Number"
msgstr ""
#: php/fieldmaps.php:29
msgid "Code Pages"
msgstr ""
#: php/fieldmaps.php:31, php/fieldmaps.php:209, php/fieldmaps.php:447, php/fieldmaps.php:618, php/fieldmaps.php:672, php/fieldmaps.php:734, php/fieldmaps.php:792, php/fieldmaps.php:853, php/fieldmaps.php:912
msgid "Number or Range of Numbers (100-200)"
msgstr ""
#: php/fieldmaps.php:35
msgid "Code Volume"
msgstr ""
#: php/fieldmaps.php:37, php/fieldmaps.php:85, php/fieldmaps.php:91, php/fieldmaps.php:97, php/fieldmaps.php:103, php/fieldmaps.php:165, php/fieldmaps.php:175, php/fieldmaps.php:181, php/fieldmaps.php:187, php/fieldmaps.php:193, php/fieldmaps.php:269, php/fieldmaps.php:414, php/fieldmaps.php:420, php/fieldmaps.php:426, php/fieldmaps.php:432, php/fieldmaps.php:607, php/fieldmaps.php:665, php/fieldmaps.php:833, php/fieldmaps.php:901, php/fieldmaps.php:948
msgid "One or more numbers, no spaces"
msgstr ""
#: php/fieldmaps.php:41, php/fieldmaps.php:727, php/fieldmaps.php:905
msgid "Section"
msgstr ""
#: php/fieldmaps.php:45
msgid "Legislative Body"
msgstr ""
#: php/fieldmaps.php:49, php/fieldmaps.php:116, php/fieldmaps.php:217, php/fieldmaps.php:282, php/fieldmaps.php:327, php/fieldmaps.php:367, php/fieldmaps.php:451, php/fieldmaps.php:509, php/fieldmaps.php:572, php/fieldmaps.php:630, php/fieldmaps.php:688, php/fieldmaps.php:746, php/fieldmaps.php:801, php/fieldmaps.php:861, php/fieldmaps.php:916, php/fieldmaps.php:961, php/fieldmaps.php:1001
msgid "Date"
msgstr ""
#: php/fieldmaps.php:52, php/fieldmaps.php:58, php/fieldmaps.php:119, php/fieldmaps.php:125, php/fieldmaps.php:220, php/fieldmaps.php:226, php/fieldmaps.php:285, php/fieldmaps.php:291, php/fieldmaps.php:330, php/fieldmaps.php:336, php/fieldmaps.php:370, php/fieldmaps.php:454, php/fieldmaps.php:460, php/fieldmaps.php:512, php/fieldmaps.php:518, php/fieldmaps.php:575, php/fieldmaps.php:633, php/fieldmaps.php:691, php/fieldmaps.php:697, php/fieldmaps.php:749, php/fieldmaps.php:755, php/fieldmaps.php:804, php/fieldmaps.php:810, php/fieldmaps.php:864, php/fieldmaps.php:870, php/fieldmaps.php:919, php/fieldmaps.php:925, php/fieldmaps.php:964, php/fieldmaps.php:970, php/fieldmaps.php:1003, php/fieldmaps.php:1009
msgid "YYYY/MM/DD or YYYY/MM or YYYY"
msgstr ""
#: php/fieldmaps.php:56, php/fieldmaps.php:123, php/fieldmaps.php:224, php/fieldmaps.php:289, php/fieldmaps.php:334, php/fieldmaps.php:458, php/fieldmaps.php:516, php/fieldmaps.php:695, php/fieldmaps.php:753, php/fieldmaps.php:808, php/fieldmaps.php:868, php/fieldmaps.php:923, php/fieldmaps.php:968, php/fieldmaps.php:1007
msgid "Date Accessed"
msgstr ""
#: php/fieldmaps.php:64
msgid "Sponsor"
msgstr ""
#: php/fieldmaps.php:70, php/i18n.php:53
msgid "Book"
msgstr ""
#: php/fieldmaps.php:79
msgid "Series Title"
msgstr ""
#: php/fieldmaps.php:83, php/fieldmaps.php:173, php/fieldmaps.php:412
msgid "Series Number"
msgstr ""
#: php/fieldmaps.php:89, php/fieldmaps.php:946
msgid "# of Pages"
msgstr ""
#: php/fieldmaps.php:95, php/fieldmaps.php:179, php/fieldmaps.php:418, php/fieldmaps.php:605, php/fieldmaps.php:663
msgid "Volume"
msgstr ""
#: php/fieldmaps.php:101, php/fieldmaps.php:191, php/fieldmaps.php:430
msgid "Edition"
msgstr ""
#: php/fieldmaps.php:107, php/fieldmaps.php:197, php/fieldmaps.php:436, php/fieldmaps.php:845
msgid "Publisher"
msgstr ""
#: php/fieldmaps.php:112, php/fieldmaps.php:202, php/fieldmaps.php:440
msgid "Publisher Location"
msgstr ""
#: php/fieldmaps.php:131, php/fieldmaps.php:342, php/fieldmaps.php:376, php/fieldmaps.php:466, php/fieldmaps.php:639, php/fieldmaps.php:703, php/fieldmaps.php:761, php/fieldmaps.php:876, php/fieldmaps.php:931, php/fieldmaps.php:976, php/fieldmaps.php:1015
msgid "Author"
msgstr ""
#: php/fieldmaps.php:135, php/fieldmaps.php:240, php/fieldmaps.php:380, php/fieldmaps.php:470, php/fieldmaps.php:643, php/fieldmaps.php:707, php/fieldmaps.php:765
msgid "Editor"
msgstr ""
#: php/fieldmaps.php:139, php/fieldmaps.php:244, php/fieldmaps.php:384, php/fieldmaps.php:474, php/fieldmaps.php:880
msgid "Series Editor"
msgstr ""
#: php/fieldmaps.php:143, php/fieldmaps.php:248, php/fieldmaps.php:388, php/fieldmaps.php:478, php/fieldmaps.php:884
msgid "Translator"
msgstr ""
#: php/fieldmaps.php:149, php/i18n.php:57
msgid "Book Section"
msgstr ""
#: php/fieldmaps.php:153
msgid "Section Title"
msgstr ""
#: php/fieldmaps.php:158
msgid "Book Title"
msgstr ""
#: php/fieldmaps.php:163
msgid "Chapter Number"
msgstr ""
#: php/fieldmaps.php:169, php/fieldmaps.php:408, php/fieldmaps.php:837
msgid "Series"
msgstr ""
#: php/fieldmaps.php:185, php/fieldmaps.php:424
msgid "# of Volumes"
msgstr ""
#: php/fieldmaps.php:206, php/fieldmaps.php:444, php/fieldmaps.php:616, php/fieldmaps.php:669, php/fieldmaps.php:731, php/fieldmaps.php:790, php/fieldmaps.php:850, php/fieldmaps.php:909
msgid "Pages"
msgstr ""
#: php/fieldmaps.php:213, php/i18n.php:205
msgid "ISBN"
msgstr ""
#: php/fieldmaps.php:232
msgid "Section Author"
msgstr ""
#: php/fieldmaps.php:236
msgid "Book Author"
msgstr ""
#: php/fieldmaps.php:254
msgid "Broadcast"
msgstr ""
#: php/fieldmaps.php:262
msgid "Program Title"
msgstr ""
#: php/fieldmaps.php:267
msgid "Episode Number"
msgstr ""
#: php/fieldmaps.php:273, php/fieldmaps.php:505
msgid "Format"
msgstr ""
#: php/fieldmaps.php:277
msgid "Network"
msgstr ""
#: php/fieldmaps.php:297, php/fieldmaps.php:532
msgid "Producer"
msgstr ""
#: php/fieldmaps.php:301, php/fieldmaps.php:528
msgid "Director"
msgstr ""
#: php/fieldmaps.php:307, php/i18n.php:61
msgid "Case"
msgstr ""
#: php/fieldmaps.php:311
msgid "Case Name"
msgstr ""
#: php/fieldmaps.php:316
msgid "Court"
msgstr ""
#: php/fieldmaps.php:321
msgid "Docket Number"
msgstr ""
#: php/fieldmaps.php:323
msgid "Any combination of non-whitespace characters"
msgstr ""
#: php/fieldmaps.php:348, php/i18n.php:65
msgid "Conference Proceeding"
msgstr ""
#: php/fieldmaps.php:357
msgid "Conference Name"
msgstr ""
#: php/fieldmaps.php:362
msgid "Conference Location"
msgstr ""
#: php/fieldmaps.php:394, php/i18n.php:69
msgid "Encyclopedia Entry"
msgstr ""
#: php/fieldmaps.php:403
msgid "Encyclopedia Title"
msgstr ""
#: php/fieldmaps.php:484, php/i18n.php:73
msgid "Film"
msgstr ""
#: php/fieldmaps.php:493
msgid "Distributor"
msgstr ""
#: php/fieldmaps.php:497
msgid "Genre"
msgstr ""
#: php/fieldmaps.php:501, php/fieldmaps.php:568
msgid "Language"
msgstr ""
#: php/fieldmaps.php:524
msgid "Scriptwriter"
msgstr ""
#: php/fieldmaps.php:538, php/i18n.php:77
msgid "Generic (Note)"
msgstr ""
#: php/fieldmaps.php:542
msgid "Text"
msgstr ""
#: php/fieldmaps.php:550
msgid "Presentation"
msgstr ""
#: php/fieldmaps.php:559
msgid "Event Name"
msgstr ""
#: php/fieldmaps.php:564
msgid "Event Location"
msgstr ""
#: php/fieldmaps.php:581
msgid "Presenter"
msgstr ""
#: php/fieldmaps.php:587, php/i18n.php:85
msgid "Journal Article"
msgstr ""
#: php/fieldmaps.php:596
msgid "Journal"
msgstr ""
#: php/fieldmaps.php:601
msgid "Journal Abbreviation"
msgstr ""
#: php/fieldmaps.php:611, php/fieldmaps.php:676, php/fieldmaps.php:738
msgid "Issue"
msgstr ""
#: php/fieldmaps.php:622
msgid "DOI"
msgstr ""
#: php/fieldmaps.php:626, php/fieldmaps.php:684, php/fieldmaps.php:742, php/fieldmaps.php:857, php/fieldmaps.php:996, php/i18n.php:207
msgid "URL"
msgstr ""
#: php/fieldmaps.php:649, php/i18n.php:89
msgid "Magazine Article"
msgstr ""
#: php/fieldmaps.php:658
msgid "Magazine"
msgstr ""
#: php/fieldmaps.php:680
msgid "ISSN"
msgstr ""
#: php/fieldmaps.php:713, php/i18n.php:93
msgid "Newspaper Article"
msgstr ""
#: php/fieldmaps.php:722, php/fieldmaps.php:841
msgid "Publication"
msgstr ""
#: php/fieldmaps.php:771, php/i18n.php:97
msgid "Patent"
msgstr ""
#: php/fieldmaps.php:780, php/fieldmaps.php:831
msgid "Number"
msgstr ""
#: php/fieldmaps.php:785
msgid "Jurisdiction"
msgstr ""
#: php/fieldmaps.php:796
msgid "Issuer"
msgstr ""
#: php/fieldmaps.php:816
msgid "Inventor"
msgstr ""
#: php/fieldmaps.php:822, php/i18n.php:101
msgid "Report"
msgstr ""
#: php/fieldmaps.php:890, php/i18n.php:105
msgid "Statute"
msgstr ""
#: php/fieldmaps.php:899
msgid "Statute Number"
msgstr ""
#: php/fieldmaps.php:937, php/i18n.php:109
msgid "Thesis"
msgstr ""
#: php/fieldmaps.php:952
msgid "University"
msgstr ""
#: php/fieldmaps.php:957
msgid "Location"
msgstr ""
#: php/fieldmaps.php:982, php/i18n.php:117
msgid "Web Page"
msgstr ""
#: php/fieldmaps.php:986
msgid "Content Title"
msgstr ""
#: php/fieldmaps.php:991
msgid "Website Title"
msgstr ""
#: php/i18n.php:81
msgid "Hearing"
msgstr ""
#: php/i18n.php:113
msgid "Television Broadcast"
msgstr ""
#: php/i18n.php:125, php/views/options-page.php:237
msgid "Footnotes"
msgstr ""
#: php/i18n.php:126
msgid "Source"
msgstr ""
#: php/i18n.php:132
msgid "Your WordPress PHP installation is incomplete. You must have the following PHP extensions enabled to use this feature: %s"
msgstr ""
#: php/i18n.php:135
msgid "Request not valid"
msgstr ""
#: php/i18n.php:136
msgid "Site denied request"
msgstr ""
#: php/i18n.php:137
msgid "Invalid file extension. Extension must be .ris, .bib, or .bibtex"
msgstr ""
#: php/i18n.php:138
msgid "The selected file could not be processed"
msgstr ""
#: php/i18n.php:140
msgid "No identifiers could be found for your request"
msgstr ""
#: php/i18n.php:141
msgid "The following identifiers could not be found"
msgstr ""
#: php/i18n.php:143
msgid "Network Error"
msgstr ""
#: php/i18n.php:144
msgid "Your search returned 0 results"
msgstr ""
#: php/i18n.php:145
msgid "Error"
msgstr ""
#: php/i18n.php:146
msgid "The following references were unable to be processed"
msgstr ""
#: php/i18n.php:147
msgid "Request returned a non-200 status code"
msgstr ""
#: php/i18n.php:149
msgid "Warning"
msgstr ""
#: php/i18n.php:150
msgid "Reason"
msgstr ""
#: php/i18n.php:151
msgid "No bibliography format exists for your citation type"
msgstr ""
#: php/i18n.php:154
msgid "An unexpected error occurred"
msgstr ""
#: php/i18n.php:157
msgid "Please report this error, including the steps taken to trigger it, here: %s"
msgstr ""
#: php/i18n.php:161
msgid "TinyMCE editor doesn't appear to be available in this scope"
msgstr ""
#: php/i18n.php:162
msgid "Invalid predefined style type"
msgstr ""
#: php/i18n.php:168
msgid "Custom Style"
msgstr ""
#: php/i18n.php:169
msgid "Pre-defined Styles"
msgstr ""
#: php/i18n.php:171
msgid "Toggle menu"
msgstr ""
#: php/i18n.php:173
msgid "Delete all references"
msgstr ""
#: php/i18n.php:174
msgid "Usage instructions"
msgstr ""
#: php/i18n.php:175
msgid "Import references"
msgstr ""
#: php/i18n.php:176
msgid "Refresh reference list"
msgstr ""
#: php/i18n.php:177
msgid "Insert static publication list"
msgstr ""
#: php/i18n.php:180
msgid "Cited Items"
msgstr ""
#: php/i18n.php:182
msgid "Add reference"
msgstr ""
#: php/i18n.php:183
msgid "Insert selected references"
msgstr ""
#: php/i18n.php:184
msgid "Pin reference list"
msgstr ""
#: php/i18n.php:185
msgid "Remove selected references"
msgstr ""
#: php/i18n.php:187
msgid "Uncited Items"
msgstr ""
#: php/i18n.php:193
msgid "Add Manually"
msgstr ""
#: php/i18n.php:194
msgid "Add Reference"
msgstr ""
#: php/i18n.php:195
msgid "Add with Identifier"
msgstr ""
#: php/i18n.php:196
msgid "Insert citation inline"
msgstr ""
#: php/i18n.php:197, php/i18n.php:237
msgid "Search PubMed"
msgstr ""
#: php/i18n.php:200
msgid "DOI/PMID/PMCID"
msgstr ""
#: php/i18n.php:203
msgid "Autocite"
msgstr ""
#: php/i18n.php:204
msgid "Citation Type"
msgstr ""
#: php/i18n.php:206, php/i18n.php:236
msgid "Search"
msgstr ""
#: php/i18n.php:210
msgid "Add contributor"
msgstr ""
#: php/i18n.php:211
msgid "Contributors"
msgstr ""
#: php/i18n.php:214
msgid "Given Name, M.I."
msgstr ""
#: php/i18n.php:215
msgid "Surname"
msgstr ""
#: php/i18n.php:216
msgid "Literal Name"
msgstr ""
#: php/i18n.php:217
msgid "Remove contributor"
msgstr ""
#: php/i18n.php:218
msgid "Toggle literal name"
msgstr ""
#: php/i18n.php:220
msgid "Add References"
msgstr ""
#: php/i18n.php:222
msgid "Close dialog"
msgstr ""
#: php/i18n.php:224
msgid "Edit Reference"
msgstr ""
#: php/i18n.php:225
msgid "Confirm"
msgstr ""
#: php/i18n.php:228
msgid "Import"
msgstr ""
#: php/i18n.php:229
msgid "Import References"
msgstr ""
#: php/i18n.php:230
msgid "Choose File"
msgstr ""
#: php/i18n.php:233
msgid "Select"
msgstr ""
#: php/i18n.php:234
msgid "Next"
msgstr ""
#: php/i18n.php:235
msgid "Previous"
msgstr ""
#: php/i18n.php:238
msgid "View"
msgstr ""
#: php/i18n.php:243
msgid "Citation Style Type"
msgstr ""
#: php/i18n.php:244
msgid "Predefined"
msgstr ""
#: php/i18n.php:245
msgid "Custom"
msgstr ""
#: php/i18n.php:246
msgid "Heading"
msgstr ""
#: php/i18n.php:247
msgid "Heading Level"
msgstr ""
#: php/i18n.php:248
msgid "Fixed"
msgstr ""
#: php/i18n.php:249
msgid "Toggle"
msgstr ""
#: php/i18n.php:250
msgid "Bibliography Style"
msgstr ""
#: php/i18n.php:252
msgid "Link Format"
msgstr ""
#: php/i18n.php:253
msgid "Make URLs clickable and always add trailing source link"
msgstr ""
#: php/i18n.php:254
msgid "Make entire reference a clickable link to the source URL"
msgstr ""
#: php/i18n.php:255
msgid "Make URLs clickable only"
msgstr ""
#: php/i18n.php:256
msgid "Never add clickable links"
msgstr ""
#: php/views/options-page.php:3
msgid "Please send your feedback!"
msgstr ""
#: php/views/options-page.php:9
msgid "If you experience a bug or would like to request a new feature, please visit the <a href=\"%s\">GitHub Repository</a> and submit an issue."
msgstr ""
#: php/views/options-page.php:24
msgid "Plugin Requirements Check"
msgstr ""
#: php/views/options-page.php:29
msgid "PHP Version"
msgstr ""
#: php/views/options-page.php:36
msgid "PHP version should be at least 7.0"
msgstr ""
#: php/views/options-page.php:47, php/views/options-page.php:94
msgid "PHP %s Extension"
msgstr ""
#: php/views/options-page.php:59, php/views/options-page.php:106
msgid "Enabled"
msgstr ""
#: php/views/options-page.php:61, php/views/options-page.php:108
msgid "Disabled"
msgstr ""
#: php/views/options-page.php:71, php/views/options-page.php:118
msgid "The %s PHP extension is required for some plugin features."
msgstr ""
#: php/views/options-page.php:81, php/views/options-page.php:128
msgid "Click here for installation instructions"
msgstr ""
#: php/views/options-page.php:135
msgid "Recommended Browsers"
msgstr ""
#: php/views/options-page.php:138
msgid "Google Chrome, Mozilla Firefox, Apple Safari, or Microsoft Edge."
msgstr ""
#: php/views/options-page.php:147
msgid "Note: Be sure that your server does not have %1$s or %2$s configured in your php.ini file or .htaccess file. Both can cause issues."
msgstr ""
#: php/views/options-page.php:164
msgid "Default Citation Style"
msgstr ""
#: php/views/options-page.php:170, php/views/options-page.php:187, php/views/options-page.php:251
msgid "Update"
msgstr ""
#: php/views/options-page.php:181
msgid "Display Options"
msgstr ""
#: php/views/options-page.php:198
msgid "Override CSS"
msgstr ""
#: php/views/options-page.php:203
msgid "CSS Selectors used by this plugin"
msgstr ""
#: php/views/options-page.php:205
msgid "Inline Citations"
msgstr ""
#: php/views/options-page.php:213
msgid "Citation Tooltips"
msgstr ""
#: php/views/options-page.php:221
msgid "Bibliography"
msgstr ""
#: php/views/options-page.php:229
msgid "Static Publication Lists"
msgstr ""
#: php/views/options-page.php:260
msgid "How do I"
msgstr ""
#: php/views/options-page.php:264
msgid "Make my tooltips a different color?"
msgstr ""
#: php/views/options-page.php:278
msgid "Apply style to the bibliography list?"
msgstr ""
#: php/views/options-page.php:292
msgid "Apply style to the inline citations"
msgstr ""

View File

@@ -0,0 +1,562 @@
# Copyright (C) 2018 ThemeEgg
# This file is distributed under the GPL-2.0+.
msgid ""
msgstr ""
"Project-Id-Version: Accordion for WordPress 1.1.3\n"
"Report-Msgid-Bugs-To: themeeggofficial@gmail.com\n"
"POT-Creation-Date: 2018-02-24 04:16:52+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2018-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
"X-Generator: grunt-wp-i18n1.0.0\n"
#: includes/class-afwp-accordion-post-type.php:66
#: includes/class-afwp-accordion-post-type.php:109
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:66
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:109
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:66
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:109
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:66
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:109
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:66
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:109
msgid "Accordion template"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:79
#: includes/class-afwp-accordion-post-type.php:128
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:79
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:128
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:79
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:128
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:79
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:128
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:79
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:128
msgid "Select template for accordion"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:82
#: includes/class-afwp-accordion-post-type.php:133
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:82
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:133
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:82
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:133
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:82
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:133
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:82
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:133
msgid "Accordion style"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:93
#: includes/class-afwp-accordion-post-type.php:151
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:93
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:151
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:93
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:151
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:93
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:151
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:93
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:151
msgid "Select style for accordion"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:190
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:190
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:190
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:190
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:190
msgid "Shortcode"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:203
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:203
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:203
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:203
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:203
msgid "Search accordion group"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:204
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:204
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:204
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:204
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:204
msgid "All Accordion groups"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:205
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:205
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:205
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:205
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:205
msgid "Parent Accordion group"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:206
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:206
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:206
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:206
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:206
msgid "Parent Accordion group:"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:207
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:207
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:207
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:207
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:207
msgid "Edit Accordion group"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:208
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:208
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:208
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:208
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:208
msgid "Update Accordion group"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:209
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:209
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:209
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:209
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:209
msgid "Add New Accordion group"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:210
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:210
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:210
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:210
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:210
msgid "New Accordion group Name"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:211
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:211
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:211
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:211
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:211
msgid "Accordion group"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:232
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:232
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:232
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:232
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:232
msgid "Add New Accordion"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:233
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:233
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:233
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:233
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:233
msgid "New Accordion"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:234
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:234
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:234
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:234
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:234
msgid "Edit Accordion"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:235
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:235
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:235
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:235
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:235
msgid "View Accordion"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:236
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:236
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:236
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:236
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:236
msgid "All Accordions"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:237
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:237
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:237
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:237
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:237
msgid "Search Accordions"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:238
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:238
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:238
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:238
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:238
msgid "Parent Accordions:"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:239
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:239
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:239
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:239
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:239
msgid "No accordions found."
msgstr ""
#: includes/class-afwp-accordion-post-type.php:240
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:240
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:240
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:240
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:240
msgid "No accordions found in Trash."
msgstr ""
#: includes/class-afwp-accordion-post-type.php:245
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:245
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:245
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:245
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:245
msgid "Description."
msgstr ""
#: includes/class-afwp-accordion-widget.php:28
#: svn-production/tags/1.0.0/includes/class-afwp-accordion-widget.php:23
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-widget.php:28
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-widget.php:28
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-widget.php:28
#: svn-production/trunk/includes/class-afwp-accordion-widget.php:28
msgid "Widget for Accordion"
msgstr ""
#: includes/class-afwp-accordion-widget.php:32
#: svn-production/tags/1.0.0/includes/class-afwp-accordion-widget.php:27
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-widget.php:32
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-widget.php:32
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-widget.php:32
#: svn-production/trunk/includes/class-afwp-accordion-widget.php:32
msgid "Accordion Post Widget"
msgstr ""
#: includes/class-afwp-accordion-widget.php:150
#: includes/class-afwp-nav-menu-accordion-widget.php:183
#: includes/class-afwp-term-accordion-widget.php:143
#: svn-production/tags/1.0.0/includes/class-afwp-accordion-widget.php:134
#: svn-production/tags/1.0.0/includes/class-afwp-nav-menu-accordion-widget.php:168
#: svn-production/tags/1.0.0/includes/class-afwp-term-accordion-widget.php:138
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-widget.php:150
#: svn-production/tags/1.1.0/includes/class-afwp-nav-menu-accordion-widget.php:183
#: svn-production/tags/1.1.0/includes/class-afwp-term-accordion-widget.php:143
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-widget.php:150
#: svn-production/tags/1.1.1/includes/class-afwp-nav-menu-accordion-widget.php:183
#: svn-production/tags/1.1.1/includes/class-afwp-term-accordion-widget.php:143
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-widget.php:150
#: svn-production/tags/1.1.2/includes/class-afwp-nav-menu-accordion-widget.php:183
#: svn-production/tags/1.1.2/includes/class-afwp-term-accordion-widget.php:143
#: svn-production/trunk/includes/class-afwp-accordion-widget.php:150
#: svn-production/trunk/includes/class-afwp-nav-menu-accordion-widget.php:183
#: svn-production/trunk/includes/class-afwp-term-accordion-widget.php:143
msgid "Title:"
msgstr ""
#: includes/class-afwp-accordion-widget.php:156
#: svn-production/tags/1.0.0/includes/class-afwp-accordion-widget.php:137
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-widget.php:156
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-widget.php:156
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-widget.php:156
#: svn-production/trunk/includes/class-afwp-accordion-widget.php:156
msgid "Post Type:"
msgstr ""
#: includes/class-afwp-accordion-widget.php:175
#: includes/class-afwp-term-accordion-widget.php:148
#: svn-production/tags/1.0.0/includes/class-afwp-accordion-widget.php:150
#: svn-production/tags/1.0.0/includes/class-afwp-term-accordion-widget.php:143
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-widget.php:175
#: svn-production/tags/1.1.0/includes/class-afwp-term-accordion-widget.php:148
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-widget.php:175
#: svn-production/tags/1.1.1/includes/class-afwp-term-accordion-widget.php:148
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-widget.php:175
#: svn-production/tags/1.1.2/includes/class-afwp-term-accordion-widget.php:148
#: svn-production/trunk/includes/class-afwp-accordion-widget.php:175
#: svn-production/trunk/includes/class-afwp-term-accordion-widget.php:148
msgid "Taxonomy:"
msgstr ""
#: includes/class-afwp-accordion-widget.php:191
#: svn-production/tags/1.0.0/includes/class-afwp-accordion-widget.php:161
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-widget.php:191
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-widget.php:191
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-widget.php:191
#: svn-production/trunk/includes/class-afwp-accordion-widget.php:191
msgid "Term:"
msgstr ""
#: includes/class-afwp-accordion-widget.php:211
#: svn-production/tags/1.0.0/includes/class-afwp-accordion-widget.php:177
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-widget.php:211
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-widget.php:211
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-widget.php:211
#: svn-production/trunk/includes/class-afwp-accordion-widget.php:211
msgid "Show no of post:"
msgstr ""
#: includes/class-afwp-accordion-widget.php:217
#: includes/class-afwp-nav-menu-accordion-widget.php:213
#: includes/class-afwp-term-accordion-widget.php:173
#: svn-production/tags/1.0.0/includes/class-afwp-accordion-widget.php:180
#: svn-production/tags/1.0.0/includes/class-afwp-nav-menu-accordion-widget.php:193
#: svn-production/tags/1.0.0/includes/class-afwp-term-accordion-widget.php:166
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-widget.php:217
#: svn-production/tags/1.1.0/includes/class-afwp-nav-menu-accordion-widget.php:213
#: svn-production/tags/1.1.0/includes/class-afwp-term-accordion-widget.php:173
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-widget.php:217
#: svn-production/tags/1.1.1/includes/class-afwp-nav-menu-accordion-widget.php:213
#: svn-production/tags/1.1.1/includes/class-afwp-term-accordion-widget.php:173
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-widget.php:217
#: svn-production/tags/1.1.2/includes/class-afwp-nav-menu-accordion-widget.php:213
#: svn-production/tags/1.1.2/includes/class-afwp-term-accordion-widget.php:173
#: svn-production/trunk/includes/class-afwp-accordion-widget.php:217
#: svn-production/trunk/includes/class-afwp-nav-menu-accordion-widget.php:213
#: svn-production/trunk/includes/class-afwp-term-accordion-widget.php:173
msgid "Template:"
msgstr ""
#: includes/class-afwp-accordion-widget.php:229
#: includes/class-afwp-nav-menu-accordion-widget.php:227
#: includes/class-afwp-term-accordion-widget.php:186
#: svn-production/tags/1.0.0/includes/class-afwp-accordion-widget.php:192
#: svn-production/tags/1.0.0/includes/class-afwp-nav-menu-accordion-widget.php:207
#: svn-production/tags/1.0.0/includes/class-afwp-term-accordion-widget.php:181
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-widget.php:229
#: svn-production/tags/1.1.0/includes/class-afwp-nav-menu-accordion-widget.php:227
#: svn-production/tags/1.1.0/includes/class-afwp-term-accordion-widget.php:186
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-widget.php:229
#: svn-production/tags/1.1.1/includes/class-afwp-nav-menu-accordion-widget.php:227
#: svn-production/tags/1.1.1/includes/class-afwp-term-accordion-widget.php:186
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-widget.php:229
#: svn-production/tags/1.1.2/includes/class-afwp-nav-menu-accordion-widget.php:227
#: svn-production/tags/1.1.2/includes/class-afwp-term-accordion-widget.php:186
#: svn-production/trunk/includes/class-afwp-accordion-widget.php:229
#: svn-production/trunk/includes/class-afwp-nav-menu-accordion-widget.php:227
#: svn-production/trunk/includes/class-afwp-term-accordion-widget.php:186
msgid "Style:"
msgstr ""
#: includes/class-afwp-nav-menu-accordion-widget.php:32
#: svn-production/tags/1.0.0/includes/class-afwp-nav-menu-accordion-widget.php:27
#: svn-production/tags/1.1.0/includes/class-afwp-nav-menu-accordion-widget.php:32
#: svn-production/tags/1.1.1/includes/class-afwp-nav-menu-accordion-widget.php:32
#: svn-production/tags/1.1.2/includes/class-afwp-nav-menu-accordion-widget.php:32
#: svn-production/trunk/includes/class-afwp-nav-menu-accordion-widget.php:32
msgid "Add a custom accordion menu to your sidebar."
msgstr ""
#: includes/class-afwp-nav-menu-accordion-widget.php:35
#: svn-production/tags/1.0.0/includes/class-afwp-nav-menu-accordion-widget.php:30
#: svn-production/tags/1.1.0/includes/class-afwp-nav-menu-accordion-widget.php:35
#: svn-production/tags/1.1.1/includes/class-afwp-nav-menu-accordion-widget.php:35
#: svn-production/tags/1.1.2/includes/class-afwp-nav-menu-accordion-widget.php:35
#: svn-production/trunk/includes/class-afwp-nav-menu-accordion-widget.php:35
msgid "Accordion Menu"
msgstr ""
#: includes/class-afwp-nav-menu-accordion-widget.php:176
#: svn-production/tags/1.0.0/includes/class-afwp-nav-menu-accordion-widget.php:164
#: svn-production/tags/1.1.0/includes/class-afwp-nav-menu-accordion-widget.php:176
#: svn-production/tags/1.1.1/includes/class-afwp-nav-menu-accordion-widget.php:176
#: svn-production/tags/1.1.2/includes/class-afwp-nav-menu-accordion-widget.php:176
#: svn-production/trunk/includes/class-afwp-nav-menu-accordion-widget.php:176
msgid "No menus have been created yet. <a href=\"%s\">Create some</a>."
msgstr ""
#: includes/class-afwp-nav-menu-accordion-widget.php:190
#: svn-production/tags/1.0.0/includes/class-afwp-nav-menu-accordion-widget.php:172
#: svn-production/tags/1.1.0/includes/class-afwp-nav-menu-accordion-widget.php:190
#: svn-production/tags/1.1.1/includes/class-afwp-nav-menu-accordion-widget.php:190
#: svn-production/tags/1.1.2/includes/class-afwp-nav-menu-accordion-widget.php:190
#: svn-production/trunk/includes/class-afwp-nav-menu-accordion-widget.php:190
msgid "Select Menu:"
msgstr ""
#: includes/class-afwp-nav-menu-accordion-widget.php:193
#: svn-production/tags/1.0.0/includes/class-afwp-nav-menu-accordion-widget.php:174
#: svn-production/tags/1.1.0/includes/class-afwp-nav-menu-accordion-widget.php:193
#: svn-production/tags/1.1.1/includes/class-afwp-nav-menu-accordion-widget.php:193
#: svn-production/tags/1.1.2/includes/class-afwp-nav-menu-accordion-widget.php:193
#: svn-production/trunk/includes/class-afwp-nav-menu-accordion-widget.php:193
msgid "&mdash; Select &mdash;"
msgstr ""
#: includes/class-afwp-nav-menu-accordion-widget.php:206
#: svn-production/tags/1.0.0/includes/class-afwp-nav-menu-accordion-widget.php:184
#: svn-production/tags/1.1.0/includes/class-afwp-nav-menu-accordion-widget.php:206
#: svn-production/tags/1.1.1/includes/class-afwp-nav-menu-accordion-widget.php:206
#: svn-production/tags/1.1.2/includes/class-afwp-nav-menu-accordion-widget.php:206
#: svn-production/trunk/includes/class-afwp-nav-menu-accordion-widget.php:206
msgid "Show as Accordion:"
msgstr ""
#: includes/class-afwp-nav-menu-accordion-widget.php:240
#: svn-production/tags/1.0.0/includes/class-afwp-nav-menu-accordion-widget.php:216
#: svn-production/tags/1.1.0/includes/class-afwp-nav-menu-accordion-widget.php:240
#: svn-production/tags/1.1.1/includes/class-afwp-nav-menu-accordion-widget.php:240
#: svn-production/tags/1.1.2/includes/class-afwp-nav-menu-accordion-widget.php:240
#: svn-production/trunk/includes/class-afwp-nav-menu-accordion-widget.php:240
msgid "Edit Menu"
msgstr ""
#: includes/class-afwp-term-accordion-widget.php:28
#: svn-production/tags/1.0.0/includes/class-afwp-term-accordion-widget.php:23
#: svn-production/tags/1.1.0/includes/class-afwp-term-accordion-widget.php:28
#: svn-production/tags/1.1.1/includes/class-afwp-term-accordion-widget.php:28
#: svn-production/tags/1.1.2/includes/class-afwp-term-accordion-widget.php:28
#: svn-production/trunk/includes/class-afwp-term-accordion-widget.php:28
msgid "Widget for Term Accordion"
msgstr ""
#: includes/class-afwp-term-accordion-widget.php:32
#: svn-production/tags/1.0.0/includes/class-afwp-term-accordion-widget.php:27
#: svn-production/tags/1.1.0/includes/class-afwp-term-accordion-widget.php:32
#: svn-production/tags/1.1.1/includes/class-afwp-term-accordion-widget.php:32
#: svn-production/tags/1.1.2/includes/class-afwp-term-accordion-widget.php:32
#: svn-production/trunk/includes/class-afwp-term-accordion-widget.php:32
msgid "Accordion Term Widget"
msgstr ""
#: includes/class-afwp-term-accordion-widget.php:167
#: svn-production/tags/1.0.0/includes/class-afwp-term-accordion-widget.php:161
#: svn-production/tags/1.1.0/includes/class-afwp-term-accordion-widget.php:167
#: svn-production/tags/1.1.1/includes/class-afwp-term-accordion-widget.php:167
#: svn-production/tags/1.1.2/includes/class-afwp-term-accordion-widget.php:167
#: svn-production/trunk/includes/class-afwp-term-accordion-widget.php:167
msgid "Show no of term:"
msgstr ""
#: includes/function-afwp-core.php:14
#: svn-production/tags/1.1.0/includes/function-afwp-core.php:14
#: svn-production/tags/1.1.1/includes/function-afwp-core.php:14
#: svn-production/tags/1.1.2/includes/function-afwp-core.php:14
#: svn-production/trunk/includes/function-afwp-core.php:14
msgid "Default"
msgstr ""
#: includes/function-afwp-core.php:15
#: svn-production/tags/1.1.0/includes/function-afwp-core.php:15
#: svn-production/tags/1.1.1/includes/function-afwp-core.php:15
#: svn-production/tags/1.1.2/includes/function-afwp-core.php:15
#: svn-production/trunk/includes/function-afwp-core.php:15
msgid "Template 1"
msgstr ""
#: includes/function-afwp-core.php:16
#: svn-production/tags/1.1.2/includes/function-afwp-core.php:16
#: svn-production/trunk/includes/function-afwp-core.php:16
msgid "Theme default"
msgstr ""
#: includes/function-afwp-core.php:26
#: svn-production/tags/1.1.0/includes/function-afwp-core.php:25
#: svn-production/tags/1.1.1/includes/function-afwp-core.php:25
#: svn-production/tags/1.1.2/includes/function-afwp-core.php:26
#: svn-production/trunk/includes/function-afwp-core.php:26
msgid "Vertical"
msgstr ""
#: includes/function-afwp-core.php:27
#: svn-production/tags/1.1.0/includes/function-afwp-core.php:26
#: svn-production/tags/1.1.1/includes/function-afwp-core.php:26
#: svn-production/tags/1.1.2/includes/function-afwp-core.php:27
#: svn-production/trunk/includes/function-afwp-core.php:27
msgid "Horizontal"
msgstr ""
#. Plugin Name of the plugin/theme
msgid "Accordion for WordPress"
msgstr ""
#. Plugin URI of the plugin/theme
msgid "http://themeegg.com/plugins/accordion-for-wp/"
msgstr ""
#. Description of the plugin/theme
msgid ""
"Accordion for wordpress widgets and shortcode plugin with multiple "
"templates."
msgstr ""
#. Author of the plugin/theme
msgid "ThemeEgg"
msgstr ""
#. Author URI of the plugin/theme
msgid "http://themeegg.com/"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:201
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:201
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:201
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:201
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:201
msgctxt "taxonomy general name"
msgid "Accordion group"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:202
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:202
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:202
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:202
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:202
msgctxt "taxonomy singular name"
msgid "Accordion group"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:227
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:227
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:227
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:227
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:227
msgctxt "post type general name"
msgid "Accordion"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:228
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:228
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:228
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:228
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:228
msgctxt "post type singular name"
msgid "Accordion"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:229
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:229
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:229
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:229
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:229
msgctxt "admin menu"
msgid "Accordions"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:230
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:230
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:230
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:230
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:230
msgctxt "add new on admin bar"
msgid "Accordion"
msgstr ""
#: includes/class-afwp-accordion-post-type.php:231
#: svn-production/tags/1.1.0/includes/class-afwp-accordion-post-type.php:231
#: svn-production/tags/1.1.1/includes/class-afwp-accordion-post-type.php:231
#: svn-production/tags/1.1.2/includes/class-afwp-accordion-post-type.php:231
#: svn-production/trunk/includes/class-afwp-accordion-post-type.php:231
msgctxt "book"
msgid "Add New"
msgstr ""

View File

@@ -0,0 +1,88 @@
msgid ""
msgstr ""
"Project-Id-Version: ACF Field Selector 4.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-04-21 23:13+0100\n"
"PO-Revision-Date: 2015-04-21 23:13+0100\n"
"Last-Translator: Daniel Pataki <contact@tastique.org>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-KeywordsList: __;_e\n"
"X-Poedit-Basepath: .\n"
"X-Poedit-SearchPath-0: ..\n"
#: ../acf-field_selector-v4.php:41 ../acf-field_selector-v5.php:38
msgid "Field Selector"
msgstr ""
#: ../acf-field_selector-v4.php:42 ../acf-field_selector-v5.php:39
msgid "Choice"
msgstr ""
#: ../acf-field_selector-v4.php:106 ../acf-field_selector-v5.php:93
msgid "Group Filtering"
msgstr ""
#: ../acf-field_selector-v4.php:107
msgid "Enter group id numbers separated by commas to include or exclude them."
msgstr ""
#: ../acf-field_selector-v4.php:118 ../acf-field_selector-v4.php:154
#: ../acf-field_selector-v5.php:99 ../acf-field_selector-v5.php:118
msgid "Include"
msgstr ""
#: ../acf-field_selector-v4.php:119 ../acf-field_selector-v4.php:155
#: ../acf-field_selector-v5.php:100 ../acf-field_selector-v5.php:119
msgid "Exclude"
msgstr ""
#: ../acf-field_selector-v4.php:142 ../acf-field_selector-v5.php:112
msgid "Type Filtering"
msgstr ""
#: ../acf-field_selector-v4.php:143
msgid "Enter type slugs separated by commas to include or exclude them."
msgstr ""
#: ../acf-field_selector-v4.php:196 ../acf-field_selector-v5.php:152
msgid "Available Fields"
msgstr ""
#: ../acf-field_selector-v4.php:197 ../acf-field_selector-v5.php:153
msgid "Type to search..."
msgstr ""
#: ../acf-field_selector-v4.php:206 ../acf-field_selector-v5.php:162
msgid "Selected Fields"
msgstr ""
#: ../acf-field_selector-v4.php:207 ../acf-field_selector-v5.php:163
msgid "Drag and drop to re-order your selection"
msgstr ""
#: ../acf-field_selector-v5.php:94
msgid "Set how the given groups are used"
msgstr ""
#: ../acf-field_selector-v5.php:105
msgid "Groups"
msgstr ""
#: ../acf-field_selector-v5.php:106
msgid "Set the ID of groups to include or exclude"
msgstr ""
#: ../acf-field_selector-v5.php:113
msgid "Set how the given types are used"
msgstr ""
#: ../acf-field_selector-v5.php:124
msgid "Types"
msgstr ""
#: ../acf-field_selector-v5.php:125
msgid "Set the types to include or exclude"
msgstr ""

View File

@@ -0,0 +1,90 @@
msgid ""
msgstr ""
"Project-Id-Version: ACF Field Selector 4.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-04-21 23:13+0100\n"
"PO-Revision-Date: 2015-04-21 23:13+0100\n"
"Last-Translator: Daniel Pataki <contact@tastique.org>\n"
"Language-Team: Daniel Pataki <hello@danielpataki.com>\n"
"Language: Hungarian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-KeywordsList: __;_e\n"
"X-Poedit-Basepath: .\n"
"X-Poedit-SearchPath-0: ..\n"
#: ../acf-field_selector-v4.php:41 ../acf-field_selector-v5.php:38
msgid "Field Selector"
msgstr "Mező Választó"
#: ../acf-field_selector-v4.php:42 ../acf-field_selector-v5.php:39
msgid "Choice"
msgstr "Választás"
#: ../acf-field_selector-v4.php:106 ../acf-field_selector-v5.php:93
msgid "Group Filtering"
msgstr "Csoport Szűkítés"
#: ../acf-field_selector-v4.php:107
msgid "Enter group id numbers separated by commas to include or exclude them."
msgstr ""
"A mezők szűlítéséhez adj meg csoport azonosítókat, vesszővel elválasztva"
#: ../acf-field_selector-v4.php:118 ../acf-field_selector-v4.php:154
#: ../acf-field_selector-v5.php:99 ../acf-field_selector-v5.php:118
msgid "Include"
msgstr "Engedélyezés"
#: ../acf-field_selector-v4.php:119 ../acf-field_selector-v4.php:155
#: ../acf-field_selector-v5.php:100 ../acf-field_selector-v5.php:119
msgid "Exclude"
msgstr "Titlás"
#: ../acf-field_selector-v4.php:142 ../acf-field_selector-v5.php:112
msgid "Type Filtering"
msgstr "Típus Szűkítés"
#: ../acf-field_selector-v4.php:143
msgid "Enter type slugs separated by commas to include or exclude them."
msgstr "A mezők szűkítéséhezt adj meg típus neveket, vesszővel elválasztva"
#: ../acf-field_selector-v4.php:196 ../acf-field_selector-v5.php:152
msgid "Available Fields"
msgstr "Választható Mezők"
#: ../acf-field_selector-v4.php:197 ../acf-field_selector-v5.php:153
msgid "Type to search..."
msgstr "Kereséshez kezdj el írni"
#: ../acf-field_selector-v4.php:206 ../acf-field_selector-v5.php:162
msgid "Selected Fields"
msgstr "Választott Mezők"
#: ../acf-field_selector-v4.php:207 ../acf-field_selector-v5.php:163
msgid "Drag and drop to re-order your selection"
msgstr "Kattints, húzd és engedd el a mezőt az átrendezéshez"
#: ../acf-field_selector-v5.php:94
msgid "Set how the given groups are used"
msgstr "Addm meg, hogyan szűkítsék a csoportok a listát"
#: ../acf-field_selector-v5.php:105
msgid "Groups"
msgstr "Csoportok"
#: ../acf-field_selector-v5.php:106
msgid "Set the ID of groups to include or exclude"
msgstr "Adj meg csoport azonosítókat engedélyezéshez vagy tiltáshoz"
#: ../acf-field_selector-v5.php:113
msgid "Set how the given types are used"
msgstr "Add meg, hogyan szűkítsék a típusok a listát"
#: ../acf-field_selector-v5.php:124
msgid "Types"
msgstr "Típusok"
#: ../acf-field_selector-v5.php:125
msgid "Set the types to include or exclude"
msgstr "Adj meg típusokat engedélyezéshez vagy tiltáshoz"

Some files were not shown because too many files have changed in this diff Show More