wordlist 1.0.3 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +12 -7
  3. data/ChangeLog.md +14 -0
  4. data/LICENSE.txt +1 -1
  5. data/README.md +61 -3
  6. data/gemspec.yml +2 -2
  7. data/lib/wordlist/abstract_wordlist.rb +1 -1
  8. data/lib/wordlist/builder.rb +7 -7
  9. data/lib/wordlist/cli.rb +8 -6
  10. data/lib/wordlist/compression/reader.rb +13 -16
  11. data/lib/wordlist/compression/writer.rb +31 -20
  12. data/lib/wordlist/exceptions.rb +6 -0
  13. data/lib/wordlist/file.rb +6 -6
  14. data/lib/wordlist/format.rb +5 -3
  15. data/lib/wordlist/lexer/stop_words.rb +1 -1
  16. data/lib/wordlist/lexer.rb +2 -2
  17. data/lib/wordlist/list_methods.rb +2 -2
  18. data/lib/wordlist/modifiers/capitalize.rb +1 -1
  19. data/lib/wordlist/modifiers/downcase.rb +1 -1
  20. data/lib/wordlist/modifiers/gsub.rb +1 -1
  21. data/lib/wordlist/modifiers/mutate.rb +1 -1
  22. data/lib/wordlist/modifiers/mutate_case.rb +1 -1
  23. data/lib/wordlist/modifiers/sub.rb +1 -1
  24. data/lib/wordlist/modifiers/tr.rb +1 -1
  25. data/lib/wordlist/modifiers/upcase.rb +1 -1
  26. data/lib/wordlist/modifiers.rb +8 -8
  27. data/lib/wordlist/operators/binary_operator.rb +1 -1
  28. data/lib/wordlist/operators/concat.rb +1 -1
  29. data/lib/wordlist/operators/intersect.rb +2 -2
  30. data/lib/wordlist/operators/power.rb +2 -2
  31. data/lib/wordlist/operators/product.rb +1 -1
  32. data/lib/wordlist/operators/subtract.rb +2 -2
  33. data/lib/wordlist/operators/unary_operator.rb +1 -1
  34. data/lib/wordlist/operators/union.rb +2 -2
  35. data/lib/wordlist/operators/unique.rb +2 -2
  36. data/lib/wordlist/operators.rb +7 -7
  37. data/lib/wordlist/version.rb +1 -1
  38. data/lib/wordlist.rb +5 -5
  39. data/spec/builder_spec.rb +32 -0
  40. data/spec/compression/reader_spec.rb +23 -1
  41. data/spec/compression/writer_spec.rb +124 -4
  42. data/spec/file_spec.rb +80 -0
  43. data/spec/fixtures/wordlist.txt.7z +0 -0
  44. data/spec/fixtures/wordlist.txt.zip +0 -0
  45. data/spec/format_spec.rb +12 -0
  46. data/wordlist.gemspec +1 -4
  47. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e732c8a8b2aa358e9c21c46fd9b5f509b5aeef52d51477ceb49111f94a4102d
4
- data.tar.gz: 0cb119f423d984b5538b5547f972a7c6c54e1e96e52e461acf3ba13328e8f4d5
3
+ metadata.gz: 8257ee6c587ba685ac202f3c4839739312397c00b85af8b3a954fac4d889bf25
4
+ data.tar.gz: d75c4cd68b7d3eb5e05399b8f38d155cadd6dd6caeb06787c84e1872e9cf8467
5
5
  SHA512:
6
- metadata.gz: b060a80fafcd2e24a1771537030085d19b70722b8436a62e810b2cc2ab876ac3c132b036d625ae496b2b2c2f18c11a75761b0ab6933878a29207f28cfb1b8a73
7
- data.tar.gz: edef70fcf4bbcf6ab3d0ff4f78281bd4c1edca5535c057a515f662c5cd0efcae254a492d301d7d583ac622c0177961c3b028c2431d94a95da3d03116579824f1
6
+ metadata.gz: 23f77e8df9ad6a77fa21df3d47840b0938d5b562473ec40abd1823e21c06f3d456a0af28685cbc1522684948da798afc8287c13d5fe674c119ed53e9f715fd4e
7
+ data.tar.gz: 9e41f171d870b0b2868697407669bcb20a48e110b4ed6a7739cae09faba75ce42b634723793b403724bdd3acf557d74c9d7787a4f34de12646886e204a242a93
@@ -12,21 +12,26 @@ jobs:
12
12
  - ubuntu-latest
13
13
  - macos-latest
