mihari 4.6.1 → 4.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 491cb9d0477c4101251c1f3e5705328008a196920efb41c239048247937f21f4
4
- data.tar.gz: 14bcfd11b8871a759e70f6658cf2773dadc6afe7ffde44dbbffaef99961b8e00
3
+ metadata.gz: '091892853042ab3f1010c89b943eb2a885370da2d619016f3f3cd9dcb59e80cf'
4
+ data.tar.gz: 119ccbb407a49c741a4bf6c7cfafc7cd99855c3af950af9d0f1dc3735fc24672
5
5
  SHA512:
6
- metadata.gz: d833915545629ade609ec994e6139387fd66247fa1c48fdbe4e3eab01679fb42820e3b07cb95fdbb8cff092753394f1dfa9aaa4459259837c2c0d7d5f2f855ed
7
- data.tar.gz: dcbb112faa805b27157ec72d0f3544031c7e7789e855eb082a69a76216d0fcd644013ade95aea28ae138ebfb3bc8eb90d8fb922c83999d292c12b78d15acfe5c
6
+ metadata.gz: 5364837634a6cde1b370db5613e745f05b40bf7321a5b7fcc4a2c7d32b1d395fa45e4472ef2a5f9f28d664f0b45e31d0554acec7bb641a21ce179ebf70bf9317
7
+ data.tar.gz: 57ca2f920db2da9e8c9a10f59aa81984dff0a81f0073ba839c351f3fe5e7979358ce44d87f48adcffd7df1bf7268bab178fec82731f72d62c24aa9ce04eed026
@@ -51,6 +51,7 @@ module Mihari
51
51
  option :disallowed_data_values, default: proc { [] }
52
52
 
53
53
  option :emitters, optional: true
54
+ option :enrichers, optional: true
54
55
 
55
56
  attr_reader :source
56
57
 
@@ -60,6 +61,7 @@ module Mihari
60
61
  @source = id
61
62
 
62
63
  @emitters = emitters || DEFAULT_EMITTERS
64
+ @enrichers = enrichers || DEFAULT_ENRICHERS
63
65
 
64
66
  validate_analyzer_configurations
65
67
  end
@@ -112,6 +114,21 @@ module Mihari
112
114
  end
113
115
  end
114
116
 
117
+ #
118
+ # Enriched artifacts
119
+ #
120
+ # @return [Array<Mihari::Artifact>]
121
+ #
122
+ def enriched_artifacts
123
+ @enriched_artifacts ||= Parallel.map(unique_artifacts) do |artifact|
124
+ enrichers.each do |enricher|
125
+ artifact.enrich_by_enricher(enricher[:enricher])
126
+ end
127
+
128
+ artifact
129
+ end
130
+ end
131
+
115
132
  #
116
133
  # Normalized disallowed data values
117
134
  #
@@ -4,4 +4,6 @@ module Mihari
4
4
  ALLOWED_DATA_TYPES = ["hash", "ip", "domain", "url", "mail"].freeze
5
5
 
6
6
  DEFAULT_EMITTERS = ["database", "misp", "slack", "the_hive", "webhook"].map { |name| { emitter: name } }.freeze
