hachi 0.3.1 → 2.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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +23 -0
- data/.gitignore +5 -1
- data/README.md +12 -76
- data/Rakefile +1 -1
- data/hachi.gemspec +7 -5
- data/lib/hachi/api.rb +37 -5
- data/lib/hachi/awrence/methods.rb +66 -0
- data/lib/hachi/clients/alert.rb +9 -119
- data/lib/hachi/clients/artifact.rb +3 -38
- data/lib/hachi/clients/base.rb +72 -106
- data/lib/hachi/clients/case.rb +9 -102
- data/lib/hachi/clients/observable.rb +53 -0
- data/lib/hachi/clients/query.rb +18 -0
- data/lib/hachi/clients/user.rb +6 -16
- data/lib/hachi/version.rb +1 -1
- data/lib/hachi.rb +15 -6
- data/renovate.json +5 -0
- metadata +50 -27
- data/.travis.yml +0 -7
- data/lib/hachi/models/alert.rb +0 -74
- data/lib/hachi/models/artifact.rb +0 -44
- data/lib/hachi/models/base.rb +0 -31
- data/lib/hachi/models/case.rb +0 -61
- data/lib/hachi/models/user.rb +0 -39
- data/samples/01_create_an_alert.rb +0 -17
- data/samples/02_search_artifacts.rb +0 -16
- data/samples/03_list_cases.rb +0 -16
- data/samples/04_merge_alerts.rb +0 -17
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hachi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Manabu Niseki
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,28 +16,42 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '2.
|
19
|
+
version: '2.3'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '2.
|
26
|
+
version: '2.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: coveralls_reborn
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0.
|
33
|
+
version: '0.24'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0.
|
40
|
+
version: '0.24'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dotenv
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.7'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.7'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,42 +72,56 @@ dependencies:
|
|
58
72
|
requirements:
|
59
73
|
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version: '3.
|
75
|
+
version: '3.11'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.11'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov-lcov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.8.0
|
62
90
|
type: :development
|
63
91
|
prerelease: false
|
64
92
|
version_requirements: !ruby/object:Gem::Requirement
|
65
93
|
requirements:
|
66
94
|
- - "~>"
|
67
95
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
96
|
+
version: 0.8.0
|
69
97
|
- !ruby/object:Gem::Dependency
|
70
98
|
name: vcr
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|
72
100
|
requirements:
|
73
101
|
- - "~>"
|
74
102
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
103
|
+
version: '6.1'
|
76
104
|
type: :development
|
77
105
|
prerelease: false
|
78
106
|
version_requirements: !ruby/object:Gem::Requirement
|
79
107
|
requirements:
|
80
108
|
- - "~>"
|
81
109
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
110
|
+
version: '6.1'
|
83
111
|
- !ruby/object:Gem::Dependency
|
84
112
|
name: webmock
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
86
114
|
requirements:
|
87
115
|
- - "~>"
|
88
116
|
- !ruby/object:Gem::Version
|
89
|
-
version: '3.
|
117
|
+
version: '3.14'
|
90
118
|
type: :development
|
91
119
|
prerelease: false
|
92
120
|
version_requirements: !ruby/object:Gem::Requirement
|
93
121
|
requirements:
|
94
122
|
- - "~>"
|
95
123
|
- !ruby/object:Gem::Version
|
96
|
-
version: '3.
|
124
|
+
version: '3.14'
|
97
125
|
description: A dead simple TheHive API wrapper.
|
98
126
|
email:
|
99
127
|
- manabu.niseki@gmail.com
|
@@ -101,9 +129,9 @@ executables: []
|
|
101
129
|
extensions: []
|
102
130
|
extra_rdoc_files: []
|
103
131
|
files:
|
132
|
+
- ".github/workflows/test.yml"
|
104
133
|
- ".gitignore"
|
105
134
|
- ".rspec"
|
106
|
-
- ".travis.yml"
|
107
135
|
- Gemfile
|
108
136
|
- LICENSE.txt
|
109
137
|
- README.md
|
@@ -113,26 +141,21 @@ files:
|
|
113
141
|
- hachi.gemspec
|
114
142
|
- lib/hachi.rb
|
115
143
|
- lib/hachi/api.rb
|
144
|
+
- lib/hachi/awrence/methods.rb
|
116
145
|
- lib/hachi/clients/alert.rb
|
117
146
|
- lib/hachi/clients/artifact.rb
|
118
147
|
- lib/hachi/clients/base.rb
|
119
148
|
- lib/hachi/clients/case.rb
|
149
|
+
- lib/hachi/clients/observable.rb
|
150
|
+
- lib/hachi/clients/query.rb
|
120
151
|
- lib/hachi/clients/user.rb
|
121
|
-
- lib/hachi/models/alert.rb
|
122
|
-
- lib/hachi/models/artifact.rb
|
123
|
-
- lib/hachi/models/base.rb
|
124
|
-
- lib/hachi/models/case.rb
|
125
|
-
- lib/hachi/models/user.rb
|
126
152
|
- lib/hachi/version.rb
|
127
|
-
-
|
128
|
-
- samples/02_search_artifacts.rb
|
129
|
-
- samples/03_list_cases.rb
|
130
|
-
- samples/04_merge_alerts.rb
|
153
|
+
- renovate.json
|
131
154
|
homepage: https://github.com/ninoseki/hachi
|
132
155
|
licenses:
|
133
156
|
- MIT
|
134
157
|
metadata: {}
|
135
|
-
post_install_message:
|
158
|
+
post_install_message:
|
136
159
|
rdoc_options: []
|
137
160
|
require_paths:
|
138
161
|
- lib
|
@@ -147,8 +170,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
170
|
- !ruby/object:Gem::Version
|
148
171
|
version: '0'
|
149
172
|
requirements: []
|
150
|
-
rubygems_version: 3.
|
151
|
-
signing_key:
|
173
|
+
rubygems_version: 3.2.14
|
174
|
+
signing_key:
|
152
175
|
specification_version: 4
|
153
176
|
summary: A dead simple TheHive API wrapper.
|
154
177
|
test_files: []
|
data/.travis.yml
DELETED
data/lib/hachi/models/alert.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "date"
|
4
|
-
require "securerandom"
|
5
|
-
|
6
|
-
module Hachi
|
7
|
-
module Models
|
8
|
-
class Alert < Base
|
9
|
-
attr_reader :title
|
10
|
-
attr_reader :description
|
11
|
-
attr_reader :severity
|
12
|
-
attr_reader :date
|
13
|
-
attr_reader :tags
|
14
|
-
attr_reader :tlp
|
15
|
-
attr_reader :status
|
16
|
-
attr_reader :type
|
17
|
-
attr_reader :source
|
18
|
-
attr_reader :source_ref
|
19
|
-
attr_reader :artifacts
|
20
|
-
attr_reader :follow
|
21
|
-
|
22
|
-
def initialize(title:, description:, severity: nil, date: nil, tags: nil, tlp: nil, status: nil, type:, source:, source_ref: nil, artifacts: nil, follow: nil)
|
23
|
-
@title = title
|
24
|
-
@description = description
|
25
|
-
@severity = severity
|
26
|
-
@date = date
|
27
|
-
@tags = tags
|
28
|
-
@tlp = tlp
|
29
|
-
@status = status
|
30
|
-
@type = type
|
31
|
-
@source = source
|
32
|
-
@source_ref = source_ref || SecureRandom.hex(10)
|
33
|
-
@artifacts = artifacts.nil? ? nil : artifacts.map { |a| Artifact.new a }
|
34
|
-
@follow = follow
|
35
|
-
|
36
|
-
validate_date if date
|
37
|
-
validate_severity if severity
|
38
|
-
validate_status if status
|
39
|
-
validate_tlp if tlp
|
40
|
-
validate_artifacts if artifacts
|
41
|
-
end
|
42
|
-
|
43
|
-
def payload
|
44
|
-
{
|
45
|
-
title: title,
|
46
|
-
description: description,
|
47
|
-
severity: severity,
|
48
|
-
date: date,
|
49
|
-
tags: tags,
|
50
|
-
tlp: tlp,
|
51
|
-
status: status,
|
52
|
-
type: type,
|
53
|
-
source: source,
|
54
|
-
sourceRef: source_ref,
|
55
|
-
artifacts: artifacts&.map(&:payload),
|
56
|
-
follow: follow
|
57
|
-
}.compact
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
def validate_date
|
63
|
-
DateTime.parse(date)
|
64
|
-
true
|
65
|
-
rescue ArgumentError => _e
|
66
|
-
raise ArgumentError, "date should be Date format"
|
67
|
-
end
|
68
|
-
|
69
|
-
def validate_artifacts
|
70
|
-
artifacts.each(&:validate_for_creation)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Hachi
|
4
|
-
module Models
|
5
|
-
class Artifact < Base
|
6
|
-
DATA_TYPES = %w(filename file fqdn hash uri_path ip domain mail autonomous-system registry mail_subject regexp user-agent other url).freeze
|
7
|
-
|
8
|
-
attr_reader :data
|
9
|
-
attr_reader :data_type
|
10
|
-
attr_reader :message
|
11
|
-
attr_reader :tlp
|
12
|
-
attr_reader :tags
|
13
|
-
|
14
|
-
def initialize(data:, data_type:, message: nil, tlp: nil, tags: nil)
|
15
|
-
@data = data
|
16
|
-
@data_type = data_type
|
17
|
-
@message = message
|
18
|
-
@tlp = tlp
|
19
|
-
@tags = tags
|
20
|
-
|
21
|
-
raise(ArgumentError, "data is required") unless data
|
22
|
-
raise(ArgumentError, "data_type is required") unless data_type
|
23
|
-
raise(ArgumentError, "invalid data type") unless DATA_TYPES.include?(data_type)
|
24
|
-
|
25
|
-
validate_tags if tags
|
26
|
-
validate_tlp if tlp
|
27
|
-
end
|
28
|
-
|
29
|
-
def payload
|
30
|
-
{
|
31
|
-
data: data,
|
32
|
-
dataType: data_type,
|
33
|
-
message: message,
|
34
|
-
tlp: tlp,
|
35
|
-
tags: tags
|
36
|
-
}.compact
|
37
|
-
end
|
38
|
-
|
39
|
-
def validate_for_creation
|
40
|
-
raise(ArgumentError, "message or tags is requried for artifact creation") unless message || tags
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
data/lib/hachi/models/base.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Hachi
|
4
|
-
module Models
|
5
|
-
class Base
|
6
|
-
private
|
7
|
-
|
8
|
-
def validate_severity
|
9
|
-
return true if severity >= 1 && severity <= 3
|
10
|
-
|
11
|
-
raise ArgumentError, "severity should be 1 - 3 (1: low; 2: medium; 3: high)"
|
12
|
-
end
|
13
|
-
|
14
|
-
def validate_tlp
|
15
|
-
return true if tlp >= 0 && tlp <= 3
|
16
|
-
|
17
|
-
raise ArgumentError, "tlp should be 0 - 3 (0: white; 1: green; 2: amber; 3: red)"
|
18
|
-
end
|
19
|
-
|
20
|
-
def validate_status
|
21
|
-
return true if %w(New Updated Ignored Imported).include?(status)
|
22
|
-
|
23
|
-
raise ArgumentError, "status should be New, Updated, Ignored or Imported"
|
24
|
-
end
|
25
|
-
|
26
|
-
def validate_tags
|
27
|
-
raise ArgumentError, "tags should be an array" unless tags.is_a?(Array)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
data/lib/hachi/models/case.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Hachi
|
4
|
-
module Models
|
5
|
-
class Case < Base
|
6
|
-
attr_reader :title
|
7
|
-
attr_reader :description
|
8
|
-
attr_reader :severity
|
9
|
-
attr_reader :start_date
|
10
|
-
attr_reader :owner
|
11
|
-
attr_reader :flag
|
12
|
-
attr_reader :tlp
|
13
|
-
attr_reader :tags
|
14
|
-
|
15
|
-
def initialize(title:, description:, severity: nil, start_date: nil, owner: nil, flag: nil, tlp: nil, tags: nil)
|
16
|
-
@title = title
|
17
|
-
@description = description
|
18
|
-
@severity = severity
|
19
|
-
@start_date = start_date
|
20
|
-
@owner = owner
|
21
|
-
@flag = flag
|
22
|
-
@tlp = tlp
|
23
|
-
@tags = tags
|
24
|
-
|
25
|
-
validate_flag if flag
|
26
|
-
validate_severity if severity
|
27
|
-
validate_start_date if start_date
|
28
|
-
validate_tags if tags
|
29
|
-
validate_tlp if tlp
|
30
|
-
end
|
31
|
-
|
32
|
-
def payload
|
33
|
-
{
|
34
|
-
title: title,
|
35
|
-
description: description,
|
36
|
-
severity: severity,
|
37
|
-
startDate: start_date,
|
38
|
-
owner: owner,
|
39
|
-
flag: flag,
|
40
|
-
tlp: tlp,
|
41
|
-
tags: tags
|
42
|
-
}.compact
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
def validate_start_date
|
48
|
-
DateTime.parse(start_date)
|
49
|
-
true
|
50
|
-
rescue ArgumentError => _e
|
51
|
-
raise ArgumentError, "date should be Date format"
|
52
|
-
end
|
53
|
-
|
54
|
-
def validate_flag
|
55
|
-
return true if [true, false].include?(flag)
|
56
|
-
|
57
|
-
raise ArgumentError, "flag should be true or false"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
data/lib/hachi/models/user.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Hachi
|
4
|
-
module Models
|
5
|
-
class User < Base
|
6
|
-
attr_reader :login
|
7
|
-
attr_reader :name
|
8
|
-
attr_reader :roles
|
9
|
-
attr_reader :password
|
10
|
-
|
11
|
-
ROLES = %w(read write admin).freeze
|
12
|
-
|
13
|
-
def initialize(login:, name:, roles:, password:)
|
14
|
-
@login = login
|
15
|
-
@name = name
|
16
|
-
@roles = roles
|
17
|
-
@password = password
|
18
|
-
|
19
|
-
validate_roles
|
20
|
-
end
|
21
|
-
|
22
|
-
def payload
|
23
|
-
{
|
24
|
-
login: login,
|
25
|
-
name: name,
|
26
|
-
roles: roles,
|
27
|
-
password: password
|
28
|
-
}.compact
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def validate_roles
|
34
|
-
raise ArgumentError, "roles should be an array" unless roles.is_a?(Array)
|
35
|
-
raise ArgumentError, "role should be one of #{ROLES.join('.')}" unless roles.all? { |role| ROLES.include? role }
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
$LOAD_PATH.unshift("#{__dir__}/../lib")
|
4
|
-
|
5
|
-
require "hachi"
|
6
|
-
|
7
|
-
api = Hachi::API.new
|
8
|
-
|
9
|
-
# create a simple alert
|
10
|
-
api.alert.create(title: "test", description: "test", type: "test", source: "test")
|
11
|
-
|
12
|
-
# create an alert with artifacts
|
13
|
-
artifacts = [
|
14
|
-
{ data: "1.1.1.1", data_type: "ip", message: "test" },
|
15
|
-
{ data: "github.com", data_type: "domain", tags: ["test"] }
|
16
|
-
]
|
17
|
-
api.alert.create(title: "test", description: "test", type: "test", source: "test", artifacts: artifacts)
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
$LOAD_PATH.unshift("#{__dir__}/../lib")
|
4
|
-
|
5
|
-
require "hachi"
|
6
|
-
|
7
|
-
api = Hachi::API.new
|
8
|
-
|
9
|
-
# search artifacts
|
10
|
-
results = api.artifact.search(data: "1.1.1.1", data_type: "ip")
|
11
|
-
ids = results.map { |result| result.dig("id") }
|
12
|
-
|
13
|
-
ids.each do |id|
|
14
|
-
artifact = api.artifact.get_by_id(id)
|
15
|
-
p artifact
|
16
|
-
end
|
data/samples/03_list_cases.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
$LOAD_PATH.unshift("#{__dir__}/../lib")
|
4
|
-
|
5
|
-
require "hachi"
|
6
|
-
|
7
|
-
api = Hachi::API.new
|
8
|
-
|
9
|
-
# list up cases
|
10
|
-
results = api.case.list
|
11
|
-
ids = results.map { |result| result.dig("id") }
|
12
|
-
|
13
|
-
ids.each do |id|
|
14
|
-
kase = api.case.get_by_id(id)
|
15
|
-
p kase
|
16
|
-
end
|
data/samples/04_merge_alerts.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
$LOAD_PATH.unshift("#{__dir__}/../lib")
|
4
|
-
|
5
|
-
require "hachi"
|
6
|
-
|
7
|
-
def api
|
8
|
-
@api ||= Hachi::API.new
|
9
|
-
end
|
10
|
-
|
11
|
-
description = ARGV[0].to_s
|
12
|
-
case_id = ARGV[1].to_s
|
13
|
-
|
14
|
-
alerts = api.alert.search(description: description)
|
15
|
-
alert_ids = alerts.map { |alert| alert.dig "id" }
|
16
|
-
|
17
|
-
api.alert.merge_into_case(alert_ids, case_id)
|