ruby-rustscan 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ed273c201a779c2af67db77c918ceb5be91d5215115d0f24bf9eb4f787f54ec3
4
+ data.tar.gz: ecc1c363ba8068c177202cbe1e20f27e8740b2783637c1c7a815af9a25b5c84e
5
+ SHA512:
6
+ metadata.gz: 218a92ab0d1fc7ec48d5fbbac74d3a551344df13d933104255437c66b8ad5937f63f532ca895d8fa4b26ce42801851afe4cdc496388cbabe8a4bf7503ea232c0
7
+ data.tar.gz: 17b7fe2485ac511f0af7ed5530aa316181fade303287e59e38b5b5a7791c74aab1247671c5f227ab8bdea91c7c84c9c3bb55bc2273f5ab38edeaec6333d4b228
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ -
2
+ ChangeLog.md
3
+ LICENSE.txt
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on: [ push, pull_request ]
4
+
5
+ jobs:
6
+ tests:
7
+ runs-on: ubuntu-latest
8
+ strategy:
9
+ fail-fast: false
10
+ matrix:
11
+ ruby:
12
+ - 2.6
13
+ - 2.7
14
+ - '3.0'
15
+ - 3.1
16
+ - jruby
17
+ - truffleruby
18
+ name: Ruby ${{ matrix.ruby }}
19
+ steps:
20
+ - uses: actions/checkout@v2
21
+ - name: Set up Ruby
22
+ uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: ${{ matrix.ruby }}
25
+ - name: Install dependencies
26
+ run: bundle install --jobs 4 --retry 3
27
+ - name: Run tests
28
+ run: bundle exec rake test
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /Gemfile.lock
2
+ /coverage
3
+ /doc
4
+ /pkg
5
+ /.yardoc
6
+ .DS_Store
7
+ *.db
8
+ *.log
9
+ *.swp
10
+ *~
11
+ *.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown --title 'Ruby Gobuster Documentation' --protected
data/ChangeLog.md ADDED
@@ -0,0 +1,5 @@
1
+ ### 0.1.0 / 2021-04-22
2
+
3
+ * Initial release:
4
+ * Added {Rustscan::Command}.
5
+
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ # gem 'command_mapper', '~> 0.2', github: 'postmodern/command_mapper.rb'
6
+
7
+ group :development do
8
+ gem 'rake'
9
+ gem 'rubygems-tasks', '~> 0.2'
10
+ gem 'rspec', '~> 3.0'
11
+ gem 'simplecov', '~> 0.7'
12
+
13
+ gem 'kramdown'
14
+ gem 'redcarpet', platform: :mri
15
+ gem 'yard', '~> 0.9'
16
+ gem 'yard-spellcheck', require: false
17
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2022 Hal Brodigan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ 'Software'), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # ruby-rustscan
2
+
3
+ [![CI](https://github.com/postmodern/ruby-rustscan/actions/workflows/ruby.yml/badge.svg)](https://github.com/postmodern/ruby-rustscan/actions/workflows/ruby.yml)
4
+ [![Gem Version](https://badge.fury.io/rb/ruby-rustscan.svg)](https://badge.fury.io/rb/ruby-rustscan)
5
+
6
+ * [Source](https://github.com/postmodern/ruby-rustscan/)
7
+ * [Issues](https://github.com/postmodern/ruby-rustscan/issues)
8
+ * [Documentation](http://rubydoc.info/gems/ruby-rustscan/frames)
9
+
10
+ ## Description
11
+
12
+ A Ruby interface to [rustscan], the Modern Port Scanner.
13
+
14
+ ## Features
15
+
16
+ * Provides a [Ruby interface][Rustscan::Command] for running the `rustscan`
17
+ command.
18
+
19
+ [Rustscan::Command]: https://rubydoc.info/gems/ruby-rustscan/Rustscan/Command
20
+
21
+ ## Examples
22
+
23
+ Run `rustscan --addresses 127.0.0.1 -p 80,443` from Ruby:
24
+
25
+ ```ruby
26
+ require 'rustscan/command'
27
+
28
+ Rustscan::Command.run(addresses: ['127.0.0.1'], ports: [80, 443])
29
+ ```
30
+
31
+ ## Requirements
32
+
33
+ * [ruby] >= 2.0.0
34
+ * [rustscan] >= 2.0.0
35
+ * [command_mapper] ~> 0.2, >= 0.2.1
36
+
37
+ [ruby]: https://www.ruby-lang.org/
38
+ [command_mapper]: https://github.com/postmodern/command_mapper.rb#readme
39
+
40
+ ## Install
41
+
42
+ ```shell
43
+ $ gem install ruby-rustscan
44
+ ```
45
+
46
+ ### gemspec
47
+
48
+ ```ruby
49
+ gemspec.add_dependency 'ruby-rustscan', '~> 0.1'
50
+ ```
51
+
52
+ ### Gemfile
53
+
54
+ ```ruby
55
+ gem 'ruby-rustscan', '~> 0.1'
56
+ ```
57
+
58
+ ## License
59
+
60
+ Copyright (c) 2022 Hal Brodigan
61
+
62
+ See {file:LICENSE.txt} for license information.
63
+
64
+ [rustscan]: https://github.com/OJ/rustscan#readme
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+
5
+ begin
6
+ require 'bundler/setup'
7
+ rescue LoadError => e
8
+ warn e.message
9
+ warn "Run `gem install bundler` to install Bundler"
10
+ exit -1
11
+ end
12
+
13
+ require 'rubygems/tasks'
14
+ Gem::Tasks.new
15
+
16
+ require 'rspec/core/rake_task'
17
+ RSpec::Core::RakeTask.new
18
+ task :test => :spec
19
+ task :default => :spec
20
+
21
+ require 'yard'
22
+ YARD::Rake::YardocTask.new
23
+ task :doc => :yard
data/gemspec.yml ADDED
@@ -0,0 +1,27 @@
1
+ name: ruby-rustscan
2
+ summary: A Ruby interface to rustscan.
3
+ description:
4
+ A Ruby interface to rustscan, the Modern Port Scanner.
5
+
6
+ license: MIT
7
+ authors: Postmodern
8
+ email: postmodern.mod3@gmail.com
9
+ homepage: https://github.com/postmodern/ruby-rustscan#readme
10
+ has_yard: true
11
+
12
+ metadata:
13
+ documentation_uri: https://rubydoc.info/gems/ruby-rustscan
14
+ source_code_uri: https://github.com/postmodern/ruby-rustscan
15
+ bug_tracker_uri: https://github.com/postmodern/ruby-rustscan/issues
16
+ changelog_uri: https://github.com/postmodern/ruby-rustscan/blob/master/ChangeLog.md
17
+ rubygems_mfa_required: 'true'
18
+
19
+ required_ruby_version: ">= 2.0.0"
20
+
21
+ requirements: rustscan >= 2.0.0
22
+
23
+ dependencies:
24
+ command_mapper: ~> 0.2, >= 0.2.1
25
+
26
+ development_dependencies:
27
+ bundler: ~> 2.0
@@ -0,0 +1,26 @@
1
+ require 'command_mapper/command'
2
+
3
+ module Rustscan
4
+ class Command < CommandMapper::Command
5
+
6
+ command 'rustscan' do
7
+ option '--accessible'
8
+ option '--greppable'
9
+ option '--help'
10
+ option '--no-config'
11
+ option '--top'
12
+ option '--version'
13
+ option '--addresses', value: {type: List.new}
14
+ option '--batch-size', value: {type: Num.new}
15
+ option '--ports', value: {type: List.new(type: Num.new)}
16
+ option '--scan-order', value: {type: Enum[:serial, :random]}
17
+ option '--scripts', value: {type: Enum[:none, :default, :custom]}
18
+ option '--timeout', value: {type: Num.new}
19
+ option '--tries', value: {type: Num.new}
20
+ option '--ulimit', value: {type: Num.new}
21
+
22
+ argument :command, repeats: true, required: false
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,4 @@
1
+ module Rustscan
2
+ # ruby-rustscan version
3
+ VERSION = '0.1.0'
4
+ end
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
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 'rustscan/version'
14
+ Rustscan::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+ gem.metadata = gemspec['metadata'] if gemspec['metadata']
24
+
25
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
26
+
27
+ gem.files = `git ls-files`.split($/)
28
+ gem.files = glob[gemspec['files']] if gemspec['files']
29
+
30
+ gem.executables = gemspec.fetch('executables') do
31
+ glob['bin/*'].map { |path| File.basename(path) }
32
+ end
33
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
34
+
35
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
36
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
37
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
38
+
39
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
40
+ %w[ext lib].select { |dir| File.directory?(dir) }
41
+ })
42
+
43
+ gem.requirements = Array(gemspec['requirements'])
44
+ gem.required_ruby_version = gemspec['required_ruby_version']
45
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
46
+ gem.post_install_message = gemspec['post_install_message']
47
+
48
+ split = lambda { |string| string.split(/,\s*/) }
49
+
50
+ if gemspec['dependencies']
51
+ gemspec['dependencies'].each do |name,versions|
52
+ gem.add_dependency(name,split[versions])
53
+ end
54
+ end
55
+
56
+ if gemspec['development_dependencies']
57
+ gemspec['development_dependencies'].each do |name,versions|
58
+ gem.add_development_dependency(name,split[versions])
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,256 @@
1
+ require 'spec_helper'
2
+ require 'rustscan/command'
3
+
4
+ describe Rustscan::Command do
5
+ describe ".command_name" do
6
+ subject { described_class }
7
+
8
+ it "must be set to 'rustscan'" do
9
+ expect(subject.command_name).to eq('rustscan')
10
+ end
11
+ end
12
+
13
+ describe ":addresses" do
14
+ let(:ip1) { '127.0.0.1' }
15
+ let(:ip2) { '192.168.1.1' }
16
+
17
+ let(:addresses) { [ip1, ip2] }
18
+
19
+ subject { described_class.new(addresses: addresses) }
20
+
21
+ it "must map multiple addresses to --addresses and a comma separated list" do
22
+ expect(subject.command_argv).to eq(
23
+ [subject.command_name, '--addresses', "#{ip1},#{ip2}"]
24
+ )
25
+ end
26
+ end
27
+
28
+ describe ":batch_size" do
29
+ let(:batch_size) { 10 }
30
+
31
+ subject { described_class.new(batch_size: batch_size) }
32
+
33
+ it "must map to --batch-size" do
34
+ expect(subject.command_argv).to eq(
35
+ [subject.command_name, '--batch-size', "#{batch_size}"]
36
+ )
37
+ end
38
+
39
+ context "but when a non-number is given" do
40
+ let(:batch_size) { "foo" }
41
+
42
+ it "must only accept numeric values" do
43
+ expect {
44
+ subject.command_argv
45
+ }.to raise_error(CommandMapper::ValidationError,"option batch_size was given an invalid value (#{batch_size.inspect}): contains non-numeric characters (#{batch_size.inspect})")
46
+ end
47
+ end
48
+ end
49
+
50
+ describe ":ports" do
51
+ let(:port1) { 80 }
52
+ let(:port2) { 443 }
53
+ let(:port3) { 8080 }
54
+ let(:ports) { [port1, port2, port3] }
55
+
56
+ subject { described_class.new(ports: ports) }
57
+
58
+ it "must map to --ports and a comma-separated list" do
59
+ expect(subject.command_argv).to eq(
60
+ [subject.command_name, '--ports', "#{port1},#{port2},#{port3}"]
61
+ )
62
+ end
63
+
64
+ context "but when a non-number is given" do
65
+ let(:port2) { "foo" }
66
+
67
+ it "must only accept numeric values" do
68
+ expect {
69
+ subject.command_argv
70
+ }.to raise_error(CommandMapper::ValidationError,"option ports was given an invalid value (#{ports.inspect}): element contains non-numeric characters (#{port2.inspect})")
71
+ end
72
+ end
73
+ end
74
+
75
+ describe ":scan_order" do
76
+ context "when given :serial" do
77
+ let(:scan_order) { :serial }
78
+
79
+ subject { described_class.new(scan_order: scan_order) }
80
+
81
+ it "must map to --scan-order serial" do
82
+ expect(subject.command_argv).to eq(
83
+ [subject.command_name, '--scan-order', "#{scan_order}"]
84
+ )
85
+ end
86
+ end
87
+
88
+ context "when given :random" do
89
+ let(:scan_order) { :random }
90
+
91
+ subject { described_class.new(scan_order: scan_order) }
92
+
93
+ it "must map to --scan-order random" do
94
+ expect(subject.command_argv).to eq(
95
+ [subject.command_name, '--scan-order', "#{scan_order}"]
96
+ )
97
+ end
98
+ end
99
+
100
+ context "but when given an invalid scan order type" do
101
+ let(:scan_order) { :foo }
102
+
103
+ subject { described_class.new(scan_order: scan_order) }
104
+
105
+ it "must only accept :serial or :random" do
106
+ expect {
107
+ subject.command_argv
108
+ }.to raise_error(CommandMapper::ValidationError,"option scan_order was given an invalid value (#{scan_order.inspect}): unknown value (#{scan_order.inspect}) must be :serial, :random, or \"serial\", \"random\"")
109
+ end
110
+ end
111
+ end
112
+
113
+ describe ":scripts" do
114
+ context "when given :none" do
115
+ let(:scripts) { :none }
116
+
117
+ subject { described_class.new(scripts: scripts) }
118
+
119
+ it "must map to --scripts none" do
120
+ expect(subject.command_argv).to eq(
121
+ [subject.command_name, '--scripts', "#{scripts}"]
122
+ )
123
+ end
124
+ end
125
+
126
+ context "when given :default" do
127
+ let(:scripts) { :default }
128
+
129
+ subject { described_class.new(scripts: scripts) }
130
+
131
+ it "must map to --scripts default" do
132
+ expect(subject.command_argv).to eq(
133
+ [subject.command_name, '--scripts', "#{scripts}"]
134
+ )
135
+ end
136
+ end
137
+
138
+ context "when given :custom" do
139
+ let(:scripts) { :custom}
140
+
141
+ subject { described_class.new(scripts: scripts) }
142
+
143
+ it "must map to --scripts custom" do
144
+ expect(subject.command_argv).to eq(
145
+ [subject.command_name, '--scripts', "#{scripts}"]
146
+ )
147
+ end
148
+ end
149
+
150
+ context "but when given an invalid scan order type" do
151
+ let(:scripts) { :foo }
152
+
153
+ subject { described_class.new(scripts: scripts) }
154
+
155
+ it "must only accept :none, :default, or :random" do
156
+ expect {
157
+ subject.command_argv
158
+ }.to raise_error(CommandMapper::ValidationError,"option scripts was given an invalid value (#{scripts.inspect}): unknown value (#{scripts.inspect}) must be :none, :default, :custom, or \"none\", \"default\", \"custom\"")
159
+ end
160
+ end
161
+ end
162
+
163
+ describe ":timeout" do
164
+ let(:timeout) { 10 }
165
+
166
+ subject { described_class.new(timeout: timeout) }
167
+
168
+ it "must map to --timeout" do
169
+ expect(subject.command_argv).to eq(
170
+ [subject.command_name, '--timeout', "#{timeout}"]
171
+ )
172
+ end
173
+
174
+ context "but when a non-number is given" do
175
+ let(:timeout) { "foo" }
176
+
177
+ it "must only accept numeric values" do
178
+ expect {
179
+ subject.command_argv
180
+ }.to raise_error(CommandMapper::ValidationError,"option timeout was given an invalid value (#{timeout.inspect}): contains non-numeric characters (#{timeout.inspect})")
181
+ end
182
+ end
183
+ end
184
+
185
+ describe ":tries" do
186
+ let(:tries) { 10 }
187
+
188
+ subject { described_class.new(tries: tries) }
189
+
190
+ it "must map to --tries" do
191
+ expect(subject.command_argv).to eq(
192
+ [subject.command_name, '--tries', "#{tries}"]
193
+ )
194
+ end
195
+
196
+ context "but when a non-number is given" do
197
+ let(:tries) { "foo" }
198
+
199
+ it "must only accept numeric values" do
200
+ expect {
201
+ subject.command_argv
202
+ }.to raise_error(CommandMapper::ValidationError,"option tries was given an invalid value (#{tries.inspect}): contains non-numeric characters (#{tries.inspect})")
203
+ end
204
+ end
205
+ end
206
+
207
+ describe ":ulimit" do
208
+ let(:ulimit) { 10 }
209
+
210
+ subject { described_class.new(ulimit: ulimit) }
211
+
212
+ it "must map to --ulimit" do
213
+ expect(subject.command_argv).to eq(
214
+ [subject.command_name, '--ulimit', "#{ulimit}"]
215
+ )
216
+ end
217
+
218
+ context "but when a non-number is given" do
219
+ let(:ulimit) { "foo" }
220
+
221
+ it "must only accept numeric values" do
222
+ expect {
223
+ subject.command_argv
224
+ }.to raise_error(CommandMapper::ValidationError,"option ulimit was given an invalid value (#{ulimit.inspect}): contains non-numeric characters (#{ulimit.inspect})")
225
+ end
226
+ end
227
+ end
228
+
229
+ describe ":command" do
230
+ let(:addresses) { '127.0.0.1' }
231
+
232
+ context "when given one value" do
233
+ let(:command) { '-A' }
234
+
235
+ subject { described_class.new(addresses: addresses, command: command) }
236
+
237
+ it "must append the value to the end of the command" do
238
+ expect(subject.command_argv).to eq(
239
+ [subject.command_name, '--addresses', "#{addresses}", '--', command]
240
+ )
241
+ end
242
+ end
243
+
244
+ context "when given multiple values" do
245
+ let(:command) { %w[-A -sC] }
246
+
247
+ subject { described_class.new(addresses: addresses, command: command) }
248
+
249
+ it "must append each value to the end of the command" do
250
+ expect(subject.command_argv).to eq(
251
+ [subject.command_name, '--addresses', "#{addresses}", '--', *command]
252
+ )
253
+ end
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,3 @@
1
+ require 'rspec'
2
+ require 'simplecov'
3
+ SimpleCov.start
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-rustscan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Postmodern
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-04-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: command_mapper
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.2'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.2.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.2'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.2.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.0'
47
+ description: A Ruby interface to rustscan, the Modern Port Scanner.
48
+ email: postmodern.mod3@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files:
52
+ - ChangeLog.md
53
+ - LICENSE.txt
54
+ - README.md
55
+ files:
56
+ - ".document"
57
+ - ".github/workflows/ruby.yml"
58
+ - ".gitignore"
59
+ - ".rspec"
60
+ - ".yardopts"
61
+ - ChangeLog.md
62
+ - Gemfile
63
+ - LICENSE.txt
64
+ - README.md
65
+ - Rakefile
66
+ - gemspec.yml
67
+ - lib/rustscan/command.rb
68
+ - lib/rustscan/version.rb
69
+ - ruby-rustscan.gemspec
70
+ - spec/command_spec.rb
71
+ - spec/spec_helper.rb
72
+ homepage: https://github.com/postmodern/ruby-rustscan#readme
73
+ licenses:
74
+ - MIT
75
+ metadata:
76
+ documentation_uri: https://rubydoc.info/gems/ruby-rustscan
77
+ source_code_uri: https://github.com/postmodern/ruby-rustscan
78
+ bug_tracker_uri: https://github.com/postmodern/ruby-rustscan/issues
79
+ changelog_uri: https://github.com/postmodern/ruby-rustscan/blob/master/ChangeLog.md
80
+ rubygems_mfa_required: 'true'
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 2.0.0
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements:
96
+ - rustscan >= 2.0.0
97
+ rubygems_version: 3.2.22
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: A Ruby interface to rustscan.
101
+ test_files: []