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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e065fd460cb9324e124aef7c1f779c2c4d2eb4368248be8b64de1ccff687dc99
4
- data.tar.gz: ee69559c7d0d3d2e494bf8fc64fc743b60404f15701f8ad2acfec1fb7d629e9f
3
+ metadata.gz: a88c7c477df9e4dbd8566ff3464424dbd994f9d976f9e235b6c1244200d32fd7
4
+ data.tar.gz: 1729ececbdb34f98abff15b7d80c189729d10d840f199876c87dc8eb22411581
5
5
  SHA512:
6
- metadata.gz: efd71a3a72134fd70f2caf17b6e835212972640b7535b294c26224ce944ac77e5d7866889b78b3836449cbd04b6169203af76da167443524ca4dd4397974fce7
7
- data.tar.gz: 0b052f52652fb095bd1786c2394439f774e876d48175628a1e701a32debe487b65ece8881d24cdea3b00231d811ef8b80817507c12901dfe58c1dcb2df57e157
6
+ metadata.gz: 40517bf2830268e88af14dc70ffc1af9f1e7c32d509e53883b6e125b48b7e689b81f628eb6225f2b76c517479ab19efb721ccea0b24b8bf9df11b598796aeb4d
7
+ data.tar.gz: e334655c99088a1038618b85a03f068fe3c459bd25f5eb179cc6a69bfb654aed185893e0d139ea270854cb87e80e6c62120c70a8f7e1a2f79e4325207b66c0be
@@ -0,0 +1,23 @@
1
+ name: Ruby CI
2
+
3
+ on: [pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+
9
+ strategy:
10
+ fail-fast: false
11
+ matrix:
12
+ ruby: [2.7, "3.0", 3.1]
13
+
14
+ steps:
15
+ - uses: actions/checkout@v3
16
+ - name: Set up Ruby
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: ${{ matrix.ruby }}
20
+ bundler-cache: true
21
+ - name: Test with Rake
22
+ run: |
23
+ bundle exec rake
data/.gitignore CHANGED
@@ -11,7 +11,7 @@
11
11
  /tmp/
12
12
 
13
13
  # Used by dotenv library to load environment variables.
14
- # .env
14
+ .env
15
15
 
16
16
  ## Specific to RubyMotion:
17
17
  .dat*
@@ -51,3 +51,7 @@ Gemfile.lock
51
51
 
52
52
  # RSpec
53
53
  .rspec_status
54
+
55
+ # Docker
56
+ Dockerfile
57
+ docker-compose.yml
data/README.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # Hachi
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/hachi.svg)](https://badge.fury.io/rb/hachi)
4
- [![Build Status](https://travis-ci.com/ninoseki/hachi.svg?branch=master)](https://travis-ci.com/ninoseki/hachi)
4
+ [![Ruby CI](https://github.com/ninoseki/hachi/actions/workflows/test.yml/badge.svg)](https://github.com/ninoseki/hachi/actions/workflows/test.yml)
5
5
  [![Coverage Status](https://coveralls.io/repos/github/ninoseki/hachi/badge.svg?branch=master)](https://coveralls.io/github/ninoseki/hachi?branch=master)
6
6
  [![CodeFactor](https://www.codefactor.io/repository/github/ninoseki/hachi/badge)](https://www.codefactor.io/repository/github/ninoseki/hachi)
7
7
 
8
8
  Hachi(`蜂`) is a dead simple [TheHive](https://github.com/TheHive-Project/TheHive) API wrapper for Ruby.
9
9
 
10
+ **Note**: This library supports TheHive v4 & v5.
11
+
10
12
  ## Installation
11
13
 
12
14
  ```bash
@@ -15,89 +17,23 @@ gem install hachi
15
17
 
16
18
  ## Usage
17
19
 
20
+ Hachi tries to load API settings from `ENV` by default. Or you can set them manually.
21
+
22
+ | Name | Default | Desc. |
23
+ |--------------|-----------------------------|-------------------------------------------------|
24
+ | api_key | ENV["THEHIVE_API_KEY"] | TheHive API key |
25
+ | api_endpoint | ENV["THEHIVE_API_ENDPOINT"] | TheHive API endpoint |
26
+ | api_version | ENV["THEHIVE_API_VERSION"] | TheHive API version (`nil` for v4, `v1` for v5) |
27
+
18
28
  ```ruby
19
29
  require "hachi"
20
30
 
21
- # when given nothing, it tries to load your API key from ENV["THEHIVE_API_KEY"] & API endpoint from ENV["THEHIVE_API_ENDPOINT"]
31
+ # when given nothing, it tries to load your API key from ENV
22
32
  api = Hachi::API.new
23
33
  # or you can set them manually
24
34
  api = Hachi::API.new(api_endpoint: "http://your_api_endpoint", api_key: "yoru_api_key")
25
-
26
- # list alerts
27
- api.alert.list
28
-
29
- # search atrifacts
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))
33
35
  ```
34
36
 
35
- See `samples` for more.
36
-
37
- ## Implemented methods
38
-
39
- ### Alert
40
-
41
- | HTTP Method | URI | Action | API method |
42
- |-------------|-----------------------------------|-----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
43
- | GET | /api/alert | List alerts | `#api.alert.list` |
44
- | POST | /api/alert/_search | Find alerts | `#api.alert.search(attributes, range: "all")` |
45
- | PATCH | /api/alert/_bulk | Update alerts in bulk | N/A |
46
- | POST | /api/alert/_stats | Compute stats on alerts | N/A |
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)` |
48
- | GET | /api/alert/:alertId | Get an alert | `#api.alert.get_by_id(id)` |
49
- | PATCH | /api/alert/:alertId | Update an alert | `#api.alert.update(id, title:, description:, severity: nil, tags: nil, tlp: nil, artifacts: nil)` |
50
- | DELETE | /api/alert/:alertId | Delete an alert | `#api.alert.delete_by_id(id)` |
51
- | POST | /api/alert/:alertId/markAsRead | Mark an alert as read | `#api.alert.mark_as_read(id)` |
52
- | POST | /api/alert/:alertId/markAsUnread | Mark an alert as unread | `#api.alert.mark_as_unread(id)` |
53
- | POST | /api/alert/:alertId/createCase | Create a case from an alert | `#api.alert.promote_to_case(id)` |
54
- | POST | /api/alert/:alertId/follow | Follow an alert | N/A |
55
- | POST | /api/alert/:alertId/unfollow | Unfollow an alert | N/A |
56
- | POST | /api/alert/:alertId/merge/:caseId | Merge an alert in a case | `#api.alert.merge_into_case(*ids, case_id)` |
57
-
58
- ### Artifact(Observable)
59
-
60
- | HTTP Method | URI | Action | API method |
61
- |-------------|----------------------------------------|---------------------------------|---------------------------------------------------------------------------------------|
62
- | POST | /api/case/artifact/_search | Find observables | `#api.artifact.search(attributes, range: "all")` |
63
- | POST | /api/case/artifact/_stats | Compute stats on observables | N/A |
64
- | POST | /api/case/:caseId/artifact | Create an observable | `#api.artifact.create(case_id, data:, data_type:, message: nil, tlp: nil, tags: nil)` |
65
- | GET | /api/case/artifact/:artifactId | Get an observable | `#api.artifact.get_by_id(id)` |
66
- | DELETE | /api/case/artifact/:artifactId | Remove an observable | `#api.artifact.delete_by_id(id)` |
67
- | PATCH | /api/case/artifact/:artifactId | Update an observable | N/A |
68
- | GET | /api/case/artifact/:artifactId/similar | Get list of similar observables | `#api.artifact.similar(id)` |
69
- | PATCH | /api/case/artifact/_bulk | Update observables in bulk | N/A |
70
-
71
- ### Case
72
-
73
- | HTTP Method | URI | Action | API method |
74
- |-------------|------------------------------------|---------------------------------------|----------------------------------------------------------------------------------------------------------------------|
75
- | GET | /api/case | List cases | `#api.case.list` |
76
- | POST | /api/case/_search | Find cases | `#api.case.search(attributes, range: "all")` |
77
- | PATCH | /api/case/_bulk | Update cases in bulk | N/A |
78
- | POST | /api/case/_stats | Compute stats on cases | N/A |
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)` |
80
- | GET | /api/case/:caseId | Get a case | `#api.case.get_by_id(id)` |
81
- | PATCH | /api/case/:caseId | Update a case | N/A |
82
- | DELETE | /api/case/:caseId | Remove a case | `#api.case.delete_by_id(id)` |
83
- | GET | /api/case/:caseId/links | Get list of cases linked to this case | `#api.case.links(id)` |
84
- | POST | /api/case/:caseId1/_merge/:caseId2 | Merge two cases | `#api.case.merge(id1, id2)` |
85
-
86
- ### User
87
-
88
- | HTTP Method | URI | Action | API method |
89
- |-------------|-----------------------------------|---------------------|------------------------------------------------------|
90
- | GET | /api/logout | Logout | N/A |
91
- | POST | /api/login | User login | N/A |
92
- | GET | /api/user/current | Get current user | `#api.user.current` |
93
- | POST | /api/user/_search | Find user | N/A |
94
- | POST | /api/user | Create a user | `#api.user.create(login:, name:, roles:, password:)` |
95
- | GET | /api/user/:userId | Get a user | `#api.user.get_by_id(id)` |
96
- | DELETE | /api/user/:userId | Delete a case | `#api.user.delete_by_id(id)` |
97
- | PATCH | /api/user/:userId | Update user details | N/A |
98
- | POST | /api/user/:userId/password/set | Set password | N/A |
99
- | POST | /api/user/:userId/password/change | Change password | N/A |
100
-
101
37
  ## License
102
38
 
103
39
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -3,4 +3,4 @@ require "rspec/core/rake_task"
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
data/hachi.gemspec CHANGED
@@ -24,10 +24,12 @@ Gem::Specification.new do |spec|
24
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
25
  spec.require_paths = ["lib"]
26
26
 
27
- spec.add_development_dependency "bundler", "~> 2.0"
28
- spec.add_development_dependency "coveralls", "~> 0.8"
27
+ spec.add_development_dependency "bundler", "~> 2.3"
28
+ spec.add_development_dependency "coveralls_reborn", "~> 0.24"
29
+ spec.add_development_dependency "dotenv", "~> 2.7"
29
30
  spec.add_development_dependency "rake", "~> 13.0"
30
- spec.add_development_dependency "rspec", "~> 3.9"
31
- spec.add_development_dependency "vcr", "~> 5.0"
32
- spec.add_development_dependency "webmock", "~> 3.7"
31
+ spec.add_development_dependency "rspec", "~> 3.11"
32
+ spec.add_development_dependency "simplecov-lcov", "~> 0.8.0"
33
+ spec.add_development_dependency "vcr", "~> 6.1"
34
+ spec.add_development_dependency "webmock", "~> 3.14"
33
35
  end
data/lib/hachi/api.rb CHANGED
@@ -1,34 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "forwardable"
4
+
3
5
  module Hachi
4
6
  class API
7
+ extend Forwardable
8
+
5
9
  # @return [String] TheHive API endpoint
6
10
  attr_reader :api_endpoint
7
11
 
8
12
  # @return [String] TheHive API key
9
13
  attr_reader :api_key
10
14
 
15
+ # @return [String, nil] TheHive API version
16
+ attr_reader :api_version
17
+
11
18
  #
12
19
  # @param [String, nil] api_endpoint TheHive API endpoint
13
20
  # @param [String, nil] api_key TheHive API key
21
+ # @param [String, nil] api_version TheHive API version
14
22
  #
15
23
  # @raise [ArgumentError] When given or an empty endpoint or key
16
24
  #
17
- def initialize(api_endpoint: ENV["THEHIVE_API_ENDPOINT"], api_key: ENV["THEHIVE_API_KEY"])
25
+ def initialize(api_endpoint: ENV.fetch("THEHIVE_API_ENDPOINT", nil), api_key: ENV.fetch("THEHIVE_API_KEY", nil), api_version: ENV.fetch("THEHIVE_API_VERSION", nil))
18
26
  @api_endpoint = api_endpoint
19
27
  raise ArgumentError, "api_endpoint argument is required" unless api_endpoint
20
28
 
21
29
  @api_key = api_key
22
30
  raise ArgumentError, "api_key argument is required" unless api_key
31
+
32
+ @api_version = api_version
33
+
34
+ @base = Clients::Base.new(api_endpoint: api_endpoint, api_key: api_key, api_version: api_version)
23
35
  end
24
36
 
37
+ def_delegators :@base, :get, :post, :delete, :push
38
+
25
39
  #
26
40
  # Alert API endpoint client
27
41
  #
28
42
  # @return [Clients::Alert]
29
43
  #
30
44
  def alert
31
- @alert ||= Clients::Alert.new(api_endpoint: api_endpoint, api_key: api_key)
45
+ @alert ||= Clients::Alert.new(api_endpoint: api_endpoint, api_key: api_key, api_version: api_version)
32
46
  end
33
47
 
34
48
  #
@@ -37,7 +51,7 @@ module Hachi
37
51
  # @return [Clients::Artifact]
38
52
  #
39
53
  def artifact
40
- @artifact ||= Clients::Artifact.new(api_endpoint: api_endpoint, api_key: api_key)
54
+ @artifact ||= Clients::Artifact.new(api_endpoint: api_endpoint, api_key: api_key, api_version: api_version)
41
55
  end
42
56
 
43
57
  #
@@ -46,7 +60,7 @@ module Hachi
46
60
  # @return [Clients::Case]
47
61
  #
48
62
  def case
49
- @case ||= Clients::Case.new(api_endpoint: api_endpoint, api_key: api_key)
63
+ @case ||= Clients::Case.new(api_endpoint: api_endpoint, api_key: api_key, api_version: api_version)
50
64
  end
51
65
 
52
66
  #
@@ -55,7 +69,25 @@ module Hachi
55
69
  # @return [Clients::User]
56
70
  #
57
71
  def user
58
- @user ||= Clients::User.new(api_endpoint: api_endpoint, api_key: api_key)
72
+ @user ||= Clients::User.new(api_endpoint: api_endpoint, api_key: api_key, api_version: api_version)
73
+ end
74
+
75
+ #
76
+ # Observable API endpoint client
77
+ #
78
+ # @return [Clients::Observable]
79
+ #
80
+ def observable
81
+ @observable ||= Clients::Observable.new(api_endpoint: api_endpoint, api_key: api_key, api_version: api_version)
82
+ end
83
+
84
+ #
85
+ # Query API endpoint client
86
+ #
87
+ # @return [Clients::Query]
88
+ #
89
+ def query
90
+ @query ||= Clients::Query.new(api_endpoint: api_endpoint, api_key: api_key, api_version: api_version)
59
91
  end
60
92
  end
61
93
  end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ # forked from https://github.com/technicalpanda/awrence
4
+ module Hachi
5
+ module Awrence
6
+ module Methods
7
+ # Recursively converts Rubyish snake_case hash keys to camelBack JSON-style
8
+ # hash keys suitable for use with a JSON API.
9
+ #
10
+ def to_camelback_keys(value = self)
11
+ process_value(:to_camelback_keys, value, first_upper: false)
12
+ end
13
+
14
+ # Recursively converts Rubyish snake_case hash keys to CamelCase JSON-style
15
+ # hash keys suitable for use with a JSON API.
16
+ #
17
+ def to_camel_keys(value = self)
18
+ process_value(:to_camel_keys, value, first_upper: true)
19
+ end
20
+
21
+ private
22
+
23
+ def camelize_key(key, first_upper: true)
24
+ case key
25
+ when Symbol
26
+ camelize(key.to_s, first_upper: first_upper).to_sym
27
+ when String
28
+ camelize(key, first_upper: first_upper)
29
+ else
30
+ key # Awrence can't camelize anything except strings and symbols
31
+ end
32
+ end
33
+
34
+ def camelize(snake_word, first_upper: true)
35
+ return snake_word if snake_word.start_with? "_"
36
+
37
+ if first_upper
38
+ str = snake_word.to_s
39
+ str = gsubbed(str, /(?:^|_)([^_\s]+)/)
40
+ gsubbed(str, %r{/([^/]*)}, "::")
41
+ else
42
+ parts = snake_word.split("_", 2)
43
+ parts[0] << camelize(parts[1]) if parts.size > 1
44
+ parts[0] || ""
45
+ end
46
+ end
47
+
48
+ def gsubbed(str, pattern, extra = "")
49
+ str.gsub(pattern) do
50
+ extra + (Hachi::Awrence.acronyms[Regexp.last_match(1)] || Regexp.last_match(1).capitalize)
51
+ end
52
+ end
53
+
54
+ def process_value(method, value, first_upper: true)
55
+ case value
56
+ when Array
57
+ value.map { |v| send(method, v) }
58
+ when Hash
59
+ value.to_h { |k, v| [camelize_key(k, first_upper: first_upper), send(method, v)] }
60
+ else
61
+ value
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -6,15 +6,6 @@ require "securerandom"
6
6
  module Hachi
7
7
  module Clients
8
8
  class Alert < Base
9
- #
10
- # List alerts
11
- #
12
- # @return [Array]
13
- #
14
- def list
15
- get("/api/alert") { |json| json }
16
- end
17
-
18
9
  #
19
10
  # Get an alert
20
11
  #
@@ -23,7 +14,7 @@ module Hachi
23
14
  # @return [Hash]
24
15
  #
25
16
  def get_by_id(id)
26
- get("/api/alert/#{id}") { |json| json }
17
+ get("/alert/#{id}") { |json| json }
27
18
  end
28
19
 
29
20
  #
@@ -34,130 +25,29 @@ module Hachi
34
25
  # @return [String]
35
26
  #
36
27
  def delete_by_id(id)
37
- delete("/api/alert/#{id}") { |json| json }
28
+ delete("/alert/#{id}") { |json| json }
38
29
  end
39
30
 
40
31
  #
41
32
  # Create an alert
42
33
  #
43
- # @param [String] title
44
- # @param [String] description
45
- # @param [String, nil] severity
46
- # @param [String, nil] date
47
- # @param [String, nil] tags
48
- # @param [String, nil] tlp
49
- # @param [String, nil] status
50
- # @param [String, nil] type
51
- # @param [String, nil] source
52
- # @param [String, nil] source_ref
53
- # @param [String, nil] artifacts
54
- # @param [String, nil] follow
55
- #
56
- # @return [Hash]
57
- #
58
- def create(title:, description:, severity: nil, date: nil, tags: nil, tlp: nil, status: nil, type:, source:, source_ref: nil, artifacts: nil, follow: nil)
59
- alert = Models::Alert.new(
60
- title: title,
61
- description: description,
62
- severity: severity,
63
- date: date,
64
- tags: tags,
65
- tlp: tlp,
66
- status: status,
67
- type: type,
68
- source: source,
69
- source_ref: source_ref,
70
- artifacts: artifacts,
71
- follow: follow,
72
- )
73
- post("/api/alert", alert.payload) { |json| json }
74
- end
75
-
76
- #
77
- # Find alerts
78
- #
79
- # @param [Hash] attributes
80
- # @param [String] range
81
- # @param [String, nil] sort
82
- #
83
- # @return [Array]
84
- #
85
- def search(attributes, range: "all", sort: nil)
86
- _search("/api/alert/_search", attributes: attributes, range: range, sort: sort) { |json| json }
87
- end
88
-
89
- #
90
- # Mark an alert as read
91
- #
92
- # @param [String] id Alert ID
93
- #
94
- # @return [Hash]
95
- #
96
- def mark_as_read(id)
97
- post("/api/alert/#{id}/markAsRead") { |json| json }
98
- end
99
-
100
- #
101
- # Mark an alert as unread
102
- #
103
- # @param [String] id Alert ID
104
- #
105
- # @return [Hash] hash
106
- #
107
- def mark_as_unread(id)
108
- post("/api/alert/#{id}/markAsUnread") { |json| json }
109
- end
110
-
111
- #
112
- # Create a case from an alert
113
- #
114
- # @param [String] id Alert ID
115
- #
116
- # @return [Hash]
117
- #
118
- def promote_to_case(id)
119
- post("/api/alert/#{id}/createCase") { |json| json }
120
- end
121
-
122
- #
123
- # Merge an alert / alerts in a case
124
- #
125
- # @param [String, Array] *ids Alert ID(s)
126
- # @param [String] case_id Case ID
34
+ # @param [Hash] payload
127
35
  #
128
36
  # @return [Hash]
129
37
  #
130
- def merge_into_case(*ids, case_id)
131
- params = {
132
- alertIds: ids.flatten,
133
- caseId: case_id
134
- }
135
- post("/api/alert/merge/_bulk", params) { |json| json }
38
+ def create(**payload)
39
+ post("/alert", json: payload) { |json| json }
136
40
  end
137
41
 
138
- #
139
42
  # Update an alert
140
43
  #
141
- # @param [String, nil] id
142
- # @param [String, nil] title
143
- # @param [String, nil] description
144
- # @param [String, nil] severity
145
- # @param [String, nil] tags
146
- # @param [String, nil] tlp
147
- # @param [String, nil] artifacts
44
+ # @param [String] id
45
+ # @param [Hash] payload
148
46
  #
149
47
  # @return [Hash]
150
48
  #
151
- def update(id, title: nil, description: nil, severity: nil, tags: nil, tlp: nil, artifacts: nil)
152
- attributes = {
153
- title: title,
154
- description: description,
155
- severity: severity,
156
- tags: tags,
157
- tlp: tlp,
158
- artifacts: artifacts,
159
- }.compact
160
- patch("/api/alert/#{id}", attributes) { |json| json }
49
+ def update(id, **payload)
50
+ patch("/alert/#{id}", json: payload) { |json| json }
161
51
  end
162
52
  end
163
53
  end
@@ -7,24 +7,12 @@ module Hachi
7
7
  # Create an artifact
8
8
  #
9
9
  # @param [String] case_id Artifact ID
10
- # @param [String] data
11
- # @param [String] data_type
12
- # @param [String, nil] message
13
- # @param [Integer, nil] tlp
14
- # @param [Array<String>, nil] tags
10
+ # @param [Hash] payload
15
11
  #
16
12
  # @return [Hash]
17
13
  #
18
- def create(case_id, data:, data_type:, message: nil, tlp: nil, tags: nil)
19
- artifact = Models::Artifact.new(
20
- data: data,
21
- data_type: data_type,
22
- message: message,
23
- tlp: tlp,
24
- tags: tags,
25
- )
26
-
27
- post("/api/case/#{case_id}/artifact", artifact.payload) { |json| json }
14
+ def create(case_id, **payload)
15
+ post("/api/case/#{case_id}/artifact", json: payload) { |json| json }
28
16
  end
29
17
 
30
18
  #
@@ -48,29 +36,6 @@ module Hachi
48
36
  def delete_by_id(id)
49
37
  delete("/api/case/artifact/#{id}") { |json| json }
50
38
  end
51
-
52
- #
53
- # Find artifacts
54
- #
55
- # @param [Hash] attributes
56
- # @param [String] range
57
- #
58
- # @return [Array]
59
- #
60
- def search(attributes, range: "all")
61
- _search("/api/case/artifact/_search", attributes: attributes, range: range) { |json| json }
62
- end
63
-
64
- #
65
- # Get list of similar observables
66
- #
67
- # @param [String] id Artifact ID
68
- #
69
- # @return [Array]
70
- #
71
- def similar(id)
72
- get("/api/case/artifact/#{id}/similar") { |json| json }
73
- end
74
39
  end
75
40
  end
76
41
  end