7
+
8
+ DEFAULT_ENRICHERS = ["whois", "ipinfo", "shodan", "google_public_dns"].map { |name| { enricher: name } }.freeze
7
9
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/https"
4
+
5
+ module Mihari
6
+ module Enrichers
7
+ class GooglePublicDNS < Base
8
+ # @return [Boolean]
9
+ def valid?
10
+ true
11
+ end
12
+
13
+ class << self
14
+ #
15
+ # Query Google Public DNS
16
+ #
17
+ # @param [String] name
18
+ # @param [String] resource_type
19
+ #
20
+ # @return [Mihari::Structs::Shodan::GooglePublicDNS::Response, nil]
21
+ #
22
+ def query(name, resource_type)
23
+ url = "https://dns.google/resolve"
24
+ params = { name: name, type: resource_type }
25
+ res = HTTP.get(url, params: params)
26
+
27
+ data = JSON.parse(res.body.to_s)
28
+
29
+ Structs::GooglePublicDNS::Response.from_dynamic! data
30
+ rescue HTTPError
31
+ nil
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "whois-parser"
4
+
5
+ module Mihari
6
+ module Enrichers
7
+ class Whois < Base
8
+ @memo = {}
9
+
10
+ # @return [Boolean]
11
+ def valid?
12
+ true
13
+ end
14
+
15
+ class << self
16
+ #
17
+ # Query IAIA Whois API
18
+ #
19
+ # @param [String] name
20
+ #
21
+ # @return [Mihari::WhoisRecord, nil]
22
+ #
23
+ def query(domain)
24
+ domain = PublicSuffix.domain(domain)
25
+
26
+ # check memo
27
+ if @memo.key?(domain)
28
+ whois_record = @memo[domain]
29
+ # return clone of the record
30
+ return whois_record.dup
31
+ end
32
+
33
+ record = ::Whois.whois(domain)
34
+ parser = record.parser
35
+
36
+ return nil if parser.available?
37
+
38
+ whois_record = WhoisRecord.new(
39
+ domain: domain,
40
+ created_on: get_created_on(parser),
41
+ updated_on: get_updated_on(parser),
42
+ expires_on: get_expires_on(parser),
43
+ registrar: get_registrar(parser),
44
+ contacts: get_contacts(parser)
45
+ )
46
+ # set memo
47
+ @memo[domain] = whois_record
48
+ whois_record
49
+ rescue ::Whois::Error, ::Whois::ParserError, Timeout::Error
50
+ nil
51
+ end
52
+
53
+ def reset_cache
54
+ @memo = {}
55
+ end
56
+
57
+ private
58
+
59
+ #
60
+ # Get created_on
61
+ #
62
+ # @param [::Whois::Parser:] parser
63
+ #
64
+ # @return [Date, nil]
65
+ #
66
+ def get_created_on(parser)
67
+ parser.created_on
68
+ rescue ::Whois::AttributeNotImplemented
69
+ nil
70
+ end
71
+
72
+ #
73
+ # Get updated_on
74
+ #
75
+ # @param [::Whois::Parser:] parser
76
+ #
77
+ # @return [Date, nil]
78
+ #
79
+ def get_updated_on(parser)
80
+ parser.updated_on
81
+ rescue ::Whois::AttributeNotImplemented
82
+ nil
83
+ end
84
+
85
+ #
86
+ # Get expires_on
87
+ #
88
+ # @param [::Whois::Parser:] parser
89
+ #
90
+ # @return [Date, nil]
91
+ #
92
+ def get_expires_on(parser)
93
+ parser.expires_on
94
+ rescue ::Whois::AttributeNotImplemented
95
+ nil
96
+ end
97
+
98
+ #
99
+ # Get registrar
100
+ #
101
+ # @param [::Whois::Parser:] parser
102
+ #
103
+ # @return [Hash, nil]
104
+ #
105
+ def get_registrar(parser)
106
+ parser.registrar&.to_h
107
+ rescue ::Whois::AttributeNotImplemented
108
+ nil
109
+ end
110
+
111
+ #
112
+ # Get contacts
113
+ #
114
+ # @param [::Whois::Parser:] parser
115
+ #
116
+ # @return [Array[Hash], nil]
117
+ #
118
+ def get_contacts(parser)
119
+ parser.contacts.map(&:to_h)
120
+ rescue ::Whois::AttributeNotImplemented
121
+ nil
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
data/lib/mihari/http.rb CHANGED
@@ -44,8 +44,8 @@ module Mihari
44
44
  end
45
45
 
46
46
  class << self
47
- def get(uri, headers: {}, payload: {})
48
- client = new(uri, headers: headers, payload: payload)
47
+ def get(uri, headers: {}, params: {})
48
+ client = new(uri, headers: headers, payload: params)
49
49
  client.get
50
50
  end
51
51
 
@@ -135,6 +135,36 @@ module Mihari
135
135
  enrich_cpes
136
136
  end
137
137
 
138
+ ENRICH_METHODS_BY_ENRICHER = {
139
+ whois: [
140
+ :enrich_whois
141
+ ],
142
+ ipinfo: [
143
+ :enrich_autonomous_system,
144
+ :enrich_geolocation
145
+ ],
146
+ shodan: [
147
+ :enrich_ports,
148
+ :enrich_cpes,
149
+ :enrich_reverse_dns
150
+ ],
151
+ google_public_dns: [
152
+ :enrich_dns
153
+ ]
154
+ }.freeze
155
+
156
+ #
157
+ # Enrich by name of enricher
158
+ #
159
+ # @param [String] enricher
160
+ #
161
+ def enrich_by_enricher(enricher)
162
+ methods = ENRICH_METHODS_BY_ENRICHER[enricher.downcase.to_sym] || []
163
+ methods.each do |method|
164
+ send(method) if respond_to?(method)
165
+ end
166
+ end
167
+
138
168
  private
139
169
 
140
170
  def normalize_as_domain(url_or_domain)
@@ -13,14 +13,7 @@ module Mihari
13
13
  # @return [Array<Mihari::DnsRecord>]
14
14
  #
15
15
  def build_by_domain(domain)
16
- resource_types = [
17
- Resolv::DNS::Resource::IN::A,
18
- Resolv::DNS::Resource::IN::AAAA,
19
- Resolv::DNS::Resource::IN::CNAME,
20
- Resolv::DNS::Resource::IN::TXT,
21
- Resolv::DNS::Resource::IN::NS
22
- ]
23
-
16
+ resource_types = %w[A AAAA CNAME TXT NS]
24
17
  resource_types.map do |resource_type|
25
18
  get_values domain, resource_type
26
19
  rescue Resolv::ResolvError
@@ -31,20 +24,11 @@ module Mihari
31
24
  private
32
25
 
33
26
  def get_values(domain, resource_type)
34
- resources = Resolv::DNS.new.getresources(domain, resource_type)
35
- resource_name = resource_type.to_s.split("::").last
27
+ response = Enrichers::GooglePublicDNS.query(domain, resource_type)
28
+ answers = response.answers || []
36
29
 
37
- resources.filter_map do |resource|
38
- # A, AAAA
39
- if resource.respond_to?(:address)
40
- new(resource: resource_name, value: resource.address.to_s)
41
- # CNAME, NS
42
- elsif resource.respond_to?(:name)
43
- new(resource: resource_name, value: resource.name.to_s)
44
- # TXT
45
- elsif resource.respond_to?(:data)
46
- new(resource: resource_name, value: resource.data.to_s)
47
- end
30
+ answers.filter_map do |answer|
31
+ new(resource: answer.resource_type, value: answer.data)
48
32
  end
49
33
  end
50
34
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "whois-parser"
4
-
5
3
  module Mihari
6
4
  class WhoisRecord < ActiveRecord::Base
7
5
  belongs_to :artifact
@@ -17,100 +15,7 @@ module Mihari
17
15
  # @return [WhoisRecord, nil]
18
16
  #
19
17
  def build_by_domain(domain)
