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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 970c4289986bb3f0b3ea9a60b31777a29b4c927879a3204d28c3f9bdd46a2a9f
4
- data.tar.gz: f75ae4ae8ba5bd0cfadb065c62f495fcb4eea86b2473aa5d8357569e9ce49059
3
+ metadata.gz: a7af617b6ac8bb27cbc7d5c790a2de9fa788fb3d426ae062581654fbc9f77c5f
4
+ data.tar.gz: f5dfabfdde6c466951862fdc458321ad4f9384293e1fe773fb78a0ca80e51283
5
5
  SHA512:
6
- metadata.gz: b86acc435cc02cdd0976361305331b4bf98b176fd25c8accb791cfba794c7bdf6d42d94d62cc76b11cb510e9c3ac23495ac99aa244e76a39e5e6e061aeeae4a8
7
- data.tar.gz: 31f95548e2cb64bedb1781977222c705183c3e866ce8c8a9fb5532dfdbdeabe11d59faa92818c8506d5235d2fc868d1eb58d949b17ecc5f6c3d66bafde910750
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
- # flush the logs for this computer in a given policy
1162
- # @see Jamf::Policy.flush_logs
1161
+ # Flush all policy logs for this computer older than a given time period.
1163
1162
  #
1164
- def flush_policy_logs(policy, older_than: 0, period: :days)
1165
- Jamf::Policy.flush_logs(
1166
- policy,
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
- computers: [@id], cnx: @cnx
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
- # Check the validity of a password.
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
- # @param user[Symbol] one of :ro, :rw, :ssh, :http
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 pw[String] the password to check for the given user
311
+ # @param user[Symbol] ignored
318
312
  #
319
- # @return [Boolean,Nil] was the password correct?
320
- # nil is returned if there is no password set in the JSS.
313
+ # @param pw[String] ignored
321
314
  #
322
- def check_pw(user, pw)
323
- raise Jamf::InvalidDataError, 'The first parameter must be one of :ro, :rw, :ssh, :http' unless %i[ro rw ssh http].include? user
324
-
325
- sha256 = case user
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-enabled lost mode when re-enrolled after wipe.
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: true,
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-enabled lost mode when re-enrolled after wipe.
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
- phone_number: nil,
1387
+ phone: nil,
1388
1388
  footnote: nil,
1389
- enforce_lost_mode: true,
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
- phone_number: phone_number,
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 # Note: any other value in :specify_startup is a path to some other drive to boot from, e.g. /Volumes/Foo
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: "apply",
204
- remediate: "remediate",
205
- none: "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 some number of days, weeks,
297
- # months or years, possibly limited to one or more computers.
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
- # With no parameters, flushes all logs for the policy for all computers.
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, computers: [], api: nil, cnx: Jamf.cnx)
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 = LOG_FLUSH_INTERVAL_INTEGERS[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
- return cnx.c_delete "#{LOG_FLUSH_RSRC}/policy/id/#{pol_id}/interval/#{older_than}+#{period}" if computers.empty?
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
- # use an XML body in a DELETE request to flush logs for
347
- # a list of computers - used by the flush_logs class method
348
- def self.flush_logs_for_specific_computers(pol_id, older_than, period, computers, cnx)
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
- private_class_method :flush_logs_for_specific_computers
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] ? @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
- unless evt == RETRY_EVENTS[:none]
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
- return nil
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
- begin
1681
- @printers.map { |p| p[:id] }
1682
- rescue TypeError
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
- begin
1690
- @printers.map { |p| p[:name] }
1691
- rescue TypeError
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: "Individual"
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
- return
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 action == :change_pw || action == :reset_pw
1778
- raise Jamf::MissingDataError, ":password must be provided when changing management account password" if opts[:password].nil?
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 action == :reset_random || action == :generate_pw
1785
- raise Jamf::MissingDataError, ":password_length must be provided when setting a random password" if opts[:password_length].nil?
1786
- raise Jamf::InvalidDataError, ":password_length must be an Integer" unless opts[:password_length].is_a? Integer
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
- # Check if management password matches provided password
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
- # @param password[String] the password that is SHA256'ed to compare to the one from the API.
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
- # @return [Boolean] The result of the comparison of the management password and provided text.
1886
+ # @param password[String] ignored
1811
1887
  #
1812
- def verify_management_password(password)
1813
- raise Jamf::InvalidDataError, "Management password must be a string." unless password.is_a? String
1814
-
1815
- raise Jamf::UnsupportedError, "'#{@management_account[:action].to_s}' does not support management passwords." unless @management_account[:action] == MGMT_ACCOUNT_ACTIONS[:change_pw] || @management_account[:action] == MGMT_ACCOUNT_ACTIONS[:reset_pw]
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
- # some number of days, weeks, months or years, possibly limited to
1840
- # one or more computers
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, flushes all logs for all computers
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, computers: [])
1860
- raise Jamf::NoSuchItemError, "Policy doesn't exist in the JSS. Use #create first." unless @in_jss
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
- computers: computers, cnx: @cnx
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
- # if the given position is past the end, set it to -1 (the end)
1967
- opts[:position] = -1 if opts[:position] > @directory_bindings.size
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
- id = Jamf::DirectoryBinding.valid_id identifier, cnx: @cnx
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
- raise Jamf::InvalidDataError, "make_default must be either true or false." unless opts[:make_default].is_a?(TrueClass) || opts[:make_default].is_a?(FalseClass) || opts[:make_default].nil?
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
- raise Jamf::AlreadyExistsError, "Can't set #{key} target to '#{item}' because it's already an explicit exclusion." if @exclusions[key]&.include?(item_id)
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 [String] Required. 'DOWNLOAD_AND_INSTALL' or 'DOWNLOAD_ONLY'
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 deviceIDs are given.
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
- # DOWNLOAD_ONLY updateAction.
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 DownloadAndInstall
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 DOWNLOAD_AND_INSTALLn and the devices the command is sent to are on macOs 11 or higher.
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
- if self == Jamf::Computer
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 groupId if groupId
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] = updateAction if 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
@@ -27,6 +27,6 @@
27
27
  module Jamf
28
28
 
29
29
  ### The version of ruby-jss
30
- VERSION = '2.1.0'.freeze
30
+ VERSION = '3.0.0b1'.freeze
31
31
 
32
32
  end # module
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: 2.1.0
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: 2022-10-11 00:00:00.000000000 Z
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: '0'
829
+ version: 1.3.1
830
830
  requirements: []
831
831
  rubygems_version: 3.0.3.1
832
832
  signing_key: