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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc528f87e1d77992648872b73b304cadd0770fcd61104a013b968da7c6db8712
4
- data.tar.gz: d84191bbf3ef2aa98e43e6ab76c73e63f277387141bd406f5ee670b6a1c1b879
3
+ metadata.gz: 59094f4d94c54c1468ac70bb38ed293f0d7faa99b4626d409742060c48b0bd74
4
+ data.tar.gz: c7d004ebbb8774848c1874db3ebc93f4f27eccc5662193d9ed5c0e2cb3872c40
5
5
  SHA512:
6
- metadata.gz: ca13340ef9443169c8aafba8ee2181398eb1c26c8544c463508236d717ea1697eec8627fc23b6f34391356bd6816f71eee28c50aea2ea06b8a259b4d3f36a6ac
7
- data.tar.gz: eaee116e0eb3ddae02329cd3c6287b81ad00bf80bb7ac3afb961fd5dcda7f2d53ceb0927230b041f38e43fce2c227cdd2ede6b9189376d69879dd8648276f4fb
6
+ metadata.gz: 325da7bd11690bf0837a17809526cd051c3482dbae094af1740b2561b0a5492809ea51ff093f568d63eba48a196eb363b5d56491b50bdde7de2a025f2a852d0b
7
+ data.tar.gz: 7ab0a2f04941f2884c9c5a3100b4991f414b37e84f3a6d6aaf1733d3ccaeafe2f9399a54cbfc1e80e42f9eea670db8695ec740d854310ad02b90cd7408cd11b6
@@ -7,12 +7,18 @@ on:
7
7
  jobs:
8
8
  build:
9
9
  name: RSpec
10
- runs-on: ubuntu-latest
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: 3.1.2
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
@@ -10,3 +10,4 @@
10
10
  /spec/fixtures/spec_ca/
11
11
  /tmp/
12
12
  /vendor/bundle/
13
+ *.gem
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-taxii'
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-taxii
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/ryanbreed/ruby-taxii.
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
@@ -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
- CONTENT_XPATH = '/taxii_11:Poll_Response/taxii_11:Content_Block/taxii_11:Content'
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( poll_request_message, url: self.poll_service_url)
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( poll_request_message,
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
- content_xml.xpath(xpath).flat_map { |blk| blk.children.map(&:to_s) }
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
@@ -1,3 +1,3 @@
1
1
  module Taxii
2
- VERSION = '0.3.1'
2
+ VERSION = '0.3.2'
3
3
  end
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(config: File.join(ENV['HOME'],'.taxii.json'), client: PollClient)
20
- configuration = JSON.parse(File.read(config))
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
@@ -33,4 +33,6 @@ Gem::Specification.new do |spec|
33
33
  spec.add_development_dependency 'simplecov'
34
34
  spec.add_development_dependency 'vcr'
35
35
  spec.add_development_dependency 'webmock'
36
+ spec.add_development_dependency 'pry'
37
+ spec.add_development_dependency 'pry-byebug'
36
38
  end
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.1
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-27 00:00:00.000000000 Z
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