site-inspector 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.travis.yml +4 -1
- data/README.md +11 -2
- data/lib/site-inspector/checks/accessibility.rb +114 -0
- data/lib/site-inspector/checks/check.rb +4 -0
- data/lib/site-inspector/checks/content.rb +6 -5
- data/lib/site-inspector/checks/cookies.rb +45 -0
- data/lib/site-inspector/checks/headers.rb +0 -16
- data/lib/site-inspector/checks/sniffer.rb +28 -6
- data/lib/site-inspector/disk_cache.rb +3 -1
- data/lib/site-inspector/domain.rb +28 -10
- data/lib/site-inspector/endpoint.rb +5 -8
- data/lib/site-inspector/version.rb +1 -1
- data/lib/site-inspector.rb +5 -1
- data/package.json +23 -0
- data/script/bootstrap +1 -0
- data/script/cibuild +2 -0
- data/site-inspector.gemspec +3 -2
- data/spec/checks/site_inspector_endpoint_accessibility_spec.rb +81 -0
- data/spec/checks/site_inspector_endpoint_check_spec.rb +4 -0
- data/spec/checks/site_inspector_endpoint_content_spec.rb +20 -2
- data/spec/checks/site_inspector_endpoint_cookies_spec.rb +72 -0
- data/spec/checks/site_inspector_endpoint_headers_spec.rb +0 -10
- data/spec/checks/site_inspector_endpoint_sniffer_spec.rb +99 -37
- data/spec/{site_inspector_disc_cache_spec.rb → site_inspector_disk_cache_spec.rb} +13 -7
- data/spec/site_inspector_domain_spec.rb +28 -6
- data/spec/site_inspector_endpoint_spec.rb +32 -11
- data/spec/site_inspector_spec.rb +1 -1
- metadata +27 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b994e74251bb7b1be968d5bbad80273ee3ffea24
|
4
|
+
data.tar.gz: e104a5856e1710233df4da02b234935e56910f3b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c68e92c9e4c7b82aa7f19fb56f625f0656104b026ef81ede02b8f9dff90b430fc1af16062bb0fa8d337ad53f410ee563c127de9c594a3b47ce4a93723b668b90
|
7
|
+
data.tar.gz: 2e07f88d11a2c116289bfeb3e9050ad59b7314523aedeb45cf7d4b4042912c31e2ac4e80828ed27a272cec8952726ed02735c2af4022821255d3685c38478c61
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
A Ruby Gem to sniff information about a domain's technology and capabilities.
|
4
4
|
|
5
|
-
[![Gem Version](https://badge.fury.io/rb/site-inspector.svg)](http://badge.fury.io/rb/site-inspector) [![Build Status](https://travis-ci.org/benbalter/site-inspector
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/site-inspector.svg)](http://badge.fury.io/rb/site-inspector) [![Build Status](https://travis-ci.org/benbalter/site-inspector.svg)](https://travis-ci.org/benbalter/site-inspector)
|
6
6
|
|
7
7
|
## Demo
|
8
8
|
|
@@ -87,6 +87,15 @@ Options:
|
|
87
87
|
|
88
88
|
Each endpoint also returns the following checks:
|
89
89
|
|
90
|
+
#### Accessibility
|
91
|
+
|
92
|
+
Uses the `pa11y` CLI to run automated accessibility tests. Requires `node`. To install `pally`: `[sudo] npm install -g pa11y`.
|
93
|
+
|
94
|
+
* `section508` - Tests against the Section508 standard
|
95
|
+
* `wcag2a` - Tests against the WCAG2A standard
|
96
|
+
* `wcag2aa` - Tests against the WCAG2AA standard
|
97
|
+
* `wcag2aaa` - Tests against the WCAG2AAA standard
|
98
|
+
|
90
99
|
#### Content
|
91
100
|
|
92
101
|
* `doctype` - The HTML doctype returned
|
@@ -136,7 +145,7 @@ Each endpoint also returns the following checks:
|
|
136
145
|
|
137
146
|
## Adding your own check
|
138
147
|
|
139
|
-
[Checks](https://github.com/benbalter/site-inspector
|
148
|
+
[Checks](https://github.com/benbalter/site-inspector/tree/master/lib/site-inspector/checks) are special classes that are children of [`SiteInspector::Endpoint::Check`](https://github.com/benbalter/site-inspector/blob/master/lib/site-inspector/checks/check.rb). You can implement your own check like this:
|
140
149
|
|
141
150
|
```ruby
|
142
151
|
class SiteInspector
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'open3'
|
3
|
+
|
4
|
+
class SiteInspector
|
5
|
+
class Endpoint
|
6
|
+
class Accessibility < Check
|
7
|
+
class Pa11yError < RuntimeError; end
|
8
|
+
|
9
|
+
STANDARDS = {
|
10
|
+
section508: 'Section508', # Default standard
|
11
|
+
wcag2a: 'WCAG2A',
|
12
|
+
wcag2aa: 'WCAG2AA',
|
13
|
+
wcag2aaa: 'WCAG2AAA'
|
14
|
+
}
|
15
|
+
|
16
|
+
DEFAULT_LEVEL = :error
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def pa11y_version
|
20
|
+
output, status = Open3.capture2e("pa11y", "--version")
|
21
|
+
output.strip if status == 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def pa11y?
|
25
|
+
!!(Cliver.detect('pa11y'))
|
26
|
+
end
|
27
|
+
alias_method :enabled?, :pa11y?
|
28
|
+
end
|
29
|
+
|
30
|
+
def level
|
31
|
+
@level ||= DEFAULT_LEVEL
|
32
|
+
end
|
33
|
+
|
34
|
+
def level=(level)
|
35
|
+
raise ArgumentError, "Invalid level '#{level}'" unless [:error, :warning, :notice].include?(level)
|
36
|
+
@level = level
|
37
|
+
end
|
38
|
+
|
39
|
+
def standard?(standard)
|
40
|
+
STANDARDS.keys.include?(standard)
|
41
|
+
end
|
42
|
+
|
43
|
+
def standard
|
44
|
+
@standard ||= STANDARDS.keys.first
|
45
|
+
end
|
46
|
+
|
47
|
+
def standard=(standard)
|
48
|
+
raise ArgumentError, "Unknown standard '#{standard}'" unless standard?(standard)
|
49
|
+
@standard = standard
|
50
|
+
end
|
51
|
+
|
52
|
+
def valid?
|
53
|
+
check[:valid] if check
|
54
|
+
end
|
55
|
+
|
56
|
+
def errors
|
57
|
+
check[:results].count { |r| r["type"] == "error" } if check
|
58
|
+
end
|
59
|
+
|
60
|
+
def check
|
61
|
+
@check ||= pa11y(standard)
|
62
|
+
rescue Pa11yError
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
alias_method :to_h, :check
|
66
|
+
|
67
|
+
def method_missing(method_sym, *arguments, &block)
|
68
|
+
if standard?(method_sym)
|
69
|
+
pa11y(method_sym)
|
70
|
+
else
|
71
|
+
super
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def respond_to?(method_sym, include_private = false)
|
76
|
+
if standard?(method_sym)
|
77
|
+
true
|
78
|
+
else
|
79
|
+
super
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def pa11y(standard)
|
86
|
+
Cliver.assert('pa11y')
|
87
|
+
raise ArgumentError, "Unknown standard '#{standard}'" unless standard?(standard)
|
88
|
+
|
89
|
+
args = [
|
90
|
+
"--standard", STANDARDS[standard],
|
91
|
+
"--reporter", "json",
|
92
|
+
"--level", level.to_s,
|
93
|
+
endpoint.uri.to_s
|
94
|
+
]
|
95
|
+
output, status = run_command(args)
|
96
|
+
|
97
|
+
# Pa11y exit codes: https://github.com/nature/pa11y#exit-codes
|
98
|
+
# 0: No errors, 1: Technical error within pa11y, 2: accessibility error (configurable via --level)
|
99
|
+
raise Pa11yError if status == 1
|
100
|
+
|
101
|
+
{
|
102
|
+
valid: status == 0,
|
103
|
+
results: JSON.parse(output)
|
104
|
+
}
|
105
|
+
rescue Pa11yError, JSON::ParserError
|
106
|
+
raise Pa11yError, "Command `pa11y #{args.join(" ")}` failed: #{output}"
|
107
|
+
end
|
108
|
+
|
109
|
+
def run_command(args)
|
110
|
+
Open3.capture2e("pa11y", *args)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -3,7 +3,7 @@ class SiteInspector
|
|
3
3
|
class Content < Check
|
4
4
|
# Given a path (e.g, "/data"), check if the given path exists on the canonical endpoint
|
5
5
|
def path_exists?(path)
|
6
|
-
endpoint.request(path: path, followlocation: true).success?
|
6
|
+
endpoint.up? && endpoint.request(path: path, followlocation: true).success?
|
7
7
|
end
|
8
8
|
|
9
9
|
def document
|
@@ -17,22 +17,23 @@ class SiteInspector
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def robots_txt?
|
20
|
-
@bodts_txt ||= path_exists?("robots.txt")
|
20
|
+
@bodts_txt ||= path_exists?("robots.txt") if proper_404s?
|
21
21
|
end
|
22
22
|
|
23
23
|
def sitemap_xml?
|
24
|
-
@sitemap_xml ||= path_exists?("sitemap.xml")
|
24
|
+
@sitemap_xml ||= path_exists?("sitemap.xml") if proper_404s?
|
25
25
|
end
|
26
26
|
|
27
27
|
def humans_txt?
|
28
|
-
@humans_txt ||= path_exists?("humans.txt")
|
28
|
+
@humans_txt ||= path_exists?("humans.txt") if proper_404s?
|
29
29
|
end
|
30
30
|
|
31
31
|
def doctype
|
32
|
-
document.internal_subset.
|
32
|
+
document.internal_subset.external_id
|
33
33
|
end
|
34
34
|
|
35
35
|
def prefetch
|
36
|
+
return unless endpoint.up?
|
36
37
|
options = SiteInspector.typhoeus_defaults.merge(followlocation: true)
|
37
38
|
["robots.txt", "sitemap.xml", "humans.txt", random_path].each do |path|
|
38
39
|
request = Typhoeus::Request.new(URI.join(endpoint.uri, path), options)
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class SiteInspector
|
2
|
+
class Endpoint
|
3
|
+
class Cookies < Check
|
4
|
+
|
5
|
+
def any?(&block)
|
6
|
+
if cookie_header.nil? || cookie_header.empty?
|
7
|
+
false
|
8
|
+
elsif block_given?
|
9
|
+
all.any? { |cookie| block.call(cookie) }
|
10
|
+
else
|
11
|
+
true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
alias_method :cookies?, :any?
|
15
|
+
|
16
|
+
def all
|
17
|
+
@cookies ||= cookie_header.map { |c| CGI::Cookie::parse(c) } if cookies?
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](key)
|
21
|
+
all.find { |cookie| cookie.keys.first == key } if cookies?
|
22
|
+
end
|
23
|
+
|
24
|
+
def secure?
|
25
|
+
pairs = cookie_header.join("; ").split("; ") # CGI::Cookies#Parse doesn't seem to like secure headers
|
26
|
+
pairs.any? { |c| c.downcase == "secure" } && pairs.any? { |c| c.downcase == "httponly" }
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_h
|
30
|
+
{
|
31
|
+
:cookie? => any?,
|
32
|
+
:secure? => secure?
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def cookie_header
|
39
|
+
# Cookie header may be an array or string, always return an array
|
40
|
+
[endpoint.headers.all["set-cookie"]].flatten.compact
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -2,12 +2,6 @@ class SiteInspector
|
|
2
2
|
class Endpoint
|
3
3
|
class Headers < Check
|
4
4
|
|
5
|
-
# cookies can have multiple set-cookie headers, so this detects
|
6
|
-
# whether cookies are set, but not all their values.
|
7
|
-
def cookies?
|
8
|
-
!!headers["set-cookie"]
|
9
|
-
end
|
10
|
-
|
11
5
|
# TODO: kill this
|
12
6
|
def strict_transport_security?
|
13
7
|
!!strict_transport_security
|
@@ -49,13 +43,6 @@ class SiteInspector
|
|
49
43
|
xss_protection == "1; mode=block"
|
50
44
|
end
|
51
45
|
|
52
|
-
def secure_cookies?
|
53
|
-
return false if !cookies?
|
54
|
-
cookie = headers["set-cookie"]
|
55
|
-
cookie = cookie.first if cookie.is_a?(Array)
|
56
|
-
!!(cookie =~ /(; secure.*; httponly|; httponly.*; secure)/i)
|
57
|
-
end
|
58
|
-
|
59
46
|
# Returns an array of hashes of downcased key/value header pairs (or an empty hash)
|
60
47
|
def all
|
61
48
|
@all ||= (response && response.headers) ? Hash[response.headers.map{ |k,v| [k.downcase,v] }] : {}
|
@@ -68,14 +55,11 @@ class SiteInspector
|
|
68
55
|
|
69
56
|
def to_h
|
70
57
|
{
|
71
|
-
:cookies => cookies?,
|
72
58
|
:strict_transport_security => strict_transport_security || false,
|
73
59
|
:content_security_policy => content_security_policy || false,
|
74
60
|
:click_jacking_protection => click_jacking_protection || false,
|
75
|
-
:click_jacking_protection => click_jacking_protection || false,
|
76
61
|
:server => server,
|
77
62
|
:xss_protection => xss_protection || false,
|
78
|
-
:secure_cookies => secure_cookies?
|
79
63
|
}
|
80
64
|
end
|
81
65
|
end
|
@@ -2,8 +2,31 @@ class SiteInspector
|
|
2
2
|
class Endpoint
|
3
3
|
class Sniffer < Check
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
OPEN_SOURCE_FRAMEWORKS = [
|
6
|
+
# Sniffles
|
7
|
+
:drupal,
|
8
|
+
:joomla,
|
9
|
+
:movabletype,
|
10
|
+
:phpbb,
|
11
|
+
:wordpress,
|
12
|
+
|
13
|
+
# Internal
|
14
|
+
:php,
|
15
|
+
:expression_engine,
|
16
|
+
:cowboy
|
17
|
+
]
|
18
|
+
|
19
|
+
def framework
|
20
|
+
cms = sniff :cms
|
21
|
+
return cms unless cms.nil?
|
22
|
+
return :expression_engine if endpoint.cookies.any? { |c| c.keys.first =~ /^exp_/ }
|
23
|
+
return :php if endpoint.cookies["PHPSESSID"]
|
24
|
+
return :cowboy if endpoint.headers.server.to_s.downcase == "cowboy"
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def open_source?
|
29
|
+
OPEN_SOURCE_FRAMEWORKS.include?(framework)
|
7
30
|
end
|
8
31
|
|
9
32
|
def analytics
|
@@ -20,7 +43,7 @@ class SiteInspector
|
|
20
43
|
|
21
44
|
def to_h
|
22
45
|
{
|
23
|
-
:
|
46
|
+
:framework => framework,
|
24
47
|
:analytics => analytics,
|
25
48
|
:javascript => javascript,
|
26
49
|
:advertising => advertising
|
@@ -31,9 +54,8 @@ class SiteInspector
|
|
31
54
|
|
32
55
|
def sniff(type)
|
33
56
|
require 'sniffles'
|
34
|
-
results = Sniffles.sniff(endpoint.content.body, type).select { |name, meta| meta[:found]
|
35
|
-
results.
|
36
|
-
results
|
57
|
+
results = Sniffles.sniff(endpoint.content.body, type).select { |name, meta| meta[:found] }
|
58
|
+
results.keys.first if results
|
37
59
|
rescue
|
38
60
|
nil
|
39
61
|
end
|
@@ -31,8 +31,10 @@ class SiteInspector
|
|
31
31
|
|
32
32
|
private
|
33
33
|
|
34
|
+
# The `request` is a Typhoeus::Request, which provides a
|
35
|
+
# unique `cache_key` string for exactly this sort of thing.
|
34
36
|
def path(request)
|
35
|
-
File.join(@dir, request)
|
37
|
+
File.join(@dir, request.cache_key)
|
36
38
|
end
|
37
39
|
end
|
38
40
|
end
|
@@ -32,12 +32,20 @@ class SiteInspector
|
|
32
32
|
Gman.valid? host
|
33
33
|
end
|
34
34
|
|
35
|
-
# Does *any* endpoint return a 200 response code?
|
35
|
+
# Does *any* endpoint return a 200 or 300 response code?
|
36
36
|
def up?
|
37
37
|
endpoints.any? { |e| e.up? }
|
38
38
|
end
|
39
39
|
|
40
|
-
# Does any
|
40
|
+
# Does *any* endpoint respond to HTTP?
|
41
|
+
# TODO: needs to allow an invalid chain.
|
42
|
+
def responds?
|
43
|
+
endpoints.any? { |e| e.responds? }
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
# TODO: These weren't present before, and may not be useful.
|
48
|
+
# Can you connect to www?
|
41
49
|
def www?
|
42
50
|
endpoints.any? { |e| e.www? && e.up? }
|
43
51
|
end
|
@@ -51,11 +59,13 @@ class SiteInspector
|
|
51
59
|
#
|
52
60
|
# * Either of the HTTPS endpoints is listening, and doesn't have
|
53
61
|
# an invalid hostname.
|
62
|
+
#
|
63
|
+
# TODO: needs to allow an invalid chain.
|
54
64
|
def https?
|
55
65
|
endpoints.any? { |e| e.https? && e.up? && e.https.valid? }
|
56
66
|
end
|
57
67
|
|
58
|
-
# HTTPS is enforced if one of the HTTPS endpoints is "
|
68
|
+
# HTTPS is enforced if one of the HTTPS endpoints is "up",
|
59
69
|
# and if both *HTTP* endpoints are either:
|
60
70
|
#
|
61
71
|
# * down, or
|
@@ -66,14 +76,19 @@ class SiteInspector
|
|
66
76
|
# * an HTTP redirect can go to HTTPS on another domain, as long
|
67
77
|
# as it's immediate.
|
68
78
|
# * a domain with an invalid cert can still be enforcing HTTPS.
|
79
|
+
#
|
80
|
+
# TODO: need to ensure the redirect *immediately* goes to HTTPS.
|
81
|
+
# TODO: don't need to require that the HTTPS cert is valid for this purpose.
|
69
82
|
def enforces_https?
|
70
83
|
return false unless https?
|
71
|
-
endpoints.select { |e| e.http? }.all? { |e| e.
|
84
|
+
endpoints.select { |e| e.http? }.all? { |e| !e.up? || (e.redirect && e.redirect.https?) }
|
72
85
|
end
|
73
86
|
|
74
87
|
# we can say that a canonical HTTPS site "defaults" to HTTPS,
|
75
88
|
# even if it doesn't *strictly* enforce it (e.g. having a www
|
76
89
|
# subdomain first to go HTTP root before HTTPS root).
|
90
|
+
#
|
91
|
+
# TODO: not implemented.
|
77
92
|
def defaults_https?
|
78
93
|
raise "Not implemented. Halp?"
|
79
94
|
end
|
@@ -82,9 +97,11 @@ class SiteInspector
|
|
82
97
|
#
|
83
98
|
# * HTTPS is supported, and
|
84
99
|
# * The 'canonical' endpoint gets an immediate internal redirect to HTTP.
|
100
|
+
#
|
101
|
+
# TODO: the redirect must be internal.
|
85
102
|
def downgrades_https?
|
86
103
|
return false unless https?
|
87
|
-
canonical_endpoint.redirect && canonical_endpoint.redirect.http?
|
104
|
+
canonical_endpoint.redirect? && canonical_endpoint.redirect.http?
|
88
105
|
end
|
89
106
|
|
90
107
|
# A domain is "canonically" at www if:
|
@@ -108,7 +125,7 @@ class SiteInspector
|
|
108
125
|
return false unless www?
|
109
126
|
|
110
127
|
# Are both root endpoints down?
|
111
|
-
return true if endpoints.select { |e| e.root? }.all? { |e| e.
|
128
|
+
return true if endpoints.select { |e| e.root? }.all? { |e| !e.up? }
|
112
129
|
|
113
130
|
# Does either root endpoint redirect to a www endpoint?
|
114
131
|
endpoints.select { |e| e.root? }.any? { |e| e.redirect && e.redirect.www? }
|
@@ -139,7 +156,7 @@ class SiteInspector
|
|
139
156
|
return false unless https?
|
140
157
|
|
141
158
|
# Both http endpoints are down
|
142
|
-
return true if endpoints.select { |e| e.http? }.all? { |e| e.
|
159
|
+
return true if endpoints.select { |e| e.http? }.all? { |e| !e.up? }
|
143
160
|
|
144
161
|
# at least one http endpoint redirects immediately to https
|
145
162
|
endpoints.select { |e| e.http? }.any? { |e| e.redirect && e.redirect.https? }
|
@@ -150,7 +167,7 @@ class SiteInspector
|
|
150
167
|
# 2. All endpoints are either down or an external redirect
|
151
168
|
def redirect?
|
152
169
|
return false unless redirect
|
153
|
-
endpoints.all? { |e| e.
|
170
|
+
endpoints.all? { |e| !e.up? || e.external_redirect? }
|
154
171
|
end
|
155
172
|
|
156
173
|
# The first endpoint to respond with a redirect
|
@@ -205,10 +222,11 @@ class SiteInspector
|
|
205
222
|
# Returns a complete hash of the domain's information
|
206
223
|
def to_h(options={})
|
207
224
|
prefetch
|
208
|
-
|
225
|
+
|
209
226
|
hash = {
|
210
227
|
host: host,
|
211
228
|
up: up?,
|
229
|
+
responds: responds?,
|
212
230
|
www: www?,
|
213
231
|
root: root?,
|
214
232
|
https: https?,
|
@@ -220,7 +238,7 @@ class SiteInspector
|
|
220
238
|
hsts: hsts?,
|
221
239
|
hsts_subdomains: hsts_subdomains?,
|
222
240
|
hsts_preload_ready: hsts_preload_ready?,
|
223
|
-
|
241
|
+
canonical_endpoint: canonical_endpoint.to_h(options)
|
224
242
|
}
|
225
243
|
|
226
244
|
if options["all"]
|
@@ -56,11 +56,6 @@ class SiteInspector
|
|
56
56
|
@response ||= request
|
57
57
|
end
|
58
58
|
|
59
|
-
# Does the server return any response? (including 50x)
|
60
|
-
def response?
|
61
|
-
response.code != 0 && !timed_out?
|
62
|
-
end
|
63
|
-
|
64
59
|
def response_code
|
65
60
|
response.response_code.to_s if response
|
66
61
|
end
|
@@ -74,8 +69,9 @@ class SiteInspector
|
|
74
69
|
response && response_code.start_with?("2") || response_code.start_with?("3")
|
75
70
|
end
|
76
71
|
|
77
|
-
|
78
|
-
|
72
|
+
# Does the server respond at all?
|
73
|
+
def responds?
|
74
|
+
response.code != 0 && !timed_out?
|
79
75
|
end
|
80
76
|
|
81
77
|
# If the domain is a redirect, what's the first endpoint we're redirected to?
|
@@ -155,6 +151,7 @@ class SiteInspector
|
|
155
151
|
https: https?,
|
156
152
|
scheme: scheme,
|
157
153
|
up: up?,
|
154
|
+
responds: responds?,
|
158
155
|
timed_out: timed_out?,
|
159
156
|
redirect: redirect?,
|
160
157
|
external_redirect: external_redirect?,
|
@@ -172,7 +169,7 @@ class SiteInspector
|
|
172
169
|
end
|
173
170
|
|
174
171
|
def self.checks
|
175
|
-
ObjectSpace.each_object(Class).select { |klass| klass < Check }
|
172
|
+
ObjectSpace.each_object(Class).select { |klass| klass < Check }.select { |check| check.enabled? }
|
176
173
|
end
|
177
174
|
|
178
175
|
def method_missing(method_sym, *arguments, &block)
|
data/lib/site-inspector.rb
CHANGED
@@ -2,18 +2,22 @@ require 'open-uri'
|
|
2
2
|
require 'addressable/uri'
|
3
3
|
require 'public_suffix'
|
4
4
|
require 'typhoeus'
|
5
|
+
require 'cliver'
|
6
|
+
require 'cgi'
|
5
7
|
|
6
8
|
require_relative 'site-inspector/cache'
|
7
9
|
require_relative 'site-inspector/disk_cache'
|
8
10
|
require_relative 'site-inspector/rails_cache'
|
9
11
|
require_relative 'site-inspector/domain'
|
10
12
|
require_relative 'site-inspector/checks/check'
|
13
|
+
require_relative 'site-inspector/checks/accessibility'
|
11
14
|
require_relative 'site-inspector/checks/content'
|
12
15
|
require_relative 'site-inspector/checks/dns'
|
13
16
|
require_relative 'site-inspector/checks/headers'
|
14
17
|
require_relative 'site-inspector/checks/hsts'
|
15
18
|
require_relative 'site-inspector/checks/https'
|
16
19
|
require_relative 'site-inspector/checks/sniffer'
|
20
|
+
require_relative 'site-inspector/checks/cookies'
|
17
21
|
require_relative 'site-inspector/endpoint'
|
18
22
|
require_relative 'site-inspector/version'
|
19
23
|
|
@@ -46,7 +50,7 @@ class SiteInspector
|
|
46
50
|
:timeout => SiteInspector.timeout,
|
47
51
|
:accept_encoding => "gzip",
|
48
52
|
:headers => {
|
49
|
-
"User-Agent" => "Mozilla/5.0 (compatible; SiteInspector/#{SiteInspector::VERSION}; +https://github.com/benbalter/site-inspector
|
53
|
+
"User-Agent" => "Mozilla/5.0 (compatible; SiteInspector/#{SiteInspector::VERSION}; +https://github.com/benbalter/site-inspector)"
|
50
54
|
}
|
51
55
|
}
|
52
56
|
end
|
data/package.json
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
{
|
2
|
+
"name": "site-inspector",
|
3
|
+
"version": "2.0.0",
|
4
|
+
"description": "Returns information about a domain's technology and capabilities",
|
5
|
+
"main": "site-inspector",
|
6
|
+
"dependencies": {
|
7
|
+
"pa11y": "^2.1.0"
|
8
|
+
},
|
9
|
+
"devDependencies": {},
|
10
|
+
"scripts": {
|
11
|
+
"test": "script/cibuild"
|
12
|
+
},
|
13
|
+
"repository": {
|
14
|
+
"type": "git",
|
15
|
+
"url": "git+https://github.com/benbalter/site-inspector.git"
|
16
|
+
},
|
17
|
+
"author": "",
|
18
|
+
"license": "MIT",
|
19
|
+
"bugs": {
|
20
|
+
"url": "https://github.com/benbalter/site-inspector/issues"
|
21
|
+
},
|
22
|
+
"homepage": "https://github.com/benbalter/site-inspector#readme"
|
23
|
+
}
|
data/script/bootstrap
CHANGED
data/script/cibuild
CHANGED
data/site-inspector.gemspec
CHANGED
@@ -4,11 +4,11 @@ Gem::Specification.new do |s|
|
|
4
4
|
|
5
5
|
s.name = "site-inspector"
|
6
6
|
s.version = SiteInspector::VERSION
|
7
|
-
s.summary = "A Ruby port and v2 of Site Inspector (
|
7
|
+
s.summary = "A Ruby port and v2 of Site Inspector (https://github.com/benbalter/site-inspector)"
|
8
8
|
s.description = "Returns information about a domain's technology and capabilities"
|
9
9
|
s.authors = "Ben Balter"
|
10
10
|
s.email = "ben@balter.com"
|
11
|
-
s.homepage = "https://github.com/benbalter/site-inspector
|
11
|
+
s.homepage = "https://github.com/benbalter/site-inspector"
|
12
12
|
s.license = "MIT"
|
13
13
|
|
14
14
|
s.files = `git ls-files -z`.split("\x0")
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.add_dependency("oj", "~> 2.11")
|
26
26
|
s.add_dependency("mercenary", "~> 0.3")
|
27
27
|
s.add_dependency("colorator", "~> 0.1")
|
28
|
+
s.add_dependency("cliver", "~> 0.3")
|
28
29
|
s.add_development_dependency("pry", "~> 0.10")
|
29
30
|
s.add_development_dependency( "rake", "~> 10.4" )
|
30
31
|
s.add_development_dependency( "rspec", "~> 3.2")
|