wordlist 1.0.3 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e732c8a8b2aa358e9c21c46fd9b5f509b5aeef52d51477ceb49111f94a4102d
4
- data.tar.gz: 0cb119f423d984b5538b5547f972a7c6c54e1e96e52e461acf3ba13328e8f4d5
3
+ metadata.gz: 84d2d2f168e655e19497f02a9cf7841e553315ec52e64ea46e9a9f01e943db9d
4
+ data.tar.gz: 709fedece526b979a744579a1868e6612b24da8ea0e85a2c9a496e2a219f58a7
5
5
  SHA512:
6
- metadata.gz: b060a80fafcd2e24a1771537030085d19b70722b8436a62e810b2cc2ab876ac3c132b036d625ae496b2b2c2f18c11a75761b0ab6933878a29207f28cfb1b8a73
7
- data.tar.gz: edef70fcf4bbcf6ab3d0ff4f78281bd4c1edca5535c057a515f662c5cd0efcae254a492d301d7d583ac622c0177961c3b028c2431d94a95da3d03116579824f1
6
+ metadata.gz: fd6bf3d64ddef5eae7bd03e03b53676b03b06165233b0bc8812c81cce5ad04f208e969f1d5a69f6330641d4997a3bdfaa43d00103721b9704fdf4f0d98331261
7
+ data.tar.gz: 44c4075fdd792d75586be3d6b82ab93da2e2bb6ad07c7139479996bb46751aa483937097a53da1a968996ca3e5bb4341fc05767bb999f3c23ed4f7e46081bd7d
@@ -12,8 +12,6 @@ jobs:
12
12
  - ubuntu-latest
13
13
  - macos-latest
14
14
  ruby:
15
- - 2.6
16
- - 2.7
17
15
  - 3.0
18
16
  - 3.1
19
17
  - 3.2
@@ -26,7 +24,13 @@ jobs:
26
24
  uses: ruby/setup-ruby@v1
27
25
  with:
28
26
  ruby-version: ${{ matrix.ruby }}
29
- - name: Install dependencies
27
+ - if: matrix.os == 'ubuntu-latest'
28
+ name: Install external dependencies
29
+ run: sudo apt-get install -y xz-utils unzip p7zip
30
+ - if: matrix.os == 'macos-latest'
31
+ name: Install external dependencies
32
+ run: brew install xz unzip p7zip
33
+ - name: Install Ruby dependencies
30
34
  run: bundle install --jobs 4 --retry 3
31
35
  - name: Run tests
32
36
  run: bundle exec rake test
data/ChangeLog.md CHANGED
@@ -1,3 +1,13 @@
1
+ ### 1.1.0 / 2023-09-12
2
+
3
+ * Added support for reading zip (`.zip`) and 7zip (`.7z`) compressed wordlist
4
+ files.
5
+ * Added support for building zip or 7zip compressed wordlist files.
6
+
7
+ #### CLI
8
+
9
+ * `-f,--format` now accepts `zip` and `7zip` format values.
10
+
1
11
  ### 1.0.3 / 2023-08-04
2
12
 
3
13
  * Fix reading of compressed wordlists on macOS.
data/README.md CHANGED
@@ -15,10 +15,10 @@ building wordlists, efficiently.
15
15
 
16
16
  ## Features
17
17
 
18
- * Supports reading `.txt` wordlists, and `.txt.gz`, `.txt.bz2`, and `.txt.xz`
18
+ * Supports reading `.txt` wordlists, and `.gz`, `.bz2`, `.xz`, `.zip`, and `.7z`
19
19
  compressed wordlists.
20
20
  * Supports building wordlists from arbitrary text. Also supports `.gz`, `.bz2,`
21
- and `.xz` compression.
21
+ `.xz`, `.zip`, and `.7z` compression.
22
22
  * Provides an advanced lexer for parsing text into words.
23
23
  * Can parse/skip digits, special characters, whole numbers, acronyms.
24
24
  * Can normalize case, apostrophes, and acronyms.
@@ -223,7 +223,7 @@ builder.parse_file(path)
223
223
 
224
224
  ## Requirements
225
225
 
226
- * [ruby] >= 2.0.0
226
+ * [ruby] >= 3.0.0
227
227
 
228
228
  [ruby]: https://www.ruby-lang.org/
229
229
 
@@ -247,6 +247,59 @@ gem 'wordlist', '~> 1.0'
247
247
 
248
248
  ### Synopsis
249
249
 
250
+ ```
251
+ usage: wordlist { [options] WORDLIST ... | --build WORDLIST [FILE ...] }
252
+
253
+ Wordlist Reading Options:
254
+ -f {txt|gzip|bz2|xz|zip|7zip}, Sets the desired wordlist format
255
+ --format
256
+ --exec COMMAND Runs the command with each word from the wordlist.
257
+ The string "{}" will be replaced with each word.
258
+
259
+ Wordlist Operations:
260
+ -U, --union WORDLIST Unions the wordlist with the other WORDLIST
261
+ -I, --intersect WORDLIST Intersects the wordlist with the other WORDLIST
262
+ -S, --subtract WORDLIST Subtracts the words from the WORDLIST
263
+ -p, --product WORDLIST Combines every word with the other words from WORDLIST
264
+ -P, --power NUM Combines every word with the other words from WORDLIST
265
+ -u, --unique Filters out duplicate words
266
+
267
+ Wordlist Modifiers:
268
+ -C, --capitalize Capitalize each word
269
+ --uppercase, --upcase Converts each word to UPPERCASE
270
+ --lowercase, --downcase Converts each word to lowercase
271
+ -t, --tr CHARS:REPLACE Translates the characters of each word
272
+ -s, --sub PATTERN:SUB Replaces PATTERN with SUB in each word
273
+ -g, --gsub PATTERN:SUB Replaces all PATTERNs with SUB in each word
274
+ -m, --mutate PATTERN:SUB Performs every possible substitution on each word
275
+ -M, --mutate-case Switches the case of each letter in each word
276
+
277
+ Wordlist Building Options:
278
+ -b, --build WORDLIST Builds a wordlist
279
+ -a, --[no-]append Appends to the new wordlist instead of overwriting it
280
+ -L, --lang LANG The language to expect
281
+ --stop-words WORDS... Ignores the stop words
282
+ --ignore-words WORDS... Ignore the words
283
+ --[no-]digits Allow digits in the middle of words
284
+ --special-chars CHARS Allows the given special characters inside of words
285
+ --[no-]numbers Parses whole numbers in addition to words
286
+ --[no-]acronyms Parses acronyms in addition to words
287
+ --[no-]normalize-case Converts all words to lowercase
288
+ --[no-]normalize-apostrophes Removes "'s" from words
289
+ --[no-]normalize-acronyms Removes the dots from acronyms
290
+
291
+ General Options:
292
+ -V, --version Print the version
293
+ -h, --help Print the help output
294
+
295
+ Examples:
296
+ wordlist rockyou.txt.gz
297
+ wordlist passwords_short.txt passwords_long.txt
298
+ wordlist sport_teams.txt -p beers.txt -p digits.txt
299
+ cat *.txt | wordlist --build custom.txt
300
+
301
+ ```
302
+
250
303
  Reading a wordlist:
251
304
 
252
305
  ```shell
data/gemspec.yml CHANGED
@@ -8,7 +8,7 @@ description:
8
8
  license: MIT
9
9
  authors: Postmodern
10
10
  email: postmodern.mod3@gmail.com
11
- homepage: https://github.com/postmodern/wordlist.rb
11
+ homepage: https://github.com/postmodern/wordlist.rb#readme
12
12
  has_yard: true
13
13
 
14
14
  metadata:
@@ -17,7 +17,7 @@ metadata:
17
17
  bug_tracker_uri: https://github.com/postmodern/wordlist.rb/issues
18
18
  changelog_uri: https://github.com/postmodern/wordlist.rb/blob/master/ChangeLog.md
19
19
 
20
- required_ruby_version: ">= 2.0.0"
20
+ required_ruby_version: ">= 3.0.0"
21
21
 
22
22
  development_dependencies:
23
23
  bundler: ~> 2.0
@@ -22,7 +22,7 @@ module Wordlist
22
22
 
23
23
  # The format of the wordlist file.
24
24
  #
25
- # @return [:txt, :gzip, :bzip2, :xz]
25
+ # @return [:txt, :gzip, :bzip2, :xz, :zip, :7zip]
26
26
  attr_reader :format
27
27
 
28
28
  # The word lexer.
@@ -41,7 +41,7 @@ module Wordlist
41
41
  # @param [String] path
42
42
  # The path of the wordlist file.
43
43
  #
44
- # @param [:txt, :gz, :bzip2, :xz, nil] format
44
+ # @param [:txt, :gz, :bzip2, :xz, :zip, :7zip, nil] format
45
45
  # The format of the wordlist. If not given the format will be inferred
46
46
  # from the file extension.
47
47
  #
data/lib/wordlist/cli.rb CHANGED
@@ -26,7 +26,9 @@ module Wordlist
26
26
  'txt' => :txt,
27
27
  'gzip' => :gzip,
28
28
  'bzip2'=> :bzip2,
29
- 'xz' => :xz
29
+ 'xz' => :xz,
30
+ 'zip' => :zip,
31
+ '7zip' => :"7zip"
30
32
  }
31
33
 
32
34
  # The command's option parser.
@@ -74,7 +76,7 @@ module Wordlist
74
76
  #
75
77
  # @param [:read, :build] mode
76
78
  #
77
- # @param [:txt, :gzip, :bzip2, :xz, nil] format
79
+ # @param [:txt, :gzip, :bzip2, :xz, :zip, :7zip, nil] format
78
80
  #
79
81
  # @param [String, nil] command
80
82
  #
@@ -277,7 +279,7 @@ module Wordlist
277
279
  opts.separator ""
278
280
  opts.separator "Wordlist Reading Options:"
279
281
 
280
- opts.on('-f','--format {txt|gzip|bz2|xz}', FORMATS, 'Saves the output to FILE') do |format|
282
+ opts.on('-f','--format {txt|gzip|bz2|xz|zip|7zip}', FORMATS, 'Saves the output to FILE') do |format|
281
283
  @format = format
282
284
  end
283
285
 
@@ -10,34 +10,31 @@ module Wordlist
10
10
  # @since 1.0.0
11
11
  #
12
12
  module Reader
13
- # Mapping of compression formats to the commands to read them.
14
- COMMANDS = {
15
- gzip: 'zcat',
16
- bzip2: 'bzcat',
17
- xz: 'xzcat'
18
- }
19
-
20
13
  #
21
14
  # Returns the command to read the compressed wordlist.
22
15
  #
23
16
  # @param [String] path
24
17
  # The path to the file.
25
18
  #
26
- # @param [:gzip, :bzip2, :xz] format
19
+ # @param [:gzip, :bzip2, :xz, :zip, :7zip] format
27
20
  # The compression format of the file.
28
21
  #
29
22
  # @return [String]
30
23
  # The shellescaped command string.
31
24
  #
32
25
  # @raise [UnknownFormat]
33
- # The given format was not `:gzip`, `:bzip2`, or `:xz`.
26
+ # The given format was not `:gzip`, `:bzip2`, `:xz`, `:zip`, `:7zip`.
34
27
  #
35
28
  def self.command(path, format: )
36
- command = COMMANDS.fetch(format) do
37
- raise(UnknownFormat,"unsupported format: #{format.inspect}")
29
+ case format
30
+ when :gzip then "zcat < #{Shellwords.shellescape(path)}"
31
+ when :bzip2 then "bzcat < #{Shellwords.shellescape(path)}"
32
+ when :xz then "xzcat < #{Shellwords.shellescape(path)}"
33
+ when :zip then "unzip -p #{Shellwords.shellescape(path)}"
34
+ when :"7zip" then "7za e -so #{Shellwords.shellescape(path)}"
35
+ else
36
+ raise(UnknownFormat,"unsupported input format: #{format.inspect}")
38
37
  end
39
-
40
- "#{command} < #{Shellwords.shellescape(path)}"
41
38
  end
42
39
 
43
40
  #
@@ -53,10 +50,10 @@ module Wordlist
53
50
  # The uncompressed IO stream.
54
51
  #
55
52
  # @raise [ArgumentError]
56
- # The given format was not `:gzip`, `:bzip2`, or `:xz`.
53
+ # The given format was not `:gzip`, `:bzip2`, `:xz`, `:zip`, or `:7zip`.
57
54
  #
58
55
  # @raise [CommandNotFound]
59
- # The `zcat,` `bzcat`, or `xzcat` command could not be found.
56
+ # The `zcat,` `bzcat`, `xzcat`, or `unzip` command could not be found.
60
57
  #
61
58
  def self.open(path,**kwargs,&block)
62
59
  command = self.command(path,**kwargs)
@@ -10,20 +10,13 @@ module Wordlist
10
10
  # @since 1.0.0
11
11
  #
12
12
  module Writer
13
- # Mapping of compression formats to the commands to write to them.
14
- COMMANDS = {
15
- gzip: 'gzip',
16
- bzip2: 'bzip2',
17
- xz: 'xz'
18
- }
19
-
20
13
  #
21
14
  # Returns the command to write to the compressed wordlist.
22
15
  #
23
16
  # @param [String] path
24
17
  # The path to the file.
25
18
  #
26
- # @param [:gzip, :bzip2, :xz] format
19
+ # @param [:gzip, :bzip2, :xz, :zip] format
27
20
  # The compression format of the file.
28
21
  #
29
22
  # @param [Boolean] append
@@ -33,19 +26,36 @@ module Wordlist
33
26
  # @return [String]
34
27
  # The shellescaped command string.
35
28
  #
36
- # @raise [UnknownFormat]
37
- # The given format was not `:gzip`, `:bzip2`, or `:xz`.
29
+ # @raise [UnknownFormat, AppendNotSupported]
30
+ # * {UnknownFormat} - the given format was not `:gzip`, `:bzip2`, `:xz`,
31
+ # or `:zip`.
32
+ # * {AppendNotSupported} - the `zip` archive format does not support
33
+ # appending to existing files within existing archives.
38
34
  #
39
35
  def self.command(path, format: , append: false)
40
- command = COMMANDS.fetch(format) do
41
- raise(UnknownFormat,"unsupported format: #{format.inspect}")
42
- end
36
+ case format
37
+ when :gzip, :bzip2, :xz
38
+ command = format.to_s
39
+ redirect = if append then '>>'
40
+ else '>'
41
+ end
43
42
 
44
- redirect = if append then '>>'
45
- else '>'
46
- end
43
+ "#{command} #{redirect} #{Shellwords.shellescape(path)}"
44
+ when :zip
45
+ if append
46
+ raise(AppendNotSupported,"zip format does not support appending to files within pre-existing archives: #{path.inspect}")
47
+ end
47
48
 
48
- return "#{Shellwords.shellescape(command)} #{redirect} #{Shellwords.shellescape(path)}"
49
+ "zip -q #{Shellwords.shellescape(path)} -"
50
+ when :"7zip"
51
+ if append
52
+ raise(AppendNotSupported,"7zip format does not support appending to files within pre-existing archives: #{path.inspect}")
53
+ end
54
+
55
+ "7za a -si #{Shellwords.shellescape(path)} >/dev/null"
56
+ else
57
+ raise(UnknownFormat,"unsupported output format: #{format.inspect}")
58
+ end
49
59
  end
50
60
 
51
61
  #
@@ -61,10 +71,11 @@ module Wordlist
61
71
  # The uncompressed IO stream.
62
72
  #
63
73
  # @raise [ArgumentError]
64
- # The given format was not `:gzip`, `:bzip2`, or `:xz`.
74
+ # The given format was not `:gzip`, `:bzip2`, `:xz`, `:zip`.
65
75
  #
66
76
  # @raise [CommandNotFound]
67
- # The `gzip`, `bzip2,` or `xz` command was not found on the system.
77
+ # The `gzip`, `bzip2,` `xz`, or `zip` command was not found on the
78
+ # system.
68
79
  #
69
80
  def self.open(path,**kwargs)
70
81
  command = self.command(path,**kwargs)
@@ -17,6 +17,12 @@ module Wordlist
17
17
  class UnknownFormat < WordlistError
18
18
  end
19
19
 
20
+ #
21
+ # @since 1.1.0
22
+ #
23
+ class AppendNotSupported < WordlistError
24
+ end
25
+
20
26
  #
21
27
  # @since 1.0.0
22
28
  #
data/lib/wordlist/file.rb CHANGED
@@ -24,7 +24,7 @@ module Wordlist
24
24
 
25
25
  # The format of the wordlist file.
26
26
  #
27
- # @return [:txt, :gzip, :bzip2, :xz]
27
+ # @return [:txt, :gzip, :bzip2, :xz, :zip, :7zip]
28
28
  attr_reader :format
29
29
 
30
30
  #
@@ -33,7 +33,7 @@ module Wordlist
33
33
  # @param [String] path
34
34
  # The path to the `.txt` file wordlist read from.
35
35
  #
36
- # @param [:txt, :gz, :bzip2, :xz, nil] format
36
+ # @param [:txt, :gz, :bzip2, :xz, :zip, :7zip, nil] format
37
37
  # The format of the wordlist. If not given the format will be inferred
38
38
  # from the file extension.
39
39
  #
@@ -13,7 +13,9 @@ module Wordlist
13
13
  '.txt' => :txt,
14
14
  '.gz' => :gzip,
15
15
  '.bz2' => :bzip2,
16
- '.xz' => :xz
16
+ '.xz' => :xz,
17
+ '.zip' => :zip,
18
+ '.7z' => :"7zip"
17
19
  }
18
20
 
19
21
  # Valid formats.
@@ -25,7 +27,7 @@ module Wordlist
25
27
  # @param [String] path
26
28
  # The path to the file.
27
29
  #
28
- # @return [:txt, :gzip, :bzip2, :xz]
30
+ # @return [:txt, :gzip, :bzip2, :xz, :zip, :7zip]
29
31
  #
30
32
  # @raise [UnknownFormat]
31
33
  # The format could not be inferred from the file path.
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Wordlist
4
4
  # wordlist version
5
- VERSION = '1.0.3'
5
+ VERSION = '1.1.0'
6
6
  end
data/lib/wordlist.rb CHANGED
@@ -31,7 +31,7 @@ module Wordlist
31
31
  # @param [Hash{Symbol => Object}] kwargs
32
32
  # Additional keyword arguments for {Wordlist::File#initialize}.
33
33
  #
34
- # @option kwargs [:txt, :bzip, :bzip2, :xz] :format
34
+ # @option kwargs [:txt, :bzip, :bzip2, :xz, :zip, :7zip] :format
35
35
  # Specifies the format of the wordlist. If no format is given, the format
36
36
  # will be inferred from the path's file extension.
37
37
  #
data/spec/builder_spec.rb CHANGED
@@ -46,6 +46,22 @@ describe Wordlist::Builder do
46
46
  end
47
47
  end
48
48
 
49
+ context "when the path ends in '.zip'" do
50
+ let(:path) { ::File.join(fixtures_dir,'new_wordlist.zip') }
51
+
52
+ it "must default #format to :zip" do
53
+ expect(subject.format).to eq(:zip)
54
+ end
55
+ end
56
+
57
+ context "when the path ends in '.7z'" do
58
+ let(:path) { ::File.join(fixtures_dir,'new_wordlist.7z') }
59
+
60
+ it "must default #format to :7zip" do
61
+ expect(subject.format).to eq(:"7zip")
62
+ end
63
+ end
64
+
49
65
  context "when format: :txt is given" do
50
66
  subject { described_class.new(path, format: :txt) }
51
67
 
@@ -78,6 +94,22 @@ describe Wordlist::Builder do
78
94
  end
79
95
  end
80
96
 
97
+ context "when format: :zip is given" do
98
+ subject { described_class.new(path, format: :zip) }
99
+
100
+ it "must set #format to :zip" do
101
+ expect(subject.format).to eq(:zip)
102
+ end
103
+ end
104
+
105
+ context "when format: :7zip is given" do
106
+ subject { described_class.new(path, format: :"7zip") }
107
+
108
+ it "must set #format to :7zip" do
109
+ expect(subject.format).to eq(:"7zip")
110
+ end
111
+ end
112
+
81
113
  it "must default #append? to false" do
82
114
  expect(subject.append?).to be(false)
83
115
  end
@@ -53,13 +53,35 @@ describe Wordlist::Compression::Reader do
53
53
  end
54
54
  end
55
55
 
56
+ context "when given format: :zip" do
57
+ let(:file_name) { 'file_name' }
58
+ let(:path) { "path/to/#{file_name}.zip" }
59
+
60
+ subject { described_class.command(path, format: :zip) }
61
+
62
+ it "must return 'unzip -p path/to/file_name.zip'" do
63
+ expect(subject).to eq("unzip -p #{path}")
64
+ end
65
+ end
66
+
67
+ context "when given format: :7zip" do
68
+ let(:file_name) { 'file_name' }
69
+ let(:path) { "path/to/#{file_name}.7z" }
70
+
71
+ subject { described_class.command(path, format: :"7zip") }
72
+
73
+ it "must return 'unzip -p path/to/file_name.zip'" do
74
+ expect(subject).to eq("7za e -so #{path}")
75
+ end
76
+ end
77
+
56
78
  context "when given an unknown format: value" do
57
79
  let(:format) { :foo }
58
80
 
59
81
  it do
60
82
  expect {
61
83
  subject.command(path, format: format)
62
- }.to raise_error(Wordlist::UnknownFormat,"unsupported format: #{format.inspect}")
84
+ }.to raise_error(Wordlist::UnknownFormat,"unsupported input format: #{format.inspect}")
63
85
  end
64
86
  end
65
87
  end
@@ -79,13 +79,61 @@ describe Wordlist::Compression::Writer do
79
79
  end
80
80
  end
81
81
 
82
+ context "when given format: :zip" do
83
+ subject { described_class.command(path, format: :zip) }
84
+
85
+ it "must return 'zip -q path/to/file -'" do
86
+ expect(subject).to eq("zip -q #{path} -")
87
+ end
88
+
89
+ context "and given append: true" do
90
+ it do
91
+ expect {
92
+ described_class.command(path, format: :zip, append: true)
93
+ }.to raise_error(Wordlist::AppendNotSupported,"zip format does not support appending to files within pre-existing archives: #{path.inspect}")
94
+ end
95
+ end
96
+
97
+ context "and the file contains special characters" do
98
+ let(:path) { 'path/to/the file' }
99
+
100
+ it "must shellescape them" do
101
+ expect(subject).to eq("zip -q #{Shellwords.shellescape(path)} -")
102
+ end
103
+ end
104
+ end
105
+
106
+ context "when given format: :7zip" do
107
+ subject { described_class.command(path, format: :"7zip") }
108
+
109
+ it "must return '7za a -si path/to/file'" do
110
+ expect(subject).to eq("7za a -si #{path} >/dev/null")
111
+ end
112
+
113
+ context "and given append: true" do
114
+ it do
115
+ expect {
116
+ described_class.command(path, format: :"7zip", append: true)
117
+ }.to raise_error(Wordlist::AppendNotSupported,"7zip format does not support appending to files within pre-existing archives: #{path.inspect}")
118
+ end
119
+ end
120
+
121
+ context "and the file contains special characters" do
122
+ let(:path) { 'path/to/the file' }
123
+
124
+ it "must shellescape them" do
125
+ expect(subject).to eq("7za a -si #{Shellwords.shellescape(path)} >/dev/null")
126
+ end
127
+ end
128
+ end
129
+
82
130
  context "when given an unknown format: value" do
83
131
  let(:format) { :foo }
84
132
 
85
133
  it do
86
134
  expect {
87
135
  subject.command(path, format: format)
88
- }.to raise_error(Wordlist::UnknownFormat,"unsupported format: #{format.inspect}")
136
+ }.to raise_error(Wordlist::UnknownFormat,"unsupported output format: #{format.inspect}")
89
137
  end
90
138
  end
91
139
  end
@@ -107,6 +155,7 @@ describe Wordlist::Compression::Writer do
107
155
  context "when written to" do
108
156
  before do
109
157
  subject.puts words
158
+ subject.flush
110
159
  subject.close
111
160
  end
112
161
 
@@ -118,7 +167,10 @@ describe Wordlist::Compression::Writer do
118
167
  end
119
168
  end
120
169
 
121
- after { ::FileUtils.rm_f(path) }
170
+ after do
171
+ subject.close
172
+ ::FileUtils.rm_f(path)
173
+ end
122
174
  end
123
175
 
124
176
  context "when given format: :bzip2" do
@@ -133,6 +185,7 @@ describe Wordlist::Compression::Writer do
133
185
  context "when written to" do
134
186
  before do
135
187
  subject.puts words
188
+ subject.flush
136
189
  subject.close
137
190
  end
138
191
 
@@ -144,7 +197,10 @@ describe Wordlist::Compression::Writer do
144
197
  end
145
198
  end
146
199
 
147
- after { ::FileUtils.rm_f(path) }
200
+ after do
201
+ subject.close
202
+ ::FileUtils.rm_f(path)
203
+ end
148
204
  end
149
205
 
150
206
  context "when given format: :xz" do
@@ -159,6 +215,7 @@ describe Wordlist::Compression::Writer do
159
215
  context "when written to" do
160
216
  before do
161
217
  subject.puts words
218
+ subject.flush
162
219
  subject.close
163
220
  end
164
221
 
@@ -170,7 +227,70 @@ describe Wordlist::Compression::Writer do
170
227
  end
171
228
  end
172
229
 
173
- after { ::FileUtils.rm_f(path) }
230
+ after do
231
+ subject.close
232
+ ::FileUtils.rm_f(path)
233
+ end
234
+ end
235
+
236
+ context "when given format: :zip" do
237
+ let(:path) { ::File.join(fixtures_dir,'new_wordlist.txt.zip') }
238
+
239
+ subject { described_class.open(path, format: :zip) }
240
+
241
+ it "must return an IO object" do
242
+ expect(subject).to be_kind_of(IO)
243
+ end
244
+
245
+ context "when written to" do
246
+ before do
247
+ subject.puts words
248
+ subject.flush
249
+ subject.close
250
+ end
251
+
252
+ let(:written_contents) { `unzip -p #{Shellwords.shellescape(path)}` }
253
+ let(:written_words) { written_contents.lines.map(&:chomp) }
254
+
255
+ it "must writing xz compressed data to the file" do
256
+ expect(written_words).to eq(words)
257
+ end
258
+ end
259
+
260
+ after do
261
+ subject.close
262
+ ::FileUtils.rm_f(path)
263
+ end
264
+ end
265
+
266
+ context "when given format: :7zip" do
267
+ let(:path) { ::File.join(fixtures_dir,'new_wordlist.txt.7z') }
268
+
269
+ subject { described_class.open(path, format: :"7zip") }
270
+
271
+ it "must return an IO object" do
272
+ expect(subject).to be_kind_of(IO)
273
+ end
274
+
275
+ context "when written to" do
276
+ before do
277
+ subject.puts words
278
+ subject.flush
279
+ subject.close
280
+ end
281
+
282
+ let(:written_contents) { `7za e -so #{Shellwords.shellescape(path)}` }
283
+ let(:written_words) { written_contents.lines.map(&:chomp) }
284
+
285
+ it "must writing xz compressed data to the file" do
286
+ expect(written_words).to eq(words)
287
+ end
288
+ end
289
+
290
+ after do
291
+ subject.close
292
+ ::FileUtils.rm_f(path)
293
+ end
174
294
  end
