investigate 1.0.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ac625584a4ae8f946228752e85e8ff967d588d4b
4
+ data.tar.gz: eb65489710eaefebb6e5253fe582b81fcdf92df9
5
+ SHA512:
6
+ metadata.gz: b6af4681102260bdf2d264f1cea6bb2d32713e4e5701e384c84b649ec589c352889769cc5d2959fc485f69f36c5f5ab328c0205b1e98473e317b3680e84b61e5
7
+ data.tar.gz: a6551994bad83549cfbeb092a08dc2e7f79cfef9424a2fa432e8d043063878bbbc670dcfc0df9553c9d621671eb47bfb5e69a3b412c6eebd598f1dd24123dfdb
@@ -0,0 +1,3 @@
1
+ *.DS_Store
2
+ *.lock
3
+ *.swp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format documentation
3
+ --backtrace
@@ -0,0 +1 @@
1
+ 2.1.2
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # gem 'rest-client'
4
+ # gem 'siphash', github: 'emboss/siphash-ruby'
5
+
6
+ gemspec
@@ -0,0 +1,52 @@
1
+ # Ruby API for the OpenDNS Security Graph
2
+
3
+ ## Usage
4
+
5
+ In your Ruby script, you can use it like this:
6
+
7
+ ```ruby
8
+ require 'investigate'
9
+
10
+ inv = Investigate.new('f29be9cc-f833-4a9a-b984-19dc4d5186ac')
11
+
12
+ # get domain categorization and status
13
+ inv.categorization('amazon.com')
14
+
15
+ # categorization and status on a list of domains with labels
16
+ domains = ['www.amazon.com', 'www.opendns.com', 'bibikun.ru']
17
+ inv.categorization(domains, true)
18
+
19
+ # cooccurrences
20
+ inv.cooccurrences('test.com')
21
+
22
+ # related domains
23
+ inv.related("test.com")
24
+
25
+ # security features
26
+ inv.security("test.com")
27
+
28
+ # domain tags
29
+ inv.domain_tags('bibikun.ru')
30
+
31
+ # domain RR history
32
+ inv.rr_history('bibikun.ru')
33
+
34
+ # IP RR history
35
+ inv.rr_history('50.23.225.49')
36
+ ...
37
+ ```
38
+
39
+ ## Installation
40
+ You can do:
41
+ ```sh
42
+ gem install investigate
43
+ ```
44
+
45
+ or install manually with:
46
+ ```sh
47
+ git clone git@github.com:dead10ck/ruby-investigate.git
48
+ cd ruby-investigate
49
+ bundle install
50
+ gem build investigate.gemspec
51
+ gem install {generated_name}.gem
52
+ ```
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'investigate'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "investigate"
8
+ spec.version = Investigate::VERSION
9
+ spec.authors = ["skyler"]
10
+ spec.email = ["skyler@opendns.com"]
11
+ spec.summary = "Ruby API for the OpenDNS Security Graph"
12
+ spec.description = spec.summary
13
+ spec.homepage = 'https://github.com/dead10ck/ruby-investigate'
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "rest-client", "~> 1.7"
22
+ end
@@ -0,0 +1,121 @@
1
+ require 'json'
2
+ require 'rest-client'
3
+
4
+ # Ruby API for the OpenDNS Security Graph
5
+ class Investigate
6
+ VERSION = '1.0.0'
7
+ SGRAPH_URL = 'https://investigate.api.opendns.com'
8
+ SIPHASH_KEY = 'Umbrella/OpenDNS'
9
+ SUPPORTED_DNS_TYPES = [
10
+ "A",
11
+ "NS",
12
+ "MX",
13
+ "TXT",
14
+ "CNAME"
15
+ ]
16
+
17
+ # Builds a new Investigate object.
18
+ def initialize(key)
19
+ @res = RestClient::Resource.new(SGRAPH_URL,
20
+ :headers => { "Authorization" => "Bearer #{key}" })
21
+ end
22
+
23
+ # Generic GET call to the API with the given URI
24
+ # Parses the response into a JSON object
25
+ def get(uri, params={})
26
+ resp = @res[uri].get(:params => params)
27
+ JSON.parse(resp)
28
+ end
29
+
30
+ # Generic POST call to the API with the given URI and body
31
+ # Parses the response into a JSON object
32
+ def post(uri, body, params)
33
+ resp = @res[uri].post(body, :params => params)
34
+ JSON.parse(resp)
35
+ end
36
+
37
+ # Get the domain status and categorization of a domain or list of domains.
38
+ # 'domains' can be either a single domain, or a list of domains.
39
+ # Setting 'labels' to True will give back categorizations in human-readable
40
+ # form.
41
+ #
42
+ # For more detail, see https://sgraph.opendns.com/docs/api#categorization
43
+ def categorization(domains, labels=false)
44
+ if domains.kind_of?(Array)
45
+ post_categorization(domains, labels)
46
+ elsif domains.kind_of?(String)
47
+ get_categorization(domains, labels)
48
+ else
49
+ raise "domains must be a string or a list of strings"
50
+ end
51
+ end
52
+
53
+ # Get the cooccurrences of the given domain.
54
+ #
55
+ # For details, see https://sgraph.opendns.com/docs/api#co-occurrences
56
+ def cooccurrences(domain)
57
+ get("/recommendations/name/#{domain}.json")
58
+ end
59
+
60
+ # Get the related domains of the given domain.
61
+ #
62
+ # For details, see https://sgraph.opendns.com/docs/api#relatedDomains
63
+ def related_domains(domain)
64
+ get("/links/name/#{domain}.json")
65
+ end
66
+
67
+ # Get the Security Information for the given domain.
68
+ #
69
+ # For details, see https://sgraph.opendns.com/docs/api#securityInfo
70
+ def security(domain)
71
+ get("/security/name/#{domain}.json")
72
+ end
73
+
74
+ # Get the domain tagging dates for the given domain.
75
+ #
76
+ # For details, see https://sgraph.opendns.com/docs/api#latest_tags
77
+ def domain_tags(domain)
78
+ get("/domains/#{domain}/latest_tags")
79
+ end
80
+
81
+ # Get the RR (Resource Record) History of the given domain or IP.
82
+ # The default query type is for 'A' records, but the following query types
83
+ # are supported:
84
+ #
85
+ # A, NS, MX, TXT, CNAME
86
+ #
87
+ # For details, see https://sgraph.opendns.com/docs/api#dnsrr_domain
88
+ def rr_history(query, query_type="A")
89
+ raise "unsupported query type" unless SUPPORTED_DNS_TYPES.include?(query_type)
90
+ if query =~ /(\d{1,3}\.){3}\d{1,3}/
91
+ get_ip(query, query_type)
92
+ else
93
+ get_domain(query, query_type)
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ # Make a GET call to '/dnsdb/ip/a/{ip}.json'.
100
+ # Return the JSON object in the response
101
+ def get_ip(ip, query_type)
102
+ get("/dnsdb/ip/#{query_type}/#{ip}.json")
103
+ end
104
+
105
+ # Make a GET call to '/dnsdb/name/a/{domain}.json'.
106
+ # Return the JSON object in the response
107
+ def get_domain(domain, query_type)
108
+ get("/dnsdb/name/#{query_type}/#{domain}.json")
109
+ end
110
+
111
+ def get_categorization(domain, labels)
112
+ params = labels ? { "showLabels" => true } : {}
113
+ get("/domains/categorization/#{domain}", params)
114
+ end
115
+
116
+ def post_categorization(domains, labels)
117
+ params = labels ? { "showLabels" => true } : {}
118
+ data = JSON.generate(domains)
119
+ post("/domains/categorization/", data, params)
120
+ end
121
+ end
@@ -0,0 +1 @@
1
+ require_relative '../lib/investigate.rb'
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+ require 'time'
3
+
4
+ describe "Investigate" do
5
+ before(:all) do
6
+ @sg = Investigate.new(ENV['INVESTIGATE_KEY'])
7
+ end
8
+
9
+ def has_keys?(data={}, keys=[])
10
+ keys.each do |key|
11
+ expect(data.has_key?(key)).to eq true
12
+ end
13
+ end
14
+
15
+ it "does categorization() correctly" do
16
+ # test a single domain
17
+ cat_keys = ["status", "security_categories", "content_categories"]
18
+ resp_json = @sg.categorization('www.amazon.com')
19
+ expect(resp_json.has_key?('www.amazon.com')).to eq true
20
+ has_keys?(resp_json['www.amazon.com'], cat_keys)
21
+
22
+ # test a domain with labels
23
+ resp_json = @sg.categorization('www.amazon.com', true)
24
+ expect(resp_json.has_key?('www.amazon.com')).to eq true
25
+ has_keys?(resp_json['www.amazon.com'], cat_keys)
26
+
27
+ # test a list of domains with labels
28
+ domains = ['www.amazon.com', 'www.opendns.com', 'bibikun.ru']
29
+ resp_json = @sg.categorization(domains, true)
30
+ has_keys?(resp_json, domains)
31
+ domains.each do |d|
32
+ has_keys?(resp_json[d], cat_keys)
33
+ end
34
+
35
+ # calling with the wrong kind of object should raise an error
36
+ lambda { @sg.categorization({"blah" => "hello"}) }.should raise_error
37
+ end
38
+
39
+ it "does rr_history() correctly" do
40
+ # query an IP
41
+ data = @sg.rr_history('208.64.121.161')
42
+ has_keys?(data, ['features', 'rrs'])
43
+
44
+ # query a domain
45
+ data = @sg.rr_history('www.test.com')
46
+ has_keys?(data, ['features', 'rrs_tf'])
47
+
48
+ # query a domain with a different query_type
49
+ data = @sg.rr_history('www.test.com', 'NS')
50
+ has_keys?(data, ['rrs_tf'])
51
+
52
+ # trying an unsupported query type should raise an error
53
+ lambda { @sg.rr_history('www.test.com', 'AFSDB') }.should raise_error
54
+ end
55
+
56
+ it "does related_domains() correctly" do
57
+ data = @sg.related_domains('www.test.com')
58
+ has_keys?(data, ['found', 'tb1'])
59
+ end
60
+
61
+ it "does cooccurrences() correctly" do
62
+ data = @sg.cooccurrences('www.test.com')
63
+ has_keys?(data, ['found', 'pfs2'])
64
+ end
65
+
66
+ it "does security() correctly" do
67
+ data = @sg.security('www.test.com')
68
+ keys = [
69
+ "dga_score",
70
+ "perplexity",
71
+ "entropy",
72
+ "securerank2",
73
+ "pagerank",
74
+ "asn_score",
75
+ "prefix_score",
76
+ "rip_score",
77
+ "fastflux",
78
+ "popularity",
79
+ "geodiversity",
80
+ "geodiversity_normalized",
81
+ "tld_geodiversity",
82
+ "geoscore",
83
+ "ks_test",
84
+ "handlings",
85
+ "attack",
86
+ "threat_type",
87
+ "found"
88
+ ]
89
+ has_keys?(data, keys)
90
+ end
91
+
92
+ it "does domain_tags() correctly" do
93
+ resp_json = @sg.domain_tags('bibikun.ru')
94
+ resp_json.each do |tag_entry|
95
+ has_keys?(tag_entry, ['category', 'period', 'url'])
96
+ has_keys?(tag_entry['period'], ['begin', 'end'])
97
+ end
98
+ end
99
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: investigate
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - skyler
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ description: Ruby API for the OpenDNS Security Graph
28
+ email:
29
+ - skyler@opendns.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - ".rspec"
36
+ - ".ruby-version"
37
+ - Gemfile
38
+ - README.md
39
+ - investigate.gemspec
40
+ - lib/investigate.rb
41
+ - spec/spec_helper.rb
42
+ - spec/tests.rb
43
+ homepage: https://github.com/dead10ck/ruby-investigate
44
+ licenses:
45
+ - MIT
46
+ metadata: {}
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project:
63
+ rubygems_version: 2.2.2
64
+ signing_key:
65
+ specification_version: 4
66
+ summary: Ruby API for the OpenDNS Security Graph
67
+ test_files:
68
+ - spec/spec_helper.rb
69
+ - spec/tests.rb