huntress 0.1.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 +7 -0
- data/.env.template +2 -0
- data/.gitignore +44 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +10 -0
- data/README.md +86 -0
- data/Rakefile +20 -0
- data/huntress.gemspec +37 -0
- data/lib/huntress/api.rb +35 -0
- data/lib/huntress/authentication.rb +25 -0
- data/lib/huntress/client.rb +92 -0
- data/lib/huntress/connection.rb +16 -0
- data/lib/huntress/error.rb +9 -0
- data/lib/huntress/pagination.rb +109 -0
- data/lib/huntress/version.rb +5 -0
- data/lib/huntress.rb +45 -0
- metadata +143 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b47fbf82bfacb413dde2b52eed39dfaf2aa240d38798a315efdf3e669b3859c8
|
|
4
|
+
data.tar.gz: 7726b763502f9ab5f18a1c86057c9118a44abd5ddf518161b528add65cfeaf04
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 075da61fc4b04310b673b0a1e72d32eb2d2a1c044667587fa28781952753873604361c6ccb0c4f87a9dc7e4e16833982ecc754696351596953c14a10d3c9dfc1
|
|
7
|
+
data.tar.gz: 7c6c0769058c8e5da1b5eefeb9577a9c47b83fb99078e718bd9cd78cbdda79ea494fca3906db623198dc99d129ea3aa603215735de0dd45fb3cba246f6a1d1ab
|
data/.env.template
ADDED
data/.gitignore
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
/.config
|
|
4
|
+
/coverage/
|
|
5
|
+
/InstalledFiles
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/spec/examples.txt
|
|
9
|
+
/test/tmp/
|
|
10
|
+
/test/version_tmp/
|
|
11
|
+
/tmp/
|
|
12
|
+
/data/
|
|
13
|
+
*.log
|
|
14
|
+
*.txt
|
|
15
|
+
*.json
|
|
16
|
+
*.yml
|
|
17
|
+
|
|
18
|
+
# Used by dotenv library to load environment variables.
|
|
19
|
+
.env
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## Documentation cache and generated files:
|
|
23
|
+
/.yardoc/
|
|
24
|
+
/_yardoc/
|
|
25
|
+
/doc/
|
|
26
|
+
/rdoc/
|
|
27
|
+
|
|
28
|
+
## Environment normalization:
|
|
29
|
+
/.bundle/
|
|
30
|
+
/vendor/bundle
|
|
31
|
+
/lib/bundler/man/
|
|
32
|
+
|
|
33
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
34
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
35
|
+
# Gemfile.lock
|
|
36
|
+
# .ruby-version
|
|
37
|
+
# .ruby-gemset
|
|
38
|
+
|
|
39
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
40
|
+
.rvmrc
|
|
41
|
+
|
|
42
|
+
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
|
43
|
+
# .rubocop-https?--*
|
|
44
|
+
Gemfile.lock
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Sophos Central Partner API
|
|
2
|
+
|
|
3
|
+
[](https://rubygems.org/gems/huntress)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
This is a wrapper for the Huntress API.
|
|
7
|
+
You can see the [API endpoints](https://api.huntress.io/docs)
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Add this line to your application's Gemfile:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
gem 'huntress'
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
And then execute:
|
|
18
|
+
|
|
19
|
+
```console
|
|
20
|
+
> bundle install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or install it yourself as:
|
|
24
|
+
|
|
25
|
+
```console
|
|
26
|
+
> gem install huntress
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
Before you start making the requests to API provide the client id and client secret
|
|
32
|
+
and email/password using the configuration wrapping.
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
require 'huntress'
|
|
36
|
+
|
|
37
|
+
LOGGER = 'huntres-api.log'
|
|
38
|
+
|
|
39
|
+
Huntress.reset
|
|
40
|
+
Huntress.logger = Logger.new(AUTH_LOGGER)
|
|
41
|
+
|
|
42
|
+
Huntress.configure do |config|
|
|
43
|
+
config.client_id = ENV['HUNTRESS_API_KEY']
|
|
44
|
+
config.client_secret = ENV['HUNTRESS_API_SECRET']
|
|
45
|
+
end
|
|
46
|
+
client = Huntress.client
|
|
47
|
+
result = client.login
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Resources
|
|
51
|
+
|
|
52
|
+
### Authentication
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
# setup configuration
|
|
56
|
+
#
|
|
57
|
+
client.login
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
|Resource|API endpoint|Description|
|
|
61
|
+
|:--|:--|:--|
|
|
62
|
+
|.login|||
|
|
63
|
+
|
|
64
|
+
### Operations
|
|
65
|
+
|
|
66
|
+
Huntress endpoint implemented
|
|
67
|
+
|
|
68
|
+
|Resource|API endpoint|
|
|
69
|
+
|:--|:--|
|
|
70
|
+
|.account |/v1/account|
|
|
71
|
+
|.actor |/v1/actor|
|
|
72
|
+
|.agents, .agent(id) |/v1/agents/{id}|
|
|
73
|
+
|.billing_reports, .billing_report |/v1/billing_reports/{id}|
|
|
74
|
+
|.incident_reports, .incident_report(id) |/v1/incident_reports/{id}|
|
|
75
|
+
|.remediations(report_id), .remediation(report_id, id) |/v1incident_reports/{report_id}/remediations/{id}|
|
|
76
|
+
|.organizations, .organization(id) |/v1/organizations/{id}|
|
|
77
|
+
|.reports, .report(id) |/v1/reports/{id}|
|
|
78
|
+
|.signals, .signal(id) |/v1/signals/{id}|
|
|
79
|
+
|
|
80
|
+
## Contributing
|
|
81
|
+
|
|
82
|
+
Bug reports and pull requests are welcome on [GitHub](https://github.com/jancotanis/huntress).
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/gem_tasks'
|
|
4
|
+
require 'dotenv'
|
|
5
|
+
require 'rake/testtask'
|
|
6
|
+
|
|
7
|
+
Dotenv.load
|
|
8
|
+
|
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
|
10
|
+
t.libs << 'test'
|
|
11
|
+
t.libs << 'lib'
|
|
12
|
+
t.test_files = FileList['test/**/*_test.rb']
|
|
13
|
+
at_exit do
|
|
14
|
+
system './bin/cc-test-reporter after-build'
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
require 'rubocop/rake_task'
|
|
19
|
+
RuboCop::RakeTask.new
|
|
20
|
+
task default: %i[test rubocop]
|
data/huntress.gemspec
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/huntress/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = 'huntress'
|
|
7
|
+
s.version = Huntress::VERSION
|
|
8
|
+
s.authors = ['Janco Tanis']
|
|
9
|
+
s.email = 'gems@jancology.com'
|
|
10
|
+
s.license = 'MIT'
|
|
11
|
+
|
|
12
|
+
s.summary = 'A Ruby wrapper for the Huntress APIs (readonly)'
|
|
13
|
+
s.homepage = 'https://rubygems.org/gems/huntress'
|
|
14
|
+
|
|
15
|
+
s.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
|
|
16
|
+
|
|
17
|
+
s.metadata['homepage_uri'] = s.homepage
|
|
18
|
+
s.metadata['source_code_uri'] = 'https://github.com/jancotanis/huntress'
|
|
19
|
+
|
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
22
|
+
s.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
23
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
|
24
|
+
end
|
|
25
|
+
s.bindir = 'exe'
|
|
26
|
+
s.executables = s.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
27
|
+
s.require_paths = ['lib']
|
|
28
|
+
|
|
29
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
30
|
+
s.platform = Gem::Platform::RUBY
|
|
31
|
+
s.add_runtime_dependency 'faraday'
|
|
32
|
+
s.add_runtime_dependency 'wrapi', ">= 0.5.0"
|
|
33
|
+
s.add_development_dependency 'dotenv'
|
|
34
|
+
s.add_development_dependency 'minitest'
|
|
35
|
+
s.add_development_dependency 'simplecov'
|
|
36
|
+
s.add_development_dependency 'rubocop'
|
|
37
|
+
end
|
data/lib/huntress/api.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'wrapi'
|
|
4
|
+
require File.expand_path('connection', __dir__)
|
|
5
|
+
require File.expand_path('authentication', __dir__)
|
|
6
|
+
|
|
7
|
+
module Huntress
|
|
8
|
+
# @private
|
|
9
|
+
class API
|
|
10
|
+
# @private
|
|
11
|
+
attr_accessor *WrAPI::Configuration::VALID_OPTIONS_KEYS
|
|
12
|
+
|
|
13
|
+
# Creates a new API and copies settings from singleton
|
|
14
|
+
def initialize(options = {})
|
|
15
|
+
options = Huntress.options.merge(options)
|
|
16
|
+
WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
|
|
17
|
+
send("#{key}=", options[key])
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def config
|
|
22
|
+
conf = {}
|
|
23
|
+
WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
|
|
24
|
+
conf[key] = send key
|
|
25
|
+
end
|
|
26
|
+
conf
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
include WrAPI::Connection
|
|
30
|
+
include Connection
|
|
31
|
+
include WrAPI::Request
|
|
32
|
+
include WrAPI::Authentication
|
|
33
|
+
include Authentication
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'base64'
|
|
4
|
+
require File.expand_path('error', __dir__)
|
|
5
|
+
|
|
6
|
+
module Huntress
|
|
7
|
+
# Deals with authentication flow and stores it within global configuration
|
|
8
|
+
module Authentication
|
|
9
|
+
#
|
|
10
|
+
# Authorize to the Hudu portal and return access_token
|
|
11
|
+
def login(options = {})
|
|
12
|
+
raise ArgumentError, 'client_id not set' unless client_id
|
|
13
|
+
raise ArgumentError, 'client_secret not set' unless client_secret
|
|
14
|
+
|
|
15
|
+
# pass api key (id) and secret using basic authentication/connection
|
|
16
|
+
self.token_type = 'Basic'
|
|
17
|
+
self.access_token = Base64.strict_encode64("#{client_id}:#{client_secret}")
|
|
18
|
+
|
|
19
|
+
# will do sanitty check if token if valid
|
|
20
|
+
get('/v1/account', options)
|
|
21
|
+
rescue Faraday::Error => e
|
|
22
|
+
raise AuthenticationError, e
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require File.expand_path('api', __dir__)
|
|
4
|
+
#require File.expand_path('asset_helper', __dir__)
|
|
5
|
+
|
|
6
|
+
module Huntress
|
|
7
|
+
# The Client class serves as a wrapper for the Hudu REST API, providing methods to interact
|
|
8
|
+
# with various Hudu resources.
|
|
9
|
+
#
|
|
10
|
+
# This class dynamically defines methods to fetch, create, update, and manipulate Hudu resources
|
|
11
|
+
# such as companies, articles, assets, and more.
|
|
12
|
+
#
|
|
13
|
+
# @example Basic Usage
|
|
14
|
+
# client.companies # Fetch all companies
|
|
15
|
+
# client.company(1) # Fetch a company by ID
|
|
16
|
+
# client.update_company(1, { name: "Updated Company" }) # Update a company
|
|
17
|
+
# client.create_company({ name: "New Company" }) # Create a new company
|
|
18
|
+
class Client < API
|
|
19
|
+
|
|
20
|
+
# Dynamically defines methods for interacting with Hudu API resources.
|
|
21
|
+
#
|
|
22
|
+
# Depending on the arguments, this will define methods to:
|
|
23
|
+
# - Fetch all records for a resource
|
|
24
|
+
# - Fetch a specific record by ID
|
|
25
|
+
# - Update a record
|
|
26
|
+
# - Create a new record
|
|
27
|
+
#
|
|
28
|
+
# @param method [Symbol] The method name for fetching all records.
|
|
29
|
+
# @param singular_method [Symbol, nil] The method name for fetching a single record by ID. Optional.
|
|
30
|
+
# @param path [String] The API path for the resource. Defaults to the method name.
|
|
31
|
+
#
|
|
32
|
+
# @example Defining endpoints
|
|
33
|
+
# api_endpoint :companies, :company
|
|
34
|
+
# # Defines:
|
|
35
|
+
# # - `companies(params = {})` to fetch all companies.
|
|
36
|
+
# # - `company(id, params = {})` to fetch a single company by ID.
|
|
37
|
+
# # - `update_companies(id, params = {})` to update a company.
|
|
38
|
+
# # - `create_companies(params = {})` to create a new company.
|
|
39
|
+
def self.api_endpoint(method, singular_method = nil, path = method)
|
|
40
|
+
if singular_method
|
|
41
|
+
# Define method to fetch all records and one by id
|
|
42
|
+
send(:define_method, method) do |params = {}|
|
|
43
|
+
r = get_paged(api_url(path), params)
|
|
44
|
+
end
|
|
45
|
+
# Define method to fetch a single record by ID
|
|
46
|
+
send(:define_method, singular_method) do |id, params = {}|
|
|
47
|
+
r = get(api_url("#{path}/#{id}"), params)
|
|
48
|
+
end
|
|
49
|
+
else
|
|
50
|
+
# Define simple method to fetch data
|
|
51
|
+
send(:define_method, method) do |params = {}|
|
|
52
|
+
get(api_url(path), params)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def account(options = {})
|
|
58
|
+
get(api_url('account'), options)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def actor(options = {})
|
|
62
|
+
get(api_url('actor'), options)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def remediation(incident_report_id, remediation, options = {})
|
|
66
|
+
get_paged(api_url("incident_reports/#{incident_report_id}/remediations/#{remediation}"), options)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def remediations(incident_report_id, options = {})
|
|
70
|
+
#get_paged(api_url("incident_reports/#{incident_report_id}/remediations"), options)
|
|
71
|
+
remediation(incident_report_id, nil, options)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Define API endpoints for various resources
|
|
75
|
+
api_endpoint :agents, :agent
|
|
76
|
+
api_endpoint :billing_reports, :billing_report
|
|
77
|
+
api_endpoint :incident_reports, :incident_report
|
|
78
|
+
api_endpoint :organizations, :organization
|
|
79
|
+
api_endpoint :reports, :report
|
|
80
|
+
api_endpoint :signals, :signal
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Constructs the full API URL for a given path.
|
|
84
|
+
#
|
|
85
|
+
# @param path [String] The API path.
|
|
86
|
+
# @return [String] The full API URL.
|
|
87
|
+
def api_url(path)
|
|
88
|
+
"/v1/#{path}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Huntress
|
|
4
|
+
# Create connection including and keep it persistent so we add the rate throtling middleware only once
|
|
5
|
+
module Connection
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def connection
|
|
9
|
+
unless @connection
|
|
10
|
+
@connection = super
|
|
11
|
+
@connection.use WrAPI::RateThrottleMiddleware, limit: 60, period: 60
|
|
12
|
+
end
|
|
13
|
+
@connection
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'uri'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
module Huntress
|
|
7
|
+
# Defines HTTP request methods
|
|
8
|
+
# @see https://api.huntress.io/docs
|
|
9
|
+
module RequestPagination
|
|
10
|
+
# The PaginationPager class provides a mechanism to handle pagination information for API responses.
|
|
11
|
+
#
|
|
12
|
+
# It manages the current page, page size, and provides utilities for determining if there are more pages to fetch.
|
|
13
|
+
#
|
|
14
|
+
# @example Basic Usage
|
|
15
|
+
# pager = PaginationPager.new(50)
|
|
16
|
+
# while pager.more_pages?
|
|
17
|
+
# response = api_client.get_data(pager.page_options)
|
|
18
|
+
# pager.next_page!(response.body)
|
|
19
|
+
# end
|
|
20
|
+
class PaginationPager
|
|
21
|
+
# Initializes a new PaginationPager instance.
|
|
22
|
+
#
|
|
23
|
+
# @param page_size [Integer] The number of records to fetch per page.
|
|
24
|
+
def initialize(page_size)
|
|
25
|
+
@page = 1
|
|
26
|
+
@page_token = @pagination_data = nil
|
|
27
|
+
@limit = page_size
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Provides the current pagination parameter options for each rest request.
|
|
31
|
+
#
|
|
32
|
+
# @return [Hash] A hash containing the current page and page size.
|
|
33
|
+
#
|
|
34
|
+
# @example
|
|
35
|
+
# pager.page_options # => { page_token: 'Mjadso43289', page_size: 50 }
|
|
36
|
+
def page_options
|
|
37
|
+
options = { limit: @limit }
|
|
38
|
+
options.merge!({ page_token: @page_token }) if @page_token
|
|
39
|
+
options
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Advances to the next page based on the response body and updates internal pagination state.
|
|
43
|
+
#
|
|
44
|
+
# @param body [Hash] The response body from the API, expected to contain a paginated resource.
|
|
45
|
+
# @return [Integer] The updated page total, typically the count of items on the current page.
|
|
46
|
+
#
|
|
47
|
+
# @example
|
|
48
|
+
# response_body = { "items" => [...] }
|
|
49
|
+
# pager.next_page!(response_body)
|
|
50
|
+
def next_page!(body)
|
|
51
|
+
@page += 1
|
|
52
|
+
@pagination_data = PaginationPager.pagination_data(body)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Determines whether there are more pages to fetch.
|
|
56
|
+
#
|
|
57
|
+
# @return [Boolean] Returns `true` if the current page is full, indicating another page might exist.
|
|
58
|
+
#
|
|
59
|
+
# @example
|
|
60
|
+
# pager.more_pages? # => true or false
|
|
61
|
+
def more_pages?
|
|
62
|
+
# while full page we have next page
|
|
63
|
+
if @pagination_data
|
|
64
|
+
@page_token = @pagination_data["next_page_token"]
|
|
65
|
+
else
|
|
66
|
+
@page.eql? 1
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Extracts paginated data from the response body.
|
|
71
|
+
#
|
|
72
|
+
# @param body [Hash] The response body containing resource data, expected to be in a hash format.
|
|
73
|
+
# @return [Array, Hash, Object] Returns the extracted data, which could be an array, hash, or other object.
|
|
74
|
+
#
|
|
75
|
+
# @example
|
|
76
|
+
# response_body = { "items" => [1, 2, 3] }
|
|
77
|
+
# PaginationPager.data(response_body) # => [1, 2, 3]
|
|
78
|
+
def self.data(body)
|
|
79
|
+
# assume hash {"resource":[...]}, get first key and return array data
|
|
80
|
+
result = body
|
|
81
|
+
if result.is_a?(Hash)
|
|
82
|
+
_k, v = body.first
|
|
83
|
+
result = v if v.is_a?(Array) || v.is_a?(Hash)
|
|
84
|
+
end
|
|
85
|
+
result
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Extracts pagination information
|
|
89
|
+
#
|
|
90
|
+
# @param body [Hash] The response body containing resource data, and pagination infromation in a hash format.
|
|
91
|
+
# @return Hash Returns the extracted data, which could be an array, hash, or other object.
|
|
92
|
+
#
|
|
93
|
+
# @example
|
|
94
|
+
# response_body = {
|
|
95
|
+
# "items" => [1, 2, 3],
|
|
96
|
+
# "pagination" => {"current_page" => 1, "current_page_count": 10, "limit": 10, "total_count":60, "next_page": 2,
|
|
97
|
+
# "next_page_url": "https://api.xx.io/v1/signals?page_token=NjEyNjgxMzE%3D&limit=10", "next_page_token": "NjEyNjgxMzE=" } }
|
|
98
|
+
# PaginationPager.pagination_data(response_body) # => {"current_page" => 1, "current_page_count": 10, ...
|
|
99
|
+
def self.pagination_data(body)
|
|
100
|
+
# assume hash {"resource":[...], "pagination":{}}, return pagination data
|
|
101
|
+
result = nil
|
|
102
|
+
if body.is_a?(Hash)
|
|
103
|
+
result = body["pagination"]
|
|
104
|
+
end
|
|
105
|
+
result
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
data/lib/huntress.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'wrapi'
|
|
4
|
+
require File.expand_path('huntress/version', __dir__)
|
|
5
|
+
require File.expand_path('huntress/client', __dir__)
|
|
6
|
+
require File.expand_path('huntress/pagination', __dir__)
|
|
7
|
+
|
|
8
|
+
# The Huntress module provides utilities to manage and manipulate assets within the Huntress api
|
|
9
|
+
module Huntress
|
|
10
|
+
extend WrAPI::Configuration
|
|
11
|
+
extend WrAPI::RespondTo
|
|
12
|
+
|
|
13
|
+
# Default User-Agent header sent with API requests, including gem version information.
|
|
14
|
+
DEFAULT_UA = "Huntress Ruby API wrapper #{Huntress::VERSION}"
|
|
15
|
+
# Default api endpoint
|
|
16
|
+
DEFAULT_ENDPOINT = 'https://api.huntress.io'
|
|
17
|
+
DEFAULT_PAGINATION = RequestPagination::PaginationPager
|
|
18
|
+
DEFAULT_PAGE_SIZE = 25
|
|
19
|
+
|
|
20
|
+
#
|
|
21
|
+
# @return [Huntress::Client]
|
|
22
|
+
def self.client(options = {})
|
|
23
|
+
Huntress::Client.new({
|
|
24
|
+
endpoint: DEFAULT_ENDPOINT,
|
|
25
|
+
user_agent: DEFAULT_UA,
|
|
26
|
+
page_size: DEFAULT_PAGE_SIZE,
|
|
27
|
+
pagination_class: DEFAULT_PAGINATION
|
|
28
|
+
}.merge(options))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Resets the Skykick configuration to default values.
|
|
32
|
+
#
|
|
33
|
+
# This method resets the configuration values to their defaults:
|
|
34
|
+
# - `DEFAULT_UA` for the User-Agent
|
|
35
|
+
#
|
|
36
|
+
# @example Reset the Huntress configuration:
|
|
37
|
+
# Huntress.reset
|
|
38
|
+
def self.reset
|
|
39
|
+
super
|
|
40
|
+
self.endpoint = DEFAULT_ENDPOINT
|
|
41
|
+
self.user_agent = DEFAULT_UA
|
|
42
|
+
self.page_size = DEFAULT_PAGE_SIZE
|
|
43
|
+
self.pagination_class = DEFAULT_PAGINATION
|
|
44
|
+
end
|
|
45
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: huntress
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Janco Tanis
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-10-30 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: faraday
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: wrapi
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 0.5.0
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 0.5.0
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: dotenv
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: minitest
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: simplecov
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rubocop
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
description:
|
|
98
|
+
email: gems@jancology.com
|
|
99
|
+
executables: []
|
|
100
|
+
extensions: []
|
|
101
|
+
extra_rdoc_files: []
|
|
102
|
+
files:
|
|
103
|
+
- ".env.template"
|
|
104
|
+
- ".gitignore"
|
|
105
|
+
- CHANGELOG.md
|
|
106
|
+
- Gemfile
|
|
107
|
+
- README.md
|
|
108
|
+
- Rakefile
|
|
109
|
+
- huntress.gemspec
|
|
110
|
+
- lib/huntress.rb
|
|
111
|
+
- lib/huntress/api.rb
|
|
112
|
+
- lib/huntress/authentication.rb
|
|
113
|
+
- lib/huntress/client.rb
|
|
114
|
+
- lib/huntress/connection.rb
|
|
115
|
+
- lib/huntress/error.rb
|
|
116
|
+
- lib/huntress/pagination.rb
|
|
117
|
+
- lib/huntress/version.rb
|
|
118
|
+
homepage: https://rubygems.org/gems/huntress
|
|
119
|
+
licenses:
|
|
120
|
+
- MIT
|
|
121
|
+
metadata:
|
|
122
|
+
homepage_uri: https://rubygems.org/gems/huntress
|
|
123
|
+
source_code_uri: https://github.com/jancotanis/huntress
|
|
124
|
+
post_install_message:
|
|
125
|
+
rdoc_options: []
|
|
126
|
+
require_paths:
|
|
127
|
+
- lib
|
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
129
|
+
requirements:
|
|
130
|
+
- - ">="
|
|
131
|
+
- !ruby/object:Gem::Version
|
|
132
|
+
version: 2.4.0
|
|
133
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - ">="
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '0'
|
|
138
|
+
requirements: []
|
|
139
|
+
rubygems_version: 3.1.6
|
|
140
|
+
signing_key:
|
|
141
|
+
specification_version: 4
|
|
142
|
+
summary: A Ruby wrapper for the Huntress APIs (readonly)
|
|
143
|
+
test_files: []
|