175
295
 
176
296
  context "when the command is not installed" do
data/spec/file_spec.rb CHANGED
@@ -75,6 +75,22 @@ describe Wordlist::File do
75
75
  expect(subject.format).to eq(:xz)
76
76
  end
77
77
  end
78
+
79
+ context "and the path ends in .zip" do
80
+ let(:path) { ::File.join(fixtures_dir,'wordlist.txt.zip') }
81
+
82
+ it "must set #format to :zip" do
83
+ expect(subject.format).to eq(:zip)
84
+ end
85
+ end
86
+
87
+ context "and the path ends in .7z" do
88
+ let(:path) { ::File.join(fixtures_dir,'wordlist.txt.7z') }
89
+
90
+ it "must set #format to :7zip" do
91
+ expect(subject.format).to eq(:"7zip")
92
+ end
93
+ end
78
94
  end
79
95
 
80
96
  context "when format: is given" do
@@ -162,6 +178,28 @@ describe Wordlist::File do
162
178
  }.to yield_successive_args(*expected_lines)
163
179
  end
164
180
  end
181
+
182
+ context "and the wordlist format is zip" do
183
+ let(:path) { ::File.join(fixtures_dir,'wordlist.txt.zip') }
184
+ let(:expected_contents) { `unzip -p #{Shellwords.shellescape(path)}` }
185
+
186
+ it "must read the uncompressed zip data" do
187
+ expect { |b|
188
+ subject.each_line(&b)
189
+ }.to yield_successive_args(*expected_lines)
190
+ end
191
+ end
192
+
193
+ context "and the wordlist format is 7zip" do
194
+ let(:path) { ::File.join(fixtures_dir,'wordlist.txt.7z') }
195
+ let(:expected_contents) { `7za e -so #{Shellwords.shellescape(path)}` }
196
+
197
+ it "must read the uncompressed 7zip data" do
198
+ expect { |b|
199
+ subject.each_line(&b)
200
+ }.to yield_successive_args(*expected_lines)
201
+ end
202
+ end
165
203
  end
