hachi 0.1.2 → 0.2.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: 789e04c496071bb676e874312b47929b538a1d6a028ca5042ac18b85364d2ac7
4
- data.tar.gz: 439eccca76345fb3b74aacc2a9749ef4875652b5ba1ab15f171b7b47a9f0d45b
3
+ metadata.gz: f58d7b1ed785abfc7d69d44f261074333b779f60f21317bf6070c79bf9ea67cd
4
+ data.tar.gz: 55b4a69a5aa240fc7b81e81f576ecf2afc9ae6a58598a136dc0cfa398cd7bc31
5
5
  SHA512:
6
- metadata.gz: ba111b9284560325d00bcbe3f09240130c75428072a85fe596db524e35f9437c603a0788ca008ae309b179f475aac0ab11c0872455b6233f178da687b1c01996
7
- data.tar.gz: c9c720cf508b16cc10170d52732b6a2cdb0d0b39899810a5f3b559d1a561574cea3298b5a64911cc2addb574f117e5afd8870f32445ef0ca5f90f3dc42ac0ab4
6
+ metadata.gz: e127d0b1f0e49334cce18a4ee0fe1d56de814a52862ed9048e1810e851f1030a85d181d442661d42b7f13b9cdc4a71c39f4816b835d9b2d2f2646808eb9f852b
7
+ data.tar.gz: c100c3044222c254321f9de7675b9417ee16c147cfe72349c803204c6ab6798528bfb1612fc36f6dd0b287b4520905efc4a8de4357b86ce3552d868916f04c99
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/hachi.svg)](https://badge.fury.io/rb/hachi)
4
4
  [![Build Status](https://travis-ci.org/ninoseki/hachi.svg?branch=master)](https://travis-ci.org/ninoseki/hachi)
5
5
  [![Coverage Status](https://coveralls.io/repos/github/ninoseki/hachi/badge.svg?branch=master)](https://coveralls.io/github/ninoseki/hachi?branch=master)
6
+ [![CodeFactor](https://www.codefactor.io/repository/github/ninoseki/hachi/badge)](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 | N/A |
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(data:, date_type:)` |
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 | N/A |
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(query)` |
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 | N/A |
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
@@ -1,33 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path('lib', __dir__)
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 = "hachi"
9
- spec.version = Hachi::VERSION
10
- spec.authors = ["Manabu Niseki"]
11
- spec.email = ["manabu.niseki@gmail.com"]
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 = "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"
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 = "exe"
24
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
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", "~> 4.0"
32
- spec.add_development_dependency "webmock", "~> 3.5"
31
+ spec.add_development_dependency "vcr", "~> 5.0"
32
+ spec.add_development_dependency "webmock", "~> 3.6"
33
33
  end
@@ -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(data:, data_type:, range: "all")
27
- validate_range range
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
- post("/api/case/artifact/_search?range=#{range}", payload) { |json| json }
30
+ def similar(id)
31
+ get("/api/case/artifact/#{id}/similar") { |json| json }
47
32
  end
48
33
  end
49
34
  end
@@ -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')})" ) unless response.code.start_with? "20"
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
@@ -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(query, range: "all")
34
- validate_range range
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
- post("/api/case/_search?range=#{range}", payload) { |json| json }
37
+ def links(id)
38
+ get("/api/case/#{id}/links") { |json| json }
52
39
  end
53
40
  end
54
41
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hachi
4
- VERSION = "0.1.2"
4
+ VERSION = "0.2.0"
5
5
  end
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.1.2
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-04-20 00:00:00.000000000 Z
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: '4.0'
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: '4.0'
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.5'
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.5'
96
+ version: '3.6'
97
97
  description: A dead simple TheHive API wrapper.
98
98
  email:
99
99
  - manabu.niseki@gmail.com