zanshin 1.0.1

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.
@@ -0,0 +1,189 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'configparser'
4
+ require 'uri'
5
+ require 'logger'
6
+
7
+ require_relative 'request/zanshin_request'
8
+ require_relative 'account'
9
+ require_relative 'alerts'
10
+ require_relative 'organization_followers'
11
+ require_relative 'organization_following'
12
+ require_relative 'organization_members'
13
+ require_relative 'organization_scan_targets'
14
+ require_relative 'organizations'
15
+ require_relative 'summaries'
16
+
17
+ module Zanshin
18
+ module SDK
19
+ # Zanshin SDK Client
20
+ class Client
21
+ include Zanshin::SDK::Account
22
+ include Zanshin::SDK::Alerts
23
+ include Zanshin::SDK::Organizations
24
+ include Zanshin::SDK::OrganizationFollowers
25
+ include Zanshin::SDK::OrganizationFollowing
26
+ include Zanshin::SDK::OrganizationMembers
27
+ include Zanshin::SDK::OrganizationScanTargets
28
+ include Zanshin::SDK::Summaries
29
+
30
+ # @overload api_key
31
+ # Gets the current value of api_key
32
+ # @return api_key
33
+ # @overload api_key=(value)
34
+ # Sets the api_key
35
+ # @param [value] the new api_key
36
+ attr_reader :api_key
37
+ # @overload api_url
38
+ # Gets the current value of api_url
39
+ # @return api_url
40
+ # @overload api_url=(value)
41
+ # Sets the api_url
42
+ # @param [value] the new api_url
43
+ attr_reader :api_url
44
+ # @overload user_agent
45
+ # Gets the current value of user_agent
46
+ # @return user_agent
47
+ # @overload user_agent=(value)
48
+ # Sets the user_agent
49
+ # @param [value] the new user_agent
50
+ attr_reader :user_agent
51
+ # @overload proxy_url
52
+ # Gets the current value of proxy_url
53
+ # @return proxy_url
54
+ # @overload proxy_url=(value)
55
+ # Sets the proxy_url
56
+ # @param [value] the new proxy_url
57
+ attr_reader :proxy_url
58
+
59
+ # @overload http
60
+ # Gets the current value of http
61
+ # @return http
62
+ # @overload http=(`:HTTPClient`)
63
+ # Sets the http
64
+ # @param [value] the new http
65
+ attr_accessor :http
66
+
67
+ # Initialize a new Zanshin SDK instance
68
+ # @overload initialize(profile, api_key, api_url, user_agent, proxy_url)
69
+ # @param profile [String] Which configuration file section to use for settings
70
+ # @param api_key [String] Optional override of the API key to use
71
+ # @param api_url [String] Optional override of the base URL of the Zanshin API to use
72
+ # @param user_agent [String] Optional addition of the user agent to use in requests performed
73
+ # @param proxy_url [String] Optional URL indicating which proxy server to use
74
+ def initialize(profile: 'default',
75
+ api_key: ENV.fetch('ZANSHIN_API_KEY', nil),
76
+ api_url: ENV.fetch('ZANSHIN_API_URL', nil) || ZANSHIN_API,
77
+ user_agent: ENV.fetch('ZANSHIN_USER_AGENT', nil),
78
+ proxy_url: ENV.fetch('HTTP_PROXY', ENV.fetch('HTTPS_PROXY', nil)))
79
+ @logger = Logger.new($stdout)
80
+ @logger.level = Logger::WARN
81
+
82
+ config = get_config(profile)
83
+
84
+ @api_key = api_key || config['api_key'] || raise('No API key found')
85
+ @api_url = validate_url(api_url || config['api_url'])
86
+ @user_agent = add_sdk_agent(user_agent || config['user_agent'])
87
+ @proxy_url = validate_proxy(proxy_url || config['proxy_url'])
88
+
89
+ update_request
90
+ @logger.debug('Zanshin SDK Initialized')
91
+ end
92
+
93
+ def api_key=(value)
94
+ raise('API key cannot be nil') unless value
95
+
96
+ @api_key = value
97
+
98
+ update_request
99
+ end
100
+
101
+ def api_url=(value)
102
+ @api_url = validate_url(value)
103
+
104
+ update_request
105
+ end
106
+
107
+ def user_agent=(value)
108
+ @user_agent = add_sdk_agent(value)
109
+
110
+ update_request
111
+ end
112
+
113
+ def proxy_url=(value)
114
+ @proxy_url = validate_proxy(value)
115
+
116
+ update_request
117
+ end
118
+
119
+ private
120
+
121
+ attr_accessor :logger
122
+
123
+ # Internal method to read user configuration file
124
+ def get_config(profile)
125
+ parser = if File.exist?(File.expand_path(CONFIG_FILE))
126
+ ConfigParser.new(CONFIG_FILE)
127
+ else
128
+ raise("Not found #{CONFIG_FILE}")
129
+ end
130
+ raise "Profile #{profile} not found in #{CONFIG_FILE}" unless parser[profile]
131
+
132
+ parser[profile]
133
+ end
134
+
135
+ # Internal method to validate URL
136
+ def validate_url(url)
137
+ raise 'API URL cannot be nil' unless url
138
+
139
+ uri = URI(url)
140
+ if (uri.scheme != 'https') ||
141
+ !uri.host ||
142
+ (uri.password || uri.user) ||
143
+ !uri.port.between?(0, 65_535)
144
+ raise "Invalid API URL: #{url}"
145
+ end
146
+
147
+ url
148
+ end
149
+
150
+ # Internal method to validate proxy
151
+ def validate_proxy(proxy_url)
152
+ return nil unless proxy_url
153
+
154
+ proxy = URI(proxy_url)
155
+ if !(%w[http https].include? proxy.scheme) ||
156
+ !proxy.host ||
157
+ (proxy.user && !proxy.password) ||
158
+ !proxy.port.between?(0, 65_535)
159
+ raise "Invalid proxy URL: #{proxy_url}"
160
+ end
161
+
162
+ proxy_url
163
+ end
164
+
165
+ # Internal method to concatenate user-agent with SDK pattern
166
+ def add_sdk_agent(agent)
167
+ if agent.to_s.strip.empty?
168
+ "Zanshin Ruby SDK #{Zanshin::SDK::VERSION}"
169
+ else
170
+ "#{agent}/Zanshin Ruby SDK #{Zanshin::SDK::VERSION}"
171
+ end
172
+ end
173
+
174
+ # Internal method to create a new pre-configured Zanshin::SDK::Request::HTTPClient instance when one
175
+ # of the relevant settings is changed (API key, API URL, user-agent or Proxy URL).
176
+ def update_request
177
+ @http = Zanshin::SDK::Request::HTTPClient.new(@api_key, @api_url, @user_agent, @proxy_url)
178
+ end
179
+
180
+ # Internal method to validate UUID
181
+ def validate_uuid(uuid)
182
+ uuid_regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
183
+ raise "#{uuid} is not a valid UUID" unless uuid_regex.match?(uuid.to_s.downcase)
184
+
185
+ uuid
186
+ end
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zanshin
4
+ module SDK
5
+ # Zanshin SDK Organization Followers
6
+ module OrganizationFollowers
7
+ ###################################################
8
+ # Organization Follower
9
+ ###################################################
10
+
11
+ # Organization Followers Enumerator of an organization
12
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationFollowers)
13
+ #
14
+ # @param organization_id [UUID] of the organization
15
+ #
16
+ # @return an Organization Followers Enumerator object
17
+ def iter_organization_followers(organization_id)
18
+ Enumerator.new do |yielder|
19
+ @http.request('GET', "/organizations/#{validate_uuid(organization_id)}/followers").each do |e|
20
+ yielder.yield e
21
+ end
22
+ end
23
+ end
24
+
25
+ # Organization Followers Enumerator of an organization
26
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationFollowers)
27
+ #
28
+ # @param organization_id [UUID] of the organization
29
+ # @param follower_id [UUID] of the follower
30
+ #
31
+ # @return a Boolean with result
32
+ def stop_organization_follower(organization_id, follower_id)
33
+ @http.request('DELETE',
34
+ "/organizations/#{validate_uuid(organization_id)}/followers/#{validate_uuid(follower_id)}")
35
+ end
36
+
37
+ ###################################################
38
+ # Organization Follower Request
39
+ ###################################################
40
+
41
+ # Organization Followers Requests Enumerator of an organization
42
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationFollowRequests)
43
+ #
44
+ # @param organization_id [UUID] of the organization
45
+ #
46
+ # @return an Organization Followers Requests Enumerator object
47
+ def iter_organization_follower_requests(organization_id)
48
+ Enumerator.new do |yielder|
49
+ @http.request('GET', "/organizations/#{validate_uuid(organization_id)}/followers/requests").each do |e|
50
+ yielder.yield e
51
+ end
52
+ end
53
+ end
54
+
55
+ # Create organization follower request
56
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/createOrganizationFollowRequests)
57
+ #
58
+ # @param organization_id [UUID] of the organization
59
+ # @param token [UUID] of the follower request
60
+ #
61
+ # @return an Organization Followers Requests Enumerator object
62
+ def create_organization_follower_request(organization_id, token)
63
+ body = {
64
+ 'token' => validate_uuid(token)
65
+ }
66
+ @http.request('POST', "/organizations/#{validate_uuid(organization_id)}/followers/requests", body)
67
+ end
68
+
69
+ # Get organization follower request
70
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationFollowRequestsByToken)
71
+ #
72
+ # @param organization_id [UUID] of the organization
73
+ # @param token [UUID] of the follower request
74
+ #
75
+ # @return an Object representing the organization follower
76
+ def get_organization_follower_request(organization_id, token)
77
+ @http.request('GET',
78
+ "/organizations/#{validate_uuid(organization_id)}/followers/requests/#{validate_uuid(token)}")
79
+ end
80
+
81
+ # Delete organization follower request
82
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/deleteOrganizationFollowRequestsbyToken)
83
+ #
84
+ # @param organization_id [UUID] of the organization
85
+ # @param token [UUID] of the follower request
86
+ #
87
+ # @return a Boolean with result
88
+ def delete_organization_follower_request(organization_id, token)
89
+ @http.request('DELETE',
90
+ "/organizations/#{validate_uuid(organization_id)}/followers/requests/#{validate_uuid(token)}")
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zanshin
4
+ module SDK
5
+ # Zanshin SDK Organization Following
6
+ module OrganizationFollowing
7
+ ###################################################
8
+ # Organization Following
9
+ ###################################################
10
+
11
+ # Organization Following Enumerator of an organization
12
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationFollowing)
13
+ #
14
+ # @param organization_id [UUID] of the organization
15
+ #
16
+ # @return an Organization Following Enumerator object
17
+ def iter_organization_following(organization_id)
18
+ Enumerator.new do |yielder|
19
+ @http.request('GET', "/organizations/#{validate_uuid(organization_id)}/following").each do |e|
20
+ yielder.yield e
21
+ end
22
+ end
23
+ end
24
+
25
+ # Organization Followers Enumerator of an organization
26
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/removeOrganizationFollowingById)
27
+ #
28
+ # @param organization_id [UUID] of the organization
29
+ # @param following_id [UUID] of the follower
30
+ #
31
+ # @return a Boolean with result
32
+ def stop_organization_following(organization_id, following_id)
33
+ @http.request('DELETE',
34
+ "/organizations/#{validate_uuid(organization_id)}/following/#{validate_uuid(following_id)}")
35
+ end
36
+
37
+ ###################################################
38
+ # Organization Following Request
39
+ ###################################################
40
+
41
+ # Organization Following Requests Enumerator of an organization
42
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationFollowingRequests)
43
+ #
44
+ # @param organization_id [UUID] of the organization
45
+ #
46
+ # @return an Organization Following Requests Enumerator object
47
+ def iter_organization_following_requests(organization_id)
48
+ Enumerator.new do |yielder|
49
+ @http.request('GET', "/organizations/#{validate_uuid(organization_id)}/following/requests").each do |e|
50
+ yielder.yield e
51
+ end
52
+ end
53
+ end
54
+
55
+ # Returns a request received by an organization to follow another
56
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationFollowingRequestByToken)
57
+ #
58
+ # @param organization_id [UUID] of the organization
59
+ # @param following_id [UUID] of the follower request
60
+ #
61
+ # @return an Object representing the organization following request
62
+ def get_organization_following_request(organization_id, following_id)
63
+ @http.request(
64
+ 'GET',
65
+ "/organizations/#{validate_uuid(organization_id)}/following/requests/#{validate_uuid(following_id)}"
66
+ )
67
+ end
68
+
69
+ # Accepts a request to follow another organization
70
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/acceptOrganizationFollowingRequestByToken)
71
+ #
72
+ # @param organization_id [UUID] of the organization who was invited to follow another
73
+ # @param following_id [UUID] of the organization who is going to be followed
74
+ #
75
+ # @return an Object describing the newly established following relationship
76
+ def accept_organization_following_request(organization_id, following_id)
77
+ @http.request(
78
+ 'POST',
79
+ "/organizations/#{validate_uuid(organization_id)}/following/requests/#{validate_uuid(following_id)}/accept"
80
+ )
81
+ end
82
+
83
+ # Declines a request to follow another organization
84
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/declineOrganizationFollowingRequestByToken)
85
+ #
86
+ # @param organization_id [UUID] of the organization who was invited to follow another
87
+ # @param following_id [UUID] of the organization who is going to be followed
88
+ #
89
+ # @return an Object describing the newly established following relationship
90
+ def decline_organization_following_request(organization_id, following_id)
91
+ @http.request(
92
+ 'POST',
93
+ "/organizations/#{validate_uuid(organization_id)}/following/requests/#{validate_uuid(following_id)}/decline"
94
+ )
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zanshin
4
+ module SDK
5
+ # Zanshin SDK Organization Members
6
+ module OrganizationMembers
7
+ ###################################################
8
+ # Organization Member
9
+ ###################################################
10
+
11
+ # Organization Members Enumerator of the users which are members of an organization
12
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationMembers)
13
+ #
14
+ # @param organization_id [UUID] of the organization
15
+ #
16
+ # @return an Organization Members Enumerator object
17
+ def iter_organization_members(organization_id)
18
+ Enumerator.new do |yielder|
19
+ @http.request('GET', "/organizations/#{validate_uuid(organization_id)}/members").each do |e|
20
+ yielder.yield e
21
+ end
22
+ end
23
+ end
24
+
25
+ # Get details on a user's organization membership
26
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationMemberById)
27
+ #
28
+ # @param organization_id [UUID] of the organization
29
+ # @param member_id [UUID] of the member
30
+ #
31
+ # @return a Object representing the organization member
32
+ def get_organization_member(organization_id, member_id)
33
+ @http.request('GET',
34
+ "/organizations/#{validate_uuid(organization_id)}/members/#{validate_uuid(member_id)}")
35
+ end
36
+
37
+ # Update organization member
38
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/editOrganizationMembersById)
39
+ #
40
+ # @param organization_id [UUID] of the organization
41
+ # @param member_id [UUID] of the member
42
+ # @param roles ['ADMIN'] of the member
43
+ #
44
+ # @return a Object representing the organization member
45
+ def update_organization_member(organization_id, member_id, roles = nil)
46
+ body = {
47
+ 'roles' => [roles].compact
48
+ }
49
+ @http.request('PUT',
50
+ "/organizations/#{validate_uuid(organization_id)}/members/#{validate_uuid(member_id)}",
51
+ body)
52
+ end
53
+
54
+ # Delete organization member
55
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/removeOrganizationMemberById)
56
+ #
57
+ # @param organization_id [UUID] of the organization
58
+ # @param member_id [UUID] of the member
59
+ #
60
+ # @return a Boolean with result
61
+ def delete_organization_member(organization_id, member_id)
62
+ @http.request('DELETE',
63
+ "/organizations/#{validate_uuid(organization_id)}/members/#{validate_uuid(member_id)}")
64
+ end
65
+
66
+ # Reset organization member MFA
67
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/resetOrganizationMemberMfaById)
68
+ #
69
+ # @param organization_id [UUID] of the organization
70
+ # @param member_id [UUID] of the member
71
+ #
72
+ # @return a Boolean with result
73
+ def reset_organization_member_mfa(organization_id, member_id)
74
+ @http.request(
75
+ 'POST',
76
+ "/organizations/#{validate_uuid(organization_id)}/members/#{validate_uuid(member_id)}/mfa/reset"
77
+ )
78
+ end
79
+
80
+ # Reset organization member Password
81
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/resetOrganizationMemberPasswordById)
82
+ #
83
+ # @param organization_id [UUID] of the organization
84
+ # @param member_id [UUID] of the member
85
+ #
86
+ # @return a Boolean with result
87
+ def reset_organization_member_password(organization_id, member_id)
88
+ @http.request(
89
+ 'POST',
90
+ "/organizations/#{validate_uuid(organization_id)}/members/#{validate_uuid(member_id)}/password/reset"
91
+ )
92
+ end
93
+
94
+ ###################################################
95
+ # Organization Member Invite
96
+ ###################################################
97
+
98
+ # Organization Members Invites Enumerator of an organization
99
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrgamizationInvites)
100
+ #
101
+ # @param organization_id [UUID] of the organization
102
+ #
103
+ # @return an Organization Members Invites Enumerator object
104
+ def iter_organization_members_invites(organization_id)
105
+ Enumerator.new do |yielder|
106
+ @http.request('GET', "/organizations/#{validate_uuid(organization_id)}/invites").each do |e|
107
+ yielder.yield e
108
+ end
109
+ end
110
+ end
111
+
112
+ # Create organization member invite
113
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/createOrgamizationInvite)
114
+ #
115
+ # @param organization_id [UUID] of the organization
116
+ # @param email [String] of the new member
117
+ # @param roles ['ADMIN'] of the new member
118
+ #
119
+ # @return a Object representing the organization member invite
120
+ def create_organization_members_invite(organization_id, email, roles = nil)
121
+ body = {
122
+ 'email' => email,
123
+ 'roles' => [roles].compact
124
+ }
125
+ @http.request('POST',
126
+ "/organizations/#{validate_uuid(organization_id)}/invites",
127
+ body)
128
+ end
129
+
130
+ # Get organization member invite
131
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/getOrganizationInviteByEmail)
132
+ #
133
+ # @param organization_id [UUID] of the organization
134
+ # @param email [String] of the invited member
135
+ #
136
+ # @return a Object representing the organization member invite
137
+ def get_organization_member_invite(organization_id, email)
138
+ @http.request('GET',
139
+ "/organizations/#{validate_uuid(organization_id)}/invites/#{email}")
140
+ end
141
+
142
+ # Delete organization member invite
143
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/deleteOrganizationInviteByEmail)
144
+ #
145
+ # @param organization_id [UUID] of the organization
146
+ # @param email [String] of the invited member
147
+ #
148
+ # @return a Boolean with result
149
+ def delete_organization_member_invite(organization_id, email)
150
+ @http.request('DELETE',
151
+ "/organizations/#{validate_uuid(organization_id)}/invites/#{email}")
152
+ end
153
+
154
+ # Resend organization member invitation
155
+ # [#reference](https://api.zanshin.tenchisecurity.com/#operation/resendOrganizationInviteByEmail)
156
+ #
157
+ # @param organization_id [UUID] of the organization
158
+ # @param email [String] of the invited member
159
+ #
160
+ # @return a Boolean with result
161
+ def resend_organization_member_invite(organization_id, email)
162
+ @http.request('POST',
163
+ "/organizations/#{validate_uuid(organization_id)}/invites/#{email}/resend")
164
+ end
165
+ end
166
+ end
167
+ end