censu 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +13 -0
- data/.document +3 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/.rubocop.yml +166 -0
- data/.travis.yml +12 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +4 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +7 -0
- data/README.md +76 -0
- data/Rakefile +21 -0
- data/censys.gemspec +28 -0
- data/lib/censys.rb +2 -0
- data/lib/censys/api.rb +254 -0
- data/lib/censys/autonomous_system.rb +43 -0
- data/lib/censys/certificate.rb +31 -0
- data/lib/censys/document.rb +48 -0
- data/lib/censys/document/has_asn.rb +16 -0
- data/lib/censys/document/has_location.rb +16 -0
- data/lib/censys/document/has_services.rb +21 -0
- data/lib/censys/exceptions.rb +16 -0
- data/lib/censys/ipv4.rb +26 -0
- data/lib/censys/location.rb +54 -0
- data/lib/censys/report.rb +1 -0
- data/lib/censys/report/metadata.rb +41 -0
- data/lib/censys/report/response.rb +54 -0
- data/lib/censys/search.rb +1 -0
- data/lib/censys/search/certificate.rb +19 -0
- data/lib/censys/search/ipv4.rb +18 -0
- data/lib/censys/search/metadata.rb +33 -0
- data/lib/censys/search/response.rb +124 -0
- data/lib/censys/search/result.rb +49 -0
- data/lib/censys/search/website.rb +18 -0
- data/lib/censys/version.rb +4 -0
- data/lib/censys/website.rb +30 -0
- data/spec/censys_spec.rb +8 -0
- data/spec/fixtures/vcr_cassettes/Censys_API/_report/certificates/should_return_certificate_response.yml +49 -0
- data/spec/fixtures/vcr_cassettes/Censys_API/_report/ipv4/should_return_ipv4_response.yml +52 -0
- data/spec/fixtures/vcr_cassettes/Censys_API/_report/websites/should_return_website_response.yml +49 -0
- data/spec/fixtures/vcr_cassettes/Censys_API/_search/certificates/should_return_Certificate_response.yml +397 -0
- data/spec/fixtures/vcr_cassettes/Censys_API/_search/ipv4/should_return_IPv4_response.yml +606 -0
- data/spec/fixtures/vcr_cassettes/Censys_API/_search/websites/should_return_Website_response.yml +112 -0
- data/spec/fixtures/vcr_cassettes/Censys_API/_view/certificates/should_return_Certificate_response.yml +143 -0
- data/spec/fixtures/vcr_cassettes/Censys_API/_view/ipv4/should_return_IPv4_response.yml +176 -0
- data/spec/fixtures/vcr_cassettes/Censys_API/_view/websites/should_return_Website_response.yml +1020 -0
- data/spec/report_spec.rb +60 -0
- data/spec/search_spec.rb +49 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/view_spec.rb +48 -0
- metadata +219 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dc032c148fcfd0d25166894346ef57abb771edba
|
4
|
+
data.tar.gz: 7bc3d93c58883260e0eb274f9104b505ea99156a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a7283ce3bb2407fd4e85874432139a2742d4d052b2d2db8674cbd23ad208cd43f67ff883d3c4339caccba23787aa721c59e2cb007622707db568916fc84879f7
|
7
|
+
data.tar.gz: 5c8011da8618be9bd7cc7e5f7ababd13f811c00fe896de01b2ba34924431ea42e07a3f80c4827e3e8becb0a930b35a853ce931ac7f164f66b7250eab4b66f3f4
|
data/.codeclimate.yml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
version: "2"
|
2
|
+
prepare:
|
3
|
+
fetch:
|
4
|
+
- url: "https://raw.githubusercontent.com/janlelis/relaxed.ruby.style/master/.rubocop.yml"
|
5
|
+
path: "alternate-rubocop-path.yml"
|
6
|
+
plugins:
|
7
|
+
rubocop:
|
8
|
+
enabled: true
|
9
|
+
config:
|
10
|
+
file: "alternate-rubocop-path.yml"
|
11
|
+
exclude_patterns:
|
12
|
+
- "spec/"
|
13
|
+
- "!spec/support/helpers"
|
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format documentation
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
# Relaxed.Ruby.Style
|
2
|
+
## Version 2.1
|
3
|
+
|
4
|
+
Style/Alias:
|
5
|
+
Enabled: false
|
6
|
+
StyleGuide: http://relaxed.ruby.style/#stylealias
|
7
|
+
|
8
|
+
Style/AsciiComments:
|
9
|
+
Enabled: false
|
10
|
+
StyleGuide: http://relaxed.ruby.style/#styleasciicomments
|
11
|
+
|
12
|
+
Style/BeginBlock:
|
13
|
+
Enabled: false
|
14
|
+
StyleGuide: http://relaxed.ruby.style/#stylebeginblock
|
15
|
+
|
16
|
+
Style/BlockDelimiters:
|
17
|
+
Enabled: false
|
18
|
+
StyleGuide: http://relaxed.ruby.style/#styleblockdelimiters
|
19
|
+
|
20
|
+
Style/CommentAnnotation:
|
21
|
+
Enabled: false
|
22
|
+
StyleGuide: http://relaxed.ruby.style/#stylecommentannotation
|
23
|
+
|
24
|
+
Style/Documentation:
|
25
|
+
Enabled: false
|
26
|
+
StyleGuide: http://relaxed.ruby.style/#styledocumentation
|
27
|
+
|
28
|
+
Layout/DotPosition:
|
29
|
+
Enabled: false
|
30
|
+
StyleGuide: http://relaxed.ruby.style/#layoutdotposition
|
31
|
+
|
32
|
+
Style/DoubleNegation:
|
33
|
+
Enabled: false
|
34
|
+
StyleGuide: http://relaxed.ruby.style/#styledoublenegation
|
35
|
+
|
36
|
+
Style/EndBlock:
|
37
|
+
Enabled: false
|
38
|
+
StyleGuide: http://relaxed.ruby.style/#styleendblock
|
39
|
+
|
40
|
+
Style/FormatString:
|
41
|
+
Enabled: false
|
42
|
+
StyleGuide: http://relaxed.ruby.style/#styleformatstring
|
43
|
+
|
44
|
+
Style/IfUnlessModifier:
|
45
|
+
Enabled: false
|
46
|
+
StyleGuide: http://relaxed.ruby.style/#styleifunlessmodifier
|
47
|
+
|
48
|
+
Style/Lambda:
|
49
|
+
Enabled: false
|
50
|
+
StyleGuide: http://relaxed.ruby.style/#stylelambda
|
51
|
+
|
52
|
+
Style/ModuleFunction:
|
53
|
+
Enabled: false
|
54
|
+
StyleGuide: http://relaxed.ruby.style/#stylemodulefunction
|
55
|
+
|
56
|
+
Style/MultilineBlockChain:
|
57
|
+
Enabled: false
|
58
|
+
StyleGuide: http://relaxed.ruby.style/#stylemultilineblockchain
|
59
|
+
|
60
|
+
Style/NegatedIf:
|
61
|
+
Enabled: false
|
62
|
+
StyleGuide: http://relaxed.ruby.style/#stylenegatedif
|
63
|
+
|
64
|
+
Style/NegatedWhile:
|
65
|
+
Enabled: false
|
66
|
+
StyleGuide: http://relaxed.ruby.style/#stylenegatedwhile
|
67
|
+
|
68
|
+
Style/ParallelAssignment:
|
69
|
+
Enabled: false
|
70
|
+
StyleGuide: http://relaxed.ruby.style/#styleparallelassignment
|
71
|
+
|
72
|
+
Style/PercentLiteralDelimiters:
|
73
|
+
Enabled: false
|
74
|
+
StyleGuide: http://relaxed.ruby.style/#stylepercentliteraldelimiters
|
75
|
+
|
76
|
+
Style/PerlBackrefs:
|
77
|
+
Enabled: false
|
78
|
+
StyleGuide: http://relaxed.ruby.style/#styleperlbackrefs
|
79
|
+
|
80
|
+
Style/Semicolon:
|
81
|
+
Enabled: false
|
82
|
+
StyleGuide: http://relaxed.ruby.style/#stylesemicolon
|
83
|
+
|
84
|
+
Style/SignalException:
|
85
|
+
Enabled: false
|
86
|
+
StyleGuide: http://relaxed.ruby.style/#stylesignalexception
|
87
|
+
|
88
|
+
Style/SingleLineBlockParams:
|
89
|
+
Enabled: false
|
90
|
+
StyleGuide: http://relaxed.ruby.style/#stylesinglelineblockparams
|
91
|
+
|
92
|
+
Style/SingleLineMethods:
|
93
|
+
Enabled: false
|
94
|
+
StyleGuide: http://relaxed.ruby.style/#stylesinglelinemethods
|
95
|
+
|
96
|
+
Layout/SpaceBeforeBlockBraces:
|
97
|
+
Enabled: false
|
98
|
+
StyleGuide: http://relaxed.ruby.style/#layoutspacebeforeblockbraces
|
99
|
+
|
100
|
+
Layout/SpaceInsideParens:
|
101
|
+
Enabled: false
|
102
|
+
StyleGuide: http://relaxed.ruby.style/#layoutspaceinsideparens
|
103
|
+
|
104
|
+
Style/SpecialGlobalVars:
|
105
|
+
Enabled: false
|
106
|
+
StyleGuide: http://relaxed.ruby.style/#stylespecialglobalvars
|
107
|
+
|
108
|
+
Style/StringLiterals:
|
109
|
+
Enabled: false
|
110
|
+
StyleGuide: http://relaxed.ruby.style/#stylestringliterals
|
111
|
+
|
112
|
+
Style/TrailingCommaInArguments:
|
113
|
+
Enabled: false
|
114
|
+
StyleGuide: http://relaxed.ruby.style/#styletrailingcommainarguments
|
115
|
+
|
116
|
+
Style/TrailingCommaInLiteral:
|
117
|
+
Enabled: false
|
118
|
+
StyleGuide: http://relaxed.ruby.style/#styletrailingcommainliteral
|
119
|
+
|
120
|
+
Style/WhileUntilModifier:
|
121
|
+
Enabled: false
|
122
|
+
StyleGuide: http://relaxed.ruby.style/#stylewhileuntilmodifier
|
123
|
+
|
124
|
+
Style/WordArray:
|
125
|
+
Enabled: false
|
126
|
+
StyleGuide: http://relaxed.ruby.style/#stylewordarray
|
127
|
+
|
128
|
+
Lint/AmbiguousRegexpLiteral:
|
129
|
+
Enabled: false
|
130
|
+
StyleGuide: http://relaxed.ruby.style/#lintambiguousregexpliteral
|
131
|
+
|
132
|
+
Lint/AssignmentInCondition:
|
133
|
+
Enabled: false
|
134
|
+
StyleGuide: http://relaxed.ruby.style/#lintassignmentincondition
|
135
|
+
|
136
|
+
Metrics/AbcSize:
|
137
|
+
Enabled: false
|
138
|
+
|
139
|
+
Metrics/BlockNesting:
|
140
|
+
Enabled: false
|
141
|
+
|
142
|
+
Metrics/BlockLength:
|
143
|
+
Exclude:
|
144
|
+
- 'spec/**/*'
|
145
|
+
|
146
|
+
Metrics/ClassLength:
|
147
|
+
Enabled: false
|
148
|
+
|
149
|
+
Metrics/ModuleLength:
|
150
|
+
Enabled: false
|
151
|
+
|
152
|
+
Metrics/CyclomaticComplexity:
|
153
|
+
Enabled: false
|
154
|
+
|
155
|
+
Metrics/LineLength:
|
156
|
+
Enabled: false
|
157
|
+
|
158
|
+
Metrics/MethodLength:
|
159
|
+
Enabled: false
|
160
|
+
|
161
|
+
Metrics/ParameterLists:
|
162
|
+
Enabled: false
|
163
|
+
|
164
|
+
Metrics/PerceivedComplexity:
|
165
|
+
Enabled: false
|
166
|
+
|
data/.travis.yml
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown --title "CenSys Documentation" --protected
|
data/ChangeLog.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright 2017 ninoseki(Manabu Niseki)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# Censu
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/ninoseki/censu.svg?branch=master)](https://travis-ci.org/ninoseki/censu)
|
4
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/39e77d63ce6a7d89b4dc/maintainability)](https://codeclimate.com/github/ninoseki/censu/maintainability)
|
5
|
+
|
6
|
+
* [Homepage](https://github.com/ninoseki/censu)
|
7
|
+
* [Issues](https://github.com/ninoseki/censu/issues)
|
8
|
+
|
9
|
+
## Description
|
10
|
+
|
11
|
+
Ruby API client to the [Censys] internet search engine.
|
12
|
+
|
13
|
+
## Features
|
14
|
+
|
15
|
+
## Examples
|
16
|
+
|
17
|
+
Initialize the API:
|
18
|
+
|
19
|
+
require 'censys'
|
20
|
+
api = Censys::API.new(uid,secret)
|
21
|
+
|
22
|
+
Initialize the API using `$CENSYS_ID` and `$CENSYS_SECRET` environment
|
23
|
+
variables:
|
24
|
+
|
25
|
+
api = Censys::API.new
|
26
|
+
|
27
|
+
Search for IPv4 addresses:
|
28
|
+
|
29
|
+
response = api.ipv4.search(query: 'dropbox.com')
|
30
|
+
|
31
|
+
Search for Websites:
|
32
|
+
|
33
|
+
response = api.websites.search(query: 'dropbox.com')
|
34
|
+
|
35
|
+
Search for Certificates:
|
36
|
+
|
37
|
+
response = api.certificates.search(query: 'dropbox.com')
|
38
|
+
|
39
|
+
Enumerate through search results:
|
40
|
+
|
41
|
+
response.each_page do |page|
|
42
|
+
puts ">>> Page ##{page.metadata.page} / #{page.metadata.pages} ..."
|
43
|
+
|
44
|
+
page.each do |result|
|
45
|
+
puts result
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
Generate aggregate reports:
|
50
|
+
|
51
|
+
response = api.websites.report(
|
52
|
+
query: '80.http.get.headers.server: Apache',
|
53
|
+
field: 'location.country_code',
|
54
|
+
buckets: 100
|
55
|
+
)
|
56
|
+
|
57
|
+
response.each do |country,count|
|
58
|
+
puts "#{country}: #{count}"
|
59
|
+
end
|
60
|
+
|
61
|
+
## Requirements
|
62
|
+
|
63
|
+
* [ruby] >= 2.0
|
64
|
+
|
65
|
+
## Install
|
66
|
+
|
67
|
+
$ gem install censu
|
68
|
+
|
69
|
+
## License
|
70
|
+
|
71
|
+
See {file:LICENSE.txt} for details.
|
72
|
+
|
73
|
+
Note:: This gem is forked from [trailofbits/censys-ruby](https://github.com/trailofbits/censys-ruby).
|
74
|
+
|
75
|
+
[ruby]: http://www.ruby-lang.org/
|
76
|
+
[Cens:qys]: https://censys.io/
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError => e
|
6
|
+
abort e.message
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rake'
|
10
|
+
require 'rubygems/tasks'
|
11
|
+
Gem::Tasks.new
|
12
|
+
|
13
|
+
require 'rspec/core/rake_task'
|
14
|
+
RSpec::Core::RakeTask.new
|
15
|
+
|
16
|
+
task test: :spec
|
17
|
+
task default: :spec
|
18
|
+
|
19
|
+
require 'yard'
|
20
|
+
YARD::Rake::YardocTask.new
|
21
|
+
task doc: :yard
|
data/censys.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'censys/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = "censu"
|
7
|
+
gem.version = Censys::VERSION
|
8
|
+
gem.summary = "API client for censys.io"
|
9
|
+
gem.description = "Ruby API client for the Censys Internet search engine."
|
10
|
+
gem.license = "MIT"
|
11
|
+
gem.authors = ["Manabu Niseki"]
|
12
|
+
gem.email = "manabu.niseki@gmail.com"
|
13
|
+
gem.homepage = "https://github.com/ninoseki/censu"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ['lib']
|
19
|
+
|
20
|
+
gem.add_development_dependency 'bundler', '~> 1.16'
|
21
|
+
gem.add_development_dependency 'dotenv', '~> 2.2'
|
22
|
+
gem.add_development_dependency 'rake', '~> 12.3'
|
23
|
+
gem.add_development_dependency 'rspec', '~> 3.7'
|
24
|
+
gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
|
25
|
+
gem.add_development_dependency 'vcr', '~> 4.0'
|
26
|
+
gem.add_development_dependency 'webmock', '~> 3.1'
|
27
|
+
gem.add_development_dependency 'yard', '~> 0.9'
|
28
|
+
end
|
data/lib/censys.rb
ADDED
data/lib/censys/api.rb
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
require 'censys/exceptions'
|
2
|
+
require 'censys/search'
|
3
|
+
require 'censys/report'
|
4
|
+
require 'censys/ipv4'
|
5
|
+
require 'censys/website'
|
6
|
+
require 'censys/certificate'
|
7
|
+
|
8
|
+
require 'net/https'
|
9
|
+
require 'json'
|
10
|
+
|
11
|
+
module Censys
|
12
|
+
class API
|
13
|
+
VERSION = 1
|
14
|
+
HOST = 'www.censys.io'.freeze
|
15
|
+
URL = "https://#{HOST}/api/v#{VERSION}".freeze
|
16
|
+
|
17
|
+
class Resource
|
18
|
+
def initialize(type, api)
|
19
|
+
@type = type
|
20
|
+
@api = api
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# @see API#search
|
25
|
+
#
|
26
|
+
def search(params = {})
|
27
|
+
@api.search(@type, params)
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# @see API#view
|
32
|
+
#
|
33
|
+
def [](id)
|
34
|
+
@api.view(@type, id)
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# @see API#report
|
39
|
+
#
|
40
|
+
def report(params)
|
41
|
+
@api.report(@type, params)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# API UID.
|
46
|
+
#
|
47
|
+
# @return [String]
|
48
|
+
attr_reader :id
|
49
|
+
|
50
|
+
# API Secret.
|
51
|
+
#
|
52
|
+
# @return [String]
|
53
|
+
attr_reader :secret
|
54
|
+
|
55
|
+
# IPv4 resource.
|
56
|
+
#
|
57
|
+
# @return [Resource]
|
58
|
+
attr_reader :ipv4
|
59
|
+
|
60
|
+
# Websites resource.
|
61
|
+
#
|
62
|
+
# @return [Resource]
|
63
|
+
attr_reader :websites
|
64
|
+
|
65
|
+
# Certificates resource.
|
66
|
+
#
|
67
|
+
# @return [Resource]
|
68
|
+
attr_reader :certificates
|
69
|
+
|
70
|
+
#
|
71
|
+
# Initializes the API.
|
72
|
+
#
|
73
|
+
# @param [String] id
|
74
|
+
# The API UID used for authentication.
|
75
|
+
#
|
76
|
+
# @param [String] secret
|
77
|
+
# The API secret used for authentication.
|
78
|
+
#
|
79
|
+
# @raise [ArgumentError]
|
80
|
+
# Either `id` or `secret` was `nil` or empty.
|
81
|
+
#
|
82
|
+
# @see https://censys.io/account
|
83
|
+
# Censys - My Account
|
84
|
+
#
|
85
|
+
def initialize(id = ENV['CENSYS_ID'], secret = ENV['CENSYS_SECRET'])
|
86
|
+
raise(ArgumentError, "'id' argument required") if id.nil? || id.empty?
|
87
|
+
raise(ArgumentError, "'secret' argument required") if secret.nil? || secret.empty?
|
88
|
+
|
89
|
+
@id, @secret = id, secret
|
90
|
+
|
91
|
+
@ipv4 = Resource.new(:ipv4, self)
|
92
|
+
@websites = Resource.new(:websites, self)
|
93
|
+
@certificates = Resource.new(:certificates, self)
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# Performs a search.
|
98
|
+
#
|
99
|
+
# @param [:ipv4, :websites, :certificates] resource
|
100
|
+
#
|
101
|
+
# @param [Hash] params
|
102
|
+
# Optional search params.
|
103
|
+
#
|
104
|
+
# @option params [String] :query
|
105
|
+
# The query to perform.
|
106
|
+
#
|
107
|
+
# @option params [Fixnum] :page
|
108
|
+
# Optional page number to request.
|
109
|
+
#
|
110
|
+
# @option params [Array<String>] :fields
|
111
|
+
# Optional list of fields to include in the results.
|
112
|
+
#
|
113
|
+
# @api private
|
114
|
+
#
|
115
|
+
def search(resource, params = {})
|
116
|
+
post("/search/#{resource}", params) do |json|
|
117
|
+
Search::Response.new(self, resource, params, json)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
DOCUMENTS = {
|
122
|
+
ipv4: IPv4,
|
123
|
+
websites: Website,
|
124
|
+
certificates: Certificate
|
125
|
+
}.freeze
|
126
|
+
|
127
|
+
#
|
128
|
+
# Requests the document of the given type.
|
129
|
+
#
|
130
|
+
# @param [:ipv4, :websites, :certificates] resource
|
131
|
+
#
|
132
|
+
# @param [String] id
|
133
|
+
#
|
134
|
+
# @api private
|
135
|
+
#
|
136
|
+
def view(resource, id)
|
137
|
+
document_class = DOCUMENTS.fetch(resource)
|
138
|
+
|
139
|
+
get("/view/#{resource}/#{id}") do |attributes|
|
140
|
+
document_class.new(attributes)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
# Builds a report of aggregate data.
|
146
|
+
#
|
147
|
+
# @param [:ipv4, :websites, :certificates] resource
|
148
|
+
#
|
149
|
+
# @param [Hash] params
|
150
|
+
#
|
151
|
+
# @option params [String] :query
|
152
|
+
# (**Required**) The query to perform.
|
153
|
+
#
|
154
|
+
# @option params [String] :field
|
155
|
+
# (**Required**) The field to aggregate.
|
156
|
+
#
|
157
|
+
# @option params [Fixnum] :buckets
|
158
|
+
# Optional maximum number of values to be returned.
|
159
|
+
#
|
160
|
+
# @option params
|
161
|
+
#
|
162
|
+
def report(resource, params)
|
163
|
+
raise(ArgumentError, "must specify the :query param") unless params[:query]
|
164
|
+
raise(ArgumentError, "must specify the :field param") unless params[:field]
|
165
|
+
|
166
|
+
post("/report/#{resource}", params) do |response|
|
167
|
+
Report::Response.new(response)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
private
|
172
|
+
|
173
|
+
#
|
174
|
+
# Returns a URL for the API sub-path.
|
175
|
+
#
|
176
|
+
# @param [String] path
|
177
|
+
# Path relative to `/api/v1`.
|
178
|
+
#
|
179
|
+
# @return [URI::HTTPS]
|
180
|
+
# Fully qualified URI.
|
181
|
+
#
|
182
|
+
def url_for(path)
|
183
|
+
URI(URL + path)
|
184
|
+
end
|
185
|
+
|
186
|
+
#
|
187
|
+
# Sends the HTTP request and handles the response.
|
188
|
+
#
|
189
|
+
# @param [Net::HTTP::Get, Net::HTTP::Post] req
|
190
|
+
# The prepared request to send.
|
191
|
+
#
|
192
|
+
# @yield [json]
|
193
|
+
# The given block will be passed the parsed JSON.
|
194
|
+
#
|
195
|
+
# @yieldparam [Hash{String => Object}] json
|
196
|
+
# The parsed JSON.
|
197
|
+
#
|
198
|
+
# @raise [NotFound, RateLimited, InternalServerError, ResponseError]
|
199
|
+
# If an error response is returned, the appropriate exception will be
|
200
|
+
# raised.
|
201
|
+
#
|
202
|
+
def request(req)
|
203
|
+
Net::HTTP.start(HOST, 443, use_ssl: true) do |http|
|
204
|
+
response = http.request(req)
|
205
|
+
|
206
|
+
case response.code
|
207
|
+
when '200' then yield JSON.parse(response.body)
|
208
|
+
when '302' then raise(AuthenticationError, response.body)
|
209
|
+
when '404' then raise(NotFound, "#{req.uri} not found")
|
210
|
+
when '429' then raise(RateLimited, "rate limit exceeded")
|
211
|
+
when '500' then raise(InternalServerError, response.body)
|
212
|
+
else
|
213
|
+
raise(ResponseError, "unsupported response code returned: #{response.code}")
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
#
|
219
|
+
# Creates a new HTTP GET request.
|
220
|
+
#
|
221
|
+
# @param [String] path
|
222
|
+
#
|
223
|
+
# @see #request
|
224
|
+
#
|
225
|
+
def get(path, &block)
|
226
|
+
get = Net::HTTP::Get.new(url_for(path))
|
227
|
+
get.basic_auth @id, @secret
|
228
|
+
|
229
|
+
request(get, &block)
|
230
|
+
end
|
231
|
+
|
232
|
+
#
|
233
|
+
# Creates a new HTTP POST request.
|
234
|
+
#
|
235
|
+
# @param [String] path
|
236
|
+
#
|
237
|
+
# @param [#to_json] json
|
238
|
+
#
|
239
|
+
# @see #request
|
240
|
+
#
|
241
|
+
def post(path, json, &block)
|
242
|
+
post = Net::HTTP::Post.new(url_for(path))
|
243
|
+
post.basic_auth @id, @secret
|
244
|
+
post.content_type = 'application/json'
|
245
|
+
post.body = json.to_json
|
246
|
+
|
247
|
+
request(post, &block)
|
248
|
+
end
|
249
|
+
|
250
|
+
def validate_index!(index)
|
251
|
+
raise(ArgumentError, "unsupported index type: #{index}") unless INDEXES.include?(index)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|