deadfinder 1.3.5 → 1.4.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/lib/deadfinder/logger.rb +20 -6
- data/lib/deadfinder/version.rb +1 -1
- data/lib/deadfinder.rb +46 -9
- metadata +54 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf75290cf2187f96b42398ac743fd60fc203616a2cd763c4de85a179b6dc4ae6
|
4
|
+
data.tar.gz: cd894f1ac871e057ac3df4e1d0b89b6bf08c9625f9089c9a0213e94bc4f43010
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9e2c6ee268a3ce006c3a23c123852cf23e75b59218876aa0fd1a0ef779e07fb04994b781bb97d231b01db549903eb206c11b1a15774fcf8bce73423d7c1870b
|
7
|
+
data.tar.gz: dbe9ab7a014687e2fb34cb893cecb236c842c6d8dd3b9dcc5107c96630fe9b123684608e047db182a6f94eb9393281410b7c7831cb0c560d72ba529da11e49d1
|
data/lib/deadfinder/logger.rb
CHANGED
@@ -3,27 +3,41 @@
|
|
3
3
|
require 'colorize'
|
4
4
|
|
5
5
|
class Logger
|
6
|
+
@silent = false
|
7
|
+
|
8
|
+
def self.set_silent
|
9
|
+
@silent = true
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.silent?
|
13
|
+
@silent
|
14
|
+
end
|
15
|
+
|
6
16
|
def self.info(text)
|
7
|
-
puts 'ℹ '.colorize(:blue) + text.to_s.colorize(:light_blue)
|
17
|
+
puts 'ℹ '.colorize(:blue) + text.to_s.colorize(:light_blue) unless silent?
|
8
18
|
end
|
9
19
|
|
10
20
|
def self.error(text)
|
11
|
-
puts '⚠︎ '.colorize(:red) + text.to_s
|
21
|
+
puts '⚠︎ '.colorize(:red) + text.to_s unless silent?
|
12
22
|
end
|
13
23
|
|
14
24
|
def self.target(text)
|
15
|
-
puts '► '.colorize(:green) + text.to_s.colorize(:light_green)
|
25
|
+
puts '► '.colorize(:green) + text.to_s.colorize(:light_green) unless silent?
|
16
26
|
end
|
17
27
|
|
18
28
|
def self.sub_info(text)
|
19
|
-
puts ' ● '.colorize(:blue) + text.to_s.colorize(:light_blue)
|
29
|
+
puts ' ● '.colorize(:blue) + text.to_s.colorize(:light_blue) unless silent?
|
20
30
|
end
|
21
31
|
|
22
32
|
def self.sub_done(text)
|
23
|
-
puts ' ✓ '.colorize(:blue) + text.to_s.colorize(:light_blue)
|
33
|
+
puts ' ✓ '.colorize(:blue) + text.to_s.colorize(:light_blue) unless silent?
|
24
34
|
end
|
25
35
|
|
26
36
|
def self.found(text)
|
27
|
-
puts " ✘ #{text}".colorize(:red)
|
37
|
+
puts " ✘ #{text}".colorize(:red) unless silent?
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.verbose(text)
|
41
|
+
puts ' ➜ '.colorize(:yellow) + text.to_s.colorize(:light_yellow) unless silent?
|
28
42
|
end
|
29
43
|
end
|
data/lib/deadfinder/version.rb
CHANGED
data/lib/deadfinder.rb
CHANGED
@@ -9,7 +9,6 @@ require 'deadfinder/logger'
|
|
9
9
|
require 'deadfinder/version'
|
10
10
|
require 'concurrent-edge'
|
11
11
|
require 'sitemap-parser'
|
12
|
-
require 'set'
|
13
12
|
require 'json'
|
14
13
|
|
15
14
|
Channel = Concurrent::Channel
|
@@ -18,7 +17,20 @@ CacheQue = Concurrent::Map.new
|
|
18
17
|
Output = Concurrent::Map.new
|
19
18
|
|
20
19
|
class DeadFinderRunner
|
20
|
+
def default_options
|
21
|
+
{
|
22
|
+
'concurrency' => 50,
|
23
|
+
'timeout' => 10,
|
24
|
+
'output' => '',
|
25
|
+
'headers' => [],
|
26
|
+
'silent' => true,
|
27
|
+
'verbose' => false,
|
28
|
+
'include30x' => false
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
21
32
|
def run(target, options)
|
33
|
+
Logger.set_silent if options['silent']
|
22
34
|
headers = options['headers'].each_with_object({}) do |header, hash|
|
23
35
|
kv = header.split(': ')
|
24
36
|
hash[kv[0]] = kv[1]
|
@@ -66,14 +78,26 @@ class DeadFinderRunner
|
|
66
78
|
CacheSet[j] = true
|
67
79
|
begin
|
68
80
|
CacheQue[j] = true
|
69
|
-
URI.
|
70
|
-
|
71
|
-
|
72
|
-
|
81
|
+
uri = URI.parse(j)
|
82
|
+
|
83
|
+
# Create HTTP request with timeout and headers
|
84
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
85
|
+
http.use_ssl = (uri.scheme == 'https')
|
86
|
+
http.read_timeout = options['timeout'].to_i if options['timeout']
|
87
|
+
|
88
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
89
|
+
response = http.request(request)
|
90
|
+
status_code = response.code.to_i
|
91
|
+
Logger.verbose "Status Code: #{status_code} for #{j}" if options['verbose']
|
92
|
+
|
93
|
+
if status_code >= 400 || (status_code >= 300 && options['include30x'])
|
94
|
+
Logger.found "[#{status_code} #{response.message}] #{j}"
|
73
95
|
CacheQue[j] = false
|
74
96
|
Output[target] ||= []
|
75
97
|
Output[target] << j
|
76
98
|
end
|
99
|
+
rescue StandardError => e
|
100
|
+
Logger.verbose "[#{e}] #{j}" if options['verbose']
|
77
101
|
end
|
78
102
|
end
|
79
103
|
results << j
|
@@ -96,35 +120,49 @@ class DeadFinderRunner
|
|
96
120
|
end
|
97
121
|
|
98
122
|
def run_pipe(options)
|
123
|
+
Logger.set_silent if options['silent']
|
124
|
+
|
125
|
+
Logger.info 'Reading from STDIN'
|
99
126
|
app = DeadFinderRunner.new
|
100
127
|
while $stdin.gets
|
101
128
|
target = $LAST_READ_LINE.chomp
|
129
|
+
Logger.target "Checking: #{target}"
|
102
130
|
app.run target, options
|
103
131
|
end
|
104
132
|
gen_output(options)
|
105
133
|
end
|
106
134
|
|
107
135
|
def run_file(filename, options)
|
136
|
+
Logger.set_silent if options['silent']
|
137
|
+
|
138
|
+
Logger.info "Reading: #{filename}"
|
108
139
|
app = DeadFinderRunner.new
|
109
140
|
File.foreach(filename) do |line|
|
110
141
|
target = line.chomp
|
142
|
+
Logger.target "Checking: #{target}"
|
111
143
|
app.run target, options
|
112
144
|
end
|
113
145
|
gen_output(options)
|
114
146
|
end
|
115
147
|
|
116
148
|
def run_url(url, options)
|
149
|
+
Logger.set_silent if options['silent']
|
150
|
+
|
151
|
+
Logger.target "Checking: #{url}"
|
117
152
|
app = DeadFinderRunner.new
|
118
153
|
app.run url, options
|
119
154
|
gen_output(options)
|
120
155
|
end
|
121
156
|
|
122
157
|
def run_sitemap(sitemap_url, options)
|
158
|
+
Logger.set_silent if options['silent']
|
159
|
+
Logger.info "Parsing sitemap: #{sitemap_url}"
|
123
160
|
app = DeadFinderRunner.new
|
124
161
|
base_uri = URI(sitemap_url)
|
125
162
|
sitemap = SitemapParser.new sitemap_url, { recurse: true }
|
126
163
|
sitemap.to_a.each do |url|
|
127
164
|
turl = generate_url url, base_uri
|
165
|
+
Logger.target "Checking: #{turl}"
|
128
166
|
app.run turl, options
|
129
167
|
end
|
130
168
|
gen_output(options)
|
@@ -135,32 +173,31 @@ def gen_output(options)
|
|
135
173
|
end
|
136
174
|
|
137
175
|
class DeadFinder < Thor
|
176
|
+
class_option :include30x, aliases: :r, default: false, type: :boolean, desc: 'Include 30x redirections'
|
138
177
|
class_option :concurrency, aliases: :c, default: 50, type: :numeric, desc: 'Number of concurrency'
|
139
178
|
class_option :timeout, aliases: :t, default: 10, type: :numeric, desc: 'Timeout in seconds'
|
140
179
|
class_option :output, aliases: :o, default: '', type: :string, desc: 'File to write JSON result'
|
141
180
|
class_option :headers, aliases: :H, default: [], type: :array, desc: 'Custom HTTP headers to send with request'
|
181
|
+
class_option :silent, aliases: :s, default: false, type: :boolean, desc: 'Silent mode'
|
182
|
+
class_option :verbose, aliases: :v, default: false, type: :boolean, desc: 'Verbose mode'
|
142
183
|
|
143
184
|
desc 'pipe', 'Scan the URLs from STDIN. (e.g cat urls.txt | deadfinder pipe)'
|
144
185
|
def pipe
|
145
|
-
Logger.info 'Pipe mode'
|
146
186
|
run_pipe options
|
147
187
|
end
|
148
188
|
|
149
189
|
desc 'file <FILE>', 'Scan the URLs from File. (e.g deadfinder file urls.txt)'
|
150
190
|
def file(filename)
|
151
|
-
Logger.info 'File mode'
|
152
191
|
run_file filename, options
|
153
192
|
end
|
154
193
|
|
155
194
|
desc 'url <URL>', 'Scan the Single URL.'
|
156
195
|
def url(url)
|
157
|
-
Logger.info 'Single URL mode'
|
158
196
|
run_url url, options
|
159
197
|
end
|
160
198
|
|
161
199
|
desc 'sitemap <SITEMAP-URL>', 'Scan the URLs from sitemap.'
|
162
200
|
def sitemap(sitemap)
|
163
|
-
Logger.info 'Sitemap mode'
|
164
201
|
run_sitemap sitemap, options
|
165
202
|
end
|
166
203
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deadfinder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hahwul
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -17,6 +17,9 @@ dependencies:
|
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 0.8.0
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.8.0
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -24,6 +27,9 @@ dependencies:
|
|
24
27
|
- - "~>"
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: 0.8.0
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.8.0
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: concurrent-ruby-edge
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -31,6 +37,9 @@ dependencies:
|
|
31
37
|
- - "~>"
|
32
38
|
- !ruby/object:Gem::Version
|
33
39
|
version: 0.6.0
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 0.6.0
|
34
43
|
type: :runtime
|
35
44
|
prerelease: false
|
36
45
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -38,6 +47,9 @@ dependencies:
|
|
38
47
|
- - "~>"
|
39
48
|
- !ruby/object:Gem::Version
|
40
49
|
version: 0.6.0
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 0.6.0
|
41
53
|
- !ruby/object:Gem::Dependency
|
42
54
|
name: json
|
43
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,6 +57,9 @@ dependencies:
|
|
45
57
|
- - "~>"
|
46
58
|
- !ruby/object:Gem::Version
|
47
59
|
version: 2.6.0
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 2.6.0
|
48
63
|
type: :runtime
|
49
64
|
prerelease: false
|
50
65
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -52,6 +67,9 @@ dependencies:
|
|
52
67
|
- - "~>"
|
53
68
|
- !ruby/object:Gem::Version
|
54
69
|
version: 2.6.0
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 2.6.0
|
55
73
|
- !ruby/object:Gem::Dependency
|
56
74
|
name: nokogiri
|
57
75
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,6 +77,9 @@ dependencies:
|
|
59
77
|
- - "~>"
|
60
78
|
- !ruby/object:Gem::Version
|
61
79
|
version: 1.13.0
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.13.0
|
62
83
|
type: :runtime
|
63
84
|
prerelease: false
|
64
85
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -66,6 +87,9 @@ dependencies:
|
|
66
87
|
- - "~>"
|
67
88
|
- !ruby/object:Gem::Version
|
68
89
|
version: 1.13.0
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 1.13.0
|
69
93
|
- !ruby/object:Gem::Dependency
|
70
94
|
name: open-uri
|
71
95
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,6 +97,9 @@ dependencies:
|
|
73
97
|
- - "~>"
|
74
98
|
- !ruby/object:Gem::Version
|
75
99
|
version: 0.2.0
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 0.2.0
|
76
103
|
type: :runtime
|
77
104
|
prerelease: false
|
78
105
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -80,20 +107,29 @@ dependencies:
|
|
80
107
|
- - "~>"
|
81
108
|
- !ruby/object:Gem::Version
|
82
109
|
version: 0.2.0
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: 0.2.0
|
83
113
|
- !ruby/object:Gem::Dependency
|
84
114
|
name: set
|
85
115
|
requirement: !ruby/object:Gem::Requirement
|
86
116
|
requirements:
|
87
117
|
- - "~>"
|
88
118
|
- !ruby/object:Gem::Version
|
89
|
-
version: 1.
|
119
|
+
version: 1.1.0
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: 1.1.0
|
90
123
|
type: :runtime
|
91
124
|
prerelease: false
|
92
125
|
version_requirements: !ruby/object:Gem::Requirement
|
93
126
|
requirements:
|
94
127
|
- - "~>"
|
95
128
|
- !ruby/object:Gem::Version
|
96
|
-
version: 1.
|
129
|
+
version: 1.1.0
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 1.1.0
|
97
133
|
- !ruby/object:Gem::Dependency
|
98
134
|
name: sitemap-parser
|
99
135
|
requirement: !ruby/object:Gem::Requirement
|
@@ -101,6 +137,9 @@ dependencies:
|
|
101
137
|
- - "~>"
|
102
138
|
- !ruby/object:Gem::Version
|
103
139
|
version: 0.5.0
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: 0.5.0
|
104
143
|
type: :runtime
|
105
144
|
prerelease: false
|
106
145
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -108,6 +147,9 @@ dependencies:
|
|
108
147
|
- - "~>"
|
109
148
|
- !ruby/object:Gem::Version
|
110
149
|
version: 0.5.0
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 0.5.0
|
111
153
|
- !ruby/object:Gem::Dependency
|
112
154
|
name: thor
|
113
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -115,6 +157,9 @@ dependencies:
|
|
115
157
|
- - "~>"
|
116
158
|
- !ruby/object:Gem::Version
|
117
159
|
version: 1.2.0
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: 1.2.0
|
118
163
|
type: :runtime
|
119
164
|
prerelease: false
|
120
165
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -122,6 +167,9 @@ dependencies:
|
|
122
167
|
- - "~>"
|
123
168
|
- !ruby/object:Gem::Version
|
124
169
|
version: 1.2.0
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: 1.2.0
|
125
173
|
description: Find dead-links (broken links). Dead link (broken link) means a link
|
126
174
|
within a web page that cannot be connected. These links can have a negative impact
|
127
175
|
to SEO and Security. This tool makes it easy to identify and modify.
|
@@ -150,14 +198,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
150
198
|
requirements:
|
151
199
|
- - ">="
|
152
200
|
- !ruby/object:Gem::Version
|
153
|
-
version:
|
201
|
+
version: 3.3.0
|
154
202
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
203
|
requirements:
|
156
204
|
- - ">="
|
157
205
|
- !ruby/object:Gem::Version
|
158
206
|
version: '0'
|
159
207
|
requirements: []
|
160
|
-
rubygems_version: 3.5.
|
208
|
+
rubygems_version: 3.5.16
|
161
209
|
signing_key:
|
162
210
|
specification_version: 4
|
163
211
|
summary: Find dead-links (broken links)
|