xolo-server 2.2.4 → 2.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0af0f8b82fade2b7a8d3c65dedf4146e00e9adba56b7c553506a072b4942fcdb
4
- data.tar.gz: f351cb8a10515a30b851490f77b64067f9485783a5ea0522c0ddf739f5a2ea25
3
+ metadata.gz: e78577a11f1d65aba560ec5540c3a79acdfc7d6a491060e256bb9e2da5a057d9
4
+ data.tar.gz: 9e7e776f48e8e9e260bc41a9090603bbfc41d1dad7dd62fc00396ce9914450cb
5
5
  SHA512:
6
- metadata.gz: 9575c70693bbc8acf6abfb662e7d535a416dcb1bf32dfa69614194017011247ebcf8e4552f987952d484e30bca490100de0e311942eb9c18cf0bb2d7129ccb31
7
- data.tar.gz: 1a3ce31608e7fe9d62fe86465a8c8c686c6caec1d44062f2fce899e8e6ccc56ee353adf4b84ac834b8aa500d30c1a9bbe7e222400742609a1df3856131b87432
6
+ metadata.gz: b83f99bda3666a2fd124241a26882499c393a75b3289fb503bdcb6ac994827228b5f813acc79a7a81f437f879b2e9aaca727800ddd711f17b2713d7a45a98738
7
+ data.tar.gz: 05bb86ec68010bf2258853983f093936ffa735c52144b6760c64177621a971bdf93823a46562a4b347c5a080d5206900a39ff8b6019e7fb1fa0cf0b400e4336e
data/data/client/xolo CHANGED
@@ -27,6 +27,9 @@ zmodload zsh/zutil
27
27
  ###############################
28
28
  ###############################
29
29
 
30
+ # just in case
31
+ export PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/libexec:$PATH"
32
+
30
33
  # Needed for the UTF-8 chars in the lsreg output
31
34
  export LANG="en_US.UTF-8"
32
35
  export LC_ALL="en_US.UTF-8"
@@ -356,42 +359,43 @@ function debug() {
356
359
  debugging_on && echo "DEBUG: $*" 1>&2
357
360
  }
358
361
 
359
- # Gather all installed bundle ids and installed versions from lsreg
362
+ # Gather all installed bundle ids and installed versions from system_profiler
360
363
  # store them in an associative array in $installed_apps.
361
364
  # keys are bundle ids, values are app name & installed version
362
365
  # separated by a semicolon
363
366
  # e.g. 'com.apple.Safari => Safari.app;14.0.3'
364
367
  ###############################
