ronin-db-activerecord 0.1.0.beta1

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.
Files changed (135) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.github/workflows/ruby.yml +31 -0
  4. data/.gitignore +13 -0
  5. data/.rspec +1 -0
  6. data/.ruby-version +1 -0
  7. data/.yardopts +1 -0
  8. data/COPYING.txt +165 -0
  9. data/ChangeLog.md +39 -0
  10. data/Gemfile +27 -0
  11. data/README.md +143 -0
  12. data/Rakefile +72 -0
  13. data/db/migrate/0001_create_ronin_ip_address_mac_addresses_table.rb +43 -0
  14. data/db/migrate/0002_create_ronin_vulnerabilities_table.rb +61 -0
  15. data/db/migrate/0003_create_ronin_url_schemes_table.rb +32 -0
  16. data/db/migrate/0004_create_ronin_url_query_param_names_table.rb +32 -0
  17. data/db/migrate/0005_create_ronin_user_names_table.rb +33 -0
  18. data/db/migrate/0006_create_ronin_software_vendors_table.rb +32 -0
  19. data/db/migrate/0007_create_ronin_advisories_table.rb +42 -0
  20. data/db/migrate/0008_create_ronin_host_name_ip_addresses_table.rb +43 -0
  21. data/db/migrate/0009_create_ronin_host_names_table.rb +34 -0
  22. data/db/migrate/0010_create_ronin_arches_table.rb +37 -0
  23. data/db/migrate/0011_create_ronin_email_addresses_table.rb +44 -0
  24. data/db/migrate/0012_create_ronin_oses_table.rb +36 -0
  25. data/db/migrate/0013_create_ronin_organizations_table.rb +31 -0
  26. data/db/migrate/0014_create_ronin_ip_addresses_table.rb +35 -0
  27. data/db/migrate/0015_create_ronin_os_guesses_table.rb +40 -0
  28. data/db/migrate/0016_create_ronin_url_query_params_table.rb +42 -0
  29. data/db/migrate/0017_create_ronin_passwords_table.rb +32 -0
  30. data/db/migrate/0018_create_ronin_open_ports_table.rb +46 -0
  31. data/db/migrate/0019_create_ronin_urls_table.rb +50 -0
  32. data/db/migrate/0020_create_ronin_softwares_table.rb +39 -0
  33. data/db/migrate/0021_create_ronin_mac_addresses_table.rb +33 -0
  34. data/db/migrate/0022_create_ronin_countries_table.rb +34 -0
  35. data/db/migrate/0023_create_ronin_services_table.rb +32 -0
  36. data/db/migrate/0024_create_ronin_credentials_table.rb +44 -0
  37. data/db/migrate/0025_create_ronin_ports_table.rb +33 -0
  38. data/db/migrate/0026_create_ronin_asns_table.rb +44 -0
  39. data/db/migrate/0027_create_ronin_http_query_param_names_table.rb +32 -0
  40. data/db/migrate/0028_create_ronin_http_query_params_table.rb +42 -0
  41. data/db/migrate/0029_create_ronin_http_header_names_table.rb +31 -0
  42. data/db/migrate/0030_create_ronin_http_request_headers_table.rb +41 -0
  43. data/db/migrate/0031_create_ronin_http_response_headers_table.rb +41 -0
  44. data/db/migrate/0032_create_ronin_http_requests_table.rb +41 -0
  45. data/db/migrate/0033_create_ronin_http_responses_table.rb +36 -0
  46. data/db/migrate/0034_create_ronin_service_credentials_table.rb +41 -0
  47. data/db/migrate/0035_create_ronin_web_credentials_table.rb +41 -0
  48. data/gemspec.yml +28 -0
  49. data/lib/ronin/db/address.rb +105 -0
  50. data/lib/ronin/db/advisory.rb +169 -0
  51. data/lib/ronin/db/arch.rb +160 -0
  52. data/lib/ronin/db/asn.rb +212 -0
  53. data/lib/ronin/db/credential.rb +248 -0
  54. data/lib/ronin/db/email_address.rb +225 -0
  55. data/lib/ronin/db/host_name.rb +224 -0
  56. data/lib/ronin/db/host_name_ip_address.rb +65 -0
  57. data/lib/ronin/db/http_header_name.rb +75 -0
  58. data/lib/ronin/db/http_query_param.rb +79 -0
  59. data/lib/ronin/db/http_query_param_name.rb +76 -0
  60. data/lib/ronin/db/http_request.rb +120 -0
  61. data/lib/ronin/db/http_request_header.rb +78 -0
  62. data/lib/ronin/db/http_response.rb +91 -0
  63. data/lib/ronin/db/http_response_header.rb +78 -0
  64. data/lib/ronin/db/ip_address.rb +351 -0
  65. data/lib/ronin/db/ip_address_mac_address.rb +62 -0
  66. data/lib/ronin/db/mac_address.rb +91 -0
  67. data/lib/ronin/db/migrations.rb +137 -0
  68. data/lib/ronin/db/model/has_name.rb +102 -0
  69. data/lib/ronin/db/model/has_unique_name.rb +82 -0
  70. data/lib/ronin/db/model/importable.rb +85 -0
  71. data/lib/ronin/db/model/last_scanned_at.rb +48 -0
  72. data/lib/ronin/db/model.rb +37 -0
  73. data/lib/ronin/db/models.rb +108 -0
  74. data/lib/ronin/db/open_port.rb +148 -0
  75. data/lib/ronin/db/organization.rb +50 -0
  76. data/lib/ronin/db/os.rb +183 -0
  77. data/lib/ronin/db/os_guess.rb +67 -0
  78. data/lib/ronin/db/password.rb +167 -0
  79. data/lib/ronin/db/port.rb +123 -0
  80. data/lib/ronin/db/root.rb +28 -0
  81. data/lib/ronin/db/schema_migration.rb +34 -0
  82. data/lib/ronin/db/service.rb +48 -0
  83. data/lib/ronin/db/service_credential.rb +66 -0
  84. data/lib/ronin/db/software.rb +85 -0
  85. data/lib/ronin/db/software_vendor.rb +42 -0
  86. data/lib/ronin/db/url.rb +497 -0
  87. data/lib/ronin/db/url_query_param.rb +79 -0
  88. data/lib/ronin/db/url_query_param_name.rb +76 -0
  89. data/lib/ronin/db/url_scheme.rb +80 -0
  90. data/lib/ronin/db/user_name.rb +96 -0
  91. data/lib/ronin/db/vulnerability.rb +81 -0
  92. data/lib/ronin/db/web_credential.rb +69 -0
  93. data/ronin-db-activerecord.gemspec +61 -0
  94. data/spec/advisory_spec.rb +277 -0
  95. data/spec/arch_spec.rb +228 -0
  96. data/spec/asn_spec.rb +504 -0
  97. data/spec/credential_spec.rb +362 -0
  98. data/spec/email_address_spec.rb +372 -0
  99. data/spec/host_name_ip_address_spec.rb +8 -0
  100. data/spec/host_name_spec.rb +207 -0
  101. data/spec/http_header_name_spec.rb +25 -0
  102. data/spec/http_query_param_name_spec.rb +25 -0
  103. data/spec/http_query_param_spec.rb +104 -0
  104. data/spec/http_request_header_spec.rb +72 -0
  105. data/spec/http_request_spec.rb +168 -0
  106. data/spec/http_response_header_spec.rb +74 -0
  107. data/spec/http_response_spec.rb +103 -0
  108. data/spec/ip_address_mac_addresses_spec.rb +8 -0
  109. data/spec/ip_address_spec.rb +386 -0
  110. data/spec/mac_address_spec.rb +67 -0
  111. data/spec/migrations_spec.rb +122 -0
  112. data/spec/model/has_name_spec.rb +65 -0
  113. data/spec/model/has_unique_name_spec.rb +61 -0
  114. data/spec/model/importable_spec.rb +105 -0
  115. data/spec/models_spec.rb +60 -0
  116. data/spec/open_port_spec.rb +87 -0
  117. data/spec/organization_spec.rb +10 -0
  118. data/spec/os_guess_spec.rb +43 -0
  119. data/spec/os_spec.rb +114 -0
  120. data/spec/password_spec.rb +81 -0
  121. data/spec/port_spec.rb +102 -0
  122. data/spec/schema_migration_spec.rb +8 -0
  123. data/spec/service_credential_spec.rb +43 -0
  124. data/spec/service_spec.rb +39 -0
  125. data/spec/software_spec.rb +76 -0
  126. data/spec/software_vendor_spec.rb +33 -0
  127. data/spec/spec_helper.rb +13 -0
  128. data/spec/url_query_param_name_spec.rb +25 -0
  129. data/spec/url_query_param_spec.rb +110 -0
  130. data/spec/url_scheme_spec.rb +39 -0
  131. data/spec/url_spec.rb +951 -0
  132. data/spec/user_name_spec.rb +54 -0
  133. data/spec/vulnerability_spec.rb +8 -0
  134. data/spec/web_credential_spec.rb +72 -0
  135. metadata +266 -0
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/model/importable'
3
+
4
+ describe Ronin::DB::Model::Importable do
5
+ class TestModelImportable < ActiveRecord::Base
6
+ include Ronin::DB::Model::Importable
7
+
8
+ self.table_name = 'test_model_importable'
9
+
10
+ def self.lookup(value)
11
+ find_by(value: value)
12
+ end
13
+
14
+ def self.import(value)
15
+ create(value: value)
16
+ end
17
+ end
18
+
19
+ class TestModelImportableWithoutMethods < ActiveRecord::Base
20
+ include Ronin::DB::Model::Importable
21
+
22
+ self.table_name = 'test_model_importable'
23
+ end
24
+
25
+ let(:model) { TestModelImportable }
26
+
27
+ before(:all) do
28
+ ActiveRecord::Base.connection.create_table :test_model_importable do |t|
29
+ t.string :value
30
+
31
+ t.index :value, unique: true
32
+ end
33
+ end
34
+
35
+ let(:value) { "foo" }
36
+
37
+ describe ".lookup" do
38
+ subject { model }
39
+
40
+ context "when not defined in the model class" do
41
+ let(:model) { TestModelImportableWithoutMethods }
42
+
43
+ it "must raise NotImplementedError" do
44
+ expect {
45
+ subject.lookup(value)
46
+ }.to raise_error(NotImplementedError,"#{model} did not define a self.lookup method")
47
+ end
48
+ end
49
+ end
50
+
51
+ describe ".import" do
52
+ subject { model }
53
+
54
+ context "when not defined in the model class" do
55
+ let(:model) { TestModelImportableWithoutMethods }
56
+
57
+ it "must raise NotImplementedError" do
58
+ expect {
59
+ subject.import(value)
60
+ }.to raise_error(NotImplementedError,"#{model} did not define a self.import method")
61
+ end
62
+ end
63
+ end
64
+
65
+ describe ".find_or_import" do
66
+ subject { model }
67
+
68
+ context "when a record with the matching value already exists" do
69
+ before do
70
+ model.create(value: 'other value1')
71
+ model.create(value: value)
72
+ model.create(value: 'other value2')
73
+ end
74
+
75
+ it "must query and return the existing record for the value" do
76
+ record = subject.find_or_import(value)
77
+
78
+ expect(record).to be_kind_of(model)
79
+ expect(record).to be_persisted
80
+ expect(record.value).to eq(value)
81
+ expect(record).to eq(model.all[1])
82
+ end
83
+
84
+ after { model.destroy_all }
85
+ end
86
+
87
+ context "when a record with the matching value does not already exists" do
88
+ before do
89
+ model.create(value: 'other value1')
90
+ model.create(value: 'other value2')
91
+ end
92
+
93
+ it "must create and return a new record for the value" do
94
+ record = subject.find_or_import(value)
95
+
96
+ expect(record).to be_kind_of(model)
97
+ expect(record).to be_persisted
98
+ expect(record.value).to eq(value)
99
+ expect(record).to eq(model.last)
100
+ end
101
+
102
+ after { model.destroy_all }
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ronin/db/models' do
4
+ it "must load all models" do
5
+ expect(require 'ronin/db/models').to eq(true)
6
+ end
7
+ end
8
+
9
+ describe 'Ronin::DB::Models'do
10
+ before(:all) { require 'ronin/db/models' }
11
+
12
+ subject { Ronin::DB::Models }
13
+
14
+ describe "ALL" do
15
+ subject { super()::ALL }
16
+
17
+ it { expect(subject).to include(Ronin::DB::Arch) }
18
+ it { expect(subject).to include(Ronin::DB::Credential) }
19
+ it { expect(subject).to include(Ronin::DB::EmailAddress) }
20
+ it { expect(subject).to include(Ronin::DB::HostName) }
21
+ it { expect(subject).to include(Ronin::DB::HostNameIPAddress) }
22
+ it { expect(subject).to include(Ronin::DB::IPAddress) }
23
+ it { expect(subject).to include(Ronin::DB::IPAddressMACAddress) }
24
+ it { expect(subject).to include(Ronin::DB::MACAddress) }
25
+ it { expect(subject).to include(Ronin::DB::OS) }
26
+ it { expect(subject).to include(Ronin::DB::OSGuess) }
27
+ it { expect(subject).to include(Ronin::DB::OpenPort) }
28
+ it { expect(subject).to include(Ronin::DB::Organization) }
29
+ it { expect(subject).to include(Ronin::DB::Password) }
30
+ it { expect(subject).to include(Ronin::DB::Port) }
31
+ it { expect(subject).to include(Ronin::DB::Service) }
32
+ it { expect(subject).to include(Ronin::DB::ServiceCredential) }
33
+ it { expect(subject).to include(Ronin::DB::Software) }
34
+ it { expect(subject).to include(Ronin::DB::URLQueryParamName) }
35
+ it { expect(subject).to include(Ronin::DB::URLQueryParam) }
36
+ it { expect(subject).to include(Ronin::DB::URLScheme) }
37
+ it { expect(subject).to include(Ronin::DB::URL) }
38
+ it { expect(subject).to include(Ronin::DB::UserName) }
39
+ it { expect(subject).to include(Ronin::DB::SoftwareVendor) }
40
+ it { expect(subject).to include(Ronin::DB::WebCredential) }
41
+ it { expect(subject).to include(Ronin::DB::ASN) }
42
+ it { expect(subject).to include(Ronin::DB::HTTPQueryParamName) }
43
+ it { expect(subject).to include(Ronin::DB::HTTPQueryParam) }
44
+ it { expect(subject).to include(Ronin::DB::HTTPHeaderName) }
45
+ it { expect(subject).to include(Ronin::DB::HTTPRequestHeader) }
46
+ it { expect(subject).to include(Ronin::DB::HTTPResponseHeader) }
47
+ it { expect(subject).to include(Ronin::DB::HTTPRequest) }
48
+ it { expect(subject).to include(Ronin::DB::HTTPResponse) }
49
+ end
50
+
51
+ describe ".connect" do
52
+ it "must call #connection on all MODELS" do
53
+ subject::ALL.each do |model|
54
+ expect(model).to receive(:connection)
55
+ end
56
+
57
+ subject.connect
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/open_port'
3
+
4
+ describe Ronin::DB::OpenPort do
5
+ it "must use the 'ronin_open_ports' table" do
6
+ expect(described_class.table_name).to eq('ronin_open_ports')
7
+ end
8
+
9
+ let(:port_number) { 443 }
10
+ let(:port_protocol) { :tcp }
11
+ let(:port) do
12
+ Ronin::DB::Port.new(protocol: port_protocol, number: port_number)
13
+ end
14
+
15
+ let(:address) { '127.0.0.1' }
16
+ let(:ip_address) { Ronin::DB::IPAddress.new(address: address) }
17
+
18
+ describe "validations" do
19
+ describe "ip_address" do
20
+ it "must require an ip_address" do
21
+ open_port = described_class.new(port: port)
22
+ expect(open_port).to_not be_valid
23
+ expect(open_port.errors[:ip_address]).to eq(
24
+ ["must exist"]
25
+ )
26
+
27
+ open_port = described_class.new(ip_address: ip_address, port: port)
28
+ expect(open_port).to be_valid
29
+ end
30
+ end
31
+
32
+ describe "port" do
33
+ it "must require an ip_address" do
34
+ open_port = described_class.new(ip_address: ip_address)
35
+ expect(open_port).to_not be_valid
36
+ expect(open_port.errors[:port]).to eq(
37
+ ["must exist"]
38
+ )
39
+
40
+ open_port = described_class.new(ip_address: ip_address, port: port)
41
+ expect(open_port).to be_valid
42
+ end
43
+ end
44
+ end
45
+
46
+ subject { described_class.new(ip_address: ip_address, port: port) }
47
+
48
+ describe "#address" do
49
+ it "must return the IP address String associated with the open port" do
50
+ expect(subject.address).to eq(address)
51
+ end
52
+ end
53
+
54
+ describe "#number" do
55
+ it "must return the port number associated with the open port" do
56
+ expect(subject.number).to eq(port_number)
57
+ end
58
+ end
59
+
60
+ describe "#to_i" do
61
+ it "must return the port number associated with the open port" do
62
+ expect(subject.to_i).to eq(port_number)
63
+ end
64
+ end
65
+
66
+ describe "#to_s" do
67
+ it "must return the port protocol/number associated with the open port" do
68
+ expect(subject.to_s).to eq("#{port_number}/#{port_protocol}")
69
+ end
70
+
71
+ context "when #service is also set" do
72
+ let(:service_name) { 'Apache' }
73
+ let(:service) { Ronin::DB::Service.new(name: service_name) }
74
+
75
+ subject do
76
+ described_class.new(
77
+ ip_address: ip_address,
78
+ port: port,
79
+ service: service
80
+ )
81
+ end
82
+ it "must return the port number and service name" do
83
+ expect(subject.to_s).to eq("#{port_number}/#{port_protocol} (#{service_name})")
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/organization'
3
+
4
+ describe Ronin::DB::Organization do
5
+ it "must use the 'ronin_organizations' table" do
6
+ expect(described_class.table_name).to eq('ronin_organizations')
7
+ end
8
+
9
+ let(:name) { 'ACEM, Corp.' }
10
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/os_guess'
3
+
4
+ describe Ronin::DB::OSGuess do
5
+ it "must use the 'ronin_os_guesses' table" do
6
+ expect(described_class.table_name).to eq('ronin_os_guesses')
7
+ end
8
+
9
+ let(:address) { '127.0.0.1' }
10
+ let(:ip_address) { Ronin::DB::IPAddress.new(address: address) }
11
+
12
+ let(:os_name) { 'Windows' }
13
+ let(:os_version) { '10' }
14
+ let(:os) { Ronin::DB::OS.new(name: os_name, version: os_version) }
15
+
16
+ describe "validations" do
17
+ describe "ip_address" do
18
+ it "must require an ip_address" do
19
+ os_guess = described_class.new(os: os)
20
+ expect(os_guess).to_not be_valid
21
+ expect(os_guess.errors[:ip_address]).to eq(
22
+ ["must exist"]
23
+ )
24
+
25
+ os_guess = described_class.new(os: os, ip_address: ip_address)
26
+ expect(os_guess).to be_valid
27
+ end
28
+ end
29
+
30
+ describe "os" do
31
+ it "must require an os" do
32
+ os_guess = described_class.new(ip_address: ip_address)
33
+ expect(os_guess).to_not be_valid
34
+ expect(os_guess.errors[:os]).to eq(
35
+ ["must exist"]
36
+ )
37
+
38
+ os_guess = described_class.new(os: os, ip_address: ip_address)
39
+ expect(os_guess).to be_valid
40
+ end
41
+ end
42
+ end
43
+ end
data/spec/os_spec.rb ADDED
@@ -0,0 +1,114 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/os'
3
+
4
+ describe Ronin::DB::OS do
5
+ it "must use the 'ronin_oses' table" do
6
+ expect(described_class.table_name).to eq('ronin_oses')
7
+ end
8
+
9
+ let(:name) { 'Linux' }
10
+ let(:version) { '2.6.11' }
11
+
12
+ subject { described_class.new(name: name, version: version) }
13
+
14
+ describe "validations" do
15
+ describe "name" do
16
+ it "should require a name" do
17
+ os = described_class.new(version: version)
18
+ expect(os).not_to be_valid
19
+
20
+ os = described_class.new(name: name, version: version)
21
+ expect(os).to be_valid
22
+ end
23
+ end
24
+
25
+ describe "version" do
26
+ it "should require a version" do
27
+ os = described_class.new(name: name)
28
+ expect(os).not_to be_valid
29
+
30
+ os = described_class.new(name: name, version: version)
31
+ expect(os).to be_valid
32
+ end
33
+ end
34
+ end
35
+
36
+ describe ".linux" do
37
+ let(:name) { 'Linux' }
38
+
39
+ it "must find or create a new Linux OS" do
40
+ os = described_class.linux(version)
41
+
42
+ expect(os.name).to eq(name)
43
+ expect(os.flavor).to eq('linux')
44
+ expect(os.version).to eq(version)
45
+ end
46
+ end
47
+
48
+ describe ".freebsd" do
49
+ let(:name) { 'FreeBSD' }
50
+
51
+ it "must find or create a new FreeBSD OS" do
52
+ os = described_class.freebsd(version)
53
+
54
+ expect(os.name).to eq(name)
55
+ expect(os.flavor).to eq('bsd')
56
+ expect(os.version).to eq(version)
57
+ end
58
+ end
59
+
60
+ describe ".openbsd" do
61
+ let(:name) { 'OpenBSD' }
62
+
63
+ it "must find or create a new OpenBSD OS" do
64
+ os = described_class.openbsd(version)
65
+
66
+ expect(os.name).to eq(name)
67
+ expect(os.flavor).to eq('bsd')
68
+ expect(os.version).to eq(version)
69
+ end
70
+ end
71
+
72
+ describe ".netbsd" do
73
+ let(:name) { 'NetBSD' }
74
+
75
+ it "must find or create a new NetBSD OS" do
76
+ os = described_class.netbsd(version)
77
+
78
+ expect(os.name).to eq(name)
79
+ expect(os.flavor).to eq('bsd')
80
+ expect(os.version).to eq(version)
81
+ end
82
+ end
83
+
84
+ describe ".macos" do
85
+ let(:name) { 'macOS' }
86
+
87
+ it "must find or create a new macOS OS" do
88
+ os = described_class.macos(version)
89
+
90
+ expect(os.name).to eq(name)
91
+ expect(os.flavor).to eq('bsd')
92
+ expect(os.version).to eq(version)
93
+ end
94
+ end
95
+
96
+ describe ".windows" do
97
+ let(:name) { 'Windows' }
98
+
99
+ it "must find or create a new Windows OS" do
100
+ os = described_class.windows(version)
101
+
102
+ expect(os.version).to eq(version)
103
+ end
104
+ end
105
+
106
+ describe "#recent_ip_address" do
107
+ end
108
+
109
+ describe "#to_s" do
110
+ it "must return the OS name and version" do
111
+ expect(subject.to_s).to eq("#{name} #{version}")
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/password'
3
+
4
+ describe Ronin::DB::Password do
5
+ it "must use the 'ronin_passwords' table" do
6
+ expect(described_class.table_name).to eq('ronin_passwords')
7
+ end
8
+
9
+ let(:plain_text) { 'secret' }
10
+
11
+ subject { described_class.new(plain_text: plain_text) }
12
+
13
+ describe "validations" do
14
+ it "should require a clear-text password" do
15
+ pass = described_class.new
16
+ expect(pass).not_to be_valid
17
+
18
+ pass.plain_text = plain_text
19
+ expect(pass).to be_valid
20
+ end
21
+ end
22
+
23
+ describe ".lookup" do
24
+ before do
25
+ described_class.create(plain_text: 'other_password1')
26
+ described_class.create(plain_text: plain_text)
27
+ described_class.create(plain_text: 'other_pasword2')
28
+ end
29
+
30
+ it "must query the #{described_class} with the matching plain text password" do
31
+ password = described_class.lookup(plain_text)
32
+
33
+ expect(password).to be_kind_of(described_class)
34
+ expect(password.plain_text).to eq(plain_text)
35
+ end
36
+
37
+ after { described_class.destroy_all }
38
+ end
39
+
40
+ describe ".import" do
41
+ subject { described_class.import(plain_text) }
42
+
43
+ it "must import the given password" do
44
+ expect(subject.id).to_not be(nil)
45
+ expect(subject.plain_text).to eq(plain_text)
46
+ end
47
+
48
+ after { described_class.destroy_all }
49
+ end
50
+
51
+ describe "#digest" do
52
+ let(:salt) { 'foo' }
53
+
54
+ it "should calculate the digest of the password" do
55
+ digest = subject.digest(:sha1)
56
+
57
+ expect(digest).to eq(Digest::SHA1.hexdigest(plain_text))
58
+ end
59
+
60
+ it "should calculate the digest of the password and prepended salt" do
61
+ digest = subject.digest(:sha1, prepend_salt: salt)
62
+
63
+ expect(digest).to eq(Digest::SHA1.hexdigest(salt + plain_text))
64
+ end
65
+
66
+ it "should calculate the digest of the password and appended salt" do
67
+ digest = subject.digest(:sha1, append_salt: salt)
68
+
69
+ expect(digest).to eq(Digest::SHA1.hexdigest(plain_text + salt))
70
+ end
71
+ end
72
+
73
+ describe "#count" do
74
+ end
75
+
76
+ describe "#to_s" do
77
+ it "should return the plain text password" do
78
+ expect(subject.to_s).to eq(plain_text)
79
+ end
80
+ end
81
+ end
data/spec/port_spec.rb ADDED
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/port'
3
+
4
+ describe Ronin::DB::Port do
5
+ it "must use the 'ronin_ports' table" do
6
+ expect(described_class.table_name).to eq('ronin_ports')
7
+ end
8
+
9
+ let(:protocol) { 'tcp' }
10
+ let(:number) { 80 }
11
+
12
+ subject do
13
+ described_class.new(protocol: protocol, number: number)
14
+ end
15
+
16
+ describe "validations" do
17
+ context "when not given a port number" do
18
+ subject { described_class.new(protocol: protocol) }
19
+
20
+ it "must require a port number" do
21
+ expect(subject).not_to be_valid
22
+ end
23
+ end
24
+
25
+ context "when given an unknown protocol" do
26
+ let(:protocol) { 'foo' }
27
+
28
+ it "must only allow 'tcp' and 'udp' as protocols" do
29
+ expect {
30
+ described_class.new(protocol: protocol, number: number)
31
+ }.to raise_error(ArgumentError,"'#{protocol}' is not a valid protocol")
32
+ end
33
+ end
34
+
35
+ context "when a duplicate protocol/port-number pairs is saved" do
36
+ before { subject.save }
37
+
38
+ it "must only allow saving unique protocol/port-number pairs" do
39
+ port = described_class.new(protocol: protocol, number: number)
40
+
41
+ expect(port).not_to be_valid
42
+ end
43
+
44
+ after { subject.destroy }
45
+ end
46
+ end
47
+
48
+ describe ".lookup" do
49
+ before do
50
+ described_class.create(number: 1111)
51
+ described_class.create(number: number)
52
+ described_class.create(number: 2222)
53
+ end
54
+
55
+ it "must query the #{described_class} with the matching port number" do
56
+ port = described_class.lookup(number)
57
+
58
+ expect(port).to be_kind_of(described_class)
59
+ expect(port.number).to eq(number)
60
+ end
61
+
62
+ after { described_class.destroy_all }
63
+ end
64
+
65
+ describe ".import" do
66
+ context "when given an Integer" do
67
+ subject { described_class.import(number) }
68
+
69
+ it "must import the port number and set #number" do
70
+ expect(subject).to be_kind_of(described_class)
71
+ expect(subject.id).to_not be(nil)
72
+ expect(subject.number).to eq(number)
73
+ end
74
+ end
75
+
76
+ context "when given a String" do
77
+ let(:string) { number.to_s }
78
+
79
+ subject { described_class.import(string) }
80
+
81
+ it "must parse and import the port number and set #number" do
82
+ expect(subject).to be_kind_of(described_class)
83
+ expect(subject.id).to_not be(nil)
84
+ expect(subject.number).to eq(number)
85
+ end
86
+ end
87
+
88
+ after { described_class.destroy_all }
89
+ end
90
+
91
+ describe "#to_i" do
92
+ it "must be convertable to an Integer" do
93
+ expect(subject.to_i).to eq(number)
94
+ end
95
+ end
96
+
97
+ describe "#to_s" do
98
+ it "must include the number and protocol" do
99
+ expect(subject.to_s).to eq("#{number}/#{protocol}")
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/schema_migration'
3
+
4
+ describe Ronin::DB::SchemaMigration do
5
+ it "must use the 'ronin_schema_migrations' table" do
6
+ expect(described_class.table_name).to eq('ronin_schema_migrations')
7
+ end
8
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/service_credential'
3
+
4
+ describe Ronin::DB::ServiceCredential do
5
+ it "must use the 'ronin_service_credentials' table" do
6
+ expect(described_class.table_name).to eq('ronin_service_credentials')
7
+ end
8
+
9
+ let(:user) { 'admin' }
10
+ let(:user_name) { Ronin::DB::UserName.new(name: user) }
11
+ let(:password) { Ronin::DB::Password.new(plain_text: 'secret') }
12
+ let(:credential) do
13
+ Ronin::DB::Credential.new(
14
+ user_name: user_name,
15
+ password: password
16
+ )
17
+ end
18
+
19
+ let(:port_number) { 22 }
20
+ let(:ip_address) { Ronin::DB::IPAddress.new(address: '1.2.3.4') }
21
+ let(:port) { Ronin::DB::Port.new(number: port_number) }
22
+ let(:open_port) do
23
+ Ronin::DB::OpenPort.new(
24
+ port: port,
25
+ ip_address: ip_address
26
+ )
27
+ end
28
+
29
+ subject do
30
+ described_class.new(
31
+ credential: credential,
32
+ open_port: open_port
33
+ )
34
+ end
35
+
36
+ describe "#to_s" do
37
+ it "must return the username:password and ip:port values in the String" do
38
+ expect(subject.to_s).to eq(
39
+ "#{user_name}:#{password} (#{open_port})"
40
+ )
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/service'
3
+
4
+ describe Ronin::DB::Service do
5
+ it "must use the 'ronin_services' table" do
6
+ expect(described_class.table_name).to eq('ronin_services')
7
+ end
8
+
9
+ let(:name) { 'Apache' }
10
+
11
+ describe "validations" do
12
+ describe "name" do
13
+ it "must require a name" do
14
+ service = described_class.new
15
+ expect(service).to_not be_valid
16
+ expect(service.errors[:name]).to eq(
17
+ ["can't be blank"]
18
+ )
19
+
20
+ service = described_class.new(name: name)
21
+ expect(service).to be_valid
22
+ end
23
+
24
+ it "must require a unique name" do
25
+ described_class.create(name: name)
26
+
27
+ service = described_class.new(name: name)
28
+ expect(service).not_to be_valid
29
+ expect(service.errors[:name]).to eq(
30
+ ["has already been taken"]
31
+ )
32
+
33
+ described_class.destroy_all
34
+ end
35
+ end
36
+ end
37
+
38
+ subject { described_class.new(name: name) }
39
+ end