ruby-jss 4.2.0b2 → 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +44 -7
- data/README-2.0.0.md +19 -8
- data/README.md +43 -30
- data/lib/jamf/api/classic/api_objects/patch_title.rb +0 -2
- data/lib/jamf/api/jamf_pro/api_objects/api_client.rb +3 -0
- data/lib/jamf/api/jamf_pro/api_objects/api_role.rb +3 -0
- data/lib/jamf/api/jamf_pro/api_objects/j_package.rb +333 -119
- data/lib/jamf/api/jamf_pro/api_objects/managed_software_updates/plan.rb +237 -0
- data/lib/jamf/api/jamf_pro/api_objects/managed_software_updates.rb +291 -0
- data/lib/jamf/api/jamf_pro/base_classes/oapi_object.rb +24 -3
- data/lib/jamf/api/jamf_pro/mixins/collection_resource.rb +23 -3
- data/lib/jamf/api/jamf_pro/mixins/filterable.rb +8 -0
- data/lib/jamf/api/jamf_pro/mixins/jpapi_resource.rb +17 -3
- data/lib/jamf/api/jamf_pro/mixins/macos_managed_updates.rb +2 -0
- data/lib/jamf/api/jamf_pro/mixins/prestage.rb +3 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/account_group.rb +123 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/account_preferences_v1.rb +105 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/assign_remove_profile_response_sync_state.rb +112 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/auth_account_v1.rb +159 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/authentication_type.rb +97 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/{device_enrollment_disown_body.rb → available_updates.rb} +14 -10
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_application.rb +124 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_attachment.rb +102 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_certificate.rb +151 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_configuration_profile.rb +118 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_content_caching.rb +372 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_content_caching_alert.rb +120 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_content_caching_cache_detail.rb +97 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_content_caching_data_migration_error.rb +98 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_content_caching_data_migration_error_user_info.rb +89 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_content_caching_parent.rb +131 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_content_caching_parent_alert.rb +105 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_content_caching_parent_capabilities.rb +124 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_content_caching_parent_details.rb +118 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_content_caching_parent_local_network.rb +97 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_disk.rb +143 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_disk_encryption.rb +120 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_extension_attribute.rb +175 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_font.rb +93 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_general.rb +244 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_hardware.rb +264 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_ibeacon.rb +81 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_inventory.rb +276 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_inventory_file_vault.rb +127 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_licensed_software.rb +88 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_local_user_account.rb +196 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_mdm_capability.rb +88 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_operating_system.rb +148 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_package_receipts.rb +97 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_partition.rb +145 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_partition_encryption.rb +94 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_partition_file_vault2_state.rb +97 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_plugin.rb +93 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_prestage_v3.rb +129 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_printer.rb +99 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_purchase.rb +158 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_remote_management.rb +88 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_section.rb +109 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_security.rb +193 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_service.rb +81 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_software_update.rb +93 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_storage.rb +90 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/computer_user_and_location.rb +131 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/dss_declaration.rb +111 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/dss_declarations.rb +88 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/enrollment_method.rb +97 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/group_membership.rb +94 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/inventory_preload_extension_attribute.rb +89 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/location_information.rb +146 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/{package_manifest.rb → location_information_v2.rb} +35 -37
- data/lib/jamf/api/jamf_pro/oapi_schemas/managed_software_update_plan.rb +181 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/managed_software_update_plan_event_store.rb +85 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/managed_software_update_plan_group_post.rb +99 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/managed_software_update_plan_post.rb +98 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/managed_software_update_plan_post_response.rb +100 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/managed_software_update_plan_toggle.rb +115 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/managed_software_update_plan_toggle_status.rb +169 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/managed_software_update_plan_toggle_status_wrapper.rb +91 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/managed_software_update_plans.rb +102 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/managed_software_update_status.rb +173 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/managed_software_update_statuses.rb +102 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/mobile_device_prestage_name_v2.rb +94 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/mobile_device_prestage_names_v2.rb +118 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/plan_configuration_post.rb +142 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/plan_device.rb +105 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/plan_device_post.rb +97 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/plan_device_response.rb +96 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/plan_group_post.rb +96 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/plan_search_results.rb +89 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/plan_status.rb +127 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/{device_enrollment_prestage.rb → prestage_purchasing_information.rb} +51 -88
- data/lib/jamf/api/jamf_pro/oapi_schemas/prestage_purchasing_information_v2.rb +174 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/prestage_scope_assignment_v2.rb +94 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas/v1_site.rb +91 -0
- data/lib/jamf/api/jamf_pro/oapi_schemas.rb +24 -1
- data/lib/jamf/api/jamf_pro/other_classes/pager.rb +7 -1
- data/lib/jamf/composer.rb +114 -107
- data/lib/jamf/oapi_validate.rb +1 -0
- data/lib/jamf/utility.rb +20 -14
- data/lib/jamf/version.rb +1 -1
- data/test/bin/runtests +2 -2
- data/test/lib/jamf_test/collection_tests.rb +10 -2
- data/test/tests/computer_group.rb +29 -12
- data/test/tests/{jp_building.rb → j_building.rb} +2 -2
- data/test/tests/j_package.rb +47 -0
- metadata +87 -8
@@ -25,6 +25,8 @@
|
|
25
25
|
|
26
26
|
# frozen_string_literal: true
|
27
27
|
|
28
|
+
require 'cfpropertylist'
|
29
|
+
|
28
30
|
# The main Module
|
29
31
|
module Jamf
|
30
32
|
|
@@ -102,6 +104,13 @@ module Jamf
|
|
102
104
|
# which usually only identifies ':id'
|
103
105
|
ALT_IDENTIFIERS = %i[packageName fileName].freeze
|
104
106
|
|
107
|
+
# If the object does not have a 'name' attribute, this is the attribute
|
108
|
+
# that holds its name. Used to allow referencing objects by 'name',
|
109
|
+
# creates a alias of the attribute called "name" and "name=",
|
110
|
+
# and allows the use of "name:" as an identifier in the .fetch, .valid_id and
|
111
|
+
# similar methods.
|
112
|
+
OBJECT_NAME_ATTR = :packageName
|
113
|
+
|
105
114
|
# Must define this when extending Filterable
|
106
115
|
FILTER_KEYS = %i[
|
107
116
|
id fileName packageName categoryId info notes manifestFileName cloudTransferStatus
|
@@ -126,7 +135,7 @@ module Jamf
|
|
126
135
|
# The hashType value in the API or manifests for md5
|
127
136
|
CHECKSUM_HASH_TYPE_MD5 = 'MD5'
|
128
137
|
|
129
|
-
# The hashType value in the API for sha256 - IF it exists
|
138
|
+
# The hashType value in the API for sha256 - IF it exists?
|
130
139
|
CHECKSUM_HASH_TYPE_SHA256 = 'SHA_256'
|
131
140
|
|
132
141
|
# The hashType value in MDM deploy manifests for sha256
|
@@ -149,7 +158,15 @@ module Jamf
|
|
149
158
|
# fileName, with spaces converted to dashes.
|
150
159
|
MANIFEST_FILENAME_DEFAULT_SUFFIX = '-manifest.plist'
|
151
160
|
|
152
|
-
#
|
161
|
+
# If no manifest bundle identifier is provided, this will be used before
|
162
|
+
# the packageName.
|
163
|
+
MANIFEST_BUNDLE_ID_PREFIX = 'com.pixar.ruby-jss.'
|
164
|
+
|
165
|
+
# if no manifest bundle version is provided, this will be used.
|
166
|
+
MANIFEST_BUNDLE_VERSION_DEFAULT = '0'
|
167
|
+
|
168
|
+
# Not doing chunking by default in generated manifests,
|
169
|
+
# but if we do, we'll use this
|
153
170
|
MANIFEST_CHUNK_SIZE = 1024 * 1024 * 10 # 10MB
|
154
171
|
|
155
172
|
MANIFEST_PLIST_TEMPLATE = {
|
@@ -164,10 +181,11 @@ module Jamf
|
|
164
181
|
], # end assets array,
|
165
182
|
metadata: {
|
166
183
|
'kind' => 'software',
|
167
|
-
'bundle-identifier' =>
|
168
|
-
'bundle-version' =>
|
184
|
+
'bundle-identifier' => "#{MANIFEST_BUNDLE_ID_PREFIX}example",
|
185
|
+
'bundle-version' => MANIFEST_BUNDLE_VERSION_DEFAULT,
|
169
186
|
'title' => 'title',
|
170
|
-
'sizeInBytes' => 1
|
187
|
+
'sizeInBytes' => 1,
|
188
|
+
'sha256-whole' => 'sha256-goes-here'
|
171
189
|
} # end metadata
|
172
190
|
} # end hash
|
173
191
|
] # end items array
|
@@ -210,8 +228,8 @@ module Jamf
|
|
210
228
|
# for all Jamf::JPackage objects in this ruby session.
|
211
229
|
#
|
212
230
|
# Setting this in the config or here means you don't have to provide a base URL
|
213
|
-
# each time when calling #generate_manifest, however you can still provide
|
214
|
-
# at that time to override any default.
|
231
|
+
# each time when calling #generate_manifest or #upload, however you can still provide
|
232
|
+
# one at that time to override any default.
|
215
233
|
#
|
216
234
|
# Normally, the package's fileName is appended to this URL to generate the full
|
217
235
|
# download URL. E.g. for a package with a fileName 'my-app.pkg', with the base URL of
|
@@ -244,18 +262,22 @@ module Jamf
|
|
244
262
|
#####################################
|
245
263
|
|
246
264
|
# Checksums
|
265
|
+
#
|
247
266
|
# Packages in Jamf Pro can have a checksum in either MD5 or SHA512, or possibly
|
248
267
|
# SHA256 - none of our 1500 pkgs have 256, but given the existence of the sha256
|
249
268
|
# attribute in the API data, I'm assuming it existed at some point, and behaves like
|
250
269
|
# md5 (read on)
|
251
270
|
#
|
252
|
-
# In all cases, the hashType indicates the type of checksum, as a string,
|
253
|
-
# 'MD5', 'SHA_256', or 'SHA_512'.
|
271
|
+
# In all cases, the hashType attribute indicates the type of checksum, as a string,
|
272
|
+
# one of 'MD5', 'SHA_256', or 'SHA_512'.
|
254
273
|
#
|
255
|
-
# In the case of md5 and sha256, the
|
274
|
+
# In the case of md5 and sha256, the actual digest value (the checksum) is in the
|
256
275
|
# 'md5' or 'sha256' attribute. In the case of sha512, the digest is in the 'hashValue'
|
257
276
|
# attribute.
|
258
|
-
# In anycase, the digest value will be stored in the checksum attribute
|
277
|
+
# In anycase, the digest value will also be stored in the checksum attribute
|
278
|
+
#
|
279
|
+
# NOTE: This is the checksum used when installing via a Policy.
|
280
|
+
# The checksum(s) used when deploying via MDM is stored in the manifest.
|
259
281
|
#
|
260
282
|
# @return [String] the checksum of the package, either an MD5, SHA256, or SHA512
|
261
283
|
# digest of the package file.
|
@@ -318,6 +340,12 @@ module Jamf
|
|
318
340
|
self.suppressEula = DEFAULT_SUPPRESS_EULA if suppressEula.nil?
|
319
341
|
self.suppressRegistration = DEFAULT_SUPPRESS_REGISTRATION if suppressRegistration.nil?
|
320
342
|
|
343
|
+
if creating_from_create && osRequirements
|
344
|
+
# if we're creating a new object, and osRequirements is set,
|
345
|
+
# convert it to a comma-separated string
|
346
|
+
@osRequirements = osRequirements_as_comma_sep_string(osRequirements)
|
347
|
+
end
|
348
|
+
|
321
349
|
@checksum =
|
322
350
|
case hashType
|
323
351
|
when CHECKSUM_HASH_TYPE_MD5
|
@@ -333,14 +361,62 @@ module Jamf
|
|
333
361
|
#####################################
|
334
362
|
|
335
363
|
# @return [Pathname] the local receipt when this pkg is installed by a policy
|
364
|
+
#############################
|
336
365
|
def receipt
|
337
366
|
# the receipt is the filename with any .zip extension removed.
|
338
367
|
fileName ? (Jamf::Client::RECEIPTS_FOLDER + fileName.to_s.sub(/.zip$/, '')) : nil
|
339
368
|
end
|
340
369
|
|
370
|
+
# Change the os_requirements field in the JSS
|
371
|
+
# E.g. 10.5, 10.5.3, 10.6.x
|
372
|
+
#
|
373
|
+
# Extra feature: Minumum OS's can now be specified as a
|
374
|
+
# string using the notation ">=10.6.7".
|
375
|
+
#
|
376
|
+
# @see Jamf.expand_min_os
|
377
|
+
#
|
378
|
+
# @param new_val [String,Array<String>] comma-separated string, or array of os versions
|
379
|
+
#
|
380
|
+
# @return [void]
|
381
|
+
#############################
|
382
|
+
def osRequirements=(new_val)
|
383
|
+
orig_osRequirements = osRequirements
|
384
|
+
|
385
|
+
new_val = osRequirements_as_comma_sep_string(new_val)
|
386
|
+
@osRequirements = new_val
|
387
|
+
|
388
|
+
note_unsaved_change :osRequirements, orig_osRequirements
|
389
|
+
end
|
390
|
+
|
391
|
+
# Take a value for osRequirements, and return it as a comma-separated string,
|
392
|
+
# possibly expanded if any of them starts with '>='.
|
393
|
+
#
|
394
|
+
# @see Jamf.expand_min_os
|
395
|
+
#
|
396
|
+
# @param val [String,Array<String>] comma-separated string, or array of os versions
|
397
|
+
#
|
398
|
+
# @return [Array<String>] the osRequirements as an array of strings
|
399
|
+
#############################
|
400
|
+
def osRequirements_as_comma_sep_string(val)
|
401
|
+
# make sure we have a flat array of strings
|
402
|
+
val = val.split(',').map(&:strip) if val.is_a? String
|
403
|
+
val = [val].flatten.compact.uniq.map(&:to_s)
|
404
|
+
|
405
|
+
# expand any minimum OS versions
|
406
|
+
val.map! do |vers|
|
407
|
+
vers.start_with?('>=') ? Jamf.expand_min_os(vers) : vers
|
408
|
+
end
|
409
|
+
|
410
|
+
val.flatten.join(', ')
|
411
|
+
end
|
412
|
+
private :osRequirements_as_comma_sep_string
|
413
|
+
|
341
414
|
# Recalculate the checksum of the package file from a given filepath, and update the
|
342
415
|
# object's checksum and hashValue attributes.
|
343
416
|
#
|
417
|
+
# NOTE: This updates the checksum used when installing via a Policy.
|
418
|
+
# The checksum(s) used when deploying via MDM is stored in the manifest.
|
419
|
+
#
|
344
420
|
# You will need to call #save on the object to save the new checksum to the server.
|
345
421
|
#
|
346
422
|
# New checksums are always SHA512
|
@@ -368,38 +444,65 @@ module Jamf
|
|
368
444
|
self.class.calculate_checksum(filepath, hashType) == checksum
|
369
445
|
end
|
370
446
|
|
371
|
-
# @return [String]
|
447
|
+
# @return [String] A default if none is set explicitly
|
372
448
|
##############################
|
373
449
|
def default_manifestFileName
|
374
450
|
"#{fileName.gsub(' ', '-')}#{MANIFEST_FILENAME_DEFAULT_SUFFIX}"
|
375
451
|
end
|
376
452
|
|
377
|
-
# Set the manifest from a local file or XML plist
|
378
|
-
# If from a file,
|
453
|
+
# Set the manifest from a local file or a String containing an XML plist.
|
454
|
+
# If from a file, the manifestFileName attribute is set to the filename
|
455
|
+
#
|
456
|
+
# To automatically generate a manifest plist for this package from a
|
457
|
+
# locally-readable .pkg file, use #generate_manifest
|
458
|
+
#
|
459
|
+
# All manifests require a valid URL for downloading the .pkg file when
|
460
|
+
# installing on a client.
|
379
461
|
#
|
380
|
-
#
|
462
|
+
# No validation of the manifest is done here.
|
381
463
|
#
|
382
|
-
#
|
383
|
-
# #deploy_via_mdm, the manifest MUST include a metadata dictionary
|
384
|
-
# with at least the following keys
|
385
|
-
# - 'bundle-identifier' that matches the bundle identifier of the pkg
|
386
|
-
# - 'bundle-version' = the version of the pkg
|
387
|
-
# - 'kind' = 'software'
|
388
|
-
# - 'title' = the name of the pkg or what it installs
|
389
|
-
# - 'sizeInBytes' = the size of the pkg in bytes
|
390
|
-
# optional keys include bundle-version, and subtitle
|
464
|
+
# DEPLOYING VIA MDM:
|
391
465
|
#
|
392
|
-
#
|
466
|
+
# When using this method, if you want to be able to deploy the package using
|
467
|
+
# deploy_via_mdm, the manifest MUST include a metadata dictionary
|
468
|
+
# with at least the following keys:
|
469
|
+
# - 'kind' = 'software'
|
470
|
+
# - 'bundle-identifier' that preferably matches the bundle identifier of the pkg
|
471
|
+
# - 'bundle-version' = that preferably matches the version of the pkg
|
472
|
+
# - 'title' = the name of the pkg or what it installs
|
473
|
+
# - 'sizeInBytes' = the size of the .pkg in bytes
|
474
|
+
# as well as one of these non-standard keys:
|
475
|
+
# - 'sha256-whole' = the SHA256 digest of the whole file, regardless of chunking data in the 'assets' array
|
476
|
+
# OR
|
477
|
+
# - 'md5-whole' = the MD5 digest of the whole file, regardless of chunking data in the 'assets' array
|
478
|
+
#
|
479
|
+
# The non-standard keys are because the Jamf Pro API endpoint for deploying via MDM requires
|
480
|
+
# a whole-file checksum even if the file is chunked in the manifest.
|
481
|
+
#
|
482
|
+
# See the MANIFEST_PLIST_TEMPLATE constant for an example of the data structure (as a ruby hash, not a plist)
|
483
|
+
#
|
484
|
+
# @param new_manifest [String, Pathname] the manifest plist data or path to a local file
|
393
485
|
#
|
394
486
|
# @return [void]
|
395
487
|
##############################
|
396
|
-
def manifest=(
|
397
|
-
if
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
488
|
+
def manifest=(new_manifest)
|
489
|
+
# if its a string but not an xml plist, assume its a path
|
490
|
+
new_manifest = Pathname.new(new_manifest) if new_manifest.is_a?(String) && !new_manifest.start_with?('<?xml')
|
491
|
+
orig_manifest = manifest
|
492
|
+
|
493
|
+
new_xml =
|
494
|
+
if new_manifest.is_a? Pathname
|
495
|
+
new_manifest.read
|
496
|
+
|
497
|
+
elsif new_manifest.is_a? String
|
498
|
+
new_manifest
|
499
|
+
|
500
|
+
else
|
501
|
+
raise ArgumentError, 'Argument must be a Pathname, or a String containing a path or an XML plist'
|
502
|
+
end
|
503
|
+
|
504
|
+
@manifest = new_xml
|
505
|
+
note_unsaved_change :manifest, orig_manifest
|
403
506
|
end
|
404
507
|
|
405
508
|
# return the manifest as a ruby hash converted from the plist
|
@@ -413,24 +516,34 @@ module Jamf
|
|
413
516
|
CFPropertyList.native_types(CFPropertyList::List.new(data: manifest).value)
|
414
517
|
end
|
415
518
|
|
416
|
-
# Generate a manifest plist (xml) for this package
|
417
|
-
# and
|
519
|
+
# Generate a manifest plist (xml) for this package from a local .pkg file,
|
520
|
+
# and update the #manifest and #manifestFileName attributes
|
418
521
|
#
|
419
522
|
# Afterwards, you will need to call #save on the object to save the new values to
|
420
523
|
# the server.
|
421
524
|
#
|
525
|
+
# See also #manifest= for setting the manifest from a file or string.
|
526
|
+
#
|
422
527
|
# The download URL used in the manifest will be the default for the class
|
423
|
-
# (if you have set one)
|
424
|
-
# class default may come from the ruby-jss config, or be set directly on the class
|
528
|
+
# (if you have set one) usually with the fileName appended. The
|
529
|
+
# class default may come from the ruby-jss config, or be set directly on the class,
|
530
|
+
# see JPackage.default_manifest_base_url=
|
425
531
|
#
|
426
532
|
# Unless set explicitly afterward using #manifestFileName= the manifest filename
|
427
533
|
# will be the fileName of the Package object, with spaces converted to dashes,
|
428
534
|
# followed by MANIFEST_FILENAME_DEFAULT_SUFFIX.
|
429
535
|
# e.g. my-app.pkg-manifest.plist
|
430
536
|
#
|
431
|
-
#
|
432
|
-
#
|
433
|
-
#
|
537
|
+
# By default, this method is invoked when uploading the pkg file using #upload
|
538
|
+
# and the opts will be passed from that method to this one.
|
539
|
+
# When invoked from #upload, the new values will be saved to the Jamf Pro server automatically.
|
540
|
+
#
|
541
|
+
# The manifests generated by this method are suitable for use in MDM deployments.
|
542
|
+
#
|
543
|
+
# If you don't provide a bundle_identifier, it will be generated from the packageName,
|
544
|
+
# prefixed with 'com.pixar.ruby-jss.' and with spaces converted to dashes.
|
545
|
+
#
|
546
|
+
# If you don't provide a bundle_version, it will be '0'
|
434
547
|
#
|
435
548
|
# @param filepath [String, Pathname] the path to a local copy of the package file for which
|
436
549
|
# this manifest is being generated. This MUST match the one uploaded to the server, as it is
|
@@ -450,10 +563,12 @@ module Jamf
|
|
450
563
|
# A common chunk size is 10MB, or 1024 * 1024 * 10.
|
451
564
|
# NOTE: Not all distribution points support chunked downloads.
|
452
565
|
#
|
453
|
-
# @option opts bundle_identifier [String, Symbol]
|
454
|
-
# Should match that in the .pkg itself
|
566
|
+
# @option opts bundle_identifier [String, Symbol] The bundle identifier of the package,
|
567
|
+
# Should match that in the .pkg itself.
|
568
|
+
# Defaults to 'com.pixar.ruby-jss.packageName' where packageName is the
|
569
|
+
# packageName with whitespace converted to dashes.
|
455
570
|
#
|
456
|
-
# @option opts bundle_version [String
|
571
|
+
# @option opts bundle_version [String] the version of the package.
|
457
572
|
# Defaults to '0'
|
458
573
|
#
|
459
574
|
# @option opts subtitle [String] a subtitle for the package, optional
|
@@ -470,10 +585,12 @@ module Jamf
|
|
470
585
|
validate_local_file(file)
|
471
586
|
|
472
587
|
filesize = file.size
|
473
|
-
url = parse_manifest_url opts[:url], append_filename: opts[:append_filename_to_url]
|
474
588
|
|
475
589
|
# make the manifest
|
476
590
|
new_manifest = MANIFEST_PLIST_TEMPLATE.dup
|
591
|
+
|
592
|
+
url = build_manifest_url opts[:url], append_filename: opts[:append_filename_to_url]
|
593
|
+
|
477
594
|
new_manifest[:items][0][:assets][0]['url'] = url.to_s
|
478
595
|
|
479
596
|
# get the checksum(s)
|
@@ -486,25 +603,14 @@ module Jamf
|
|
486
603
|
new_manifest[:items][0][:metadata]['title'] = packageName
|
487
604
|
new_manifest[:items][0][:metadata]['subtitle'] = opts[:subtitle] if opts[:subtitle]
|
488
605
|
new_manifest[:items][0][:metadata]['sizeInBytes'] = filesize
|
489
|
-
new_manifest[:items][0][:metadata]['bundle-identifier'] =
|
490
|
-
|
491
|
-
|
492
|
-
# TESTING - store the whole-file checksum in
|
493
|
-
# manifest[:items][0][:metadata]['sha256-whole']. taking it from
|
494
|
-
# manifest[:items][0][:assets][0]['sha256s'][0], if available, or generate it if needed
|
495
|
-
# It is used by the deploy_via_mdm method.
|
496
|
-
# The test will be to deploy this pkg via MDM in a prestage, and see
|
497
|
-
# if the 'unknown' hash key 'sha256-whole' causes a problem installing.
|
498
|
-
new_manifest[:items][0][:metadata]['sha256-whole'] =
|
499
|
-
if new_manifest[:items][0][:assets][0]['sha256s'].size == 1
|
500
|
-
new_manifest[:items][0][:assets][0]['sha256s'][0]
|
501
|
-
else
|
502
|
-
new_manifest[:items][0][:assets][0]['sha256s'] = [Digest::SHA256.hexdigest(file.read)]
|
503
|
-
end
|
606
|
+
new_manifest[:items][0][:metadata]['bundle-identifier'] =
|
607
|
+
(opts[:bundle_identifier] || "#{MANIFEST_BUNDLE_ID_PREFIX}#{packageName.gsub(/\s+/, '-')}")
|
608
|
+
new_manifest[:items][0][:metadata]['bundle-version'] = opts[:bundle_version] if opts[:bundle_version]
|
504
609
|
|
505
610
|
plist = CFPropertyList::List.new
|
506
611
|
plist.value = CFPropertyList.guess(new_manifest)
|
507
|
-
self.manifest = plist.to_str
|
612
|
+
self.manifest = plist.to_str(CFPropertyList::List::FORMAT_XML, formatted: true)
|
613
|
+
|
508
614
|
self.manifestFileName = default_manifestFileName
|
509
615
|
end
|
510
616
|
|
@@ -524,12 +630,16 @@ module Jamf
|
|
524
630
|
# the url is not valid.
|
525
631
|
#
|
526
632
|
# @param given_url [String] the URL to use, if provided
|
633
|
+
# @param append_filename [Boolean] should the filename be appended to the URL?
|
527
634
|
#
|
528
635
|
# @return [URI] the URI object for the URL
|
529
636
|
##############################
|
530
|
-
def
|
637
|
+
def build_manifest_url(given_url = nil, append_filename: true)
|
531
638
|
url = given_url || self.class.default_manifest_base_url
|
532
|
-
|
639
|
+
unless url
|
640
|
+
raise ArgumentError,
|
641
|
+
'No URL for manifest. Pass one with url: or set one with Jamf::JPackage.default_manifest_base_url=, or set package_manifest_base_url in the ruby-jss.conf file.'
|
642
|
+
end
|
533
643
|
|
534
644
|
# append the filename to the URL if needed
|
535
645
|
url = "#{url.to_s.chomp('/')}/#{CGI.escape fileName}" unless append_filename == false
|
@@ -537,9 +647,10 @@ module Jamf
|
|
537
647
|
# check validity and return
|
538
648
|
URI.parse url
|
539
649
|
end
|
540
|
-
private :
|
650
|
+
private :build_manifest_url
|
541
651
|
|
542
|
-
# calculate the manifest checksum[s] for a given file, and store in the manifest data
|
652
|
+
# calculate the manifest checksum[s] for a given file, and store in the manifest data.
|
653
|
+
# We only do SHA256, but Apple supports MD5 as well.
|
543
654
|
#
|
544
655
|
# @param file [Pathname] the path to the file to checksum
|
545
656
|
# @param chunk_size [Integer] the size of each chunk in the manifest, in bytes.
|
@@ -564,6 +675,18 @@ module Jamf
|
|
564
675
|
new_manifest[:items][0][:assets][0]['sha256-size'] = file.size
|
565
676
|
new_manifest[:items][0][:assets][0]['sha256s'] = [Digest::SHA256.hexdigest(file.read)]
|
566
677
|
end
|
678
|
+
|
679
|
+
# Store the whole-file checksum in
|
680
|
+
# manifest[:items][0][:metadata]['sha256-whole']. taking it from
|
681
|
+
# manifest[:items][0][:assets][0]['sha256s'][0], if available, or generate it if needed
|
682
|
+
# It is used by the deploy_via_mdm method.
|
683
|
+
# This value is required for MDM deployments, even if the file is chunked in the manifest.
|
684
|
+
new_manifest[:items][0][:metadata]['sha256-whole'] =
|
685
|
+
if new_manifest[:items][0][:assets][0]['sha256s'].size == 1
|
686
|
+
new_manifest[:items][0][:assets][0]['sha256s'][0]
|
687
|
+
else
|
688
|
+
Digest::SHA256.hexdigest(file.read)
|
689
|
+
end
|
567
690
|
end
|
568
691
|
private :calculate_manifest_checksums
|
569
692
|
|
@@ -583,8 +706,10 @@ module Jamf
|
|
583
706
|
end
|
584
707
|
private :append_manifest_image
|
585
708
|
|
586
|
-
# Upload a package file to Jamf Pro
|
587
|
-
#
|
709
|
+
# Upload a package file to Jamf Pro.
|
710
|
+
#
|
711
|
+
# WARNING: This will automatically call #save, saving any pending changes to
|
712
|
+
# the Jamf Pro server!
|
588
713
|
#
|
589
714
|
# This uses the Jamf Pro API to upload the file via the package/upload endpoint.
|
590
715
|
# If you don't use an appropriate primary distribution point, this may not work.
|
@@ -594,44 +719,44 @@ module Jamf
|
|
594
719
|
# If that filename is in use by some other package, you'll get an error:
|
595
720
|
# Field: fileName, Error: DUPLICATE_FIELD duplicate name
|
596
721
|
#
|
597
|
-
#
|
722
|
+
# This will automatically call #save at least once, and possibly twice.
|
598
723
|
# First, in order to ensure the correct fileName in Jamf based on the file being uploaded,
|
599
724
|
# and second, in order to update the checksum and manifest in Jamf Pro, if needed.
|
600
725
|
# *** Any other outstanding changes will also be saved!
|
601
726
|
#
|
727
|
+
# After uploading, the response from the server is in the #upload_response attribute,
|
728
|
+
# with a timestamp added to the data from the API.
|
729
|
+
#
|
602
730
|
# @param filepath [String, Pathname] the path to the package file to upload
|
603
731
|
#
|
604
732
|
# @param opts[Hash] a hash of keyword arguments
|
605
733
|
#
|
606
734
|
# @option opts :update_checksum [Boolean] update the checksum of the package in Jamf Pro.
|
607
735
|
# Defaults to true. All new checksums are SHA_512.
|
736
|
+
# WARNING: If you set this to false, the checksum in the object will not be updated
|
737
|
+
# and installs may fail. Be sure to set it to the correct value yourself.
|
608
738
|
#
|
609
739
|
# @option opts :update_manifest [Boolean] update the manifest of the package in Jamf Pro
|
610
|
-
# Defaults to true
|
740
|
+
# Defaults to true.
|
741
|
+
# WARNING: If you set this to false, the manifest in the object will not be updated
|
742
|
+
# and PreStage & MDM deployments may fail. Be sure to set it to the correct value
|
743
|
+
# using #generate_manifest or #manifest= yourself.
|
611
744
|
#
|
612
|
-
# @options opts url [String]
|
613
|
-
# defaults to the class default
|
745
|
+
# @options opts url [String] See #generate_manifest
|
614
746
|
#
|
615
|
-
# @option opts append_filename_to_url [Boolean]
|
616
|
-
# defaults to true.
|
617
|
-
# If false, the url given must be the full URL to download the individual package file.
|
747
|
+
# @option opts append_filename_to_url [Boolean] See #generate_manifest
|
618
748
|
#
|
619
|
-
# @option opts chunk_size [Integer]
|
620
|
-
# If omitted, the whole file will be checksummed at once and downloads will not be chunked.
|
621
|
-
# A common chunk size is 10MB, or 1024 * 1024 * 10.
|
622
|
-
# NOTE: Not all distribution points support chunked downloads.
|
749
|
+
# @option opts chunk_size [Integer] See #generate_manifest
|
623
750
|
#
|
624
|
-
# @option opts bundle_identifier [String
|
625
|
-
# Should match that in the .pkg itself, but defaults to 'xolo.fileName'
|
751
|
+
# @option opts bundle_identifier [String] See #generate_manifest
|
626
752
|
#
|
627
|
-
# @option opts bundle_version [String
|
628
|
-
# Defaults to '0'
|
753
|
+
# @option opts bundle_version [String] See #generate_manifest
|
629
754
|
#
|
630
|
-
# @option opts subtitle [String]
|
755
|
+
# @option opts subtitle [String] See #generate_manifest
|
631
756
|
#
|
632
|
-
# @option opts full_size_image_url [String]
|
757
|
+
# @option opts full_size_image_url [String] See #generate_manifest
|
633
758
|
#
|
634
|
-
# @option opts display_image_url [String]
|
759
|
+
# @option opts display_image_url [String] See #generate_manifest
|
635
760
|
#
|
636
761
|
# @return [void]
|
637
762
|
##############################
|
@@ -640,70 +765,72 @@ module Jamf
|
|
640
765
|
validate_local_file(file)
|
641
766
|
|
642
767
|
# update the filename if needed
|
643
|
-
# must happen before the upload
|
644
|
-
|
645
|
-
self.fileName = real_filename unless fileName == real_filename
|
646
|
-
save
|
768
|
+
# must happen before the upload so it matches the file being uploaded
|
769
|
+
self.fileName = file.basename.to_s
|
647
770
|
|
648
|
-
#
|
649
|
-
|
650
|
-
|
771
|
+
# We must save the checksum and manifest to the server before uploading
|
772
|
+
# the file, because otherwise jamf will likely overwrite the manifest
|
773
|
+
# after it uploads to the primary distribution point.
|
651
774
|
|
652
775
|
# recalulate the checksum unless told no to
|
776
|
+
# NOTE: It appears that the checksum will always be recaluclated by
|
777
|
+
# the Jamf Pro server, as MD5. If you really want our default SHA512,
|
778
|
+
# then do this again later, manually.
|
653
779
|
recalculate_checksum(file) unless opts[:update_checksum] == false
|
654
780
|
|
655
|
-
# generate a manifest
|
656
|
-
generate_manifest
|
781
|
+
# generate a manifest using the new file
|
782
|
+
generate_manifest(file, **opts) unless opts[:update_manifest] == false
|
657
783
|
|
658
|
-
# save the new checksum and manifest
|
784
|
+
# save the new fileName, checksum and manifest
|
659
785
|
save
|
786
|
+
|
787
|
+
# upload the file
|
788
|
+
@upload_response = cnx.jp_upload("#{get_path}/#{UPLOAD_ENDPOINT}", file)
|
789
|
+
@upload_response[:time] = Time.now
|
790
|
+
@upload_response
|
660
791
|
end
|
661
792
|
|
662
793
|
# Deploy this package to computers or a group via MDM.
|
663
794
|
#
|
664
795
|
# REQUIREMENTS:
|
665
|
-
# - The package must have a manifest
|
796
|
+
# - The package must have a manifest with specific data. See #manifest=
|
797
|
+
# and #generate_manifest for details.
|
666
798
|
# - The .pkg file must be a product archive (.pkg) built with Xcode or productbuild.
|
667
799
|
# (it must contain a 'Distribution' file, usually generated by those tools)
|
668
800
|
# Simple 'component' packages built with pkgbuild are not supported.
|
669
|
-
# - The .pkg file must be signed with a
|
801
|
+
# - The .pkg file must be signed with a trusted signing certificate
|
670
802
|
#
|
671
|
-
# This will send
|
672
|
-
# computers, and/or the members of a single computer group.
|
803
|
+
# This will send an MDM InstallEnterpriseApplication command to install the package
|
804
|
+
# to one or more computers, and/or the members of a single computer group.
|
673
805
|
#
|
674
806
|
# @param computer_ids [Array<Integer>,Integer] The ids of the computers to deploy to
|
675
807
|
#
|
676
808
|
# @param group_id [Integer] The id of the computer group to deploy to
|
677
809
|
#
|
678
|
-
# @param managed [Boolean] Should the installed package be managed by Jamf Pro
|
810
|
+
# @param managed [Boolean] Should the installed package be managed by Jamf Pro?
|
811
|
+
# Defaults to false. This seems to be for App Store apps only??
|
679
812
|
#
|
680
|
-
# @return [
|
813
|
+
# @return [Hash] the response from the server. see #deploy_response
|
681
814
|
##############################
|
682
815
|
def deploy_via_mdm(computer_ids: nil, group_id: nil, managed: false)
|
683
|
-
raise
|
684
|
-
raise Jamf::
|
816
|
+
raise ArgumentError, 'No computer_ids or group_id provided' unless computer_ids || group_id
|
817
|
+
raise Jamf::MissingDataError, 'No manifest set for this package' if manifest.to_s.empty?
|
818
|
+
raise Jamf::NoSuchItemError, 'This package has no id, it must be saved in Jamf Pro before uploading' unless exist?
|
685
819
|
|
686
|
-
# convert the manifest to a ruby hash
|
820
|
+
# convert the full manifest to a ruby hash
|
687
821
|
parsed_manifest = manifest_hash
|
688
822
|
|
689
823
|
# manifest data for the MDMDeploy command, which is a hash.
|
690
824
|
# hopefully some day Jamf will just use the manifest for the pkg
|
691
825
|
mdm_manifest = {}
|
692
|
-
mdm_manifest['url'] = parsed_manifest
|
693
|
-
|
694
|
-
mdm_manifest['
|
695
|
-
mdm_manifest['
|
696
|
-
mdm_manifest['
|
697
|
-
mdm_manifest['
|
698
|
-
|
699
|
-
mdm_manifest
|
700
|
-
|
701
|
-
mdm_manifest['subtitle'] = parsed_manifest['items'][0]['metadata']['subtitle'] if parsed_manifest['items'][0]['metadata']['subtitle']
|
702
|
-
|
703
|
-
parsed_manifest['items'][0]['assets'].each do |asset|
|
704
|
-
mdm_manifest['fullSizeImageURL'] = asset['url'] if asset['kind'] == 'full-size-image'
|
705
|
-
mdm_manifest['displayImageURL'] = asset['url'] if asset['kind'] == 'display-image'
|
706
|
-
end
|
826
|
+
mdm_manifest['url'] = manifest_url_for_deployment(parsed_manifest)
|
827
|
+
mdm_manifest['hash'], mdm_manifest['hashType'] = manifest_checksum_for_deployment(parsed_manifest)
|
828
|
+
mdm_manifest['bundleId'] = manifest_bundle_identifier_for_deployment(parsed_manifest)
|
829
|
+
mdm_manifest['bundleVersion'] = manifest_bundle_version_for_deployment(parsed_manifest)
|
830
|
+
mdm_manifest['title'] = manifest_title_for_deployment(parsed_manifest)
|
831
|
+
mdm_manifest['sizeInBytes'] = manifest_size_for_deployment(parsed_manifest)
|
832
|
+
|
833
|
+
set_optional_mdm_manifest_values(parsed_manifest, mdm_manifest)
|
707
834
|
|
708
835
|
# make sure the computers are in an array
|
709
836
|
computer_ids = [computer_ids].flatten.compact.uniq
|
@@ -712,13 +839,100 @@ module Jamf
|
|
712
839
|
payload = {
|
713
840
|
manifest: mdm_manifest,
|
714
841
|
installAsManaged: managed,
|
715
|
-
devices: computer_ids
|
716
|
-
groupId: group_id.to_s
|
842
|
+
devices: computer_ids
|
717
843
|
}
|
844
|
+
payload[:groupId] = group_id.to_s if group_id
|
845
|
+
|
718
846
|
# send the command
|
719
847
|
@deploy_response = cnx.post(DEPLOYMENT_ENDPOINT, payload)
|
720
848
|
end
|
721
849
|
|
850
|
+
# the URL is required for MDM deployments
|
851
|
+
# @param parsed_manifest [Hash] the parsed manifest data as a ruby hash
|
852
|
+
# @return [String] the URL in the manifest for MDM deployments
|
853
|
+
#####################################
|
854
|
+
def manifest_url_for_deployment(parsed_manifest)
|
855
|
+
url = parsed_manifest.dig 'items', 0, 'assets', 0, 'url'
|
856
|
+
raise Jamf::MissingDataError, 'No URL in the manifest' unless url
|
857
|
+
|
858
|
+
url
|
859
|
+
end
|
860
|
+
private :manifest_url_for_deployment
|
861
|
+
|
862
|
+
# whole-file checksums are required for MDM deployments
|
863
|
+
# @return [Array<String>] the checksum and checksum type in the manifest for MDM deployments
|
864
|
+
#####################################
|
865
|
+
def manifest_checksum_for_deployment(parsed_manifest)
|
866
|
+
if whole = parsed_manifest.dig('items', 0, 'metadata', 'sha256-whole')
|
867
|
+
[whole, CHECKSUM_HASH_TYPE_SHA256_MDM_DEPLOY]
|
868
|
+
elsif whole = parsed_manifest.dig('items', 0, 'metadata', 'md5-whole')
|
869
|
+
[whole, CHECKSUM_HASH_TYPE_MD5]
|
870
|
+
else
|
871
|
+
raise Jamf::MissingDataError, 'No whole-file checksum in the manifest. Must have either sha256-whole or md5-whole in the metadata'
|
872
|
+
end
|
873
|
+
end
|
874
|
+
private :manifest_checksum_for_deployment
|
875
|
+
|
876
|
+
# size in bytes is required for MDM deployments
|
877
|
+
# @return [Integer] the size in bytes in the manifest for MDM deployments
|
878
|
+
#####################################
|
879
|
+
def manifest_size_for_deployment(parsed_manifest)
|
880
|
+
size = parsed_manifest.dig 'items', 0, 'metadata', 'sizeInBytes'
|
881
|
+
raise Jamf::MissingDataError, 'No sizeInBytes in the manifest metadata' unless size
|
882
|
+
|
883
|
+
size
|
884
|
+
end
|
885
|
+
private :manifest_size_for_deployment
|
886
|
+
|
887
|
+
# bundle identifier is required for MDM deployments
|
888
|
+
# @return [String] the bundle identifier in the manifest for MDM deployments
|
889
|
+
#####################################
|
890
|
+
def manifest_bundle_identifier_for_deployment(parsed_manifest)
|
891
|
+
bid = parsed_manifest.dig 'items', 0, 'metadata', 'bundle-identifier'
|
892
|
+
raise Jamf::MissingDataError, 'No bundle-identifier in the manifest metadata' unless bid
|
893
|
+
|
894
|
+
bid
|
895
|
+
end
|
896
|
+
private :manifest_bundle_identifier_for_deployment
|
897
|
+
|
898
|
+
# bundle version is required for MDM deployments
|
899
|
+
# @return [String] the bundle version in the manifest for MDM deployments
|
900
|
+
#####################################
|
901
|
+
def manifest_bundle_version_for_deployment(parsed_manifest)
|
902
|
+
bv = parsed_manifest.dig 'items', 0, 'metadata', 'bundle-version'
|
903
|
+
raise Jamf::MissingDataError, 'No bundle-version in the manifest metadata' unless bv
|
904
|
+
|
905
|
+
bv
|
906
|
+
end
|
907
|
+
private :manifest_bundle_version_for_deployment
|
908
|
+
|
909
|
+
# title is required for MDM deployments
|
910
|
+
# @return [String] the title in the manifest for MDM deployments
|
911
|
+
#####################################
|
912
|
+
def manifest_title_for_deployment(parsed_manifest)
|
913
|
+
ttl = parsed_manifest.dig 'items', 0, 'metadata', 'title'
|
914
|
+
raise Jamf::MissingDataError, 'No title in the manifest metadata' unless ttl
|
915
|
+
|
916
|
+
ttl
|
917
|
+
end
|
918
|
+
private :manifest_title_for_deployment
|
919
|
+
|
920
|
+
# set the optional values for the MDM deployment manifest
|
921
|
+
# @return [void]
|
922
|
+
#####################################
|
923
|
+
def set_optional_mdm_manifest_values(parsed_manifest, mdm_manifest)
|
924
|
+
# subtitle is optional for MDM deployments
|
925
|
+
sttl = parsed_manifest.dig 'items', 0, 'metadata', 'subtitle'
|
926
|
+
mdm_manifest['subtitle'] = sttl if sttl
|
927
|
+
|
928
|
+
# Images are optional for MDM deployments
|
929
|
+
parsed_manifest['items'][0]['assets']&.each do |asset|
|
930
|
+
mdm_manifest['fullSizeImageURL'] = asset['url'] if asset['kind'] == 'full-size-image'
|
931
|
+
mdm_manifest['displayImageURL'] = asset['url'] if asset['kind'] == 'display-image'
|
932
|
+
end
|
933
|
+
end
|
934
|
+
private :set_optional_mdm_manifest_values
|
935
|
+
|
722
936
|
end # class
|
723
937
|
|
724
938
|
end # module
|