UrlCategorise 0.1.7 → 0.1.11
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/.claude/settings.local.json +9 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +56 -0
- data/.sublime-project +14 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +89 -41
- data/README.md +167 -9
- data/Rakefile +1 -1
- data/bin/check_lists +124 -22
- data/bin/export_csv +45 -36
- data/bin/export_hosts +34 -24
- data/bin/generate_categorised_lists +533 -0
- data/bin/generate_social_media_lists +398 -0
- data/bin/generate_video_lists +303 -124
- data/bin/generate_video_lists_focused +381 -0
- data/correct_usage_example.rb +18 -18
- data/lib/url_categorise/active_record_client.rb +11 -11
- data/lib/url_categorise/client.rb +856 -226
- data/lib/url_categorise/constants.rb +148 -70
- data/lib/url_categorise/dataset_processor.rb +68 -64
- data/lib/url_categorise/iab_compliance.rb +111 -99
- data/lib/url_categorise/models.rb +15 -15
- data/lib/url_categorise/version.rb +1 -1
- data/lib/url_categorise.rb +14 -14
- data/lists/blogging_domains.hosts +62 -0
- data/lists/crypto_domains.hosts +46 -0
- data/lists/developer_domains.hosts +108 -0
- data/lists/forum_domains.hosts +65 -0
- data/lists/gaming_domains.hosts +99 -0
- data/lists/messaging_domains.hosts +96 -0
- data/lists/music_domains.hosts +62 -0
- data/lists/security_domains.hosts +48 -0
- data/lists/social_media_domains.hosts +443 -0
- data/lists/streaming_domains.hosts +41 -0
- data/lists/video_hosting_domains.hosts +203 -175
- data/lists/video_url_patterns.txt +15 -15
- data/url_categorise.gemspec +11 -9
- metadata +69 -20
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'net/http'
|
|
5
|
+
require 'uri'
|
|
6
|
+
require 'json'
|
|
7
|
+
require 'fileutils'
|
|
8
|
+
require 'time'
|
|
9
|
+
require 'set'
|
|
10
|
+
require 'optparse'
|
|
11
|
+
|
|
12
|
+
module CategorisedListGenerator
|
|
13
|
+
class SiteParser
|
|
14
|
+
MR_HOLMES_SITE_LIST_URL = 'https://raw.githubusercontent.com/Lucksi/Mr.Holmes/master/Site_lists/Username/site_list.json'
|
|
15
|
+
|
|
16
|
+
# Map Mr.Holmes tags to our category list names
|
|
17
|
+
TAG_TO_CATEGORY = {
|
|
18
|
+
'gaming' => :gaming,
|
|
19
|
+
'fortnite' => :gaming,
|
|
20
|
+
'playstation' => :gaming,
|
|
21
|
+
'minecraft' => :gaming,
|
|
22
|
+
'roblox' => :gaming,
|
|
23
|
+
'steam' => :gaming,
|
|
24
|
+
'chess' => :gaming,
|
|
25
|
+
'chess.com' => :gaming,
|
|
26
|
+
'osu' => :gaming,
|
|
27
|
+
'pokemon' => :gaming,
|
|
28
|
+
'lol' => :gaming,
|
|
29
|
+
'speedrun' => :gaming,
|
|
30
|
+
'programming' => :developer,
|
|
31
|
+
'opensource' => :developer,
|
|
32
|
+
'python' => :developer,
|
|
33
|
+
'ruby' => :developer,
|
|
34
|
+
'npm' => :developer,
|
|
35
|
+
'docker' => :developer,
|
|
36
|
+
'music' => :music,
|
|
37
|
+
'sing' => :music,
|
|
38
|
+
'streaming' => :streaming,
|
|
39
|
+
'forum' => :forum,
|
|
40
|
+
'questions' => :forum,
|
|
41
|
+
'chatting' => :messaging,
|
|
42
|
+
'crypto' => :crypto,
|
|
43
|
+
'bitcoin' => :crypto,
|
|
44
|
+
'bitcoin-forum' => :crypto,
|
|
45
|
+
'blog' => :blogging,
|
|
46
|
+
'article' => :blogging,
|
|
47
|
+
'writing' => :blogging,
|
|
48
|
+
'stories' => :blogging,
|
|
49
|
+
'social' => :social_media,
|
|
50
|
+
'photo' => :social_media,
|
|
51
|
+
'image' => :social_media,
|
|
52
|
+
'portfolio' => :social_media,
|
|
53
|
+
'art' => :social_media,
|
|
54
|
+
'meme' => :social_media,
|
|
55
|
+
'fashion' => :social_media,
|
|
56
|
+
'modelling' => :social_media,
|
|
57
|
+
'shopping' => :social_media,
|
|
58
|
+
'hacking' => :security,
|
|
59
|
+
'bugbounty' => :security,
|
|
60
|
+
'donations' => :social_media,
|
|
61
|
+
'link' => :social_media,
|
|
62
|
+
'gallery' => :social_media
|
|
63
|
+
}.freeze
|
|
64
|
+
|
|
65
|
+
# Categories to generate hosts files for
|
|
66
|
+
CATEGORIES = {
|
|
67
|
+
gaming: {
|
|
68
|
+
filename: 'gaming_domains.hosts',
|
|
69
|
+
title: 'Gaming Platform Domains',
|
|
70
|
+
description: 'gaming platforms and communities'
|
|
71
|
+
},
|
|
72
|
+
developer: {
|
|
73
|
+
filename: 'developer_domains.hosts',
|
|
74
|
+
title: 'Developer Platform Domains',
|
|
75
|
+
description: 'developer tools, package registries, and programming platforms'
|
|
76
|
+
},
|
|
77
|
+
music: {
|
|
78
|
+
filename: 'music_domains.hosts',
|
|
79
|
+
title: 'Music Platform Domains',
|
|
80
|
+
description: 'music streaming and sharing platforms'
|
|
81
|
+
},
|
|
82
|
+
streaming: {
|
|
83
|
+
filename: 'streaming_domains.hosts',
|
|
84
|
+
title: 'Streaming Platform Domains',
|
|
85
|
+
description: 'live streaming platforms'
|
|
86
|
+
},
|
|
87
|
+
forum: {
|
|
88
|
+
filename: 'forum_domains.hosts',
|
|
89
|
+
title: 'Forum and Q&A Domains',
|
|
90
|
+
description: 'forums, Q&A platforms, and community discussion sites'
|
|
91
|
+
},
|
|
92
|
+
messaging: {
|
|
93
|
+
filename: 'messaging_domains.hosts',
|
|
94
|
+
title: 'Messaging Platform Domains',
|
|
95
|
+
description: 'messaging and chat platforms'
|
|
96
|
+
},
|
|
97
|
+
crypto: {
|
|
98
|
+
filename: 'crypto_domains.hosts',
|
|
99
|
+
title: 'Cryptocurrency Platform Domains',
|
|
100
|
+
description: 'cryptocurrency exchanges, forums, and NFT platforms'
|
|
101
|
+
},
|
|
102
|
+
blogging: {
|
|
103
|
+
filename: 'blogging_domains.hosts',
|
|
104
|
+
title: 'Blogging Platform Domains',
|
|
105
|
+
description: 'blogging, writing, and content publishing platforms'
|
|
106
|
+
},
|
|
107
|
+
security: {
|
|
108
|
+
filename: 'security_domains.hosts',
|
|
109
|
+
title: 'Security Community Domains',
|
|
110
|
+
description: 'security research, bug bounty, and hacking community platforms'
|
|
111
|
+
}
|
|
112
|
+
}.freeze
|
|
113
|
+
|
|
114
|
+
def initialize(options = {})
|
|
115
|
+
@category_domains = {}
|
|
116
|
+
CATEGORIES.each_key { |cat| @category_domains[cat] = Set.new }
|
|
117
|
+
@verbose = options[:verbose] || false
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def generate_lists
|
|
121
|
+
puts 'Generating categorised domain lists...'
|
|
122
|
+
|
|
123
|
+
puts 'Adding manually curated domains...'
|
|
124
|
+
add_manual_domains
|
|
125
|
+
|
|
126
|
+
puts 'Fetching Mr.Holmes site list data...'
|
|
127
|
+
fetch_mr_holmes_data
|
|
128
|
+
|
|
129
|
+
create_lists_directory
|
|
130
|
+
|
|
131
|
+
CATEGORIES.each do |category, info|
|
|
132
|
+
generate_hosts_file(category, info)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
puts ''
|
|
136
|
+
puts 'Categorised lists generated successfully!'
|
|
137
|
+
puts 'Files created in lists/ directory:'
|
|
138
|
+
CATEGORIES.each do |category, info|
|
|
139
|
+
puts " - #{info[:filename]} (#{@category_domains[category].size} domains)"
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
|
|
145
|
+
def add_manual_domains
|
|
146
|
+
# Gaming platforms
|
|
147
|
+
add_domains(:gaming, [
|
|
148
|
+
'steamcommunity.com', 'store.steampowered.com', 'steampowered.com',
|
|
149
|
+
'roblox.com', 'www.roblox.com',
|
|
150
|
+
'epicgames.com', 'www.epicgames.com',
|
|
151
|
+
'ea.com', 'www.ea.com',
|
|
152
|
+
'ubisoft.com', 'www.ubisoft.com',
|
|
153
|
+
'blizzard.com', 'www.blizzard.com', 'battle.net',
|
|
154
|
+
'nintendo.com', 'www.nintendo.com',
|
|
155
|
+
'rockstargames.com', 'www.rockstargames.com',
|
|
156
|
+
'twitch.tv', 'www.twitch.tv', 'clips.twitch.tv', 'm.twitch.tv',
|
|
157
|
+
'twitchtracker.com',
|
|
158
|
+
'fortnitetracker.com',
|
|
159
|
+
'psnprofiles.com',
|
|
160
|
+
'osu.ppy.sh',
|
|
161
|
+
'gamespot.com', 'www.gamespot.com',
|
|
162
|
+
'newgrounds.com',
|
|
163
|
+
'speedrun.com', 'www.speedrun.com',
|
|
164
|
+
'chess.com', 'www.chess.com',
|
|
165
|
+
'lichess.org',
|
|
166
|
+
'fandom.com', 'www.fandom.com',
|
|
167
|
+
'pokemonshowdown.com',
|
|
168
|
+
'splits.io',
|
|
169
|
+
'lolprofile.net',
|
|
170
|
+
'pubg.op.gg', 'euw.op.gg', 'op.gg',
|
|
171
|
+
'ign.com', 'www.ign.com',
|
|
172
|
+
'gog.com', 'www.gog.com',
|
|
173
|
+
'humblebundle.com', 'www.humblebundle.com',
|
|
174
|
+
'itch.io',
|
|
175
|
+
'myanimelist.net',
|
|
176
|
+
'crunchyroll.com', 'www.crunchyroll.com'
|
|
177
|
+
])
|
|
178
|
+
|
|
179
|
+
# Developer platforms
|
|
180
|
+
add_domains(:developer, [
|
|
181
|
+
'github.com', 'www.github.com', 'gist.github.com',
|
|
182
|
+
'gitlab.com',
|
|
183
|
+
'bitbucket.org',
|
|
184
|
+
'sourceforge.net',
|
|
185
|
+
'pypi.org',
|
|
186
|
+
'npmjs.com', 'www.npmjs.com',
|
|
187
|
+
'rubygems.org',
|
|
188
|
+
'hub.docker.com',
|
|
189
|
+
'gitee.com',
|
|
190
|
+
'notabug.org',
|
|
191
|
+
'scratch.mit.edu',
|
|
192
|
+
'codewars.com', 'www.codewars.com',
|
|
193
|
+
'codecademy.com', 'www.codecademy.com',
|
|
194
|
+
'hackaday.io',
|
|
195
|
+
'pastebin.com',
|
|
196
|
+
'asciinema.org',
|
|
197
|
+
'drupal.org', 'www.drupal.org',
|
|
198
|
+
'opensource.com',
|
|
199
|
+
'dev.to',
|
|
200
|
+
'stackoverflow.com', 'www.stackoverflow.com',
|
|
201
|
+
'stackexchange.com',
|
|
202
|
+
'crates.io',
|
|
203
|
+
'packagist.org',
|
|
204
|
+
'maven.org',
|
|
205
|
+
'nuget.org',
|
|
206
|
+
'hex.pm',
|
|
207
|
+
'pkg.go.dev',
|
|
208
|
+
'cocoapods.org',
|
|
209
|
+
'pub.dev',
|
|
210
|
+
'cpan.org',
|
|
211
|
+
'cran.r-project.org',
|
|
212
|
+
'conda.io',
|
|
213
|
+
'anaconda.org',
|
|
214
|
+
'codepen.io',
|
|
215
|
+
'jsfiddle.net',
|
|
216
|
+
'replit.com', 'www.replit.com',
|
|
217
|
+
'glitch.com',
|
|
218
|
+
'vercel.com',
|
|
219
|
+
'netlify.com',
|
|
220
|
+
'heroku.com',
|
|
221
|
+
'render.com',
|
|
222
|
+
'fly.io',
|
|
223
|
+
'railway.app'
|
|
224
|
+
])
|
|
225
|
+
|
|
226
|
+
# Music platforms
|
|
227
|
+
add_domains(:music, [
|
|
228
|
+
'soundcloud.com', 'www.soundcloud.com',
|
|
229
|
+
'bandcamp.com', 'www.bandcamp.com',
|
|
230
|
+
'mixcloud.com',
|
|
231
|
+
'audiojungle.net',
|
|
232
|
+
'rateyourmusic.com',
|
|
233
|
+
'smule.com', 'www.smule.com',
|
|
234
|
+
'ourdjtalk.com',
|
|
235
|
+
'house-mixes.com', 'www.house-mixes.com',
|
|
236
|
+
'freesound.org',
|
|
237
|
+
'spotify.com', 'open.spotify.com',
|
|
238
|
+
'music.apple.com',
|
|
239
|
+
'music.amazon.com',
|
|
240
|
+
'tidal.com', 'www.tidal.com',
|
|
241
|
+
'deezer.com', 'www.deezer.com',
|
|
242
|
+
'pandora.com', 'www.pandora.com',
|
|
243
|
+
'last.fm', 'www.last.fm',
|
|
244
|
+
'genius.com',
|
|
245
|
+
'musixmatch.com',
|
|
246
|
+
'songkick.com',
|
|
247
|
+
'discogs.com', 'www.discogs.com',
|
|
248
|
+
'musicbrainz.org'
|
|
249
|
+
])
|
|
250
|
+
|
|
251
|
+
# Streaming platforms
|
|
252
|
+
add_domains(:streaming, [
|
|
253
|
+
'twitch.tv', 'www.twitch.tv', 'clips.twitch.tv',
|
|
254
|
+
'twitchtracker.com',
|
|
255
|
+
'younow.com',
|
|
256
|
+
'pscp.tv', 'www.pscp.tv',
|
|
257
|
+
'livestream.com',
|
|
258
|
+
'kick.com', 'www.kick.com',
|
|
259
|
+
'caffeine.tv',
|
|
260
|
+
'dlive.tv',
|
|
261
|
+
'trovo.live',
|
|
262
|
+
'bigo.tv', 'www.bigo.tv',
|
|
263
|
+
'nimo.tv',
|
|
264
|
+
'streamlabs.com'
|
|
265
|
+
])
|
|
266
|
+
|
|
267
|
+
# Forum and Q&A platforms
|
|
268
|
+
add_domains(:forum, [
|
|
269
|
+
'ask.fm',
|
|
270
|
+
'tellonym.me',
|
|
271
|
+
'disqus.com',
|
|
272
|
+
'quora.com', 'www.quora.com',
|
|
273
|
+
'reddit.com', 'www.reddit.com', 'old.reddit.com',
|
|
274
|
+
'stackoverflow.com', 'www.stackoverflow.com',
|
|
275
|
+
'stackexchange.com',
|
|
276
|
+
'quizsilo.com',
|
|
277
|
+
'community.oracle.com',
|
|
278
|
+
'forum.sublimetext.com',
|
|
279
|
+
'forum.pixelfederation.com',
|
|
280
|
+
'community.signalusers.org',
|
|
281
|
+
'discourse.org',
|
|
282
|
+
'lemmy.world',
|
|
283
|
+
'kbin.social',
|
|
284
|
+
'lobste.rs',
|
|
285
|
+
'news.ycombinator.com',
|
|
286
|
+
'slashdot.org',
|
|
287
|
+
'ngl.link',
|
|
288
|
+
'fandom.com', 'www.fandom.com',
|
|
289
|
+
'colourlovers.com', 'www.colourlovers.com',
|
|
290
|
+
'native-instruments.com', 'www.native-instruments.com'
|
|
291
|
+
])
|
|
292
|
+
|
|
293
|
+
# Messaging platforms
|
|
294
|
+
add_domains(:messaging, [
|
|
295
|
+
'whatsapp.com', 'www.whatsapp.com', 'web.whatsapp.com',
|
|
296
|
+
'telegram.org', 'www.telegram.org', 't.me', 'web.telegram.org',
|
|
297
|
+
'discord.com', 'www.discord.com', 'discord.gg',
|
|
298
|
+
'signal.org', 'www.signal.org',
|
|
299
|
+
'messenger.com', 'www.messenger.com',
|
|
300
|
+
'slack.com', 'www.slack.com',
|
|
301
|
+
'kik.me',
|
|
302
|
+
'viber.com', 'www.viber.com',
|
|
303
|
+
'line.me', 'www.line.me',
|
|
304
|
+
'kakaotalk.com',
|
|
305
|
+
'element.io',
|
|
306
|
+
'matrix.org',
|
|
307
|
+
'rocket.chat',
|
|
308
|
+
'zulip.com',
|
|
309
|
+
'mattermost.com',
|
|
310
|
+
'teams.microsoft.com',
|
|
311
|
+
'skype.com', 'www.skype.com',
|
|
312
|
+
'zoom.us',
|
|
313
|
+
'meet.google.com',
|
|
314
|
+
'webex.com'
|
|
315
|
+
])
|
|
316
|
+
|
|
317
|
+
# Crypto platforms
|
|
318
|
+
add_domains(:crypto, [
|
|
319
|
+
'bitcoinforum.com',
|
|
320
|
+
'opensea.io',
|
|
321
|
+
'coinbase.com', 'www.coinbase.com',
|
|
322
|
+
'binance.com', 'www.binance.com',
|
|
323
|
+
'kraken.com', 'www.kraken.com',
|
|
324
|
+
'coinmarketcap.com',
|
|
325
|
+
'coingecko.com',
|
|
326
|
+
'etherscan.io',
|
|
327
|
+
'blockchain.com',
|
|
328
|
+
'bitcoin.org',
|
|
329
|
+
'ethereum.org',
|
|
330
|
+
'rarible.com',
|
|
331
|
+
'foundation.app',
|
|
332
|
+
'looksrare.org',
|
|
333
|
+
'uniswap.org',
|
|
334
|
+
'pancakeswap.finance',
|
|
335
|
+
'defi.org'
|
|
336
|
+
])
|
|
337
|
+
|
|
338
|
+
# Blogging platforms
|
|
339
|
+
add_domains(:blogging, [
|
|
340
|
+
'medium.com',
|
|
341
|
+
'wordpress.com',
|
|
342
|
+
'blogspot.com',
|
|
343
|
+
'substack.com',
|
|
344
|
+
'hubpages.com',
|
|
345
|
+
'wattpad.com', 'www.wattpad.com',
|
|
346
|
+
'quotev.com', 'www.quotev.com',
|
|
347
|
+
'flipboard.com',
|
|
348
|
+
'buzzfeed.com',
|
|
349
|
+
'about.me',
|
|
350
|
+
'tumblr.com', 'www.tumblr.com',
|
|
351
|
+
'ghost.org',
|
|
352
|
+
'hashnode.dev',
|
|
353
|
+
'beehiiv.com',
|
|
354
|
+
'buttondown.email',
|
|
355
|
+
'revue.email',
|
|
356
|
+
'tinyletter.com',
|
|
357
|
+
'writeas.com', 'write.as',
|
|
358
|
+
'telegraph.ph',
|
|
359
|
+
'noted.lol',
|
|
360
|
+
'bookcrossing.com', 'www.bookcrossing.com',
|
|
361
|
+
'slideshare.net',
|
|
362
|
+
'livejournal.com', 'www.livejournal.com'
|
|
363
|
+
])
|
|
364
|
+
|
|
365
|
+
# Security communities
|
|
366
|
+
add_domains(:security, [
|
|
367
|
+
'hackthebox.eu', 'www.hackthebox.eu', 'app.hackthebox.com',
|
|
368
|
+
'tryhackme.com',
|
|
369
|
+
'hackerone.com',
|
|
370
|
+
'bugcrowd.com',
|
|
371
|
+
'vulnhub.com',
|
|
372
|
+
'exploit-db.com',
|
|
373
|
+
'cvedetails.com',
|
|
374
|
+
'shodan.io',
|
|
375
|
+
'censys.io',
|
|
376
|
+
'virustotal.com',
|
|
377
|
+
'urlscan.io',
|
|
378
|
+
'otx.alienvault.com',
|
|
379
|
+
'intigriti.com',
|
|
380
|
+
'synack.com',
|
|
381
|
+
'cobalt.io',
|
|
382
|
+
'yeswehack.com',
|
|
383
|
+
'portswigger.net'
|
|
384
|
+
])
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def add_domains(category, domains)
|
|
388
|
+
domains.each { |domain| @category_domains[category].add(domain) }
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
def fetch_mr_holmes_data
|
|
392
|
+
uri = URI(MR_HOLMES_SITE_LIST_URL)
|
|
393
|
+
response = Net::HTTP.get_response(uri)
|
|
394
|
+
|
|
395
|
+
unless response.code == '200'
|
|
396
|
+
puts ' Could not fetch from Mr.Holmes repository, using manual domains only'
|
|
397
|
+
return
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
begin
|
|
401
|
+
data = JSON.parse(response.body)
|
|
402
|
+
process_mr_holmes_site_list(data)
|
|
403
|
+
rescue JSON::ParserError => e
|
|
404
|
+
puts " Error parsing Mr.Holmes site list: #{e.message}"
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
@category_domains.each do |category, domains|
|
|
408
|
+
puts " #{category}: #{domains.size} domains" if @verbose
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def process_mr_holmes_site_list(data)
|
|
413
|
+
sites = data.is_a?(Array) ? data.first : data
|
|
414
|
+
return unless sites.is_a?(Hash)
|
|
415
|
+
|
|
416
|
+
sites.each do |_key, site_info|
|
|
417
|
+
next unless site_info.is_a?(Hash)
|
|
418
|
+
|
|
419
|
+
tags = site_info['Tag']
|
|
420
|
+
next unless tags.is_a?(Array)
|
|
421
|
+
|
|
422
|
+
main_domain = site_info['main']
|
|
423
|
+
next unless main_domain
|
|
424
|
+
|
|
425
|
+
domain = clean_mr_holmes_domain(main_domain)
|
|
426
|
+
next unless domain && valid_domain?(domain)
|
|
427
|
+
|
|
428
|
+
# Determine categories from tags (only include categories we have sets for)
|
|
429
|
+
categories = tags.flat_map { |tag| TAG_TO_CATEGORY[tag.downcase.strip] }.compact.uniq
|
|
430
|
+
categories = categories.select { |cat| @category_domains.key?(cat) }
|
|
431
|
+
|
|
432
|
+
categories.each do |category|
|
|
433
|
+
@category_domains[category].add(domain.downcase)
|
|
434
|
+
|
|
435
|
+
# Also extract domains from user URLs
|
|
436
|
+
extract_domain_to_category(site_info['user'], category)
|
|
437
|
+
extract_domain_to_category(site_info['user2'], category)
|
|
438
|
+
extract_domain_to_category(site_info['Scrapable_url'], category) if site_info['Scrapable_url']
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
def extract_domain_to_category(url, category)
|
|
444
|
+
return unless url
|
|
445
|
+
|
|
446
|
+
match = url.match(%r{https?://(?:www\.)?([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})})
|
|
447
|
+
return unless match
|
|
448
|
+
|
|
449
|
+
domain = match[1].downcase
|
|
450
|
+
@category_domains[category].add(domain) if valid_domain?(domain)
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
def clean_mr_holmes_domain(domain)
|
|
454
|
+
return nil unless domain
|
|
455
|
+
|
|
456
|
+
cleaned = domain.strip
|
|
457
|
+
cleaned = cleaned.sub(%r{^https?://}, '')
|
|
458
|
+
cleaned = cleaned.sub(%r{/+$}, '')
|
|
459
|
+
cleaned = cleaned.sub(/^www\./, '')
|
|
460
|
+
cleaned
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
def valid_domain?(domain)
|
|
464
|
+
return false unless domain
|
|
465
|
+
return false if domain.length < 4
|
|
466
|
+
return false unless domain.match?(/^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)
|
|
467
|
+
return false if domain.include?('example.') || domain.include?('test.')
|
|
468
|
+
return false if domain.include?('localhost')
|
|
469
|
+
return false if domain.end_with?('.html') || domain.end_with?('.htm')
|
|
470
|
+
return false if domain.start_with?('api.') && !domain.include?('mojang')
|
|
471
|
+
|
|
472
|
+
true
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
def create_lists_directory
|
|
476
|
+
FileUtils.mkdir_p('lists')
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
def generate_hosts_file(category, info)
|
|
480
|
+
hosts_file_path = "lists/#{info[:filename]}"
|
|
481
|
+
|
|
482
|
+
File.open(hosts_file_path, 'w') do |file|
|
|
483
|
+
write_hosts_header(file, info)
|
|
484
|
+
|
|
485
|
+
@category_domains[category].sort.each do |domain|
|
|
486
|
+
file.puts "0.0.0.0 #{domain}"
|
|
487
|
+
file.puts "0.0.0.0 www.#{domain}" unless domain.start_with?('www.')
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
def write_hosts_header(file, info)
|
|
493
|
+
file.puts "# #{info[:title]} - PiHole Compatible Hosts File"
|
|
494
|
+
file.puts "# Generated on: #{Time.now.strftime('%Y-%m-%d %H:%M:%S UTC')}"
|
|
495
|
+
file.puts '# Sources:'
|
|
496
|
+
file.puts '# - Mr.Holmes OSINT tool (https://github.com/Lucksi/Mr.Holmes)'
|
|
497
|
+
file.puts '# - Manually curated domain lists'
|
|
498
|
+
file.puts "# Purpose: Identify and categorize #{info[:description]}"
|
|
499
|
+
file.puts '# Format: 0.0.0.0 domain.com'
|
|
500
|
+
file.puts '#'
|
|
501
|
+
file.puts ''
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
# Run the generator if this file is executed directly
|
|
507
|
+
if __FILE__ == $0
|
|
508
|
+
options = { verbose: false }
|
|
509
|
+
|
|
510
|
+
OptionParser.new do |opts|
|
|
511
|
+
opts.banner = "Usage: #{$0} [options]"
|
|
512
|
+
opts.separator ''
|
|
513
|
+
opts.separator 'Generate categorised domain lists from Mr.Holmes OSINT tool and curated sources'
|
|
514
|
+
opts.separator ''
|
|
515
|
+
opts.separator 'Categories generated:'
|
|
516
|
+
CategorisedListGenerator::SiteParser::CATEGORIES.each do |category, info|
|
|
517
|
+
opts.separator " - #{category}: #{info[:description]}"
|
|
518
|
+
end
|
|
519
|
+
opts.separator ''
|
|
520
|
+
|
|
521
|
+
opts.on('-v', '--verbose', 'Verbose output') do
|
|
522
|
+
options[:verbose] = true
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
opts.on('-h', '--help', 'Show this help message') do
|
|
526
|
+
puts opts
|
|
527
|
+
exit
|
|
528
|
+
end
|
|
529
|
+
end.parse!
|
|
530
|
+
|
|
531
|
+
generator = CategorisedListGenerator::SiteParser.new(options)
|
|
532
|
+
generator.generate_lists
|
|
533
|
+
end
|