hachi 0.1.2 → 0.2.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/README.md +8 -5
- data/hachi.gemspec +13 -13
- data/lib/hachi/clients/alert.rb +5 -1
- data/lib/hachi/clients/artifact.rb +6 -21
- data/lib/hachi/clients/base.rb +28 -3
- data/lib/hachi/clients/case.rb +6 -19
- data/lib/hachi/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f58d7b1ed785abfc7d69d44f261074333b779f60f21317bf6070c79bf9ea67cd
|
4
|
+
data.tar.gz: 55b4a69a5aa240fc7b81e81f576ecf2afc9ae6a58598a136dc0cfa398cd7bc31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e127d0b1f0e49334cce18a4ee0fe1d56de814a52862ed9048e1810e851f1030a85d181d442661d42b7f13b9cdc4a71c39f4816b835d9b2d2f2646808eb9f852b
|
7
|
+
data.tar.gz: c100c3044222c254321f9de7675b9417ee16c147cfe72349c803204c6ab6798528bfb1612fc36f6dd0b287b4520905efc4a8de4357b86ce3552d868916f04c99
|
data/README.md
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
[](https://badge.fury.io/rb/hachi)
|
4
4
|
[](https://travis-ci.org/ninoseki/hachi)
|
5
5
|
[](https://coveralls.io/github/ninoseki/hachi?branch=master)
|
6
|
+
[](https://www.codefactor.io/repository/github/ninoseki/hachi)
|
6
7
|
|
7
8
|
Hachi(`蜂`) is a dead simple [TheHive](https://github.com/TheHive-Project/TheHive) API wrapper for Ruby.
|
8
9
|
|
@@ -27,6 +28,8 @@ api.alert.list
|
|
27
28
|
|
28
29
|
# search atrifacts
|
29
30
|
api.artifact.search(data: "1.1.1.1", data_type: "ip")
|
31
|
+
# you can do a bulk search by giving an array as an input
|
32
|
+
api.artifact.search(data: %w(1.1.1.1 8.8.8.8 github.com))
|
30
33
|
```
|
31
34
|
|
32
35
|
See `samples` for more.
|
@@ -38,7 +41,7 @@ See `samples` for more.
|
|
38
41
|
| HTTP Method | URI | Action | API method |
|
39
42
|
|-------------|-----------------------------------|-----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
40
43
|
| GET | /api/alert | List alerts | `#api.alert.list` |
|
41
|
-
| POST | /api/alert/_search | Find alerts |
|
44
|
+
| POST | /api/alert/_search | Find alerts | `#api.alert.search(attributes:, range: "all")` |
|
42
45
|
| PATCH | /api/alert/_bulk | Update alerts in bulk | N/A |
|
43
46
|
| POST | /api/alert/_stats | Compute stats on alerts | N/A |
|
44
47
|
| POST | /api/alert | Create an alert | `#api.alert.create(title:, description:, severity: nil, date: nil, tags: nil, tlp: nil, status: nil, type:, source:, source_ref: nil, artifacts: nil, follow: nil)` |
|
@@ -56,13 +59,13 @@ See `samples` for more.
|
|
56
59
|
|
57
60
|
| HTTP Method | URI | Action | API method |
|
58
61
|
|-------------|----------------------------------------|---------------------------------|---------------------------------------------------------------------------------------|
|
59
|
-
| POST | /api/case/artifact/_search | Find observables | `#api.artifact.search(
|
62
|
+
| POST | /api/case/artifact/_search | Find observables | `#api.artifact.search(attributes, range: "all")` |
|
60
63
|
| POST | /api/case/artifact/_stats | Compute stats on observables | N/A |
|
61
64
|
| POST | /api/case/:caseId/artifact | Create an observable | `#api.artifact.create(case_id, data:, data_type:, message: nil, tlp: nil, tags: nil)` |
|
62
65
|
| GET | /api/case/artifact/:artifactId | Get an observable | `#api.artifact.get_by_id(id)` |
|
63
66
|
| DELETE | /api/case/artifact/:artifactId | Remove an observable | `#api.artifact.delete_by_id(id)` |
|
64
67
|
| PATCH | /api/case/artifact/:artifactId | Update an observable | N/A |
|
65
|
-
| GET | /api/case/artifact/:artifactId/similar | Get list of similar observables |
|
68
|
+
| GET | /api/case/artifact/:artifactId/similar | Get list of similar observables | `#api.artifact.similar(id)` |
|
66
69
|
| PATCH | /api/case/artifact/_bulk | Update observables in bulk | N/A |
|
67
70
|
|
68
71
|
### Case
|
@@ -70,14 +73,14 @@ See `samples` for more.
|
|
70
73
|
| HTTP Method | URI | Action | API method |
|
71
74
|
|-------------|------------------------------------|---------------------------------------|----------------------------------------------------------------------------------------------------------------------|
|
72
75
|
| GET | /api/case | List cases | `#api.case.list` |
|
73
|
-
| POST | /api/case/_search | Find cases | `#api.case.search(
|
76
|
+
| POST | /api/case/_search | Find cases | `#api.case.search(attributes, range: "all")` |
|
74
77
|
| PATCH | /api/case/_bulk | Update cases in bulk | N/A |
|
75
78
|
| POST | /api/case/_stats | Compute stats on cases | N/A |
|
76
79
|
| POST | /api/case | Create a case | `#api.case.create(title:, description:, severity: nil, start_date: nil, owner: nil, flag: nil, tlp: nil, tags: nil)` |
|
77
80
|
| GET | /api/case/:caseId | Get a case | `#api.case.get_by_id(id)` |
|
78
81
|
| PATCH | /api/case/:caseId | Update a case | N/A |
|
79
82
|
| DELETE | /api/case/:caseId | Remove a case | `#api.case.delete_by_id(id)` |
|
80
|
-
| GET | /api/case/:caseId/links | Get list of cases linked to this case |
|
83
|
+
| GET | /api/case/:caseId/links | Get list of cases linked to this case | `#api.case.links(id)` |
|
81
84
|
| POST | /api/case/:caseId1/_merge/:caseId2 | Merge two cases | N/A |
|
82
85
|
|
83
86
|
## License
|
data/hachi.gemspec
CHANGED
@@ -1,33 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
lib = File.expand_path(
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
require "hachi/version"
|
6
6
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
|
-
spec.name
|
9
|
-
spec.version
|
10
|
-
spec.authors
|
11
|
-
spec.email
|
8
|
+
spec.name = "hachi"
|
9
|
+
spec.version = Hachi::VERSION
|
10
|
+
spec.authors = ["Manabu Niseki"]
|
11
|
+
spec.email = ["manabu.niseki@gmail.com"]
|
12
12
|
|
13
|
-
spec.summary
|
14
|
-
spec.description
|
15
|
-
spec.homepage
|
16
|
-
spec.license
|
13
|
+
spec.summary = "A dead simple TheHive API wrapper."
|
14
|
+
spec.description = "A dead simple TheHive API wrapper."
|
15
|
+
spec.homepage = "https://github.com/ninoseki/hachi"
|
16
|
+
spec.license = "MIT"
|
17
17
|
|
18
18
|
# Specify which files should be added to the gem when it is released.
|
19
19
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
20
20
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
21
21
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
22
22
|
end
|
23
|
-
spec.bindir
|
24
|
-
spec.executables
|
23
|
+
spec.bindir = "exe"
|
24
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
25
|
spec.require_paths = ["lib"]
|
26
26
|
|
27
27
|
spec.add_development_dependency "bundler", "~> 2.0"
|
28
28
|
spec.add_development_dependency "coveralls", "~> 0.8"
|
29
29
|
spec.add_development_dependency "rake", "~> 12.3"
|
30
30
|
spec.add_development_dependency "rspec", "~> 3.8"
|
31
|
-
spec.add_development_dependency "vcr", "~>
|
32
|
-
spec.add_development_dependency "webmock", "~> 3.
|
31
|
+
spec.add_development_dependency "vcr", "~> 5.0"
|
32
|
+
spec.add_development_dependency "webmock", "~> 3.6"
|
33
33
|
end
|
data/lib/hachi/clients/alert.rb
CHANGED
@@ -31,10 +31,14 @@ module Hachi
|
|
31
31
|
source: source,
|
32
32
|
source_ref: source_ref,
|
33
33
|
artifacts: artifacts,
|
34
|
-
follow: follow
|
34
|
+
follow: follow,
|
35
35
|
)
|
36
36
|
post("/api/alert", alert.payload) { |json| json }
|
37
37
|
end
|
38
|
+
|
39
|
+
def search(attributes:, range: "all")
|
40
|
+
_search("/api/alert/_search", attributes: attributes, range: range) { |json| json }
|
41
|
+
end
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
@@ -9,7 +9,7 @@ module Hachi
|
|
9
9
|
data_type: data_type,
|
10
10
|
message: message,
|
11
11
|
tlp: tlp,
|
12
|
-
tags: tags
|
12
|
+
tags: tags,
|
13
13
|
)
|
14
14
|
|
15
15
|
post("/api/case/#{case_id}/artifact", artifact.payload) { |json| json }
|
@@ -23,27 +23,12 @@ module Hachi
|
|
23
23
|
delete("/api/case/artifact/#{id}") { |json| json }
|
24
24
|
end
|
25
25
|
|
26
|
-
def search(
|
27
|
-
|
28
|
-
|
29
|
-
artifact = Models::Artifact.new(data: data, data_type: data_type)
|
30
|
-
payload = {
|
31
|
-
query: {
|
32
|
-
_and:
|
33
|
-
[
|
34
|
-
{ _field: "data", _value: artifact.data },
|
35
|
-
{ _field: "dataType", _value: artifact.data_type },
|
36
|
-
{ _and:
|
37
|
-
[
|
38
|
-
{ _not: { status: "Deleted" } },
|
39
|
-
{ _not:
|
40
|
-
{ _in: { _field: "_type", _values: ["dashboard", "data", "user", "analyzer", "caseTemplate", "reportTemplate", "action"] } } }
|
41
|
-
] }
|
42
|
-
]
|
43
|
-
}
|
44
|
-
}
|
26
|
+
def search(attributes, range: "all")
|
27
|
+
_search("/api/case/artifact/_search", attributes: attributes, range: range) { |json| json }
|
28
|
+
end
|
45
29
|
|
46
|
-
|
30
|
+
def similar(id)
|
31
|
+
get("/api/case/artifact/#{id}/similar") { |json| json }
|
47
32
|
end
|
48
33
|
end
|
49
34
|
end
|
data/lib/hachi/clients/base.rb
CHANGED
@@ -33,7 +33,7 @@ module Hachi
|
|
33
33
|
proxy_address: uri.hostname,
|
34
34
|
proxy_port: uri.port,
|
35
35
|
proxy_from_env: false,
|
36
|
-
use_ssl: true
|
36
|
+
use_ssl: true,
|
37
37
|
}
|
38
38
|
else
|
39
39
|
{ use_ssl: true }
|
@@ -55,7 +55,7 @@ module Hachi
|
|
55
55
|
|
56
56
|
def parse_body(body)
|
57
57
|
JSON.parse body.to_s
|
58
|
-
rescue JSON::ParserError =>
|
58
|
+
rescue JSON::ParserError => _e
|
59
59
|
body.to_s
|
60
60
|
end
|
61
61
|
|
@@ -64,7 +64,7 @@ module Hachi
|
|
64
64
|
response = http.request(req)
|
65
65
|
json = parse_body(response.body)
|
66
66
|
|
67
|
-
raise(Error, "Unsupported response code returned: #{response.code} (#{json&.dig('message')})"
|
67
|
+
raise(Error, "Unsupported response code returned: #{response.code} (#{json&.dig('message')})") unless response.code.start_with? "20"
|
68
68
|
|
69
69
|
yield json
|
70
70
|
end
|
@@ -109,6 +109,31 @@ module Hachi
|
|
109
109
|
|
110
110
|
raise ArgumentError, "from should be smaller than to"
|
111
111
|
end
|
112
|
+
|
113
|
+
def _search(path, attributes:, range: "all")
|
114
|
+
validate_range range
|
115
|
+
|
116
|
+
conditions = attributes.map do |key, value|
|
117
|
+
if value.is_a?(Array)
|
118
|
+
{ _string: value.join(", ") }
|
119
|
+
else
|
120
|
+
{ _string: "#{key}:#{value}" }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
default_conditions = {
|
125
|
+
_and: [
|
126
|
+
{ _not: { status: "Deleted" } },
|
127
|
+
{ _not: { _in: { _field: "_type", _values: ["dashboard", "data", "user", "analyzer", "caseTemplate", "reportTemplate", "action"] } } },
|
128
|
+
],
|
129
|
+
}
|
130
|
+
|
131
|
+
query = {
|
132
|
+
_and: [conditions, default_conditions].flatten,
|
133
|
+
}
|
134
|
+
|
135
|
+
post("#{path}?range=#{range}", query: query) { |json| json }
|
136
|
+
end
|
112
137
|
end
|
113
138
|
end
|
114
139
|
end
|
data/lib/hachi/clients/case.rb
CHANGED
@@ -24,31 +24,18 @@ module Hachi
|
|
24
24
|
owner: owner,
|
25
25
|
flag: flag,
|
26
26
|
tlp: tlp,
|
27
|
-
tags: tags
|
27
|
+
tags: tags,
|
28
28
|
)
|
29
29
|
|
30
30
|
post("/api/case", kase.payload) { |json| json }
|
31
31
|
end
|
32
32
|
|
33
|
-
def search(
|
34
|
-
|
35
|
-
|
36
|
-
payload = {
|
37
|
-
query: {
|
38
|
-
_and:
|
39
|
-
[
|
40
|
-
{ string: query },
|
41
|
-
{ _and:
|
42
|
-
[
|
43
|
-
{ _not: { status: "Deleted" } },
|
44
|
-
{ _not:
|
45
|
-
{ _in: { _field: "_type", _values: ["dashboard", "data", "user", "analyzer", "caseTemplate", "reportTemplate", "action"] } } }
|
46
|
-
] }
|
47
|
-
]
|
48
|
-
}
|
49
|
-
}
|
33
|
+
def search(attributes, range: "all")
|
34
|
+
_search("/api/case/_search", attributes: attributes, range: range) { |json| json }
|
35
|
+
end
|
50
36
|
|
51
|
-
|
37
|
+
def links(id)
|
38
|
+
get("/api/case/#{id}/links") { |json| json }
|
52
39
|
end
|
53
40
|
end
|
54
41
|
end
|
data/lib/hachi/version.rb
CHANGED
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: 0.2.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: 2019-
|
11
|
+
date: 2019-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -72,28 +72,28 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '5.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '5.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: webmock
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '3.
|
89
|
+
version: '3.6'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '3.
|
96
|
+
version: '3.6'
|
97
97
|
description: A dead simple TheHive API wrapper.
|
98
98
|
email:
|
99
99
|
- manabu.niseki@gmail.com
|