365
368
  function get_installed_apps() {
369
+ # debug "PATH is $PATH"
366
370
  debug "Getting all installed .apps on this Mac..."
367
371
  local app_name
368
372
  local app_bundle_id
369
373
  local app_vers
374
+ local app_plist
370
375
 
371
- # loop thru lsreg output
372
- "$LSREG" -dump Bundle | while IFS= read -r line ; do
373
- # a line if ------ starts a new record
374
- if [[ "$line" =~ '^-+$' ]] ; then
375
- unset app_name
376
- unset app_bundle_id
377
- unset app_vers
378
- continue
379
- fi
376
+ json_app_data=$(/usr/sbin/system_profiler -json SPApplicationsDataType )
377
+
378
+ apps_to_look_at=$(echo "$json_app_data" | grep '"path"' | cut -d'"' -f4 | grep -v '^/System/')
379
+
380
+ for app_path in ${(f)apps_to_look_at} ; do
381
+ app_name=$(/usr/bin/basename "$app_path")
382
+ app_plist="$app_path/Contents/Info.plist"
380
383
 
381
- # $MATCH is the whole matched string, $match is the array of captures
382
- # NOTE this only works if the path is listed before the CFBundleIdentifier
383
- # which seems to be the case in the lsreg output
384
- [[ "$line" =~ '^path:[[:space:]]+/.*/(.+\.app) \(' ]] && app_name=$match[1]
385
- [[ "$line" =~ '^[[:space:]]+CFBundleIdentifier = \"(.+)\";' ]] && app_bundle_id=$match[1]
386
- [[ "$line" =~ '^[[:space:]]+CFBundleShortVersionString = \"(.+)\";' ]] && app_vers=$match[1]
384
+ if [[ -f "$app_plist" ]] ; then
385
+ app_bundle_id=$(/usr/bin/plutil -extract CFBundleIdentifier raw "$app_plist" 2>/dev/null)
386
+
387
+ app_vers=$(/usr/bin/plutil -extract CFBundleShortVersionString raw "$app_plist" 2>/dev/null)
388
+
389
+ # Use CFBundleVersion if no CFBundleShortVersionString
390
+ [[ -z "$app_vers" ]] && \
391
+ app_vers=$(/usr/bin/plutil -extract CFBundleVersion raw "$app_plist" 2>/dev/null)
387
392
 
388
- if [[ -n "$app_name" && -n "$app_bundle_id" && -n "$app_vers" ]] ; then
389
393
  installed_apps[$app_bundle_id]="$app_name;$app_vers"
390
- unset app_name
391
- unset app_bundle_id
392
- unset app_vers
394
+ else
395
+ debug "App Path '$app_path' has no Info.plist"
393
396
  fi
394
397
  done
398
+
395
399
  # installed_apps is now an associative array with bundle ids as keys and app names as values
396
400
 
397
401
  # print the installed apps - this is a long list
@@ -402,8 +406,70 @@ function get_installed_apps() {
402
406
  done
403
407
  fi
404
408
 
409
+ # debug "PATH is $PATH"
405
410
  } # end installed_apps
406
411
 
412
+ ########################################
413
+ ########################################
414
+ ########################################
415
+ ########################################
416
+ ########################################
417
+ ########################################
418
+ # Gather all installed bundle ids and installed versions from lsreg
419
+ # store them in an associative array in $installed_apps.
420
+ # keys are bundle ids, values are app name & installed version
421
+ # separated by a semicolon
422
+ # e.g. 'com.apple.Safari => Safari.app;14.0.3'
423
+ ###############################
424
+ # function get_installed_apps() {
425
+ # debug "Getting all installed .apps on this Mac..."
426
+ # local app_name
427
+ # local app_bundle_id
428
+ # local app_vers
429
+
430
+ # # loop thru lsreg output
431
+ # "$LSREG" -dump Bundle | while IFS= read -r line ; do
432
+ # # a line if ------ starts a new record
433
+ # if [[ "$line" =~ '^-+$' ]] ; then
434
+ # unset app_name
435
+ # unset app_bundle_id
436
+ # unset app_vers
437
+ # continue
438
+ # fi
439
+
440
+ # # $MATCH is the whole matched string, $match is the array of captures
441
+ # # NOTE this only works if the path is listed before the CFBundleIdentifier
442
+ # # which seems to be the case in the lsreg output
443
+ # [[ "$line" =~ '^path:[[:space:]]+/.*/(.+\.app) \(' ]] && app_name=$match[1]
444
+ # [[ "$line" =~ '^[[:space:]]+CFBundleIdentifier = \"(.+)\";' ]] && app_bundle_id=$match[1]
445
+ # [[ "$line" =~ '^[[:space:]]+CFBundleShortVersionString = \"(.+)\";' ]] && app_vers=$match[1]
446
+
447
+ # if [[ -n "$app_name" && -n "$app_bundle_id" && -n "$app_vers" ]] ; then
448
+ # installed_apps[$app_bundle_id]="$app_name;$app_vers"
449
+ # unset app_name
450
+ # unset app_bundle_id
451
+ # unset app_vers
452
+ # fi
453
+ # done
454
+ # # installed_apps is now an associative array with bundle ids as keys and app names as values
455
+
456
+ # # print the installed apps - this is a long list
457
+ # if debugging_on ; then
458
+ # debug "All installed .apps on this Mac:"
459
+ # for bundle app in ${(kv)installed_apps}; do
460
+ # debug "'$bundle' -> '$app'"
461
+ # done
462
+ # fi
463
+
464
+ # } # end installed_apps
465
+ ########################################
466
+ ########################################
467
+ ########################################
468
+ ########################################
469
+ ########################################
470
+ ########################################
471
+ ########################################
472
+
407
473
  # Extract data from the client-data.json file
408
474
  #
409
475
  # TODO: Once we only support macOS 15 (Sequoia) and higher, we
@@ -463,7 +529,7 @@ function all_xolo_titles() {
463
529
  read -r -d '' jscode <<ENDJAVASCRIPT
464
530
  result = Object.keys(parsed_data.titles).join('\n');
465
531
  ENDJAVASCRIPT
466
- extract_json_data "$jscode" | sort
532
+ extract_json_data "$jscode" | /usr/bin/sort
467
533
  }
468
534
 
469
535
  # Outputs all known titles, one per line, with versions and statuses
@@ -1020,12 +1086,15 @@ function list_installed_titles() {
1020
1086
  local ttl
1021
1087
  local app_data
1022
1088
 
1023
-
1024
1089
  verbose "Locating installed titles..."
1025
1090
 
1026
1091
  # populate the installed_apps associative array
1027
1092
  get_installed_apps
1028
1093
 
1094
+ # gather output here, display it at the end
1095
+ # rather than interspersed with debug lines
1096
+ installed_titles_report=""
1097
+
1029
1098
  while IFS= read -r ttl; do
1030
1099
  app_data=$(app_data_for_title $ttl)
1031
1100
 
@@ -1036,6 +1105,8 @@ function list_installed_titles() {
1036
1105
  display_title_if_installed_by_version_script $ttl
1037
1106
  fi
1038
1107
  done <<<"$(all_xolo_titles)"
1108
+
1109
+ say "$installed_titles_report"
1039
1110
  return 0
1040
1111
  }
1041
1112
 
@@ -1075,9 +1146,9 @@ function display_title_if_installed_by_app_data() {
1075
1146
  [[ "$inst_app_name" == "$app_name" ]] || return
1076
1147
 
1077
1148
  if [[ -n "$no_versions" ]] ; then
1078
- echo $ttl
1149
+ installed_titles_report="$installed_titles_report\n$ttl"
1079
1150
  else
1080
- echo "$ttl ($inst_app_vers)"
1151
+ installed_titles_report="$installed_titles_report\n$ttl ($inst_app_vers)"
1081
1152
  fi
1082
1153
  }
1083
1154
 
@@ -1114,9 +1185,9 @@ function display_title_if_installed_by_version_script() {
1114
1185
  [[ -n "$app_vers" ]] || return
1115
1186
 
1116
1187
  if [[ -n "$no_versions" ]] ; then
1117
- echo $ttl
1188
+ installed_titles_report="$installed_titles_report\n$ttl"
1118
1189
  else
1119
- echo "$ttl ($app_vers)"
1190
+ installed_titles_report="$installed_titles_report\n$ttl ($inst_app_vers)"
1120
1191
  fi
1121
1192
  }
1122
1193
 
@@ -12,7 +12,7 @@ module Xolo
12
12
 
13
13
  module Version
14
14
 
15
- VERSION = '2.2.4'.freeze
15
+ VERSION = '2.3.0'.freeze
16
16
 
17
17
  end
18
18
 
@@ -108,14 +108,14 @@ module Xolo
108
108
  @maint_timer_task
109
109
  end
110
110
 
111
- # When was our last maint?
111
+ # When was our last automated maint?
112
112
  # @return [Time] the time of the last maint, or the epoch if never
113
113
  ######################################
114
114
  def self.last_maint
115
115
  @last_maint ||= Time.at(0)
116
116
  end
117
117
 
118
- # Set the time of the last maint
118
+ # Set the time of the last maint, if it was automated
119
119
  # @param time [Time] the time of the last maint
120
120
  # @return [Time] the time of the last maint
121
121
  ######################################
@@ -153,7 +153,7 @@ module Xolo
153
153
  Xolo::Server.logger.info 'Maint: Starting nightly run now'
154
154
 
155
155
  else
156
- Xolo::Server.logger.info "Maint: Not starting, it isn't time"
156
+ Xolo::Server.logger.debug "Maint: Not starting, it isn't time"
157
157
  return
158
158
  end
159
159
 
@@ -195,13 +195,16 @@ module Xolo
195
195
 
196
196
  # add new maintenance tasks/methods here
197
197
  ######
198
+ update_ssl_cert_and_key
198
199
  accept_title_editor_eas title_objects_for_maint
199
200
  auto_release_versions title_objects_for_maint
200
201
  cleanup_versions title_objects_for_maint
201
202
  notify_admins_of_unreleased_pilots title_objects_for_maint
202
203
 
203
- # make note of the time.
204
- Xolo::Server::Helpers::Maintenance.last_maint = Time.now
204
+ # make note of the time, but only for automated runs.
205
+ # Manual runs don't affect this.
206
+ Xolo::Server::Helpers::Maintenance.last_maint = Time.now unless @manual_maintenance
207
+
205
208
  log_info 'Maint: complete'
206
209
 
207
210
  log_debug 'Maint: running update_client_data after all tasks'
@@ -210,6 +213,51 @@ module Xolo
210
213
  mutex&.unlock
211
214
  end
212
215
 
216
+ # Re-fetch the SSL certificate and key, as defined in the server config,
217
+ # and compare to the current values. If they are different, save and activate
218
+ # the new ones.
219
+ #
220
+ # NOTE, to get the current values we read the active files from disk,
221
+ # not the value in memory in the Xolo::Server.config object.
222
+ # In other words we use this:
223
+ # curr_crt = Xolo::Server::Configuration::SSL_CERT_FILE.read.strip
224
+ # Not this:
225
+ # curr_crt = Xolo::Server.config.ssl_cert
226
+ # This is because the file contents are what get sent to the https clients,
227
+ # so that's what matters.
228
+ # We do however update the in-memory value if an update is needed, just in case.
229
+ ######################################
230
+ def update_ssl_cert_and_key
231
+ log_info 'Maint: Checking if SSL Certificate & Key need updating.'
232
+ update = false
233
+
234
+ # check the cert
235
+ new_crt_src = Xolo::Server.config.raw_data[:ssl_cert]
236
+ log_debug "Maint: Re-fetching SSL Certificate from: #{new_crt_src}"
237
+ new_crt = Xolo::Server.config.data_from_command_file_or_string(new_crt_src).strip
238
+ curr_crt = Xolo::Server::Configuration::SSL_CERT_FILE.read.strip
239
+ update = true unless new_crt == curr_crt
240
+
241
+ # check the key
242
+ new_key_src = Xolo::Server.config.raw_data[:ssl_key]
243
+ log_debug "Maint: Re-fetching SSL Private Key from: #{new_key_src}"
244
+ new_key = Xolo::Server.config.data_from_command_file_or_string(new_key_src).strip
245
+ curr_key = Xolo::Server::Configuration::SSL_KEY_FILE.read.strip
246
+ update = true unless new_key == curr_key
247
+
248
+ if update
249
+ log_info 'Maint: SSL Certificate or Key has been updated, installing...'
250
+ Xolo::Server.config.ssl_cert = new_crt
251
+ Xolo::Server.config.ssl_key = new_key
252
+ Xolo::Server::Configuration::SSL_CERT_FILE.pix_save new_crt
253
+ Xolo::Server::Configuration::SSL_KEY_FILE.pix_save new_key
254
+ else
255
+ log_debug 'Maint: SSL Certificate and Private Key are unchanged.'
256
+ end
257
+
258
+ log_info 'Maint: Done Checking if SSL Certificate & Key.'
259
+ end
260
+
213
261
  # look for any titles that need their Title Editor EA's accepted,
214
262
  # and auto accept them if we need to
215
263
  # @return [void]
@@ -91,7 +91,7 @@ module Xolo
91
91
  new_version: new_version
92
92
  )
93
93
  else
94
- log_debug "Title '#{title_name}' ID #{title_id} is not a subscribed title in Xolo. Ignoring webhook."
94
+ log_debug "Title '#{title_name}' ID #{title_id} is not a subscribed title. Ignoring webhook."
95
95
  end
96
96
  rescue => e
97
97
  msg = "Error processing PatchSoftwareTitleUpdated webhook event: #{e.class}: #{e}"
@@ -101,21 +101,6 @@ module Xolo
101
101
  end # thread
102
102
  end
103
103
 
104
- # TODO: Delete this method after confirming we don't want it
105
- # It wasn't in use when it was commented out.
106
- #
107
- # Subscribe to a title on a given patch source.
108
- # @param source_id [Integer] the id or name of the patch source in Jamf
109
- # @param name_id [Integer] the name_id of the title on that patch source
110
- # @param display_name [String] an display name for the title
111
- # @return [Integer] the id of the new subscribed title, or false on failure
112
- #####################################
113
- # def subscribe_to_title(source_id:, name_id:, display_name:)
114
- # new_sub = Jamf::PatchTitle.create name: display_name, source_id: source_id, name_id: name_id, cnx: jamf_cnx
115
-
116
- # new_sub.save
117
- # end
118
-
119
104
  end # Subscriptions
120
105
 
121
106
  end # Helpers
@@ -119,17 +119,17 @@ module Xolo
119
119
 
120
120
  # the capabilites
121
121
  stub_patch.capabilities.add_criterion(
122
- # Use the title as the name, so it matches all the future versions/patches
123
- # avoiding a warning message in the TEd gui.
124
- # name: Xolo::Server::Version::STUB_PATCH_CAPABILITY_CRITERION_NAME,
125
- name: title,
122
+ name: Xolo::Server::Version::STUB_PATCH_CAPABILITY_CRITERION_NAME,
126
123
  operator: Xolo::Server::Version::STUB_PATCH_CAPABILITY_CRITERION_OPERATOR,
127
124
  value: Xolo::Server::Version::STUB_PATCH_CAPABILITY_CRITERION_VALUE
128
125
  )
129
126
 
130
127
  # the component
131
128
  stub_patch.add_component(
132
- name: Xolo::Server::Version::STUB_PATCH_COMPONENT_NAME,
129
+ # Use the title as the name, so it matches all the future versions/patches
130
+ # avoiding a warning message in the TEd gui.
131
+ # name: Xolo::Server::Version::STUB_PATCH_COMPONENT_NAME,
132
+ name: title,
133
133
  version: Xolo::Server::Version::STUB_PATCH_VERSION
134
134
  )
135
135
 
@@ -51,7 +51,7 @@ module Xolo
51
51
  start_time: Xolo::Server.start_time,
52
52
  uptime: uptime_secs.pix_humanize_secs,
53
53
  uptime_secs: uptime_secs,
54
- last_maint: Xolo::Server::Helpers::Maintenance.last_maint,
54
+ last_automated_maint: Xolo::Server::Helpers::Maintenance.last_maint,
55
55
  app_env: Xolo::Server.app_env,
56
56
  test_server: Xolo::Server.test_server?,
57
57
  data_dir: Xolo::Server::DATA_DIR,
@@ -71,6 +71,14 @@ module Xolo
71
71
  }