20
- domain = PublicSuffix.domain(domain)
21
-
22
- # check memo
23
- if @memo.key?(domain)
24
- whois_record = @memo[domain]
25
- # return clone of the record
26
- return whois_record.dup
27
- end
28
-
29
- record = Whois.whois(domain)
30
- parser = record.parser
31
-
32
- return nil if parser.available?
33
-
34
- whois_record = new(
35
- domain: domain,
36
- created_on: get_created_on(parser),
37
- updated_on: get_updated_on(parser),
38
- expires_on: get_expires_on(parser),
39
- registrar: get_registrar(parser),
40
- contacts: get_contacts(parser)
41
- )
42
- # set memo
43
- @memo[domain] = whois_record
44
- whois_record
45
- rescue Whois::Error, Whois::ParserError, Timeout::Error
46
- nil
47
- end
48
-
49
- private
50
-
51
- #
52
- # Get created_on
53
- #
54
- # @param [::Whois::Parser:] parser
55
- #
56
- # @return [Date, nil]
57
- #
58
- def get_created_on(parser)
59
- parser.created_on
60
- rescue ::Whois::AttributeNotImplemented
61
- nil
62
- end
63
-
64
- #
65
- # Get updated_on
66
- #
67
- # @param [::Whois::Parser:] parser
68
- #
69
- # @return [Date, nil]
70
- #
71
- def get_updated_on(parser)
72
- parser.updated_on
73
- rescue ::Whois::AttributeNotImplemented
74
- nil
75
- end
76
-
77
- #
78
- # Get expires_on
79
- #
80
- # @param [::Whois::Parser:] parser
81
- #
82
- # @return [Date, nil]
83
- #
84
- def get_expires_on(parser)
85
- parser.expires_on
86
- rescue ::Whois::AttributeNotImplemented
87
- nil
88
- end
89
-
90
- #
91
- # Get registrar
92
- #
93
- # @param [::Whois::Parser:] parser
94
- #
95
- # @return [Hash, nil]
96
- #
97
- def get_registrar(parser)
98
- parser.registrar&.to_h
99
- rescue ::Whois::AttributeNotImplemented
100
- nil
101
- end
102
-
103
- #
104
- # Get contacts
105
- #
106
- # @param [::Whois::Parser:] parser
107
- #
108
- # @return [Array[Hash], nil]
109
- #
110
- def get_contacts(parser)
111
- parser.contacts.map(&:to_h)
112
- rescue ::Whois::AttributeNotImplemented
113
- nil
18
+ Enrichers::Whois.query domain
114
19
  end
115
20
  end
116
21
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Schemas
5
+ Enricher = Dry::Schema.Params do
6
+ required(:enricher).value(Types::EnricherTypes)
7
+ end
8
+ end
9
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "mihari/schemas/analyzer"
4
4
  require "mihari/schemas/emitter"
5
+ require "mihari/schemas/enricher"
5
6
 
6
7
  module Mihari
7
8
  module Schemas
@@ -20,6 +21,8 @@ module Mihari
20
21
 
21
22
  optional(:emitters).value(:array).each { Emitter | MISP | TheHive | Slack | HTTP }
22
23
 
24
+ optional(:enrichers).value(:array).each(Enricher)
25
+
23
26
  optional(:allowed_data_types).value(array[Types::DataTypes]).default(ALLOWED_DATA_TYPES)
24
27
  optional(:disallowed_data_values).value(array[:string]).default([])
25
28
 
@@ -35,6 +38,9 @@ module Mihari
35
38
  emitters = h[:emitters]
36
39
  h[:emitters] = emitters || DEFAULT_EMITTERS
37
40
 
41
+ enrichers = h[:enrichers]
42
+ h[:enrichers] = enrichers || DEFAULT_ENRICHERS
43
+
38
44
  h
39
45
  end
40
46
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Structs
5
+ module GooglePublicDNS
6
+ INT_TYPE_TO_TYPE = {
7
+ 1 => "A",
8
+ 2 => "NS",
9
+ 5 => "CNAME",
10
+ 16 => "TXT",
11
+ 28 => "AAAA"
12
+ }
13
+
14
+ class Answer < Dry::Struct
15
+ attribute :name, Types::String
16
+ attribute :data, Types::String
17
+ attribute :resource_type, Types::String
18
+
19
+ def self.from_dynamic!(d)
20
+ d = Types::Hash[d]
21
+ resource_type = INT_TYPE_TO_TYPE[d.fetch("type")]
22
+ new(
23
+ name: d.fetch("name"),
24
+ data: d.fetch("data"),
25
+ resource_type: resource_type
26
+ )
27
+ end
28
+ end
29
+
30
+ class Response < Dry::Struct
31
+ attribute :answers, Types.Array(Answer)
32
+
33
+ def self.from_dynamic!(d)
34
+ d = Types::Hash[d]
35
+ new(
36
+ answers: d.fetch("Answer", []).map { |x| Answer.from_dynamic!(x) }
37
+ )
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -88,7 +88,7 @@ module Mihari
88
88
 
