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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.github/workflows/ruby.yml +31 -0
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/COPYING.txt +165 -0
- data/ChangeLog.md +39 -0
- data/Gemfile +27 -0
- data/README.md +143 -0
- data/Rakefile +72 -0
- data/db/migrate/0001_create_ronin_ip_address_mac_addresses_table.rb +43 -0
- data/db/migrate/0002_create_ronin_vulnerabilities_table.rb +61 -0
- data/db/migrate/0003_create_ronin_url_schemes_table.rb +32 -0
- data/db/migrate/0004_create_ronin_url_query_param_names_table.rb +32 -0
- data/db/migrate/0005_create_ronin_user_names_table.rb +33 -0
- data/db/migrate/0006_create_ronin_software_vendors_table.rb +32 -0
- data/db/migrate/0007_create_ronin_advisories_table.rb +42 -0
- data/db/migrate/0008_create_ronin_host_name_ip_addresses_table.rb +43 -0
- data/db/migrate/0009_create_ronin_host_names_table.rb +34 -0
- data/db/migrate/0010_create_ronin_arches_table.rb +37 -0
- data/db/migrate/0011_create_ronin_email_addresses_table.rb +44 -0
- data/db/migrate/0012_create_ronin_oses_table.rb +36 -0
- data/db/migrate/0013_create_ronin_organizations_table.rb +31 -0
- data/db/migrate/0014_create_ronin_ip_addresses_table.rb +35 -0
- data/db/migrate/0015_create_ronin_os_guesses_table.rb +40 -0
- data/db/migrate/0016_create_ronin_url_query_params_table.rb +42 -0
- data/db/migrate/0017_create_ronin_passwords_table.rb +32 -0
- data/db/migrate/0018_create_ronin_open_ports_table.rb +46 -0
- data/db/migrate/0019_create_ronin_urls_table.rb +50 -0
- data/db/migrate/0020_create_ronin_softwares_table.rb +39 -0
- data/db/migrate/0021_create_ronin_mac_addresses_table.rb +33 -0
- data/db/migrate/0022_create_ronin_countries_table.rb +34 -0
- data/db/migrate/0023_create_ronin_services_table.rb +32 -0
- data/db/migrate/0024_create_ronin_credentials_table.rb +44 -0
- data/db/migrate/0025_create_ronin_ports_table.rb +33 -0
- data/db/migrate/0026_create_ronin_asns_table.rb +44 -0
- data/db/migrate/0027_create_ronin_http_query_param_names_table.rb +32 -0
- data/db/migrate/0028_create_ronin_http_query_params_table.rb +42 -0
- data/db/migrate/0029_create_ronin_http_header_names_table.rb +31 -0
- data/db/migrate/0030_create_ronin_http_request_headers_table.rb +41 -0
- data/db/migrate/0031_create_ronin_http_response_headers_table.rb +41 -0
- data/db/migrate/0032_create_ronin_http_requests_table.rb +41 -0
- data/db/migrate/0033_create_ronin_http_responses_table.rb +36 -0
- data/db/migrate/0034_create_ronin_service_credentials_table.rb +41 -0
- data/db/migrate/0035_create_ronin_web_credentials_table.rb +41 -0
- data/gemspec.yml +28 -0
- data/lib/ronin/db/address.rb +105 -0
- data/lib/ronin/db/advisory.rb +169 -0
- data/lib/ronin/db/arch.rb +160 -0
- data/lib/ronin/db/asn.rb +212 -0
- data/lib/ronin/db/credential.rb +248 -0
- data/lib/ronin/db/email_address.rb +225 -0
- data/lib/ronin/db/host_name.rb +224 -0
- data/lib/ronin/db/host_name_ip_address.rb +65 -0
- data/lib/ronin/db/http_header_name.rb +75 -0
- data/lib/ronin/db/http_query_param.rb +79 -0
- data/lib/ronin/db/http_query_param_name.rb +76 -0
- data/lib/ronin/db/http_request.rb +120 -0
- data/lib/ronin/db/http_request_header.rb +78 -0
- data/lib/ronin/db/http_response.rb +91 -0
- data/lib/ronin/db/http_response_header.rb +78 -0
- data/lib/ronin/db/ip_address.rb +351 -0
- data/lib/ronin/db/ip_address_mac_address.rb +62 -0
- data/lib/ronin/db/mac_address.rb +91 -0
- data/lib/ronin/db/migrations.rb +137 -0
- data/lib/ronin/db/model/has_name.rb +102 -0
- data/lib/ronin/db/model/has_unique_name.rb +82 -0
- data/lib/ronin/db/model/importable.rb +85 -0
- data/lib/ronin/db/model/last_scanned_at.rb +48 -0
- data/lib/ronin/db/model.rb +37 -0
- data/lib/ronin/db/models.rb +108 -0
- data/lib/ronin/db/open_port.rb +148 -0
- data/lib/ronin/db/organization.rb +50 -0
- data/lib/ronin/db/os.rb +183 -0
- data/lib/ronin/db/os_guess.rb +67 -0
- data/lib/ronin/db/password.rb +167 -0
- data/lib/ronin/db/port.rb +123 -0
- data/lib/ronin/db/root.rb +28 -0
- data/lib/ronin/db/schema_migration.rb +34 -0
- data/lib/ronin/db/service.rb +48 -0
- data/lib/ronin/db/service_credential.rb +66 -0
- data/lib/ronin/db/software.rb +85 -0
- data/lib/ronin/db/software_vendor.rb +42 -0
- data/lib/ronin/db/url.rb +497 -0
- data/lib/ronin/db/url_query_param.rb +79 -0
- data/lib/ronin/db/url_query_param_name.rb +76 -0
- data/lib/ronin/db/url_scheme.rb +80 -0
- data/lib/ronin/db/user_name.rb +96 -0
- data/lib/ronin/db/vulnerability.rb +81 -0
- data/lib/ronin/db/web_credential.rb +69 -0
- data/ronin-db-activerecord.gemspec +61 -0
- data/spec/advisory_spec.rb +277 -0
- data/spec/arch_spec.rb +228 -0
- data/spec/asn_spec.rb +504 -0
- data/spec/credential_spec.rb +362 -0
- data/spec/email_address_spec.rb +372 -0
- data/spec/host_name_ip_address_spec.rb +8 -0
- data/spec/host_name_spec.rb +207 -0
- data/spec/http_header_name_spec.rb +25 -0
- data/spec/http_query_param_name_spec.rb +25 -0
- data/spec/http_query_param_spec.rb +104 -0
- data/spec/http_request_header_spec.rb +72 -0
- data/spec/http_request_spec.rb +168 -0
- data/spec/http_response_header_spec.rb +74 -0
- data/spec/http_response_spec.rb +103 -0
- data/spec/ip_address_mac_addresses_spec.rb +8 -0
- data/spec/ip_address_spec.rb +386 -0
- data/spec/mac_address_spec.rb +67 -0
- data/spec/migrations_spec.rb +122 -0
- data/spec/model/has_name_spec.rb +65 -0
- data/spec/model/has_unique_name_spec.rb +61 -0
- data/spec/model/importable_spec.rb +105 -0
- data/spec/models_spec.rb +60 -0
- data/spec/open_port_spec.rb +87 -0
- data/spec/organization_spec.rb +10 -0
- data/spec/os_guess_spec.rb +43 -0
- data/spec/os_spec.rb +114 -0
- data/spec/password_spec.rb +81 -0
- data/spec/port_spec.rb +102 -0
- data/spec/schema_migration_spec.rb +8 -0
- data/spec/service_credential_spec.rb +43 -0
- data/spec/service_spec.rb +39 -0
- data/spec/software_spec.rb +76 -0
- data/spec/software_vendor_spec.rb +33 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/url_query_param_name_spec.rb +25 -0
- data/spec/url_query_param_spec.rb +110 -0
- data/spec/url_scheme_spec.rb +39 -0
- data/spec/url_spec.rb +951 -0
- data/spec/user_name_spec.rb +54 -0
- data/spec/vulnerability_spec.rb +8 -0
- data/spec/web_credential_spec.rb +72 -0
- 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
|
data/spec/models_spec.rb
ADDED
|
@@ -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,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,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
|