mihari 3.6.1 → 3.8.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -3
  3. data/lib/mihari/analyzers/base.rb +2 -17
  4. data/lib/mihari/analyzers/rule.rb +1 -0
  5. data/lib/mihari/analyzers/virustotal_intelligence.rb +63 -0
  6. data/lib/mihari/cli/analyzer.rb +2 -0
  7. data/lib/mihari/commands/passivetotal.rb +1 -0
  8. data/lib/mihari/commands/virustotal.rb +1 -0
  9. data/lib/mihari/commands/virustotal_intelligence.rb +22 -0
  10. data/lib/mihari/database.rb +13 -0
  11. data/lib/mihari/enrichers/base.rb +18 -0
  12. data/lib/mihari/enrichers/ipinfo.rb +49 -0
  13. data/lib/mihari/mixins/autonomous_system.rb +19 -0
  14. data/lib/mihari/models/artifact.rb +42 -3
  15. data/lib/mihari/models/autonomous_system.rb +18 -1
  16. data/lib/mihari/models/dns.rb +2 -0
  17. data/lib/mihari/models/geolocation.rb +21 -1
  18. data/lib/mihari/models/reverse_dns.rb +2 -0
  19. data/lib/mihari/models/whois.rb +1 -1
  20. data/lib/mihari/status.rb +7 -2
  21. data/lib/mihari/structs/ipinfo.rb +39 -0
  22. data/lib/mihari/structs/virustotal_intelligence.rb +75 -0
  23. data/lib/mihari/types.rb +13 -3
  24. data/lib/mihari/version.rb +1 -1
  25. data/lib/mihari/web/controllers/artifacts_controller.rb +27 -1
  26. data/lib/mihari/web/controllers/ip_address_controller.rb +4 -19
  27. data/lib/mihari/web/public/index.html +1 -1
  28. data/lib/mihari/web/public/redoc-static.html +7 -6
  29. data/lib/mihari/web/public/static/js/app.06d5cf1c.js +36 -0
  30. data/lib/mihari/web/public/static/js/app.06d5cf1c.js.map +1 -0
  31. data/lib/mihari.rb +42 -27
  32. data/mihari.gemspec +8 -6
  33. data/sig/lib/mihari/analyzers/base.rbs +1 -10
  34. data/sig/lib/mihari/analyzers/virustotal_intelligence.rbs +32 -0
  35. data/sig/lib/mihari/enrichers/base.rbs +12 -0
  36. data/sig/lib/mihari/enrichers/ipinfo.rbs +16 -0
  37. data/sig/lib/mihari/mixins/autonomous_system.rbs +14 -0
  38. data/sig/lib/mihari/models/artifact.rbs +11 -0
  39. data/sig/lib/mihari/models/autonomous_system.rbs +9 -0
  40. data/sig/lib/mihari/models/geolocation.rbs +9 -0
  41. data/sig/lib/mihari/structs/ipinfo.rbs +17 -0
  42. data/sig/lib/mihari/structs/virustotal_intelligence.rbs +33 -0
  43. data/sig/lib/mihari.rbs +2 -0
  44. metadata +57 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14d0c74e85fbf6ef624afefe7e948595586d6c00fa8bc32f211e60caee581fc3
4
- data.tar.gz: 9d5fde6d69f664efac0d6c56e6a0ba60adcad0edcfe45c69f285ffcaba8d11f0
3
+ metadata.gz: aac91d43689cb53dc0570bfed3cec57a07cbe88de0716530f2ea8bfac8f8d39d
4
+ data.tar.gz: 0f59bdc53cfa75e56884dd3497fa0492d3a41a3b7540cbdab1345ec5b301c69c
5
5
  SHA512:
6
- metadata.gz: 30597743e91f124388fbdf426199d97a00f92db9e525fe5725643d529d319ca670d1e9aa6eccff86c0844802157ca3d5c7db9b9afd925d6f0ac4d8b881c44949
7
- data.tar.gz: 9d199a3c2f6c7794214730de7c8db812e939c5ddd11ab06d1c6f28c3b8764b2881958b0684adb59e8516d0ac4b6a1dc66b19c5a593efaac9695cb6e317ce8105
6
+ metadata.gz: 30aef30fb14c7c1a50e75162141d1266b1ec5b847f6329935a221a90f59d37a2bed97c6a8aa4371962ab85b18c5ff23cf0417f08f9dc3320c737721ac1a07602
7
+ data.tar.gz: 1029878ec85cbdbe0a2c800b6b68cce99d45510818dde6b1d84a826022379cbe21fc57f490e3a77521136dbc22e8112b804d891892ea0a351e0d1db935b28b4b
data/README.md CHANGED
@@ -46,7 +46,7 @@ Mihari supports the following services by default.
46
46
  - [Shodan](https://shodan.io)
47
47
  - [Spyse](https://spyse.com)
48
48
  - [urlscan.io](https://urlscan.io)
49
- - [VirusTotal](http://virustotal.com)
49
+ - [VirusTotal](http://virustotal.com) & [VirusTotal Intelligence](https://www.virustotal.com/gui/intelligence-overview)
50
50
  - [ZoomEye](https://zoomeye.org)
51
51
 
52
52
  ## Docs
@@ -64,5 +64,3 @@ The gem is available as open source under the terms of the [MIT License](https:/
64
64
  ## Acknowledgement
65
65
 
66
66
  Mihari is proudly supported by [Tines.io](https://tines.io?utm_source=github&utm_medium=sponsorship&utm_campaign=ninoseki), The SOAR Platform for Enterprise Security Teams.
67
-
68
- $ bundle exec rbs -rpathname --repo=gem_rbs/gems -ractivesupport -ractionpack -ractivejob -ractivemodel -ractionview -ractiverecord -rrailties -I sig validate
@@ -8,6 +8,7 @@ module Mihari
8
8
  class Base
9
9
  extend Dry::Initializer
10
10
 
11
+ include Mixins::AutonomousSystem
11
12
  include Mixins::Configurable
12
13
  include Mixins::Retriable
13
14
 
@@ -111,9 +112,7 @@ module Mihari
111
112
  #
112
113
  def enriched_artifacts
113
114
  @enriched_artifacts ||= unique_artifacts.map do |artifact|
114
- artifact.enrich_whois
115
- artifact.enrich_dns
116
- artifact.enrich_reverse_dns
115
+ artifact.enrich_all
117
116
  artifact
118
117
  end
119
118
  end
@@ -141,20 +140,6 @@ module Mihari
141
140
  emitter.valid? ? emitter : nil
142
141
  end.compact
143
142
  end
144
-
145
- #
146
- # Normalize ASN value
147
- #
148
- # @param [String, Integer] asn
149
- #
150
- # @return [Integer]
151
- #
152
- def normalize_asn(asn)
153
- return asn if asn.is_a?(Integer)
154
- return asn.to_i unless asn.start_with?("AS")
155
-
156
- asn.delete_prefix("AS").to_i
157
- end
158
143
  end
159
144
  end
160
145
  end
@@ -42,6 +42,7 @@ module Mihari
42
42
  "spyse" => Spyse,
43
43
  "urlscan" => Urlscan,
44
44
  "virustotal" => VirusTotal,
45
+ "virustotal_intelligence" => VirusTotalIntelligence,
45
46
  "zoomeye" => ZoomEye
46
47
  }.freeze
47
48
 
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "virustotal"
4
+
5
+ module Mihari
6
+ module Analyzers
7
+ class VirusTotalIntelligence < Base
8
+ param :query
9
+ option :title, default: proc { "VirusTotal Intelligence search" }
10
+ option :description, default: proc { "query = #{query}" }
11
+ option :tags, default: proc { [] }
12
+
13
+ def initialize(*args, **kwargs)
14
+ super
15
+
16
+ @query = query
17
+ end
18
+
19
+ def artifacts
20
+ responses = search_witgh_cursor
21
+ responses.map do |response|
22
+ response.data.map(&:value)
23
+ end.flatten.compact.uniq
24
+ end
25
+
26
+ private
27
+
28
+ def configuration_keys
29
+ %w[virustotal_api_key]
30
+ end
31
+
32
+ #
33
+ # VT API
34
+ #
35
+ # @return [::VirusTotal::API]
36
+ #
37
+ def api
38
+ @api = ::VirusTotal::API.new(key: Mihari.config.virustotal_api_key)
39
+ end
40
+
41
+ #
42
+ # Search with cursor
43
+ #
44
+ # @return [Array<Structs::VirusTotalIntelligence::Response>]
45
+ #
46
+ def search_witgh_cursor
47
+ cursor = nil
48
+ responses = []
49
+
50
+ loop do
51
+ response = Structs::VirusTotalIntelligence::Response.from_dynamic!(api.intelligence.search(query, cursor: cursor))
52
+ responses << response
53
+
54
+ break if response.meta.cursor.nil?
55
+
56
+ cursor = response.meta.cursor
57
+ end
58
+
59
+ responses
60
+ end
61
+ end
62
+ end
63
+ end
@@ -14,6 +14,7 @@ require "mihari/commands/securitytrails"
14
14
  require "mihari/commands/shodan"
15
15
  require "mihari/commands/spyse"
16
16
  require "mihari/commands/urlscan"
17
+ require "mihari/commands/virustotal_intelligence"
17
18
  require "mihari/commands/virustotal"
18
19
  require "mihari/commands/zoomeye"
19
20
 
@@ -42,6 +43,7 @@ module Mihari
42
43
  include Mihari::Commands::Spyse
43
44
  include Mihari::Commands::Urlscan
44
45
  include Mihari::Commands::VirusTotal
46
+ include Mihari::Commands::VirusTotalIntelligence
45
47
  include Mihari::Commands::ZoomEye
46
48
  end
47
49
  end
@@ -14,6 +14,7 @@ module Mihari
14
14
  run_analyzer Analyzers::PassiveTotal, query: indicator, options: options
15
15
  end
16
16
  end
17
+ map "pt" => :passivetotal
17
18
  end
18
19
  end
19
20
  end
@@ -14,6 +14,7 @@ module Mihari
14
14
  run_analyzer Analyzers::VirusTotal, query: indiactor, options: options
15
15
  end
16
16
  end
17
+ map "vt" => :virustotal
17
18
  end
18
19
  end
19
20
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Commands
5
+ module VirusTotalIntelligence
6
+ def self.included(thor)
7
+ thor.class_eval do
8
+ desc "virustotal_intelligence [QUERY]", "VirusTotal Intelligence search"
9
+ method_option :title, type: :string, desc: "title"
10
+ method_option :description, type: :string, desc: "description"
11
+ method_option :tags, type: :array, desc: "tags"
12
+ def virustotal_intelligence(query)
13
+ with_error_handling do
14
+ run_analyzer Analyzers::VirusTotalIntelligence, query: query, options: options
15
+ end
16
+ end
17
+ map "vt_intel" => :virustotal_intelligence
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -74,6 +74,17 @@ class EnrichmentsSchema < ActiveRecord::Migration[6.1]
74
74
  end
75
75
  end
76
76
 
77
+ class EnrichmentCreatedAtSchema < ActiveRecord::Migration[6.1]
78
+ def change
79
+ # Add created_at column because now it is able to enrich an atrifact after the creation
80
+ add_column :autonomous_systems, :created_at, :datetime, if_not_exists: true
81
+ add_column :geolocations, :created_at, :datetime, if_not_exists: true
82
+ add_column :whois_records, :created_at, :datetime, if_not_exists: true
83
+ add_column :dns_records, :created_at, :datetime, if_not_exists: true
84
+ add_column :reverse_dns_names, :created_at, :datetime, if_not_exists: true
85
+ end
86
+ end
87
+
77
88
  def adapter
78
89
  return "postgresql" if Mihari.config.database.start_with?("postgresql://", "postgres://")
79
90
  return "mysql2" if Mihari.config.database.start_with?("mysql2://")
@@ -101,6 +112,7 @@ module Mihari
101
112
  InitialSchema.migrate(:up)
102
113
  AddeSourceToArtifactSchema.migrate(:up)
103
114
  EnrichmentsSchema.migrate(:up)
115
+ EnrichmentCreatedAtSchema.migrate(:up)
104
116
  rescue StandardError
105
117
  # Do nothing
106
118
  end
@@ -116,6 +128,7 @@ module Mihari
116
128
  InitialSchema.migrate(:down)
117
129
  AddeSourceToArtifactSchema.migrate(:down)
118
130
  EnrichmentsSchema.migrate(:down)
131
+ EnrichmentCreatedAtSchema.migrate(:down)
119
132
  end
120
133
  end
121
134
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Enrichers
5
+ class Base
6
+ include Mixins::Configurable
7
+
8
+ def self.inherited(child)
9
+ Mihari.enrichers << child
10
+ end
11
+
12
+ # @return [Boolean]
13
+ def valid?
14
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,49 @@
1
+ require "http"
2
+ require "json"
3
+ require "memist"
4
+
5
+ module Mihari
6
+ module Enrichers
7
+ class IPInfo < Base
8
+ # @return [Boolean]
9
+ def valid?
10
+ Mihari.config.ipinfo_api_key.nil?
11
+ end
12
+
13
+ private
14
+
15
+ def configuration_keys
16
+ %w[ipinfo_api_key]
17
+ end
18
+
19
+ class << self
20
+ include Memist::Memoizable
21
+
22
+ #
23
+ # Query IPInfo
24
+ #
25
+ # @param [String] ip
26
+ #
27
+ # @return [Mihari::Structs::IPInfo::Response, nil]
28
+ #
29
+ def query(ip)
30
+ headers = {}
31
+ token = Mihari.config.ipinfo_api_key
32
+ unless token.nil?
33
+ headers[:authorization] = "Bearer #{token}"
34
+ end
35
+
36
+ begin
37
+ res = HTTP.headers(headers).get("https://ipinfo.io/#{ip}/json")
38
+ data = JSON.parse(res.body.to_s)
39
+
40
+ Structs::IPInfo::Response.from_dynamic! data
41
+ rescue HTTP::Error
42
+ nil
43
+ end
44
+ end
45
+ memoize :query
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,19 @@
1
+ module Mihari
2
+ module Mixins
3
+ module AutonomousSystem
4
+ #
5
+ # Normalize ASN value
6
+ #
7
+ # @param [String, Integer] asn
8
+ #
9
+ # @return [Integer]
10
+ #
11
+ def normalize_asn(asn)
12
+ return asn if asn.is_a?(Integer)
13
+ return asn.to_i unless asn.start_with?("AS")
14
+
15
+ asn.delete_prefix("AS").to_i
16
+ end
17
+ end
18
+ end
19
+ end
@@ -16,6 +16,8 @@ end
16
16
 
17
17
  module Mihari
18
18
  class Artifact < ActiveRecord::Base
19
+ belongs_to :alert
20
+
19
21
  has_one :autonomous_system, dependent: :destroy
20
22
  has_one :geolocation, dependent: :destroy
21
23
  has_one :whois_record, dependent: :destroy
@@ -80,6 +82,35 @@ module Mihari
80
82
  self.reverse_dns_names = ReverseDnsName.build_by_ip(data)
81
83
  end
82
84
 
85
+ #
86
+ # Enrich(add) geolocation
87
+ #
88
+ def enrich_geolocation
89
+ return unless can_enrich_geolocation?
90
+
91
+ self.geolocation = Geolocation.build_by_ip(data)
92
+ end
93
+
94
+ #
95
+ # Enrich(add) geolocation
96
+ #
97
+ def enrich_autonomous_system
98
+ return unless can_enrich_autonomous_system?
99
+
100
+ self.autonomous_system = AutonomousSystem.build_by_ip(data)
101
+ end
102
+
103
+ #
104
+ # Enrich all the enrichable relationships of the artifact
105
+ #
106
+ def enrich_all
107
+ enrich_autonomous_system
108
+ enrich_dns
109
+ enrich_geolocation
110
+ enrich_reverse_dns
111
+ enrich_whois
112
+ end
113
+
83
114
  private
84
115
 
85
116
  def normalize_as_domain(url_or_domain)
@@ -89,15 +120,23 @@ module Mihari
89
120
  end
90
121
 
91
122
  def can_enrich_whois?
92
- %w[domain url].include? data_type
123
+ %w[domain url].include?(data_type) && whois_record.nil?
93
124
  end
94
125
 
95
126
  def can_enrich_dns?
96
- %w[domain url].include? data_type
127
+ %w[domain url].include?(data_type) && dns_records.empty?
97
128
  end
98
129
 
99
130
  def can_enrich_revese_dns?
100
- data_type == "ip"
131
+ data_type == "ip" && reverse_dns_names.empty?
132
+ end
133
+
134
+ def can_enrich_geolocation?
135
+ data_type == "ip" && geolocation.nil?
136
+ end
137
+
138
+ def can_enrich_autonomous_system?
139
+ data_type == "ip" && autonomous_system.nil?
101
140
  end
102
141
  end
103
142
  end
@@ -4,6 +4,23 @@ require "active_record"
4
4
 
5
5
  module Mihari
6
6
  class AutonomousSystem < ActiveRecord::Base
7
- has_one :artifact, dependent: :destroy
7
+ belongs_to :artifact
8
+
9
+ class << self
10
+ #
11
+ # Build AS
12
+ #
13
+ # @param [String] ip
14
+ #
15
+ # @return [Mihari::AutonomousSystem, nil]
16
+ #
17
+ def build_by_ip(ip)
18
+ res = Enrichers::IPInfo.query(ip)
19
+
20
+ return nil if res.nil? || res.asn.nil?
21
+
22
+ new(asn: res.asn)
23
+ end
24
+ end
8
25
  end
9
26
  end
@@ -5,6 +5,8 @@ require "resolv"
5
5
 
6
6
  module Mihari
7
7
  class DnsRecord < ActiveRecord::Base
8
+ belongs_to :artifact
9
+
8
10
  class << self
9
11
  #
10
12
  # Build DNS records
@@ -1,9 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_record"
4
+ require "normalize_country"
4
5
 
5
6
  module Mihari
6
7
  class Geolocation < ActiveRecord::Base
7
- has_one :artifact, dependent: :destroy
8
+ belongs_to :artifact
9
+
10
+ class << self
11
+ #
12
+ # Build Geolocation
13
+ #
14
+ # @param [String] ip
15
+ #
16
+ # @return [Mihari::Geolocation, nil]
17
+ #
18
+ def build_by_ip(ip)
19
+ res = Enrichers::IPInfo.query(ip)
20
+
21
+ unless res.nil?
22
+ return new(country: NormalizeCountry(res.country_code, to: :short), country_code: res.country_code)
23
+ end
24
+
25
+ nil
26
+ end
27
+ end
8
28
  end
9
29
  end
@@ -5,6 +5,8 @@ require "resolv"
5
5
 
6
6
  module Mihari
7
7
  class ReverseDnsName < ActiveRecord::Base
8
+ belongs_to :artifact
9
+
8
10
  class << self
9
11
  #
10
12
  # Build reverse DNS names
@@ -6,7 +6,7 @@ require "public_suffix"
6
6
 
7
7
  module Mihari
8
8
  class WhoisRecord < ActiveRecord::Base
9
- has_one :artifact, dependent: :destroy
9
+ belongs_to :artifact
10
10
 
11
11
  @memo = {}
12
12
 
data/lib/mihari/status.rb CHANGED
@@ -18,7 +18,7 @@ module Mihari
18
18
  # @return [Array<Hash>]
19
19
  #
20
20
  def statuses
21
- (Mihari.analyzers + Mihari.emitters).map do |klass|
21
+ (Mihari.analyzers + Mihari.emitters + Mihari.enrichers).map do |klass|
22
22
  name = klass.to_s.split("::").last.to_s
23
23
 
24
24
  [name, build_status(klass)]
@@ -36,11 +36,16 @@ module Mihari
36
36
  return nil if klass == Mihari::Analyzers::Rule
37
37
 
38
38
  is_analyzer = klass.ancestors.include?(Mihari::Analyzers::Base)
39
+ is_emitter = klass.ancestors.include?(Mihari::Emitters::Base)
40
+ is_enricher = klass.ancestors.include?(Mihari::Enrichers::Base)
39
41
 
40
42
  instance = is_analyzer ? klass.new("dummy") : klass.new
41
43
  is_configured = instance.configured?
42
44
  values = instance.configuration_values
43
- type = is_analyzer ? "Analyzer" : "Emitter"
45
+
46
+ type = "Analyzer"
47
+ type = "Emitter" if is_emitter
48
+ type = "Enricher" if is_enricher
44
49
 
45
50
  values ? { is_configured: is_configured, values: values, type: type } : nil
46
51
  rescue ArgumentError => _e
@@ -0,0 +1,39 @@
1
+ require "json"
2
+ require "dry/struct"
3
+
4
+ module Mihari
5
+ module Structs
6
+ module IPInfo
7
+ class Response < Dry::Struct
8
+ attribute :ip, Types::String
9
+ attribute :hostname, Types::String.optional
10
+ attribute :loc, Types::String
11
+ attribute :country_code, Types::String
12
+ attribute :asn, Types::Integer.optional
13
+
14
+ class << self
15
+ include Mixins::AutonomousSystem
16
+
17
+ def from_dynamic!(d)
18
+ d = Types::Hash[d]
19
+
20
+ asn = nil
21
+ org = d["org"]
22
+ unless org.nil?
23
+ asn = org.split.first
24
+ asn = normalize_asn(asn)
25
+ end
26
+
27
+ new(
28
+ ip: d.fetch("ip"),
29
+ loc: d.fetch("loc"),
30
+ hostname: d["hostname"],
31
+ country_code: d.fetch("country"),
32
+ asn: asn
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,75 @@
1
+ require "json"
2
+ require "dry/struct"
3
+
4
+ module Mihari
5
+ module Structs
6
+ module VirusTotalIntelligence
7
+ class ContextAttributes < Dry::Struct
8
+ attribute :url, Types.Array(Types::String).optional
9
+
10
+ def self.from_dynamic!(d)
11
+ d = Types::Hash[d]
12
+ new(
13
+ url: d["url"]
14
+ )
15
+ end
16
+ end
17
+
18
+ class Datum < Dry::Struct
19
+ attribute :type, Types::String
20
+ attribute :id, Types::String
21
+ attribute :context_attributes, ContextAttributes.optional
22
+
23
+ def value
24
+ case type
25
+ when "file"
26
+ id
27
+ when "url"
28
+ (context_attributes.url || []).first
29
+ when "domain"
30
+ id
31
+ when "ip_address"
32
+ id
33
+ end
34
+ end
35
+
36
+ def self.from_dynamic!(d)
37
+ d = Types::Hash[d]
38
+
39
+ context_attributes = nil
40
+ context_attributes = ContextAttributes.from_dynamic!(d.fetch("context_attributes")) if d.key?("context_attributes")
41
+
42
+ new(
43
+ type: d.fetch("type"),
44
+ id: d.fetch("id"),
45
+ context_attributes: context_attributes
46
+ )
47
+ end
48
+ end
49
+
50
+ class Meta < Dry::Struct
51
+ attribute :cursor, Types::String.optional
52
+
53
+ def self.from_dynamic!(d)
54
+ d = Types::Hash[d]
55
+ new(
56
+ cursor: d["cursor"]
57
+ )
58
+ end
59
+ end
60
+
61
+ class Response < Dry::Struct
62
+ attribute :meta, Meta
63
+ attribute :data, Types.Array(Datum)
64
+
65
+ def self.from_dynamic!(d)
66
+ d = Types::Hash[d]
67
+ new(
68
+ meta: Meta.from_dynamic!(d.fetch("meta")),
69
+ data: d.fetch("data").map { |x| Datum.from_dynamic!(x) }
70
+ )
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
data/lib/mihari/types.rb CHANGED
@@ -13,9 +13,19 @@ module Mihari
13
13
  DataTypes = Types::String.enum(*ALLOWED_DATA_TYPES)
14
14
 
15
15
  AnalyzerTypes = Types::String.enum(
16
- "binaryedge", "censys", "circl", "dnpedia", "dnstwister",
17
- "onyphe", "otx", "passivetotal", "pulsedive", "securitytrails",
18
- "shodan", "virustotal"
16
+ "binaryedge",
17
+ "censys",
18
+ "circl",
19
+ "dnpedia",
20
+ "dnstwister",
21
+ "onyphe",
22
+ "otx",
23
+ "passivetotal",
24
+ "pulsedive",
25
+ "securitytrails",
26
+ "shodan",
27
+ "virustotal_intelligence",
28
+ "virustotal"
19
29
  )
20
30
  end
21
31
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "3.6.1"
4
+ VERSION = "3.8.0"
5
5
  end