sonar-client 0.0.1
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/.gitignore +35 -0
- data/.rspec +2 -0
- data/.rubocop.yml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +94 -0
- data/LICENSE +21 -0
- data/README.md +81 -0
- data/Rakefile +7 -0
- data/bin/sonar +11 -0
- data/lib/sonar/certificate.rb +15 -0
- data/lib/sonar/cli/cli.rb +46 -0
- data/lib/sonar/cli/rcfile.rb +31 -0
- data/lib/sonar/client.rb +83 -0
- data/lib/sonar/request.rb +64 -0
- data/lib/sonar/search.rb +37 -0
- data/lib/sonar/user.rb +9 -0
- data/lib/sonar/version.rb +3 -0
- data/lib/sonar.rb +28 -0
- data/sonar-client.gemspec +37 -0
- data/spec/fixtures/sonar.rc +3 -0
- data/spec/sonar/certificate_spec.rb +13 -0
- data/spec/sonar/cli_spec.rb +21 -0
- data/spec/sonar/client_spec.rb +10 -0
- data/spec/sonar/search_spec.rb +189 -0
- data/spec/sonar/user_spec.rb +15 -0
- data/spec/sonar_spec.rb +67 -0
- data/spec/spec_helper.rb +60 -0
- metadata +292 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9e04adb9fca3c12bc9ae907eaa64df648c568ca6
|
4
|
+
data.tar.gz: f363d98148215460920438b61f5c0f025224bbdb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d80394c4745caba23f50df647c3b83ecfa0dccbbc76afe1986021f7f904e14bdf1d4a3c11b86ecee306e9ddc6247ff5b70aa3d48fad4213aea3aacaf5646c44a
|
7
|
+
data.tar.gz: 40263868a73f583575e963a2573a82a39b8e3c00ce0f37ba37d5f4c7ddda6c0d67fb17c98ecdb6dda8bc68fcdf71c10915fbcfd56945545496a9a71b1ab5ed58
|
data/.gitignore
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
coverage
|
6
|
+
lib/bundler/man
|
7
|
+
pkg
|
8
|
+
rdoc
|
9
|
+
spec/reports
|
10
|
+
spec/cassette
|
11
|
+
test/tmp
|
12
|
+
test/version_tmp
|
13
|
+
tmp
|
14
|
+
|
15
|
+
# OSX
|
16
|
+
.DS_Store
|
17
|
+
|
18
|
+
# YARD artifacts
|
19
|
+
.yardoc
|
20
|
+
_yardoc
|
21
|
+
doc/
|
22
|
+
|
23
|
+
# Specific to RubyMotion
|
24
|
+
.dat*
|
25
|
+
.repl_history
|
26
|
+
build/
|
27
|
+
|
28
|
+
# for a library or gem, you might want to ignore these files since the code is
|
29
|
+
# intended to run in multiple environments; otherwise, check them in:
|
30
|
+
# Gemfile.lock
|
31
|
+
.ruby-version
|
32
|
+
.ruby-gemset
|
33
|
+
|
34
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
35
|
+
.rvmrc
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sonar-client (0.0.1)
|
5
|
+
awesome_print
|
6
|
+
faraday_middleware (~> 0.9.0)
|
7
|
+
hashie (~> 2.0.3)
|
8
|
+
multi_json
|
9
|
+
thor
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
activesupport (4.2.0)
|
15
|
+
i18n (~> 0.7)
|
16
|
+
json (~> 1.7, >= 1.7.7)
|
17
|
+
minitest (~> 5.1)
|
18
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
19
|
+
tzinfo (~> 1.1)
|
20
|
+
addressable (2.3.6)
|
21
|
+
api_matchers (0.5.1)
|
22
|
+
activesupport (>= 3.2.5)
|
23
|
+
nokogiri (>= 1.5.2)
|
24
|
+
rspec (>= 2.14)
|
25
|
+
awesome_print (1.6.1)
|
26
|
+
crack (0.4.2)
|
27
|
+
safe_yaml (~> 1.0.0)
|
28
|
+
diff-lcs (1.2.5)
|
29
|
+
docile (1.1.5)
|
30
|
+
faraday (0.9.1)
|
31
|
+
multipart-post (>= 1.2, < 3)
|
32
|
+
faraday_middleware (0.9.1)
|
33
|
+
faraday (>= 0.7.4, < 0.10)
|
34
|
+
hashie (2.0.5)
|
35
|
+
i18n (0.7.0)
|
36
|
+
json (1.8.2)
|
37
|
+
mini_portile (0.6.2)
|
38
|
+
minitest (5.5.1)
|
39
|
+
multi_json (1.10.1)
|
40
|
+
multipart-post (2.0.0)
|
41
|
+
nokogiri (1.6.5)
|
42
|
+
mini_portile (~> 0.6.0)
|
43
|
+
rake (10.4.2)
|
44
|
+
rspec (3.1.0)
|
45
|
+
rspec-core (~> 3.1.0)
|
46
|
+
rspec-expectations (~> 3.1.0)
|
47
|
+
rspec-mocks (~> 3.1.0)
|
48
|
+
rspec-core (3.1.7)
|
49
|
+
rspec-support (~> 3.1.0)
|
50
|
+
rspec-expectations (3.1.2)
|
51
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
52
|
+
rspec-support (~> 3.1.0)
|
53
|
+
rspec-mocks (3.1.3)
|
54
|
+
rspec-support (~> 3.1.0)
|
55
|
+
rspec-support (3.1.2)
|
56
|
+
safe_yaml (1.0.4)
|
57
|
+
shoulda (3.5.0)
|
58
|
+
shoulda-context (~> 1.0, >= 1.0.1)
|
59
|
+
shoulda-matchers (>= 1.4.1, < 3.0)
|
60
|
+
shoulda-context (1.2.1)
|
61
|
+
shoulda-matchers (2.7.0)
|
62
|
+
activesupport (>= 3.0.0)
|
63
|
+
simplecov (0.9.1)
|
64
|
+
docile (~> 1.1.0)
|
65
|
+
multi_json (~> 1.0)
|
66
|
+
simplecov-html (~> 0.8.0)
|
67
|
+
simplecov-html (0.8.0)
|
68
|
+
simplecov-rcov (0.2.3)
|
69
|
+
simplecov (>= 0.4.1)
|
70
|
+
thor (0.19.1)
|
71
|
+
thread_safe (0.3.4)
|
72
|
+
tzinfo (1.2.2)
|
73
|
+
thread_safe (~> 0.1)
|
74
|
+
vcr (2.8.0)
|
75
|
+
webmock (1.8.11)
|
76
|
+
addressable (>= 2.2.7)
|
77
|
+
crack (>= 0.1.7)
|
78
|
+
yard (0.8.7.6)
|
79
|
+
|
80
|
+
PLATFORMS
|
81
|
+
ruby
|
82
|
+
|
83
|
+
DEPENDENCIES
|
84
|
+
api_matchers
|
85
|
+
bundler
|
86
|
+
rake
|
87
|
+
rspec
|
88
|
+
shoulda
|
89
|
+
simplecov
|
90
|
+
simplecov-rcov
|
91
|
+
sonar-client!
|
92
|
+
vcr (~> 2.8.0)
|
93
|
+
webmock (~> 1.8.0)
|
94
|
+
yard
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Rapid7, Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
sonar-client
|
2
|
+
===============
|
3
|
+
|
4
|
+
Ruby API Wrapper and CLI for [Sonar](https://sonar.labs.rapid7.com)
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Install the gem by running
|
9
|
+
|
10
|
+
gem install sonar-client
|
11
|
+
|
12
|
+
or add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'sonar-client'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle install
|
19
|
+
|
20
|
+
## Gem usage
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
require 'sonar'
|
24
|
+
|
25
|
+
# If you're using Rails 3+, create an initializer
|
26
|
+
# config/initializers/sonar.rb
|
27
|
+
Sonar.configure do |config|
|
28
|
+
config.api_url = 'https://sonar.labs.rapid7.com'
|
29
|
+
config.api_version = 'v2'
|
30
|
+
config.email = 'email@example.com'
|
31
|
+
config.access_token = 'YOURTOKEN'
|
32
|
+
end
|
33
|
+
|
34
|
+
# If you're using straight ruby (no Rails),
|
35
|
+
# create a Sonar::Client Object
|
36
|
+
options = {
|
37
|
+
api_url: 'https://sonar.labs.rapid7.com',
|
38
|
+
api_version: 'v2',
|
39
|
+
access_token: 'YOURTOKEN',
|
40
|
+
email: 'email@example.com'
|
41
|
+
}
|
42
|
+
client = Sonar::Client.new(options)
|
43
|
+
|
44
|
+
# Create a Client Object expecting you have an initializer in place
|
45
|
+
# Sonar::Client Object
|
46
|
+
client = Sonar::Client.new
|
47
|
+
|
48
|
+
# Get fdns
|
49
|
+
client.search(fdns: 'rapid7.com')
|
50
|
+
# => responds with a Hashie object
|
51
|
+
```
|
52
|
+
|
53
|
+
## CLI dev setup
|
54
|
+
|
55
|
+
From the project root directory
|
56
|
+
```
|
57
|
+
$ rake install
|
58
|
+
sonar-client 0.0.1 built to pkg/sonar-client-0.0.1.gem.
|
59
|
+
sonar-client (0.0.1) installed.
|
60
|
+
$ sonar
|
61
|
+
```
|
62
|
+
|
63
|
+
On the first run, sonar will setup a sonar.rc config file in your user folder. Run `sonar config` to view the full path to your config file. Here's what your file will look like when it's first created:
|
64
|
+
```
|
65
|
+
email: YOUR_EMAIL
|
66
|
+
access_token: SONAR_TOKEN
|
67
|
+
api_url: https://sonar.labs.rapid7.com
|
68
|
+
```
|
69
|
+
Replace YOUR_EMAIL with the email you used to register on the [Sonar website](https://sonar.labs.rapid7.com). Replace SONAR_TOKEN with your API token found on the [Settings page](https://sonar.labs.rapid7.com/users/edit) of the Sonar website. Enclosing quotes around these two credentials are not needed.
|
70
|
+
|
71
|
+
## CLI usage
|
72
|
+
|
73
|
+
Typing `sonar help` will list all the available commands. You can type `sonar help TASK` to get help for a specific command. If running locally from the root project directory, you may need to prefix `sonar` commands with `bundle exec`. A rdns search command might look like `bundle exec sonar search rdns .rapid7.com`.
|
74
|
+
|
75
|
+
## Contributing
|
76
|
+
|
77
|
+
1. Fork it
|
78
|
+
2. Create your feature branch (`git checkout -b feature/my-new-feature`)
|
79
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
80
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
81
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/sonar
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Sonar
|
4
|
+
module Certificate
|
5
|
+
##
|
6
|
+
# Get certificate based on sha1 id
|
7
|
+
# /api/v2/certificates/1e80c24b97c928bb1db7d4d3c05475a6a40a1186
|
8
|
+
#
|
9
|
+
# @return [Hashie::Mash] with response of certificate
|
10
|
+
def get_certificate(options = {})
|
11
|
+
response = get("/api/#{Sonar.api_version}/certificates/#{options[:sha1]}", options)
|
12
|
+
response if response
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
require 'sonar/cli/rcfile'
|
5
|
+
require 'awesome_print'
|
6
|
+
|
7
|
+
module Sonar
|
8
|
+
class CLI < Thor
|
9
|
+
class_option 'profile', aliases: '-P', type: :string, default: File.join(File.expand_path('~'), Sonar::RCFile::FILENAME),
|
10
|
+
desc: 'Path to Sonar RC file', banner: 'FILE'
|
11
|
+
|
12
|
+
def initialize(*)
|
13
|
+
@rcfile = Sonar::RCFile.instance.load_file
|
14
|
+
@client = Sonar::Client.new(email: @rcfile["email"], access_token: @rcfile["access_token"], api_url: @rcfile["api_url"])
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'profile', 'Display the current profile from sonar.rc'
|
19
|
+
def profile
|
20
|
+
ap @rcfile
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'usage', 'Display API usage for current user.'
|
24
|
+
def usage
|
25
|
+
ap @client.usage
|
26
|
+
end
|
27
|
+
|
28
|
+
desc 'search [QUERY TYPE] [QUERY TERM]', 'Search anything from Sonar.'
|
29
|
+
def search(type, term)
|
30
|
+
@query = {}
|
31
|
+
@query[type.to_sym] = term
|
32
|
+
ap @client.search(@query)
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'types', 'List all Sonar query types.'
|
36
|
+
def types
|
37
|
+
ap Search::QUERY_TYPES_MAP
|
38
|
+
end
|
39
|
+
|
40
|
+
desc 'config', 'Update Sonar config file'
|
41
|
+
def config
|
42
|
+
# TODO: add a way to set config
|
43
|
+
puts "Your config file is located at #{RCFile.instance.path}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'singleton'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Sonar
|
6
|
+
class RCFile
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
attr_accessor :path
|
10
|
+
FILENAME = 'sonar.rc'
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@path = File.join(File.expand_path('~'), FILENAME)
|
14
|
+
@data = load_file
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_file
|
18
|
+
File.open(@path, 'w') do |f|
|
19
|
+
f.puts 'email: YOUR_EMAIL'
|
20
|
+
f.puts 'access_token: SONAR_TOKEN'
|
21
|
+
f.puts 'api_url: https://sonar.labs.rapid7.com'
|
22
|
+
end
|
23
|
+
puts "Config file setup at: #{@path}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def load_file
|
27
|
+
create_file unless File.exist?(@path)
|
28
|
+
YAML.load_file(@path)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/sonar/client.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'forwardable'
|
3
|
+
require 'sonar/request'
|
4
|
+
require 'sonar/certificate'
|
5
|
+
require 'sonar/search'
|
6
|
+
require 'sonar/user'
|
7
|
+
require 'sonar/cli/cli'
|
8
|
+
|
9
|
+
module Sonar
|
10
|
+
class Client
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
include Request
|
14
|
+
include Certificate
|
15
|
+
include Search
|
16
|
+
include User
|
17
|
+
|
18
|
+
attr_accessor :api_url, :api_version, :access_token, :email
|
19
|
+
|
20
|
+
##
|
21
|
+
# Create a new Sonar::Client object
|
22
|
+
#
|
23
|
+
# @params options[Hash]
|
24
|
+
def initialize(options = {})
|
25
|
+
@api_url = options[:api_url] || Sonar.api_url || "https://sonar.labs.rapid7.com"
|
26
|
+
@api_version = options[:api_version] || Sonar.api_version || "v2"
|
27
|
+
@access_token = options[:access_token] || Sonar.access_token
|
28
|
+
@email = options[:email] || Sonar.email
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Create a Faraday::Connection object
|
33
|
+
#
|
34
|
+
# @return [Faraday::Connection]
|
35
|
+
def connection
|
36
|
+
params = {}
|
37
|
+
@conn = Faraday.new(url: api_url, params: params, headers: default_headers, ssl: { verify: true }) do |faraday|
|
38
|
+
faraday.use FaradayMiddleware::Mashify
|
39
|
+
faraday.use FaradayMiddleware::ParseJson, content_type: /\bjson$/
|
40
|
+
faraday.use FaradayMiddleware::FollowRedirects
|
41
|
+
faraday.adapter Faraday.default_adapter
|
42
|
+
end
|
43
|
+
@conn.headers['X-Sonar-Token'] = access_token
|
44
|
+
@conn.headers['X-Sonar-Email'] = email
|
45
|
+
@conn
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Generic GET of Sonar search Objects
|
50
|
+
def get_search_endpoint(type, params = {})
|
51
|
+
url = "/api/#{api_version}/search/#{type}"
|
52
|
+
if params[:limit]
|
53
|
+
RequestIterator.new(url, connection, params)
|
54
|
+
else
|
55
|
+
get(url, params)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Generic GET of Sonar Objects
|
61
|
+
def get_endpoint(type, params = {})
|
62
|
+
url = "/api/#{api_version}/#{type}"
|
63
|
+
get(url, params)
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Generic POST to Sonar
|
68
|
+
def post_to_sonar(type, params = {})
|
69
|
+
url = "/api/#{api_version}/#{type}"
|
70
|
+
post(url, params)
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def default_headers
|
76
|
+
{
|
77
|
+
accept: 'application/json',
|
78
|
+
content_type: 'application/json',
|
79
|
+
user_agent: "Sonar #{Sonar::VERSION} Ruby Gem"
|
80
|
+
}
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'multi_json'
|
3
|
+
|
4
|
+
module Sonar
|
5
|
+
module Request
|
6
|
+
def extract_params(params)
|
7
|
+
# extract something from Sonar if needed
|
8
|
+
params
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(path, options = {})
|
12
|
+
request(:get, path, options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def post(path, options = {})
|
16
|
+
request(:post, path, options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def put(path, options = {})
|
20
|
+
request(:put, path, options)
|
21
|
+
end
|
22
|
+
|
23
|
+
def request(method, path, options)
|
24
|
+
response = connection.send(method) do |request|
|
25
|
+
options.delete(:connection)
|
26
|
+
case method
|
27
|
+
when :get
|
28
|
+
request.url(path, options)
|
29
|
+
when :post, :put
|
30
|
+
request.path = path
|
31
|
+
request.body = MultiJson.encode(options) unless options.empty?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
response.body
|
36
|
+
end
|
37
|
+
|
38
|
+
class RequestIterator
|
39
|
+
include Request
|
40
|
+
|
41
|
+
attr_accessor :url, :connection, :params
|
42
|
+
|
43
|
+
def initialize(url, connection, params = {})
|
44
|
+
self.url = url
|
45
|
+
self.connection = connection
|
46
|
+
self.params = params
|
47
|
+
end
|
48
|
+
|
49
|
+
def each
|
50
|
+
more = true
|
51
|
+
records_rcvd = 0
|
52
|
+
while more && records_rcvd < params[:limit]
|
53
|
+
# TODO: refactor to not pass around the connection
|
54
|
+
params[:connection] = connection
|
55
|
+
resp = get(url, params)
|
56
|
+
params[:iterator_id] = resp.iterator_id
|
57
|
+
records_rcvd += resp['collection'].size
|
58
|
+
more = resp['more']
|
59
|
+
yield resp
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/sonar/search.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Sonar
|
4
|
+
module Search
|
5
|
+
# 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
|
+
}
|
20
|
+
|
21
|
+
##
|
22
|
+
# Get search
|
23
|
+
#
|
24
|
+
# params take in search type as key and query as value
|
25
|
+
# {fdns: 'rapid7.com'}
|
26
|
+
#
|
27
|
+
# @return [Hashie::Mash] with response of search
|
28
|
+
def search(params = {})
|
29
|
+
type_query = params.select { |k, _v| QUERY_TYPES_MAP.keys.include?(k.to_s) }.first
|
30
|
+
fail ArgumentError, "The query type provided is invalid or not yet implemented." unless type_query
|
31
|
+
type = type_query[0].to_sym
|
32
|
+
params[:q] = type_query[1]
|
33
|
+
params = extract_params(params)
|
34
|
+
get_search_endpoint(type, params)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/sonar/user.rb
ADDED
data/lib/sonar.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "faraday_middleware"
|
3
|
+
require "sonar/cli/cli"
|
4
|
+
require "sonar/client"
|
5
|
+
require "sonar/version"
|
6
|
+
|
7
|
+
module Sonar
|
8
|
+
class << self
|
9
|
+
attr_accessor :api_url, :api_version, :access_token, :email
|
10
|
+
|
11
|
+
##
|
12
|
+
# Configure default
|
13
|
+
#
|
14
|
+
# @yield Sonar client object
|
15
|
+
def configure
|
16
|
+
load_defaults
|
17
|
+
yield self
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def load_defaults
|
24
|
+
self.api_url ||= "https://sonar.labs.rapid7.com"
|
25
|
+
self.api_version ||= "v2"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sonar/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sonar-client"
|
8
|
+
spec.version = Sonar::VERSION
|
9
|
+
spec.authors = ["Paul Deardorff & HD Moore"]
|
10
|
+
spec.email = ["paul_deardorff@rapid7.com", "hd_moore@rapid7.com"]
|
11
|
+
spec.description = 'API Wrapper for Sonar'
|
12
|
+
spec.summary = spec.description
|
13
|
+
spec.homepage = "https://sonar.labs.rapid7.com"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
|
+
spec.executables = ["sonar"]
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'faraday_middleware', '~> 0.9.0'
|
22
|
+
spec.add_dependency 'hashie', '~> 2.0.3'
|
23
|
+
spec.add_dependency 'multi_json'
|
24
|
+
spec.add_dependency 'thor'
|
25
|
+
spec.add_dependency 'awesome_print'
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler"
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
spec.add_development_dependency "rspec"
|
30
|
+
spec.add_development_dependency "simplecov"
|
31
|
+
spec.add_development_dependency "simplecov-rcov"
|
32
|
+
spec.add_development_dependency "yard"
|
33
|
+
spec.add_development_dependency "vcr", '~> 2.8.0'
|
34
|
+
spec.add_development_dependency "shoulda"
|
35
|
+
spec.add_development_dependency "webmock", '~> 1.8.0'
|
36
|
+
spec.add_development_dependency "api_matchers"
|
37
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Sonar::Search do
|
5
|
+
let(:client) { Sonar::Client.new }
|
6
|
+
|
7
|
+
context "sha1 #get_certificate" do
|
8
|
+
it "should find the Rapid7 certificate by sha1" do
|
9
|
+
res = client.get_certificate(sha1: "1e80c24b97c928bb1db7d4d3c05475a6a40a1186")
|
10
|
+
expect(res.subject.CN).to eq("www.rapid7.com")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Sonar::CLI do
|
5
|
+
context "with a valid profile" do
|
6
|
+
before do
|
7
|
+
Sonar::RCFile.instance.path = "#{fixtures_path}/sonar.rc"
|
8
|
+
end
|
9
|
+
it "should return the profile" do
|
10
|
+
output = capture(:stdout) { Sonar::CLI.start(['profile']) }
|
11
|
+
expect(output).to match(/email@asdfasdfasfd.com/)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
context "without a config file" do
|
15
|
+
before do
|
16
|
+
Sonar::RCFile.instance.path = ""
|
17
|
+
end
|
18
|
+
xit "should create the missing config file" do
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Sonar::Search do
|
5
|
+
let(:client) { Sonar::Client.new }
|
6
|
+
|
7
|
+
describe "parameters" do
|
8
|
+
describe "query type" do
|
9
|
+
context "with an invalid query type" do
|
10
|
+
it "should raise an ArgumentError" do
|
11
|
+
expect { client.search(invalid: 'something.org') }.to raise_error(ArgumentError)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "exact" do
|
17
|
+
it "shouldn't match anything when #exact is true" do
|
18
|
+
resp = client.search(rdns: "1.1.", exact: true)
|
19
|
+
expect(resp["collection"].size).to eq(0)
|
20
|
+
end
|
21
|
+
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./)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "limit" do
|
28
|
+
# The default size from APIv1/v2 is 1,000 records
|
29
|
+
context "specifying the :limit to 3000 on #search" do
|
30
|
+
let(:resp) { client.search(rdns: '.hp.com', limit: 3000) }
|
31
|
+
|
32
|
+
it "should return a RequestIterator" do
|
33
|
+
expect(resp.class).to eq(Sonar::Request::RequestIterator)
|
34
|
+
end
|
35
|
+
it "should return 3 x 1,000-record blocks" do
|
36
|
+
num_blocks = 0
|
37
|
+
resp.each do |resp_block|
|
38
|
+
expect(resp_block['collection'].size).to eq(1000)
|
39
|
+
num_blocks += 1
|
40
|
+
end
|
41
|
+
expect(num_blocks).to eq(3)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "certificate" do
|
48
|
+
let(:resp) { client.search(certificate: '.hp.com') }
|
49
|
+
|
50
|
+
it "should provide certificate details" do
|
51
|
+
expect(resp).to have_key('collection')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "rdns" do
|
56
|
+
context "rdnsname" do
|
57
|
+
let(:resp) { client.search(rdns: '208.118.227.10.rapid7.com') }
|
58
|
+
|
59
|
+
it "returns hashie response of search" do
|
60
|
+
expect(resp.class).to eq(Hashie::Mash)
|
61
|
+
end
|
62
|
+
it "rdnsname finds 208.118.227.10 for 208.118.227.10.rapid7.com" do
|
63
|
+
expect(resp['collection'].any? { |x| x['address'] == '208.118.227.10' }).to be(true)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "rdnsip" do
|
68
|
+
let(:resp) { client.search(rdns: '188.40.56.11') }
|
69
|
+
|
70
|
+
it "rdnsip finds static.11.56.40.188.clients.your-server.de for 188.40.56.11" do
|
71
|
+
expect(resp['collection'].any? { |x| x['name'] == 'static.11.56.40.188.clients.your-server.de' }).to be(true)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "validation" do
|
76
|
+
let(:resp) { client.search(rdns: '188.40.56.11@#&#') }
|
77
|
+
|
78
|
+
it "should error for invalid domain query type" do
|
79
|
+
expect(resp["error"]).to eq("Invalid query")
|
80
|
+
expect(resp["errors"].first).to eq("Expected a domain but got '188.40.56.11@#&#'")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "fdns" do
|
86
|
+
context "fdnsname" do
|
87
|
+
let(:resp) { client.search(fdns: 'rapid7.com') }
|
88
|
+
|
89
|
+
it "returns hashie response of search" do
|
90
|
+
expect(resp.class).to eq(Hashie::Mash)
|
91
|
+
end
|
92
|
+
it "finds fdnsname 208.118.227.10 for rapid7.com" do
|
93
|
+
expect(resp['collection'].any? { |x| x['address'] == '208.118.227.10' }).to be(true)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "fdnsip" do
|
98
|
+
let(:resp) { client.search(fdns: '208.118.227.10') }
|
99
|
+
|
100
|
+
it "finds fdnsip rapid7.com at 208.118.227.10" do
|
101
|
+
expect(resp['collection'].any? { |x| x['address'] == 'rapid7.com' }).to be(true)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "validation" do
|
106
|
+
let(:resp) { client.search(fdns: '188.40.56.11@#&#') }
|
107
|
+
|
108
|
+
it "should error for invalid domain query type" do
|
109
|
+
expect(resp["error"]).to eq("Invalid query")
|
110
|
+
expect(resp["errors"].first).to eq("Expected a domain but got '188.40.56.11@#&#'")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "links_to" do
|
116
|
+
let(:resp) { client.search(links_to: 'rapid7.com') }
|
117
|
+
|
118
|
+
it "should provide links_to details" do
|
119
|
+
expect(resp).to have_key('collection')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context "ipcerts" do
|
124
|
+
let(:resp) { client.search(ipcerts: '208.118.227.10') }
|
125
|
+
|
126
|
+
it "should provide ipcerts details" do
|
127
|
+
expect(resp).to have_key('collection')
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "certips" do
|
132
|
+
let(:resp) { client.search(certips: '1e80c24b97c928bb1db7d4d3c05475a6a40a1186') }
|
133
|
+
|
134
|
+
it "should provide certips details" do
|
135
|
+
expect(resp).to have_key('collection')
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context "namecerts" do
|
140
|
+
let(:resp) { client.search(namecerts: '.rapid7.com') }
|
141
|
+
|
142
|
+
it "should provide namecerts details" do
|
143
|
+
expect(resp).to have_key('collection')
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "sslcert" do
|
148
|
+
let(:resp) { client.search(sslcert: '1e80c24b97c928bb1db7d4d3c05475a6a40a1186') }
|
149
|
+
|
150
|
+
it "should provide sslcert details" do
|
151
|
+
expect(resp).to have_key('collection')
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context "whois_ip" do
|
156
|
+
let(:resp) { client.search(whois_ip: '208.118.227.10') }
|
157
|
+
|
158
|
+
it "should find rapid7.com" do
|
159
|
+
expect(resp['name']).to eq('TWDX-208-118-227-0-1')
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# TODO: actually check response
|
164
|
+
context "raw" do
|
165
|
+
let(:resp) { client.search(raw: '208.118.227.10') }
|
166
|
+
|
167
|
+
it "should return a collection" do
|
168
|
+
expect(resp).to have_key('collection')
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# TODO: actually check response
|
173
|
+
context "processed" do
|
174
|
+
let(:resp) { client.search(processed: '208.118.227.10') }
|
175
|
+
|
176
|
+
it "should return a collection" do
|
177
|
+
expect(resp).to have_key('collection')
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# TODO: actually check response
|
182
|
+
context "ports" do
|
183
|
+
let(:resp) { client.search(ports: '208.118.227.10') }
|
184
|
+
|
185
|
+
it "should return a collection" do
|
186
|
+
expect(resp).to have_key('collection')
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Sonar::User do
|
5
|
+
let(:client) { Sonar::Client.new }
|
6
|
+
|
7
|
+
context "with a valid client querying usage" do
|
8
|
+
let(:res) { client.usage }
|
9
|
+
|
10
|
+
it "should show usage information for the user" do
|
11
|
+
expect(res.user.api_token).to_not be_nil
|
12
|
+
expect(res.current_api_hits).to be >= 0
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/spec/sonar_spec.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
# Skip the configure in spec_helper so we can test defaults
|
5
|
+
describe Sonar, skip_autoconfig: true do
|
6
|
+
let(:client) { Sonar::Client.new }
|
7
|
+
before :each do
|
8
|
+
reset_sonar_config
|
9
|
+
end
|
10
|
+
|
11
|
+
context "configure defaults" do
|
12
|
+
it "uses default API URL" do
|
13
|
+
expect(client.api_url).to eq 'https://sonar.labs.rapid7.com'
|
14
|
+
end
|
15
|
+
it "uses default API VERSION" do
|
16
|
+
expect(client.api_version).to eq 'v2'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "handles custom configuration for url and version" do
|
21
|
+
let(:new_client) do
|
22
|
+
Sonar::Client.new(
|
23
|
+
api_url: 'https://somethingnew.com',
|
24
|
+
api_version: 'v1'
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "::Client API_URL configuration" do
|
29
|
+
expect(new_client.api_url).to eq 'https://somethingnew.com'
|
30
|
+
end
|
31
|
+
it "::Client API_VERSION configuration" do
|
32
|
+
expect(new_client.api_version).to eq 'v1'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when using a configure block and setting api_version" do
|
37
|
+
before do
|
38
|
+
Sonar.configure do |c|
|
39
|
+
c.api_version = "v3"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should have set the custom api_version" do
|
44
|
+
expect(Sonar.api_version).to eq("v3")
|
45
|
+
end
|
46
|
+
it "should use the default api_url" do
|
47
|
+
expect(Sonar.api_url).to eq("https://sonar.labs.rapid7.com")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when making a request to the client with bad creds" do
|
52
|
+
before do
|
53
|
+
Sonar.configure do |c|
|
54
|
+
c.email = "wrong@sowrong.com"
|
55
|
+
c.access_token = "somewrongkey"
|
56
|
+
c.api_version = "v2"
|
57
|
+
c.api_url = "https://sonar-staging.labs.rapid7.com"
|
58
|
+
end
|
59
|
+
client = Sonar::Client.new
|
60
|
+
@resp = client.search(rdns: "hp.com")
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should return unauthorized" do
|
64
|
+
expect(@resp["error"]).to eq("Could not authenticate")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'sonar'
|
2
|
+
require 'active_support'
|
3
|
+
require 'vcr'
|
4
|
+
require 'simplecov'
|
5
|
+
require 'simplecov-rcov'
|
6
|
+
require 'api_matchers'
|
7
|
+
|
8
|
+
class SimpleCov::Formatter::MergedFormatter
|
9
|
+
def format(result)
|
10
|
+
SimpleCov::Formatter::HTMLFormatter.new.format(result)
|
11
|
+
SimpleCov::Formatter::RcovFormatter.new.format(result)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
SimpleCov.formatter = SimpleCov::Formatter::MergedFormatter
|
16
|
+
SimpleCov.start do
|
17
|
+
add_filter '/vendor'
|
18
|
+
end
|
19
|
+
|
20
|
+
VCR.configure do |c|
|
21
|
+
c.allow_http_connections_when_no_cassette = true
|
22
|
+
c.cassette_library_dir = 'spec/cassette'
|
23
|
+
c.hook_into :webmock
|
24
|
+
c.configure_rspec_metadata!
|
25
|
+
c.default_cassette_options = { record: :new_episodes }
|
26
|
+
end
|
27
|
+
|
28
|
+
RSpec.configure do |c|
|
29
|
+
c.include APIMatchers::RSpecMatchers
|
30
|
+
|
31
|
+
c.treat_symbols_as_metadata_keys_with_true_values = true
|
32
|
+
|
33
|
+
#
|
34
|
+
# Add gem specific configuration for easy access
|
35
|
+
#
|
36
|
+
c.before(:each) do
|
37
|
+
# TODO: move to using a gem like VCR for faking HTTP requests.
|
38
|
+
# For now we'll test against the staging server using
|
39
|
+
# real creds stored in env.
|
40
|
+
Sonar.configure do |config|
|
41
|
+
unless ENV['SONAR_TOKEN'] && ENV['SONAR_EMAIL']
|
42
|
+
fail ArgumentError, "Please configure Sonar for testing by setting SONAR_TOKEN, SONAR_EMAIL,
|
43
|
+
and SONAR_API_URL in your environment."
|
44
|
+
end
|
45
|
+
config.api_url = ENV['SONAR_API_URL'] || 'http://localhost:3000'
|
46
|
+
config.api_version = 'v2'
|
47
|
+
config.access_token = ENV['SONAR_TOKEN']
|
48
|
+
config.email = ENV['SONAR_EMAIL']
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def fixtures_path
|
54
|
+
File.expand_path('../fixtures', __FILE__)
|
55
|
+
end
|
56
|
+
|
57
|
+
def reset_sonar_config
|
58
|
+
Sonar.api_version = nil
|
59
|
+
Sonar.api_url = nil
|
60
|
+
end
|
metadata
ADDED
@@ -0,0 +1,292 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sonar-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paul Deardorff & HD Moore
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday_middleware
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.9.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.9.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: hashie
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.0.3
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.0.3
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: multi_json
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: thor
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: awesome_print
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bundler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: simplecov
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: simplecov-rcov
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: yard
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: vcr
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 2.8.0
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 2.8.0
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: shoulda
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: webmock
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - "~>"
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: 1.8.0
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - "~>"
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: 1.8.0
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: api_matchers
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ">="
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
223
|
+
description: API Wrapper for Sonar
|
224
|
+
email:
|
225
|
+
- paul_deardorff@rapid7.com
|
226
|
+
- hd_moore@rapid7.com
|
227
|
+
executables:
|
228
|
+
- sonar
|
229
|
+
extensions: []
|
230
|
+
extra_rdoc_files: []
|
231
|
+
files:
|
232
|
+
- ".gitignore"
|
233
|
+
- ".rspec"
|
234
|
+
- ".rubocop.yml"
|
235
|
+
- Gemfile
|
236
|
+
- Gemfile.lock
|
237
|
+
- LICENSE
|
238
|
+
- README.md
|
239
|
+
- Rakefile
|
240
|
+
- bin/sonar
|
241
|
+
- lib/sonar.rb
|
242
|
+
- lib/sonar/certificate.rb
|
243
|
+
- lib/sonar/cli/cli.rb
|
244
|
+
- lib/sonar/cli/rcfile.rb
|
245
|
+
- lib/sonar/client.rb
|
246
|
+
- lib/sonar/request.rb
|
247
|
+
- lib/sonar/search.rb
|
248
|
+
- lib/sonar/user.rb
|
249
|
+
- lib/sonar/version.rb
|
250
|
+
- sonar-client.gemspec
|
251
|
+
- spec/fixtures/sonar.rc
|
252
|
+
- spec/sonar/certificate_spec.rb
|
253
|
+
- spec/sonar/cli_spec.rb
|
254
|
+
- spec/sonar/client_spec.rb
|
255
|
+
- spec/sonar/search_spec.rb
|
256
|
+
- spec/sonar/user_spec.rb
|
257
|
+
- spec/sonar_spec.rb
|
258
|
+
- spec/spec_helper.rb
|
259
|
+
homepage: https://sonar.labs.rapid7.com
|
260
|
+
licenses:
|
261
|
+
- MIT
|
262
|
+
metadata: {}
|
263
|
+
post_install_message:
|
264
|
+
rdoc_options: []
|
265
|
+
require_paths:
|
266
|
+
- lib
|
267
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
268
|
+
requirements:
|
269
|
+
- - ">="
|
270
|
+
- !ruby/object:Gem::Version
|
271
|
+
version: '0'
|
272
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
273
|
+
requirements:
|
274
|
+
- - ">="
|
275
|
+
- !ruby/object:Gem::Version
|
276
|
+
version: '0'
|
277
|
+
requirements: []
|
278
|
+
rubyforge_project:
|
279
|
+
rubygems_version: 2.4.3
|
280
|
+
signing_key:
|
281
|
+
specification_version: 4
|
282
|
+
summary: API Wrapper for Sonar
|
283
|
+
test_files:
|
284
|
+
- spec/fixtures/sonar.rc
|
285
|
+
- spec/sonar/certificate_spec.rb
|
286
|
+
- spec/sonar/cli_spec.rb
|
287
|
+
- spec/sonar/client_spec.rb
|
288
|
+
- spec/sonar/search_spec.rb
|
289
|
+
- spec/sonar/user_spec.rb
|
290
|
+
- spec/sonar_spec.rb
|
291
|
+
- spec/spec_helper.rb
|
292
|
+
has_rdoc:
|