72
72
 
73
73
  if params[:extended]
74
+ ssl_cert_data ||= OpenSSL::X509::Certificate.new(Xolo::Server::Configuration::SSL_CERT_FILE.read)
75
+ state[:ssl_cert_subject] = ssl_cert_data.subject
76
+ state[:ssl_cert_issuer] = ssl_cert_data.issuer
77
+ state[:ssl_cert_valid_from] = ssl_cert_data.not_before.localtime
78
+ state[:ssl_cert_expires] = ssl_cert_data.not_after.localtime
79
+ state[:ssl_cert_serial] = ssl_cert_data.serial
80
+ state[:ssl_cert_signature_algorithm] = ssl_cert_data.signature_algorithm
81
+
74
82
  state[:gem_path] = Gem.paths.path
75
83
  state[:load_path] = $LOAD_PATH
76
84
  state[:object_locks] = Xolo::Server.object_locks
@@ -98,6 +106,8 @@ module Xolo
98
106
  # run the maintenance process manually from a server admin via xadm
99
107
  ################
100
108
  post '/maint/maint-start' do
109
+ @manual_maintenance = true
110
+
101
111
  log_info "Starting manual server maintenance by #{session[:admin]}"
102
112
 
103
113
  session[:admin] = "Maintenance by #{session[:admin]}"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xolo-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.4
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Lasell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-24 00:00:00.000000000 Z
11
+ date: 2026-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday