misp 0.1.0 → 0.1.4
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/.github/workflows/test.yaml +23 -0
- data/README.md +12 -3
- data/lib/misp/attribute.rb +111 -44
- data/lib/misp/base.rb +41 -14
- data/lib/misp/configuration.rb +8 -8
- data/lib/misp/event.rb +140 -65
- data/lib/misp/feed.rb +82 -36
- data/lib/misp/galaxy.rb +40 -16
- data/lib/misp/galaxy_cluster.rb +28 -12
- data/lib/misp/org.rb +12 -4
- data/lib/misp/orgc.rb +12 -4
- data/lib/misp/server.rb +22 -7
- data/lib/misp/sharing_group.rb +67 -27
- data/lib/misp/sharing_group_org.rb +17 -7
- data/lib/misp/sharing_group_server.rb +17 -7
- data/lib/misp/tag.rb +71 -28
- data/lib/misp/version.rb +1 -1
- data/misp.gemspec +6 -6
- data/renovate.json +5 -0
- metadata +21 -20
- data/.travis.yml +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc2ae518cdfe5d3872000bf12bd1083a4a8540a3e6857e50573b1b8011604605
|
4
|
+
data.tar.gz: 25917d69a7a912ace45ccaa43f5bc0a5202e37e66532e1eabf30a09df0478c2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
+
[](https://badge.fury.io/rb/misp)
|
3
4
|
[](https://travis-ci.com/ninoseki/misp-rb)
|
4
5
|
[](https://coveralls.io/github/ninoseki/misp-rb?branch=master)
|
5
6
|
[](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
|
24
|
-
- 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).
|
data/lib/misp/attribute.rb
CHANGED
@@ -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
|
28
|
-
@type = attributes
|
29
|
-
@category = attributes
|
30
|
-
@to_ids = attributes
|
31
|
-
@uuid = attributes
|
32
|
-
@event_id = attributes
|
33
|
-
@distribution = attributes
|
34
|
-
@timestamp = attributes
|
35
|
-
@comment = attributes
|
36
|
-
@sharing_group_id = attributes
|
37
|
-
@deleted = attributes
|
38
|
-
@disable_correlation = attributes
|
39
|
-
@value = attributes
|
40
|
-
@data = attributes
|
41
|
-
|
42
|
-
@sharing_groups = build_plural_attribute(items: attributes
|
43
|
-
@shadow_attributes = build_plural_attribute(items: attributes
|
44
|
-
@tags = build_plural_attribute(items: attributes
|
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
|
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
|
-
|
82
|
-
|
83
|
-
|
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
|
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
|
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(
|
108
|
-
attributes.map { |attribute| Attribute.new
|
146
|
+
attributes = json.dig(:response, :Attribute) || []
|
147
|
+
attributes.map { |attribute| Attribute.new(**attribute) }
|
109
148
|
end
|
110
149
|
end
|
111
150
|
|
112
|
-
|
113
|
-
|
114
|
-
|
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(
|
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
|
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(
|
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
|
-
|
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
|
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
|
53
|
+
klass.new(**item)
|
28
54
|
end
|
29
55
|
end
|
30
56
|
|
31
|
-
|
32
|
-
|
33
|
-
|
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) ?
|
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
|
-
|
126
|
-
|
127
|
-
|
152
|
+
'Content-Type': "application/json",
|
153
|
+
Accept: "application/json",
|
154
|
+
Authorization: api_key
|
128
155
|
}
|
129
156
|
end
|
130
157
|
|
data/lib/misp/configuration.rb
CHANGED
@@ -14,15 +14,15 @@ module MISP
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
class << self
|
18
|
+
def configuration
|
19
|
+
@configuration ||= Configuration.new
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
-
@configuration = config
|
23
|
-
end
|
22
|
+
attr_writer :configuration
|
24
23
|
|
25
|
-
|
26
|
-
|
24
|
+
def configure
|
25
|
+
yield configuration
|
26
|
+
end
|
27
27
|
end
|
28
28
|
end
|