14
14
  ruby:
15
- - 2.6
16
- - 2.7
17
- - 3.0
18
- - 3.1
19
- - 3.2
15
+ - '3.0'
16
+ - '3.1'
17
+ - '3.2'
18
+ - '3.3'
20
19
  - jruby
21
20
  - truffleruby
22
21
  name: OS ${{ matrix.os }} / Ruby ${{ matrix.ruby }}
23
22
  steps:
24
- - uses: actions/checkout@v2
23
+ - uses: actions/checkout@v4
25
24
  - name: Set up Ruby
26
25
  uses: ruby/setup-ruby@v1
27
26
  with:
28
27
  ruby-version: ${{ matrix.ruby }}
29
- - name: Install dependencies
28
+ - if: matrix.os == 'ubuntu-latest'
29
+ name: Install external dependencies
30
+ run: sudo apt-get install -y xz-utils unzip p7zip
31
+ - if: matrix.os == 'macos-latest'
32
+ name: Install external dependencies
33
+ run: brew install xz unzip p7zip
34
+ - name: Install Ruby dependencies
30
35
  run: bundle install --jobs 4 --retry 3
31
36
  - name: Run tests
32
37
  run: bundle exec rake test
data/ChangeLog.md CHANGED
@@ -1,3 +1,17 @@
1
+ ### 1.1.1 / 2024-01-23
2
+
3
+ * Switched to using `require_relative` to improve load-times.
4
+
5
+ ### 1.1.0 / 2023-09-12
6
+
7
+ * Added support for reading zip (`.zip`) and 7zip (`.7z`) compressed wordlist
8
+ files.
9
+ * Added support for building zip or 7zip compressed wordlist files.
10
+
11
+ #### CLI
12
+
13
+ * `-f,--format` now accepts `zip` and `7zip` format values.
14
+
1
15
  ### 1.0.3 / 2023-08-04
2
16
 
3
17
  * Fix reading of compressed wordlists on macOS.
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009-2023 Hal Brodigan
1
+ Copyright (c) 2009-2024 Hal Brodigan
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
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,12 @@ builder.parse_file(path)
223
223
 
224
224
  ## Requirements
225
225
 
226
- * [ruby] >= 2.0.0
226
+ * [ruby] >= 3.0.0
227
+ * `zcat`/`gzip` (for reading/writing `.gz` wordlists)
228
+ * `bzcat`/`bzip2` (for reading/writing `.bz2` wordlists)
229
+ * `xzcat`/`xz` (for reading/writing `.xz` wordlists)
230
+ * `unzip`/`zip` (for reading/writing `.zip` wordlists)
231
+ * `7za` (for reading/writing `.7z` wordlists)
227
232
 
228
233
  [ruby]: https://www.ruby-lang.org/
229
234
 
@@ -247,6 +252,59 @@ gem 'wordlist', '~> 1.0'
247
252
 
248
253
  ### Synopsis
249
254
 
255
+ ```
256
+ usage: wordlist { [options] WORDLIST ... | --build WORDLIST [FILE ...] }
257
+
258
+ Wordlist Reading Options:
259
+ -f {txt|gzip|bz2|xz|zip|7zip}, Sets the desired wordlist format
260
+ --format
261
+ --exec COMMAND Runs the command with each word from the wordlist.
262
+ The string "{}" will be replaced with each word.
263
+
264
+ Wordlist Operations:
265
+ -U, --union WORDLIST Unions the wordlist with the other WORDLIST
266
+ -I, --intersect WORDLIST Intersects the wordlist with the other WORDLIST
267
+ -S, --subtract WORDLIST Subtracts the words from the WORDLIST
268
+ -p, --product WORDLIST Combines every word with the other words from WORDLIST
269
+ -P, --power NUM Combines every word with the other words from WORDLIST
270
+ -u, --unique Filters out duplicate words
271
+
272
+ Wordlist Modifiers:
273
+ -C, --capitalize Capitalize each word
274
+ --uppercase, --upcase Converts each word to UPPERCASE
275
+ --lowercase, --downcase Converts each word to lowercase
276
+ -t, --tr CHARS:REPLACE Translates the characters of each word
277
+ -s, --sub PATTERN:SUB Replaces PATTERN with SUB in each word
278
+ -g, --gsub PATTERN:SUB Replaces all PATTERNs with SUB in each word
279
+ -m, --mutate PATTERN:SUB Performs every possible substitution on each word
280
+ -M, --mutate-case Switches the case of each letter in each word
281
+
282
+ Wordlist Building Options:
283
+ -b, --build WORDLIST Builds a wordlist
284
+ -a, --[no-]append Appends to the new wordlist instead of overwriting it
285
+ -L, --lang LANG The language to expect
286
+ --stop-words WORDS... Ignores the stop words
287
+ --ignore-words WORDS... Ignore the words
288
+ --[no-]digits Allow digits in the middle of words
289
+ --special-chars CHARS Allows the given special characters inside of words
290
+ --[no-]numbers Parses whole numbers in addition to words
291
+ --[no-]acronyms Parses acronyms in addition to words
292
+ --[no-]normalize-case Converts all words to lowercase
293
+ --[no-]normalize-apostrophes Removes "'s" from words
294
+ --[no-]normalize-acronyms Removes the dots from acronyms
295
+
296
+ General Options:
297
+ -V, --version Print the version
298
+ -h, --help Print the help output
299
+
300
+ Examples:
301
+ wordlist rockyou.txt.gz
302
+ wordlist passwords_short.txt passwords_long.txt
303
+ wordlist sport_teams.txt -p beers.txt -p digits.txt
304
+ cat *.txt | wordlist --build custom.txt
305
+
306
+ ```
307
+
250
308
  Reading a wordlist:
