ruby-jss 2.1.0 → 3.0.0b1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +27 -0
- data/lib/jamf/api/classic/api_objects/computer.rb +20 -6
- data/lib/jamf/api/classic/api_objects/distribution_point.rb +17 -41
- data/lib/jamf/api/classic/api_objects/mdm.rb +9 -9
- data/lib/jamf/api/classic/api_objects/mobile_device_application.rb +1 -0
- data/lib/jamf/api/classic/api_objects/policy.rb +173 -92
- data/lib/jamf/api/classic/api_objects/scopable/scope.rb +5 -2
- data/lib/jamf/api/jamf_pro/mixins/macos_managed_updates.rb +47 -37
- data/lib/jamf/validate.rb +3 -1
- data/lib/jamf/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a7af617b6ac8bb27cbc7d5c790a2de9fa788fb3d426ae062581654fbc9f77c5f
|
4
|
+
data.tar.gz: f5dfabfdde6c466951862fdc458321ad4f9384293e1fe773fb78a0ca80e51283
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85fd8c1218206a35545cc034058996a5b03183f29ac443cf65735c547975afcedaf406f74099f610380a1b72272db5240c2427ab4e87201ef5d9ec7ceffd2f29
|
7
|
+
data.tar.gz: a04b06cbcb9858b06dfe738ced2943e37b6a12088da394599b6ccfae66ac0a9c1bc82a264dac02c0379308141d4cc9795594c19639f473e5684cdd62e48db368
|
data/CHANGES.md
CHANGED
@@ -14,6 +14,33 @@ __Please update all installations of ruby-jss to at least v1.6.0.__
|
|
14
14
|
|
15
15
|
Many many thanks to actae0n of Blacksun Hackers Club for reporting this issue and providing examples of how it could be exploited.
|
16
16
|
|
17
|
+
--------
|
18
|
+
|
19
|
+
## \[UNRELEASED]
|
20
|
+
|
21
|
+
### Added
|
22
|
+
- Jamf::Policy.flush_logs_for_computers: formerly private class method, now public and used for flushing policy logs for specific computers.
|
23
|
+
|
24
|
+
### Fixed
|
25
|
+
- Fix bug in MDM enable_lost_mode instance method, and make the default behavior match the API
|
26
|
+
- Specify the connection instance when validating ids in MacOSManagedUpdates
|
27
|
+
- Send mandatory field 'name' with a MobileDeviceApplication request (Thanks @yanniks!)
|
28
|
+
- Policy Log Flushing now reflects API limitation: You can flush logs for a policy for all computers, or for a computer for all policies, but not specific policies for specific computers. See Jamf::Policy.flush_logs and Jamf::Policy.flush_logs_for_computers
|
29
|
+
- A validation method wasn't passing cnx param correctly.
|
30
|
+
|
31
|
+
### Changed
|
32
|
+
- MacOSManagedUpdates.send_managed_os_update takes symbols as the updateAction
|
33
|
+
|
34
|
+
## \[2.1.1] - 2022-11-07
|
35
|
+
|
36
|
+
### Fixed & Deprecated
|
37
|
+
|
38
|
+
- The classic API no longer includes SHA256 hashes of various passwords - the data value is there, but only contains a string of asterisks. As such, ruby-jss can no longer use those to validate some passwords before trying to use them. The methods doing so are still present, but only return `true`. If an incorrect password is given, the underlying process that uses it will fail on its own.
|
39
|
+
These methods will be removed in a future version of ruby-jss:
|
40
|
+
- `Jamf::DistributionPoint#check_pw` Used mostly by the `Jamf::DistributionPoint#mount` method
|
41
|
+
- `Jamf::Policy.verify_management_password`
|
42
|
+
|
43
|
+
|
17
44
|
## \[2.1.0] - 2022-10-10
|
18
45
|
|
19
46
|
### Added
|
@@ -1158,15 +1158,29 @@ module Jamf
|
|
1158
1158
|
@need_to_update = true
|
1159
1159
|
end
|
1160
1160
|
|
1161
|
-
#
|
1162
|
-
# @see Jamf::Policy.flush_logs
|
1161
|
+
# Flush all policy logs for this computer older than a given time period.
|
1163
1162
|
#
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1163
|
+
# IMPORTANT: from the Jamf Developer Site:
|
1164
|
+
# The ability to flush logs is currently only supported for flushing all logs
|
1165
|
+
# for a given policy or all logs for a given computer. There is no support for
|
1166
|
+
# flushing logs for a given policy and computer combination.
|
1167
|
+
#
|
1168
|
+
# With no parameters, will flush all logs for the computer
|
1169
|
+
#
|
1170
|
+
# NOTE: Currently the API doesn't have a way to flush only failed policies.
|
1171
|
+
#
|
1172
|
+
# @param older_than[Integer] 0, 1, 2, 3, or 6
|
1173
|
+
#
|
1174
|
+
# @param period[Symbol] :days, :weeks, :months, or :years
|
1175
|
+
#
|
1176
|
+
# @see Jamf::Policy.flush_logs_for_computers
|
1177
|
+
#
|
1178
|
+
def flush_policy_logs(older_than: 0, period: :days)
|
1179
|
+
Jamf::Policy.flush_logs_for_computers(
|
1180
|
+
[@id],
|
1167
1181
|
older_than: older_than,
|
1168
1182
|
period: period,
|
1169
|
-
|
1183
|
+
cnx: @cnx
|
1170
1184
|
)
|
1171
1185
|
end
|
1172
1186
|
|
@@ -259,8 +259,8 @@ module Jamf
|
|
259
259
|
attr_reader :ssh_password_sha256
|
260
260
|
|
261
261
|
def initialize(**args)
|
262
|
-
super
|
263
|
-
|
262
|
+
super
|
263
|
+
|
264
264
|
@ip_address = @init_data[:ip_address]
|
265
265
|
@local_path = @init_data[:local_path]
|
266
266
|
@enable_load_balancing = @init_data[:enable_load_balancing]
|
@@ -294,44 +294,28 @@ module Jamf
|
|
294
294
|
|
295
295
|
@port = @init_data[:ssh_password]
|
296
296
|
|
297
|
-
# Note, as of Casper 9.3:
|
298
|
-
# :management_password_md5=>"xxxxx"
|
299
|
-
# and
|
300
|
-
# :management_password_sha256=> "xxxxxxxxxx"
|
301
|
-
# Are the read/write password
|
302
|
-
#
|
303
|
-
# An empty passwd is
|
304
|
-
# MD5 = d41d8cd98f00b204e9800998ecf8427e
|
305
|
-
# SHA256 = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
306
|
-
#
|
307
|
-
# Seemms the read-only pw isn't available in the API
|
308
|
-
|
309
297
|
# if we mount for fileservice, where's the mountpoint?
|
310
298
|
@mountpoint = DEFAULT_MOUNTPOINT_DIR + "#{DEFAULT_MOUNTPOINT_PREFIX}#{@id}"
|
311
299
|
end # init
|
312
300
|
|
313
|
-
#
|
301
|
+
# @deprecated The API no longer sends SHA256 hashed password data, and instead
|
302
|
+
# only has a string of asterisks, meaning we can no longer use it to validate
|
303
|
+
# passwords before attempting to use them. Instead, the processes that use
|
304
|
+
# them, e.g. mounting a Dist. Point, will fail on their own if the pw is not
|
305
|
+
# valid.
|
314
306
|
#
|
315
|
-
#
|
307
|
+
# This method remains defined for backward-compatibility with any existing
|
308
|
+
# code that calls it. but it will always return true. It will be removed in
|
309
|
+
# a future version
|
316
310
|
#
|
317
|
-
# @param
|
311
|
+
# @param user[Symbol] ignored
|
318
312
|
#
|
319
|
-
# @
|
320
|
-
# nil is returned if there is no password set in the JSS.
|
313
|
+
# @param pw[String] ignored
|
321
314
|
#
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
when :rw then @read_write_password_sha256
|
327
|
-
when :ro then @read_only_password_sha256
|
328
|
-
when :http then @http_password_sha256
|
329
|
-
when :ssh then @ssh_password_sha256
|
330
|
-
end # case
|
331
|
-
|
332
|
-
return nil if sha256 == EMPTY_PW_256
|
333
|
-
|
334
|
-
sha256 == Digest::SHA2.new(256).update(pw).to_s
|
315
|
+
# @return [TrueClass] Allow the process calling this to continue.
|
316
|
+
#
|
317
|
+
def check_pw(_user = nil, _pw = nil)
|
318
|
+
true
|
335
319
|
end
|
336
320
|
|
337
321
|
# Check to see if this dist point is reachable for downloads (read-only)
|
@@ -350,7 +334,6 @@ module Jamf
|
|
350
334
|
def reachable_for_download?(pw = '', check_http = true)
|
351
335
|
return :http if check_http && http_reachable?(pw)
|
352
336
|
return :mountable if mounted?
|
353
|
-
return false unless check_pw :ro, pw
|
354
337
|
|
355
338
|
begin
|
356
339
|
mount pw, :ro
|
@@ -371,7 +354,6 @@ module Jamf
|
|
371
354
|
#
|
372
355
|
def reachable_for_upload?(pw)
|
373
356
|
return :mountable if mounted?
|
374
|
-
return false unless check_pw :rw, pw
|
375
357
|
|
376
358
|
begin
|
377
359
|
mount pw, :rw
|
@@ -413,12 +395,6 @@ module Jamf
|
|
413
395
|
pw
|
414
396
|
end
|
415
397
|
|
416
|
-
pwok = check_pw(access, password)
|
417
|
-
unless pwok
|
418
|
-
msg = pwok.nil? ? "No #{access} password set in the JSS" : "Incorrect password for #{access} account"
|
419
|
-
raise Jamf::InvalidDataError, msg
|
420
|
-
end
|
421
|
-
|
422
398
|
username = access == :ro ? @read_only_username : @read_write_username
|
423
399
|
|
424
400
|
safe_pw = CGI.escape password.to_s
|
@@ -481,7 +457,7 @@ module Jamf
|
|
481
457
|
private
|
482
458
|
|
483
459
|
# can the dp be reached for http downloads?
|
484
|
-
def http_reachable?(pw)
|
460
|
+
def http_reachable?(pw = nil)
|
485
461
|
return false unless http_downloads_enabled
|
486
462
|
|
487
463
|
url =
|
@@ -476,7 +476,7 @@ module Jamf
|
|
476
476
|
raise Jamf::UnmanagedError, "#{self} with id #{target_id} is not managed. Cannot send command." unless all_mgd.include? target_id
|
477
477
|
end
|
478
478
|
end # unles
|
479
|
-
|
479
|
+
|
480
480
|
targets
|
481
481
|
end
|
482
482
|
|
@@ -860,7 +860,7 @@ module Jamf
|
|
860
860
|
cnx = api if api
|
861
861
|
|
862
862
|
unless WALLPAPER_LOCATIONS.keys.include? wallpaper_setting
|
863
|
-
raise ArgumentError,
|
863
|
+
raise ArgumentError,
|
864
864
|
"wallpaper_setting must be one of: :#{WALLPAPER_LOCATIONS.keys.join ', :'}"
|
865
865
|
end
|
866
866
|
|
@@ -999,7 +999,7 @@ module Jamf
|
|
999
999
|
#
|
1000
1000
|
# @param play_sound[Boolean] Play a sound when entering lost mode
|
1001
1001
|
#
|
1002
|
-
# @param enforce_lost_mode[Boolean] Re-
|
1002
|
+
# @param enforce_lost_mode[Boolean] Re-enable lost mode when re-enrolled after wipe. Default is false
|
1003
1003
|
#
|
1004
1004
|
# @param cnx [Jamf::Connection] the API thru which to send the command
|
1005
1005
|
#
|
@@ -1011,7 +1011,7 @@ module Jamf
|
|
1011
1011
|
phone: nil,
|
1012
1012
|
footnote: nil,
|
1013
1013
|
play_sound: false,
|
1014
|
-
enforce_lost_mode:
|
1014
|
+
enforce_lost_mode: false,
|
1015
1015
|
api: nil,
|
1016
1016
|
cnx: Jamf.cnx
|
1017
1017
|
)
|
@@ -1081,7 +1081,7 @@ module Jamf
|
|
1081
1081
|
|
1082
1082
|
status = FLUSHABLE_STATUSES[status]
|
1083
1083
|
|
1084
|
-
# TODO: add 'unmanaged_ok:' param to raw_targets_to_ids method, so that we can
|
1084
|
+
# TODO: add 'unmanaged_ok:' param to raw_targets_to_ids method, so that we can
|
1085
1085
|
# use this to flush commands for unmanaged machines.
|
1086
1086
|
target_ids = raw_targets_to_ids targets, cnx: cnx, expand_groups: false, unmanaged_ok: true
|
1087
1087
|
|
@@ -1378,21 +1378,21 @@ module Jamf
|
|
1378
1378
|
#
|
1379
1379
|
# @param play_sound[Boolean] Play a sound when entering lost mode
|
1380
1380
|
#
|
1381
|
-
# @param enforce_lost_mode[Boolean] Re-
|
1381
|
+
# @param enforce_lost_mode[Boolean] Re-enable lost mode when re-enrolled after wipe. Default is false
|
1382
1382
|
#
|
1383
1383
|
# @return (see .send_mdm_command)
|
1384
1384
|
#
|
1385
1385
|
def enable_lost_mode(
|
1386
1386
|
message: nil,
|
1387
|
-
|
1387
|
+
phone: nil,
|
1388
1388
|
footnote: nil,
|
1389
|
-
enforce_lost_mode:
|
1389
|
+
enforce_lost_mode: false,
|
1390
1390
|
play_sound: false
|
1391
1391
|
)
|
1392
1392
|
self.class.enable_lost_mode(
|
1393
1393
|
@id,
|
1394
1394
|
message: message,
|
1395
|
-
|
1395
|
+
phone: phone,
|
1396
1396
|
footnote: footnote,
|
1397
1397
|
play_sound: play_sound,
|
1398
1398
|
enforce_lost_mode: enforce_lost_mode, cnx: @cnx
|
@@ -544,6 +544,7 @@ module Jamf
|
|
544
544
|
doc = REXML::Document.new Jamf::Connection::XML_HEADER
|
545
545
|
obj = doc.add_element self.class::RSRC_OBJECT_KEY.to_s
|
546
546
|
gen = obj.add_element 'general'
|
547
|
+
gen.add_element('name').text = @display_name
|
547
548
|
gen.add_element('display_name').text = @display_name
|
548
549
|
gen.add_element('description').text = @description
|
549
550
|
gen.add_element('os_type').text = @os_type
|
@@ -166,7 +166,7 @@ module Jamf
|
|
166
166
|
selected: 'Currently Selected Startup Disk (No Bless)',
|
167
167
|
netboot: 'NetBoot',
|
168
168
|
os_installer: 'inPlaceOSUpgradeDirectory'
|
169
|
-
}.freeze #
|
169
|
+
}.freeze # NOTE: any other value in :specify_startup is a path to some other drive to boot from, e.g. /Volumes/Foo
|
170
170
|
|
171
171
|
ACCOUNT_ACTIONS = {
|
172
172
|
create: 'Create',
|
@@ -200,9 +200,9 @@ module Jamf
|
|
200
200
|
}.freeze
|
201
201
|
|
202
202
|
DISK_ENCRYPTION_ACTIONS = {
|
203
|
-
apply:
|
204
|
-
remediate:
|
205
|
-
none:
|
203
|
+
apply: 'apply',
|
204
|
+
remediate: 'remediate',
|
205
|
+
none: 'none'
|
206
206
|
}
|
207
207
|
|
208
208
|
PRINTER_ACTIONS = {
|
@@ -293,10 +293,19 @@ module Jamf
|
|
293
293
|
# Class Methods
|
294
294
|
######################
|
295
295
|
|
296
|
-
# Flush logs for a given policy older than
|
297
|
-
#
|
296
|
+
# Flush logs for a given policy older than a given time period.
|
297
|
+
# This flushes the logs of the given policy for all computers.
|
298
298
|
#
|
299
|
-
#
|
299
|
+
# IMPORTANT: from the Jamf Developer Site:
|
300
|
+
# The ability to flush logs is currently only supported for flushing all logs
|
301
|
+
# for a given policy or all logs for a given computer. There is no support for
|
302
|
+
# flushing logs for a given policy and computer combination.
|
303
|
+
#
|
304
|
+
# (See .flush_logs_for_computers to to flush all logs for given computers)
|
305
|
+
#
|
306
|
+
# With no parameters, flushes all logs for the policy.
|
307
|
+
#
|
308
|
+
# Without older_than: and period:, will flush all logs for the policy
|
300
309
|
#
|
301
310
|
# NOTE: Currently the API doesn't have a way to flush only failed policies.
|
302
311
|
#
|
@@ -306,52 +315,74 @@ module Jamf
|
|
306
315
|
#
|
307
316
|
# @param policy[Integer,String] The id or name of the policy to flush
|
308
317
|
#
|
309
|
-
# @param older_than[Integer] 0, 1, 2, 3, or 6
|
318
|
+
# @param older_than[Integer] 0, 1, 2, 3, or 6, defaults to 0
|
310
319
|
#
|
311
|
-
# @param period[Symbol] :days, :weeks, :months, or :years
|
312
|
-
#
|
313
|
-
# @param computers[Array<Integer,String>] Identifiers of the target computers
|
314
|
-
# either ids, names, SNs, macaddrs, or UDIDs. If omitted, flushes logs for
|
315
|
-
# all computers
|
320
|
+
# @param period[Symbol] :days, :weeks, :months, or :years, defaults to :days
|
316
321
|
#
|
317
322
|
# @param cnx [Jamf::Connection] the API connection to use.
|
318
323
|
#
|
319
324
|
# @return [void]
|
320
325
|
#
|
321
|
-
def self.flush_logs(policy, older_than: 0, period: :days,
|
326
|
+
def self.flush_logs(policy, older_than: 0, period: :days, api: nil, cnx: Jamf.cnx)
|
322
327
|
cnx = api if api
|
323
328
|
|
324
|
-
orig_timeout = cnx.timeout
|
325
329
|
pol_id = valid_id policy, cnx: cnx
|
326
330
|
raise Jamf::NoSuchItemError, "No Policy identified by '#{policy}'." unless pol_id
|
327
331
|
|
328
|
-
older_than =
|
329
|
-
raise Jamf::InvalidDataError, "older_than must be one of these integers: #{LOG_FLUSH_INTERVAL_INTEGERS.keys.join ', '}" unless older_than
|
330
|
-
|
331
|
-
period = LOG_FLUSH_INTERVAL_PERIODS[period]
|
332
|
-
raise Jamf::InvalidDataError, "period must be one of these symbols: :#{LOG_FLUSH_INTERVAL_PERIODS.keys.join ', :'}" unless period
|
333
|
-
|
334
|
-
computers = [computers] unless computers.is_a? Array
|
332
|
+
older_than, period = validate_log_flush_params(older_than, period)
|
335
333
|
|
336
334
|
# log flushes can be really slow
|
335
|
+
orig_timeout = cnx.timeout
|
337
336
|
cnx.timeout = 1800 unless orig_timeout && orig_timeout > 1800
|
338
337
|
|
339
|
-
|
340
|
-
|
341
|
-
flush_logs_for_specific_computers pol_id, older_than, period, computers, cnx
|
338
|
+
cnx.c_delete "#{LOG_FLUSH_RSRC}/policy/id/#{pol_id}/interval/#{older_than}+#{period}"
|
342
339
|
ensure
|
343
340
|
cnx.timeout = orig_timeout
|
344
341
|
end
|
345
342
|
|
346
|
-
#
|
347
|
-
#
|
348
|
-
|
343
|
+
# Flush policy logs for specific computers older than a given time period.
|
344
|
+
# This flushes the logs for all policies for these computers.
|
345
|
+
#
|
346
|
+
# IMPORTANT: from the Jamf Developer Site:
|
347
|
+
# The ability to flush logs is currently only supported for flushing all logs
|
348
|
+
# for a given policy or all logs for a given computer. There is no support for
|
349
|
+
# flushing logs for a given policy and computer combination.
|
350
|
+
#
|
351
|
+
# (See .flush_logs to to flush all logs for a given policy)
|
352
|
+
#
|
353
|
+
# Without older_than: and period:, will flush all logs for the computers
|
354
|
+
#
|
355
|
+
# NOTE: Currently the API doesn't have a way to flush only failed policies.
|
356
|
+
#
|
357
|
+
# WARNING: Log flushing can take a long time, and the API call doesnt return
|
358
|
+
# until its finished. The connection timeout will be temporarily raised to
|
359
|
+
# 30 minutes, unless it's already higher.
|
360
|
+
#
|
361
|
+
# @param computers[Array<Integer,String>] Identifiers of the target computers
|
362
|
+
# either ids, names, SNs, macaddrs, or UDIDs.
|
363
|
+
#
|
364
|
+
# @param older_than[Integer] 0, 1, 2, 3, or 6, defaults to 0
|
365
|
+
#
|
366
|
+
# @param period[Symbol] :days, :weeks, :months, or :years, defaults to :days
|
367
|
+
#
|
368
|
+
# @param cnx [Jamf::Connection] the API connection to use.
|
369
|
+
#
|
370
|
+
# @return [void]
|
371
|
+
#
|
372
|
+
def self.flush_logs_for_computers(computers = [], older_than: 0, period: :days, api: nil, cnx: Jamf.cnx)
|
373
|
+
cnx = api if api
|
374
|
+
|
375
|
+
computers = [computers] unless computers.is_a? Array
|
376
|
+
raise JSS::InvalidDataError, 'One or more computers must be specified' if computers.empty?
|
377
|
+
|
378
|
+
older_than, period = validate_log_flush_params(older_than, period)
|
379
|
+
|
349
380
|
# build the xml body for a DELETE request
|
350
381
|
xml_doc = REXML::Document.new Jamf::Connection::XML_HEADER
|
351
382
|
lf = xml_doc.add_element 'logflush'
|
352
383
|
lf.add_element('log').text = 'policy'
|
353
|
-
lf.add_element('log_id').text = pol_id.to_s
|
354
384
|
lf.add_element('interval').text = "#{older_than} #{period}"
|
385
|
+
|
355
386
|
comps_elem = lf.add_element 'computers'
|
356
387
|
computers.each do |c|
|
357
388
|
id = Jamf::Computer.valid_id c, cnx: cnx
|
@@ -361,13 +392,41 @@ module Jamf
|
|
361
392
|
ce.add_element('id').text = id.to_s
|
362
393
|
end
|
363
394
|
|
395
|
+
# for debugging the xml...
|
396
|
+
#
|
397
|
+
# formatter = REXML::Formatters::Pretty.new(2)
|
398
|
+
# formatter.compact = true
|
399
|
+
# formatter.write(xml_doc, $stdout)
|
400
|
+
# puts
|
401
|
+
# return
|
402
|
+
|
403
|
+
# log flushes can be really slow
|
404
|
+
orig_timeout = cnx.timeout
|
405
|
+
cnx.timeout = 1800 unless orig_timeout && orig_timeout > 1800
|
406
|
+
|
364
407
|
# Do a DELETE request with a body.
|
365
|
-
cnx.delete(LOG_FLUSH_RSRC) do |req|
|
408
|
+
resp = cnx.c_cnx.delete(LOG_FLUSH_RSRC) do |req|
|
366
409
|
req.headers[Jamf::Connection::HTTP_CONTENT_TYPE_HEADER] = Jamf::Connection::MIME_XML
|
367
410
|
req.body = xml_doc.to_s
|
368
411
|
end
|
412
|
+
|
413
|
+
resp.body
|
414
|
+
ensure
|
415
|
+
cnx.timeout = orig_timeout
|
369
416
|
end
|
370
|
-
|
417
|
+
|
418
|
+
# validate the logflush params
|
419
|
+
# @return [Array<String>]
|
420
|
+
def self.validate_log_flush_params(older_than, period)
|
421
|
+
older_than = LOG_FLUSH_INTERVAL_INTEGERS[older_than]
|
422
|
+
raise Jamf::InvalidDataError, "older_than must be one of these integers: #{LOG_FLUSH_INTERVAL_INTEGERS.keys.join ', '}" unless older_than
|
423
|
+
|
424
|
+
period = LOG_FLUSH_INTERVAL_PERIODS[period]
|
425
|
+
raise Jamf::InvalidDataError, "period must be one of these symbols: :#{LOG_FLUSH_INTERVAL_PERIODS.keys.join ', :'}" unless period
|
426
|
+
|
427
|
+
[older_than, period]
|
428
|
+
end
|
429
|
+
private_class_method :validate_log_flush_params
|
371
430
|
|
372
431
|
# Attributes
|
373
432
|
######################
|
@@ -751,7 +810,7 @@ module Jamf
|
|
751
810
|
@management_account = amaint[:management_account]
|
752
811
|
@accounts = amaint[:accounts]
|
753
812
|
|
754
|
-
@packages = @init_data[:package_configuration][:packages]
|
813
|
+
@packages = @init_data[:package_configuration][:packages] || []
|
755
814
|
|
756
815
|
@scripts = @init_data[:scripts]
|
757
816
|
|
@@ -815,6 +874,7 @@ module Jamf
|
|
815
874
|
#
|
816
875
|
def enabled=(new_val)
|
817
876
|
return if @enabled == new_val
|
877
|
+
|
818
878
|
@enabled = Jamf::Validate.boolean new_val
|
819
879
|
@need_to_update = true
|
820
880
|
end
|
@@ -868,9 +928,7 @@ module Jamf
|
|
868
928
|
|
869
929
|
# if the event is not 'none' and attempts is <= 0,
|
870
930
|
# set events to 1, or the API won't accept it
|
871
|
-
|
872
|
-
@retry_attempts = 1 unless @retry_attempts.positive?
|
873
|
-
end
|
931
|
+
@retry_attempts = 1 if !(evt == RETRY_EVENTS[:none]) && !@retry_attempts.positive?
|
874
932
|
|
875
933
|
@retry_event = evt
|
876
934
|
@need_to_update = true
|
@@ -934,6 +992,7 @@ module Jamf
|
|
934
992
|
#
|
935
993
|
def target_drive=(path_to_drive)
|
936
994
|
raise Jamf::InvalidDataError, 'Path to target drive must be absolute' unless path_to_drive.to_s.start_with? '/'
|
995
|
+
|
937
996
|
@target_drive = path_to_drive.to_s
|
938
997
|
@need_to_update = true
|
939
998
|
end
|
@@ -946,6 +1005,7 @@ module Jamf
|
|
946
1005
|
#
|
947
1006
|
def offline=(new_val)
|
948
1007
|
raise Jamf::InvalidDataError, 'New value must be boolean true or false' unless Jamf::TRUE_FALSE.include? new_val
|
1008
|
+
|
949
1009
|
@offline = new_val
|
950
1010
|
@need_to_update = true
|
951
1011
|
end
|
@@ -960,6 +1020,7 @@ module Jamf
|
|
960
1020
|
#
|
961
1021
|
def set_trigger_event(type, new_val)
|
962
1022
|
raise Jamf::InvalidDataError, "Trigger type must be one of #{TRIGGER_EVENTS.keys.join(', ')}" unless TRIGGER_EVENTS.key?(type)
|
1023
|
+
|
963
1024
|
if type == :custom
|
964
1025
|
raise Jamf::InvalidDataError, 'Custom triggers must be Strings' unless new_val.is_a? String
|
965
1026
|
else
|
@@ -977,6 +1038,7 @@ module Jamf
|
|
977
1038
|
#
|
978
1039
|
def server_side_activation=(activation)
|
979
1040
|
raise Jamf::InvalidDataError, 'Activation must be a Time' unless activation.is_a? Time
|
1041
|
+
|
980
1042
|
@server_side_limitations[:activation] = activation
|
981
1043
|
@need_to_update = true
|
982
1044
|
end
|
@@ -989,6 +1051,7 @@ module Jamf
|
|
989
1051
|
#
|
990
1052
|
def server_side_expiration=(expiration)
|
991
1053
|
raise Jamf::InvalidDataError, 'Expiration must be a Time' unless expiration.is_a? Time
|
1054
|
+
|
992
1055
|
@server_side_limitations[:expiration] = expiration
|
993
1056
|
@need_to_update = true
|
994
1057
|
end
|
@@ -999,6 +1062,7 @@ module Jamf
|
|
999
1062
|
#
|
1000
1063
|
def verify_startup_disk=(bool)
|
1001
1064
|
return if @verify_startup_disk == bool
|
1065
|
+
|
1002
1066
|
@verify_startup_disk = Jamf::Validate.boolean bool
|
1003
1067
|
@need_to_update = true
|
1004
1068
|
end
|
@@ -1007,6 +1071,7 @@ module Jamf
|
|
1007
1071
|
#
|
1008
1072
|
def permissions_repair=(bool)
|
1009
1073
|
return if @permissions_repair == bool
|
1074
|
+
|
1010
1075
|
@permissions_repair = Jamf::Validate.boolean bool
|
1011
1076
|
@need_to_update = true
|
1012
1077
|
end
|
@@ -1015,6 +1080,7 @@ module Jamf
|
|
1015
1080
|
#
|
1016
1081
|
def recon=(bool)
|
1017
1082
|
return if @recon == bool
|
1083
|
+
|
1018
1084
|
@recon = Jamf::Validate.boolean bool
|
1019
1085
|
@need_to_update = true
|
1020
1086
|
end
|
@@ -1024,6 +1090,7 @@ module Jamf
|
|
1024
1090
|
#
|
1025
1091
|
def fix_byhost=(bool)
|
1026
1092
|
return if @fix_byhost == bool
|
1093
|
+
|
1027
1094
|
@fix_byhost = Jamf::Validate.boolean bool
|
1028
1095
|
@need_to_update = true
|
1029
1096
|
end
|
@@ -1032,6 +1099,7 @@ module Jamf
|
|
1032
1099
|
#
|
1033
1100
|
def reset_name=(bool)
|
1034
1101
|
return if @reset_name == bool
|
1102
|
+
|
1035
1103
|
@reset_name = Jamf::Validate.boolean bool
|
1036
1104
|
@need_to_update = true
|
1037
1105
|
end
|
@@ -1040,6 +1108,7 @@ module Jamf
|
|
1040
1108
|
#
|
1041
1109
|
def flush_system_cache=(bool)
|
1042
1110
|
return if @flush_system_cache == bool
|
1111
|
+
|
1043
1112
|
@flush_system_cache = Jamf::Validate.boolean bool
|
1044
1113
|
@need_to_update = true
|
1045
1114
|
end # see attr_reader :recon
|
@@ -1048,6 +1117,7 @@ module Jamf
|
|
1048
1117
|
#
|
1049
1118
|
def install_cached_pkgs=(bool)
|
1050
1119
|
return if @install_cached_pkgs == bool
|
1120
|
+
|
1051
1121
|
@install_cached_pkgs = Jamf::Validate.boolean bool
|
1052
1122
|
@need_to_update = true
|
1053
1123
|
end
|
@@ -1056,6 +1126,7 @@ module Jamf
|
|
1056
1126
|
#
|
1057
1127
|
def flush_user_cache=(bool)
|
1058
1128
|
return if @flush_user_cache == bool
|
1129
|
+
|
1059
1130
|
@flush_user_cache = Jamf::Validate.boolean bool
|
1060
1131
|
@need_to_update = true
|
1061
1132
|
end
|
@@ -1071,6 +1142,7 @@ module Jamf
|
|
1071
1142
|
#
|
1072
1143
|
def no_user_logged_in=(no_user_option)
|
1073
1144
|
raise Jamf::InvalidDataError, "no_user_logged_in options: #{NO_USER_LOGGED_IN.join(', ')}" unless NO_USER_LOGGED_IN.include? no_user_option
|
1145
|
+
|
1074
1146
|
@reboot_options[:no_user_logged_in] = no_user_option
|
1075
1147
|
@need_to_update = true
|
1076
1148
|
end
|
@@ -1083,6 +1155,7 @@ module Jamf
|
|
1083
1155
|
#
|
1084
1156
|
def user_logged_in=(logged_in_option)
|
1085
1157
|
raise Jamf::InvalidDataError, "user_logged_in options: #{USER_LOGGED_IN.join(', ')}" unless USER_LOGGED_IN.include? logged_in_option
|
1158
|
+
|
1086
1159
|
@reboot_options[:user_logged_in] = logged_in_option
|
1087
1160
|
@need_to_update = true
|
1088
1161
|
end
|
@@ -1095,6 +1168,7 @@ module Jamf
|
|
1095
1168
|
#
|
1096
1169
|
def reboot_message=(message)
|
1097
1170
|
raise Jamf::InvalidDataError, 'Reboot message must be a String' unless message.is_a? String
|
1171
|
+
|
1098
1172
|
@reboot_options[:message] = message
|
1099
1173
|
@need_to_update = true
|
1100
1174
|
end
|
@@ -1107,6 +1181,7 @@ module Jamf
|
|
1107
1181
|
# @return [void] description of returned object
|
1108
1182
|
def user_message_start=(message)
|
1109
1183
|
raise Jamf::InvalidDataError, 'User message must be a String' unless message.is_a? String
|
1184
|
+
|
1110
1185
|
@user_message_start = message
|
1111
1186
|
@need_to_update = true
|
1112
1187
|
end
|
@@ -1118,6 +1193,7 @@ module Jamf
|
|
1118
1193
|
# @return [void] description of returned object
|
1119
1194
|
def user_message_end=(message)
|
1120
1195
|
raise Jamf::InvalidDataError, 'User message must be a String' unless message.is_a? String
|
1196
|
+
|
1121
1197
|
@user_message_finish = message
|
1122
1198
|
@need_to_update = true
|
1123
1199
|
end
|
@@ -1133,6 +1209,7 @@ module Jamf
|
|
1133
1209
|
#
|
1134
1210
|
def startup_disk=(startup_disk_option)
|
1135
1211
|
raise Jamf::InvalidDataError, "#{startup_disk_option} is not a valid Startup Disk" unless startup_disk_option.is_a? String
|
1212
|
+
|
1136
1213
|
@reboot_options[:startup_disk] = 'Specify Local Startup Disk'
|
1137
1214
|
self.specify_startup = startup_disk_option
|
1138
1215
|
@need_to_update = true
|
@@ -1147,6 +1224,7 @@ module Jamf
|
|
1147
1224
|
#
|
1148
1225
|
def specify_startup=(startup_volume)
|
1149
1226
|
raise Jamf::InvalidDataError, "#{startup_volume} is not a valid Startup Disk" unless startup_volume.is_a? String
|
1227
|
+
|
1150
1228
|
@reboot_options[:specify_startup] = startup_volume
|
1151
1229
|
@need_to_update = true
|
1152
1230
|
end
|
@@ -1172,6 +1250,7 @@ module Jamf
|
|
1172
1250
|
#
|
1173
1251
|
def minutes_until_reboot=(minutes)
|
1174
1252
|
raise Jamf::InvalidDataError, 'Minutes until reboot must be an Integer' unless minutes.is_a? Integer
|
1253
|
+
|
1175
1254
|
@reboot_options[:minutes_until_reboot] = minutes
|
1176
1255
|
@need_to_update = true
|
1177
1256
|
end
|
@@ -1185,6 +1264,7 @@ module Jamf
|
|
1185
1264
|
#
|
1186
1265
|
def file_vault_2_reboot=(fv_bool)
|
1187
1266
|
raise Jamf::InvalidDataError, 'FileVault 2 Reboot must be a Boolean' unless fv_bool.jss_boolean?
|
1267
|
+
|
1188
1268
|
@reboot_options[:file_vault_2_reboot] = fv_bool
|
1189
1269
|
@need_to_update = true
|
1190
1270
|
end
|
@@ -1206,6 +1286,7 @@ module Jamf
|
|
1206
1286
|
#
|
1207
1287
|
def run_command=(command)
|
1208
1288
|
raise Jamf::InvalidDataError, 'Command to run must be a String' unless command.is_a? String
|
1289
|
+
|
1209
1290
|
@files_processes[:run_command] = command
|
1210
1291
|
@need_to_update = true
|
1211
1292
|
end
|
@@ -1262,7 +1343,7 @@ module Jamf
|
|
1262
1343
|
#
|
1263
1344
|
def search_by_path
|
1264
1345
|
if @files_processes[:search_by_path].nil?
|
1265
|
-
|
1346
|
+
nil
|
1266
1347
|
else
|
1267
1348
|
Pathname.new @files_processes[:search_by_path]
|
1268
1349
|
end
|
@@ -1289,6 +1370,7 @@ module Jamf
|
|
1289
1370
|
#
|
1290
1371
|
def set_search_by_path(path, delete = false)
|
1291
1372
|
raise Jamf::InvalidDataError, 'Path to search for must be a String or a Pathname' unless path.is_a?(String) || path.is_a?(Pathname)
|
1373
|
+
|
1292
1374
|
@files_processes[:search_by_path] = path.to_s
|
1293
1375
|
@files_processes[:delete_file] = delete ? true : false
|
1294
1376
|
@need_to_update = true
|
@@ -1308,6 +1390,7 @@ module Jamf
|
|
1308
1390
|
#
|
1309
1391
|
def spotlight_search=(term)
|
1310
1392
|
raise Jamf::InvalidDataError, 'Spotlight search term must be a String' unless term.is_a? String
|
1393
|
+
|
1311
1394
|
@files_processes[:spotlight_search] = term
|
1312
1395
|
@need_to_update = true
|
1313
1396
|
end
|
@@ -1326,6 +1409,7 @@ module Jamf
|
|
1326
1409
|
#
|
1327
1410
|
def locate_file=(term)
|
1328
1411
|
raise Jamf::InvalidDataError, 'Term to locate must be a String' unless term.is_a? String
|
1412
|
+
|
1329
1413
|
@files_processes[:locate_file] = term
|
1330
1414
|
@need_to_update = true
|
1331
1415
|
end
|
@@ -1571,7 +1655,6 @@ module Jamf
|
|
1571
1655
|
@directory_bindings
|
1572
1656
|
end
|
1573
1657
|
|
1574
|
-
|
1575
1658
|
# Remove a directory binding from this policy by name or id
|
1576
1659
|
#
|
1577
1660
|
# @param identifier [String,Integer] the name or id of the directory binding to remove
|
@@ -1596,7 +1679,6 @@ module Jamf
|
|
1596
1679
|
@dock_items.map { |p| p[:name] }
|
1597
1680
|
end
|
1598
1681
|
|
1599
|
-
|
1600
1682
|
###### Printers
|
1601
1683
|
|
1602
1684
|
# Add a specific printer object to the policy.
|
@@ -1661,7 +1743,7 @@ module Jamf
|
|
1661
1743
|
|
1662
1744
|
name = Jamf::DockItem.map_all_ids_to(:name, cnx: @cnx)[id]
|
1663
1745
|
|
1664
|
-
@dock_items << {id: id, name: name, action: DOCK_ITEM_ACTIONS[action]}
|
1746
|
+
@dock_items << { id: id, name: name, action: DOCK_ITEM_ACTIONS[action] }
|
1665
1747
|
|
1666
1748
|
@need_to_update = true
|
1667
1749
|
@dock_items
|
@@ -1677,24 +1759,18 @@ module Jamf
|
|
1677
1759
|
|
1678
1760
|
# @return [Array] the id's of the printers handled by the policy
|
1679
1761
|
def printer_ids
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
1683
|
-
return []
|
1684
|
-
end
|
1762
|
+
@printers.map { |p| p[:id] }
|
1763
|
+
rescue TypeError
|
1764
|
+
[]
|
1685
1765
|
end
|
1686
1766
|
|
1687
1767
|
# @return [Array] the names of the printers handled by the policy
|
1688
1768
|
def printer_names
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
1692
|
-
return []
|
1693
|
-
end
|
1769
|
+
@printers.map { |p| p[:name] }
|
1770
|
+
rescue TypeError
|
1771
|
+
[]
|
1694
1772
|
end
|
1695
1773
|
|
1696
|
-
|
1697
|
-
|
1698
1774
|
###### Disk Encryption
|
1699
1775
|
|
1700
1776
|
# Sets the Disk Encryption application to "Remediate" and sets the remediation key type to individual.
|
@@ -1703,12 +1779,12 @@ module Jamf
|
|
1703
1779
|
#
|
1704
1780
|
# @return [Void]
|
1705
1781
|
#
|
1706
|
-
def reissue_key
|
1782
|
+
def reissue_key
|
1707
1783
|
if @disk_encryption[:action] != DISK_ENCRYPTION_ACTIONS[:remediate]
|
1708
1784
|
# Setting New Action
|
1709
1785
|
hash = {
|
1710
1786
|
action: DISK_ENCRYPTION_ACTIONS[:remediate],
|
1711
|
-
remediate_key_type:
|
1787
|
+
remediate_key_type: 'Individual'
|
1712
1788
|
}
|
1713
1789
|
|
1714
1790
|
@disk_encryption = hash
|
@@ -1716,12 +1792,10 @@ module Jamf
|
|
1716
1792
|
|
1717
1793
|
else
|
1718
1794
|
# Update
|
1719
|
-
|
1795
|
+
nil
|
1720
1796
|
end
|
1721
|
-
|
1722
1797
|
end
|
1723
1798
|
|
1724
|
-
|
1725
1799
|
# Sets the Disk Encryption application to "Apply" and sets the correct disk encryption configuration ID using either the name or id.
|
1726
1800
|
#
|
1727
1801
|
# @author Tyler Morgan
|
@@ -1729,7 +1803,6 @@ module Jamf
|
|
1729
1803
|
# @return [Void]
|
1730
1804
|
#
|
1731
1805
|
def apply_encryption_configuration(identifier)
|
1732
|
-
|
1733
1806
|
id = Jamf::DiskEncryptionConfiguration.valid_id identifier
|
1734
1807
|
|
1735
1808
|
return if id.nil?
|
@@ -1744,14 +1817,13 @@ module Jamf
|
|
1744
1817
|
@need_to_update = true
|
1745
1818
|
end
|
1746
1819
|
|
1747
|
-
|
1748
1820
|
# Removes the Disk Encryption settings associated with this specific policy.
|
1749
1821
|
#
|
1750
1822
|
# @author Tyler Morgan
|
1751
1823
|
#
|
1752
1824
|
# @return [Void]
|
1753
1825
|
#
|
1754
|
-
def remove_encryption_configuration
|
1826
|
+
def remove_encryption_configuration
|
1755
1827
|
hash = {
|
1756
1828
|
action: DISK_ENCRYPTION_ACTIONS[:none]
|
1757
1829
|
}
|
@@ -1774,16 +1846,16 @@ module Jamf
|
|
1774
1846
|
|
1775
1847
|
management_data = {}
|
1776
1848
|
|
1777
|
-
if
|
1778
|
-
raise Jamf::MissingDataError,
|
1849
|
+
if %i[change_pw reset_pw].include?(action)
|
1850
|
+
raise Jamf::MissingDataError, ':password must be provided when changing management account password' if opts[:password].nil?
|
1779
1851
|
|
1780
1852
|
management_data = {
|
1781
1853
|
action: MGMT_ACCOUNT_ACTIONS[action],
|
1782
1854
|
managed_password: opts[:password]
|
1783
1855
|
}
|
1784
|
-
elsif
|
1785
|
-
raise Jamf::MissingDataError,
|
1786
|
-
raise Jamf::InvalidDataError,
|
1856
|
+
elsif %i[reset_random generate_pw].include?(action)
|
1857
|
+
raise Jamf::MissingDataError, ':password_length must be provided when setting a random password' if opts[:password_length].nil?
|
1858
|
+
raise Jamf::InvalidDataError, ':password_length must be an Integer' unless opts[:password_length].is_a? Integer
|
1787
1859
|
|
1788
1860
|
management_data = {
|
1789
1861
|
action: MGMT_ACCOUNT_ACTIONS[action],
|
@@ -1800,21 +1872,23 @@ module Jamf
|
|
1800
1872
|
@need_to_update = true
|
1801
1873
|
|
1802
1874
|
@management_account
|
1803
|
-
|
1804
1875
|
end
|
1805
1876
|
|
1806
|
-
#
|
1877
|
+
# @deprecated The API no longer sends SHA256 hashed password data, and instead
|
1878
|
+
# only has a string of asterisks, meaning we can no longer use it to validate
|
1879
|
+
# passwords before attempting to use them. Instead, the processes that use
|
1880
|
+
# the password will fail on their own if the pw is not valid.
|
1807
1881
|
#
|
1808
|
-
#
|
1882
|
+
# This method remains defined for backward-compatibility with any existing
|
1883
|
+
# code that calls it. but it will always return true. Itwill be removed in
|
1884
|
+
# a future version
|
1809
1885
|
#
|
1810
|
-
# @
|
1886
|
+
# @param password[String] ignored
|
1811
1887
|
#
|
1812
|
-
|
1813
|
-
|
1814
|
-
|
1815
|
-
|
1816
|
-
|
1817
|
-
return Digest::SHA256.hexdigest(password).to_s == @management_account[:managed_password_sha256].to_s
|
1888
|
+
# @return [TrueClass] Allow the process calling this to continue.
|
1889
|
+
#
|
1890
|
+
def verify_management_password(_password = nil)
|
1891
|
+
true
|
1818
1892
|
end
|
1819
1893
|
|
1820
1894
|
###### Actions
|
@@ -1829,17 +1903,22 @@ module Jamf
|
|
1829
1903
|
#
|
1830
1904
|
def run(show_output = false)
|
1831
1905
|
return nil unless enabled?
|
1906
|
+
|
1832
1907
|
output = Jamf::Client.run_jamf('policy', "-id #{id}", show_output)
|
1833
1908
|
return nil if output.include? 'No policies were found for the ID'
|
1909
|
+
|
1834
1910
|
$CHILD_STATUS.exitstatus.zero? ? true : false
|
1835
1911
|
end
|
1836
1912
|
alias execute run
|
1837
1913
|
|
1838
|
-
# Flush logs for this policy older than
|
1839
|
-
#
|
1840
|
-
#
|
1914
|
+
# Flush logs for this policy older than a given time period.
|
1915
|
+
#
|
1916
|
+
# IMPORTANT: from the Jamf Developer Site:
|
1917
|
+
# The ability to flush logs is currently only supported for flushing all logs
|
1918
|
+
# for a given policy or all logs for a given computer. There is no support for
|
1919
|
+
# flushing logs for a given policy and computer combination.
|
1841
1920
|
#
|
1842
|
-
# With no parameters,
|
1921
|
+
# With no parameters, will flush all logs for the policy
|
1843
1922
|
#
|
1844
1923
|
# NOTE: Currently the API doesn't have a way to flush only failed policies.
|
1845
1924
|
#
|
@@ -1851,19 +1930,16 @@ module Jamf
|
|
1851
1930
|
#
|
1852
1931
|
# @param period[Symbol] :days, :weeks, :months, or :years
|
1853
1932
|
#
|
1854
|
-
# @param computers[Array<Integer,String>] Identifiers of the target computers
|
1855
|
-
# either ids, names, SNs, macaddrs, or UDIDs
|
1856
|
-
#
|
1857
1933
|
# @return [void]
|
1858
1934
|
#
|
1859
|
-
def flush_logs(older_than: 0, period: :days
|
1860
|
-
raise Jamf::NoSuchItemError, "Policy doesn't exist in the JSS. Use #
|
1935
|
+
def flush_logs(older_than: 0, period: :days)
|
1936
|
+
raise Jamf::NoSuchItemError, "Policy doesn't exist in the JSS. Use #save first." unless @in_jss
|
1861
1937
|
|
1862
1938
|
Jamf::Policy.flush_logs(
|
1863
1939
|
@id,
|
1864
1940
|
older_than: older_than,
|
1865
1941
|
period: period,
|
1866
|
-
|
1942
|
+
cnx: @cnx
|
1867
1943
|
)
|
1868
1944
|
end
|
1869
1945
|
|
@@ -1944,6 +2020,7 @@ module Jamf
|
|
1944
2020
|
|
1945
2021
|
id = Jamf::Script.valid_id identifier, cnx: @cnx
|
1946
2022
|
raise Jamf::NoSuchItemError, "No script matches '#{identifier}'" unless id
|
2023
|
+
|
1947
2024
|
id
|
1948
2025
|
end
|
1949
2026
|
|
@@ -1963,12 +2040,13 @@ module Jamf
|
|
1963
2040
|
else Jamf::Validate.integer(opts[:position])
|
1964
2041
|
end
|
1965
2042
|
|
1966
|
-
|
1967
|
-
|
2043
|
+
# if the given position is past the end, set it to -1 (the end)
|
2044
|
+
opts[:position] = -1 if opts[:position] > @directory_bindings.size
|
2045
|
+
|
2046
|
+
id = Jamf::DirectoryBinding.valid_id identifier, cnx: @cnx
|
2047
|
+
raise Jamf::NoSuchItemError, "No directory binding matches '#{identifier}'" unless id
|
1968
2048
|
|
1969
|
-
|
1970
|
-
raise Jamf::NoSuchItemError, "No directory binding matches '#{identifier}'" unless id
|
1971
|
-
id
|
2049
|
+
id
|
1972
2050
|
end
|
1973
2051
|
|
1974
2052
|
# Raises an error if the printer being added isn't valid, additionally checks the options and sets defaults where possible.
|
@@ -1994,14 +2072,17 @@ module Jamf
|
|
1994
2072
|
raise Jamf::MissingDataError, "action must be provided, must be one of :#{PRINTER_ACTIONS.keys.join(':,')}." if opts[:action].nil?
|
1995
2073
|
raise Jamf::InvalidDataError, "action must be one of :#{PRINTER_ACTIONS.keys.join(',:')}." unless PRINTER_ACTIONS.keys.include? opts[:action]
|
1996
2074
|
|
1997
|
-
|
1998
2075
|
# Checks if the make_default option is valid, and sets the default if needed.
|
1999
|
-
|
2076
|
+
unless opts[:make_default].is_a?(TrueClass) || opts[:make_default].is_a?(FalseClass) || opts[:make_default].nil?
|
2077
|
+
raise Jamf::InvalidDataError,
|
2078
|
+
'make_default must be either true or false.'
|
2079
|
+
end
|
2000
2080
|
|
2001
2081
|
opts[:make_default] = false if opts[:make_default].nil?
|
2002
2082
|
|
2003
2083
|
id = Jamf::Printer.valid_id identifier, cnx: @cnx
|
2004
2084
|
raise Jamf::NoSuchItemError, "No printer matches '#{identifier}'" unless id
|
2085
|
+
|
2005
2086
|
id
|
2006
2087
|
end
|
2007
2088
|
|
@@ -2081,7 +2162,7 @@ module Jamf
|
|
2081
2162
|
|
2082
2163
|
disk_encryption = obj.add_element 'disk_encryption'
|
2083
2164
|
|
2084
|
-
@disk_encryption.each do |k,v|
|
2165
|
+
@disk_encryption.each do |k, v|
|
2085
2166
|
disk_encryption.add_element(k.to_s).text = v.to_s
|
2086
2167
|
end
|
2087
2168
|
|
@@ -476,7 +476,10 @@ module Jamf
|
|
476
476
|
item_id = validate_item(:target, key, item)
|
477
477
|
return if @targets[key]&.include?(item_id)
|
478
478
|
|
479
|
-
|
479
|
+
if @exclusions[key]&.include?(item_id)
|
480
|
+
raise Jamf::AlreadyExistsError,
|
481
|
+
"Can't set #{key} target to '#{item}' because it's already an explicit exclusion."
|
482
|
+
end
|
480
483
|
|
481
484
|
@targets[key] << item_id
|
482
485
|
@all_targets = false
|
@@ -775,7 +778,7 @@ module Jamf
|
|
775
778
|
################
|
776
779
|
def scoped_machines
|
777
780
|
scoped_machines = {}
|
778
|
-
@target_class.all_objects(cnx: container.cnx).each do |machine|
|
781
|
+
@target_class.all_objects(:refresh, cnx: container.cnx).each do |machine|
|
779
782
|
scoped_machines[machine.id] = machine.name if in_scope? machine
|
780
783
|
end
|
781
784
|
scoped_machines
|
@@ -19,14 +19,14 @@
|
|
19
19
|
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
20
20
|
# KIND, either express or implied. See the Apache License for the specific
|
21
21
|
# language governing permissions and limitations under the Apache License.
|
22
|
-
|
23
|
-
#
|
22
|
+
|
23
|
+
# frozen_string_literal: true
|
24
24
|
|
25
25
|
module Jamf
|
26
26
|
|
27
27
|
# This module should be mixed in to Jamf::Computer and Jamf::ComputerGroup
|
28
28
|
#
|
29
|
-
# It provides access to the macos-managed-software-updates JPAPI resource for
|
29
|
+
# It provides access to the macos-managed-software-updates JPAPI resource for
|
30
30
|
# managed OS update commands to managed macs running Big Sur or higher.
|
31
31
|
#
|
32
32
|
module MacOSManagedUpdates
|
@@ -37,7 +37,7 @@ module Jamf
|
|
37
37
|
includer.extend(ClassMethods)
|
38
38
|
end
|
39
39
|
|
40
|
-
# These resources in the Jamf Pro API can be used to send Managed macOS
|
40
|
+
# These resources in the Jamf Pro API can be used to send Managed macOS
|
41
41
|
# updates to clients running Big Sur or higher
|
42
42
|
MANAGED_SW_UPDATES_RSRC = 'v1/macos-managed-software-updates'
|
43
43
|
|
@@ -45,7 +45,7 @@ module Jamf
|
|
45
45
|
MANAGED_SW_UPDATES_AVAILABLE_VERSIONS_RSRC = "#{MANAGED_SW_UPDATES_RSRC}/available-updates"
|
46
46
|
|
47
47
|
# POSTing JSON data to this resource will send the MDM commands to install os updates
|
48
|
-
# For details about the data to send, see
|
48
|
+
# For details about the data to send, see
|
49
49
|
# https://developer.jamf.com/jamf-pro/reference/post_v1-macos-managed-software-updates-send-updates
|
50
50
|
MANAGED_SW_UPDATES_SEND_UPDATES_RSRC = "#{MANAGED_SW_UPDATES_RSRC}/send-updates"
|
51
51
|
|
@@ -53,6 +53,12 @@ module Jamf
|
|
53
53
|
DOWNLOAD_AND_INSTALL = 'DOWNLOAD_AND_INSTALL'
|
54
54
|
DOWNLOAD_ONLY = 'DOWNLOAD_ONLY'
|
55
55
|
|
56
|
+
# for easier use of these values as the updateAction
|
57
|
+
UPDATE_ACTIONS = {
|
58
|
+
install: DOWNLOAD_AND_INSTALL,
|
59
|
+
download: DOWNLOAD_ONLY
|
60
|
+
}
|
61
|
+
|
56
62
|
# Class Methods
|
57
63
|
#####################################
|
58
64
|
module ClassMethods
|
@@ -73,48 +79,52 @@ module Jamf
|
|
73
79
|
|
74
80
|
# Send the os update command to target Computers or a ComputerGroup
|
75
81
|
#
|
76
|
-
# @param updateAction [
|
82
|
+
# @param updateAction [Symbol] Required. Use :install to send the
|
83
|
+
# DOWNLOAD_AND_INSTALL action, or :download to send DOWNLOAD_ONLY
|
77
84
|
#
|
78
|
-
# @param deviceIds [String, Integer, Array<String, Integer>] Identifiers for the
|
85
|
+
# @param deviceIds [String, Integer, Array<String, Integer>] Identifiers for the
|
79
86
|
# computer targets. Required if no groupId is given.
|
80
87
|
#
|
81
88
|
# @param groupId [String, Integer] Identifier for the computer group target.
|
82
|
-
# Requied if no
|
89
|
+
# Requied if no deviceIds are given.
|
83
90
|
#
|
84
|
-
# @param maxDeferrals [Integer] Allow users to defer the update the provided number
|
85
|
-
# of times before macOS forces the update. If a value is provided, the Software
|
86
|
-
# Update will use the InstallLater install action. MaxDeferral is ignored if using the
|
87
|
-
#
|
91
|
+
# @param maxDeferrals [Integer] Allow users to defer the update the provided number
|
92
|
+
# of times before macOS forces the update. If a value is provided, the Software
|
93
|
+
# Update will use the InstallLater install action. MaxDeferral is ignored if using the
|
94
|
+
# :download updateAction.
|
88
95
|
#
|
89
|
-
# @param version [String] The OS version to install. If no value is provided, the
|
96
|
+
# @param version [String] The OS version to install. If no value is provided, the
|
90
97
|
# version will default to latest version based on device eligibility.
|
91
98
|
#
|
92
99
|
# @param skipVersionVerification [Boolean] Should the specified version be installed
|
93
100
|
# even it it isn't applicable to this machine? If no value is provided, will default to false.
|
94
|
-
# If true, the specified version will be forced to complete
|
95
|
-
# install action.
|
101
|
+
# If true, the specified version will be forced to complete the :install updateAction.
|
96
102
|
#
|
97
103
|
# @param applyMajorUpdate [Boolean] Available only when updating to the latest version
|
98
104
|
# based on device eligibility. Defaults to false. If false the calculated latest version
|
99
105
|
# will only include minor version updates. If a value is provided, the calculated latest
|
100
106
|
# version will include minor and major version updates.
|
101
107
|
#
|
102
|
-
# @param forceRestart [Boolean] Will default to false. Can only be true if updateAction
|
103
|
-
# is
|
104
|
-
# If true, the DownloadAndInstall action is performed, a restart will be forced.
|
105
|
-
# MaxDeferral will be ignored if true.
|
108
|
+
# @param forceRestart [Boolean] Will default to false. Can only be true if updateAction
|
109
|
+
# is :install and the target devices are on macOs 11 or higher.
|
110
|
+
# If true, the DownloadAndInstall action is performed, a restart will be forced.
|
111
|
+
# MaxDeferral will be ignored if true.
|
106
112
|
#
|
107
|
-
# @param cnx [Jamf::Connection] The API connection to use. Defaults to Jamf.cnx
|
113
|
+
# @param cnx [Jamf::Connection] The API connection to use. Defaults to Jamf.cnx
|
108
114
|
#
|
109
|
-
# @return [Jamf::OAPISchemas::MacOsManagedSoftwareUpdateResponse]
|
115
|
+
# @return [Jamf::OAPISchemas::MacOsManagedSoftwareUpdateResponse]
|
110
116
|
########################
|
111
117
|
def send_managed_os_update(updateAction:, deviceIds: nil, groupId: nil, maxDeferrals: nil, version: nil, skipVersionVerification: false, applyMajorUpdate: false, forceRestart: false, cnx: Jamf.cnx)
|
112
|
-
|
118
|
+
action_to_send = UPDATE_ACTIONS.value?(updateAction) ? updateAction : UPDATE_ACTIONS[updateAction]
|
119
|
+
|
120
|
+
raise ArgumentError, "Unknown updateAction, must be one of: #{UPDATE_ACTIONS.keys.join ', '}" unless action_to_send
|
121
|
+
|
122
|
+
if self == Jamf::Computer
|
113
123
|
raise ArgumentError, 'Must provide one or more deviceIds' unless deviceIds
|
114
124
|
elsif self == Jamf::ComputerGroup
|
115
125
|
raise ArgumentError, 'Must provide a groupId' unless groupId
|
116
126
|
else
|
117
|
-
raise Jamf::UnsupportedError, 'This method is only available for Jamf::Computer and Jamf::ComputerGroup'
|
127
|
+
raise Jamf::UnsupportedError, 'This method is only available for Jamf::Computer and Jamf::ComputerGroup'
|
118
128
|
end
|
119
129
|
|
120
130
|
if version
|
@@ -124,9 +134,9 @@ module Jamf
|
|
124
134
|
|
125
135
|
if deviceIds
|
126
136
|
deviceIds = [deviceIds] unless deviceIds.is_a?(Array)
|
127
|
-
deviceIds.map! { |id| valid_id id }
|
137
|
+
deviceIds.map! { |id| valid_id id, cnx: cnx }
|
128
138
|
end
|
129
|
-
groupId = valid_id
|
139
|
+
groupId = valid_id(groupId, cnx: cnx) if groupId
|
130
140
|
|
131
141
|
data = {}
|
132
142
|
# ids in the JPAPI are string containing integers
|
@@ -137,11 +147,11 @@ module Jamf
|
|
137
147
|
data[:version] = version if version
|
138
148
|
data[:skipVersionVerification] = skipVersionVerification if skipVersionVerification
|
139
149
|
data[:applyMajorUpdate] = applyMajorUpdate if applyMajorUpdate
|
140
|
-
data[:updateAction] =
|
141
|
-
data[:forceRestart] = forceRestart if forceRestart
|
142
|
-
|
150
|
+
data[:updateAction] = action_to_send
|
151
|
+
data[:forceRestart] = forceRestart if forceRestart
|
152
|
+
|
143
153
|
payload = Jamf::OAPISchemas::MacOsManagedSoftwareUpdate.new(data).to_json
|
144
|
-
|
154
|
+
|
145
155
|
result = cnx.jp_post MANAGED_SW_UPDATES_SEND_UPDATES_RSRC, payload
|
146
156
|
Jamf::OAPISchemas::MacOsManagedSoftwareUpdateResponse.new result
|
147
157
|
end
|
@@ -161,14 +171,14 @@ module Jamf
|
|
161
171
|
groupId = is_a?(Jamf::Computer) ? nil : @id
|
162
172
|
|
163
173
|
self.class.send_managed_os_update(
|
164
|
-
deviceIds: deviceIds,
|
165
|
-
groupId: groupId,
|
166
|
-
maxDeferrals: maxDeferrals,
|
167
|
-
version: version,
|
168
|
-
skipVersionVerification: skipVersionVerification,
|
169
|
-
applyMajorUpdate: applyMajorUpdate,
|
170
|
-
forceRestart: forceRestart,
|
171
|
-
updateAction: updateAction,
|
174
|
+
deviceIds: deviceIds,
|
175
|
+
groupId: groupId,
|
176
|
+
maxDeferrals: maxDeferrals,
|
177
|
+
version: version,
|
178
|
+
skipVersionVerification: skipVersionVerification,
|
179
|
+
applyMajorUpdate: applyMajorUpdate,
|
180
|
+
forceRestart: forceRestart,
|
181
|
+
updateAction: updateAction,
|
172
182
|
cnx: @cnx
|
173
183
|
)
|
174
184
|
end
|
data/lib/jamf/validate.rb
CHANGED
@@ -98,7 +98,9 @@ module Jamf
|
|
98
98
|
#
|
99
99
|
# @return [Object] the validated unique value
|
100
100
|
#
|
101
|
-
def self.doesnt_already_exist(klass, identifier, val, msg: nil, api: Jamf.cnx)
|
101
|
+
def self.doesnt_already_exist(klass, identifier, val, msg: nil, api: nil, cnx: Jamf.cnx)
|
102
|
+
cnx = api if api
|
103
|
+
|
102
104
|
return val unless klass.all(:refresh, cnx: cnx).map { |i| i[identifier] }.include? val
|
103
105
|
|
104
106
|
key = klass.real_lookup_key identifier
|
data/lib/jamf/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-jss
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0b1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Lasell
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2023-04-24 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: CFPropertyList
|
@@ -824,9 +824,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
824
824
|
version: 2.6.3
|
825
825
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
826
826
|
requirements:
|
827
|
-
- - "
|
827
|
+
- - ">"
|
828
828
|
- !ruby/object:Gem::Version
|
829
|
-
version:
|
829
|
+
version: 1.3.1
|
830
830
|
requirements: []
|
831
831
|
rubygems_version: 3.0.3.1
|
832
832
|
signing_key:
|