ruby-masscan 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.
@@ -0,0 +1,58 @@
1
+ require 'rspec'
2
+
3
+ shared_examples_for "Parser.open" do
4
+ context "when not given a block" do
5
+ it "must return the opened file" do
6
+ file = subject.open(path)
7
+
8
+ expect(file).to be_kind_of(File)
9
+ expect(file.closed?).to be(false)
10
+ end
11
+ end
12
+
13
+ context "when given a block" do
14
+ it "must yield the opened file" do
15
+ file_class = nil
16
+ file_opened = nil
17
+
18
+ subject.open(path) do |file|
19
+ file_class = file.class
20
+ file_opened = !file.closed?
21
+ end
22
+
23
+ expect(file_class).to be(File)
24
+ expect(file_opened).to be(true)
25
+ end
26
+ end
27
+ end
28
+
29
+ shared_examples_for "Parser.parse" do
30
+ context "when given a block" do
31
+ it "must yield Masscan::Status and Masscan::Banner objects" do
32
+ yielded_record_classes = []
33
+
34
+ subject.parse(io) do |record|
35
+ yielded_record_classes << record.class
36
+ end
37
+
38
+ expect(yielded_record_classes.uniq).to eq([
39
+ Masscan::Status,
40
+ Masscan::Banner
41
+ ])
42
+ end
43
+ end
44
+
45
+ context "when given no block" do
46
+ let(:expected_records) do
47
+ [].tap do |yielded_records|
48
+ subject.parse(subject.open(path)) do |record|
49
+ yielded_records << record
50
+ end
51
+ end
52
+ end
53
+
54
+ it "must return an Enumerator" do
55
+ expect(subject.parse(io).to_a).to eq(expected_records)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+ require 'masscan/parsers/plain_text'
3
+
4
+ describe Masscan::Parsers::PlainText do
5
+ module TestPlainText
6
+ extend Masscan::Parsers::PlainText
7
+ end
8
+
9
+ subject { TestPlainText }
10
+
11
+ describe "#parse_status" do
12
+ context "when given 'open'" do
13
+ it "must return :open" do
14
+ expect(subject.parse_status("open")).to be(:open)
15
+ end
16
+ end
17
+
18
+ context "when given 'closed'" do
19
+ it "must return :closed" do
20
+ expect(subject.parse_status("closed")).to be(:closed)
21
+ end
22
+ end
23
+
24
+ context "when given an unknown String" do
25
+ it "must return the String" do
26
+ expect(subject.parse_status("foo")).to eq("foo")
27
+ end
28
+ end
29
+ end
30
+
31
+ describe "#parse_reason" do
32
+ context "when given one flag" do
33
+ it "must map it to a keyword and return an Array" do
34
+ expect(subject.parse_reason("rst")).to eq([:rst])
35
+ end
36
+ end
37
+
38
+ context "when given multiple flags" do
39
+ it "must split them and map them to keyword" do
40
+ expect(subject.parse_reason("syn-ack")).to eq([:syn, :ack])
41
+ end
42
+ end
43
+
44
+ context "when given an unknown String" do
45
+ it "must return the String" do
46
+ expect(subject.parse_reason("foo")).to eq(["foo"])
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "#parse_ip_protocol" do
52
+ context "when given 'tcp'" do
53
+ it "must return :tcp" do
54
+ expect(subject.parse_ip_protocol("tcp")).to be(:tcp)
55
+ end
56
+ end
57
+
58
+ context "when given 'udp'" do
59
+ it "must return :udp" do
60
+ expect(subject.parse_ip_protocol("udp")).to be(:udp)
61
+ end
62
+ end
63
+
64
+ context "when given 'icmp'" do
65
+ it "must return :icmp" do
66
+ expect(subject.parse_ip_protocol("icmp")).to be(:icmp)
67
+ end
68
+ end
69
+
70
+ context "when given 'sctp'" do
71
+ it "must return :sctp" do
72
+ expect(subject.parse_ip_protocol("sctp")).to be(:sctp)
73
+ end
74
+ end
75
+
76
+ context "when given an unknown String" do
77
+ it "must return the String" do
78
+ expect(subject.parse_ip_protocol("foo")).to eq("foo")
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "#parse_app_protocol" do
84
+ described_class::APP_PROTOCOLS.each do |string,keyword|
85
+ context "when given '#{string}'" do
86
+ it "must return #{keyword.inspect}" do
87
+ expect(subject.parse_app_protocol(string)).to be(keyword)
88
+ end
89
+ end
90
+ end
91
+
92
+ context "when given an unknown String" do
93
+ it "must return the String" do
94
+ expect(subject.parse_app_protocol("foo")).to eq("foo")
95
+ end
96
+ end
97
+ end
98
+
99
+ describe "#parse_timestamp" do
100
+ let(:timestamp) { 1629960470 }
101
+ let(:time) { Time.at(timestamp) }
102
+
103
+ it "must parse a given UNIX timestamp and return a Time object" do
104
+ expect(subject.parse_timestamp(timestamp)).to eq(time)
105
+ end
106
+ end
107
+
108
+ describe "#parse_ip" do
109
+ let(:ip_string) { "1.2.3.4" }
110
+ let(:ip_addr) { IPAddr.new(ip_string) }
111
+
112
+ it "must parse a given IP string and return an IPAddr" do
113
+ expect(subject.parse_ip(ip_string)).to eq(ip_addr)
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+
5
+ module Fixtures
6
+ DIR = File.join(__dir__,'fixtures')
7
+
8
+ def self.join(*names)
9
+ File.join(DIR,*names)
10
+ end
11
+ end
data/spec/task_spec.rb ADDED
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+ require 'masscan/task'
3
+
4
+ describe Masscan::Task do
5
+ describe "#ports=" do
6
+ context "when given an empty Array" do
7
+ before { subject.ports = [] }
8
+
9
+ it "should ignore empty port Arrays" do
10
+ subject.ports = []
11
+
12
+ expect(subject.arguments).to eq([])
13
+ end
14
+ end
15
+
16
+ context "when given a String" do
17
+ let(:ports) { '80,21,25' }
18
+
19
+ before { subject.ports = ports }
20
+
21
+ it "should emit the String as is" do
22
+ expect(subject.arguments).to eq(['-p', ports])
23
+ end
24
+ end
25
+
26
+ context "when given an Array of Strings" do
27
+ let(:ports) { %w[80 21 25] }
28
+
29
+ before { subject.ports = ports }
30
+
31
+ it "should format an Array of String ports" do
32
+ expect(subject.arguments).to eq(['-p', ports.join(',')])
33
+ end
34
+ end
35
+
36
+ context "when given an Array of Integers" do
37
+ let(:ports) { [80, 21, 25] }
38
+
39
+ before { subject.ports = ports }
40
+
41
+ it "should format an Array of Integer ports" do
42
+ expect(subject.arguments).to eq(['-p', ports.join(',')])
43
+ end
44
+ end
45
+
46
+ context "when given an Array containing a Range" do
47
+ let(:ports) { [80, 21..25] }
48
+
49
+ before { subject.ports = ports }
50
+
51
+ it "should format the Range" do
52
+ expect(subject.arguments).to eq([
53
+ '-p', "#{ports[0]},#{ports[1].begin}-#{ports[1].end}"
54
+ ])
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "#shards=" do
60
+ context "when given a Rational value" do
61
+ let(:rational) { (1/2r) }
62
+
63
+ before { subject.shards = rational }
64
+
65
+ it "must format it into \#{numerator}/\#{denominator}" do
66
+ expect(subject.arguments).to eq([
67
+ "--shards", "#{rational.numerator}/#{rational.denominator}"
68
+ ])
69
+ end
70
+ end
71
+
72
+ context "when given an Array value" do
73
+ let(:array) { [1, 2] }
74
+
75
+ before { subject.shards = array }
76
+
77
+ it "must format it into \#{array[0]}/\#{array[1]}" do
78
+ expect(subject.arguments).to eq([
79
+ "--shards", "#{array[0]}/#{array[1]}"
80
+ ])
81
+ end
82
+
83
+ context "but the Array length is > 2" do
84
+ let(:array) { [1,2,3] }
85
+
86
+ before { subject.shards = array }
87
+
88
+ it do
89
+ expect {
90
+ subject.arguments
91
+ }.to raise_error(ArgumentError,"#{described_class}#shards= does not accept more than two values")
92
+ end
93
+ end
94
+ end
95
+
96
+ context "otherwise" do
97
+ let(:object) { :"1/2" }
98
+
99
+ before { subject.shards = object }
100
+
101
+ it "must convert the value to a String" do
102
+ expect(subject.arguments).to eq([
103
+ "--shards", object.to_s
104
+ ])
105
+ end
106
+ end
107
+ end
108
+
109
+ describe "#http_field=" do
110
+ let(:name) { 'X-Foo' }
111
+ let(:value) { 'bar' }
112
+
113
+ before { subject.http_field = [ [name, value] ] }
114
+
115
+ it "must join two values together with a ':'" do
116
+ expect(subject.arguments).to eq([
117
+ "--http-field", "#{name}:#{value}"
118
+ ])
119
+ end
120
+ end
121
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-masscan
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: 2021-08-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rprogram
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ description: A Ruby interface to masscan, an Internet-scale port scanner. Allows automating
42
+ masscan and parsing masscan Binary, List, JSON, and output file formats.
43
+ email: postmodern.mod3@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files:
47
+ - ChangeLog.md
48
+ - LICENSE.txt
49
+ - README.md
50
+ files:
51
+ - ".document"
52
+ - ".editorconfig"
53
+ - ".github/workflows/ruby.yml"
54
+ - ".gitignore"
55
+ - ".rspec"
56
+ - ".yardopts"
57
+ - ChangeLog.md
58
+ - Gemfile
59
+ - LICENSE.txt
60
+ - README.md
61
+ - Rakefile
62
+ - gemspec.yml
63
+ - lib/masscan.rb
64
+ - lib/masscan/banner.rb
65
+ - lib/masscan/output_file.rb
66
+ - lib/masscan/parsers.rb
67
+ - lib/masscan/parsers/binary.rb
68
+ - lib/masscan/parsers/json.rb
69
+ - lib/masscan/parsers/list.rb
70
+ - lib/masscan/parsers/plain_text.rb
71
+ - lib/masscan/program.rb
72
+ - lib/masscan/status.rb
73
+ - lib/masscan/task.rb
74
+ - lib/masscan/version.rb
75
+ - ruby-masscan.gemspec
76
+ - spec/fixtures/masscan.bin
77
+ - spec/fixtures/masscan.json
78
+ - spec/fixtures/masscan.list
79
+ - spec/fixtures/masscan.ndjson
80
+ - spec/fixtures/masscan.xml
81
+ - spec/output_file_spec.rb
82
+ - spec/parsers/binary_spec.rb
83
+ - spec/parsers/json_spec.rb
84
+ - spec/parsers/list_spec.rb
85
+ - spec/parsers/parser_examples.rb
86
+ - spec/parsers/plain_text_spec.rb
87
+ - spec/spec_helper.rb
88
+ - spec/task_spec.rb
89
+ homepage: https://github.com/postmodern/ruby-masscan#readme
90
+ licenses:
91
+ - MIT
92
+ metadata:
93
+ documentation_uri: https://rubydoc.info/gems/ruby-masscan
94
+ source_code_uri: https://github.com/postmodern/ruby-masscan
95
+ bug_tracker_uri: https://github.com/postmodern/ruby-masscan/issues
96
+ changelog_uri: https://github.com/postmodern/ruby-masscan/blob/master/ChangeLog.md
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: 2.0.0
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements:
112
+ - masscan >= 1.0.0
113
+ rubygems_version: 3.2.22
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: A Ruby interface to masscan.
117
+ test_files: []