Skip to content

Commit 602380c

Browse files
committed
Added CLI::WordlistIndex (closes #35).
1 parent ea134a0 commit 602380c

File tree

8 files changed

+410
-14
lines changed

8 files changed

+410
-14
lines changed

lib/ronin/wordlists/cli/commands/available.rb

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
#
2020

2121
require 'ronin/wordlists/cli/command'
22-
23-
require 'yaml'
22+
require 'ronin/wordlists/cli/wordlist_index'
2423

2524
module Ronin
2625
module Wordlists
@@ -49,14 +48,14 @@ class Available < Command
4948
# Runs the `ronin-wordlists available` command.
5049
#
5150
def run
52-
wordlists = YAML.load_file(File.join(ROOT,'data','wordlists.yml'))
51+
index = WordlistIndex.load
5352

54-
wordlists.each do |name,attributes|
55-
puts "[ #{name} ]"
53+
index.each do |entry|
54+
puts "[ #{entry.name} ]"
5655
puts
57-
puts " * URL: #{attributes[:url]}"
58-
puts " * Categories: #{attributes[:categories].join(', ')}"
59-
puts " * Summary: #{attributes[:summary]}"
56+
puts " * URL: #{entry.url}"
57+
puts " * Categories: #{entry.categories.join(', ')}"
58+
puts " * Summary: #{entry.summary}"
6059
puts
6160
end
6261
end

lib/ronin/wordlists/cli/commands/download.rb

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@
2020

2121
require 'ronin/wordlists/cli/command'
2222
require 'ronin/wordlists/cli/wordlist_dir_option'
23-
require 'ronin/wordlists/root'
23+
require 'ronin/wordlists/cli/wordlist_index'
2424

2525
require 'ronin/core/cli/logging'
26-
require 'yaml'
2726

2827
module Ronin
2928
module Wordlists
@@ -72,11 +71,11 @@ def run(name_or_url)
7271

7372
download(url)
7473
else
75-
wordlists = YAML.load_file(File.join(ROOT,'data','wordlists.yml'))
76-
name = name_or_url
74+
index = WordlistIndex.load
75+
name = name_or_url
7776

78-
if (metadata = wordlists[name])
79-
download(metadata.fetch(:url))
77+
if (entry = index[name])
78+
download(entry.url)
8079
else
8180
print_error "unknown wordlist: #{name}"
8281
exit(1)
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# frozen_string_literal: true
2+
#
3+
# ronin-wordlists - A library and tool for managing wordlists.
4+
#
5+
# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
6+
#
7+
# ronin-wordlists is free software: you can redistribute it and/or modify
8+
# it under the terms of the GNU Lesser General Public License as published
9+
# by the Free Software Foundation, either version 3 of the License, or
10+
# (at your option) any later version.
11+
#
12+
# ronin-wordlists is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU Lesser General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU Lesser General Public License
18+
# along with ronin-wordlists. If not, see <https://www.gnu.org/licenses/>.
19+
#
20+
21+
require 'ronin/wordlists/root'
22+
require 'ronin/wordlists/exceptions'
23+
24+
require 'yaml'
25+
26+
module Ronin
27+
module Wordlists
28+
class CLI
29+
#
30+
# Represents an index of known wordlists.
31+
#
32+
class WordlistIndex
33+
34+
include Enumerable
35+
36+
#
37+
# Represents an entry in the wordlist index file.
38+
#
39+
class Entry
40+
41+
# The name of the wordlist.
42+
#
43+
# @return [String]
44+
attr_reader :name
45+
46+
# The download URL of the wordlist.
47+
#
48+
# @return [String]
49+
attr_reader :url
50+
51+
# A brief summary of the wordlist.
52+
#
53+
# @return [String]
54+
attr_reader :summary
55+
56+
# The categories the wordlist belongs to.
57+
#
58+
# @return [Array<String>]
59+
attr_reader :categories
60+
61+
#
62+
# Initializes the entry object.
63+
#
64+
# @param [String] name
65+
# The name of the wordlist.
66+
#
67+
# @param [String] url
68+
# The download URL of the wordlist.
69+
#
70+
# @param [String] summary
71+
# A brief summary of the wordlist.
72+
#
73+
# @param [Array<String>] categories
74+
# The categories the wordlist belongs to.
75+
#
76+
def initialize(name, url: , summary: , categories: [])
77+
@name = name
78+
@url = url
79+
80+
@summary = summary
81+
@categories = categories
82+
end
83+
84+
end
85+
86+
# The entries in the wordlist index.
87+
#
88+
# @return [Hash{String => Entry}]
89+
attr_reader :entries
90+
91+
#
92+
# Initializes the wordlist index.
93+
#
94+
# @param [Hash{String => Entry}] entries
95+
# The entries for the wordlist index.
96+
#
97+
def initialize(entries)
98+
@entries = entries
99+
end
100+
101+
#
102+
# Indicates that the wordlist index file has an invalid schema.
103+
#
104+
class InvalidSchema < Wordlists::Exception
105+
end
106+
107+
# Path to the builtin `wordlists.yml` index file.
108+
PATH = File.join(ROOT,'data','wordlists.yml')
109+
110+
#
111+
# Loads the wordlist index file from the given path.
112+
#
113+
# @param [String] path
114+
# The path of the wordlit index file.
115+
#
116+
# @return [WordlistIndex]
117+
# The parsed wordlist index file.
118+
#
119+
# @raise [InvalidSchema]
120+
# The wordlist index file has an invalid schema.
121+
#
122+
def self.load(path=PATH)
123+
yaml = YAML.load_file(path)
124+
125+
unless yaml.kind_of?(Hash)
126+
raise(InvalidSchema,"wordlist index file does not contain a Hash: #{path.inspect}")
127+
end
128+
129+
entries = yaml.to_h do |name,attributes|
130+
unless attributes[:url]
131+
raise(InvalidSchema,"wordlist index entry does not have a URL: #{name.inspect}")
132+
end
133+
134+
unless attributes[:summary]
135+
raise(InvalidSchema,"wordlist index entry does not have a summary: #{name.inspect}")
136+
end
137+
138+
[name, Entry.new(name,**attributes)]
139+
end
140+
141+
return new(entries)
142+
end
143+
144+
#
145+
# Looks up the wordlist by name within the wordlist index.
146+
#
147+
# @param [String] name
148+
# The wordlist name.
149+
#
150+
# @return [Entry, nil]
151+
# The entry for the wordlist.
152+
#
153+
def [](name)
154+
@entries[name]
155+
end
156+
157+
#
158+
# Enumerates over every entry in the wordlist index.
159+
#
160+
# @yield [entry]
161+
# If a block is given, it will be passed every entry in the wordlist
162+
# index.
163+
#
164+
# @yieldparam [Entry] entry
165+
# An entry in the wordlist index.
166+
#
167+
# @return [Enumerator]
168+
# If no block is given, an Enumerator object will be returned instead.
169+
#
170+
def each(&block)
171+
@entries.each_value(&block)
172+
end
173+
174+
end
175+
end
176+
end
177+
end

spec/cli/fixtures/wordlists.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
rockyou:
3+
:url: https://github.com/brannondorsey/naive-hashcat/releases/download/data/rockyou.txt
4+
:summary: Common passwords list.
5+
:categories:
6+
- passwords
7+
8+
subdomains-1000:
9+
:url: https:/raw.githubusercontent./com/rbsec/dnscan/master/subdomains-1000.txt
10+
:summary: Top 1000 most common subdomain names used by the dnscan util.
11+
:categories:
12+
- dns
13+
- subdomains
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
bad:
3+
:url: https://example.com/wordlist.txt
4+
:categories:
5+
- foo
6+
- bar
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
bad:
3+
:summary: Foo bar
4+
:categories:
5+
- foo
6+
- bar
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
- one
3+
- two

0 commit comments

Comments
 (0)