251
309
 
252
310
  ```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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/list_methods'
2
+ require_relative 'list_methods'
3
3
 
4
4
  module Wordlist
5
5
  #
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/format'
3
- require 'wordlist/lexer'
4
- require 'wordlist/unique_filter'
5
- require 'wordlist/file'
6
- require 'wordlist/compression/writer'
2
+ require_relative 'format'
3
+ require_relative 'lexer'
4
+ require_relative 'unique_filter'
5
+ require_relative 'file'
6
+ require_relative 'compression/writer'
7
7
 
8
8
  module Wordlist
9
9
  #
@@ -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
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/file'
3
- require 'wordlist/builder'
4
- require 'wordlist/version'
2
+ require_relative 'file'
3
+ require_relative 'builder'
4
+ require_relative 'version'
5
5
 
6
6
  require 'optparse'
7
7
 
@@ -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
 
@@ -1,4 +1,4 @@
1
- require 'wordlist/exceptions'
1
+ require_relative '../exceptions'
2
2
 
3
3
  require 'shellwords'
4
4
 
@@ -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)
@@ -1,4 +1,4 @@
1
- require 'wordlist/exceptions'
1
+ require_relative '../exceptions'
2
2
 
3
3
  require 'shellwords'
4
4
 
@@ -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
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/abstract_wordlist'
3
- require 'wordlist/exceptions'
4
- require 'wordlist/format'
5
- require 'wordlist/compression/reader'
2
+ require_relative 'abstract_wordlist'
3
+ require_relative 'exceptions'
4
+ require_relative 'format'
5
+ require_relative 'compression/reader'
6
6
 
7
7
  module Wordlist
8
8
  #
@@ -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
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/exceptions'
2
+ require_relative 'exceptions'
3
3
 
4
4
  module Wordlist
5
5
  #
@@ -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.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/exceptions'
2
+ require_relative '../exceptions'
3
3
 
4
4
  module Wordlist
5
5
  class Lexer
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/lexer/lang'
3
- require 'wordlist/lexer/stop_words'
2
+ require_relative 'lexer/lang'
3
+ require_relative 'lexer/stop_words'
4
4
 
5
5
  require 'strscan'
6
6
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/operators'
3
- require 'wordlist/modifiers'
2
+ require_relative 'operators'
3
+ require_relative 'modifiers'
4
4
 
5
5
  module Wordlist
6
6
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/modifiers/modifier'
2
+ require_relative 'modifier'
3
3
 
4
4
  module Wordlist
5
5
  module Modifiers
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/modifiers/modifier'
2
+ require_relative 'modifier'
3
3
 
4
4
  module Wordlist
5
5
  module Modifiers
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/modifiers/sub'
2
+ require_relative 'sub'
3
3
 
4
4
  module Wordlist
5
5
  module Modifiers
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/modifiers/sub'
2
+ require_relative 'sub'
3
3
 
4
4
  module Wordlist
5
5
  module Modifiers
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/modifiers/mutate'
2
+ require_relative 'mutate'
3
3
 
4
4
  module Wordlist
5
5
  module Modifiers
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/modifiers/modifier'
2
+ require_relative 'modifier'
3
3
 
4
4
  module Wordlist
5
5
  module Modifiers
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/modifiers/modifier'
2
+ require_relative 'modifier'
3
3
 
4
4
  module Wordlist
5
5
  module Modifiers
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/modifiers/modifier'
2
+ require_relative 'modifier'
3
3
 
4
4
  module Wordlist
5
5
  module Modifiers
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/modifiers/tr'
3
- require 'wordlist/modifiers/sub'
4
- require 'wordlist/modifiers/gsub'
5
- require 'wordlist/modifiers/capitalize'
6
- require 'wordlist/modifiers/upcase'
7
- require 'wordlist/modifiers/downcase'
8
- require 'wordlist/modifiers/mutate'
9
- require 'wordlist/modifiers/mutate_case'
2
+ require_relative 'modifiers/tr'
3
+ require_relative 'modifiers/sub'
4
+ require_relative 'modifiers/gsub'
5
+ require_relative 'modifiers/capitalize'
6
+ require_relative 'modifiers/upcase'
7
+ require_relative 'modifiers/downcase'
8
+ require_relative 'modifiers/mutate'
9
+ require_relative 'modifiers/mutate_case'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/operators/operator'
2
+ require_relative 'operator'
3
3
 
4
4
  module Wordlist
5
5
  module Operators
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/operators/binary_operator'
2
+ require_relative 'binary_operator'
3
3
 
4
4
  module Wordlist
5
5
  module Operators
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/operators/binary_operator'
3
- require 'wordlist/unique_filter'
2
+ require_relative 'binary_operator'
3
+ require_relative '../unique_filter'
4
4
 
5
5
  module Wordlist
6
6
  module Operators
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/operators/binary_operator'
3
- require 'wordlist/operators/product'
2
+ require_relative 'binary_operator'
3
+ require_relative 'product'
4
4
 
5
5
  module Wordlist
6
6
  module Operators
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/operators/binary_operator'
2
+ require_relative 'binary_operator'
3
3
 
4
4
  module Wordlist
5
5
  module Operators
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/operators/binary_operator'
3
- require 'wordlist/unique_filter'
2
+ require_relative 'binary_operator'
3
+ require_relative '../unique_filter'
4
4
 
5
5
  module Wordlist
6
6
  module Operators
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/operators/operator'
2
+ require_relative 'operator'
3
3
 
4
4
  module Wordlist
5
5
  module Operators
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/operators/binary_operator'
3
- require 'wordlist/unique_filter'
2
+ require_relative 'binary_operator'
3
+ require_relative '../unique_filter'
4
4
 
5
5
  module Wordlist
6
6
  module Operators
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/operators/unary_operator'
3
- require 'wordlist/unique_filter'
2
+ require_relative 'unary_operator'
3
+ require_relative '../unique_filter'
4
4
 
5
5
  module Wordlist
6
6
  module Operators
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/operators/concat'
3
- require 'wordlist/operators/subtract'
4
- require 'wordlist/operators/product'
5
- require 'wordlist/operators/power'
6
- require 'wordlist/operators/intersect'
7
- require 'wordlist/operators/union'
8
- require 'wordlist/operators/unique'
2
+ require_relative 'operators/concat'
3
+ require_relative 'operators/subtract'
4
+ require_relative 'operators/product'
5
+ require_relative 'operators/power'
6
+ require_relative 'operators/intersect'
7
+ require_relative 'operators/union'
8
+ require_relative 'operators/unique'
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Wordlist
4
4
  # wordlist version
5
- VERSION = '1.0.3'
5
+ VERSION = '1.1.1'
6
6
  end
data/lib/wordlist.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
- require 'wordlist/words'
3
- require 'wordlist/file'
4
- require 'wordlist/builder'
5
- require 'wordlist/version'
2
+ require_relative 'wordlist/words'
3
+ require_relative 'wordlist/file'
4
+ require_relative 'wordlist/builder'
5
+ require_relative 'wordlist/version'
6
6
 
7
7
  module Wordlist
8
8
  #
@@ -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
 
data/wordlist.gemspec CHANGED
@@ -7,10 +7,7 @@ Gem::Specification.new do |gem|
7
7
 
8
8
  gem.name = gemspec.fetch('name')
9
9
  gem.version = gemspec.fetch('version') do
10
- lib_dir = File.join(File.dirname(__FILE__),'lib')
11
- $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
-
13
- require 'wordlist/version'
10
+ require_relative 'lib/wordlist/version'
14
11
  Wordlist::VERSION
15
12
  end
16
13
 
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.1
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: 2024-01-24 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
  - - ">="