zanshin 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.md +20 -0
- data/README.md +135 -0
- data/lib/zanshin/account.rb +96 -0
- data/lib/zanshin/alerts.rb +368 -0
- data/lib/zanshin/client.rb +189 -0
- data/lib/zanshin/organization_followers.rb +94 -0
- data/lib/zanshin/organization_following.rb +98 -0
- data/lib/zanshin/organization_members.rb +167 -0
- data/lib/zanshin/organization_scan_targets.rb +177 -0
- data/lib/zanshin/organizations.rb +52 -0
- data/lib/zanshin/request/zanshin_request.rb +51 -0
- data/lib/zanshin/request/zanshin_request_error.rb +22 -0
- data/lib/zanshin/scan_target.rb +114 -0
- data/lib/zanshin/summaries.rb +80 -0
- data/lib/zanshin/version.rb +8 -0
- data/lib/zanshin.rb +17 -0
- metadata +188 -0
@@ -0,0 +1,177 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'scan_target'
|
4
|
+
|
5
|
+
module Zanshin
|
6
|
+
module SDK
|
7
|
+
# Zanshin SDK Organization Scan Target
|
8
|
+
module OrganizationScanTargets
|
9
|
+
###################################################
|
10
|
+
# Organization Scan Targets
|
11
|
+
###################################################
|
12
|
+
|
13
|
+
# Scan Targets Enumerator of an organization
|
14
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationScanTargets)
|
15
|
+
#
|
16
|
+
# @param organization_id [UUID] of the organization
|
17
|
+
#
|
18
|
+
# @return an Scan Targets Enumerator object
|
19
|
+
def iter_organization_scan_targets(organization_id)
|
20
|
+
Enumerator.new do |yielder|
|
21
|
+
@http.request('GET', "/organizations/#{validate_uuid(organization_id)}/scantargets").each do |e|
|
22
|
+
yielder.yield e
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create a new scan target in organization
|
28
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/createOrganizationScanTargets)
|
29
|
+
#
|
30
|
+
# @param organization_id [UUID] of the organization
|
31
|
+
# @param name [UUID] of the organization
|
32
|
+
# @param credential [ScanTarget::AWS, ScanTarget::Azure, ScanTarget::GCP, ScanTarget::HUAWEI, ScanTarget::DOMAIN]
|
33
|
+
# to access the cloud account to be scanned
|
34
|
+
# @param schedule [Cron] in cron format
|
35
|
+
#
|
36
|
+
# @return an Object representing the newly created scan target
|
37
|
+
def create_organization_scan_target(organization_id, name, credential, schedule = '0 0 * * *')
|
38
|
+
unless [ScanTarget::AWS, ScanTarget::Azure, ScanTarget::GCP,
|
39
|
+
ScanTarget::HUAWEI, ScanTarget::DOMAIN].include? credential.class
|
40
|
+
raise "#{credential.class} is invalid instance of Zanshin::SDK::ScanTarget classes"
|
41
|
+
end
|
42
|
+
|
43
|
+
body = {
|
44
|
+
'kind' => credential.class::KIND, 'name' => name,
|
45
|
+
'credential' => credential.to_json, 'schedule' => schedule
|
46
|
+
}
|
47
|
+
@http.request('POST', "/organizations/#{validate_uuid(organization_id)}/scantargets", body)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get scan target details of organization
|
51
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationScanTargetById)
|
52
|
+
#
|
53
|
+
# @param organization_id [UUID] of the organization
|
54
|
+
# @param scan_target_id [UUID] of the scan target
|
55
|
+
#
|
56
|
+
# @return a Object representing the scan target
|
57
|
+
def get_organization_scan_target(organization_id, scan_target_id)
|
58
|
+
@http.request('GET',
|
59
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}")
|
60
|
+
end
|
61
|
+
|
62
|
+
# Update scan target of organization
|
63
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/editOrganizationMembersById)
|
64
|
+
#
|
65
|
+
# @param organization_id [UUID] of the organization
|
66
|
+
# @param scan_target_id [UUID] of the scan target
|
67
|
+
# @param name [String] of the scan target
|
68
|
+
# @param schedule [Cron] of the schedule
|
69
|
+
#
|
70
|
+
# @return a Object representing the scan target updated
|
71
|
+
def update_organization_scan_target(organization_id, scan_target_id, name = nil, schedule = nil)
|
72
|
+
body = {
|
73
|
+
'name' => name,
|
74
|
+
'schedule' => schedule
|
75
|
+
}
|
76
|
+
|
77
|
+
@http.request('PUT',
|
78
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}",
|
79
|
+
body)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Delete scan target of organization
|
83
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/deleteOrganizationScanTargetById)
|
84
|
+
#
|
85
|
+
# @param organization_id [UUID] of the organization
|
86
|
+
# @param scan_target_id [UUID] of the scan target
|
87
|
+
#
|
88
|
+
# @return a Boolean with result
|
89
|
+
def delete_organization_scan_target(organization_id, scan_target_id)
|
90
|
+
@http.request('DELETE',
|
91
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}")
|
92
|
+
end
|
93
|
+
|
94
|
+
# Starts a scan on the specified scan target
|
95
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/scanOrganizationScanTarget)
|
96
|
+
#
|
97
|
+
# @param organization_id [UUID] of the organization
|
98
|
+
# @param scan_target_id [UUID] of the scan target
|
99
|
+
#
|
100
|
+
# @return a Boolean with result
|
101
|
+
def start_organization_scan_target_scan(organization_id, scan_target_id)
|
102
|
+
@http.request(
|
103
|
+
'POST',
|
104
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}/scan"
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
# TODO: API documentation is not up to date, does not have this endpoint
|
109
|
+
# After updating you will need to add the reference here
|
110
|
+
|
111
|
+
# Stop a scan on the specific scan target
|
112
|
+
#
|
113
|
+
# @param organization_id [UUID] of the organization
|
114
|
+
# @param scan_target_id [UUID] of the scan target
|
115
|
+
#
|
116
|
+
# @return a Boolean with result
|
117
|
+
def stop_organization_scan_target_scan(organization_id, scan_target_id)
|
118
|
+
@http.request(
|
119
|
+
'POST',
|
120
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}/stop"
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Check scan target
|
125
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/checkOrganizationScanTarget)
|
126
|
+
#
|
127
|
+
# @param organization_id [UUID] of the organization
|
128
|
+
# @param scan_target_id [UUID] of the scan target
|
129
|
+
#
|
130
|
+
# @return a Object representing the scan target
|
131
|
+
def check_organization_scan_target(organization_id, scan_target_id)
|
132
|
+
@http.request(
|
133
|
+
'POST',
|
134
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}/check"
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
138
|
+
###################################################
|
139
|
+
# Organization Scan Target Scan
|
140
|
+
###################################################
|
141
|
+
|
142
|
+
# Scans Enumerator of an Scan Target
|
143
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationScanTargetScans)
|
144
|
+
#
|
145
|
+
# @param organization_id [UUID] of the organization
|
146
|
+
# @param scan_target_id [UUID] of the scan target
|
147
|
+
#
|
148
|
+
# @return an Scans Enumerator object
|
149
|
+
def iter_organization_scan_target_scans(organization_id, scan_target_id)
|
150
|
+
Enumerator.new do |yielder|
|
151
|
+
@http.request(
|
152
|
+
'GET',
|
153
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{validate_uuid(scan_target_id)}/scans"
|
154
|
+
).each do |e|
|
155
|
+
yielder.yield e
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Get scan of scan target
|
161
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationScanTargetScanSlot)
|
162
|
+
#
|
163
|
+
# @param organization_id [UUID] of the organization
|
164
|
+
# @param scan_target_id [UUID] of the scan target
|
165
|
+
# @param scan_id [UUID] of the scan
|
166
|
+
#
|
167
|
+
# @return a Object representing the scan
|
168
|
+
def get_organization_scan_target_scan(organization_id, scan_target_id, scan_id)
|
169
|
+
@http.request(
|
170
|
+
'GET',
|
171
|
+
"/organizations/#{validate_uuid(organization_id)}/scantargets/#{
|
172
|
+
validate_uuid(scan_target_id)}/scans/#{validate_uuid(scan_id)}"
|
173
|
+
)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zanshin
|
4
|
+
module SDK
|
5
|
+
# Zanshin SDK Organization
|
6
|
+
module Organizations
|
7
|
+
###################################################
|
8
|
+
# Organizations
|
9
|
+
###################################################
|
10
|
+
|
11
|
+
# Organizations Enumerator of current logged user
|
12
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizations)
|
13
|
+
#
|
14
|
+
# @return an Organizations Enumerator object
|
15
|
+
def iter_organizations
|
16
|
+
Enumerator.new do |yielder|
|
17
|
+
@http.request('GET', '/organizations').each do |e|
|
18
|
+
yielder.yield e
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Gets an organization given its ID
|
24
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationById)
|
25
|
+
#
|
26
|
+
# @param organization_id [UUID] of the organization
|
27
|
+
#
|
28
|
+
# @return an Object representing the organization
|
29
|
+
def get_organization(organization_id)
|
30
|
+
@http.request('GET', "/organizations/#{validate_uuid(organization_id)}")
|
31
|
+
end
|
32
|
+
|
33
|
+
# Gets an organization given its ID
|
34
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/editOrganizationById)
|
35
|
+
#
|
36
|
+
# @param organization_id [UUID] of the organization
|
37
|
+
# @param name [String] Optional name of the organization
|
38
|
+
# @param picture [String] Optional picture URL of the organization, accepted formats: jpg, jpeg, png, svg
|
39
|
+
# @param email [String] Optional e-mail contact of the organization
|
40
|
+
#
|
41
|
+
# @return an Object representing the organization
|
42
|
+
def update_organization(organization_id, name: nil, picture: nil, email: nil)
|
43
|
+
body = {
|
44
|
+
'name' => name,
|
45
|
+
'picture' => picture,
|
46
|
+
'email' => email
|
47
|
+
}
|
48
|
+
@http.request('PUT', "/organizations/#{validate_uuid(organization_id)}", body)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'zanshin/request/zanshin_request_error'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
module Zanshin
|
8
|
+
module SDK
|
9
|
+
# Zanshin SDK Request
|
10
|
+
module Request
|
11
|
+
# Zanshin SDK request HTTPClient
|
12
|
+
class HTTPClient
|
13
|
+
attr_accessor :headers, :http_client
|
14
|
+
|
15
|
+
# Initialize a new HTTP connection to the Zanshin API
|
16
|
+
# @overload initialize(api_key, api_url, user_agent, proxy_url)
|
17
|
+
# @param api_key [String] API key to use
|
18
|
+
# @param api_url [String] URL of the Zanshin API
|
19
|
+
# @param user_agent [String] User agent to use in requests performed
|
20
|
+
# @param proxy_url [String] Optional URL indicating which proxy server to use
|
21
|
+
def initialize(api_key, api_url, user_agent, proxy_url = nil)
|
22
|
+
@headers = { 'Authorization' => "Bearer #{api_key}",
|
23
|
+
'User-Agent' => user_agent,
|
24
|
+
'Content-Type' => 'application/json' }
|
25
|
+
# HACK: Needs to figure out why Net::HTTP is not automatically decoded `gzip` and `deflate` encoding
|
26
|
+
# 'Accept-Encoding' => 'gzip, deflate'
|
27
|
+
|
28
|
+
uri = URI.parse(api_url)
|
29
|
+
proxy = URI.parse(proxy_url || '')
|
30
|
+
|
31
|
+
@http_client = Net::HTTP.new(uri.host, uri.port, proxy.host, proxy.port, proxy.user, proxy.password)
|
32
|
+
@http_client.use_ssl = true
|
33
|
+
end
|
34
|
+
|
35
|
+
# Request to Zanshin
|
36
|
+
# @overload initialize(api_key, api_url, user_agent, proxy_url)
|
37
|
+
# @param method ['GET', 'POST', 'PUT', 'DELETE'] HTTP method to pass along to `:HTTPClient`
|
38
|
+
# @param path [String] API path to access
|
39
|
+
# @param body [Object] request body to pass along to `:HTTPClient`
|
40
|
+
def request(method, path, body = nil)
|
41
|
+
body = body.to_json if body
|
42
|
+
response = @http_client.send_request(method, path, body, @headers)
|
43
|
+
result = JSON.parse(response.body)
|
44
|
+
raise ZanshinError.new(response.code, result['message'] || result['errorName']) if response.code.to_i >= 400
|
45
|
+
|
46
|
+
result
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zanshin
|
4
|
+
module SDK
|
5
|
+
module Request
|
6
|
+
# Zanshin SDK request ZanshinError
|
7
|
+
class ZanshinError < StandardError
|
8
|
+
attr_reader :code, :body
|
9
|
+
|
10
|
+
# Initialize a new Zanshin Error
|
11
|
+
# @overload initialize(code, body)
|
12
|
+
# @param code [String] of the Error
|
13
|
+
# @param body [String] message of the error
|
14
|
+
def initialize(code, body)
|
15
|
+
@code = code
|
16
|
+
@body = body
|
17
|
+
super("Error [#{code}] #{body}")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Zanshin
|
6
|
+
module SDK
|
7
|
+
# Zanshin SDK Scan Target
|
8
|
+
#
|
9
|
+
# This module contains the classes for each provider that Zanshin supports, and which can be used
|
10
|
+
# to create a scan target
|
11
|
+
module ScanTarget
|
12
|
+
# AWS scan target
|
13
|
+
class AWS
|
14
|
+
# Type of provider that will be sent to the API
|
15
|
+
KIND = 'AWS'
|
16
|
+
|
17
|
+
attr_accessor :account
|
18
|
+
|
19
|
+
def initialize(account)
|
20
|
+
@account = account
|
21
|
+
end
|
22
|
+
|
23
|
+
# Convert AWS class to json
|
24
|
+
def to_json(*_args)
|
25
|
+
{
|
26
|
+
'account' => @account
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Azure scan target
|
32
|
+
class Azure
|
33
|
+
# Type of provider that will be sent to the API
|
34
|
+
KIND = 'Azure'
|
35
|
+
|
36
|
+
attr_accessor :application_id, :subscription_id, :directory_id, :secret
|
37
|
+
|
38
|
+
def initialize(application_id, subscription_id, directory_id, secret)
|
39
|
+
@application_id = application_id
|
40
|
+
@subscription_id = subscription_id
|
41
|
+
@directory_id = directory_id
|
42
|
+
@secret = secret
|
43
|
+
end
|
44
|
+
|
45
|
+
# Convert Azure class to json
|
46
|
+
def to_json(*_args)
|
47
|
+
{
|
48
|
+
'application_id' => @application_id,
|
49
|
+
'subscription_id' => @subscription_id,
|
50
|
+
'directory_id' => @directory_id,
|
51
|
+
'secret' => @secret
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# GCP scan target
|
57
|
+
class GCP
|
58
|
+
# Type of provider that will be sent to the API
|
59
|
+
KIND = 'GCP'
|
60
|
+
|
61
|
+
attr_accessor :project_id
|
62
|
+
|
63
|
+
def initialize(project_id)
|
64
|
+
@project_id = project_id
|
65
|
+
end
|
66
|
+
|
67
|
+
# Convert GCP class to json
|
68
|
+
def to_json(*_args)
|
69
|
+
{
|
70
|
+
'project_id' => @project_id
|
71
|
+
}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# HUAWEI scan target
|
76
|
+
class HUAWEI
|
77
|
+
# Type of provider that will be sent to the API
|
78
|
+
KIND = 'HUAWEI'
|
79
|
+
|
80
|
+
attr_accessor :account_id
|
81
|
+
|
82
|
+
def initialize(account_id)
|
83
|
+
@account_id = account_id
|
84
|
+
end
|
85
|
+
|
86
|
+
# Convert HUAWEI class to json
|
87
|
+
def to_json(*_args)
|
88
|
+
{
|
89
|
+
'account_id' => @account_id
|
90
|
+
}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# DOMAIN scan target
|
95
|
+
class DOMAIN
|
96
|
+
# Type of provider that will be sent to the API
|
97
|
+
KIND = 'DOMAIN'
|
98
|
+
|
99
|
+
attr_accessor :domain
|
100
|
+
|
101
|
+
def initialize(domain)
|
102
|
+
@domain = domain
|
103
|
+
end
|
104
|
+
|
105
|
+
# Convert DOMAIN class to json
|
106
|
+
def to_json(*_args)
|
107
|
+
{
|
108
|
+
'domain' => @domain
|
109
|
+
}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zanshin
|
4
|
+
module SDK
|
5
|
+
# Zanshin SDK Summary
|
6
|
+
module Summaries
|
7
|
+
###################################################
|
8
|
+
# Summaries
|
9
|
+
###################################################
|
10
|
+
|
11
|
+
# Gets a summary of the current state of alerts for an organization, both in total and broken down by scan target
|
12
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/alertSummary)
|
13
|
+
#
|
14
|
+
# @param organization_id [UUID] of the organization whose alert summaries are desired
|
15
|
+
# @param scan_target_ids [Array<UUID>] optional list of scan target IDs to summarize alerts from, defaults to all
|
16
|
+
#
|
17
|
+
# @return a Object representing the alert summaries
|
18
|
+
def get_alert_summaries(organization_id, scan_target_ids = [])
|
19
|
+
body = {
|
20
|
+
'organizationId' => validate_uuid(organization_id),
|
21
|
+
'scanTargetIds' => scan_target_ids.each { |scan_target_id| validate_uuid(scan_target_id) }
|
22
|
+
}
|
23
|
+
|
24
|
+
@http.request('POST', '/alerts/summaries', body)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Gets a summary of the current state of alerts for followed organizations
|
28
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/alertFollowingSummary)
|
29
|
+
#
|
30
|
+
# @param organization_id [UUID] of the organization
|
31
|
+
# @param following_ids [Array<UUID>] list of IDs of organizations being followed to summarize alerts from
|
32
|
+
#
|
33
|
+
# @return a Object representing the alert following summaries
|
34
|
+
def get_following_alert_summaries(organization_id, following_ids = [])
|
35
|
+
body = {
|
36
|
+
'organizationId' => validate_uuid(organization_id),
|
37
|
+
'followingIds' => following_ids.each { |following_id| validate_uuid(following_id) }
|
38
|
+
}
|
39
|
+
|
40
|
+
@http.request('POST', '/alerts/summaries/following', body)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns summaries of scan results over a period of time, summarizing number of alerts that changed states
|
44
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/scanSummary)
|
45
|
+
#
|
46
|
+
# @param organization_id [UUID] of the organization whose alert summaries are desired
|
47
|
+
# @param scan_target_ids [Array<UUID>] optional list of scan target IDs to summarize alerts from, defaults to all
|
48
|
+
# @param days [Integer] number of days to go back in time in historical search
|
49
|
+
#
|
50
|
+
# @return a Object representing the scan summaries
|
51
|
+
def get_scan_summaries(organization_id, scan_target_ids = [], days = 7)
|
52
|
+
body = {
|
53
|
+
'organizationId' => validate_uuid(organization_id),
|
54
|
+
'scanTargetIds' => scan_target_ids.each { |scan_target_id| validate_uuid(scan_target_id) },
|
55
|
+
'daysBefore' => days
|
56
|
+
}
|
57
|
+
|
58
|
+
@http.request('POST', '/alerts/summaries/scans', body)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Gets a summary of the current state of alerts for followed organizations
|
62
|
+
# [#reference](https://api.zanshin.tenchisecurity.com/#operation/scanSummaryFollowing)
|
63
|
+
#
|
64
|
+
# @param organization_id [UUID] of the organization whose alert summaries are desired
|
65
|
+
# @param following_ids [Array<UUID>] optional list of IDs of organizations being followed to summarize alerts from
|
66
|
+
# @param days [Integer] number of days to go back in time in historical search
|
67
|
+
#
|
68
|
+
# @return a Object representing the scan summaries
|
69
|
+
def get_following_scan_summaries(organization_id, following_ids = [], days = 7)
|
70
|
+
body = {
|
71
|
+
'organizationId' => validate_uuid(organization_id),
|
72
|
+
'followingIds' => following_ids.each { |following_id| validate_uuid(following_id) },
|
73
|
+
'daysBefore' => days
|
74
|
+
}
|
75
|
+
|
76
|
+
@http.request('POST', '/alerts/summaries/scans/following', body)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/zanshin.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'zanshin/client'
|
4
|
+
require_relative 'zanshin/version'
|
5
|
+
|
6
|
+
# {include:file:README.md}
|
7
|
+
module Zanshin
|
8
|
+
# Zanshin SDK
|
9
|
+
module SDK
|
10
|
+
# The default endpoint for Zanshin API
|
11
|
+
ZANSHIN_API = 'https://api.zanshin.tenchi-dev.com'
|
12
|
+
# The directory that Zanshin uses to store/get private settings
|
13
|
+
CONFIG_DIR = "#{Dir.home}/.tenchi"
|
14
|
+
# The file that Zanshin uses to store/get private settings
|
15
|
+
CONFIG_FILE = "#{CONFIG_DIR}/config"
|
16
|
+
end
|
17
|
+
end
|