89
89
  raise RuleValidationError, error_messages.join("\n") if errors?
90
90
 
91
- raise RuleValidationError, "Something wrong with queries or emitters." unless @no_method_error.nil?
91
+ raise RuleValidationError, "Something wrong with queries, emitters or enrichers." unless @no_method_error.nil?
92
92
  end
93
93
 
94
94
  def [](key)
@@ -150,6 +150,7 @@ module Mihari
150
150
  allowed_data_types: self[:allowed_data_types],
151
151
  disallowed_data_values: self[:disallowed_data_values],
152
152
  emitters: self[:emitters],
153
+ enrichers: self[:enrichers],
153
154
  id: id
154
155
  )
155
156
  analyzer.ignore_old_artifacts = self[:ignore_old_artifacts]
data/lib/mihari/types.rb CHANGED
@@ -21,5 +21,12 @@ module Mihari
21
21
  "database",
22
22
  "webhook"
23
23
  )
24
+
25
+ EnricherTypes = Types::String.enum(
26
+ "whois",
27
+ "ipinfo",
28
+ "shodan",
29
+ "google_public_dns"
30
+ )
24
31
  end
25
32
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "4.6.1"
4
+ VERSION = "4.7.0"
5
5
  end
data/lib/mihari.rb CHANGED
@@ -173,6 +173,7 @@ require "mihari/types"
173
173
  # Structs
174
174
  require "mihari/structs/alert"
175
175
  require "mihari/structs/censys"
176
+ require "mihari/structs/google_public_dns"
176
177
  require "mihari/structs/greynoise"
177
178
  require "mihari/structs/ipinfo"
178
179
  require "mihari/structs/onyphe"
@@ -189,8 +190,10 @@ require "mihari/schemas/rule"
189
190
 
190
191
  # Enrichers
191
192
  require "mihari/enrichers/base"
193
+ require "mihari/enrichers/google_public_dns"
192
194
  require "mihari/enrichers/ipinfo"
193
195
  require "mihari/enrichers/shodan"
196
+ require "mihari/enrichers/whois"
194
197
 
195
198
  # Models
196
199
  require "mihari/models/alert"
data/mihari.gemspec CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
 
30
30
  spec.add_development_dependency "bundler", "~> 2.3"
31
31
  spec.add_development_dependency "coveralls_reborn", "~> 0.24"
32
- spec.add_development_dependency "fakefs", "~> 1.4"
32
+ spec.add_development_dependency "fakefs", "~> 1.5"
33
33
  spec.add_development_dependency "mysql2", "~> 0.5"
34
34
  spec.add_development_dependency "overcommit", "~> 0.59"
35
35
  spec.add_development_dependency "pg", "~> 1.3"
@@ -40,7 +40,7 @@ Gem::Specification.new do |spec|
40
40
  spec.add_development_dependency "rspec", "~> 3.11"
41
41
  spec.add_development_dependency "simplecov-lcov", "~> 0.8.0"
42
42
  spec.add_development_dependency "standard", "~> 1.12"
43
- spec.add_development_dependency "steep", "~> 0.52"
43
+ spec.add_development_dependency "steep", "~> 1.0"
44
44
  spec.add_development_dependency "timecop", "~> 0.9"
45
45
  spec.add_development_dependency "vcr", "~> 6.1"
46
46
  spec.add_development_dependency "webmock", "~> 3.14"
@@ -58,9 +58,9 @@ Gem::Specification.new do |spec|
58
58
  spec.add_dependency "dry-container", "0.9.0"
59
59
  spec.add_dependency "dry-files", "0.1.0"
60
60
  spec.add_dependency "dry-initializer", "3.1.1"
61
- spec.add_dependency "dry-schema", "1.9.1"
61
+ spec.add_dependency "dry-schema", "1.9.2"
62
62
  spec.add_dependency "dry-struct", "1.4.0"
