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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 46f4c95ec260a3eb4b212c2f85c4bee5893dc461
4
- data.tar.gz: 4a574ae9f388f0db79f28e80e9dc69b9c97de3eb
3
+ metadata.gz: 4dc46841e0ddf4f091d927804c15b77b5ad95d33
4
+ data.tar.gz: 50cfb040770c7b69ef437e09edc48adf1d08fa81
5
5
  SHA512:
6
- metadata.gz: 8056aa52de648957853d67ad2ebcdb8168e4ee586dc8dfe0bdab2e6ef9d638f6caac2ae142c4eceffd9c598f0e17e402179bfad8a71df5d700b94dbce477b852
7
- data.tar.gz: 66db84c021545e129f001839cb8de8e56b221175bbbb202df443d8f35e92ee5dd344c34dbb5ec034599abededc92f805a9d4cdea2b979d9c28a3a180aca684c0
6
+ metadata.gz: 27c4336fe464f3f988df579531b2795318a12b08055b8fa049cd32104a3a7d1de577480fcc3c96c93cb1739d223ff24f28ee7e7599b052393d9e98996424cffb
7
+ data.tar.gz: 4f237e0a682fdaf8e90a9c8f63c630a4e4da90e0566550f0f1ff5659edcb99fc10be33c50f8a112d7c03ecde8ccb93230cfc93e8e0053c04e4cd5438ddeb2ca5
@@ -2,14 +2,17 @@ language: ruby
2
2
  sudo: false
3
3
  cache: bundler
4
4
  rvm:
5
- - 2.1.5
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
@@ -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 anything from Sonars'
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
- @query = {}
33
- @query[type.to_sym] = term
34
- @query[:limit] = options['record_limit']
35
- @query[:exact] = options['exact']
36
- resp = @client.search(@query)
37
-
38
- errors = 0
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
- raise Search::SearchError.new("Encountered #{errors} errors while searching") if errors > 0
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
- ap Search::QUERY_TYPES_MAP
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'
@@ -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
- QUERY_TYPES_MAP = {
7
- 'certificate' => 'Certificate lookup',
8
- 'certips' => 'Certificate to IPs',
9
- 'rdns' => 'IP to Reverse DNS Lookup or DNS Lookup to IP',
10
- 'fdns' => 'Domains to IP or IPs to Domain',
11
- 'ipcerts' => 'IP to Certificates',
12
- 'namecerts' => 'Domain to Certificates',
13
- 'links_to' => 'HTTP References to Domain',
14
- 'ports' => 'Open Ports',
15
- 'processed' => 'Open Ports (Processed)',
16
- 'raw' => 'Open Ports (Raw)',
17
- 'sslcert' => 'Certificate Details',
18
- 'whois_ip' => 'Whois (IP)'
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| QUERY_TYPES_MAP.keys.include?(k.to_s) }.first
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]
@@ -1,3 +1,3 @@
1
1
  module Sonar
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
@@ -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"
@@ -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)
@@ -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(rdns: "1.1.", exact: true)
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(rdns: "1.1.", exact: false)
23
- expect(resp["collection"].first["address"]).to match(/^1.1./)
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.3
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: 2016-04-22 00:00:00.000000000 Z
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: