windoo 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.
- checksums.yaml +7 -0
- data/CHANGES.md +9 -0
- data/LICENSE.txt +177 -0
- data/README.md +222 -0
- data/lib/windoo/base_classes/array_manager.rb +335 -0
- data/lib/windoo/base_classes/criteria_manager.rb +327 -0
- data/lib/windoo/base_classes/criterion.rb +226 -0
- data/lib/windoo/base_classes/json_object.rb +472 -0
- data/lib/windoo/configuration.rb +221 -0
- data/lib/windoo/connection/actions.rb +152 -0
- data/lib/windoo/connection/attributes.rb +156 -0
- data/lib/windoo/connection/connect.rb +402 -0
- data/lib/windoo/connection/constants.rb +55 -0
- data/lib/windoo/connection/token.rb +489 -0
- data/lib/windoo/connection.rb +92 -0
- data/lib/windoo/converters.rb +31 -0
- data/lib/windoo/exceptions.rb +34 -0
- data/lib/windoo/mixins/api_collection.rb +408 -0
- data/lib/windoo/mixins/constants.rb +43 -0
- data/lib/windoo/mixins/default_connection.rb +75 -0
- data/lib/windoo/mixins/immutable.rb +34 -0
- data/lib/windoo/mixins/loading.rb +38 -0
- data/lib/windoo/mixins/patch/component.rb +102 -0
- data/lib/windoo/mixins/software_title/extension_attribute.rb +106 -0
- data/lib/windoo/mixins/utility.rb +23 -0
- data/lib/windoo/objects/capability.rb +82 -0
- data/lib/windoo/objects/capability_manager.rb +52 -0
- data/lib/windoo/objects/component.rb +99 -0
- data/lib/windoo/objects/component_criteria_manager.rb +26 -0
- data/lib/windoo/objects/component_criterion.rb +66 -0
- data/lib/windoo/objects/extension_attribute.rb +149 -0
- data/lib/windoo/objects/kill_app.rb +92 -0
- data/lib/windoo/objects/kill_app_manager.rb +89 -0
- data/lib/windoo/objects/patch.rb +235 -0
- data/lib/windoo/objects/patch_manager.rb +240 -0
- data/lib/windoo/objects/requirement.rb +85 -0
- data/lib/windoo/objects/requirement_manager.rb +52 -0
- data/lib/windoo/objects/software_title.rb +407 -0
- data/lib/windoo/validate.rb +548 -0
- data/lib/windoo/version.rb +15 -0
- data/lib/windoo/zeitwerk_config.rb +158 -0
- data/lib/windoo.rb +56 -0
- metadata +141 -0
@@ -0,0 +1,489 @@
|
|
1
|
+
# Copyright 2025 Pixar
|
2
|
+
#
|
3
|
+
# Licensed under the terms set forth in the LICENSE.txt file available at
|
4
|
+
# at the root of this project.
|
5
|
+
#
|
6
|
+
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
module Windoo
|
10
|
+
|
11
|
+
class Connection
|
12
|
+
|
13
|
+
# A token used for a connection to the Title Editor API
|
14
|
+
class Token
|
15
|
+
|
16
|
+
AUTH_RSRC = 'auth'
|
17
|
+
|
18
|
+
NEW_TOKEN_RSRC = "#{AUTH_RSRC}/tokens"
|
19
|
+
|
20
|
+
REFRESH_RSRC = "#{AUTH_RSRC}/keepalive"
|
21
|
+
|
22
|
+
CURRENT_STATUS_RSRC = "#{AUTH_RSRC}/current"
|
23
|
+
|
24
|
+
# Seconds before expiration that the token will automatically refresh
|
25
|
+
REFRESH_BUFFER = 300
|
26
|
+
|
27
|
+
# Used bu the last_refresh_result method
|
28
|
+
REFRESH_RESULTS = {
|
29
|
+
refreshed: 'Refreshed',
|
30
|
+
refreshed_pw: 'Refresh failed, but new token created with cached pw',
|
31
|
+
refresh_failed: 'Refresh failed, could not create new token with cached pw',
|
32
|
+
refresh_failed_no_pw_fallback: 'Refresh failed, but pw_fallback was false',
|
33
|
+
expired_refreshed: 'Expired, but new token created with cached pw',
|
34
|
+
expired_failed: 'Expired, could not create new token with cached pw',
|
35
|
+
expired_no_pw_fallback: 'Expired, but pw_fallback was false'
|
36
|
+
}.freeze
|
37
|
+
|
38
|
+
# @return [String] The user who generated this token
|
39
|
+
attr_reader :user
|
40
|
+
|
41
|
+
# @return [Integer] The user id of the @user on the server
|
42
|
+
attr_reader :user_id
|
43
|
+
|
44
|
+
# @return [Array<String>] The permissions of the @user
|
45
|
+
attr_reader :scope
|
46
|
+
alias permissions scope
|
47
|
+
|
48
|
+
# @return [String] the SSL version being used
|
49
|
+
attr_reader :ssl_version
|
50
|
+
|
51
|
+
# @return [Boolean] are we verifying SSL certs?
|
52
|
+
attr_reader :verify_cert
|
53
|
+
alias verify_cert? verify_cert
|
54
|
+
|
55
|
+
# @return [Hash] the ssl version and verify cert, to pass into faraday connections
|
56
|
+
attr_reader :ssl_options
|
57
|
+
|
58
|
+
# @return [String] The token data
|
59
|
+
attr_reader :token
|
60
|
+
alias token_string token
|
61
|
+
alias auth_token token
|
62
|
+
|
63
|
+
# @return [URI] The base API url, e.g. https://yourserver.appcatalog.jamfcloud.com
|
64
|
+
attr_reader :base_url
|
65
|
+
|
66
|
+
# @return [Time] when was this Windoo::TitleServer::Connection::Token originally created?
|
67
|
+
attr_reader :creation_time
|
68
|
+
alias login_time creation_time
|
69
|
+
|
70
|
+
# @return [Time] when was this token last refreshed?
|
71
|
+
attr_reader :last_refresh
|
72
|
+
|
73
|
+
# @return [Time]
|
74
|
+
attr_reader :expires
|
75
|
+
alias expiration expires
|
76
|
+
|
77
|
+
# @return [Boolean] does this token automatically refresh itself before
|
78
|
+
# expiring?
|
79
|
+
attr_reader :keep_alive
|
80
|
+
alias keep_alive? keep_alive
|
81
|
+
|
82
|
+
# @return [Boolean] Should the provided passwd be cached in memory, to be
|
83
|
+
# used to generate a new token, if a normal refresh fails?
|
84
|
+
attr_reader :pw_fallback
|
85
|
+
alias pw_fallback? pw_fallback
|
86
|
+
|
87
|
+
# @return [Faraday::Response] The response object from instantiating
|
88
|
+
# a new Token object by creating a new token or validating a token
|
89
|
+
# string. This is not updated when refreshing a token, only when
|
90
|
+
# calling Token.new
|
91
|
+
attr_reader :creation_http_response
|
92
|
+
|
93
|
+
# @return [Time] The time the server created the token
|
94
|
+
attr_reader :server_creation_time
|
95
|
+
|
96
|
+
# @return [String] The tenantID of this server connection
|
97
|
+
attr_reader :tenantId
|
98
|
+
alias tenant_id tenantId
|
99
|
+
|
100
|
+
# @return [String] The fully qualified hostname of the server
|
101
|
+
# that generated this token
|
102
|
+
attr_reader :domain
|
103
|
+
|
104
|
+
# @param params [Hash] The data for creating and maintaining the token
|
105
|
+
#
|
106
|
+
# @option params [String, URI] base_url: The url for the Jamf Pro server
|
107
|
+
# including host and port, e.g. 'https://yourserver.appcatalog.jamfcloud.com'
|
108
|
+
#
|
109
|
+
# @option params [String] user: (see Connection#initialize)
|
110
|
+
#
|
111
|
+
# @option params [String] token_string: An existing valid token string.
|
112
|
+
# If provided, no need to provide 'user', which will be read from the
|
113
|
+
# server. If pw_fallback is true (the default) you will also need to provide
|
114
|
+
# the password for the user who created the token in the pw: parameter.
|
115
|
+
# If you don't, pw_fallback will be false even if you set it to true explicitly.
|
116
|
+
#
|
117
|
+
# @option params [String] pw: (see Connection#initialize)
|
118
|
+
#
|
119
|
+
# @option params [Integer] timeout: The http timeout for communication
|
120
|
+
# with the server. This is only used for token-related communication, not
|
121
|
+
# general API usage, and so need not be the same as that for the
|
122
|
+
# connection that uses this token.
|
123
|
+
#
|
124
|
+
# @option params [Boolean] keep_alive: (see Connection#connect)
|
125
|
+
#
|
126
|
+
# @option params [Boolean] pw_fallback: (see Connection#connect)
|
127
|
+
#
|
128
|
+
# @option params [String, Symbol] ssl_version: (see Connection#connect)
|
129
|
+
#
|
130
|
+
# @option params [Boolean] verify_cert: (see Connection#connect)
|
131
|
+
#
|
132
|
+
###########################################
|
133
|
+
def initialize(**params)
|
134
|
+
@valid = false
|
135
|
+
parse_params(**params)
|
136
|
+
|
137
|
+
if params[:token_string]
|
138
|
+
@pw_fallback = false unless @pw
|
139
|
+
@creation_http_response = init_from_token_string params[:token_string]
|
140
|
+
|
141
|
+
elsif @user && @pw
|
142
|
+
@creation_http_response = init_from_pw
|
143
|
+
|
144
|
+
else
|
145
|
+
raise ArgumentError, 'Must provide either user: & pw: or token_string:'
|
146
|
+
end
|
147
|
+
|
148
|
+
start_keep_alive if @keep_alive
|
149
|
+
@creation_time = Time.now
|
150
|
+
end # init
|
151
|
+
|
152
|
+
# Initialize from password
|
153
|
+
# @return [Faraday::Response] the response from checking the status,
|
154
|
+
# which might be used to set @creation_http_response
|
155
|
+
#################################
|
156
|
+
def init_from_pw
|
157
|
+
resp = token_connection(NEW_TOKEN_RSRC).post
|
158
|
+
|
159
|
+
if resp.success?
|
160
|
+
@token = resp.body[:token]
|
161
|
+
parse_token_status
|
162
|
+
@last_refresh = Time.now
|
163
|
+
resp
|
164
|
+
elsif resp.status == 401
|
165
|
+
raise Windoo::AuthenticationError, 'Incorrect user name or password'
|
166
|
+
else
|
167
|
+
# TODO: better error reporting here
|
168
|
+
puts
|
169
|
+
puts resp.status
|
170
|
+
puts resp.body
|
171
|
+
puts
|
172
|
+
raise Windoo::ConnectionError, "An error occurred while authenticating: #{resp.body}"
|
173
|
+
end
|
174
|
+
ensure
|
175
|
+
@pw = nil unless @pw_fallback
|
176
|
+
end # init_from_pw
|
177
|
+
|
178
|
+
# Initialize from token string
|
179
|
+
# @return [Faraday::Response] the response from checking the status,
|
180
|
+
# which might be used to set @creation_http_response
|
181
|
+
#################################
|
182
|
+
def init_from_token_string(str)
|
183
|
+
@token = str
|
184
|
+
parse_token_status
|
185
|
+
|
186
|
+
# we now know the @user who created the token string.
|
187
|
+
# if we were given a pw and expect to use it, call init_from_pw
|
188
|
+
# to validate it by getting a fresh token
|
189
|
+
return init_from_pw if @pw && @pw_fallback
|
190
|
+
|
191
|
+
# use this token to get a fresh one with the full
|
192
|
+
# 15 min lifespan
|
193
|
+
refresh
|
194
|
+
end # init_from_token_string
|
195
|
+
|
196
|
+
#################################
|
197
|
+
def host
|
198
|
+
base_url.host
|
199
|
+
end
|
200
|
+
|
201
|
+
# @return [Integer]
|
202
|
+
#################################
|
203
|
+
def port
|
204
|
+
base_url.port
|
205
|
+
end
|
206
|
+
|
207
|
+
# @return [Boolean]
|
208
|
+
#################################
|
209
|
+
def expired?
|
210
|
+
return unless @expires
|
211
|
+
|
212
|
+
Time.now >= @expires
|
213
|
+
end
|
214
|
+
|
215
|
+
# when is the next rerefresh going to happen, if we are set to keep alive?
|
216
|
+
#
|
217
|
+
# @return [Time, nil] the time of the next scheduled refresh, or nil if not keep_alive?
|
218
|
+
def next_refresh
|
219
|
+
return unless keep_alive?
|
220
|
+
|
221
|
+
@expires - REFRESH_BUFFER
|
222
|
+
end
|
223
|
+
|
224
|
+
# how many secs until the next refresh?
|
225
|
+
# will return 0 during the actual refresh process.
|
226
|
+
#
|
227
|
+
# @return [Float, nil] Seconds until the next scheduled refresh, or nil if not keep_alive?
|
228
|
+
#
|
229
|
+
def secs_to_refresh
|
230
|
+
return unless keep_alive?
|
231
|
+
|
232
|
+
secs = next_refresh - Time.now
|
233
|
+
secs.negative? ? 0 : secs
|
234
|
+
end
|
235
|
+
|
236
|
+
# Returns e.g. "1 week 6 days 23 hours 49 minutes 56 seconds"
|
237
|
+
#
|
238
|
+
# @return [String, nil]
|
239
|
+
def time_to_refresh
|
240
|
+
return unless keep_alive?
|
241
|
+
|
242
|
+
secs_to_refresh.pix_humanize_secs
|
243
|
+
end
|
244
|
+
|
245
|
+
# @return [Float]
|
246
|
+
#################################
|
247
|
+
def secs_remaining
|
248
|
+
return unless @expires
|
249
|
+
|
250
|
+
@expires - Time.now
|
251
|
+
end
|
252
|
+
|
253
|
+
# @return [String] e.g. "1 week 6 days 23 hours 49 minutes 56 seconds"
|
254
|
+
#################################
|
255
|
+
def time_remaining
|
256
|
+
return unless @expires
|
257
|
+
|
258
|
+
secs_remaining.pix_humanize_secs
|
259
|
+
end
|
260
|
+
|
261
|
+
# @return [Boolean]
|
262
|
+
#################################
|
263
|
+
def valid?
|
264
|
+
@valid =
|
265
|
+
if expired?
|
266
|
+
false
|
267
|
+
elsif !@token
|
268
|
+
false
|
269
|
+
else
|
270
|
+
token_connection(CURRENT_STATUS_RSRC, token: token).post.success?
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
# What happened the last time we tried to refresh?
|
275
|
+
# See REFRESH_RESULTS
|
276
|
+
#
|
277
|
+
# @return [String, nil] result or nil if never refreshed
|
278
|
+
#################################
|
279
|
+
def last_refresh_result
|
280
|
+
REFRESH_RESULTS[@last_refresh_result]
|
281
|
+
end
|
282
|
+
|
283
|
+
# Use this token to get a fresh one. If a pw is provided
|
284
|
+
# try to use it to get a new token if a proper refresh fails.
|
285
|
+
#
|
286
|
+
# @param pw [String] Optional password to use if token refresh fails.
|
287
|
+
# Must be the correct passwd or the token's user (obviously)
|
288
|
+
#
|
289
|
+
# @return [Faraday::Response] the response from checking the status,
|
290
|
+
# which might be used to set @creation_http_response
|
291
|
+
#
|
292
|
+
#################################
|
293
|
+
def refresh
|
294
|
+
# already expired?
|
295
|
+
if expired?
|
296
|
+
# try the passwd if we have it
|
297
|
+
return refresh_with_pw(:expired_refreshed, :expired_failed) if @pw
|
298
|
+
|
299
|
+
# no passwd fallback? no chance!
|
300
|
+
@last_refresh_result = :expired_no_pw_fallback
|
301
|
+
raise Windoo::InvalidTokenError, 'Token has expired'
|
302
|
+
end
|
303
|
+
|
304
|
+
# Now try a normal refresh of our non-expired token
|
305
|
+
refresh_resp = token_connection(REFRESH_RSRC, token: token).post
|
306
|
+
|
307
|
+
if refresh_resp.success?
|
308
|
+
@token = refresh_resp.body[:token]
|
309
|
+
parse_token_status
|
310
|
+
@last_refresh = Time.now
|
311
|
+
return refresh_resp
|
312
|
+
end
|
313
|
+
|
314
|
+
# if we're here, the normal refresh failed, so try the pw
|
315
|
+
return refresh_with_pw(:refreshed_pw, :refresh_failed) if @pw
|
316
|
+
|
317
|
+
# if we're here, no pw = no chance!
|
318
|
+
@last_refresh_result = :refresh_failed_no_pw_fallback
|
319
|
+
raise Windoo::InvalidTokenError, 'An error occurred while refreshing the token'
|
320
|
+
end
|
321
|
+
|
322
|
+
# Make this token invalid
|
323
|
+
#################################
|
324
|
+
def invalidate
|
325
|
+
stop_keep_alive
|
326
|
+
@valid = false
|
327
|
+
@token = nil
|
328
|
+
@pw = nil
|
329
|
+
end
|
330
|
+
alias destroy invalidate
|
331
|
+
|
332
|
+
# creates a thread that loops forever, sleeping most of the time, but
|
333
|
+
# waking up every 60 seconds to see if the token is expiring in the
|
334
|
+
# next REFRESH_BUFFER seconds.
|
335
|
+
#
|
336
|
+
# If so, the token is refreshed, and we keep looping and sleeping.
|
337
|
+
#
|
338
|
+
# Sets @keep_alive_thread to the Thread object
|
339
|
+
#
|
340
|
+
# @return [void]
|
341
|
+
#################################
|
342
|
+
def start_keep_alive
|
343
|
+
return if @keep_alive_thread
|
344
|
+
raise 'Token expired, cannot refresh' if expired?
|
345
|
+
|
346
|
+
@keep_alive_thread =
|
347
|
+
Thread.new do
|
348
|
+
loop do
|
349
|
+
sleep 60
|
350
|
+
begin
|
351
|
+
next if secs_remaining > REFRESH_BUFFER
|
352
|
+
|
353
|
+
refresh
|
354
|
+
rescue StandardError
|
355
|
+
# TODO: Some kind of error reporting
|
356
|
+
next
|
357
|
+
end
|
358
|
+
end # loop
|
359
|
+
end # thread
|
360
|
+
@keep_alive_thread.name = "Windoo keep_alive #{tenantId} (#{@login_time})"
|
361
|
+
end # start_keep_alive
|
362
|
+
|
363
|
+
# Kills the @keep_alive_thread, if it exists, and sets
|
364
|
+
# @keep_alive_thread to nil
|
365
|
+
#
|
366
|
+
# @return [void]
|
367
|
+
#
|
368
|
+
def stop_keep_alive
|
369
|
+
return unless @keep_alive_thread
|
370
|
+
|
371
|
+
@keep_alive_thread.kill if @keep_alive_thread.alive?
|
372
|
+
@keep_alive_thread = nil
|
373
|
+
end
|
374
|
+
|
375
|
+
# Invalidate this token by stopping any keepalive thread and
|
376
|
+
# setting most values to nil or :disconnected
|
377
|
+
#
|
378
|
+
# @return [void]
|
379
|
+
#
|
380
|
+
def disconnect
|
381
|
+
stop_keep_alive
|
382
|
+
@token = nil
|
383
|
+
@pw = nil
|
384
|
+
@pw_fallback = nil
|
385
|
+
@keep_alive = nil
|
386
|
+
@creation_http_response = nil
|
387
|
+
@expires = Time.now
|
388
|
+
@scope = nil
|
389
|
+
@user = :disconnected
|
390
|
+
@user_id = 0
|
391
|
+
@valid = false
|
392
|
+
@domain = :disconnected
|
393
|
+
@tenantId = :disconnected
|
394
|
+
end
|
395
|
+
|
396
|
+
# Private instance methods
|
397
|
+
#################################
|
398
|
+
private
|
399
|
+
|
400
|
+
# set values from params & defaults
|
401
|
+
###########################################
|
402
|
+
def parse_params(**params)
|
403
|
+
# This process of deleting suffixes will leave in place any
|
404
|
+
# URL paths before the the CAPI_RSRC_BASE or JPAPI_RSRC_BASE
|
405
|
+
# e.g. https://my.jamf.server:8443/some/path/before/api
|
406
|
+
# as is the case at some on-prem sites.
|
407
|
+
baseurl = params[:base_url].to_s.dup
|
408
|
+
baseurl.delete_suffix! '/'
|
409
|
+
@base_url = URI.parse baseurl
|
410
|
+
|
411
|
+
@timeout = params[:timeout] || Windoo::Connection::DFT_TIMEOUT
|
412
|
+
|
413
|
+
@user = params[:user]
|
414
|
+
|
415
|
+
# @pw will be deleted after use if pw_fallback is false
|
416
|
+
# It is stored as base64 merely for visual security in irb sessions
|
417
|
+
# and the like.
|
418
|
+
@pw = Base64.encode64 params[:pw] if params[:pw].is_a? String
|
419
|
+
|
420
|
+
@pw_fallback = params[:pw_fallback].instance_of?(FalseClass) ? false : true
|
421
|
+
|
422
|
+
@ssl_version = params[:ssl_version] || Jamf::Connection::DFT_SSL_VERSION
|
423
|
+
@verify_cert = (params[:verify_cert] != false)
|
424
|
+
@ssl_options = { version: @ssl_version, verify: @verify_cert }
|
425
|
+
|
426
|
+
@keep_alive = (params[:keep_alive] != false)
|
427
|
+
end
|
428
|
+
|
429
|
+
# Parse the response from the CURRENT_STATUS_RSRC to set
|
430
|
+
# ome attributes from the current token
|
431
|
+
#
|
432
|
+
# @return [Faraday::Response] the response from checking the status,
|
433
|
+
# which might be used to set @creation_http_response
|
434
|
+
####################################
|
435
|
+
def parse_token_status
|
436
|
+
resp = token_connection(CURRENT_STATUS_RSRC, token: token).post
|
437
|
+
raise Windoo::InvalidTokenError, 'Token is not valid' unless resp.success?
|
438
|
+
|
439
|
+
@server_creation_time = Time.at resp.body[:iat]
|
440
|
+
@expires = Time.at resp.body[:exp]
|
441
|
+
@user = resp.body[:user]
|
442
|
+
@user_id = resp.body[:id]
|
443
|
+
@scope = resp.body[:scope]
|
444
|
+
@domain = resp.body[:domain]
|
445
|
+
@tenantId = resp.body[:tenantId]
|
446
|
+
@valid = true
|
447
|
+
|
448
|
+
resp
|
449
|
+
end
|
450
|
+
|
451
|
+
# refresh a token using the pw cached when @pw_fallback is true
|
452
|
+
#
|
453
|
+
# @param success [Sumbol] the key from REFRESH_RESULTS to use when successful
|
454
|
+
# @param failure [Sumbol] the key from REFRESH_RESULTS to use when not successful
|
455
|
+
# @return [Faraday::Response] the response from checking the status,
|
456
|
+
# which might be used to set @creation_http_response
|
457
|
+
#################################
|
458
|
+
def refresh_with_pw(success, failure)
|
459
|
+
resp = init_from_pw
|
460
|
+
@last_refresh_result = success
|
461
|
+
resp
|
462
|
+
rescue StandardError => e
|
463
|
+
@last_refresh_result = failure
|
464
|
+
raise e, "#{e}. Status: :#{REFRESH_RESULTS[failure]}"
|
465
|
+
end
|
466
|
+
|
467
|
+
# a generic, one-time Faraday connection for token
|
468
|
+
# acquision & manipulation
|
469
|
+
#################################
|
470
|
+
def token_connection(rsrc, token: nil)
|
471
|
+
Faraday.new("#{base_url}/#{rsrc}", ssl: @ssl_options) do |con|
|
472
|
+
con.request :json
|
473
|
+
con.response :json, parser_options: { symbolize_names: true }
|
474
|
+
con.options[:timeout] = @timeout
|
475
|
+
con.options[:open_timeout] = @timeout
|
476
|
+
if token
|
477
|
+
con.request :authorization, 'Bearer', token
|
478
|
+
else
|
479
|
+
con.request :authorization, :basic, @user, Base64.decode64(@pw)
|
480
|
+
end
|
481
|
+
con.adapter :net_http
|
482
|
+
end # Faraday.new
|
483
|
+
end # token_connection
|
484
|
+
|
485
|
+
end # class Token
|
486
|
+
|
487
|
+
end # class Connection
|
488
|
+
|
489
|
+
end # module Windoo
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# Copyright 2025 Pixar
|
2
|
+
#
|
3
|
+
# Licensed under the terms set forth in the LICENSE.txt file available at
|
4
|
+
# at the root of this project.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
|
8
|
+
# frozen_string_literal: true
|
9
|
+
|
10
|
+
module Windoo
|
11
|
+
|
12
|
+
# Instances of this class represent a connection to a Jamf Title Editor
|
13
|
+
class Connection
|
14
|
+
|
15
|
+
# the code for this class is broken into multiple files
|
16
|
+
# as modules, to play will with the zeitwerk loader
|
17
|
+
include Windoo::Connection::Constants
|
18
|
+
include Windoo::Connection::Attributes
|
19
|
+
include Windoo::Connection::Connect
|
20
|
+
include Windoo::Connection::Actions
|
21
|
+
|
22
|
+
# Constructor
|
23
|
+
#####################################
|
24
|
+
|
25
|
+
# Instantiate a connection object.
|
26
|
+
#
|
27
|
+
# If name: is provided it will be stored as the Connection's name attribute.
|
28
|
+
#
|
29
|
+
# if no url is provided and params are empty, or contains only
|
30
|
+
# a :name key, then you must call #connect with all the connection
|
31
|
+
# parameters before accessing a server.
|
32
|
+
#
|
33
|
+
# See {#connect} for the parameters
|
34
|
+
#
|
35
|
+
def initialize(url = nil, **params)
|
36
|
+
@name = params.delete :name
|
37
|
+
@connected = false
|
38
|
+
|
39
|
+
return if url.nil? && params.empty?
|
40
|
+
|
41
|
+
connect url, **params
|
42
|
+
end # init
|
43
|
+
|
44
|
+
# Instance methods
|
45
|
+
#####################################
|
46
|
+
|
47
|
+
# A useful string about this connection
|
48
|
+
#
|
49
|
+
# @return [String]
|
50
|
+
#
|
51
|
+
def to_s
|
52
|
+
return 'not connected' unless connected?
|
53
|
+
|
54
|
+
if name.to_s.start_with? "#{user}@"
|
55
|
+
name
|
56
|
+
else
|
57
|
+
"#{user}@#{host}:#{port}, name: #{name}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Only selected items are displayed with prettyprint
|
62
|
+
# otherwise its too much data in irb.
|
63
|
+
#
|
64
|
+
# @return [Array] the desired instance_variables
|
65
|
+
#
|
66
|
+
def pretty_print_instance_variables
|
67
|
+
PP_VARS
|
68
|
+
end
|
69
|
+
|
70
|
+
# @deprecated, use .token.next_refresh
|
71
|
+
def next_refresh
|
72
|
+
@token.next_refresh
|
73
|
+
end
|
74
|
+
|
75
|
+
# @deprecated, use .token.secs_to_refresh
|
76
|
+
def secs_to_refresh
|
77
|
+
@token.secs_to_refresh
|
78
|
+
end
|
79
|
+
|
80
|
+
# @deprecated, use .token.time_to_refresh
|
81
|
+
def time_to_refresh
|
82
|
+
@token.time_to_refresh
|
83
|
+
end
|
84
|
+
|
85
|
+
# is this the default connection?
|
86
|
+
def default?
|
87
|
+
self == Windoo.cnx
|
88
|
+
end
|
89
|
+
|
90
|
+
end # class Connection
|
91
|
+
|
92
|
+
end # module Windoo
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Copyright 2025 Pixar
|
2
|
+
#
|
3
|
+
# Licensed under the terms set forth in the LICENSE.txt file available at
|
4
|
+
# at the root of this project.
|
5
|
+
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
module Windoo
|
9
|
+
|
10
|
+
# Methods for converting values in standard ways
|
11
|
+
# Usually used for converting between Ruby values and JSON values
|
12
|
+
# between Windoo and the Server
|
13
|
+
module Converters
|
14
|
+
|
15
|
+
# @param time [Time] a Time object to send to the API
|
16
|
+
# @return [String] The time in UTC and ISO8601 format
|
17
|
+
def self.time_to_api(time)
|
18
|
+
time.utc.iso8601
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param time [#to_s] a timestamp from the API
|
22
|
+
# @return [Time] The timestamp as a Time object
|
23
|
+
def self.to_time(time)
|
24
|
+
return time if time.is_a? Time
|
25
|
+
|
26
|
+
Time.parse time.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
end # Utility
|
30
|
+
|
31
|
+
end # Windoo
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Copyright 2025 Pixar
|
2
|
+
#
|
3
|
+
# Licensed under the terms set forth in the LICENSE.txt file available at
|
4
|
+
# at the root of this project.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
|
8
|
+
module Windoo
|
9
|
+
|
10
|
+
# Connections & Access
|
11
|
+
|
12
|
+
class ConnectionError < RuntimeError; end
|
13
|
+
|
14
|
+
class NotConnectedError < RuntimeError; end
|
15
|
+
|
16
|
+
class AuthenticationError < RuntimeError; end
|
17
|
+
|
18
|
+
class PermissionError < RuntimeError; end
|
19
|
+
|
20
|
+
class InvalidTokenError < RuntimeError; end
|
21
|
+
|
22
|
+
# General errors
|
23
|
+
|
24
|
+
class MissingDataError < RuntimeError; end
|
25
|
+
|
26
|
+
class InvalidDataError < RuntimeError; end
|
27
|
+
|
28
|
+
class NoSuchItemError < RuntimeError; end
|
29
|
+
|
30
|
+
class AlreadyExistsError < RuntimeError; end
|
31
|
+
|
32
|
+
class UnsupportedError < RuntimeError; end
|
33
|
+
|
34
|
+
end # module Windoo
|