Compare commits
152 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
73cd862e83 | ||
|
|
3305e9b74f | ||
|
|
c37ec0e8d0 | ||
|
|
0b005477c1 | ||
|
|
a1467f8dac | ||
|
|
40d2c34347 | ||
|
|
528270e767 | ||
|
|
f4a04b2387 | ||
|
|
14ed6ae109 | ||
|
|
4fd43694ae | ||
|
|
552d731e6a | ||
|
|
49ac3ef528 | ||
|
|
4379313f12 | ||
|
|
3901949f36 | ||
|
|
a3d8593fed | ||
|
|
7c5baeb9c7 | ||
|
|
c692db5f85 | ||
|
|
9130196ffc | ||
|
|
dad4a65118 | ||
|
|
4c34c2feb7 | ||
|
|
23522f7775 | ||
|
|
82c61398ba | ||
|
|
02871050a6 | ||
|
|
7d3b1fea6b | ||
|
|
24917fa2a6 | ||
|
|
de3d8e4a23 | ||
|
|
1502845d65 | ||
|
|
af3f10f74e | ||
|
|
c100372b31 | ||
|
|
72d699b39a | ||
|
|
7d2b8a2a8b | ||
|
|
8729c68e22 | ||
|
|
e2d48bedd9 | ||
|
|
6b241ce9b3 | ||
|
|
1b68bdb36c | ||
|
|
fb82538441 | ||
|
|
2709d0869a | ||
|
|
343f87bbe7 | ||
|
|
ecbfc6004c | ||
|
|
c57eecc81b | ||
|
|
7ea14dc03f | ||
|
|
4340d27258 | ||
|
|
e911be8f14 | ||
|
|
a4c650cdff | ||
|
|
31a58f8a8f | ||
|
|
ba4f15f111 | ||
|
|
206a913eb9 | ||
|
|
21ba490073 | ||
|
|
2a29e2ed95 | ||
|
|
9517d14fd3 | ||
|
|
3deaa896df | ||
|
|
c117007dc0 | ||
|
|
50baa238b9 | ||
|
|
0e2d771660 | ||
|
|
32b4670755 | ||
|
|
4a032d5e12 | ||
|
|
5887fede15 | ||
|
|
ad4eeb9f81 | ||
|
|
a62c16d7cc | ||
|
|
e766e7392a | ||
|
|
025c9c24ca | ||
|
|
ab052add27 | ||
|
|
15cb99977b | ||
|
|
82d5af926f | ||
|
|
76f73f3dc8 | ||
|
|
575b22320e | ||
|
|
d20c07dc85 | ||
|
|
f89071b87a | ||
|
|
8b4e90f285 | ||
|
|
9c4f57c786 | ||
|
|
902ec24b77 | ||
|
|
7eba77fa63 | ||
|
|
0753bbf7b3 | ||
|
|
6b2333614a | ||
|
|
80b7f458f5 | ||
|
|
dbd8e59cf4 | ||
|
|
9948230ea0 | ||
|
|
e2c858ac69 | ||
|
|
bac8b613e6 | ||
|
|
abbae15c6f | ||
|
|
1548e8bfc1 | ||
|
|
dc8cf3fc34 | ||
|
|
c3cd815567 | ||
|
|
ce543b9384 | ||
|
|
9755c8cf42 | ||
|
|
434a210fb5 | ||
|
|
587602665a | ||
|
|
bfec63df41 | ||
|
|
3b150df1af | ||
|
|
f24ecf0537 | ||
|
|
9ddecbcc0a | ||
|
|
947bb8d3d5 | ||
|
|
30cbf87b35 | ||
|
|
69c3aab35a | ||
|
|
bdeb3547f1 | ||
|
|
99e04b9669 | ||
|
|
680d2fb7eb | ||
|
|
8814eda018 | ||
|
|
7e72ba2885 | ||
|
|
b4d7a8490b | ||
|
|
e9a5bc66df | ||
|
|
edebc77726 | ||
|
|
271dee824d | ||
|
|
1e868d10ca | ||
|
|
4be3f17ae4 | ||
|
|
f24e7be264 | ||
|
|
9adc26445d | ||
|
|
353e7dcbb9 | ||
|
|
430e65c12e | ||
|
|
1aa242a9d8 | ||
|
|
7173cd85fe | ||
|
|
b95a4f55e3 | ||
|
|
6b5e016770 | ||
|
|
85aa9f61cd | ||
|
|
5c187002d6 | ||
|
|
9bc373308b | ||
|
|
cdeb0fc144 | ||
|
|
f1acdd9389 | ||
|
|
d6fac6a210 | ||
|
|
007cfb0801 | ||
|
|
1f9829b7c0 | ||
|
|
e039d22565 | ||
|
|
b0775b1610 | ||
|
|
0e429700c6 | ||
|
|
af7804ca23 | ||
|
|
9da326967b | ||
|
|
62600b3a66 | ||
|
|
b236138fb5 | ||
|
|
40c2e9a54b | ||
|
|
a9062db57f | ||
|
|
2621404c5f | ||
|
|
c47211ca79 | ||
|
|
e39a192e8d | ||
|
|
d85035d5ef | ||
|
|
de09a97343 | ||
|
|
a6855345d7 | ||
|
|
a53f88b626 | ||
|
|
7048c82124 | ||
|
|
6aa7cda478 | ||
|
|
ff339b9a8c | ||
|
|
8898cc20fe | ||
|
|
770d1da280 | ||
|
|
6ba4e8a29b | ||
|
|
953ca68495 | ||
|
|
4289dfb37d | ||
|
|
4f6f2f436a | ||
|
|
237979a479 | ||
|
|
2e48968fd3 | ||
|
|
9a0c4a5c8f | ||
|
|
9a011f0007 | ||
|
|
3f907a706f | ||
|
|
9446141716 |
@@ -14,3 +14,4 @@ Dockerfile
|
||||
*.orig
|
||||
bin/wpscan-*
|
||||
.wpscan/
|
||||
.github/
|
||||
|
||||
49
.github/workflows/build.yml
vendored
Normal file
49
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name: Build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
ruby: [2.4, 2.5, 2.6, 2.7]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Set up Ruby ${{ matrix.ruby }}
|
||||
uses: actions/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
|
||||
- name: Restore GEM cache
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: ${{ runner.os }}-${{ matrix.ruby }}-gem-${{ hashFiles('**/wpscan.gemspec') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ matrix.ruby }}-gem-
|
||||
|
||||
- name: Install GEMs
|
||||
run: |
|
||||
gem install bundler
|
||||
bundle config force_ruby_platform true
|
||||
bundle config path vendor/bundle
|
||||
bundle install --jobs 4 --retry 3
|
||||
|
||||
- name: rubocop
|
||||
run: |
|
||||
bundle exec rubocop
|
||||
|
||||
- name: rspec
|
||||
run: |
|
||||
bundle exec rspec
|
||||
|
||||
- name: Coveralls
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
40
.github/workflows/gempush.yml
vendored
Normal file
40
.github/workflows/gempush.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Ruby Gem
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build + Publish
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Set up Ruby 2.6
|
||||
uses: actions/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 2.6.x
|
||||
|
||||
#- name: Publish to GPR
|
||||
# run: |
|
||||
# mkdir -p $HOME/.gem
|
||||
# touch $HOME/.gem/credentials
|
||||
# chmod 0600 $HOME/.gem/credentials
|
||||
# printf -- "---\n:github: Bearer ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
||||
# gem build *.gemspec
|
||||
# gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
|
||||
# env:
|
||||
# GEM_HOST_API_KEY: ${{secrets.GITHUB_TOKEN}}
|
||||
# OWNER: wpscanteam
|
||||
|
||||
- name: Publish to RubyGems
|
||||
run: |
|
||||
mkdir -p $HOME/.gem
|
||||
touch $HOME/.gem/credentials
|
||||
chmod 0600 $HOME/.gem/credentials
|
||||
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
||||
gem build *.gemspec
|
||||
gem push *.gem
|
||||
env:
|
||||
GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
|
||||
5
.rspec
5
.rspec
@@ -1,3 +1,2 @@
|
||||
--color
|
||||
--fail-fast
|
||||
--require spec_helper
|
||||
--require spec_helper
|
||||
--color
|
||||
14
.rubocop.yml
14
.rubocop.yml
@@ -4,16 +4,10 @@ AllCops:
|
||||
Exclude:
|
||||
- '*.gemspec'
|
||||
- 'vendor/**/*'
|
||||
ClassVars:
|
||||
Enabled: false
|
||||
LineLength:
|
||||
Layout/LineLength:
|
||||
Max: 120
|
||||
Lint/UriEscapeUnescape:
|
||||
Enabled: false
|
||||
MethodLength:
|
||||
Max: 20
|
||||
Exclude:
|
||||
- 'app/controllers/enumeration/cli_options.rb'
|
||||
Metrics/AbcSize:
|
||||
Max: 25
|
||||
Metrics/BlockLength:
|
||||
@@ -25,6 +19,12 @@ Metrics/ClassLength:
|
||||
- 'app/controllers/enumeration/cli_options.rb'
|
||||
Metrics/CyclomaticComplexity:
|
||||
Max: 8
|
||||
Metrics/MethodLength:
|
||||
Max: 20
|
||||
Exclude:
|
||||
- 'app/controllers/enumeration/cli_options.rb'
|
||||
Style/ClassVars:
|
||||
Enabled: false
|
||||
Style/Documentation:
|
||||
Enabled: false
|
||||
Style/FormatStringToken:
|
||||
|
||||
14
.simplecov
14
.simplecov
@@ -1,4 +1,18 @@
|
||||
|
||||
if ENV['GITHUB_ACTION']
|
||||
require 'simplecov-lcov'
|
||||
|
||||
SimpleCov::Formatter::LcovFormatter.config do |c|
|
||||
c.single_report_path = 'coverage/lcov.info'
|
||||
c.report_with_single_file = true
|
||||
end
|
||||
|
||||
SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
|
||||
end
|
||||
|
||||
SimpleCov.start do
|
||||
enable_coverage :branch # Only supported for Ruby >= 2.5
|
||||
|
||||
add_filter '/spec/'
|
||||
add_filter 'helper'
|
||||
end
|
||||
33
.travis.yml
33
.travis.yml
@@ -1,33 +0,0 @@
|
||||
language: ruby
|
||||
sudo: false
|
||||
cache: bundler
|
||||
rvm:
|
||||
- 2.4.1
|
||||
- 2.4.2
|
||||
- 2.4.3
|
||||
- 2.4.4
|
||||
- 2.4.5
|
||||
- 2.4.6
|
||||
- 2.5.0
|
||||
- 2.5.1
|
||||
- 2.5.2
|
||||
- 2.5.3
|
||||
- 2.5.4
|
||||
- 2.5.5
|
||||
- 2.6.0
|
||||
- 2.6.1
|
||||
- 2.6.2
|
||||
- 2.6.3
|
||||
- ruby-head
|
||||
before_install:
|
||||
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
||||
- gem update --system
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rvm: ruby-head
|
||||
script:
|
||||
- bundle exec rubocop
|
||||
- bundle exec rspec
|
||||
notifications:
|
||||
email:
|
||||
- team@wpscan.org
|
||||
@@ -38,4 +38,3 @@ USER wpscan
|
||||
RUN /usr/local/bundle/bin/wpscan --update --verbose
|
||||
|
||||
ENTRYPOINT ["/usr/local/bundle/bin/wpscan"]
|
||||
CMD ["--help"]
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -29,8 +29,6 @@ Example cases which do not require a commercial license, and thus fall under the
|
||||
|
||||
If you need to purchase a commercial license or are unsure whether you need to purchase a commercial license contact us - team@wpscan.org.
|
||||
|
||||
We may grant commercial licenses at no monetary cost at our own discretion if the commercial usage is deemed by the WPScan Team to significantly benefit WPScan.
|
||||
|
||||
Free-use Terms and Conditions;
|
||||
|
||||
3. Redistribution
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="https://badge.fury.io/rb/wpscan" target="_blank"><img src="https://badge.fury.io/rb/wpscan.svg"></a>
|
||||
<a href="https://travis-ci.org/wpscanteam/wpscan" target="_blank"><img src="https://travis-ci.org/wpscanteam/wpscan.svg?branch=master"></a>
|
||||
<a href="https://github.com/wpscanteam/wpscan/actions?query=workflow%3ABuild" target="_blank"><img src="https://github.com/wpscanteam/wpscan/workflows/Build/badge.svg"></a>
|
||||
<a href="https://codeclimate.com/github/wpscanteam/wpscan" target="_blank"><img src="https://codeclimate.com/github/wpscanteam/wpscan/badges/gpa.svg"></a>
|
||||
</p>
|
||||
|
||||
@@ -130,6 +130,11 @@ cli_options:
|
||||
api_token: YOUR_API_TOKEN
|
||||
```
|
||||
|
||||
## Load APi Token From ENV
|
||||
|
||||
The API Token will be automatically loaded from the ENV variable `WPSCAN_API_TOKEN` if present. If the `--api-token` CLI option is also provided, the value from the CLI will be used.
|
||||
|
||||
|
||||
## Enumerating usernames
|
||||
|
||||
```shell
|
||||
|
||||
6
Rakefile
6
Rakefile
@@ -6,14 +6,18 @@ exec = []
|
||||
|
||||
begin
|
||||
require 'rubocop/rake_task'
|
||||
|
||||
RuboCop::RakeTask.new
|
||||
|
||||
exec << :rubocop
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
begin
|
||||
require 'rspec/core/rake_task'
|
||||
RSpec::Core::RakeTask.new(:spec)
|
||||
|
||||
RSpec::Core::RakeTask.new(:spec) { |t| t.rspec_opts = %w{--tag ~slow} }
|
||||
|
||||
exec << :spec
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
@@ -18,9 +18,7 @@ module WPScan
|
||||
target.content_dir = ParsedCli.wp_content_dir if ParsedCli.wp_content_dir
|
||||
target.plugins_dir = ParsedCli.wp_plugins_dir if ParsedCli.wp_plugins_dir
|
||||
|
||||
return if target.content_dir(ParsedCli.detection_mode)
|
||||
|
||||
raise Error::WpContentDirNotDetected
|
||||
raise Error::WpContentDirNotDetected unless target.content_dir
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -69,7 +69,7 @@ module WPScan
|
||||
OptInteger.new(
|
||||
['--plugins-threshold THRESHOLD',
|
||||
'Raise an error when the number of detected plugins via known locations reaches the threshold. ' \
|
||||
'Set to 0 to ignore the threshold.'], default: 100
|
||||
'Set to 0 to ignore the threshold.'], default: 100, advanced: true
|
||||
)
|
||||
]
|
||||
end
|
||||
@@ -98,7 +98,7 @@ module WPScan
|
||||
OptInteger.new(
|
||||
['--themes-threshold THRESHOLD',
|
||||
'Raise an error when the number of detected themes via known locations reaches the threshold. ' \
|
||||
'Set to 0 to ignore the threshold.'], default: 20
|
||||
'Set to 0 to ignore the threshold.'], default: 20, advanced: true
|
||||
)
|
||||
]
|
||||
end
|
||||
|
||||
@@ -4,6 +4,8 @@ module WPScan
|
||||
module Controller
|
||||
# Controller to handle the API token
|
||||
class VulnApi < CMSScanner::Controller::Base
|
||||
ENV_KEY = 'WPSCAN_API_TOKEN'
|
||||
|
||||
def cli_options
|
||||
[
|
||||
OptString.new(['--api-token TOKEN', 'The WPVulnDB API Token to display vulnerability data'])
|
||||
@@ -11,9 +13,9 @@ module WPScan
|
||||
end
|
||||
|
||||
def before_scan
|
||||
return unless ParsedCli.api_token
|
||||
return unless ParsedCli.api_token || ENV.key?(ENV_KEY)
|
||||
|
||||
DB::VulnApi.token = ParsedCli.api_token
|
||||
DB::VulnApi.token = ParsedCli.api_token || ENV[ENV_KEY]
|
||||
|
||||
api_status = DB::VulnApi.status
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ module WPScan
|
||||
module Finders
|
||||
module DbExports
|
||||
# DB Exports finder
|
||||
# See https://github.com/wpscanteam/wpscan-v3/issues/62
|
||||
class KnownLocations < CMSScanner::Finders::Finder
|
||||
include CMSScanner::Finders::Finder::Enumerator
|
||||
|
||||
@@ -41,7 +40,7 @@ module WPScan
|
||||
# @return [ Hash ]
|
||||
def potential_urls(opts = {})
|
||||
urls = {}
|
||||
domain_name = target.uri.host[/(^[\w|-]+)/, 1]
|
||||
domain_name = PublicSuffix.domain(target.uri.host)[/(^[\w|-]+)/, 1]
|
||||
|
||||
File.open(opts[:list]).each_with_index do |path, index|
|
||||
path.gsub!('{domain_name}', domain_name)
|
||||
|
||||
@@ -16,8 +16,7 @@ module WPScan
|
||||
target.url(path),
|
||||
confidence: 70,
|
||||
found_by: DIRECT_ACCESS,
|
||||
interesting_entries: target.directory_listing_entries(path),
|
||||
references: { url: 'https://github.com/wpscanteam/wpscan/issues/422' }
|
||||
interesting_entries: target.directory_listing_entries(path)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,11 +11,7 @@ module WPScan
|
||||
|
||||
return unless target.debug_log?(path)
|
||||
|
||||
Model::DebugLog.new(
|
||||
target.url(path),
|
||||
confidence: 100, found_by: DIRECT_ACCESS,
|
||||
references: { url: 'https://codex.wordpress.org/Debugging_in_WordPress' }
|
||||
)
|
||||
Model::DebugLog.new(target.url(path), confidence: 100, found_by: DIRECT_ACCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,12 +11,7 @@ module WPScan
|
||||
|
||||
return unless /DUPLICATOR INSTALL-LOG/.match?(target.head_and_get(path).body)
|
||||
|
||||
Model::DuplicatorInstallerLog.new(
|
||||
target.url(path),
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS,
|
||||
references: { url: 'https://www.exploit-db.com/ghdb/3981/' }
|
||||
)
|
||||
Model::DuplicatorInstallerLog.new(target.url(path), confidence: 100, found_by: DIRECT_ACCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,10 +15,7 @@ module WPScan
|
||||
Model::EmergencyPwdResetScript.new(
|
||||
target.url(path),
|
||||
confidence: /password/i.match?(res.body) ? 100 : 40,
|
||||
found_by: DIRECT_ACCESS,
|
||||
references: {
|
||||
url: 'https://codex.wordpress.org/Resetting_Your_Password#Using_the_Emergency_Password_Reset_Script'
|
||||
}
|
||||
found_by: DIRECT_ACCESS
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,8 +16,7 @@ module WPScan
|
||||
target.url(path),
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS,
|
||||
interesting_entries: fpd_entries,
|
||||
references: { url: 'https://www.owasp.org/index.php/Full_Path_Disclosure' }
|
||||
interesting_entries: fpd_entries
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,20 +9,14 @@ module WPScan
|
||||
def passive(_opts = {})
|
||||
pattern = %r{#{target.content_dir}/mu\-plugins/}i
|
||||
|
||||
target.in_scope_uris(target.homepage_res) do |uri|
|
||||
target.in_scope_uris(target.homepage_res, '(//@href|//@src)[contains(., "mu-plugins")]') do |uri|
|
||||
next unless uri.path&.match?(pattern)
|
||||
|
||||
url = target.url('wp-content/mu-plugins/')
|
||||
|
||||
target.mu_plugins = true
|
||||
|
||||
return Model::MuPlugins.new(
|
||||
url,
|
||||
confidence: 70,
|
||||
found_by: 'URLs In Homepage (Passive Detection)',
|
||||
to_s: "This site has 'Must Use Plugins': #{url}",
|
||||
references: { url: 'http://codex.wordpress.org/Must_Use_Plugins' }
|
||||
)
|
||||
return Model::MuPlugins.new(url, confidence: 70, found_by: 'URLs In Homepage (Passive Detection)')
|
||||
end
|
||||
nil
|
||||
end
|
||||
@@ -37,13 +31,7 @@ module WPScan
|
||||
|
||||
target.mu_plugins = true
|
||||
|
||||
Model::MuPlugins.new(
|
||||
url,
|
||||
confidence: 80,
|
||||
found_by: DIRECT_ACCESS,
|
||||
to_s: "This site has 'Must Use Plugins': #{url}",
|
||||
references: { url: 'http://codex.wordpress.org/Must_Use_Plugins' }
|
||||
)
|
||||
Model::MuPlugins.new(url, confidence: 80, found_by: DIRECT_ACCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,13 +17,7 @@ module WPScan
|
||||
|
||||
target.multisite = true
|
||||
|
||||
Model::Multisite.new(
|
||||
url,
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS,
|
||||
to_s: 'This site seems to be a multisite',
|
||||
references: { url: 'http://codex.wordpress.org/Glossary#Multisite' }
|
||||
)
|
||||
Model::Multisite.new(url, confidence: 100, found_by: DIRECT_ACCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,12 +20,7 @@ module WPScan
|
||||
|
||||
target.registration_enabled = true
|
||||
|
||||
Model::Registration.new(
|
||||
res.effective_url,
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS,
|
||||
to_s: "Registration is enabled: #{res.effective_url}"
|
||||
)
|
||||
Model::Registration.new(res.effective_url, confidence: 100, found_by: DIRECT_ACCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,12 +13,7 @@ module WPScan
|
||||
|
||||
return unless res.code == 200 && res.headers['Content-Type'] =~ %r{\Aapplication/zip}i
|
||||
|
||||
Model::TmmDbMigrate.new(
|
||||
url,
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS,
|
||||
references: { packetstorm: 131_957 }
|
||||
)
|
||||
Model::TmmDbMigrate.new(url, confidence: 100, found_by: DIRECT_ACCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,12 +13,7 @@ module WPScan
|
||||
|
||||
url = target.url(path)
|
||||
|
||||
Model::UploadDirectoryListing.new(
|
||||
url,
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS,
|
||||
to_s: "Upload directory has listing enabled: #{url}"
|
||||
)
|
||||
Model::UploadDirectoryListing.new(url, confidence: 100, found_by: DIRECT_ACCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,11 +14,7 @@ module WPScan
|
||||
|
||||
return unless SQL_PATTERN.match?(res.body)
|
||||
|
||||
Model::UploadSQLDump.new(
|
||||
target.url(path),
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS
|
||||
)
|
||||
Model::UploadSQLDump.new(target.url(path), confidence: 100, found_by: DIRECT_ACCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,17 +11,7 @@ module WPScan
|
||||
|
||||
return unless res.code == 200
|
||||
|
||||
Model::WPCron.new(
|
||||
wp_cron_url,
|
||||
confidence: 60,
|
||||
found_by: DIRECT_ACCESS,
|
||||
references: {
|
||||
url: [
|
||||
'https://www.iplocation.net/defend-wordpress-from-ddos',
|
||||
'https://github.com/wpscanteam/wpscan/issues/1299'
|
||||
]
|
||||
}
|
||||
)
|
||||
Model::WPCron.new(wp_cron_url, confidence: 60, found_by: DIRECT_ACCESS)
|
||||
end
|
||||
|
||||
def wp_cron_url
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'main_theme/css_style'
|
||||
require_relative 'main_theme/css_style_in_homepage'
|
||||
require_relative 'main_theme/css_style_in_404_page'
|
||||
require_relative 'main_theme/woo_framework_meta_generator'
|
||||
require_relative 'main_theme/urls_in_homepage'
|
||||
require_relative 'main_theme/urls_in_404_page'
|
||||
|
||||
module WPScan
|
||||
module Finders
|
||||
@@ -14,9 +16,11 @@ module WPScan
|
||||
# @param [ WPScan::Target ] target
|
||||
def initialize(target)
|
||||
finders <<
|
||||
MainTheme::CssStyle.new(target) <<
|
||||
MainTheme::CssStyleInHomepage.new(target) <<
|
||||
MainTheme::CssStyleIn404Page.new(target) <<
|
||||
MainTheme::WooFrameworkMetaGenerator.new(target) <<
|
||||
MainTheme::UrlsInHomepage.new(target)
|
||||
MainTheme::UrlsInHomepage.new(target) <<
|
||||
MainTheme::UrlsIn404Page.new(target)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
14
app/finders/main_theme/css_style_in_404_page.rb
Normal file
14
app/finders/main_theme/css_style_in_404_page.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module WPScan
|
||||
module Finders
|
||||
module MainTheme
|
||||
# From the CSS style in the 404 page
|
||||
class CssStyleIn404Page < CssStyleInHomepage
|
||||
def passive(opts = {})
|
||||
passive_from_css_href(target.error_404_res, opts) || passive_from_style_code(target.error_404_res, opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,9 +3,9 @@
|
||||
module WPScan
|
||||
module Finders
|
||||
module MainTheme
|
||||
# From the css style
|
||||
class CssStyle < CMSScanner::Finders::Finder
|
||||
include Finders::WpItems::URLsInHomepage
|
||||
# From the CSS style in the homepage
|
||||
class CssStyleInHomepage < CMSScanner::Finders::Finder
|
||||
include Finders::WpItems::UrlsInPage # To have the item_code_pattern method available here
|
||||
|
||||
def create_theme(slug, style_url, opts)
|
||||
Model::Theme.new(
|
||||
@@ -20,7 +20,7 @@ module WPScan
|
||||
end
|
||||
|
||||
def passive_from_css_href(res, opts)
|
||||
target.in_scope_uris(res, '//style/@src|//link/@href') do |uri|
|
||||
target.in_scope_uris(res, '//link/@href[contains(., "style.css")]') do |uri|
|
||||
next unless uri.path =~ %r{/themes/([^\/]+)/style.css\z}i
|
||||
|
||||
return create_theme(Regexp.last_match[1], uri.to_s, opts)
|
||||
15
app/finders/main_theme/urls_in_404_page.rb
Normal file
15
app/finders/main_theme/urls_in_404_page.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module WPScan
|
||||
module Finders
|
||||
module MainTheme
|
||||
# URLs In 404 Page Finder
|
||||
class UrlsIn404Page < UrlsInHomepage
|
||||
# @return [ Typhoeus::Response ]
|
||||
def page_res
|
||||
@page_res ||= target.error_404_res
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,7 +5,7 @@ module WPScan
|
||||
module MainTheme
|
||||
# URLs In Homepage Finder
|
||||
class UrlsInHomepage < CMSScanner::Finders::Finder
|
||||
include WpItems::URLsInHomepage
|
||||
include WpItems::UrlsInPage
|
||||
|
||||
# @param [ Hash ] opts
|
||||
#
|
||||
@@ -21,6 +21,11 @@ module WPScan
|
||||
|
||||
found
|
||||
end
|
||||
|
||||
# @return [ Typhoeus::Response ]
|
||||
def page_res
|
||||
@page_res ||= target.homepage_res
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,7 +10,7 @@ module WPScan
|
||||
PATTERN = /#{THEME_PATTERN}\s+#{FRAMEWORK_PATTERN}/i.freeze
|
||||
|
||||
def passive(opts = {})
|
||||
return unless target.homepage_res.body =~ PATTERN
|
||||
return unless target.homepage_res.body =~ PATTERN || target.error_404_res.body =~ PATTERN
|
||||
|
||||
Model::Theme.new(
|
||||
Regexp.last_match[1],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'plugins/urls_in_homepage'
|
||||
require_relative 'plugins/urls_in_404_page'
|
||||
require_relative 'plugins/known_locations'
|
||||
# From the DynamicFinders
|
||||
require_relative 'plugins/comment'
|
||||
@@ -22,6 +23,7 @@ module WPScan
|
||||
def initialize(target)
|
||||
finders <<
|
||||
Plugins::UrlsInHomepage.new(target) <<
|
||||
Plugins::UrlsIn404Page.new(target) <<
|
||||
Plugins::HeaderPattern.new(target) <<
|
||||
Plugins::Comment.new(target) <<
|
||||
Plugins::Xpath.new(target) <<
|
||||
|
||||
@@ -19,8 +19,12 @@ module WPScan
|
||||
def aggressive(opts = {})
|
||||
found = []
|
||||
|
||||
enumerate(target_urls(opts), opts.merge(check_full_response: true)) do |_res, slug|
|
||||
found << Model::Plugin.new(slug, target, opts.merge(found_by: found_by, confidence: 80))
|
||||
enumerate(target_urls(opts), opts.merge(check_full_response: true)) do |res, slug|
|
||||
finding_opts = opts.merge(found_by: found_by,
|
||||
confidence: 80,
|
||||
interesting_entries: ["#{res.effective_url}, status: #{res.code}"])
|
||||
|
||||
found << Model::Plugin.new(slug, target, finding_opts)
|
||||
|
||||
raise Error::PluginsThresholdReached if opts[:threshold].positive? && found.size >= opts[:threshold]
|
||||
end
|
||||
|
||||
16
app/finders/plugins/urls_in_404_page.rb
Normal file
16
app/finders/plugins/urls_in_404_page.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module WPScan
|
||||
module Finders
|
||||
module Plugins
|
||||
# URLs In 404 Page Finder
|
||||
# Typically, the items detected from URLs like /wp-content/plugins/<slug>/
|
||||
class UrlsIn404Page < UrlsInHomepage
|
||||
# @return [ Typhoeus::Response ]
|
||||
def page_res
|
||||
@page_res ||= target.error_404_res
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -4,10 +4,9 @@ module WPScan
|
||||
module Finders
|
||||
module Plugins
|
||||
# URLs In Homepage Finder
|
||||
# Typically, the items detected from URLs like
|
||||
# /wp-content/plugins/<slug>/
|
||||
# Typically, the items detected from URLs like /wp-content/plugins/<slug>/
|
||||
class UrlsInHomepage < CMSScanner::Finders::Finder
|
||||
include WpItems::URLsInHomepage
|
||||
include WpItems::UrlsInPage
|
||||
|
||||
# @param [ Hash ] opts
|
||||
#
|
||||
@@ -21,6 +20,11 @@ module WPScan
|
||||
|
||||
found
|
||||
end
|
||||
|
||||
# @return [ Typhoeus::Response ]
|
||||
def page_res
|
||||
@page_res ||= target.homepage_res
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'themes/urls_in_homepage'
|
||||
require_relative 'themes/urls_in_404_page'
|
||||
require_relative 'themes/known_locations'
|
||||
|
||||
module WPScan
|
||||
module Finders
|
||||
module Themes
|
||||
# themes Finder
|
||||
# Themes Finder
|
||||
class Base
|
||||
include CMSScanner::Finders::SameTypeFinder
|
||||
|
||||
@@ -14,6 +15,7 @@ module WPScan
|
||||
def initialize(target)
|
||||
finders <<
|
||||
Themes::UrlsInHomepage.new(target) <<
|
||||
Themes::UrlsIn404Page.new(target) <<
|
||||
Themes::KnownLocations.new(target)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,8 +19,12 @@ module WPScan
|
||||
def aggressive(opts = {})
|
||||
found = []
|
||||
|
||||
enumerate(target_urls(opts), opts.merge(check_full_response: true)) do |_res, slug|
|
||||
found << Model::Theme.new(slug, target, opts.merge(found_by: found_by, confidence: 80))
|
||||
enumerate(target_urls(opts), opts.merge(check_full_response: true)) do |res, slug|
|
||||
finding_opts = opts.merge(found_by: found_by,
|
||||
confidence: 80,
|
||||
interesting_entries: ["#{res.effective_url}, status: #{res.code}"])
|
||||
|
||||
found << Model::Theme.new(slug, target, finding_opts)
|
||||
|
||||
raise Error::ThemesThresholdReached if opts[:threshold].positive? && found.size >= opts[:threshold]
|
||||
end
|
||||
|
||||
15
app/finders/themes/urls_in_404_page.rb
Normal file
15
app/finders/themes/urls_in_404_page.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module WPScan
|
||||
module Finders
|
||||
module Themes
|
||||
# URLs In 04 Page Finder
|
||||
class UrlsIn404Page < UrlsInHomepage
|
||||
# @return [ Typhoeus::Response ]
|
||||
def page_res
|
||||
@page_res ||= target.error_404_res
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,7 +5,7 @@ module WPScan
|
||||
module Themes
|
||||
# URLs In Homepage Finder
|
||||
class UrlsInHomepage < CMSScanner::Finders::Finder
|
||||
include WpItems::URLsInHomepage
|
||||
include WpItems::UrlsInPage
|
||||
|
||||
# @param [ Hash ] opts
|
||||
#
|
||||
@@ -19,6 +19,11 @@ module WPScan
|
||||
|
||||
found
|
||||
end
|
||||
|
||||
# @return [ Typhoeus::Response ]
|
||||
def page_res
|
||||
@page_res ||= target.homepage_res
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -71,11 +71,13 @@ module WPScan
|
||||
return username, 'Display Name', 50 if username
|
||||
end
|
||||
|
||||
# @param [ String ] url
|
||||
# @param [ String, Addressable::URI ] uri
|
||||
#
|
||||
# @return [ String, nil ]
|
||||
def username_from_author_url(url)
|
||||
url[%r{/author/([^/\b]+)/?}i, 1]
|
||||
def username_from_author_url(uri)
|
||||
uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI)
|
||||
|
||||
uri.path[%r{/author/([^/\b]+)/?}i, 1]
|
||||
end
|
||||
|
||||
# @param [ Typhoeus::Response ] res
|
||||
@@ -83,12 +85,12 @@ module WPScan
|
||||
# @return [ String, nil ] The username found
|
||||
def username_from_response(res)
|
||||
# Permalink enabled
|
||||
target.in_scope_uris(res, '//link/@href|//a/@href') do |uri|
|
||||
username = username_from_author_url(uri.to_s)
|
||||
target.in_scope_uris(res, '//@href[contains(., "author/")]') do |uri|
|
||||
username = username_from_author_url(uri)
|
||||
return username if username
|
||||
end
|
||||
|
||||
# No permalink
|
||||
# No permalink, TODO Maybe use xpath to extract the classes ?
|
||||
res.body[/<body class="archive author author-([^\s]+)[ "]/i, 1]
|
||||
end
|
||||
|
||||
@@ -97,9 +99,12 @@ module WPScan
|
||||
# @return [ String, nil ]
|
||||
def display_name_from_body(body)
|
||||
page = Nokogiri::HTML.parse(body)
|
||||
|
||||
# WP >= 3.0
|
||||
page.css('h1.page-title span').each do |node|
|
||||
return node.text.to_s
|
||||
text = node.text.to_s.strip
|
||||
|
||||
return text unless text.empty?
|
||||
end
|
||||
|
||||
# WP < 3.0
|
||||
|
||||
@@ -45,7 +45,7 @@ module WPScan
|
||||
def potential_usernames(res)
|
||||
usernames = []
|
||||
|
||||
target.in_scope_uris(res, '//a/@href') do |uri, node|
|
||||
target.in_scope_uris(res, '//a/@href[contains(., "author")]') do |uri, node|
|
||||
if uri.path =~ %r{/author/([^/\b]+)/?\z}i
|
||||
usernames << [Regexp.last_match[1], 'Author Pattern', 100]
|
||||
elsif /author=[0-9]+/.match?(uri.query)
|
||||
|
||||
@@ -34,6 +34,8 @@ module WPScan
|
||||
def user_details_from_oembed_data(oembed_data)
|
||||
return unless oembed_data
|
||||
|
||||
oembed_data = oembed_data.first if oembed_data.is_a?(Array)
|
||||
|
||||
if oembed_data['author_url'] =~ %r{/author/([^/]+)/?\z}
|
||||
details = [Regexp.last_match[1], 'Author URL', 90]
|
||||
elsif oembed_data['author_name'] && !oembed_data['author_name'].empty?
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'wp_items/urls_in_homepage'
|
||||
require_relative 'wp_items/urls_in_page'
|
||||
|
||||
@@ -4,18 +4,24 @@ module WPScan
|
||||
module Finders
|
||||
module WpItems
|
||||
# URLs In Homepage Module to use in plugins & themes finders
|
||||
module URLsInHomepage
|
||||
module UrlsInPage
|
||||
# @param [ String ] type plugins / themes
|
||||
# @param [ Boolean ] uniq Wether or not to apply the #uniq on the results
|
||||
#
|
||||
# @return [Array<String> ] The plugins/themes detected in the href, src attributes of the homepage
|
||||
# @return [ Array<String> ] The plugins/themes detected in the href, src attributes of the page
|
||||
def items_from_links(type, uniq = true)
|
||||
found = []
|
||||
xpath = format(
|
||||
'(//@href|//@src|//@data-src)[contains(., "%s")]',
|
||||
type == 'plugins' ? target.plugins_dir : target.content_dir
|
||||
)
|
||||
|
||||
target.in_scope_uris(target.homepage_res) do |uri|
|
||||
target.in_scope_uris(page_res, xpath) do |uri|
|
||||
next unless uri.to_s =~ item_attribute_pattern(type)
|
||||
|
||||
found << Regexp.last_match[1]
|
||||
slug = Regexp.last_match[1]&.strip
|
||||
|
||||
found << slug unless slug&.empty?
|
||||
end
|
||||
|
||||
uniq ? found.uniq.sort : found.sort
|
||||
@@ -28,7 +34,7 @@ module WPScan
|
||||
def items_from_codes(type, uniq = true)
|
||||
found = []
|
||||
|
||||
target.homepage_res.html.css('script,style').each do |tag|
|
||||
page_res.html.xpath('//script[not(@src)]|//style[not(@src)]').each do |tag|
|
||||
code = tag.text.to_s
|
||||
next if code.empty?
|
||||
|
||||
@@ -42,7 +48,7 @@ module WPScan
|
||||
#
|
||||
# @return [ Regexp ]
|
||||
def item_attribute_pattern(type)
|
||||
@item_attribute_pattern ||= %r{\A#{item_url_pattern(type)}([^/]+)/}i
|
||||
@item_attribute_pattern ||= %r{#{item_url_pattern(type)}([^/]+)/}i
|
||||
end
|
||||
|
||||
# @param [ String ] type
|
||||
@@ -59,7 +65,7 @@ module WPScan
|
||||
item_dir = type == 'plugins' ? target.plugins_dir : target.content_dir
|
||||
item_url = type == 'plugins' ? target.plugins_url : target.content_url
|
||||
|
||||
url = /#{item_url.gsub(/\A(?:http|https)/i, 'https?').gsub('/', '\\\\\?\/')}/i
|
||||
url = /#{item_url.gsub(/\A(?:https?)/i, 'https?').gsub('/', '\\\\\?\/')}/i
|
||||
item_dir = %r{(?:#{url}|\\?\/#{item_dir.gsub('/', '\\\\\?\/')}\\?/)}i
|
||||
|
||||
type == 'plugins' ? item_dir : %r{#{item_dir}#{type}\\?\/}i
|
||||
@@ -28,7 +28,7 @@ module WPScan
|
||||
end
|
||||
|
||||
def passive_urls_xpath
|
||||
'//a[contains(@href, "rdf")]/@href'
|
||||
'//a[contains(@href, "/rdf")]/@href'
|
||||
end
|
||||
|
||||
def aggressive_urls(_opts = {})
|
||||
|
||||
@@ -8,45 +8,110 @@ module WPScan
|
||||
end
|
||||
|
||||
#
|
||||
# Empty classes for the #type to be correctly displayed (as taken from the self.class from the parent)
|
||||
# Some classes are empty for the #type to be correctly displayed (as taken from the self.class from the parent)
|
||||
#
|
||||
class BackupDB < InterestingFinding
|
||||
# @return [ Hash ]
|
||||
def references
|
||||
@references ||= { url: ['https://github.com/wpscanteam/wpscan/issues/422'] }
|
||||
end
|
||||
end
|
||||
|
||||
class DebugLog < InterestingFinding
|
||||
# @ return [ Hash ]
|
||||
def references
|
||||
@references ||= { url: 'https://codex.wordpress.org/Debugging_in_WordPress' }
|
||||
end
|
||||
end
|
||||
|
||||
class DuplicatorInstallerLog < InterestingFinding
|
||||
# @return [ Hash ]
|
||||
def references
|
||||
@references ||= { url: ['https://www.exploit-db.com/ghdb/3981/'] }
|
||||
end
|
||||
end
|
||||
|
||||
class EmergencyPwdResetScript < InterestingFinding
|
||||
def references
|
||||
@references ||= {
|
||||
url: ['https://codex.wordpress.org/Resetting_Your_Password#Using_the_Emergency_Password_Reset_Script']
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
class FullPathDisclosure < InterestingFinding
|
||||
# @return [ Hash ]
|
||||
def references
|
||||
@references ||= { url: ['https://www.owasp.org/index.php/Full_Path_Disclosure'] }
|
||||
end
|
||||
end
|
||||
|
||||
class MuPlugins < InterestingFinding
|
||||
# @return [ String ]
|
||||
def to_s
|
||||
@to_s ||= "This site has 'Must Use Plugins': #{url}"
|
||||
end
|
||||
|
||||
# @return [ Hash ]
|
||||
def references
|
||||
@references ||= { url: ['http://codex.wordpress.org/Must_Use_Plugins'] }
|
||||
end
|
||||
end
|
||||
|
||||
class Multisite < InterestingFinding
|
||||
# @return [ String ]
|
||||
def to_s
|
||||
@to_s ||= 'This site seems to be a multisite'
|
||||
end
|
||||
|
||||
# @return [ Hash ]
|
||||
def references
|
||||
@references ||= { url: ['http://codex.wordpress.org/Glossary#Multisite'] }
|
||||
end
|
||||
end
|
||||
|
||||
class Readme < InterestingFinding
|
||||
end
|
||||
|
||||
class Registration < InterestingFinding
|
||||
# @return [ String ]
|
||||
def to_s
|
||||
@to_s ||= "Registration is enabled: #{url}"
|
||||
end
|
||||
end
|
||||
|
||||
class TmmDbMigrate < InterestingFinding
|
||||
# @return [ Hash ]
|
||||
def references
|
||||
@references ||= { packetstorm: [131_957] }
|
||||
end
|
||||
end
|
||||
|
||||
class UploadDirectoryListing < InterestingFinding
|
||||
# @return [ String ]
|
||||
def to_s
|
||||
@to_s ||= "Upload directory has listing enabled: #{url}"
|
||||
end
|
||||
end
|
||||
|
||||
class UploadSQLDump < InterestingFinding
|
||||
end
|
||||
|
||||
class WPCron < InterestingFinding
|
||||
# @return [ String ]
|
||||
def to_s
|
||||
@to_s ||= "The external WP-Cron seems to be enabled: #{url}"
|
||||
end
|
||||
|
||||
# @return [ Hash ]
|
||||
def references
|
||||
@references ||= {
|
||||
url: [
|
||||
'https://www.iplocation.net/defend-wordpress-from-ddos',
|
||||
'https://github.com/wpscanteam/wpscan/issues/1299'
|
||||
]
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -101,7 +101,7 @@ module WPScan
|
||||
#
|
||||
# @return [ String ]
|
||||
def parse_style_tag(body, tag)
|
||||
value = body[/^\s*#{Regexp.escape(tag)}:[\t ]*([^\r\n]+)/i, 1]
|
||||
value = body[/#{Regexp.escape(tag)}:[\t ]*([^\r\n\*]+)/i, 1]
|
||||
|
||||
value && !value.strip.empty? ? value.strip : nil
|
||||
end
|
||||
|
||||
@@ -14,7 +14,7 @@ module WPScan
|
||||
|
||||
attr_reader :uri, :slug, :detection_opts, :version_detection_opts, :blog, :path_from_blog, :db_data
|
||||
|
||||
delegate :homepage_res, :xpath_pattern_from_page, :in_scope_uris, :head_or_get_params, to: :blog
|
||||
delegate :homepage_res, :error_404_res, :xpath_pattern_from_page, :in_scope_uris, :head_or_get_params, to: :blog
|
||||
|
||||
# @param [ String ] slug The plugin/theme slug
|
||||
# @param [ Target ] blog The targeted blog
|
||||
@@ -23,7 +23,7 @@ module WPScan
|
||||
# @option opts [ Hash ] :version_detection The options to use when looking for the version
|
||||
# @option opts [ String ] :url The URL of the item
|
||||
def initialize(slug, blog, opts = {})
|
||||
@slug = URI.decode(slug)
|
||||
@slug = Addressable::URI.unencode(slug)
|
||||
@blog = blog
|
||||
@uri = Addressable::URI.parse(opts[:url]) if opts[:url]
|
||||
|
||||
@@ -83,11 +83,6 @@ module WPScan
|
||||
end
|
||||
end
|
||||
|
||||
# URI.encode is preferered over Addressable::URI.encode as it will encode
|
||||
# leading # character:
|
||||
# URI.encode('#t#') => %23t%23
|
||||
# Addressable::URI.encode('#t#') => #t%23
|
||||
#
|
||||
# @param [ String ] path Optional path to merge with the uri
|
||||
#
|
||||
# @return [ String ]
|
||||
@@ -95,7 +90,7 @@ module WPScan
|
||||
return unless @uri
|
||||
return @uri.to_s unless path
|
||||
|
||||
@uri.join(URI.encode(path)).to_s
|
||||
@uri.join(Addressable::URI.encode(path)).to_s
|
||||
end
|
||||
|
||||
# @return [ Boolean ]
|
||||
@@ -166,7 +161,7 @@ module WPScan
|
||||
# @return [ Typhoeus::Response ]
|
||||
def head_and_get(path, codes = [200], params = {})
|
||||
final_path = +@path_from_blog
|
||||
final_path << URI.encode(path) unless path.nil?
|
||||
final_path << path unless path.nil?
|
||||
|
||||
blog.head_and_get(final_path, codes, params)
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@ module WPScan
|
||||
|
||||
# @return [ Hash ]
|
||||
def references
|
||||
{
|
||||
@references ||= {
|
||||
url: ['http://codex.wordpress.org/XML-RPC_Pingback_API'],
|
||||
metasploit: [
|
||||
'auxiliary/scanner/http/wordpress_ghost_scanner',
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
_______________________________________________________________
|
||||
__ _______ _____
|
||||
\ \ / / __ \ / ____|
|
||||
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
|
||||
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
|
||||
\ /\ / | | ____) | (__| (_| | | | |
|
||||
\/ \/ |_| |_____/ \___|\__,_|_| |_|
|
||||
__ _______ _____
|
||||
\ \ / / __ \ / ____|
|
||||
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
|
||||
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
|
||||
\ /\ / | | ____) | (__| (_| | | | |
|
||||
\/ \/ |_| |_____/ \___|\__,_|_| |_|
|
||||
|
||||
WordPress Security Scanner by the WPScan Team
|
||||
Version <%= WPScan::VERSION %>
|
||||
WordPress Security Scanner by the WPScan Team
|
||||
Version <%= WPScan::VERSION %>
|
||||
<%= ' ' * ((63 - WPScan::DB::Sponsor.text.length)/2) + WPScan::DB::Sponsor.text %>
|
||||
@_WPScan_, @ethicalhack3r, @erwan_lr, @_FireFart_
|
||||
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
|
||||
_______________________________________________________________
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
| Detected By: <%= @item.found_by %>
|
||||
| Found By: <%= @item.found_by %>
|
||||
<% @item.interesting_entries.each do |entry| -%>
|
||||
| - <%= entry %>
|
||||
<% end -%>
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
<% end -%>
|
||||
<% else -%>
|
||||
<%= warning_icon %> No WPVulnDB API Token given, as a result vulnerability data has not been output.
|
||||
<%= warning_icon %> You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/register.
|
||||
<%= warning_icon %> You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up
|
||||
<% end -%>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"@_WPScan_",
|
||||
"@ethicalhack3r",
|
||||
"@erwan_lr",
|
||||
"@_FireFart_"
|
||||
"@firefart"
|
||||
],
|
||||
"sponsor": <%= WPScan::DB::Sponsor.text.to_json %>
|
||||
},
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
"requests_remaining": <%= @status['requests_remaining'].to_json %>
|
||||
<% end -%>
|
||||
<% else -%>
|
||||
"error": "No WPVulnDB API Token given, as a result vulnerability data has not been output.\nYou can get a free API token with 50 daily requests by registering at https://wpvulndb.com/register."
|
||||
"error": "No WPVulnDB API Token given, as a result vulnerability data has not been output.\nYou can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up"
|
||||
<% end -%>
|
||||
},
|
||||
@@ -67,13 +67,13 @@ module WPScan
|
||||
# @return [ Hash ] The params for Typhoeus::Request
|
||||
# @note Those params can't be overriden by CLI options
|
||||
def request_params
|
||||
@request_params ||= {
|
||||
@request_params ||= Browser.instance.default_connect_request_params.merge(
|
||||
timeout: 600,
|
||||
connecttimeout: 300,
|
||||
accept_encoding: 'gzip, deflate',
|
||||
cache_ttl: 0,
|
||||
headers: { 'User-Agent' => Browser.instance.default_user_agent, 'Referer' => nil }
|
||||
}
|
||||
headers: { 'User-Agent' => Browser.instance.default_user_agent }
|
||||
)
|
||||
end
|
||||
|
||||
# @return [ String ] The raw file URL associated with the given filename
|
||||
@@ -85,7 +85,7 @@ module WPScan
|
||||
def remote_file_checksum(filename)
|
||||
url = "#{remote_file_url(filename)}.sha512"
|
||||
|
||||
res = Browser.get(url, request_params)
|
||||
res = Typhoeus.get(url, request_params)
|
||||
raise Error::Download, res if res.timed_out? || res.code != 200
|
||||
|
||||
res.body.chomp
|
||||
@@ -126,7 +126,7 @@ module WPScan
|
||||
file_path = local_file_path(filename)
|
||||
file_url = remote_file_url(filename)
|
||||
|
||||
res = Browser.get(file_url, request_params)
|
||||
res = Typhoeus.get(file_url, request_params)
|
||||
raise Error::Download, res if res.timed_out? || res.code != 200
|
||||
|
||||
File.open(file_path, 'wb') { |f| f.write(res.body) }
|
||||
@@ -148,7 +148,7 @@ module WPScan
|
||||
create_backup(filename)
|
||||
dl_checksum = download(filename)
|
||||
|
||||
raise "#{filename}: checksums do not match" unless dl_checksum == db_checksum
|
||||
raise Error::ChecksumsMismatch, filename unless dl_checksum == db_checksum
|
||||
|
||||
updated << filename
|
||||
rescue StandardError => e
|
||||
|
||||
@@ -21,8 +21,10 @@ module WPScan
|
||||
# @return [ Hash ]
|
||||
def self.get(path, params = {})
|
||||
return {} unless token
|
||||
return {} if path.end_with?('/latest') # Remove this when api/v4 is up
|
||||
|
||||
res = Browser.get(uri.join(path), params.merge(request_params))
|
||||
# Typhoeus.get is used rather than Browser.get to avoid merging irrelevant params from the CLI
|
||||
res = Typhoeus.get(uri.join(path), default_request_params.merge(params))
|
||||
|
||||
return {} if res.code == 404 # This is for API inconsistencies when dots in path
|
||||
return JSON.parse(res.body) if NON_ERROR_CODES.include?(res.code)
|
||||
@@ -64,15 +66,14 @@ module WPScan
|
||||
end
|
||||
|
||||
# @return [ Hash ]
|
||||
def self.request_params
|
||||
{
|
||||
# @note Those params can not be overriden by CLI options
|
||||
def self.default_request_params
|
||||
Browser.instance.default_connect_request_params.merge(
|
||||
headers: {
|
||||
'Host' => uri.host, # Reset in case user provided a --vhost for the target
|
||||
'Referer' => nil, # Removes referer set by the cmsscanner to the target url
|
||||
'User-Agent' => Browser.instance.default_user_agent,
|
||||
'Authorization' => "Token token=#{token}"
|
||||
}
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,5 +8,17 @@ module WPScan
|
||||
'Update required, you can not run a scan if a database file is missing.'
|
||||
end
|
||||
end
|
||||
|
||||
class ChecksumsMismatch < Standard
|
||||
attr_reader :db_file
|
||||
|
||||
def initialize(db_file)
|
||||
@db_file = db_file
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#{db_file}: checksums do not match. Please try again in a few minutes."
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -44,19 +44,27 @@ module WPScan
|
||||
#
|
||||
# @param [ Typhoeus::Response ] response
|
||||
# @param [ Hash ] opts
|
||||
# @return [ Mixed ]
|
||||
# @return [ Mixed: nil, Object, Array ]
|
||||
def find(_response, _opts = {})
|
||||
raise NoMethodError
|
||||
end
|
||||
|
||||
# @param [ Hash ] opts
|
||||
# @return [ Mixed ] See #find
|
||||
def passive(opts = {})
|
||||
return if self.class::PATH
|
||||
|
||||
find(target.homepage_res, opts)
|
||||
homepage_result = find(target.homepage_res, opts)
|
||||
|
||||
if homepage_result
|
||||
return homepage_result unless homepage_result.is_a?(Array) && homepage_result.empty?
|
||||
end
|
||||
|
||||
find(target.error_404_res, opts)
|
||||
end
|
||||
|
||||
# @param [ Hash ] opts
|
||||
# @return [ Mixed ] See #find
|
||||
def aggressive(opts = {})
|
||||
return unless self.class::PATH
|
||||
|
||||
|
||||
@@ -31,9 +31,14 @@ module WPScan
|
||||
|
||||
passive_configs.each do |slug, configs|
|
||||
configs.each do |klass, config|
|
||||
item = process_response(opts, target.homepage_res, slug, klass, config)
|
||||
[target.homepage_res, target.error_404_res].each do |page_res|
|
||||
item = process_response(opts, page_res, slug, klass, config)
|
||||
|
||||
found << item if item.is_a?(Model::WpItem)
|
||||
if item.is_a?(Model::WpItem)
|
||||
found << item
|
||||
break # No need to check the other page if detected in the current
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ module WPScan
|
||||
end
|
||||
end
|
||||
|
||||
# This one has been disabled from the DF.yml as it was causing FPs when a plugin had numerous
|
||||
# files matching a known WP version.
|
||||
class WpItemQueryParameter < QueryParameter
|
||||
def xpath
|
||||
@xpath ||=
|
||||
|
||||
@@ -11,7 +11,9 @@ module WPScan
|
||||
module WordPress
|
||||
include CMSScanner::Target::Platform::PHP
|
||||
|
||||
WORDPRESS_PATTERN = %r{/(?:(?:wp-content/(?:themes|(?:mu\-)?plugins|uploads))|wp-includes)/}i.freeze
|
||||
WORDPRESS_PATTERN = %r{/(?:(?:wp-content/(?:themes|(?:mu\-)?plugins|uploads))|wp-includes)/}i.freeze
|
||||
WP_JSON_OEMBED_PATTERN = %r{/wp\-json/oembed/}i.freeze
|
||||
WP_ADMIN_AJAX_PATTERN = %r{\\?/wp\-admin\\?/admin\-ajax\.php}i.freeze
|
||||
|
||||
# These methods are used in the associated interesting_findings finders
|
||||
# to keep the boolean state of the finding rather than re-check the whole thing again
|
||||
@@ -22,22 +24,20 @@ module WPScan
|
||||
|
||||
# @param [ Symbol ] detection_mode
|
||||
#
|
||||
# @return [ Boolean ]
|
||||
# @return [ Boolean ] Whether or not the target is running WordPress
|
||||
def wordpress?(detection_mode)
|
||||
in_scope_uris(homepage_res) do |uri|
|
||||
return true if uri.path.match(WORDPRESS_PATTERN)
|
||||
[homepage_res, error_404_res].each do |page_res|
|
||||
return true if wordpress_from_meta_comments_or_scripts?(page_res)
|
||||
end
|
||||
|
||||
homepage_res.html.css('meta[name="generator"]').each do |node|
|
||||
return true if /wordpress/i.match?(node['content'])
|
||||
end
|
||||
|
||||
return true unless comments_from_page(/wordpress/i, homepage_res).empty?
|
||||
|
||||
if %i[mixed aggressive].include?(detection_mode)
|
||||
%w[wp-admin/install.php wp-login.php].each do |path|
|
||||
in_scope_uris(Browser.get_and_follow_location(url(path))).each do |uri|
|
||||
return true if uri.path.match(WORDPRESS_PATTERN)
|
||||
res = Browser.get_and_follow_location(url(path))
|
||||
|
||||
next unless res.code == 200
|
||||
|
||||
in_scope_uris(res, '//link/@href|//script/@src') do |uri|
|
||||
return true if WORDPRESS_PATTERN.match?(uri.path)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -45,6 +45,26 @@ module WPScan
|
||||
false
|
||||
end
|
||||
|
||||
# @param [ Typhoeus::Response ] response
|
||||
# @return [ Boolean ]
|
||||
def wordpress_from_meta_comments_or_scripts?(response)
|
||||
in_scope_uris(response, '//link/@href|//script/@src') do |uri|
|
||||
return true if WORDPRESS_PATTERN.match?(uri.path) || WP_JSON_OEMBED_PATTERN.match?(uri.path)
|
||||
end
|
||||
|
||||
return true if response.html.css('meta[name="generator"]').any? do |node|
|
||||
/wordpress/i.match?(node['content'])
|
||||
end
|
||||
|
||||
return true unless comments_from_page(/wordpress/i, response).empty?
|
||||
|
||||
return true if response.html.xpath('//script[not(@src)]').any? do |node|
|
||||
WP_ADMIN_AJAX_PATTERN.match?(node.text)
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
COOKIE_PATTERNS = {
|
||||
'vjs' => /createCookie\('vjs','(?<c_value>\d+)',\d+\);/i
|
||||
}.freeze
|
||||
@@ -82,10 +102,11 @@ module WPScan
|
||||
def wordpress_hosted?
|
||||
return true if /\.wordpress\.com$/i.match?(uri.host)
|
||||
|
||||
unless content_dir(:passive)
|
||||
unless content_dir
|
||||
pattern = %r{https?://s\d\.wp\.com#{WORDPRESS_PATTERN}}i.freeze
|
||||
xpath = '(//@href|//@src)[contains(., "wp.com")]'
|
||||
|
||||
uris_from_page(homepage_res) do |uri|
|
||||
uris_from_page(homepage_res, xpath) do |uri|
|
||||
return true if uri.to_s.match?(pattern)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,25 +13,24 @@ module WPScan
|
||||
@plugins_dir = dir.chomp('/')
|
||||
end
|
||||
|
||||
# @param [ Symbol ] detection_mode
|
||||
# @return [ String ] The wp-content directory
|
||||
def content_dir(detection_mode = :mixed)
|
||||
def content_dir
|
||||
unless @content_dir
|
||||
# scope_url_pattern is from CMSScanner::Target
|
||||
pattern = %r{#{scope_url_pattern}([\w\s\-/]+)\\?/(?:themes|plugins|uploads|cache)\\?/}i
|
||||
pattern = %r{#{scope_url_pattern}([\w\s\-/]+?)\\?/(?:themes|plugins|uploads|cache)\\?/}i
|
||||
|
||||
in_scope_uris(homepage_res) do |uri|
|
||||
return @content_dir = Regexp.last_match[1] if uri.to_s.match(pattern)
|
||||
[homepage_res, error_404_res].each do |page_res|
|
||||
in_scope_uris(page_res, '//link/@href|//script/@src|//img/@src') do |uri|
|
||||
return @content_dir = Regexp.last_match[1] if uri.to_s.match(pattern)
|
||||
end
|
||||
|
||||
# Checks for the pattern in raw JS code, as well as @content attributes of meta tags
|
||||
xpath_pattern_from_page('//script[not(@src)]|//meta/@content', pattern, page_res) do |match|
|
||||
return @content_dir = match[1]
|
||||
end
|
||||
end
|
||||
|
||||
# Checks for the pattern in raw JS code, as well as @content attributes of meta tags
|
||||
xpath_pattern_from_page('//script[not(@src)]|//meta/@content', pattern, homepage_res) do |match|
|
||||
return @content_dir = match[1]
|
||||
end
|
||||
|
||||
unless detection_mode == :passive
|
||||
return @content_dir = 'wp-content' if default_content_dir_exists?
|
||||
end
|
||||
return @content_dir = 'wp-content' if default_content_dir_exists?
|
||||
end
|
||||
|
||||
@content_dir
|
||||
@@ -72,7 +71,7 @@ module WPScan
|
||||
#
|
||||
# @return [ String ]
|
||||
def plugin_url(slug)
|
||||
plugins_uri.join("#{URI.encode(slug)}/").to_s
|
||||
plugins_uri.join("#{Addressable::URI.encode(slug)}/").to_s
|
||||
end
|
||||
|
||||
# @return [ String ]
|
||||
@@ -94,7 +93,7 @@ module WPScan
|
||||
#
|
||||
# @return [ String ]
|
||||
def theme_url(slug)
|
||||
themes_uri.join("#{URI.encode(slug)}/").to_s
|
||||
themes_uri.join("#{Addressable::URI.encode(slug)}/").to_s
|
||||
end
|
||||
|
||||
# @return [ String, False ] String of the sub_dir found, false otherwise
|
||||
@@ -106,9 +105,12 @@ module WPScan
|
||||
|
||||
# url_pattern is from CMSScanner::Target
|
||||
pattern = %r{#{url_pattern}(.+?)/(?:xmlrpc\.php|wp\-includes/)}i
|
||||
xpath = '(//@src|//@href|//@data-src)[contains(., "xmlrpc.php") or contains(., "wp-includes/")]'
|
||||
|
||||
in_scope_uris(homepage_res) do |uri|
|
||||
return @sub_dir = Regexp.last_match[1] if uri.to_s.match(pattern)
|
||||
[homepage_res, error_404_res].each do |page_res|
|
||||
in_scope_uris(page_res, xpath) do |uri|
|
||||
return @sub_dir = Regexp.last_match[1] if uri.to_s.match(pattern)
|
||||
end
|
||||
end
|
||||
|
||||
@sub_dir = false
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
# Version
|
||||
module WPScan
|
||||
VERSION = '3.7.1'
|
||||
VERSION = '3.7.10'
|
||||
end
|
||||
|
||||
@@ -166,6 +166,7 @@ describe WPScan::Controller::Core do
|
||||
before do
|
||||
expect(core).to receive(:load_server_module)
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true)
|
||||
expect(core.target).to receive(:wordpress_hosted?).and_return(false)
|
||||
end
|
||||
|
||||
it 'calls the formatter when started and finished to update the db' do
|
||||
@@ -174,56 +175,6 @@ describe WPScan::Controller::Core do
|
||||
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::Error::HTTPRedirect)
|
||||
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?).with(:mixed).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?).twice.with(:mixed).and_return(false)
|
||||
|
||||
expect { core.before_scan }.to raise_error(WPScan::Error::NotWordPress)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when hosted on wordpress.com' do
|
||||
let(:target_url) { 'http://ex.wordpress.com' }
|
||||
|
||||
@@ -234,52 +185,106 @@ describe WPScan::Controller::Core do
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wordpress' do
|
||||
before do
|
||||
expect(core).to receive(:load_server_module)
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true)
|
||||
end
|
||||
context 'when not hosted on wordpress.com' do
|
||||
before { allow(core.target).to receive(:wordpress_hosted?).and_return(false) }
|
||||
|
||||
it 'does not raise any error' do
|
||||
expect { core.before_scan }.to_not raise_error
|
||||
end
|
||||
end
|
||||
context 'when a redirect occurs' do
|
||||
before do
|
||||
stub_request(:any, target_url)
|
||||
|
||||
context 'when not wordpress' do
|
||||
before do
|
||||
expect(core).to receive(:load_server_module)
|
||||
end
|
||||
expect(core.target).to receive(:homepage_res)
|
||||
.at_least(1)
|
||||
.and_return(Typhoeus::Response.new(effective_url: redirection, body: ''))
|
||||
end
|
||||
|
||||
context 'when no --force' do
|
||||
before { expect(core.target).to receive(:maybe_add_cookies) }
|
||||
context 'to the wp-admin/install.php' do
|
||||
let(:redirection) { "#{target_url}wp-admin/install.php" }
|
||||
|
||||
context 'when no cookies added or still not wordpress after being added' do
|
||||
it 'raises an error' do
|
||||
expect(core.target).to receive(:wordpress?).twice.with(:mixed).and_return(false)
|
||||
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
|
||||
|
||||
expect { core.before_scan }.to raise_error(WPScan::Error::NotWordPress)
|
||||
# TODO: Would be cool to be able to test the exit code
|
||||
expect { core.before_scan }.to raise_error(SystemExit)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the added cookies solved it' do
|
||||
it 'does not raise an error' do
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(false).ordered
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true).ordered
|
||||
context 'to something else' do
|
||||
let(:redirection) { 'http://g.com/' }
|
||||
|
||||
it 'raises an error' do
|
||||
expect { core.before_scan }.to raise_error(CMSScanner::Error::HTTPRedirect)
|
||||
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?).with(:mixed).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?).twice.with(:mixed).and_return(false)
|
||||
|
||||
expect { core.before_scan }.to raise_error(WPScan::Error::NotWordPress)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wordpress' do
|
||||
before do
|
||||
expect(core).to receive(:load_server_module)
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).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)
|
||||
end
|
||||
|
||||
context 'when no --force' do
|
||||
before { expect(core.target).to receive(:maybe_add_cookies) }
|
||||
|
||||
context 'when no cookies added or still not wordpress after being added' do
|
||||
it 'raises an error' do
|
||||
expect(core.target).to receive(:wordpress?).twice.with(:mixed).and_return(false)
|
||||
|
||||
expect { core.before_scan }.to raise_error(WPScan::Error::NotWordPress)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the added cookies solved it' do
|
||||
it 'does not raise an error' do
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(false).ordered
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true).ordered
|
||||
|
||||
expect { core.before_scan }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when --force' do
|
||||
let(:cli_args) { "#{super()} --force" }
|
||||
|
||||
it 'does not raise any error' do
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(false)
|
||||
|
||||
expect { core.before_scan }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when --force' do
|
||||
let(:cli_args) { "#{super()} --force" }
|
||||
|
||||
it 'does not raise any error' do
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(false)
|
||||
|
||||
expect { core.before_scan }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,7 +20,7 @@ describe WPScan::Controller::CustomDirectories do
|
||||
|
||||
describe '#before_scan' do
|
||||
context 'when the content_dir is not found and not supplied' do
|
||||
before { expect(controller.target).to receive(:content_dir).with(:mixed) }
|
||||
before { expect(controller.target).to receive(:content_dir).and_return(nil) }
|
||||
|
||||
it 'raises an exception' do
|
||||
expect { controller.before_scan }.to raise_error(WPScan::Error::WpContentDirNotDetected)
|
||||
|
||||
@@ -74,20 +74,40 @@ describe WPScan::Controller::VulnApi do
|
||||
context 'when limited requests' do
|
||||
let(:requests) { 100 }
|
||||
|
||||
it 'does not raise an error' do
|
||||
it 'sets the token and does not raise an error' do
|
||||
expect { controller.before_scan }.to_not raise_error
|
||||
|
||||
expect(WPScan::DB::VulnApi.token).to eql 'token'
|
||||
end
|
||||
|
||||
context 'when unlimited requests' do
|
||||
let(:requests) { 'Unlimited' }
|
||||
|
||||
it 'does not raise an error' do
|
||||
it 'sets the token and does not raise an error' do
|
||||
expect { controller.before_scan }.to_not raise_error
|
||||
|
||||
expect(WPScan::DB::VulnApi.token).to eql 'token'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when token in ENV' do
|
||||
before do
|
||||
ENV[described_class::ENV_KEY] = 'token-from-env'
|
||||
|
||||
expect(WPScan::DB::VulnApi)
|
||||
.to receive(:status)
|
||||
.and_return('success' => true, 'plan' => 'free', 'requests_remaining' => 'Unlimited')
|
||||
end
|
||||
|
||||
it 'sets the token and does not raise an error' do
|
||||
expect { controller.before_scan }.to_not raise_error
|
||||
|
||||
expect(WPScan::DB::VulnApi.token).to eql 'token-from-env'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,7 +9,7 @@ describe WPScan::Finders::DbExports::KnownLocations do
|
||||
|
||||
describe '#potential_urls' do
|
||||
before do
|
||||
expect(target).to receive(:sub_dir).at_least(1).and_return(false)
|
||||
allow(target).to receive(:sub_dir).and_return(false)
|
||||
end
|
||||
|
||||
it 'replace {domain_name} by its value' do
|
||||
@@ -22,11 +22,45 @@ describe WPScan::Finders::DbExports::KnownLocations do
|
||||
http://ex.lo/aa/backups/db_backup.sql
|
||||
]
|
||||
end
|
||||
|
||||
%w[dev poc www].each do |sub_domain|
|
||||
context "when #{sub_domain} sub-domain" do
|
||||
let(:url) { "https://#{sub_domain}.domain.tld" }
|
||||
|
||||
it 'replace {domain_name} by its correct value' do
|
||||
expect(finder.potential_urls(opts).keys).to include "#{url}/domain.sql"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when multi-level tlds' do
|
||||
let(:url) { 'https://something.com.tr' }
|
||||
|
||||
it 'replace {domain_name} by its correct value' do
|
||||
expect(finder.potential_urls(opts).keys).to include 'https://something.com.tr/something.sql'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when multi-level tlds and sub-domain' do
|
||||
let(:url) { 'https://dev.something.com.tr' }
|
||||
|
||||
it 'replace {domain_name} by its correct value' do
|
||||
expect(finder.potential_urls(opts).keys).to include 'https://dev.something.com.tr/something.sql'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when some weird stuff' do
|
||||
let(:url) { 'https://098f6bcd4621d373cade4e832627b4f6.aa-bb-ccc-dd.domain-test.com' }
|
||||
|
||||
it 'replace {domain_name} by its correct value' do
|
||||
expect(finder.potential_urls(opts).keys).to include "#{url}/domain-test.sql"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#aggressive' do
|
||||
before do
|
||||
expect(target).to receive(:sub_dir).at_least(1).and_return(false)
|
||||
allow(target).to receive(:sub_dir).and_return(false)
|
||||
expect(target).to receive(:head_or_get_params).and_return(method: :head)
|
||||
|
||||
finder.potential_urls(opts).each_key do |url|
|
||||
|
||||
@@ -6,8 +6,55 @@ describe WPScan::Finders::InterestingFindings::MuPlugins do
|
||||
let(:url) { 'http://ex.lo/' }
|
||||
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'mu_plugins') }
|
||||
|
||||
before do
|
||||
expect(target).to receive(:content_dir).at_least(1).and_return('wp-content')
|
||||
end
|
||||
|
||||
describe '#passive' do
|
||||
xit
|
||||
before { stub_request(:get, url).to_return(body: body) }
|
||||
|
||||
context 'when no uris' do
|
||||
let(:body) { '' }
|
||||
|
||||
its(:passive) { should be nil }
|
||||
end
|
||||
|
||||
context 'when a large amount of unrelated uris' do
|
||||
let(:body) do
|
||||
Array.new(250) { |i| "<a href='#{url}#{i}.html'>Some Link</a><img src='#{url}img-#{i}.png'/>" }.join("\n")
|
||||
end
|
||||
|
||||
it 'should not take a while to process the page' do
|
||||
time_start = Time.now
|
||||
result = finder.passive
|
||||
time_end = Time.now
|
||||
|
||||
expect(result).to be nil
|
||||
expect(time_end - time_start).to be < 1
|
||||
end
|
||||
end
|
||||
|
||||
context 'when uris' do
|
||||
let(:body) { File.read(fixtures.join(fixture)) }
|
||||
|
||||
context 'when none matching' do
|
||||
let(:fixture) { 'no_match.html' }
|
||||
|
||||
its(:passive) { should be nil }
|
||||
end
|
||||
|
||||
context 'when matching via href' do
|
||||
let(:fixture) { 'match_href.html' }
|
||||
|
||||
its(:passive) { should be_a WPScan::Model::MuPlugins }
|
||||
end
|
||||
|
||||
context 'when matching from src' do
|
||||
let(:fixture) { 'match_src.html' }
|
||||
|
||||
its(:passive) { should be_a WPScan::Model::MuPlugins }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#aggressive' do
|
||||
|
||||
11
spec/app/finders/main_theme/css_style_in_404_page_spec.rb
Normal file
11
spec/app/finders/main_theme/css_style_in_404_page_spec.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe WPScan::Finders::MainTheme::CssStyleIn404Page 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) { FINDERS_FIXTURES.join('main_theme', 'css_style_in_404_page') }
|
||||
|
||||
# This stuff is just a child class of CssStyleInHomepage (using the error_404_res rather than homepage_res)
|
||||
# which already has a spec
|
||||
end
|
||||
@@ -1,10 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe WPScan::Finders::MainTheme::CssStyle do
|
||||
describe WPScan::Finders::MainTheme::CssStyleInHomepage 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) { FINDERS_FIXTURES.join('main_theme', 'css_style') }
|
||||
let(:fixtures) { FINDERS_FIXTURES.join('main_theme', 'css_style_in_homepage') }
|
||||
|
||||
describe '#passive' do
|
||||
after do
|
||||
@@ -33,7 +33,7 @@ describe WPScan::Finders::MainTheme::CssStyle do
|
||||
@expected = WPScan::Model::Theme.new(
|
||||
'twentyfifteen',
|
||||
target,
|
||||
found_by: 'Css Style (Passive Detection)',
|
||||
found_by: 'Css Style In Homepage (Passive Detection)',
|
||||
confidence: 70,
|
||||
style_url: 'http://wp.lab/wp-content/themes/twentyfifteen/style.css?ver=4.1.1'
|
||||
)
|
||||
@@ -47,7 +47,7 @@ describe WPScan::Finders::MainTheme::CssStyle do
|
||||
@expected = WPScan::Model::Theme.new(
|
||||
'custom',
|
||||
target,
|
||||
found_by: 'Css Style (Passive Detection)',
|
||||
found_by: 'Css Style In Homepage (Passive Detection)',
|
||||
confidence: 70,
|
||||
style_url: 'http://wp.lab/wp-content/themes/custom/style.css'
|
||||
)
|
||||
11
spec/app/finders/main_theme/urls_in_404_page_spec.rb.rb
Normal file
11
spec/app/finders/main_theme/urls_in_404_page_spec.rb.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe WPScan::Finders::MainTheme::UrlsIn404Page do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
let(:url) { 'http://wp.lab/' }
|
||||
let(:fixtures) { FINDERS_FIXTURES.join('main_theme', 'urls_in_404_page') }
|
||||
|
||||
# This stuff is just a child class of URLsInHomepage (using the error_404_res rather than homepage_res)
|
||||
# which already has a spec
|
||||
end
|
||||
@@ -6,7 +6,8 @@ describe WPScan::Finders::MainTheme::UrlsInHomepage do
|
||||
let(:url) { 'http://wp.lab/' }
|
||||
let(:fixtures) { FINDERS_FIXTURES.join('main_theme', 'urls_in_homepage') }
|
||||
|
||||
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
|
||||
it_behaves_like 'App::Finders::WpItems::UrlsInPage' do
|
||||
let(:page_url) { url }
|
||||
let(:type) { 'themes' }
|
||||
let(:uniq_links) { false }
|
||||
let(:uniq_codes) { false }
|
||||
@@ -18,6 +19,8 @@ describe WPScan::Finders::MainTheme::UrlsInHomepage do
|
||||
before do
|
||||
stub_request(:get, /.*.css/)
|
||||
stub_request(:get, target.url).to_return(body: File.read(fixtures.join('found.html')))
|
||||
|
||||
allow(target).to receive(:content_dir).and_return('wp-content')
|
||||
end
|
||||
|
||||
it 'returns the expected Themes' do
|
||||
|
||||
@@ -7,32 +7,50 @@ describe WPScan::Finders::MainTheme::WooFrameworkMetaGenerator do
|
||||
let(:fixtures) { FINDERS_FIXTURES.join('main_theme', 'woo_framework_meta_generator') }
|
||||
|
||||
describe '#passive' do
|
||||
after do
|
||||
stub_request(:get, url).to_return(body: File.read(fixtures.join(@file)))
|
||||
|
||||
expect(finder.passive).to eql @expected
|
||||
before do
|
||||
stub_request(:get, url).to_return(body: File.read(fixtures.join(homepage_fixture)))
|
||||
stub_request(:get, ERROR_404_URL_PATTERN).to_return(body: File.read(fixtures.join(error_404_fixture)))
|
||||
end
|
||||
|
||||
context 'when no Woo generator' do
|
||||
let(:homepage_fixture) { 'no_woo_generator.html' }
|
||||
let(:error_404_fixture) { 'no_woo_generator.html' }
|
||||
|
||||
it 'returns nil' do
|
||||
@file = 'no_woo_generator.html'
|
||||
@expected = nil
|
||||
expect(finder.passive).to eql nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when Woo generator' do
|
||||
before do
|
||||
expect(target).to receive(:content_dir).at_least(1).and_return('wp-content')
|
||||
allow(target).to receive(:content_dir).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::Model::Theme.new(
|
||||
'Merchant', target,
|
||||
found_by: 'Woo Framework Meta Generator (Passive Detection)',
|
||||
confidence: 80
|
||||
)
|
||||
context 'from the homepage' do
|
||||
let(:homepage_fixture) { 'woo_generator.html' }
|
||||
let(:error_404_fixture) { 'no_woo_generator.html' }
|
||||
|
||||
it 'returns the expected theme' do
|
||||
expect(finder.passive).to eql WPScan::Model::Theme.new(
|
||||
'Merchant', target,
|
||||
found_by: 'Woo Framework Meta Generator (Passive Detection)',
|
||||
confidence: 80
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'from the 404 page' do
|
||||
let(:homepage_fixture) { 'no_woo_generator.html' }
|
||||
let(:error_404_fixture) { 'woo_generator.html' }
|
||||
|
||||
it 'returns the expected theme' do
|
||||
expect(finder.passive).to eql WPScan::Model::Theme.new(
|
||||
'Merchant', target,
|
||||
found_by: 'Woo Framework Meta Generator (Passive Detection)',
|
||||
confidence: 80
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@ describe WPScan::Finders::MainTheme::Base do
|
||||
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]
|
||||
.to eq %w[CssStyleInHomepage CssStyleIn404Page WooFrameworkMetaGenerator UrlsInHomepage UrlsIn404Page]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
11
spec/app/finders/plugins/urls_in_404_page_spec.rb
Normal file
11
spec/app/finders/plugins/urls_in_404_page_spec.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe WPScan::Finders::Plugins::UrlsIn404Page do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
let(:url) { 'https://wp.lab/' }
|
||||
let(:fixtures) { FINDERS_FIXTURES.join('plugins', 'urls_in_404_page') }
|
||||
|
||||
# This stuff is just a child class of URLsInHomepage (using the error_404_res rather than homepage_res)
|
||||
# which already has a spec
|
||||
end
|
||||
@@ -3,14 +3,17 @@
|
||||
describe WPScan::Finders::Plugins::UrlsInHomepage do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
let(:url) { 'http://wp.lab/' }
|
||||
let(:url) { 'https://wp.lab/' }
|
||||
let(:fixtures) { FINDERS_FIXTURES.join('plugins', 'urls_in_homepage') }
|
||||
|
||||
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
|
||||
before { target.scope << 'sub.lab' }
|
||||
|
||||
it_behaves_like 'App::Finders::WpItems::UrlsInPage' do
|
||||
let(:page_url) { url }
|
||||
let(:type) { 'plugins' }
|
||||
let(:uniq_links) { true }
|
||||
let(:uniq_codes) { true }
|
||||
let(:expected_from_links) { (1..4).map { |i| "dl-#{i}" } }
|
||||
let(:expected_from_links) { (1..5).map { |i| "dl-#{i}" } }
|
||||
let(:expected_from_codes) { (1..6).map { |i| "dc-#{i}" } }
|
||||
end
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ describe WPScan::Finders::Plugins::Base do
|
||||
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]
|
||||
.to eq %w[UrlsInHomepage UrlsIn404Page HeaderPattern Comment Xpath BodyPattern JavascriptVar KnownLocations]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
11
spec/app/finders/themes/urls_in_404_page_spec.rb
Normal file
11
spec/app/finders/themes/urls_in_404_page_spec.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe WPScan::Finders::Themes::UrlsIn404Page do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
let(:url) { 'http://wp.lab/' }
|
||||
let(:fixtures) { FINDERS_FIXTURES.join('themes', 'urls_in_404_page') }
|
||||
|
||||
# This stuff is just a child class of URLsInHomepage (using the error_404_res rather than homepage_res)
|
||||
# which already has a spec
|
||||
end
|
||||
@@ -6,7 +6,10 @@ describe WPScan::Finders::Themes::UrlsInHomepage do
|
||||
let(:url) { 'http://wp.lab/' }
|
||||
let(:fixtures) { FINDERS_FIXTURES.join('themes', 'urls_in_homepage') }
|
||||
|
||||
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
|
||||
# before { target.scope << 'sub.lab' }
|
||||
|
||||
it_behaves_like 'App::Finders::WpItems::UrlsInPage' do
|
||||
let(:page_url) { url }
|
||||
let(:type) { 'themes' }
|
||||
let(:uniq_links) { true }
|
||||
let(:uniq_codes) { true }
|
||||
|
||||
@@ -8,7 +8,7 @@ describe WPScan::Finders::Themes::Base do
|
||||
describe '#finders' do
|
||||
it 'contains the expected finders' do
|
||||
expect(themes.finders.map { |f| f.class.to_s.demodulize })
|
||||
.to eq %w[UrlsInHomepage KnownLocations]
|
||||
.to eq %w[UrlsInHomepage UrlsIn404Page KnownLocations]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,7 +19,7 @@ describe WPScan::Finders::Users::AuthorIdBruteForcing do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#potential_username' do
|
||||
describe '#username_from_response' do
|
||||
[
|
||||
'4.1.1', '4.1.1-permalink',
|
||||
'3.0', '3.0-permalink',
|
||||
@@ -32,6 +32,19 @@ describe WPScan::Finders::Users::AuthorIdBruteForcing do
|
||||
expect(finder.username_from_response(res)).to eql 'admin'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a lot of unrelated links' do
|
||||
it 'should not take a while to process the page' do
|
||||
body = Array.new(300) { |i| "<a href='#{url}#{i}.html'>Some Link</a>" }.join("\n")
|
||||
body << '<a href="https://wp.lab/author/test/">Link</a>'
|
||||
|
||||
time_start = Time.now
|
||||
expect(finder.username_from_response(Typhoeus::Response.new(body: body))).to eql 'test'
|
||||
time_end = Time.now
|
||||
|
||||
expect(time_end - time_start).to be < 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#display_name_from_body' do
|
||||
@@ -50,7 +63,7 @@ describe WPScan::Finders::Users::AuthorIdBruteForcing do
|
||||
end
|
||||
|
||||
context 'when no display_name' do
|
||||
['4.1.1', '3.0', '2.9.2'].each do |file|
|
||||
%w[4.9-span-tag 4.1.1 3.0 2.9.2].each do |file|
|
||||
it "returns nil for #{file}-empty.html" do
|
||||
body = File.read(fixtures.join("#{file}-empty.html"))
|
||||
|
||||
|
||||
@@ -16,12 +16,31 @@ describe WPScan::Finders::Users::AuthorPosts do
|
||||
|
||||
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]
|
||||
])
|
||||
expect(results).to eql [
|
||||
['admin', 'Author Pattern', 100],
|
||||
['admin display_name', 'Display Name', 30],
|
||||
['editor', 'Author Pattern', 100],
|
||||
['editor', 'Display Name', 30]
|
||||
]
|
||||
end
|
||||
|
||||
context 'when a lot of unrelated uris' do
|
||||
it 'should not take a while to process the page' do
|
||||
body = Array.new(300) { |i| "<a href='#{url}#{i}.html'>Some Link</a>" }.join("\n")
|
||||
body << "<a href='#{url}author/admin/'>Other Link</a>"
|
||||
body << "<a href='#{url}?author=2'>user display name</a>"
|
||||
|
||||
time_start = Time.now
|
||||
results = finder.potential_usernames(Typhoeus::Response.new(body: body))
|
||||
time_end = Time.now
|
||||
|
||||
expect(results).to eql [
|
||||
['admin', 'Author Pattern', 100],
|
||||
['user display name', 'Display Name', 30]
|
||||
]
|
||||
|
||||
expect(time_end - time_start).to be < 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,15 +19,17 @@ describe WPScan::Finders::Users::OembedApi do
|
||||
end
|
||||
|
||||
context 'when a JSON response' do
|
||||
let(:body) { File.read(fixture) }
|
||||
|
||||
context 'when 404' do
|
||||
let(:body) { File.read(fixtures.join('404.json')) }
|
||||
let(:fixture) { fixtures.join('404.json') }
|
||||
|
||||
its(:aggressive) { should eql([]) }
|
||||
end
|
||||
|
||||
context 'when 200' do
|
||||
context 'when author_url present' do
|
||||
let(:body) { File.read(fixtures.join('200_author_url.json')) }
|
||||
let(:fixture) { fixtures.join('200_author_url.json') }
|
||||
|
||||
it 'returns the expected array of users' do
|
||||
users = finder.aggressive
|
||||
@@ -44,7 +46,7 @@ describe WPScan::Finders::Users::OembedApi do
|
||||
end
|
||||
|
||||
context 'when author_url not present but author_name' do
|
||||
let(:body) { File.read(fixtures.join('200_author_name.json')) }
|
||||
let(:fixture) { fixtures.join('200_author_name.json') }
|
||||
|
||||
it 'returns the expected array of users' do
|
||||
users = finder.aggressive
|
||||
@@ -59,6 +61,12 @@ describe WPScan::Finders::Users::OembedApi do
|
||||
expect(user.interesting_entries).to eql ['http://wp.lab/wp-json/oembed/1.0/embed?url=http://wp.lab/&format=json']
|
||||
end
|
||||
end
|
||||
|
||||
context 'when body is an array' do
|
||||
let(:fixture) { fixtures.join('array.json') }
|
||||
|
||||
its(:aggressive) { should eql([]) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -87,6 +87,8 @@ describe WPScan::Finders::Users::WpJsonApi do
|
||||
describe '#api_url' do
|
||||
let(:fixtures) { super().join('api_url') }
|
||||
|
||||
before { allow(target).to receive(:sub_dir).and_return(false) }
|
||||
|
||||
context 'when url in the homepage' do
|
||||
{
|
||||
in_scope: 'https://wp.lab/wp-json/wp/v2/users/',
|
||||
@@ -100,7 +102,7 @@ describe WPScan::Finders::Users::WpJsonApi do
|
||||
end
|
||||
|
||||
context 'when subdir' do
|
||||
before { allow(target).to receive(:subdir).and_return('cms') }
|
||||
before { allow(target).to receive(:sub_dir).and_return('cms') }
|
||||
|
||||
{
|
||||
in_scope_subdir: 'https://wp.lab/cms/wp-json/wp/v2/users/',
|
||||
|
||||
@@ -10,10 +10,9 @@ describe WPScan::Model::Theme do
|
||||
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(fixtures.join('style.css')))
|
||||
end
|
||||
before { stub_request(:get, /.*\.css\z/).to_return(body: File.read(fixture)) }
|
||||
|
||||
let(:fixture) { fixtures.join('style.css') }
|
||||
|
||||
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' }
|
||||
@@ -34,6 +33,14 @@ describe WPScan::Model::Theme do
|
||||
|
||||
its(:style_url) { should eql opts[:style_url] }
|
||||
end
|
||||
|
||||
context 'when some new lines are stripped' do
|
||||
let(:fixture) { fixtures.join('stripped_new_lines.css') }
|
||||
|
||||
its(:style_name) { should eql 'Divi' }
|
||||
its(:style_uri) { should eql 'http://www.elegantthemes.com/gallery/divi/' }
|
||||
its(:license_uri) { should eql 'http://www.gnu.org/licenses/gpl-2.0.html' }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#version' do
|
||||
|
||||
@@ -46,7 +46,7 @@ describe WPScan::Model::WpItem do
|
||||
end
|
||||
|
||||
it 'encodes the path' do
|
||||
expect(wp_item.url('#t#')).to eql "#{item_url}%23t%23"
|
||||
expect(wp_item.url('#t#')).to eql "#{item_url}#t%23"
|
||||
expect(wp_item.url('t .txt')).to eql "#{item_url}t%20.txt"
|
||||
end
|
||||
end
|
||||
|
||||
2
spec/cache/.gitignore
vendored
2
spec/cache/.gitignore
vendored
@@ -1,4 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
!.gitignore
|
||||
|
||||
34326
spec/fixtures/db/dynamic_finders.yml
vendored
34326
spec/fixtures/db/dynamic_finders.yml
vendored
File diff suppressed because it is too large
Load Diff
4943
spec/fixtures/dynamic_finders/expected.yml
vendored
4943
spec/fixtures/dynamic_finders/expected.yml
vendored
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,94 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Woo Pelecard v1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-07-07 07:09+0200\n"
|
||||
"PO-Revision-Date: 2014-07-07 07:09+0200\n"
|
||||
"Last-Translator: Tzvi Rabinovitch <tzvi.ra@gmail.com>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: he_IL\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Poedit 1.5.4\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;"
|
||||
"_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2\n"
|
||||
"X-Poedit-Basepath: .\n"
|
||||
"X-Textdomain-Support: yes\n"
|
||||
"X-Poedit-SearchPath-0: ..\n"
|
||||
|
||||
#: ../10bit-easycard-paybuttons-options.php:18
|
||||
msgid "Settings saved."
|
||||
msgstr "שמרתי את ההגדרות."
|
||||
|
||||
#: ../10bit-easycard-paybuttons-options.php:23
|
||||
msgid "10Bit EasyCard PayButtons Settings"
|
||||
msgstr "כפתורי תשלום איזיקארד"
|
||||
|
||||
#: ../10bit-easycard-paybuttons-options.php:37
|
||||
msgid "Client ID"
|
||||
msgstr "מזהה לקוח"
|
||||
|
||||
# @ TenBit_woo_pelecard
|
||||
#: ../10bit-easycard-paybuttons-options.php:45
|
||||
msgid "Password"
|
||||
msgstr "סיסמה"
|
||||
|
||||
#: ../10bit-easycard-paybuttons-options.php:53
|
||||
msgid "Maximum Payments"
|
||||
msgstr "מספר תשלמים מקסימלי"
|
||||
|
||||
#: ../10bit-easycard-paybuttons-options.php:64
|
||||
msgid "Save Changes"
|
||||
msgstr "שמור שינויים"
|
||||
|
||||
#: ../10bit-easycard-paybuttons-options.php:70
|
||||
msgid "Usage :"
|
||||
msgstr "שימוש"
|
||||
|
||||
#: ../10bit-easycard-paybuttons-options.php:72
|
||||
msgid "Add the folloing short code inside a post or a page :"
|
||||
msgstr "הוסיפו את השורטקוד הבא לדף או לעמוד באתר"
|
||||
|
||||
#: ../10bit-easycard-paybuttons-options.php:76
|
||||
msgid "value : The amount to pay"
|
||||
msgstr "value : הסכום לתשלום"
|
||||
|
||||
#: ../10bit-easycard-paybuttons-options.php:78
|
||||
msgid "item_name : the name of the sold item"
|
||||
msgstr "item_name : שם המוצר למכירה"
|
||||
|
||||
#: ../10bit-easycard-paybuttons-options.php:80
|
||||
msgid "button_class : CSS class for styling"
|
||||
msgstr "button_class : קלאס CSS לעיצוב"
|
||||
|
||||
#: ../10bit-easycard-paybuttons-options.php:82
|
||||
msgid "button_text : Text to show on the button"
|
||||
msgstr "button_text : הטקסט שיופיע על הכפתור"
|
||||
|
||||
#: ../10bit-paybuttons-easycard.php:29
|
||||
msgid "EasyCard Pay Buttons"
|
||||
msgstr "כפתורי תשלום איזיקארד"
|
||||
|
||||
# @ TenBit_woo_pelecard
|
||||
#~ msgid "License Key"
|
||||
#~ msgstr "מפתח"
|
||||
|
||||
#~ msgid "Valid"
|
||||
#~ msgstr "תקין"
|
||||
|
||||
#~ msgid "Invalid"
|
||||
#~ msgstr "לא תקין"
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Leave blank for not sending a copy"
|
||||
#~ msgstr "השאר ריק במידה ואינך מעוניים בהעתק"
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "10Bit iCount Settings"
|
||||
#~ msgstr "הגדרות icount"
|
||||
|
||||
#~ msgid "Easycard"
|
||||
#~ msgstr "איזיקארד"
|
||||
@@ -0,0 +1,132 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Woo Pelecard v1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-07-09 01:31+0200\n"
|
||||
"PO-Revision-Date: 2014-07-09 01:32+0200\n"
|
||||
"Last-Translator: Tzvi Rabinovitch <tzvi.ra@gmail.com>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: he_IL\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Poedit 1.5.4\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;"
|
||||
"_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2\n"
|
||||
"X-Poedit-Basepath: .\n"
|
||||
"X-Textdomain-Support: yes\n"
|
||||
"X-Poedit-SearchPath-0: ..\n"
|
||||
|
||||
# @ TenBit_woo_pelecard
|
||||
#: ../10bit-paybuttons-pelecard.php:28
|
||||
msgid "pelecard Pay Buttons"
|
||||
msgstr "כפתורי תשלום פלאכארד"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:68
|
||||
msgid "Settings saved."
|
||||
msgstr "שמרתי את ההגדרות."
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:73
|
||||
msgid "10Bit pelecard PayButtons Settings"
|
||||
msgstr "כפתורי תשלום פלאכארד"
|
||||
|
||||
# @ TenBit_woo_pelecard
|
||||
#: ../10bit-pelecard-paybuttons-options.php:87
|
||||
msgid "Terminal Number"
|
||||
msgstr "מספר מסוף סליקה"
|
||||
|
||||
# @ TenBit_woo_pelecard
|
||||
#: ../10bit-pelecard-paybuttons-options.php:95
|
||||
msgid "Username"
|
||||
msgstr "שם משתמש"
|
||||
|
||||
# @ TenBit_woo_pelecard
|
||||
#: ../10bit-pelecard-paybuttons-options.php:103
|
||||
msgid "Password"
|
||||
msgstr "סיסמה"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:111
|
||||
msgid "Maximum Payments"
|
||||
msgstr "מספר תשלמים מקסימלי"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:119
|
||||
msgid "Currency"
|
||||
msgstr "מטבע"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:123
|
||||
msgid "ILS"
|
||||
msgstr "ש\"ח"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:124
|
||||
msgid "USD"
|
||||
msgstr "דולר"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:130
|
||||
msgid "Success ( thank you ) page URL"
|
||||
msgstr "כתובת הצלחה ( דף תודה )"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:138
|
||||
msgid "Error page URL"
|
||||
msgstr "כתובת כשלון"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:146
|
||||
msgid "Path to custom logo"
|
||||
msgstr "קישור ללוגו "
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:154
|
||||
msgid "Path to small custom logo"
|
||||
msgstr "קישור ללוגו קטן "
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:162
|
||||
msgid "Hide PCI DSS logo"
|
||||
msgstr "הסתר את הלוגו של PCI DSS"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:170
|
||||
msgid "Hide Pelecard logo"
|
||||
msgstr "הסתר את לוגו פלאכארד"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:178
|
||||
msgid "Path To custom Style sheet(CSS)"
|
||||
msgstr "כתובת כשלון"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:183
|
||||
msgid "must be a secured URL ( HTTPS )"
|
||||
msgstr "חייב להיות מכתובת מאובטחת (HTTPS )"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:189
|
||||
msgid "Background color"
|
||||
msgstr "צבע רקע"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:195
|
||||
msgid "Use hexadecimal color without the #"
|
||||
msgstr "ערך הקסדצימלי ללא #"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:217
|
||||
msgid "Save Changes"
|
||||
msgstr "שמור שינויים"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:223
|
||||
msgid "Usage :"
|
||||
msgstr "שימוש"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:225
|
||||
msgid "Add the following short code inside a post or a page :"
|
||||
msgstr "הוסיפו את השורטקוד הבא לדף או לעמוד באתר"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:229
|
||||
msgid "value : The amount to pay"
|
||||
msgstr "value : הסכום לתשלום"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:231
|
||||
msgid "item_name : the name of the sold item"
|
||||
msgstr "item_name : שם המוצר למכירה"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:233
|
||||
msgid "button_class : CSS class for styling"
|
||||
msgstr "button_class : קלאס CSS לעיצוב"
|
||||
|
||||
#: ../10bit-pelecard-paybuttons-options.php:235
|
||||
msgid "button_text : Text to show on the button"
|
||||
msgstr "button_text : הטקסט שיופיע על הכפתור"
|
||||
@@ -0,0 +1,24 @@
|
||||
# Italian translation for ab-human-time
|
||||
# Copyright (C) 2014 AB Human Time
|
||||
# This file is distributed under the same license as the AB Human Time package.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: AB Human Time 0.1\n"
|
||||
"POT-Creation-Date: 2014-02-26 20:13+0100\n"
|
||||
"PO-Revision-Date: 2014-02-26 21:25+0100\n"
|
||||
"Last-Translator: endrix.develop <endrix.develop@gmail.com>\n"
|
||||
"Language-Team: <endrix.develop@gmail.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 1.6.4\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Language: it_IT\n"
|
||||
|
||||
#: ../ab-human-time.php:21
|
||||
msgid "Published "
|
||||
msgstr "Pubblicato "
|
||||
|
||||
#: ../ab-human-time.php:23
|
||||
msgid " ago"
|
||||
msgstr " fa"
|
||||
@@ -0,0 +1,49 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: xq-xe-xt-xy 1.0\n"
|
||||
"POT-Creation-Date: 2018-07-11 09:44+0300\n"
|
||||
"PO-Revision-Date: 2018-07-11 09:44+0300\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Marko Maksym\n"
|
||||
"Language: uk_UA\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 2.0.6\n"
|
||||
"X-Poedit-Basepath: ../includes\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
|
||||
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
"X-Poedit-KeywordsList: __;_e\n"
|
||||
"X-Poedit-SearchPath-0: .\n"
|
||||
|
||||
#: admin/class-admin-main.php:66
|
||||
msgid "Title of the page"
|
||||
msgstr ""
|
||||
|
||||
#: admin/class-admin-main.php:66
|
||||
msgid "Link Name"
|
||||
msgstr ""
|
||||
|
||||
#: admin/class-admin-main.php:69
|
||||
msgid "Submenu title"
|
||||
msgstr ""
|
||||
|
||||
#: admin/class-admin-main.php:69
|
||||
msgid "Submenu item"
|
||||
msgstr ""
|
||||
|
||||
#: admin/templates/index.php:8
|
||||
msgid "Settings Page"
|
||||
msgstr ""
|
||||
|
||||
#: admin/templates/main_module_menu.php:10
|
||||
msgid "Main page"
|
||||
msgstr ""
|
||||
|
||||
#: admin/templates/main_module_menu.php:13 admin/templates/page1.php:8
|
||||
msgid "Page 1"
|
||||
msgstr ""
|
||||
|
||||
#: admin/templates/main_module_menu.php:16 admin/templates/page2.php:8
|
||||
msgid "Page 2"
|
||||
msgstr ""
|
||||
@@ -0,0 +1,112 @@
|
||||
# Copyright (C) 2016 Kailey Lampert
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# Kailey Lampert <trepmal@gmail.com>, 2016.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 1.7\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-09-08 17:48-0700\n"
|
||||
"PO-Revision-Date: 2016-09-08 17:48-0700\n"
|
||||
"Last-Translator: Kailey Lampert <trepmal@gmail.com>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: active-plugins.php:62
|
||||
msgid "Acitve Plugins is for multisite use only."
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:72 active-plugins.php:83
|
||||
msgid "Active Plugins Across Network"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:72
|
||||
msgid "Active Plugins"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:86
|
||||
#, php-format
|
||||
msgid "<a href=\"%s\">Network-Activated Plugins</a>"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:87
|
||||
#, php-format
|
||||
msgid "<a href=\"%s\">MU Plugins</a>"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:90
|
||||
#, php-format
|
||||
msgid "List does not include: %s"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:146
|
||||
msgid ""
|
||||
"Totals <span class=\"description\">each active plugin and how many users</"
|
||||
"span>"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:176 active-plugins.php:213
|
||||
#, php-format
|
||||
msgid "v%s"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:180 active-plugins.php:214
|
||||
#, php-format
|
||||
msgid "%1$s %2$s"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:182
|
||||
#, php-format
|
||||
msgid "%s (Uninstalled)"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:187
|
||||
#, php-format
|
||||
msgid " (tagged: %s)"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:197
|
||||
msgid "Select all"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:198
|
||||
msgid "Deselect all"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:199
|
||||
msgid "Toggle"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:209
|
||||
msgid "Plugins with zero (0) users:"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:217
|
||||
msgid "none"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:224
|
||||
msgid "Show sites with no active plugins"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:235
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:236
|
||||
msgid "View"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:237
|
||||
msgid "Dashboard"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:238
|
||||
msgid "Plugins"
|
||||
msgstr ""
|
||||
|
||||
#: active-plugins.php:249
|
||||
msgid "(network-activated)"
|
||||
msgstr ""
|
||||
@@ -0,0 +1,619 @@
|
||||
# Copyright (C) 2019 RedNao
|
||||
# This file is distributed under the same license as the Extra Product Options Builder for WooCommerce plugin.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Extra Product Options Builder for WooCommerce 1.2.11\n"
|
||||
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/woo-extra-products\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"POT-Creation-Date: 2019-11-02T18:08:21+00:00\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"X-Generator: WP-CLI 2.3.0\n"
|
||||
"X-Domain: rednaowooextraproduct\n"
|
||||
|
||||
#. Plugin Name of the plugin
|
||||
msgid "Extra Product Options Builder for WooCommerce"
|
||||
msgstr ""
|
||||
|
||||
#. Plugin URI of the plugin
|
||||
msgid "http://smartforms.rednao.com/getit"
|
||||
msgstr ""
|
||||
|
||||
#. Description of the plugin
|
||||
msgid "Additional product fields for woocommerce"
|
||||
msgstr ""
|
||||
|
||||
#. Author of the plugin
|
||||
msgid "RedNao"
|
||||
msgstr ""
|
||||
|
||||
#. Author URI of the plugin
|
||||
msgid "http://rednao.com"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:2
|
||||
msgid "Jan"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:3
|
||||
msgid "Feb"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:4
|
||||
msgid "Mar"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:5
|
||||
msgid "Apr"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:6
|
||||
msgid "May"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:7
|
||||
msgid "Jun"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:8
|
||||
msgid "Jul"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:9
|
||||
msgid "Aug"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:10
|
||||
msgid "Sep"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:11
|
||||
msgid "Oct"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:12
|
||||
msgid "Nov"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:13
|
||||
msgid "Dec"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:14
|
||||
msgid "January"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:15
|
||||
msgid "February"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:16
|
||||
msgid "March"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:17
|
||||
msgid "April"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:18
|
||||
msgid "June"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:19
|
||||
msgid "July"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:20
|
||||
msgid "August"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:21
|
||||
msgid "September"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:22
|
||||
msgid "October"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:23
|
||||
msgid "November"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:24
|
||||
msgid "December"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:25
|
||||
msgid "Su"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:26
|
||||
msgid "Mo"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:27
|
||||
msgid "Tu"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:28
|
||||
msgid "We"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:29
|
||||
msgid "Th"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:30
|
||||
msgid "Fr"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:31
|
||||
msgid "Sa"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:32
|
||||
msgid "Sun"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:33
|
||||
msgid "Mon"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:34
|
||||
msgid "Tue"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:35
|
||||
msgid "Wed"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:36
|
||||
msgid "Thu"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:37
|
||||
msgid "Fri"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:38
|
||||
msgid "Sat"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:39
|
||||
#: jstranslations/ProductFieldBuilder.php:97
|
||||
msgid "Sunday"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:40
|
||||
#: jstranslations/ProductFieldBuilder.php:98
|
||||
msgid "Monday"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:41
|
||||
#: jstranslations/ProductFieldBuilder.php:99
|
||||
msgid "Tuesday"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:42
|
||||
#: jstranslations/ProductFieldBuilder.php:100
|
||||
msgid "Wednesday"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:43
|
||||
#: jstranslations/ProductFieldBuilder.php:101
|
||||
msgid "Thursday"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:44
|
||||
#: jstranslations/ProductFieldBuilder.php:102
|
||||
msgid "Friday"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/InternalShared.php:45
|
||||
#: jstranslations/ProductFieldBuilder.php:103
|
||||
msgid "Saturday"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:2
|
||||
msgid "Please select a field"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:3
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:4
|
||||
msgid "Import"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:5
|
||||
msgid "Export"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:6
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Label"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:7
|
||||
msgid "Image URL"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:8
|
||||
msgid "Price"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:9
|
||||
msgid "Sale"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:10
|
||||
msgid "Price Type"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:11
|
||||
msgid "Fixed amount"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:12
|
||||
msgid "% of original price"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:13
|
||||
msgid "% of original price + options"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:14
|
||||
msgid "Settings"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:15
|
||||
msgid "Conditions"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:16
|
||||
msgid "Enable Show/Hide Conditions"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:17
|
||||
msgid "Show"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:18
|
||||
msgid "Hide"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:19
|
||||
msgid "this field if"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:20
|
||||
msgid "Select a field"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:21
|
||||
msgid "Fields"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:22
|
||||
msgid "AND"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:23
|
||||
msgid "or"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:24
|
||||
msgid "Add new group"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:25
|
||||
msgid "Select one"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:26
|
||||
msgid "Equal to"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:27
|
||||
msgid "Not Equal to"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:28
|
||||
msgid "Is Empty"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:29
|
||||
msgid "Is Not Empty"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:30
|
||||
msgid "Contains"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:31
|
||||
msgid "Not Contains"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:32
|
||||
msgid "Default text"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:33
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Placeholder"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:34
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Required"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:35
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Show quantity selector"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:36
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Quantity Position"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:37
|
||||
msgid "Left"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:38
|
||||
msgid "Right"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:39
|
||||
msgid "Top"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:40
|
||||
msgid "Bottom"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:41
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Default value"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:42
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Quantity Label"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:43
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "0 = No Maximum"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:44
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Maximum Value"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:45
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "0 = No Minimum"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:46
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Minimum Value"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:47
|
||||
msgid "Price type"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:48
|
||||
msgid "None (don't use this field to calculate price)"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:49
|
||||
msgid "Fixed Amount"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:50
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Quantity"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:51
|
||||
msgid "Current value"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:52
|
||||
msgid "Percent of the original price"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:53
|
||||
msgid "Percent of the original price + options"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:54
|
||||
msgid "Price per word"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:55
|
||||
msgid "Price per char"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:56
|
||||
msgid "Sale Price (Empty = No Sale)"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:57
|
||||
msgid "Percentage"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:58
|
||||
msgid "Sale Percentage"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:59
|
||||
msgid "Free chars"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:60
|
||||
msgid "Ignore Spaces"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:61
|
||||
msgid "Free words"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:62
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Hide price"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:63
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "General"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:64
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Pricing"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:65
|
||||
msgid "Text"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:66
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Options"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:67
|
||||
msgid "Phone: (999)99-999-999"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:68
|
||||
msgid "Credit Card: 9999 9999 9999 9999"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:69
|
||||
msgid "Custom"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:70
|
||||
msgid "9=Numbers, a=letters, *=Numbers or letters"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:71
|
||||
msgid "Custom Mask"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:72
|
||||
msgid "Mask Char"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:73
|
||||
msgid "Image Width"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:74
|
||||
msgid "Image Height"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:75
|
||||
msgid "Allow Multiple"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:76
|
||||
msgid "Horizontal"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:77
|
||||
msgid "Vertical"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:78
|
||||
#: ProductFieldBuilder.php:1
|
||||
msgid "Date Format"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:79
|
||||
msgid "Price Per Day"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:80
|
||||
msgid "Label (Start Date)"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:81
|
||||
msgid "Placeholder (Start Date)"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:82
|
||||
msgid "Default Date (Start Date)"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:83
|
||||
msgid "This property support two type of fields"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:84
|
||||
msgid "A number, representing the number of dates from now e.g. 0 for today 1 for tomorrow"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:85
|
||||
msgid "2 for the day after tomorrow and so on. It supports negative numbers as well"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:86
|
||||
msgid "An specific date in the format of YYYY/MM/DD e.g. 2000/02/01 for February first of 2000"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:87
|
||||
msgid "Start Date"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:88
|
||||
msgid "Label (End Date)"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:89
|
||||
msgid "End Date"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:90
|
||||
msgid "Title"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:91
|
||||
msgid "Style"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:92
|
||||
msgid "Dashed"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:93
|
||||
msgid "Solid"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:94
|
||||
msgid "Color"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:95
|
||||
msgid "Default Date"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:96
|
||||
msgid "Week Start On"
|
||||
msgstr ""
|
||||
|
||||
#: jstranslations/ProductFieldBuilder.php:104
|
||||
msgid "Default Color"
|
||||
msgstr ""
|
||||
@@ -0,0 +1,428 @@
|
||||
# Copyright (C) 2012
|
||||
# This file is distributed under the same license as the package.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Advanced Category Column\n"
|
||||
"Report-Msgid-Bugs-To: http://wordpress.org/tag/advanced-category-column\n"
|
||||
"POT-Creation-Date: 2016-02-17 11:35+0200\n"
|
||||
"PO-Revision-Date: 2016-02-17 11:36+0200\n"
|
||||
"Last-Translator: Stefan Crämer <translate@atelier-fuenf.de>\n"
|
||||
"Language-Team: Waldemar Stoffel <stoffel@atelier-fuenf.de>\n"
|
||||
"Language: es_ES\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Generator: Poedit 1.8.1\n"
|
||||
"X-Poedit-Basepath: ..\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
|
||||
"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;"
|
||||
"_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Poedit-SearchPath-0: .\n"
|
||||
|
||||
#: advanced-cc.php:112
|
||||
msgid "FAQ"
|
||||
msgstr "FAQ"
|
||||
|
||||
#: advanced-cc.php:113
|
||||
msgid "Donate"
|
||||
msgstr "Donar"
|
||||
|
||||
#: advanced-cc.php:123 class-lib/A5_OptionPageClass.php:31
|
||||
#: class-lib/ACC_AdminClass.php:35
|
||||
msgid "Settings"
|
||||
msgstr "Ajustes"
|
||||
|
||||
#: class-lib/A5_ImageClass.php:48
|
||||
msgid "Permalink to"
|
||||
msgstr "enlace permanente a"
|
||||
|
||||
#: class-lib/A5_OptionPageClass.php:145
|
||||
msgid "Click to toggle"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_OptionPageClass.php:382
|
||||
msgid "Not set"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:37
|
||||
msgid "Homepage"
|
||||
msgstr "Página de Inicio"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:38
|
||||
msgid "Frontpage (e.g. a static page as homepage)"
|
||||
msgstr ""
|
||||
"Página Inicial (por ejemplo, una página estática como página de inicio)"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:39
|
||||
msgid ""Page" pages"
|
||||
msgstr ""Pagína" páginas"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:40
|
||||
msgid "Category pages"
|
||||
msgstr "Categoría de páginas"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:41
|
||||
msgid "Single post pages"
|
||||
msgstr "Páginas de post simples"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:42
|
||||
msgid "Archive pages"
|
||||
msgstr "Páginas de Archivo"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:43
|
||||
#, fuzzy
|
||||
msgid "Post type archives"
|
||||
msgstr "Páginas de post simples"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:44
|
||||
msgid "Tag pages"
|
||||
msgstr "Páginas de Etiquetas"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:45
|
||||
msgid "Attachments"
|
||||
msgstr "Adjuntos"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:46
|
||||
msgid "Custom Taxonomy pages (only available, if having a plugin)"
|
||||
msgstr ""
|
||||
"Páginas de Taxonomía Personalizada (sólo está disponible si tiene un plugin)"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:47
|
||||
msgid "Author pages"
|
||||
msgstr "Páginas del autor"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:48
|
||||
msgid "Search Results"
|
||||
msgstr "Buscar Resultados"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:49
|
||||
msgid ""Not Found""
|
||||
msgstr ""No Encontrado""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:52
|
||||
#, fuzzy
|
||||
msgid "Login Page (only available, if having a plugin)"
|
||||
msgstr ""
|
||||
"Páginas de Taxonomía Personalizada (sólo está disponible si tiene un plugin)"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:54
|
||||
msgid "Check all"
|
||||
msgstr "Seleccionar todo"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:56
|
||||
msgid ""
|
||||
"Check, where you want to show the widget. By default, it is showing on the "
|
||||
"homepage and the category pages:"
|
||||
msgstr ""
|
||||
"Seleccione, dónde desea mostrar el widget. Por defecto, se muestra en la "
|
||||
"página principal y en las páginas de la categoría:"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:92
|
||||
msgid "Under image"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:92
|
||||
msgid "Left of image"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:92
|
||||
msgid "Right of image"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:92
|
||||
msgid "Don't show excerpt"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:94
|
||||
msgid ""
|
||||
"Choose, whether or not to display the excerpt and whether it comes under the "
|
||||
"thumbnail or next to it."
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:104
|
||||
msgid "Weight of the Post Title:"
|
||||
msgstr "Peso del título del Post:"
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:108
|
||||
msgid "Left"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:108
|
||||
msgid "Right"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:108
|
||||
msgid "Center"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:108
|
||||
msgid "Justify"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:110
|
||||
msgid "How do you want to align the Post Title?"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:121
|
||||
msgid ""
|
||||
"Check to have an additional 'read more' link at the end of the "
|
||||
"excerpt."
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:122
|
||||
#, php-format
|
||||
msgid ""
|
||||
"Write here some text for the 'read more' link. By default, it is %s:"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/A5_WidgetClass.php:123
|
||||
msgid ""
|
||||
"If you want to style the 'read more' link, you can enter a class "
|
||||
"here."
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:63
|
||||
msgid ""
|
||||
"http://wasistlos.waldemarstoffel.com/plugins-fur-wordpress/advanced-category-"
|
||||
"column-plugin"
|
||||
msgstr ""
|
||||
"http://wasistlos.waldemarstoffel.com/plugins-fur-wordpress/advanced-category-"
|
||||
"column-plugin"
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:63
|
||||
msgid "Plugin Support"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:65
|
||||
msgid ""
|
||||
"Style the links of the widget. If you leave this empty, your theme will "
|
||||
"style the hyperlinks."
|
||||
msgstr ""
|
||||
"El estilo de los enlaces del widget. Si deja el campo vacío, el tema será el "
|
||||
"mismo estilo de los hipervínculos."
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:67
|
||||
msgid "Just input something like,"
|
||||
msgstr "Sólo algo de entrada como,"
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:71
|
||||
msgid "to get fat, blue, underlined links."
|
||||
msgstr "Los enlaces serán, azul subrayado."
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:73
|
||||
msgid ""
|
||||
"You most probably have to use "!important" at the end of each line, "
|
||||
"to make it work."
|
||||
msgstr ""
|
||||
"Lo más probable es usar "!important" al final de cada línea, para "
|
||||
"hacer que funcione."
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:86
|
||||
msgid "Debug Info"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:105
|
||||
msgid "Styling of the links"
|
||||
msgstr "Estilo de los enlaces"
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:107
|
||||
msgid "Link style:"
|
||||
msgstr "Estílo enlace:"
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:109
|
||||
msgid "Hover style:"
|
||||
msgstr "Estilo hover:"
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:111
|
||||
msgid "Widget container:"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:111
|
||||
msgid ""
|
||||
"You can enter your own style for the widgets here. This will overwrite the "
|
||||
"styles of your theme."
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:111
|
||||
msgid ""
|
||||
"If you leave this empty, you can still style every instance of the widget "
|
||||
"individually."
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:113
|
||||
#, fuzzy
|
||||
msgid "Compress Style Sheet:"
|
||||
msgstr "Estílo enlace:"
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:113
|
||||
msgid "Click here to compress the style sheet."
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:115
|
||||
msgid "Debug:"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:115
|
||||
msgid ""
|
||||
"If you can't reach the dynamical style sheet, you'll have to display "
|
||||
"the styles inline. By clicking here you can do so."
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:119
|
||||
msgid "entries"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:119
|
||||
msgid "entry"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:121
|
||||
#, php-format
|
||||
msgid "Empty cache (%d %s):"
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:121
|
||||
msgid "You can empty the plugin's cache here, if necessary."
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:129
|
||||
msgid "Just put some css code here."
|
||||
msgstr "Sólo hay que poner algo de código CSS aquí."
|
||||
|
||||
#: class-lib/ACC_AdminClass.php:189
|
||||
msgid "Cache emptied."
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:18
|
||||
msgid ""
|
||||
"Configure the output and looks of the widget. Then display thumbnails and "
|
||||
"excerpts of posts in your sidebars and define, on what kind of pages they "
|
||||
"will show."
|
||||
msgstr ""
|
||||
"Configure la salida y la apariencia del widget. Entonces se mostrarán las "
|
||||
"miniaturas y extractos de los mensajes en las barras laterales y se definirá "
|
||||
"en qué tipo de páginas se mostrarán."
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:108
|
||||
msgid "Title:"
|
||||
msgstr "Título:"
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:109
|
||||
#, php-format
|
||||
msgid ""
|
||||
"To exclude certain categories or to show just a special category, simply "
|
||||
"write their ID's separated by comma (e.g. %s-5, 2, 4%s will show "
|
||||
"categories 2 and 4 and will exclude category 5):"
|
||||
msgstr ""
|
||||
"Para excluir ciertas categorías o para mostrar sólo una categoría especial, "
|
||||
"basta con escribir su ID separado por coma (por ejemplo,%s-5, 2, 4%s "
|
||||
"mostrará las categorías 2 y 4, y se excluye la categoría 5):"
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:110
|
||||
msgid "Check to show the categories in which the post is filed."
|
||||
msgstr "Seleccione para mostrar las categorías en que se presenta el mensaje."
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:111
|
||||
msgid ""
|
||||
"Give some text that you want in front of the post's categtories (i.e "
|
||||
"'filed under':"
|
||||
msgstr ""
|
||||
"De algún texto que usted quiere al frente de la categoría de mensajes (ej. "
|
||||
"'llenado debajo':"
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:112
|
||||
msgid "How many posts will be displayed in the sidebar:"
|
||||
msgstr "Cuántos post se mostrarán en la barra lateral:"
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:113
|
||||
msgid "Offset (how many posts are spared out in the beginning):"
|
||||
msgstr "Offset (cuántos post están a salvo en el inicio):"
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:114
|
||||
msgid "Check to have the offset only on your homepage."
|
||||
msgstr ""
|
||||
"Verificación para que el desplazamiento sólo sea en la página principal."
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:115
|
||||
msgid "Width of the thumbnail (in px):"
|
||||
msgstr "Ancho de las miniaturas (en px)"
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:116
|
||||
#, php-format
|
||||
msgid ""
|
||||
"If wanting a border around the image, write the style here. %s would make it "
|
||||
"a black border, 1px wide."
|
||||
msgstr ""
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:118
|
||||
msgid "In case there is no excerpt defined, how many sentences are displayed:"
|
||||
msgstr ""
|
||||
"En caso de que no haya extracto definido, como cuantas frases se muestran:"
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:119
|
||||
msgid "Check to display words instead of sentences."
|
||||
msgstr "Seleccione para mostrar palabras en lugar de oraciones."
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:120
|
||||
msgid "Check to have each sentense in a new line."
|
||||
msgstr "Seleccione para tener cada sentencia en una línea nueva."
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:122
|
||||
msgid ""
|
||||
"Check to return the excerpt unfiltered (might avoid interferences with other "
|
||||
"plugins)."
|
||||
msgstr ""
|
||||
"Seleccione para retornar el extracto sin filtrar (puede evitar "
|
||||
"interferencias con otros plugins)."
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:123
|
||||
msgid ""
|
||||
"If you want a line between the posts, this is the height in px (if not "
|
||||
"wanting a line, leave emtpy):"
|
||||
msgstr ""
|
||||
"Si usted quiere una línea entre los posts, esta es la altura en píxeles (si "
|
||||
"no quisiera una línea, deje en blanco)"
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:124
|
||||
msgid "The color of the line (e.g. #cccccc):"
|
||||
msgstr "El color de la línea (e.g. #cccccc):"
|
||||
|
||||
#: class-lib/ACC_WidgetClass.php:126
|
||||
#, fuzzy, php-format
|
||||
msgid ""
|
||||
"Here you can finally style the widget. Simply type something like%sto get "
|
||||
"just a gray outline and a padding of 10 px. If you leave that section empty, "
|
||||
"your theme will style the widget."
|
||||
msgstr ""
|
||||
"Aquí usted puede finalmente ver el estilo del widget. Simplemente escriba "
|
||||
"algo como%1$s%2$sborder-left: 1px dashed;%2$sborder-color: #000000;%3$s"
|
||||
"%2$spara obtener una línea de puntos negro de la izquierda. Si deja la "
|
||||
"sección vacía, su tema le dará estilo al widget."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "The Advanced Category Column does, what the Category Column Plugin does; "
|
||||
#~ "it creates a widget, which you can drag to your sidebar and it will show "
|
||||
#~ "excerpts of the posts of other categories than showed in the center-"
|
||||
#~ "column. It just has more options than the the Category Column Plugin. It "
|
||||
#~ "is tested with WP up to version 3.5 and it might work with versions down "
|
||||
#~ "to 2.9, but will never be explicitly supported for those. The 'Advanced' "
|
||||
#~ "means, that you have a couple of more options than in the 'Category "
|
||||
#~ "Column Plugin'."
|
||||
#~ msgstr ""
|
||||
#~ "La Columna Categoría Avanzada hace, lo que hace el Plugin de Columna de "
|
||||
#~ "Categoría, se crea un widget, que se puede arrastrar a la barra lateral y "
|
||||
#~ "se mostrarán extractos de los mensajes de otras categorías que se "
|
||||
#~ "mostraron en la columna del centro. Simplemente tiene más opciones que el "
|
||||
#~ "Plugin de Columna de Categoría. Se probó con WP hasta la versión 3.5 y "
|
||||
#~ "que podría funcionar con las versiones hasta la 2.9, pero nunca se probó "
|
||||
#~ "explícitamente en aquellos. Los menús 'Avanzados' significan, que tiene "
|
||||
#~ "un par de opciones más que el 'Plugin de Columna de Categoría'."
|
||||
|
||||
#~ msgid "Waldemar Stoffel"
|
||||
#~ msgstr "Waldemar Stoffel"
|
||||
|
||||
#~ msgid "http://www.waldemarstoffel.com"
|
||||
#~ msgstr "http://www.waldemarstoffel.com"
|
||||
410
spec/fixtures/dynamic_finders/plugin_version/alkubot/translation_file/languages/Alkubot-en_US.po
vendored
Normal file
410
spec/fixtures/dynamic_finders/plugin_version/alkubot/translation_file/languages/Alkubot-en_US.po
vendored
Normal file
@@ -0,0 +1,410 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Alkubot v1.0.0\n"
|
||||
"POT-Creation-Date: 2019-08-11 13:37+0300\n"
|
||||
"PO-Revision-Date: 2019-10-22 09:43+0300\n"
|
||||
"Language-Team: Alkubot\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 2.0.6\n"
|
||||
"X-Poedit-Basepath: .\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Last-Translator: \n"
|
||||
"Language: en_US\n"
|
||||
"X-Poedit-SearchPath-0: .\n"
|
||||
|
||||
# Admin - layouts/menu
|
||||
msgid "Terméklista"
|
||||
msgstr "Product list"
|
||||
|
||||
msgid "Beállítások"
|
||||
msgstr "Settings"
|
||||
|
||||
msgid "Felíratkozók"
|
||||
msgstr "Subscribers"
|
||||
|
||||
msgid "Statisztika"
|
||||
msgstr "Statistics"
|
||||
|
||||
msgid "Visszajelzés"
|
||||
msgstr "Feedback"
|
||||
|
||||
msgid "Alkubot varázsló"
|
||||
msgstr "Alkubot wizard"
|
||||
|
||||
msgid "Alkubot telepítése"
|
||||
msgstr "Install Alkubot"
|
||||
|
||||
# Admin - product
|
||||
msgid "Újragenerálás"
|
||||
msgstr "Rework"
|
||||
|
||||
msgid "Product subtitle"
|
||||
msgstr "Here you can find the product list that can be modified or you can even generate a new one."
|
||||
|
||||
msgid "Összes termék"
|
||||
msgstr "Every product"
|
||||
|
||||
msgid "Termék kategóriánként"
|
||||
msgstr "Categories"
|
||||
|
||||
msgid "Bizonyos termékeknél"
|
||||
msgstr "Products"
|
||||
|
||||
# Admin - product/popups
|
||||
msgid "Reinstall text"
|
||||
msgstr "Are you sure you want to rework the settings of Alkubot? Doing so will reset your current settings!"
|
||||
|
||||
msgid "Switch discount type text"
|
||||
msgstr "Are you sure you want to change the settings for the selected type? The modifications will be activated right away."
|
||||
|
||||
msgid "Mégse"
|
||||
msgstr "Cancel"
|
||||
|
||||
# Admin - product/all.content
|
||||
msgid "Product all subtitle"
|
||||
msgstr "Please set the maximum percentage of discount that Alkubot can give to a visitor!"
|
||||
|
||||
msgid "vagyis az Alkubot"
|
||||
msgstr "that is, Alkubot won’t give more than"
|
||||
|
||||
msgid "kedvezménynél többet nem ad egy látogatónak"
|
||||
msgstr "discount to a visitor"
|
||||
|
||||
msgid "Alkudozok gomb megjelenitése a termék oldalon"
|
||||
msgstr "Show “Get a Deal” button on the product page"
|
||||
|
||||
msgid "Hint text: all product"
|
||||
msgstr "The visitor can instantly start negotiating for a deal by pushing the \"Get a Deal\" button. This way, he doesn't have to wait for the timed Alkubot chat window to pop-up."
|
||||
|
||||
msgid "Engedélyezve"
|
||||
msgstr "Enabled"
|
||||
|
||||
msgid "Kikapcsolva"
|
||||
msgstr "Disabled"
|
||||
|
||||
# Admin - product/category.content
|
||||
msgid "Összes"
|
||||
msgstr "All"
|
||||
|
||||
msgid "Alkudozom gomb megjelenése:"
|
||||
msgstr "“Get a Deal” button"
|
||||
|
||||
msgid "Be"
|
||||
msgstr "On"
|
||||
|
||||
msgid "Ki"
|
||||
msgstr "Off"
|
||||
|
||||
# Admin - product/categories
|
||||
msgid "No category found"
|
||||
msgstr "No category found!"
|
||||
|
||||
# Admin - product/product.content
|
||||
msgid "Termékek rejtése"
|
||||
msgstr "Hide products"
|
||||
|
||||
msgid "Termékek megjelenítése"
|
||||
msgstr "Show products"
|
||||
|
||||
# Admin - product/products
|
||||
msgid "No product found"
|
||||
msgstr "No product found!"
|
||||
|
||||
# Admin - product/search
|
||||
msgid "Search placeholder"
|
||||
msgstr "Search for a product"
|
||||
|
||||
# Admin - settings
|
||||
msgid "Alkubot időzítése"
|
||||
msgstr "Alkubot timing"
|
||||
|
||||
msgid "Itt beállíthatod, hogy a bot, miként reagáljon, bizonyos interakciókra."
|
||||
msgstr "Here you can set how Alkubot should react to certain actions"
|
||||
|
||||
msgid "Oldal elhagyásakor"
|
||||
msgstr "While leaving the product page"
|
||||
|
||||
msgid "Bizonyos oldalon töltött idő után"
|
||||
msgstr "After a certain time that the visitor spends on the product page"
|
||||
|
||||
msgid "Kérjük adja meg hány mp után aktiválódjon"
|
||||
msgstr "The time after Alkubot shows up"
|
||||
|
||||
msgid "mp"
|
||||
msgstr "sec"
|
||||
|
||||
msgid "Oldal görgetésekor"
|
||||
msgstr "While scrolling the product page"
|
||||
|
||||
msgid "Email beállítások"
|
||||
msgstr "Email settings"
|
||||
|
||||
msgid "Sikeres alku után email cím elkérése"
|
||||
msgstr "Should Alkubot ask for an email after an accepted deal?"
|
||||
|
||||
msgid "Bot aktiválása"
|
||||
msgstr "Activate Alkubot"
|
||||
|
||||
msgid "Modosít"
|
||||
msgstr "Modify"
|
||||
|
||||
msgid "Settings popup title"
|
||||
msgstr "Saved!"
|
||||
|
||||
msgid "Settings popup text"
|
||||
msgstr "Your settings have been successfully modified!"
|
||||
|
||||
msgid "Hint text: settings leave"
|
||||
msgstr "Alkubot pops up when the visitor tries to leave the page."
|
||||
|
||||
msgid "Hint text: settings time"
|
||||
msgstr "Alkubot pops up after a certain number of seconds."
|
||||
|
||||
msgid "Hint text: settings scroll"
|
||||
msgstr "Alkubot pops up when the visitors scroll until 3/4 of the site."
|
||||
|
||||
msgid "Hint text: settings email"
|
||||
msgstr "After an accepted deal, the visitor has to give his email address in order to get his discount."
|
||||
|
||||
# Admin - settings/chat.position
|
||||
msgid "Hol helyezkedjen el?"
|
||||
msgstr "Where should Alkubot show up on your site?"
|
||||
|
||||
msgid "Bal oldalt"
|
||||
msgstr "Left side"
|
||||
|
||||
msgid "Középen"
|
||||
msgstr "Middle"
|
||||
|
||||
msgid "Jobb oldalt"
|
||||
msgstr "Right side"
|
||||
|
||||
# Admin - statistics
|
||||
msgid "Legenerált kuponkodok"
|
||||
msgstr "Coupons generated"
|
||||
|
||||
msgid "Mutass mindent"
|
||||
msgstr "Show all"
|
||||
|
||||
# Admin - statistics/infobox
|
||||
msgid "db"
|
||||
msgstr "pc"
|
||||
|
||||
msgid "Ft"
|
||||
msgstr "HUF "
|
||||
|
||||
msgid "Sikeres alku száma"
|
||||
msgstr "Successful <br> Deals"
|
||||
|
||||
msgid "Megadott email cimek száma"
|
||||
msgstr "Emails <br> Collected"
|
||||
|
||||
msgid "Eddigi bevétel"
|
||||
msgstr "Proceeds <br> so far"
|
||||
|
||||
# Admin - statistics/coupons
|
||||
msgid "Dátum"
|
||||
msgstr "Date"
|
||||
|
||||
msgid "Kupon"
|
||||
msgstr "Coupon"
|
||||
|
||||
msgid "Felhasználó"
|
||||
msgstr "User"
|
||||
|
||||
msgid "Felhasználták már?"
|
||||
msgstr "Used up?"
|
||||
|
||||
msgid "Igen"
|
||||
msgstr "Yes"
|
||||
|
||||
msgid "Nem"
|
||||
msgstr "No"
|
||||
|
||||
msgid "Részletek"
|
||||
msgstr "Details"
|
||||
|
||||
msgid "Még nincs legenerált kupon!"
|
||||
msgstr "No generated voucher yet!"
|
||||
|
||||
# Admin - statistics/details
|
||||
msgid "kupon részletei"
|
||||
msgstr "coupon details"
|
||||
|
||||
msgid "Vissza a statisztikákhoz"
|
||||
msgstr "Back to statistics"
|
||||
|
||||
msgid "Termék neve"
|
||||
msgstr "Product name"
|
||||
|
||||
msgid "Kupon generálásának időpontja"
|
||||
msgstr "Coupon generation date"
|
||||
|
||||
msgid "Felhasználva"
|
||||
msgstr "Used"
|
||||
|
||||
msgid "még nincs"
|
||||
msgstr "not yet"
|
||||
|
||||
msgid "Termékre beállitott maximális kedvezmény"
|
||||
msgstr "Maximum discount set for the product"
|
||||
|
||||
msgid "Kialkudott kedvezmény"
|
||||
msgstr "Negotiated discount"
|
||||
|
||||
msgid "vendég"
|
||||
msgstr "guest"
|
||||
|
||||
# Admin - subscribers
|
||||
msgid "Összesen"
|
||||
msgstr "Total"
|
||||
|
||||
msgid "Email cimek exportálása"
|
||||
msgstr "Exports Emails"
|
||||
|
||||
msgid "Törlés"
|
||||
msgstr "Delete"
|
||||
|
||||
msgid "Még nincs egy feliratkozó sem!"
|
||||
msgstr "No subscriber yet!"
|
||||
|
||||
msgid "Delete subscriber popup title"
|
||||
msgstr "Delete subscriber"
|
||||
|
||||
msgid "Delete subscriber popup text"
|
||||
msgstr "Are you sure you want to delete this email address?"
|
||||
|
||||
msgid "Igen törlöm"
|
||||
msgstr "Yes, I am sure!"
|
||||
|
||||
# Admin - feedback
|
||||
msgid "Név"
|
||||
msgstr "Name"
|
||||
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
msgid "Visszajelzés tipusa"
|
||||
msgstr "Feedback type"
|
||||
|
||||
msgid "Válassz a listából"
|
||||
msgstr "Pick one"
|
||||
|
||||
msgid "Értékelés"
|
||||
msgstr "Rate us"
|
||||
|
||||
msgid "Üzenet"
|
||||
msgstr "Message"
|
||||
|
||||
msgid "Küldés"
|
||||
msgstr "Send"
|
||||
|
||||
msgid "Required text"
|
||||
msgstr "Please fill out this field."
|
||||
|
||||
msgid "Feedback popup title"
|
||||
msgstr "Thank you for your feedback!"
|
||||
|
||||
msgid "Feedback popup text"
|
||||
msgstr "Your opinion is important to us. We aim to reply to your feedback as soon as possible."
|
||||
|
||||
msgid "Close window"
|
||||
msgstr "Close window"
|
||||
|
||||
msgid "Hibajelentés"
|
||||
msgstr "Bug report"
|
||||
|
||||
msgid "Észrevétel"
|
||||
msgstr "Feedback"
|
||||
|
||||
msgid "Not valid email text"
|
||||
msgstr "Please enter a valid email address"
|
||||
|
||||
msgid "kötelező"
|
||||
msgstr "required"
|
||||
|
||||
msgid "Feedback subtitle"
|
||||
msgstr "Just fill out the below form in case you have feedback or need help regarding Alkubot"
|
||||
|
||||
# Admin - wizard
|
||||
msgid "Varázsló"
|
||||
msgstr "Setup Wizard"
|
||||
|
||||
msgid "Wizard subtitle"
|
||||
msgstr "By answering a few simple questions you can setup Alkubot within minutes."
|
||||
|
||||
# Admin - wizard/lastStepComment
|
||||
msgid "Wizard last step comment text"
|
||||
msgstr "You can fine-tune Alkubot under Settings after finishing this setup wizard."
|
||||
|
||||
# Admin - wizard/step1
|
||||
msgid "Kérlek válaszd ki, milyen szinten akarod beállitani a botot"
|
||||
msgstr "Please choose the level which you want to use Alkubot for."
|
||||
|
||||
msgid "Tovább"
|
||||
msgstr "Next"
|
||||
|
||||
# Admin - wizard/step2.all
|
||||
msgid "Vissza"
|
||||
msgstr "Back"
|
||||
|
||||
# Admin - wizard/step2.categories
|
||||
msgid "Kérlek add meg, mely kategoriákra legyen engedélyezve az alkubot."
|
||||
msgstr "Please pick the categories that Alkubot should be applied to!"
|
||||
|
||||
# Admin - wizard/step3.categories
|
||||
msgid "Wizard categories step 3 subtitle"
|
||||
msgstr "Here you can set the maximum percentage of discount that Alkubot can give to a visitor for each category."
|
||||
|
||||
msgid "Nem választottál ki egy kategoriát sem."
|
||||
msgstr "No category have been chosen."
|
||||
|
||||
# Admin - wizard/step3.products
|
||||
msgid "Wizard products step 3 subtitle"
|
||||
msgstr "Here you can set the maximum percentage of discount that Alkubot can give to a visitor for each product."
|
||||
|
||||
msgid "Nem választottál ki terméket."
|
||||
msgstr "No product have been chosen."
|
||||
|
||||
# Admin - wizard/steps.header
|
||||
msgid "Step"
|
||||
msgstr "Step"
|
||||
|
||||
# Frontend
|
||||
msgid "Elfogadom"
|
||||
msgstr "Accept"
|
||||
|
||||
msgid "Elutasítom"
|
||||
msgstr "Decline"
|
||||
|
||||
msgid "Normál ár"
|
||||
msgstr "Normal price"
|
||||
|
||||
msgid "Írd ide az üzeneted"
|
||||
msgstr "Write your message here"
|
||||
|
||||
msgid "Alkudozok"
|
||||
msgstr "Bargain"
|
||||
|
||||
msgid "Gratulálunk!"
|
||||
msgstr "Congratulations!"
|
||||
|
||||
msgid "Sikeres alkut kötöttél"
|
||||
msgstr "You made a deal"
|
||||
|
||||
msgid "Az Alkubot lezárta a chatet"
|
||||
msgstr "Chat was closed by Alkubot"
|
||||
|
||||
msgid "Powered by url"
|
||||
msgstr "https://www.alkubot.com?utm_medium=referal&utm_source=bot&utm_campaign=powered+by"
|
||||
|
||||
msgid "Sokkalod az arat?"
|
||||
msgstr "Too pricey?"
|
||||
|
||||
msgid "Alkudozzunk rola"
|
||||
msgstr "Let's make a deal!"
|
||||
|
||||
msgid "Alku inditasa most"
|
||||
msgstr "Negotiate the price"
|
||||
@@ -0,0 +1,53 @@
|
||||
# Copyright (C) 2013 Allow Javascript in Text Widgets
|
||||
# This file is distributed under the same license as the Allow Javascript in Text Widgets package.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Allow Javascript in Text Widgets 0.3\n"
|
||||
"Report-Msgid-Bugs-To: http://wordpress.org/tag/allow-javascript-in-text-"
|
||||
"widgets\n"
|
||||
"POT-Creation-Date: 2013-12-17 09:48:40+00:00\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"PO-Revision-Date: 2013-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
||||
#: allow-javascript-in-text-widgets.php:20
|
||||
msgid "Arbitrary text or HTML"
|
||||
msgstr ""
|
||||
|
||||
#: allow-javascript-in-text-widgets.php:22
|
||||
msgid "Text"
|
||||
msgstr ""
|
||||
|
||||
#: allow-javascript-in-text-widgets.php:49
|
||||
msgid "Title:"
|
||||
msgstr ""
|
||||
|
||||
#: allow-javascript-in-text-widgets.php:54
|
||||
msgid "Automatically add paragraphs"
|
||||
msgstr ""
|
||||
|
||||
#. Plugin Name of the plugin/theme
|
||||
msgid "Allow Javascript in Text Widgets"
|
||||
msgstr ""
|
||||
|
||||
#. Plugin URI of the plugin/theme
|
||||
msgid "http://philipjohn.co.uk/#pj-better-multisite-text-widget"
|
||||
msgstr ""
|
||||
|
||||
#. Description of the plugin/theme
|
||||
msgid ""
|
||||
"Replaces the default text widget with one that allows Javascript so you can "
|
||||
"do basic things like add Google Ads to your sidebar without using other "
|
||||
"plugins."
|
||||
msgstr ""
|
||||
|
||||
#. Author of the plugin/theme
|
||||
msgid "Philip John"
|
||||
msgstr ""
|
||||
|
||||
#. Author URI of the plugin/theme
|
||||
msgid "http://philipjohn.co.uk"
|
||||
msgstr ""
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user