misp 0.1.0 → 0.1.4

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: db847f1e32b2e0a1064180b310b087ade5c9d608282bcbeebc5403f02b0cb71d
4
- data.tar.gz: e1090389330d2de0bfd8b0c58cd0768f1a9bc58bb220d80c9d74aea6cb9ec738
3
+ metadata.gz: dc2ae518cdfe5d3872000bf12bd1083a4a8540a3e6857e50573b1b8011604605
4
+ data.tar.gz: 25917d69a7a912ace45ccaa43f5bc0a5202e37e66532e1eabf30a09df0478c2e
5
5
  SHA512:
6
- metadata.gz: a4b3e71c139193309e919b6dc344f4fb200521b07a90fd3e45384d272549632af96eec9852416fdc8ddbfda31c9675f5ab107ae4cb1b2ff61b98dbeba0979457
7
- data.tar.gz: 16b98a9dae45d273b70600565f8130d43d592e4097b517f49a69177c367a8c88a5841e4eb238a9629f9a45d1ca12ce7addfb5118c27f52d45a9c4a0ae3e56f61
6
+ metadata.gz: 4691cfaffdc82bc4580e08ede833788371b0c9df3b4013bb96a777b2c8b35f92889d466274b301370daa0014a087ad0006d3f92a1de62de9cbea3f5e6e2d78e4
7
+ data.tar.gz: 2c7e5a0d2c3d5c503346d0a208f6dc9efc4b7b5b8470655e0bf29ea89ed4cbe4d8f4cf2e002738d62cb5b74dfd8b175ed99d01dfaf02fa0cc24c3e85029532c0
@@ -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"]
13
+
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+ - name: Set up Ruby
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: ${{ matrix.ruby }}
20
+ bundler-cache: true
21
+ - name: Build and test with Rake
22
+ run: |
23
+ bundle exec rake
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # misp-rb
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/misp.svg)](https://badge.fury.io/rb/misp)
3
4
  [![Build Status](https://travis-ci.com/ninoseki/misp-rb.svg?branch=master)](https://travis-ci.com/ninoseki/misp-rb)
4
5
  [![Coverage Status](https://coveralls.io/repos/github/ninoseki/misp-rb/badge.svg?branch=master)](https://coveralls.io/github/ninoseki/misp-rb?branch=master)
5
6
  [![CodeFactor](https://www.codefactor.io/repository/github/ninoseki/misp-rb/badge)](https://www.codefactor.io/repository/github/ninoseki/misp-rb)
@@ -20,8 +21,8 @@ gem install misp
20
21
 
21
22
  By default, it tries to load configurations from environmental variables:
22
23
 
23
- - MISP API endpoint from ENV["MISP_API_ENDPOINT"]
24
- - MISP API key from ENV["MISP_API_KEY"]
24
+ - `MISP_API_ENDPOINT`: MISP API endpoint (e.g. https://misppriv.circl.lu)
25
+ - `MISP_API_KEY`: MISP API key
25
26
 
26
27
  Also, you can configure them manually.
27
28
 
@@ -60,7 +61,7 @@ event.update
60
61
  event = MISP::Event.get(17)
61
62
  event.add_attribute(value: "8.8.8.8", type: "ip-dst")
62
63
  # or
63
- attribute = MISP::Attribute(value: "1.1.1.1", type: "ip-dst")
64
+ attribute = MISP::Attribute.new(value: "1.1.1.1", type: "ip-dst")
64
65
  event.add_attribute attribute
65
66
  event.update
66
67
  ```
@@ -109,6 +110,14 @@ event.tags << MISP::Tag.new(name: "my event-level tag")
109
110
  event.create
110
111
  ```
111
112
 
113
+ ### Search for events / attributes
114
+
115
+ ```ruby
116
+ events = MISP::Event.search(info: "test")
117
+
118
+ attributes = MISP::Attribute.search(type: "ip-dst")
119
+ ```
120
+
112
121
  ## Acknowledgement
113
122
 
114
123
  The implementation design of this gem is highly influenced by [FloatingGhost/mispex](https://github.com/FloatingGhost/mispex).
@@ -2,48 +2,70 @@
2
2
 
3
3
  module MISP
4
4
  class Attribute < Base
5
+ # @return [String]
5
6
  attr_reader :id
7
+ # @return [String]
6
8
  attr_accessor :type
9
+ # @return [String]
7
10
  attr_accessor :category
11
+ # @return [Boolean]
8
12
  attr_accessor :to_ids
13
+ # @return [String]
9
14
  attr_reader :uuid
15
+ # @return [String]
10
16
  attr_reader :event_id
17
+ # @return [String]
11
18
  attr_accessor :distribution
19
+ # @return [String]
12
20
  attr_accessor :timestamp
21
+ # @return [String]
13
22
  attr_accessor :comment
23
+ # @return [String]
14
24
  attr_accessor :sharing_group_id
25
+ # @return [Boolean]
15
26
  attr_accessor :deleted
27
+ # @return [Boolean]
16
28
  attr_accessor :disable_correlation
29
+ # @return [String]
17
30
  attr_accessor :value
31
+ # @return [String]
18
32
  attr_accessor :data
19
33
 
34
+ # @return [Array<MISP::SharingGroup>]
20
35
  attr_accessor :sharing_groups
36
+ # @return [Array<MISP::Attribute>]
21
37
  attr_accessor :shadow_attributes
38
+ # @return [Array<MISP::Tag>]
22
39
  attr_accessor :tags
23
40
 
24
41
  def initialize(**attributes)
25
- attributes = normalize_attributes(attributes)
26
-
27
- @id = attributes.dig(:id)
28
- @type = attributes.dig(:type)
29
- @category = attributes.dig(:category)
30
- @to_ids = attributes.dig(:to_ids)
31
- @uuid = attributes.dig(:uuid)
32
- @event_id = attributes.dig(:event_id)
33
- @distribution = attributes.dig(:distribution)
34
- @timestamp = attributes.dig(:timestamp)
35
- @comment = attributes.dig(:comment)
36
- @sharing_group_id = attributes.dig(:sharing_group_id)
37
- @deleted = attributes.dig(:deleted)
38
- @disable_correlation = attributes.dig(:disable_correlation)
39
- @value = attributes.dig(:value)
40
- @data = attributes.dig(:data)
41
-
42
- @sharing_groups = build_plural_attribute(items: attributes.dig(:SharingGroup), klass: SharingGroup)
43
- @shadow_attributes = build_plural_attribute(items: attributes.dig(:ShadowAttribute), klass: Attribute )
44
- @tags = build_plural_attribute(items: attributes.dig(:Tag), klass: Tag)
42
+ attributes = normalize_attributes(**attributes)
43
+
44
+ @id = attributes[:id]
45
+ @type = attributes[:type]
46
+ @category = attributes[:category]
47
+ @to_ids = attributes[:to_ids]
48
+ @uuid = attributes[:uuid]
49
+ @event_id = attributes[:event_id]
50
+ @distribution = attributes[:distribution]
51
+ @timestamp = attributes[:timestamp]
52
+ @comment = attributes[:comment]
53
+ @sharing_group_id = attributes[:sharing_group_id]
54
+ @deleted = attributes[:deleted]
55
+ @disable_correlation = attributes[:disable_correlation]
56
+ @value = attributes[:value]
57
+ @data = attributes[:data]
58
+
59
+ @sharing_groups = build_plural_attribute(items: attributes[:SharingGroup], klass: SharingGroup)
60
+ @shadow_attributes = build_plural_attribute(items: attributes[:ShadowAttribute], klass: Attribute )
61
+ @tags = build_plural_attribute(items: attributes[:Tag], klass: Tag)
45
62
  end
46
63
 
64
+ #
65
+ # Returns a hash representation of the attribute data.
66
+ #
67
+ # @return [Hash]
68
+ #
47
69
  def to_h
48
70
  {
49
71
  id: id,
@@ -66,36 +88,53 @@ module MISP
66
88
  }.compact
67
89
  end
68
90
 
91
+ #
92
+ # Get an attribute
93
+ #
94
+ # @return [MISP::Attribute]
95
+ #
69
96
  def get
70
- _get("/attributes/#{id}") { |attribute| Attribute.new symbolize_keys(attribute) }
71
- end
72
-
73
- def self.get(id)
74
- new(id: id).get
97
+ _get("/attributes/#{id}") { |attribute| Attribute.new attribute }
75
98
  end
76
99
 
100
+ #
101
+ # Delete an attribute
102
+ #
103
+ # @return [Hash]
104
+ #
77
105
  def delete
78
106
  _post("/attributes/delete/#{id}") { |json| json }
79
107
  end
80
108
 
81
- def self.delete(id)
82
- new(id: id).delete
83
- end
84
-
109
+ #
110
+ # Create an attribute
111
+ #
112
+ # @return [MISP::Attribute]
113
+ #
85
114
  def create(event_id)
86
- _post("/attributes/add/#{event_id}", wrap(to_h)) { |attribute| Attribute.new symbolize_keys(attribute) }
87
- end
88
-
89
- def self.create(event_id, **attributes)
90
- new(attributes).create(event_id)
115
+ _post("/attributes/add/#{event_id}", wrap(to_h)) { |attribute| Attribute.new(**attribute) }
91
116
  end
92
117
 
118
+ #
119
+ # Update an attribute
120
+ #
121
+ # @param [Hash] **attrs attributes
122
+ #
123
+ # @return [MISP::Attribute]
124
+ #
93
125
  def update(**attrs)
94
126
  payload = to_h.merge(attrs)
95
127
  payload[:timestamp] = nil
96
- _post("/attributes/edit/#{id}", wrap(payload)) { |json| Attribute.new symbolize_keys(json.dig("response", "Attribute")) }
128
+ _post("/attributes/edit/#{id}", wrap(payload)) { |json| Attribute.new(**json.dig(:response, :Attribute)) }
97
129
  end
98
130
 
131
+ #
132
+ # Search for attributes
133
+ #
134
+ # @param [Hash] **params parameters
135
+ #
136
+ # @return [Array<MISP::Attributes>]
137
+ #
99
138
  def search(**params)
100
139
  base = {
101
140
  returnFormat: "json",
@@ -104,25 +143,53 @@ module MISP
104
143
  }
105
144
 
106
145
  _post("/attributes/restSearch", base.merge(params)) do |json|
107
- attributes = json.dig("response", "Attribute") || []
108
- attributes.map { |attribute| Attribute.new symbolize_keys(attribute) }
146
+ attributes = json.dig(:response, :Attribute) || []
147
+ attributes.map { |attribute| Attribute.new(**attribute) }
109
148
  end
110
149
  end
111
150
 
112
- def self.search(**params)
113
- new.search params
114
- end
115
-
151
+ #
152
+ # Add a tag to an attribute
153
+ #
154
+ # @param [MISP::Tag, Hash] tag
155
+ #
156
+ # @return [MISP::Tag]
157
+ #
116
158
  def add_tag(tag)
117
- tag = Tag.new(symbolize_keys(tag)) unless tag.is_a?(MISP::Tag)
159
+ tag = Tag.new(**tag) unless tag.is_a?(MISP::Tag)
118
160
  payload = { uuid: uuid, tag: tag.name }
119
- _post("/tags/attachTagToObject", payload) { |json| Tag.new symbolize_keys(json) }
161
+ _post("/tags/attachTagToObject", payload) { |json| Tag.new(**json) }
120
162
  end
121
163
 
164
+ #
165
+ # Remove a tag from an attribute
166
+ #
167
+ # @param [MISP::Tag, Hash] tag
168
+ #
169
+ # @return [Hash]
170
+ #
122
171
  def remove_tag(tag)
123
- tag = Tag.new(symbolize_keys(tag)) unless tag.is_a?(MISP::Tag)
172
+ tag = Tag.new(**tag) unless tag.is_a?(MISP::Tag)
124
173
  payload = { uuid: uuid, tag: tag.name }
125
174
  _post("/tags/removeTagFromObject", payload) { |json| json }
126
175
  end
176
+
177
+ class << self
178
+ def get(id)
179
+ new(id: id).get
180
+ end
181
+
182
+ def delete(id)
183
+ new(id: id).delete
184
+ end
185
+
186
+ def create(event_id, **attributes)
187
+ new(**attributes).create(event_id)
188
+ end
189
+
190
+ def search(**params)
191
+ new.search(**params)
192
+ end
193
+ end
127
194
  end
128
195
  end
data/lib/misp/base.rb CHANGED
@@ -6,40 +6,67 @@ require "uri"
6
6
 
7
7
  module MISP
8
8
  class Base
9
+ private
10
+
11
+ #
12
+ # API endpoint
13
+ #
14
+ # @return [URI]
15
+ #
9
16
  def api_endpoint
10
17
  @api_endpoint ||= URI(MISP.configuration.api_endpoint)
11
18
  end
12
19
 
20
+ #
21
+ # API key
22
+ #
23
+ # @return [String]
24
+ #
13
25
  def api_key
14
26
  @api_key ||= MISP.configuration.api_key
15
27
  end
16
28
 
17
- private
18
-
29
+ #
30
+ # Build an instance of a class
31
+ #
32
+ # @param [Hash] item
33
+ # @param [Class] klass
34
+ #
35
+ # @return [Class]
36
+ #
19
37
  def build_attribute(item:, klass:)
20
38
  return nil unless item
21
39
 
22
- klass.new symbolize_keys(item)
40
+ klass.new(**item)
23
41
  end
24
42
 
43
+ #
44
+ # Build an array of an instance of a class
45
+ #
46
+ # @param [Array<Hash>] items
47
+ # @param [Class] klass
48
+ #
49
+ # @return [Arra<Class>]
50
+ #
25
51
  def build_plural_attribute(items:, klass:)
26
52
  (items || []).map do |item|
27
- klass.new symbolize_keys(item)
53
+ klass.new(**item)
28
54
  end
29
55
  end
30
56
 
31
- def symbolize_keys(hash)
32
- hash.map { |k, v| [k.to_sym, v] }.to_h
33
- end
34
-
57
+ #
58
+ # a name of the class
59
+ #
60
+ # @return [String]
61
+ #
35
62
  def class_name
36
63
  self.class.to_s.split("::").last.to_s
37
64
  end
38
65
 
39
- def normalize_attributes(attributes)
66
+ def normalize_attributes(**attributes)
40
67
  klass = class_name.to_sym
41
68
 
42
- attributes.key?(klass) ? symbolize_keys(attributes.dig(klass)) : attributes
69
+ attributes.key?(klass) ? attributes[klass] : attributes
43
70
  end
44
71
 
45
72
  def wrap(params)
@@ -99,7 +126,7 @@ module MISP
99
126
  end
100
127
 
101
128
  def parse_body(body)
102
- JSON.parse body.to_s
129
+ JSON.parse body.to_s, symbolize_names: true
103
130
  rescue JSON::ParserError => _e
104
131
  body.to_s
105
132
  end
@@ -122,9 +149,9 @@ module MISP
122
149
 
123
150
  def default_headers
124
151
  {
125
- "Content-Type": "application/json",
126
- "Accept": "application/json",
127
- "Authorization": api_key
152
+ 'Content-Type': "application/json",
153
+ Accept: "application/json",
154
+ Authorization: api_key
128
155
  }
129
156
  end
130
157
 
@@ -14,15 +14,15 @@ module MISP
14
14
  end
15
15
  end
16
16
 
17
- def self.configuration
18
- @configuration ||= Configuration.new
19
- end
17
+ class << self
18
+ def configuration
19
+ @configuration ||= Configuration.new
20
+ end
20
21
 
21
- def self.configuration=(config)
22
- @configuration = config
23
- end
22
+ attr_writer :configuration
24
23
 
25
- def self.configure
26
- yield configuration
24
+ def configure
25
+ yield configuration
26
+ end
27
27
  end
28
28
  end