sonar-client 0.1.3 → 0.1.4
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 +4 -4
- data/.travis.yml +5 -2
- data/lib/sonar/cli/cli.rb +23 -19
- data/lib/sonar/search.rb +54 -15
- data/lib/sonar/version.rb +1 -1
- data/sonar-client.gemspec +1 -0
- data/spec/sonar/cli_spec.rb +23 -0
- data/spec/sonar/search_spec.rb +21 -11
- metadata +16 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4dc46841e0ddf4f091d927804c15b77b5ad95d33
|
4
|
+
data.tar.gz: 50cfb040770c7b69ef437e09edc48adf1d08fa81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27c4336fe464f3f988df579531b2795318a12b08055b8fa049cd32104a3a7d1de577480fcc3c96c93cb1739d223ff24f28ee7e7599b052393d9e98996424cffb
|
7
|
+
data.tar.gz: 4f237e0a682fdaf8e90a9c8f63c630a4e4da90e0566550f0f1ff5659edcb99fc10be33c50f8a112d7c03ecde8ccb93230cfc93e8e0053c04e4cd5438ddeb2ca5
|
data/.travis.yml
CHANGED
@@ -2,14 +2,17 @@ language: ruby
|
|
2
2
|
sudo: false
|
3
3
|
cache: bundler
|
4
4
|
rvm:
|
5
|
-
- 2.
|
6
|
-
- jruby
|
5
|
+
- 2.2.2
|
6
|
+
- jruby-9.1.5.0
|
7
7
|
before_install:
|
8
8
|
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
9
9
|
- rake --version
|
10
10
|
before_script:
|
11
11
|
- bundle exec rake --version
|
12
12
|
script: bundle exec rspec
|
13
|
+
notifications:
|
14
|
+
email:
|
15
|
+
- r7_labs@rapid7.com
|
13
16
|
#
|
14
17
|
# Environment variables should be set in Travis repository settings per
|
15
18
|
# https://docs.travis-ci.com/user/environment-variables/#Defining-Variables-in-Repository-Settings
|
data/lib/sonar/cli/cli.rb
CHANGED
@@ -2,11 +2,15 @@
|
|
2
2
|
|
3
3
|
require 'thor'
|
4
4
|
require 'sonar/cli/rcfile'
|
5
|
+
require 'sonar/search'
|
5
6
|
require 'awesome_print'
|
7
|
+
require 'table_print'
|
8
|
+
|
9
|
+
include Sonar::Search
|
6
10
|
|
7
11
|
module Sonar
|
8
12
|
class CLI < Thor
|
9
|
-
class_option 'format', type: :string, desc: 'Flat JSON, JSON lines, or pretty printed [flat/lines/pretty]'
|
13
|
+
class_option 'format', type: :string, desc: 'Flat JSON (include empty collections), JSON lines of collection data (default), or pretty printed [flat/lines/pretty]'
|
10
14
|
|
11
15
|
def initialize(*)
|
12
16
|
@config = Sonar::RCFile.instance.load_file
|
@@ -24,34 +28,34 @@ module Sonar
|
|
24
28
|
ap @client.usage
|
25
29
|
end
|
26
30
|
|
27
|
-
desc 'search [QUERY TYPE] [QUERY TERM]', 'Search
|
31
|
+
desc 'search [QUERY TYPE] [QUERY TERM]', 'Search any query type from Sonar or specify \'all\' as QUERY TYPE to search them all.'
|
28
32
|
method_option 'record_limit', type: :numeric, aliases: '-n', desc: 'Maximum number of records to fetch'
|
29
33
|
method_option 'exact', type: :boolean, aliases: '-e', desc: 'Search for the query string exactly, do not include partial string matches'
|
30
|
-
|
31
34
|
def search(type, term)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
if resp.is_a?(Sonar::Request::RequestIterator)
|
40
|
-
resp.each do |data|
|
41
|
-
errors += 1 if data.key?('errors') || data.key?('error')
|
42
|
-
print_json(cleanup_data(data), options['format'])
|
35
|
+
types = [type]
|
36
|
+
|
37
|
+
if type == 'all'
|
38
|
+
if term =~ IS_IP
|
39
|
+
types = ip_search_type_names
|
40
|
+
else
|
41
|
+
types = domain_search_type_names
|
43
42
|
end
|
44
|
-
else
|
45
|
-
errors += 1 if resp.key?('errors') || resp.key?('error')
|
46
|
-
print_json(cleanup_data(resp), options['format'])
|
47
43
|
end
|
48
44
|
|
49
|
-
|
45
|
+
types.each do |type|
|
46
|
+
@query = {}
|
47
|
+
@query[type.to_sym] = term
|
48
|
+
@query[:limit] = options['record_limit']
|
49
|
+
@query[:exact] = options['exact']
|
50
|
+
resp = @client.search(@query)
|
51
|
+
handle_search_response(resp)
|
52
|
+
end
|
50
53
|
end
|
51
54
|
|
52
55
|
desc 'types', 'List all Sonar query types'
|
53
56
|
def types
|
54
|
-
|
57
|
+
tp.set :io, $stdout
|
58
|
+
tp QUERY_TYPES, :name, { description: { width: 100 } }, :input
|
55
59
|
end
|
56
60
|
|
57
61
|
desc 'config', 'Sonar config file location'
|
data/lib/sonar/search.rb
CHANGED
@@ -2,21 +2,25 @@
|
|
2
2
|
|
3
3
|
module Sonar
|
4
4
|
module Search
|
5
|
+
|
6
|
+
# Allow IP queries to be in the form of "1.", "1.2.", "1.2.3.", and "1.2.3.4"
|
7
|
+
IS_IP = /^(\d{1,3}\.|\d{1,3}\.\d{1,3}\.|\d{1,3}\.\d{1,3}\.\d{1,3}\.|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/
|
8
|
+
|
5
9
|
# Implemented search query types
|
6
|
-
|
7
|
-
'certificate'
|
8
|
-
'certips'
|
9
|
-
'rdns'
|
10
|
-
'fdns'
|
11
|
-
'ipcerts'
|
12
|
-
'namecerts'
|
13
|
-
'links_to'
|
14
|
-
'ports'
|
15
|
-
'processed'
|
16
|
-
'raw'
|
17
|
-
'sslcert'
|
18
|
-
'
|
19
|
-
|
10
|
+
QUERY_TYPES = [
|
11
|
+
{ name: 'certificate', description: 'Certificate lookup', input: 'sha' },
|
12
|
+
{ name: 'certips', description: 'Certificate to IPs', input: 'sha' },
|
13
|
+
{ name: 'rdns', description: 'IP to Reverse DNS Lookup or DNS Lookup to IP', input: 'ip' },
|
14
|
+
{ name: 'fdns', description: 'Domains to IP or IPs to Domain', input: 'domain' },
|
15
|
+
{ name: 'ipcerts', description: 'IP to Certificates', input: 'ip' },
|
16
|
+
{ name: 'namecerts', description: 'Domain to Certificates', input: 'domain' },
|
17
|
+
{ name: 'links_to', description: 'HTTP References to Domain', input: 'domain' },
|
18
|
+
{ name: 'ports', description: 'Open Ports', input: 'ip' },
|
19
|
+
{ name: 'processed', description: 'Open Ports (Processed)', input: 'ip' },
|
20
|
+
{ name: 'raw', description: 'Open Ports (Raw)', input: 'ip' },
|
21
|
+
{ name: 'sslcert', description: 'Certificate Details', input: 'sha' },
|
22
|
+
{ name: 'all', description: 'Search all appropriate search types for an IP or domain', input: 'all' }
|
23
|
+
]
|
20
24
|
|
21
25
|
##
|
22
26
|
# Generic exception for errors encountered while searching
|
@@ -24,6 +28,41 @@ module Sonar
|
|
24
28
|
class SearchError < StandardError
|
25
29
|
end
|
26
30
|
|
31
|
+
def ip_search_type_names
|
32
|
+
ip_search_types.map { |type| type[:name] }
|
33
|
+
end
|
34
|
+
|
35
|
+
def domain_search_type_names
|
36
|
+
domain_search_types.map { |type| type[:name] }
|
37
|
+
end
|
38
|
+
|
39
|
+
def ip_search_types
|
40
|
+
QUERY_TYPES.select { |type| type[:input] == 'ip' }
|
41
|
+
end
|
42
|
+
|
43
|
+
def domain_search_types
|
44
|
+
QUERY_TYPES.select { |type| type[:input] == 'domain' }
|
45
|
+
end
|
46
|
+
|
47
|
+
def query_type_names
|
48
|
+
QUERY_TYPES.map { |type| type[:name] }
|
49
|
+
end
|
50
|
+
|
51
|
+
def handle_search_response(resp)
|
52
|
+
errors = 0
|
53
|
+
if resp.is_a?(Sonar::Request::RequestIterator)
|
54
|
+
resp.each do |data|
|
55
|
+
errors += 1 if data.key?('errors') || data.key?('error')
|
56
|
+
print_json(cleanup_data(data), options['format'])
|
57
|
+
end
|
58
|
+
else
|
59
|
+
errors += 1 if resp.key?('errors') || resp.key?('error')
|
60
|
+
print_json(cleanup_data(resp), options['format'])
|
61
|
+
end
|
62
|
+
|
63
|
+
raise Search::SearchError.new("Encountered #{errors} errors while searching") if errors > 0
|
64
|
+
end
|
65
|
+
|
27
66
|
##
|
28
67
|
# Get search
|
29
68
|
#
|
@@ -32,7 +71,7 @@ module Sonar
|
|
32
71
|
#
|
33
72
|
# @return [Hashie::Mash] with response of search
|
34
73
|
def search(params = {})
|
35
|
-
type_query = params.select { |k, _v|
|
74
|
+
type_query = params.select { |k, _v| query_type_names.include?(k.to_s) }.first
|
36
75
|
fail ArgumentError, "The query type provided is invalid or not yet implemented." unless type_query
|
37
76
|
type = type_query[0].to_sym
|
38
77
|
params[:q] = type_query[1]
|
data/lib/sonar/version.rb
CHANGED
data/sonar-client.gemspec
CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_dependency 'multi_json'
|
24
24
|
spec.add_dependency 'thor'
|
25
25
|
spec.add_dependency 'awesome_print'
|
26
|
+
spec.add_dependency 'table_print'
|
26
27
|
|
27
28
|
spec.add_development_dependency "bundler"
|
28
29
|
spec.add_development_dependency "rake"
|
data/spec/sonar/cli_spec.rb
CHANGED
@@ -82,6 +82,29 @@ describe Sonar::CLI do
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
85
|
+
|
86
|
+
describe 'sonar types command' do
|
87
|
+
it 'returns all sonar search types' do
|
88
|
+
output = run_command('types')
|
89
|
+
expect(output).to match(/Certificate to IPs/)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'search all command' do
|
94
|
+
before do
|
95
|
+
allow_any_instance_of(Sonar::Client).to receive(:search).and_return(
|
96
|
+
Sonar::Client.new.search(fdns: '208.118.227.20', exact: true)
|
97
|
+
)
|
98
|
+
end
|
99
|
+
it 'returns results when searching for an IP' do
|
100
|
+
output = run_command('search all 208.118.227.20')
|
101
|
+
expect(output).to match(/rapid7\.com/)
|
102
|
+
end
|
103
|
+
it 'returns results when searching for a domain' do
|
104
|
+
output = run_command('search all rapid7.com')
|
105
|
+
expect(output).to match(/208\.118\.227\.20/)
|
106
|
+
end
|
107
|
+
end
|
85
108
|
end
|
86
109
|
|
87
110
|
def run_command(args)
|
data/spec/sonar/search_spec.rb
CHANGED
@@ -4,6 +4,24 @@ require 'spec_helper'
|
|
4
4
|
describe Sonar::Search do
|
5
5
|
let(:client) { Sonar::Client.new }
|
6
6
|
|
7
|
+
describe "#ip_search_type_names" do
|
8
|
+
it 'includes rdns' do
|
9
|
+
expect(subject.ip_search_type_names).to include('rdns')
|
10
|
+
end
|
11
|
+
it 'does not include fdns' do
|
12
|
+
expect(subject.ip_search_type_names).to_not include('fdns')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#domain_search_type_names" do
|
17
|
+
it 'includes fdns' do
|
18
|
+
expect(subject.domain_search_type_names).to include('fdns')
|
19
|
+
end
|
20
|
+
it 'does not include rdns' do
|
21
|
+
expect(subject.domain_search_type_names).to_not include('rdns')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
7
25
|
describe "parameters" do
|
8
26
|
describe "query type" do
|
9
27
|
context "with an invalid query type" do
|
@@ -15,12 +33,12 @@ describe Sonar::Search do
|
|
15
33
|
|
16
34
|
describe "exact" do
|
17
35
|
it "shouldn't match anything when #exact is true" do
|
18
|
-
resp = client.search(
|
36
|
+
resp = client.search(fdns: ".rapid7.com", exact: true)
|
19
37
|
expect(resp["collection"].size).to eq(0)
|
20
38
|
end
|
21
39
|
it "should match when #exact is false" do
|
22
|
-
resp = client.search(
|
23
|
-
expect(resp["collection"].
|
40
|
+
resp = client.search(fdns: ".rapid7.com", exact: false)
|
41
|
+
expect(resp["collection"].size).to be > 0
|
24
42
|
end
|
25
43
|
end
|
26
44
|
|
@@ -152,14 +170,6 @@ describe Sonar::Search do
|
|
152
170
|
end
|
153
171
|
end
|
154
172
|
|
155
|
-
context "whois_ip" do
|
156
|
-
let(:resp) { client.search(whois_ip: '208.118.227.10') }
|
157
|
-
|
158
|
-
xit "should find rapid7.com" do
|
159
|
-
expect(resp['name']).to eq('TWDX-208-118-227-0-1')
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
173
|
# TODO: actually check response
|
164
174
|
context "raw" do
|
165
175
|
let(:resp) { client.search(raw: '208.118.227.10') }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sonar-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Deardorff & HD Moore
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday_middleware
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: table_print
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: bundler
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -296,4 +310,3 @@ test_files:
|
|
296
310
|
- spec/sonar/user_spec.rb
|
297
311
|
- spec/sonar_spec.rb
|
298
312
|
- spec/spec_helper.rb
|
299
|
-
has_rdoc:
|