166
204
 
167
205
  context "when not given a block" do
@@ -199,6 +237,26 @@ describe Wordlist::File do
199
237
  expect(subject.each_line.to_a).to eq(expected_lines)
200
238
  end
201
239
  end
240
+
241
+ context "and the wordlist format is zip" do
242
+ let(:path) { ::File.join(fixtures_dir,'wordlist.txt.zip') }
243
+ let(:expected_contents) { `unzip -p #{Shellwords.shellescape(path)}` }
244
+
245
+ it "must return an Enumerator of the compressed zip data" do
246
+ expect(subject.each_line).to be_kind_of(Enumerator)
247
+ expect(subject.each_line.to_a).to eq(expected_lines)
248
+ end
249
+ end
250
+
251
+ context "and the wordlist format is 7zip" do
252
+ let(:path) { ::File.join(fixtures_dir,'wordlist.txt.7z') }
253
+ let(:expected_contents) { `7za e -so #{Shellwords.shellescape(path)}` }
254
+
255
+ it "must return an Enumerator of the compressed 7zip data" do
256
+ expect(subject.each_line).to be_kind_of(Enumerator)
257
+ expect(subject.each_line.to_a).to eq(expected_lines)
258
+ end
259
+ end
202
260
  end
203
261
  end
204
262
 
