ruby-taxii2 0.3.1 → 0.3.2
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/rspec.yml +8 -2
- data/.gitignore +1 -0
- data/README.md +38 -3
- data/lib/taxii/client.rb +11 -4
- data/lib/taxii/messages/collection_information_request.rb +18 -0
- data/lib/taxii/messages/content_block.rb +29 -0
- data/lib/taxii/messages/poll_fulfillment_request.rb +25 -0
- data/lib/taxii/messages/poll_request.rb +2 -2
- data/lib/taxii/poll_client.rb +43 -7
- data/lib/taxii/version.rb +1 -1
- data/lib/taxii.rb +19 -2
- data/ruby-taxii.gemspec +2 -0
- metadata +33 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 59094f4d94c54c1468ac70bb38ed293f0d7faa99b4626d409742060c48b0bd74
|
4
|
+
data.tar.gz: c7d004ebbb8774848c1874db3ebc93f4f27eccc5662193d9ed5c0e2cb3872c40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 325da7bd11690bf0837a17809526cd051c3482dbae094af1740b2561b0a5492809ea51ff093f568d63eba48a196eb363b5d56491b50bdde7de2a025f2a852d0b
|
7
|
+
data.tar.gz: 7ab0a2f04941f2884c9c5a3100b4991f414b37e84f3a6d6aaf1733d3ccaeafe2f9399a54cbfc1e80e42f9eea670db8695ec740d854310ad02b90cd7408cd11b6
|
data/.github/workflows/rspec.yml
CHANGED
@@ -7,12 +7,18 @@ on:
|
|
7
7
|
jobs:
|
8
8
|
build:
|
9
9
|
name: RSpec
|
10
|
-
|
10
|
+
strategy:
|
11
|
+
matrix:
|
12
|
+
os: [ubuntu-latest, windows-latest]
|
13
|
+
ruby: ['2.7', '3.0', '3.1', head]
|
14
|
+
runs-on: ${{ matrix.os }}
|
11
15
|
steps:
|
12
16
|
- uses: actions/checkout@v3
|
13
17
|
- name: Set up Ruby
|
14
18
|
uses: ruby/setup-ruby@v1
|
15
19
|
with:
|
16
|
-
ruby-version:
|
20
|
+
ruby-version: ${{ matrix.ruby }}
|
21
|
+
bundler: latest
|
17
22
|
- run: bundle
|
18
23
|
- run: bundle exec rspec
|
24
|
+
- run: bundle exec gem build
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -9,7 +9,7 @@ Currently under development - likely to break at a moment's notice.
|
|
9
9
|
Add this line to your application's Gemfile:
|
10
10
|
|
11
11
|
```ruby
|
12
|
-
gem 'ruby-
|
12
|
+
gem 'ruby-taxii2'
|
13
13
|
```
|
14
14
|
|
15
15
|
And then execute:
|
@@ -18,14 +18,49 @@ And then execute:
|
|
18
18
|
|
19
19
|
Or install it yourself as:
|
20
20
|
|
21
|
-
$ gem install ruby-
|
21
|
+
$ gem install ruby-taxii2
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
+
```ruby
|
26
|
+
require 'taxii'
|
27
|
+
|
28
|
+
# You can use a json file configuration
|
29
|
+
# client = Taxii::configure(config: 'my.config.json')
|
30
|
+
# or a direct configuration
|
31
|
+
client = Taxii::configure(user: 'user', pass: 'pass', url: 'url')
|
32
|
+
collections = client.discover_collections
|
33
|
+
|
34
|
+
# List collections (name, type and availability)
|
35
|
+
puts "Listing collections:"
|
36
|
+
collections.each do |collection|
|
37
|
+
puts "#{collection['@collection_name']} #{collection['@collection_type']} #{collection['@available']}"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Pick up the first available collection
|
41
|
+
collection_name = collections.find{ |collection| collection['@available'] == 'true' }['@collection_name']
|
42
|
+
|
43
|
+
puts "Retrieving data for collection: #{collection_name}"
|
44
|
+
poll_request_message = Taxii::Messages::PollRequest.new(
|
45
|
+
collection_name: collection_name,
|
46
|
+
poll_parameters: Taxii::Messages::Parameters::Poll.new(response_type: 'FULL')
|
47
|
+
)
|
48
|
+
|
49
|
+
client.get_content_blocks(poll_request_message).each do |message|
|
50
|
+
begin
|
51
|
+
# Try to parse the response as a Content_Block
|
52
|
+
pp Taxii::Messages::ContentBlock.new(message)
|
53
|
+
# You can also convert it to json
|
54
|
+
# pp Taxii::Messages::ContentBlock.new(message).as_json
|
55
|
+
rescue
|
56
|
+
puts 'This is not a ContentBlock'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
```
|
25
60
|
|
26
61
|
## Development
|
27
62
|
|
28
63
|
|
29
64
|
## Contributing
|
30
65
|
|
31
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
66
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/crondaemon/ruby-taxii2.
|
data/lib/taxii/client.rb
CHANGED
@@ -14,7 +14,7 @@ module Taxii
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
def build_request(url: self.url,payload: {}, format: Taxii::Messages::TAXII_11_HEADERS)
|
17
|
+
def build_request(url: self.url, payload: {}, format: Taxii::Messages::TAXII_11_HEADERS)
|
18
18
|
RestClient::Request.new(
|
19
19
|
method: :post,
|
20
20
|
url: url,
|
@@ -33,7 +33,7 @@ module Taxii
|
|
33
33
|
|
34
34
|
def get_service_address(service_name)
|
35
35
|
service = discover_services.find do |svc|
|
36
|
-
svc['@service_type']==service_name && svc['@available']=='true'
|
36
|
+
svc['@service_type'] == service_name && svc['@available'] == 'true'
|
37
37
|
end
|
38
38
|
service.nil? ? nil : service['Address']
|
39
39
|
end
|
@@ -61,11 +61,18 @@ module Taxii
|
|
61
61
|
@poll_service_url ||= get_service_address('POLL')
|
62
62
|
end
|
63
63
|
|
64
|
-
def discover_feeds(url=self.collection_management_service_url)
|
64
|
+
def discover_feeds(url = self.collection_management_service_url)
|
65
65
|
msg = Taxii::Messages::FeedInformationRequest.new.to_xml
|
66
66
|
http = build_request(url: url, payload: msg, format: Taxii::Messages::TAXII_10_HEADERS)
|
67
67
|
parsed = xml.parse(http.execute.body)
|
68
|
-
parsed['Feed_Information_Response'].fetch('Feed',[])
|
68
|
+
parsed['Feed_Information_Response'].fetch('Feed', [])
|
69
|
+
end
|
70
|
+
|
71
|
+
def discover_collections(url = self.collection_management_service_url)
|
72
|
+
msg = Taxii::Messages::CollectionInformationRequest.new.to_xml
|
73
|
+
http = build_request(url: url, payload: msg, format: Taxii::Messages::TAXII_10_HEADERS)
|
74
|
+
parsed = xml.parse(http.execute.body)
|
75
|
+
parsed['Collection_Information_Response'].fetch('Collection', [])
|
69
76
|
end
|
70
77
|
|
71
78
|
def scheme_protocol
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Taxii
|
2
|
+
module Messages
|
3
|
+
class CollectionInformationRequest < Hashie::Dash
|
4
|
+
property :message_id, default: -> { Taxii::Messages.generate_id }
|
5
|
+
|
6
|
+
def to_h
|
7
|
+
Taxii::Messages::NAMESPACE_ATTRIBUTES.merge({
|
8
|
+
'@message_id': message_id
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_xml
|
13
|
+
Gyoku.xml({'taxii_11:Collection_Information_Request/': to_h}, key_converter: :none)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Taxii
|
4
|
+
module Messages
|
5
|
+
class ContentBlock < Hashie::Dash
|
6
|
+
def initialize(body)
|
7
|
+
parsed = Nori.new(strip_namespaces: true).parse(body)
|
8
|
+
@body = parsed['Content_Block']['Content']
|
9
|
+
@body
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
@body.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def inspect
|
17
|
+
self.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def as_json
|
21
|
+
JSON.parse(@body)
|
22
|
+
end
|
23
|
+
|
24
|
+
def pretty_print(pp)
|
25
|
+
puts self.to_s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Taxii
|
2
|
+
module Messages
|
3
|
+
class PollFulfillmentRequest < Hashie::Dash
|
4
|
+
include Hashie::Extensions::Coercion
|
5
|
+
|
6
|
+
property :collection_name, default: 'system.Default'
|
7
|
+
property :result_id
|
8
|
+
property :result_part_number
|
9
|
+
property :message_id, default: -> { Taxii::Messages.generate_id }
|
10
|
+
|
11
|
+
def to_h
|
12
|
+
NAMESPACE_ATTRIBUTES.merge({
|
13
|
+
'@message_id': message_id,
|
14
|
+
'@collection_name': collection_name,
|
15
|
+
'@result_id': result_id,
|
16
|
+
'@result_part_number': result_part_number,
|
17
|
+
})
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_xml
|
21
|
+
Gyoku.xml({'taxii_11:Poll_Fulfillment': to_h}, key_converter: :none)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -21,7 +21,7 @@ module Taxii
|
|
21
21
|
if exclusive_begin_timestamp.nil?
|
22
22
|
{}
|
23
23
|
else
|
24
|
-
{'Exclusive_Begin_Timestamp': exclusive_begin_timestamp.strftime(TS_FORMAT)}
|
24
|
+
{'taxii_11:Exclusive_Begin_Timestamp': exclusive_begin_timestamp.strftime(TS_FORMAT)}
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -29,7 +29,7 @@ module Taxii
|
|
29
29
|
if inclusive_end_timestamp.nil?
|
30
30
|
{}
|
31
31
|
else
|
32
|
-
{'Inclusive_End_Timestamp': inclusive_end_timestamp.strftime(TS_FORMAT)}
|
32
|
+
{'taxii_11:Inclusive_End_Timestamp': inclusive_end_timestamp.strftime(TS_FORMAT)}
|
33
33
|
end
|
34
34
|
end
|
35
35
|
def requested_info
|
data/lib/taxii/poll_client.rb
CHANGED
@@ -3,26 +3,62 @@ module Taxii
|
|
3
3
|
include Client
|
4
4
|
|
5
5
|
PARSE_OPTIONS = Nokogiri::XML::ParseOptions::DEFAULT_XML | Nokogiri::XML::ParseOptions::NOBLANKS
|
6
|
-
|
6
|
+
POLL_RESPONSE_PATH = '/taxii_11:Poll_Response'
|
7
|
+
CONTENT_XPATH = "#{POLL_RESPONSE_PATH}/taxii_11:Content_Block/taxii_11:Content"
|
7
8
|
|
8
|
-
def get(
|
9
|
+
def get(poll_request_message, url: self.poll_service_url)
|
9
10
|
msg = format_request(poll_request_message)
|
10
11
|
build_request(url: url, payload: msg).execute
|
11
12
|
end
|
12
13
|
|
13
|
-
def get_content_blocks(
|
14
|
+
def get_content_blocks(poll_request_message,
|
14
15
|
url: self.poll_service_url,
|
15
|
-
xpath: CONTENT_XPATH
|
16
|
+
xpath: CONTENT_XPATH)
|
16
17
|
response = self.get(poll_request_message, url: url)
|
17
|
-
content_xml = Nokogiri::XML(response.body,nil,nil,PARSE_OPTIONS)
|
18
|
-
|
18
|
+
@content_xml = Nokogiri::XML(response.body, nil, nil, PARSE_OPTIONS)
|
19
|
+
|
20
|
+
blocks = response_blocks
|
21
|
+
|
22
|
+
# We have a muulti-part message
|
23
|
+
# http://docs.oasis-open.org/cti/taxii/v1.1.1/cs01/part2-services/taxii-v1.1.1-cs01-part2-services.html#_Toc450734190
|
24
|
+
while attribute_more == 'true'
|
25
|
+
poll_fulfillment_message = Taxii::Messages::PollFulfillmentRequest.new(
|
26
|
+
collection_name: poll_request_message.collection_name,
|
27
|
+
result_id: result_id,
|
28
|
+
result_part_number: result_part_number + 1)
|
29
|
+
|
30
|
+
response = self.get(poll_fulfillment_message, url: url)
|
31
|
+
@content_xml = Nokogiri::XML(response.body, nil, nil, PARSE_OPTIONS)
|
32
|
+
|
33
|
+
blocks += response_blocks
|
34
|
+
end
|
35
|
+
|
36
|
+
blocks
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def response_blocks
|
42
|
+
@content_xml.xpath(POLL_RESPONSE_PATH).flat_map { |blk| blk.children.map(&:to_s) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def attribute_more
|
46
|
+
@content_xml.at_xpath(POLL_RESPONSE_PATH).attributes['more'].value
|
47
|
+
end
|
48
|
+
|
49
|
+
def result_id
|
50
|
+
@content_xml.at_xpath(POLL_RESPONSE_PATH).attributes['result_id'].value
|
51
|
+
end
|
52
|
+
|
53
|
+
def result_part_number
|
54
|
+
@content_xml.at_xpath(POLL_RESPONSE_PATH).attributes['result_part_number'].value.to_i
|
19
55
|
end
|
20
56
|
|
21
57
|
def format_request(request_message)
|
22
58
|
case request_message
|
23
59
|
when String
|
24
60
|
request_message
|
25
|
-
when Taxii::Messages::PollRequest
|
61
|
+
when Taxii::Messages::PollRequest, Taxii::Messages::PollFulfillmentRequest
|
26
62
|
request_message.to_xml
|
27
63
|
else
|
28
64
|
fail ArgumentError, 'request message must be String or PollRequest'
|
data/lib/taxii/version.rb
CHANGED
data/lib/taxii.rb
CHANGED
@@ -4,6 +4,7 @@ require 'rest-client'
|
|
4
4
|
require 'uri'
|
5
5
|
require 'nori'
|
6
6
|
require 'gyoku'
|
7
|
+
require 'json'
|
7
8
|
|
8
9
|
require 'taxii/version'
|
9
10
|
require 'taxii/time_extensions'
|
@@ -11,13 +12,29 @@ require 'taxii/messages'
|
|
11
12
|
require 'taxii/messages/parameters'
|
12
13
|
require 'taxii/messages/discovery_request'
|
13
14
|
require 'taxii/messages/poll_request'
|
15
|
+
require 'taxii/messages/poll_fulfillment_request'
|
14
16
|
require 'taxii/messages/feed_information_request'
|
17
|
+
require 'taxii/messages/collection_information_request'
|
18
|
+
require 'taxii/messages/content_block'
|
15
19
|
require 'taxii/client'
|
16
20
|
require 'taxii/poll_client'
|
17
21
|
|
18
22
|
module Taxii
|
19
|
-
def self.configure(
|
20
|
-
|
23
|
+
def self.configure(options = {})
|
24
|
+
client = options.fetch(:client, PollClient)
|
25
|
+
config = options.fetch(:config, File.join(ENV['HOME'],'.taxii.json'))
|
26
|
+
user = options[:user]
|
27
|
+
pass = options[:pass]
|
28
|
+
url = options[:url]
|
29
|
+
|
30
|
+
if user && pass && url
|
31
|
+
configuration = { user: user, pass: pass, url: url }
|
32
|
+
elsif File.exist?(config)
|
33
|
+
configuration = JSON.parse(File.read(config))
|
34
|
+
else
|
35
|
+
raise('You must provide user+pass+url, ora a config file, or have a default $HOME/.taxii.json')
|
36
|
+
end
|
37
|
+
|
21
38
|
client.new(configuration)
|
22
39
|
end
|
23
40
|
|
data/ruby-taxii.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-taxii2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dario Lombardo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-05
|
11
|
+
date: 2023-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -206,6 +206,34 @@ dependencies:
|
|
206
206
|
- - ">="
|
207
207
|
- !ruby/object:Gem::Version
|
208
208
|
version: '0'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: pry
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ">="
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: pry-byebug
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - ">="
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: '0'
|
230
|
+
type: :development
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
requirements:
|
234
|
+
- - ">="
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: '0'
|
209
237
|
description: " implement api-alike for python libtaxii https://github.com/TAXIIProject/libtaxii "
|
210
238
|
email:
|
211
239
|
- lomato@gmail.com
|
@@ -225,9 +253,12 @@ files:
|
|
225
253
|
- lib/taxii.rb
|
226
254
|
- lib/taxii/client.rb
|
227
255
|
- lib/taxii/messages.rb
|
256
|
+
- lib/taxii/messages/collection_information_request.rb
|
257
|
+
- lib/taxii/messages/content_block.rb
|
228
258
|
- lib/taxii/messages/discovery_request.rb
|
229
259
|
- lib/taxii/messages/feed_information_request.rb
|
230
260
|
- lib/taxii/messages/parameters.rb
|
261
|
+
- lib/taxii/messages/poll_fulfillment_request.rb
|
231
262
|
- lib/taxii/messages/poll_request.rb
|
232
263
|
- lib/taxii/parsers/sax_poll_response.rb
|
233
264
|
- lib/taxii/poll_client.rb
|