site-inspector 3.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +30 -0
- data/.rubocop.yml +1 -5
- data/.rubocop_todo.yml +185 -79
- data/.ruby-version +1 -1
- data/CHANGELOG.md +71 -0
- data/Gemfile +0 -2
- data/README.md +8 -14
- data/bin/site-inspector +13 -13
- data/lib/cliver/dependency_ext.rb +2 -2
- data/lib/data/well-known.yml +51 -0
- data/lib/site-inspector/domain.rb +27 -15
- data/lib/site-inspector/domain_parser.rb +11 -0
- data/lib/site-inspector/{checks → endpoint}/accessibility.rb +6 -4
- data/lib/site-inspector/{checks → endpoint}/check.rb +5 -1
- data/lib/site-inspector/endpoint/content.rb +151 -0
- data/lib/site-inspector/{checks → endpoint}/cookies.rb +13 -5
- data/lib/site-inspector/{checks → endpoint}/dns.rb +42 -18
- data/lib/site-inspector/endpoint/headers.rb +55 -0
- data/lib/site-inspector/{checks → endpoint}/hsts.rb +36 -5
- data/lib/site-inspector/endpoint/wappalyzer.rb +68 -0
- data/lib/site-inspector/endpoint/well_known.rb +95 -0
- data/lib/site-inspector/endpoint/whois.rb +56 -0
- data/lib/site-inspector/endpoint.rb +60 -23
- data/lib/site-inspector/formatter.rb +118 -0
- data/lib/site-inspector/version.rb +1 -1
- data/lib/site-inspector.rb +34 -30
- data/package-lock.json +670 -23
- data/package.json +2 -1
- data/renovate.json +4 -0
- data/script/benchmark +8 -0
- data/script/cibuild +2 -2
- data/script/console +1 -1
- data/script/pa11y-version +1 -1
- data/script/release +11 -4
- data/script/update-well-known +18 -0
- data/site-inspector.gemspec +16 -9
- data/spec/cliver/dependency_ext_spec.rb +21 -0
- data/spec/{site_inspector_domain_spec.rb → site_inspector/domain_spec.rb} +71 -9
- data/spec/{checks/site_inspector_endpoint_accessibility_spec.rb → site_inspector/endpoint/accessibility_spec.rb} +9 -7
- data/spec/{checks/site_inspector_endpoint_content_spec.rb → site_inspector/endpoint/content_spec.rb} +14 -4
- data/spec/{checks/site_inspector_endpoint_cookies_spec.rb → site_inspector/endpoint/cookies_spec.rb} +27 -14
- data/spec/{checks/site_inspector_endpoint_dns_spec.rb → site_inspector/endpoint/dns_spec.rb} +87 -9
- data/spec/{checks/site_inspector_endpoint_headers_spec.rb → site_inspector/endpoint/headers_spec.rb} +0 -7
- data/spec/{checks/site_inspector_endpoint_hsts_spec.rb → site_inspector/endpoint/hsts_spec.rb} +8 -8
- data/spec/site_inspector/endpoint/wappalyzer_spec.rb +20 -0
- data/spec/site_inspector/endpoint/well_known_spec.rb +12 -0
- data/spec/{checks/site_inspector_endpoint_whois_spec.rb → site_inspector/endpoint/whois_spec.rb} +2 -1
- data/spec/{site_inspector_endpoint_spec.rb → site_inspector/endpoint_spec.rb} +59 -3
- data/spec/site_inspector_spec.rb +58 -11
- data/spec/spec_helper.rb +9 -2
- metadata +100 -92
- data/.travis.yml +0 -9
- data/lib/site-inspector/cache.rb +0 -17
- data/lib/site-inspector/checks/content.rb +0 -85
- data/lib/site-inspector/checks/headers.rb +0 -68
- data/lib/site-inspector/checks/sniffer.rb +0 -67
- data/lib/site-inspector/checks/wappalyzer.rb +0 -62
- data/lib/site-inspector/checks/whois.rb +0 -36
- data/lib/site-inspector/disk_cache.rb +0 -42
- data/lib/site-inspector/rails_cache.rb +0 -13
- data/spec/checks/site_inspector_endpoint_sniffer_spec.rb +0 -150
- data/spec/checks/site_inspector_endpoint_wappalyzer_spec.rb +0 -34
- data/spec/site_inspector_cache_spec.rb +0 -15
- data/spec/site_inspector_disk_cache_spec.rb +0 -39
- /data/lib/site-inspector/{checks → endpoint}/https.rb +0 -0
- /data/spec/{checks/site_inspector_endpoint_check_spec.rb → site_inspector/endpoint/check_spec.rb} +0 -0
- /data/spec/{checks/site_inspector_endpoint_https_spec.rb → site_inspector/endpoint/https_spec.rb} +0 -0
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class SiteInspector
|
|
4
|
-
class Endpoint
|
|
5
|
-
class Content < Check
|
|
6
|
-
# Given a path (e.g, "/data"), check if the given path exists on the canonical endpoint
|
|
7
|
-
def path_exists?(path)
|
|
8
|
-
endpoint.up? && endpoint.request(path: path, followlocation: true).success?
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
# The default Check#response method is from a HEAD request
|
|
12
|
-
# The content check has a special response which includes the body from a GET request
|
|
13
|
-
def response
|
|
14
|
-
@response ||= endpoint.request(method: :get)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def document
|
|
18
|
-
require 'nokogiri'
|
|
19
|
-
@doc ||= Nokogiri::HTML response.body if response
|
|
20
|
-
end
|
|
21
|
-
alias doc document
|
|
22
|
-
|
|
23
|
-
def body
|
|
24
|
-
@body ||= document.to_s.force_encoding('UTF-8').encode('UTF-8', invalid: :replace, replace: '')
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def robots_txt?
|
|
28
|
-
@bodts_txt ||= path_exists?('robots.txt') if proper_404s?
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def sitemap_xml?
|
|
32
|
-
@sitemap_xml ||= path_exists?('sitemap.xml') if proper_404s?
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def humans_txt?
|
|
36
|
-
@humans_txt ||= path_exists?('humans.txt') if proper_404s?
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def doctype
|
|
40
|
-
document.internal_subset.external_id
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def generator
|
|
44
|
-
@generator ||= begin
|
|
45
|
-
tag = document.at('meta[name="generator"]')
|
|
46
|
-
tag['content'] if tag
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def prefetch
|
|
51
|
-
return unless endpoint.up?
|
|
52
|
-
|
|
53
|
-
options = SiteInspector.typhoeus_defaults.merge(followlocation: true)
|
|
54
|
-
['robots.txt', 'sitemap.xml', 'humans.txt', random_path].each do |path|
|
|
55
|
-
request = Typhoeus::Request.new(URI.join(endpoint.uri, path), options)
|
|
56
|
-
SiteInspector.hydra.queue(request)
|
|
57
|
-
end
|
|
58
|
-
SiteInspector.hydra.run
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def proper_404s?
|
|
62
|
-
@proper_404s ||= !path_exists?(random_path)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def to_h
|
|
66
|
-
prefetch
|
|
67
|
-
{
|
|
68
|
-
doctype: doctype,
|
|
69
|
-
generator: generator,
|
|
70
|
-
sitemap_xml: sitemap_xml?,
|
|
71
|
-
robots_txt: robots_txt?,
|
|
72
|
-
humans_txt: humans_txt?,
|
|
73
|
-
proper_404s: proper_404s?
|
|
74
|
-
}
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
private
|
|
78
|
-
|
|
79
|
-
def random_path
|
|
80
|
-
require 'securerandom'
|
|
81
|
-
@random_path ||= SecureRandom.hex
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class SiteInspector
|
|
4
|
-
class Endpoint
|
|
5
|
-
class Headers < Check
|
|
6
|
-
# TODO: kill this
|
|
7
|
-
def strict_transport_security?
|
|
8
|
-
!!strict_transport_security
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def content_security_policy?
|
|
12
|
-
!!content_security_policy
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def click_jacking_protection?
|
|
16
|
-
!!click_jacking_protection
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# return the found header value
|
|
20
|
-
|
|
21
|
-
# TODO: kill this
|
|
22
|
-
def strict_transport_security
|
|
23
|
-
headers['strict-transport-security']
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def content_security_policy
|
|
27
|
-
headers['content-security-policy']
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def click_jacking_protection
|
|
31
|
-
headers['x-frame-options']
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def server
|
|
35
|
-
headers['server']
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def xss_protection
|
|
39
|
-
headers['x-xss-protection']
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# more specific checks than presence of headers
|
|
43
|
-
def xss_protection?
|
|
44
|
-
xss_protection == '1; mode=block'
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Returns an array of hashes of downcased key/value header pairs (or an empty hash)
|
|
48
|
-
def all
|
|
49
|
-
@all ||= response&.headers ? response.headers.transform_keys(&:downcase) : {}
|
|
50
|
-
end
|
|
51
|
-
alias headers all
|
|
52
|
-
|
|
53
|
-
def [](header)
|
|
54
|
-
headers[header]
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def to_h
|
|
58
|
-
{
|
|
59
|
-
strict_transport_security: strict_transport_security || false,
|
|
60
|
-
content_security_policy: content_security_policy || false,
|
|
61
|
-
click_jacking_protection: click_jacking_protection || false,
|
|
62
|
-
server: server,
|
|
63
|
-
xss_protection: xss_protection || false
|
|
64
|
-
}
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class SiteInspector
|
|
4
|
-
class Endpoint
|
|
5
|
-
class Sniffer < Check
|
|
6
|
-
OPEN_SOURCE_FRAMEWORKS = [
|
|
7
|
-
# Sniffles
|
|
8
|
-
:drupal,
|
|
9
|
-
:joomla,
|
|
10
|
-
:movabletype,
|
|
11
|
-
:phpbb,
|
|
12
|
-
:wordpress,
|
|
13
|
-
|
|
14
|
-
# Internal
|
|
15
|
-
:php,
|
|
16
|
-
:expression_engine,
|
|
17
|
-
:cowboy
|
|
18
|
-
].freeze
|
|
19
|
-
|
|
20
|
-
def framework
|
|
21
|
-
cms = sniff :cms
|
|
22
|
-
return cms unless cms.nil?
|
|
23
|
-
return :expression_engine if endpoint.cookies.any? { |c| c.keys.first =~ /^exp_/ }
|
|
24
|
-
return :php if endpoint.cookies['PHPSESSID']
|
|
25
|
-
return :coldfusion if endpoint.cookies['CFID'] && endpoint.cookies['CFTOKEN']
|
|
26
|
-
return :cowboy if endpoint.headers.server.to_s.casecmp('cowboy').zero?
|
|
27
|
-
|
|
28
|
-
nil
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def open_source?
|
|
32
|
-
OPEN_SOURCE_FRAMEWORKS.include?(framework)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def analytics
|
|
36
|
-
sniff :analytics
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def javascript
|
|
40
|
-
sniff :javascript
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def advertising
|
|
44
|
-
sniff :advertising
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def to_h
|
|
48
|
-
{
|
|
49
|
-
framework: framework,
|
|
50
|
-
analytics: analytics,
|
|
51
|
-
javascript: javascript,
|
|
52
|
-
advertising: advertising
|
|
53
|
-
}
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
private
|
|
57
|
-
|
|
58
|
-
def sniff(type)
|
|
59
|
-
require 'sniffles'
|
|
60
|
-
results = Sniffles.sniff(endpoint.content.body, type).select { |_name, meta| meta[:found] }
|
|
61
|
-
results&.keys&.first
|
|
62
|
-
rescue StandardError
|
|
63
|
-
nil
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class SiteInspector
|
|
4
|
-
class Endpoint
|
|
5
|
-
class Wappalyzer < Check
|
|
6
|
-
ENDPOINT = 'https://api.wappalyzer.com/lookup/v2/'
|
|
7
|
-
|
|
8
|
-
def to_h
|
|
9
|
-
return {} unless data['technologies']
|
|
10
|
-
|
|
11
|
-
@to_h ||= begin
|
|
12
|
-
technologies = {}
|
|
13
|
-
data['technologies'].each do |t|
|
|
14
|
-
category = t['categories'].first
|
|
15
|
-
category = category ? category['name'] : 'Other'
|
|
16
|
-
technologies[category] ||= []
|
|
17
|
-
technologies[category].push t['name']
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
technologies
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
private
|
|
25
|
-
|
|
26
|
-
def request
|
|
27
|
-
@request ||= begin
|
|
28
|
-
options = SiteInspector.typhoeus_defaults
|
|
29
|
-
headers = options[:headers].merge({ "x-api-key": api_key })
|
|
30
|
-
options = options.merge(method: :get, headers: headers)
|
|
31
|
-
Typhoeus::Request.new(url, options)
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def data
|
|
36
|
-
return {} unless api_key && api_key != ''
|
|
37
|
-
|
|
38
|
-
@data ||= begin
|
|
39
|
-
SiteInspector.hydra.queue(request)
|
|
40
|
-
SiteInspector.hydra.run
|
|
41
|
-
|
|
42
|
-
response = request.response
|
|
43
|
-
if response.success?
|
|
44
|
-
JSON.parse(response.body).first
|
|
45
|
-
else
|
|
46
|
-
{}
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def url
|
|
52
|
-
url = Addressable::URI.parse(ENDPOINT)
|
|
53
|
-
url.query_values = { urls: endpoint.uri }
|
|
54
|
-
url
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def api_key
|
|
58
|
-
@api_key ||= ENV['WAPPALYZER_API_KEY']
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class SiteInspector
|
|
4
|
-
class Endpoint
|
|
5
|
-
class Whois < Check
|
|
6
|
-
def domain
|
|
7
|
-
@domain ||= whois.lookup host
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def ip
|
|
11
|
-
@ip ||= whois.lookup ip_address
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def to_h
|
|
15
|
-
{
|
|
16
|
-
domain: record_to_h(domain),
|
|
17
|
-
ip: record_to_h(ip)
|
|
18
|
-
}
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
def record_to_h(record)
|
|
24
|
-
record.content.scan(/^\s*(.*?):\s*(.*?)\r?\n/).to_h
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def ip_address
|
|
28
|
-
@ip_address ||= Resolv.getaddress host
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def whois
|
|
32
|
-
@whois ||= ::Whois::Client.new
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class SiteInspector
|
|
4
|
-
class DiskCache
|
|
5
|
-
def initialize(dir = nil, replace = nil)
|
|
6
|
-
@dir = dir || ENV['CACHE']
|
|
7
|
-
@replace = replace || ENV['CACHE_REPLACE']
|
|
8
|
-
@memory = {}
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def get(request)
|
|
12
|
-
return unless File.exist?(path(request))
|
|
13
|
-
return @memory[request] if @memory[request]
|
|
14
|
-
|
|
15
|
-
if @replace
|
|
16
|
-
FileUtils.rm(path(request))
|
|
17
|
-
nil
|
|
18
|
-
else
|
|
19
|
-
begin
|
|
20
|
-
contents = File.read(path(request))
|
|
21
|
-
Marshal.load(contents)
|
|
22
|
-
rescue ArgumentError
|
|
23
|
-
FileUtils.rm(path(request))
|
|
24
|
-
nil
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def set(request, response)
|
|
30
|
-
File.write(path(request), Marshal.dump(response))
|
|
31
|
-
@memory[request] = response
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
# The `request` is a Typhoeus::Request, which provides a
|
|
37
|
-
# unique `cache_key` string for exactly this sort of thing.
|
|
38
|
-
def path(request)
|
|
39
|
-
File.join(@dir, request.cache_key)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
describe SiteInspector::Endpoint::Sniffer do
|
|
6
|
-
def stub_header(header, value)
|
|
7
|
-
allow(subject.endpoint.headers).to receive(:headers) { { header => value } }
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def set_cookie(key, value)
|
|
11
|
-
cookies = [
|
|
12
|
-
CGI::Cookie.new(
|
|
13
|
-
'name' => 'foo',
|
|
14
|
-
'value' => 'bar',
|
|
15
|
-
'domain' => 'example.com',
|
|
16
|
-
'path' => '/'
|
|
17
|
-
),
|
|
18
|
-
CGI::Cookie.new(
|
|
19
|
-
'name' => key,
|
|
20
|
-
'value' => value,
|
|
21
|
-
'domain' => 'example.com',
|
|
22
|
-
'path' => '/'
|
|
23
|
-
)
|
|
24
|
-
].map(&:to_s)
|
|
25
|
-
|
|
26
|
-
stub_request(:get, 'http://example.com/')
|
|
27
|
-
.to_return(status: 200, body: '')
|
|
28
|
-
|
|
29
|
-
stub_request(:head, 'http://example.com/')
|
|
30
|
-
.to_return(status: 200, headers: { 'set-cookie' => cookies })
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
context 'stubbed body' do
|
|
34
|
-
subject do
|
|
35
|
-
body = <<-BODY
|
|
36
|
-
<html>
|
|
37
|
-
<head>
|
|
38
|
-
<link rel='stylesheet' href='/wp-content/themes/foo/style.css type='text/css' media='all' />
|
|
39
|
-
</head>
|
|
40
|
-
<body>
|
|
41
|
-
<h1>Some page</h1>
|
|
42
|
-
<script>
|
|
43
|
-
jQuery(); googletag.pubads();
|
|
44
|
-
</script>
|
|
45
|
-
<script>
|
|
46
|
-
var _gaq=[['_setAccount','UA-12345678-1'],['_trackPageview']];
|
|
47
|
-
(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
|
|
48
|
-
g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
|
|
49
|
-
s.parentNode.insertBefore(g,s)}(document,'script'));
|
|
50
|
-
</script>
|
|
51
|
-
</body>
|
|
52
|
-
</html>
|
|
53
|
-
BODY
|
|
54
|
-
|
|
55
|
-
stub_request(:get, 'http://example.com/')
|
|
56
|
-
.to_return(status: 200, body: body)
|
|
57
|
-
|
|
58
|
-
stub_request(:head, 'http://example.com/')
|
|
59
|
-
.to_return(status: 200)
|
|
60
|
-
endpoint = SiteInspector::Endpoint.new('http://example.com')
|
|
61
|
-
described_class.new(endpoint)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it 'sniffs' do
|
|
65
|
-
sniff = subject.send(:sniff, :cms)
|
|
66
|
-
expect(sniff).to be(:wordpress)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
it 'detects the CMS' do
|
|
70
|
-
expect(subject.framework).to be(:wordpress)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
it 'detects the analytics' do
|
|
74
|
-
expect(subject.analytics).to be(:google_analytics)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
it 'detects javascript' do
|
|
78
|
-
expect(subject.javascript).to be(:jquery)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it 'detects advertising' do
|
|
82
|
-
expect(subject.advertising).to be(:adsense)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
it 'knows wordpress is open source' do
|
|
86
|
-
expect(subject.open_source?).to be(true)
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
context 'no body' do
|
|
91
|
-
subject do
|
|
92
|
-
endpoint = SiteInspector::Endpoint.new('http://example.com')
|
|
93
|
-
described_class.new(endpoint)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
it "knows when something isn't open source" do
|
|
97
|
-
set_cookie('foo', 'bar')
|
|
98
|
-
expect(subject.open_source?).to be(false)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
it 'detects PHP' do
|
|
102
|
-
set_cookie('PHPSESSID', '1234')
|
|
103
|
-
expect(subject.framework).to be(:php)
|
|
104
|
-
expect(subject.open_source?).to be(true)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
it 'detects Expression Engine' do
|
|
108
|
-
set_cookie('exp_csrf_token', '1234')
|
|
109
|
-
expect(subject.framework).to be(:expression_engine)
|
|
110
|
-
expect(subject.open_source?).to be(true)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
it 'detects cowboy' do
|
|
114
|
-
stub_request(:get, 'http://example.com/')
|
|
115
|
-
.to_return(status: 200, body: '')
|
|
116
|
-
|
|
117
|
-
stub_request(:head, 'http://example.com/')
|
|
118
|
-
.to_return(status: 200, headers: { 'server' => 'Cowboy' })
|
|
119
|
-
|
|
120
|
-
expect(subject.framework).to be(:cowboy)
|
|
121
|
-
expect(subject.open_source?).to be(true)
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
it 'detects ColdFusion' do
|
|
125
|
-
cookies = [
|
|
126
|
-
CGI::Cookie.new(
|
|
127
|
-
'name' => 'CFID',
|
|
128
|
-
'value' => '1234',
|
|
129
|
-
'domain' => 'example.com',
|
|
130
|
-
'path' => '/'
|
|
131
|
-
),
|
|
132
|
-
CGI::Cookie.new(
|
|
133
|
-
'name' => 'CFTOKEN',
|
|
134
|
-
'value' => '5678',
|
|
135
|
-
'domain' => 'example.com',
|
|
136
|
-
'path' => '/'
|
|
137
|
-
)
|
|
138
|
-
].map(&:to_s)
|
|
139
|
-
|
|
140
|
-
stub_request(:get, 'http://example.com/')
|
|
141
|
-
.to_return(status: 200, body: '')
|
|
142
|
-
|
|
143
|
-
stub_request(:head, 'http://example.com/')
|
|
144
|
-
.to_return(status: 200, headers: { 'set-cookie' => cookies })
|
|
145
|
-
|
|
146
|
-
expect(subject.framework).to be(:coldfusion)
|
|
147
|
-
expect(subject.open_source?).to be(false)
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
end
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
describe SiteInspector::Endpoint::Wappalyzer do
|
|
6
|
-
subject { described_class.new(endpoint) }
|
|
7
|
-
|
|
8
|
-
let(:domain) { 'http://ben.balter.com.com' }
|
|
9
|
-
let(:endpoint) { SiteInspector::Endpoint.new(domain) }
|
|
10
|
-
let(:url) { "https://api.wappalyzer.com/lookup/v2/?urls=#{domain}/" }
|
|
11
|
-
|
|
12
|
-
before do
|
|
13
|
-
path = File.expand_path '../fixtures/wappalyzer.json', __dir__
|
|
14
|
-
body = File.read path
|
|
15
|
-
stub_request(:get, url).to_return(status: 200, body: body)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
it 'returns the API response' do
|
|
19
|
-
expected = {
|
|
20
|
-
'Analytics' => ['Google Analytics'],
|
|
21
|
-
'CDN' => %w[Cloudflare Fastly],
|
|
22
|
-
'Caching' => ['Varnish'],
|
|
23
|
-
'Other' => %w[Disqus Jekyll],
|
|
24
|
-
'PaaS' => ['GitHub Pages'],
|
|
25
|
-
'Web frameworks' => ['Ruby on Rails']
|
|
26
|
-
}
|
|
27
|
-
expect(subject.to_h).to eql(expected)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it 'fails gracefully' do
|
|
31
|
-
stub_request(:get, url).to_return(status: 400, body: '')
|
|
32
|
-
expect(subject.to_h).to eql({})
|
|
33
|
-
end
|
|
34
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
describe SiteInspector::Cache do
|
|
6
|
-
it 'stores a cache value' do
|
|
7
|
-
subject.set 'foo', 'bar'
|
|
8
|
-
expect(subject.instance_variable_get('@memory')['foo']).to eql('bar')
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
it 'retrieves values from the cache' do
|
|
12
|
-
subject.instance_variable_set('@memory', 'foo' => 'bar')
|
|
13
|
-
expect(subject.get('foo')).to eql('bar')
|
|
14
|
-
end
|
|
15
|
-
end
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
describe SiteInspector::DiskCache do
|
|
6
|
-
subject { described_class.new(tmpdir) }
|
|
7
|
-
|
|
8
|
-
before do
|
|
9
|
-
FileUtils.rm_rf(tmpdir)
|
|
10
|
-
Dir.mkdir(tmpdir)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it 'writes a value to disk' do
|
|
14
|
-
foo = Typhoeus::Request.new('foo')
|
|
15
|
-
|
|
16
|
-
path = File.expand_path foo.cache_key, tmpdir
|
|
17
|
-
expect(File.exist?(path)).to be(false)
|
|
18
|
-
|
|
19
|
-
subject.set foo, 'bar'
|
|
20
|
-
|
|
21
|
-
expect(File.exist?(path)).to be(true)
|
|
22
|
-
expect(File.open(path).read).to eql("I\"bar:ET")
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it 'reads a value from disk' do
|
|
26
|
-
foo = Typhoeus::Request.new('foo')
|
|
27
|
-
|
|
28
|
-
path = File.expand_path foo.cache_key, tmpdir
|
|
29
|
-
File.write(path, "I\"bar:ET")
|
|
30
|
-
expect(subject.get(foo)).to eql('bar')
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
it "calculates a file's path" do
|
|
34
|
-
foo = Typhoeus::Request.new('foo')
|
|
35
|
-
|
|
36
|
-
path = File.expand_path foo.cache_key, tmpdir
|
|
37
|
-
expect(subject.send(:path, foo)).to eql(path)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
File without changes
|
/data/spec/{checks/site_inspector_endpoint_check_spec.rb → site_inspector/endpoint/check_spec.rb}
RENAMED
|
File without changes
|
/data/spec/{checks/site_inspector_endpoint_https_spec.rb → site_inspector/endpoint/https_spec.rb}
RENAMED
|
File without changes
|