63
- spec.add_dependency "dry-validation", "1.8.0"
63
+ spec.add_dependency "dry-validation", "1.8.1"
64
64
  spec.add_dependency "email_address", "0.2.3"
65
65
  spec.add_dependency "grape", "1.6.2"
66
66
  spec.add_dependency "grape-entity", "0.10.1"
@@ -84,7 +84,7 @@ Gem::Specification.new do |spec|
84
84
  spec.add_dependency "public_suffix", "4.0.7"
85
85
  spec.add_dependency "pulsedive", "0.1.5"
86
86
  spec.add_dependency "puma", "5.6.4"
87
- spec.add_dependency "rack", "2.2.3"
87
+ spec.add_dependency "rack", "2.2.3.1"
88
88
  spec.add_dependency "rack-contrib", "2.3.0"
89
89
  spec.add_dependency "rack-cors", "1.1.1"
90
90
  spec.add_dependency "securitytrails", "1.0.0"
@@ -0,0 +1,18 @@
1
+ module Mihari
2
+ module Enrichers
3
+ class GooglePublicDNS < Base
4
+ # @return [Boolean]
5
+ def valid?: () -> true
6
+
7
+ #
8
+ # Query Google Public DNS
9
+ #
10
+ # @param [String] name
11
+ # @param [String] resource_type
12
+ #
13
+ # @return [Mihari::Structs::Shodan::GooglePublicDNS::Response, nil]
14
+ #
15
+ def self.query: (String name, String resource_type) -> Mihari::Structs::Shodan::GooglePublicDNS::Response?
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ module Mihari
2
+ module Structs
3
+ module GooglePublicDNS
4
+ INT_TYPE_TO_TYPE: { 1 => "A", 2 => "NS", 5 => "CNAME", 16 => "TXT", 28 => "AAAA" }
5
+
6
+ class Answer < Dry::Struct
7
+ attr_reader name: String
8
+ attr_reader data: String
9
+ attr_reader resource_type: String
10
+
11
+ def self.from_dynamic!: (Hash[(String | Symbol), untyped] d) -> Mihari::Structs::GooglePublicDNS::Answer
12
+ end
13
+
14
+ class Response < Dry::Struct
15
+ attr_reader answers: Array[Mihari::Structs::GooglePublicDNS::Answer]
16
+
17
+ def self.from_dynamic!: (Hash[(String | Symbol), untyped] d) -> Mihari::Structs::GooglePublicDNS::Response
18
+ end
19
+ end
20
+ end
21
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mihari
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.6.1
4
+ version: 4.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Manabu Niseki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-05-19 00:00:00.000000000 Z
11
+ date: 2022-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.4'
47
+ version: '1.5'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.4'
54
+ version: '1.5'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: mysql2
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -198,14 +198,14 @@ dependencies:
198
198
  requirements:
199
199
  - - "~>"
200
200
  - !ruby/object:Gem::Version
201
- version: '0.52'
201
+ version: '1.0'
202
202
  type: :development
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
206
  - - "~>"
207
207
  - !ruby/object:Gem::Version
208
- version: '0.52'
208
+ version: '1.0'
209
209
  - !ruby/object:Gem::Dependency
210
210
  name: timecop
211
211
  requirement: !ruby/object:Gem::Requirement
@@ -436,14 +436,14 @@ dependencies:
436
436
  requirements:
437
437
  - - '='
438
438
  - !ruby/object:Gem::Version
439
- version: 1.9.1
439
+ version: 1.9.2
440
440
  type: :runtime
441
441
  prerelease: false
442
442
  version_requirements: !ruby/object:Gem::Requirement
443
443
  requirements:
444
444
  - - '='
445
445
  - !ruby/object:Gem::Version
446
- version: 1.9.1
446
+ version: 1.9.2
447
447
  - !ruby/object:Gem::Dependency
448
448
  name: dry-struct
449
449
  requirement: !ruby/object:Gem::Requirement
