hachi 0.3.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|