@@ -242,6 +300,28 @@ describe Wordlist::File do
242
300
  end
243
301
  end
244
302
 
303
+ context "and the wordlist format is zip" do
304
+ let(:path) { ::File.join(fixtures_dir,'wordlist.txt.zip') }
305
+ let(:expected_contents) { `unzip -p #{Shellwords.shellescape(path)}` }
306
+
307
+ it "must read the uncompressed zip data" do
308
+ expect { |b|
309
+ subject.each_line(&b)
310
+ }.to yield_successive_args(*expected_lines)
311
+ end
312
+ end
313
+
314
+ context "and the wordlist format is 7z" do
315
+ let(:path) { ::File.join(fixtures_dir,'wordlist.txt.7z') }
316
+ let(:expected_contents) { `7za e -so #{Shellwords.shellescape(path)}` }
317
+
318
+ it "must read the uncompressed 7zip data" do
319
+ expect { |b|
320
+ subject.each_line(&b)
321
+ }.to yield_successive_args(*expected_lines)
322
+ end
323
+ end
324
+
245
325
  context "when the wordlist contains empty lines" do
246
326
  let(:expected_words) do
247
327
  super().reject { |w| w.empty? }
Binary file
Binary file
data/spec/format_spec.rb CHANGED
@@ -27,6 +27,18 @@ describe Wordlist::Format do
27
27
  end