@@ -464,14 +464,14 @@ dependencies:
464
464
  requirements:
465
465
  - - '='
466
466
  - !ruby/object:Gem::Version
467
- version: 1.8.0
467
+ version: 1.8.1
468
468
  type: :runtime
469
469
  prerelease: false
470
470
  version_requirements: !ruby/object:Gem::Requirement
471
471
  requirements:
472
472
  - - '='
473
473
  - !ruby/object:Gem::Version
474
- version: 1.8.0
474
+ version: 1.8.1
475
475
  - !ruby/object:Gem::Dependency
476
476
  name: email_address
477
477
  requirement: !ruby/object:Gem::Requirement
@@ -800,14 +800,14 @@ dependencies:
800
800
  requirements:
801
801
  - - '='
802
802
  - !ruby/object:Gem::Version
803
- version: 2.2.3
803
+ version: 2.2.3.1
804
804
  type: :runtime
805
805
  prerelease: false
806
806
  version_requirements: !ruby/object:Gem::Requirement
807
807
  requirements:
808
808
  - - '='
809
809
  - !ruby/object:Gem::Version
810
- version: 2.2.3
810
+ version: 2.2.3.1
811
811
  - !ruby/object:Gem::Dependency
812
812
  name: rack-contrib
813
813
  requirement: !ruby/object:Gem::Requirement
@@ -1110,8 +1110,10 @@ files:
1110
1110
  - lib/mihari/emitters/the_hive.rb
1111
1111
  - lib/mihari/emitters/webhook.rb
1112
1112
  - lib/mihari/enrichers/base.rb
1113
+ - lib/mihari/enrichers/google_public_dns.rb
1113
1114
  - lib/mihari/enrichers/ipinfo.rb
1114
1115
  - lib/mihari/enrichers/shodan.rb
1116
+ - lib/mihari/enrichers/whois.rb
1115
1117
  - lib/mihari/entities/alert.rb
1116
1118
  - lib/mihari/entities/artifact.rb
1117
1119
  - lib/mihari/entities/autonomous_system.rb
@@ -1153,11 +1155,13 @@ files:
1153
1155
  - lib/mihari/models/whois.rb
1154
1156
  - lib/mihari/schemas/analyzer.rb
1155
1157
  - lib/mihari/schemas/emitter.rb
1158
+ - lib/mihari/schemas/enricher.rb
1156
1159
  - lib/mihari/schemas/macros.rb
1157
1160
  - lib/mihari/schemas/rule.rb
1158
1161
  - lib/mihari/status.rb
1159
1162
  - lib/mihari/structs/alert.rb
1160
1163
  - lib/mihari/structs/censys.rb
1164
+ - lib/mihari/structs/google_public_dns.rb
1161
1165
  - lib/mihari/structs/greynoise.rb
1162
1166
  - lib/mihari/structs/ipinfo.rb
1163
1167
  - lib/mihari/structs/onyphe.rb
@@ -1243,6 +1247,7 @@ files:
1243
1247
  - sig/lib/mihari/emitters/the_hive.rbs
1244
1248
  - sig/lib/mihari/emitters/webhook.rbs
1245
1249
  - sig/lib/mihari/enrichers/base.rbs
1250
+ - sig/lib/mihari/enrichers/google_public_dns.rbs
1246
1251
  - sig/lib/mihari/enrichers/ipinfo.rbs
1247
1252
  - sig/lib/mihari/errors.rbs
1248
1253
  - sig/lib/mihari/feed/parser.rbs
@@ -1272,6 +1277,7 @@ files:
1272
1277
  - sig/lib/mihari/status.rbs
1273
1278
  - sig/lib/mihari/structs/alert.rbs
1274
1279
  - sig/lib/mihari/structs/censys.rbs
1280
+ - sig/lib/mihari/structs/google_public_dns.rbs
1275
1281
  - sig/lib/mihari/structs/greynoise.rbs
1276
1282
  - sig/lib/mihari/structs/ipinfo.rbs
1277
1283
  - sig/lib/mihari/structs/onyphe.rbs