28
28
  end
29
29
 
30
+ context "when given a path ending in '.zip'" do
31
+ it "must return :zip" do
32
+ expect(subject.infer("path/to/file.zip")).to eq(:zip)
33
+ end
34
+ end
35
+
36
+ context "when given a path ending in '.7z'" do
37
+ it "must return :7zip" do
38
+ expect(subject.infer("path/to/file.7z")).to eq(:"7zip")
39
+ end
40
+ end
41
+
30
42
  context "when given a path ending in another file extension" do
31
43
  let(:path) { "path/to/file.foo" }
32
44
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wordlist
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Postmodern
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-04 00:00:00.000000000 Z
11
+ date: 2023-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -135,9 +135,11 @@ files:
135
135
  - spec/compression/writer_spec.rb
136
136
  - spec/file_spec.rb
137
137
  - spec/fixtures/wordlist.txt
138
+ - spec/fixtures/wordlist.txt.7z
138
139
  - spec/fixtures/wordlist.txt.bz2
139
140
  - spec/fixtures/wordlist.txt.gz
140
141
  - spec/fixtures/wordlist.txt.xz
142
+ - spec/fixtures/wordlist.txt.zip
141
143
  - spec/fixtures/wordlist_with_ambiguous_format
142
144
  - spec/fixtures/wordlist_with_comments.txt
143
145
  - spec/fixtures/wordlist_with_empty_lines.txt
@@ -175,7 +177,7 @@ files:
175
177
  - spec/wordlist_spec.rb
176
178
  - spec/words_spec.rb
177
179
  - wordlist.gemspec
178
- homepage: https://github.com/postmodern/wordlist.rb
180
+ homepage: https://github.com/postmodern/wordlist.rb#readme
179
181
  licenses:
180
182
  - MIT
181
183
  metadata:
@@ -191,7 +193,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
191
193
  requirements:
192
194
  - - ">="
193
195
  - !ruby/object:Gem::Version
194
- version: 2.0.0
196
+ version: 3.0.0
195
197
  required_rubygems_version: !ruby/object:Gem::Requirement
196
198
  requirements:
197
199
  - - ">="