xolo-admin 1.0.1 → 2.0.2

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: cbba7b8d84c902f3a3683808708db421ec8a3a1759aaee8e349da02a54b3c45e
4
- data.tar.gz: 741dcbf5fc8c4df15c2043ea28d467093e56dc56747956b109f994e177e2cce0
3
+ metadata.gz: 78c42e6fb9e17f593f77705e340642273e4f83d70234a809fdef98101555cbe0
4
+ data.tar.gz: 54286e2ebccf3dbb76e28d9916da8b593792ccd1691aaebc0ff31f5313d4a6b4
5
5
  SHA512:
6
- metadata.gz: e1617d119ebb27e0785a7ebe1201f2fc96244834c5145ae4a9a810a33a951a4f30c6dc2593d60283b489f6f4d2f2110c81454e383033e25f2001d24aeeb9a2a6
7
- data.tar.gz: 381ac12e8bcee2955b22b1610b661b63764fc04f5b123a2ae85d468add291f2831b1c1a8cbc1282df0b81c8238a204849b909f2ac4fd2ed9bb54f7db1f439926
6
+ metadata.gz: e43eb8c13033590db47a1b3a8a51480956ee606f5f59a2f857ae38f9e382abb1a4b29f9213c8df4131ca53937553ad09ecea7262df7f3b1a5cbd96b16ab8d0b8
7
+ data.tar.gz: 9ad24a86d2248d8767aa9c088129071f6d3fdc2aebff88c544584eefa2e1f274e1488dffc601c463727d2131694f33ab8f7a87da12bfb998cea26a0069b93954
data/bin/xadm CHANGED
@@ -19,8 +19,11 @@ class XoloAdmin
19
19
  #####################################
20
20
 
21
21
  include Xolo::Admin
22
+
22
23
  include Xolo::Core::JSONWrappers
23
24
  include Xolo::Core::Output
25
+ include Xolo::Core::SecurityCmd
26
+
24
27
  include Xolo::Admin::CommandLine
25
28
  include Xolo::Admin::Connection
26
29
  include Xolo::Admin::Processing
data/data/client/xolo CHANGED
@@ -14,9 +14,12 @@
14
14
  zmodload zsh/zutil
15
15
 
16
16
  # for perl-style regexps
17
- # DISABLED FOR NOW - some versions of macos don't seem to have
18
- # /usr/lib/zsh/5.9/zsh/pcre.so
19
- # All our regexps now use posix style
17
+ #
18
+ # DISABLED FOR NOW - macOS before 15 Sequoia doesn't have the pcre module,
19
+ # and we want to support 14 Sonoma for now.
20
+ # The file required is /usr/lib/zsh/5.9/zsh/pcre.so
21
+ #
22
+ # Until then, all our regexps now use posix style
20
23
  #
21
24
  # setopt RE_MATCH_PCRE
22
25
 
@@ -37,10 +40,10 @@ export LC_ALL="en_US.UTF-8"
37
40
  XOLO_VERSION="0.0.0"
38
41
 
39
42
  # The usage message for xolo
40
- USAGE='xolo [options] <command> [<title> [<version>]]'
43
+ USAGE='xolo [options] <command> [ title1[=version1] [ title2[=version2] ... ]]'
41
44
 
42
45
  # The URL for more information about xolo
43
- XOLO_DOX_URL='<URL TO BE DETERMINED>'
46
+ XOLO_DOX_URL='https://pixaranimationstudios.github.io/xolo-home/'
44
47
 
45
48
  # The long path to the lsregister command
46
49
  LSREG='/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister'
@@ -54,6 +57,25 @@ CLIENT_DATA_JSON_FILE="/Library/Application Support/xolo/client-data.json"
54
57
  # The jamf policy trigger to update the client data
55
58
  UPDATE_CLIENT_DATA_TRIGGER='update-xolo-client-data'
56
59
 
60
+ # In the CLI args, titles and versions are separated by the first
61
+ # occurrence of the equals sign
62
+ TITLE_VERSION_SEPARATOR='='
63
+
64
+
65
+ # These commands must be run as root
66
+ ROOT_COMMANDS=(
67
+ install
68
+ i
69
+ uninstall
70
+ u
71
+ update
72
+ U
73
+ refresh
74
+ r
75
+ expire
76
+ e
77
+ )
78
+
57
79
  # GLOBAL VARIABLES
58
80
  ###############################
59
81
  ###############################
@@ -63,13 +85,13 @@ UPDATE_CLIENT_DATA_TRIGGER='update-xolo-client-data'
63
85
  # options
64
86
  show_help=
65
87
  be_verbose=
66
- be_quiet=
67
88
  debugging_on=
68
89
  no_versions=
69
90
  show_xolo_version=
70
91
 
71
92
  # arguments
72
93
  command=
94
+ targets=
73
95
  title=
74
96
  version=
75
97
 
@@ -92,10 +114,18 @@ function die() {
92
114
  local mystat=1
93
115
 
94
116
  [[ -n "$2" ]] && mystat=$2
95
- echoerr "$msg"
117
+ echoerr "ERROR: $msg"
96
118
  exit $mystat
97
119
  }
98
120
 
121
+ # Die if not root and the command being run is in the list of root commands
122
+ #################################
123
+ function must_be_root() {
124
+ if (( $ROOT_COMMANDS[(Ie)$command] )); then
125
+ [[ $EUID -ne 0 ]] && die "You must be root to use the '$command' command."
126
+ fi
127
+ return 0
128
+ }
99
129
 
100
130
  # Show the help message
101
131
  ###############################
@@ -109,8 +139,8 @@ Usage:
109
139
  Options:
110
140
  -h, -H, --help: Show this help message.
111
141
  -v, --verbose: Enable verbose mode, extra information will be printed.
112
- -q, --quiet: Enable quiet mode, only errors will be printed to stderr.
113
142
  -d, --debug: Enable debug mode, extra debug information will be printed.
143
+ Implies --verbose.
114
144
  -r, --recon: With 'install' or 'uninstall' run a 'jamf recon' after the
115
145
  operation completes successfully.
116
146
  -n, --no-versions: With the 'list-titles' and 'list-installed' commands,
@@ -118,15 +148,12 @@ Options:
118
148
  installed, respectively.
119
149
  -V, --version: Show the version of xolo.
120
150
 
121
- NOTE: Debug mode will also enable verbose mode. Both debug and verbose modes
122
- override quiet mode.
123
-
124
151
  Commands:
125
- install, i <title> [<version>]
152
+ install, i <title>[=<version>] [<title2>[=<version2>] ...]
126
153
  Install a title, or specific version thereof (e.g. a version currently in pilot)
127
154
  If no version is specified, the currently released version will be installed.
128
155
 
129
- uninstall, u <title>
156
+ uninstall, u <title> [<title2> ...]
130
157
  Uninstall a title, if possible. Not all titles are uninstallable via xolo.
131
158
 
132
159
  update, U
@@ -150,8 +177,10 @@ Commands:
150
177
  a few moments, since all titles with version scripts will run those scripts
151
178
  to see if they are installed.
152
179
 
153
- details, d <title> [<version>]
154
- Show detailed information about a title, or a specific version thereof.
180
+ details, d <title>[=<version>] [<title2>[=<version2>] ...]
181
+ Show detailed information about titles, or a specific versions thereof.
182
+ Note that titles and versions contain different sets of information, so the output
183
+ will differ depending on what you specify.
155
184
 
156
185
  expire, e
157
186
  Expire the given title if it has not been used in its defined expiration period.
@@ -161,6 +190,26 @@ Commands:
161
190
  help, h
162
191
  Show this help message. The same as -h or --help.
163
192
 
193
+ Examples:
194
+ xolo install transmogrifier
195
+ Installs the currently released version of the title "transmogrifier".
196
+
197
+ xolo install laserbeam transmogrifier=2.0
198
+ Installs the currently released version of the title "laserbeam" and version 2.0 of
199
+ the title "transmogrifier", if it is in pilot or already released.
200
+
201
+ xolo uninstall transmogrifier laserbeam
202
+ Uninstalls the titles "transmogrifier" and "laserbeam, if they are uninstallable via
203
+ xolo and currently installed. Note that versions are ignored for uninstalling, since
204
+ only one version of a title can be installed at a time.
205
+
206
+ xolo list-titles
207
+ Lists all titles known to xolo, with their versions and statuses.
208
+
209
+ xolo details laserbeam transmogrifier=2.0
210
+ Shows detailed information about the title "laserbeam" and version 2.0 of the title
211
+ "transmogrifier".
212
+
164
213
  For more information about xolo, see $XOLO_DOX_URL
165
214
  ENDHELP
166
215
  } # end show_help
@@ -171,7 +220,6 @@ function parse_cli() {
171
220
  zparseopts -D -F -E -- \
172
221
  {h,H,-help}=show_help \
173
222
  {v,-verbose}=be_verbose \
174
- {q,-quiet}=be_quiet \
175
223
  {d,-debug}=debugging_on \
176
224
  {n,-no-versions}=no_versions \
177
225
  {r,-recon}=do_recon \
@@ -181,7 +229,6 @@ function parse_cli() {
181
229
  # they are in arrays, but we want regular vars
182
230
  show_help=$show_help[-1]
183
231
  be_verbose=$be_verbose[-1]
184
- be_quiet=$be_quiet[-1]
185
232
  debugging_on=$debugging_on[-1]
186
233
  no_versions=$no_versions[-1]
187
234
  do_recon=$do_recon[-1]
@@ -190,37 +237,43 @@ function parse_cli() {
190
237
  # if debugging is on, verbose is also on
191
238
  [[ -n $debugging_on ]] && be_verbose=1
192
239
 
193
- # if we're in verbose mode, we're not in quiet mode
194
- [[ -n $be_verbose ]] && unset be_quiet
195
-
196
240
  command=$1
197
241
  [[ ${#@} -gt 0 ]] && shift
198
242
 
199
- title=$1
200
- [[ ${#@} -gt 0 ]] && shift
201
-
202
- version=$1
203
-
204
- # echo "show_help is: $show_help"
205
- # echo "be_verbose is: $be_verbose"
206
- # echo "be_quiet is: $be_quiet"
207
- # echo "debugging_on is: $debugging_on"
208
- # echo "command is: $command"
209
- # echo "title is: $title"
210
- # echo "version is: $version"
211
-
243
+ targets=("${(@)@}")
212
244
 
213
245
  debug "Parsed command line:"
214
246
  debug "..show_help is: $show_help"
215
247
  debug "..be_verbose is: $be_verbose"
216
- debug "..be_quiet is: $be_quiet"
217
248
  debug "..debugging_on is: $debugging_on"
218
249
  debug "..no_versions is: $no_versions"
219
250
  debug "..show_xolo_version is: $show_xolo_version"
220
251
 
221
252
  debug "..command is: $command"
222
- debug "..title is: $title"
223
- debug "..version is: $version"
253
+ debug "..targets are: $targets"
254
+ }
255
+
256
+ # Parse a title and version from the command line, where they may be given in the form
257
+ # title or title=version
258
+ #################################
259
+ function parse_title_and_version() {
260
+ local arg=$1
261
+ debug "Parsing title and version from arg: '$arg'"
262
+
263
+ if [[ "$arg" == *"$TITLE_VERSION_SEPARATOR"* ]] ; then
264
+ # everything before the first = is title
265
+ title=${arg%%$TITLE_VERSION_SEPARATOR*}
266
+ # everything after the first = is version
267
+ version=${arg#*$TITLE_VERSION_SEPARATOR}
268
+ else
269
+ title="$arg"
270
+ version=''
271
+ fi
272
+
273
+ debug "..title is: '$title'"
274
+ debug "..version is: '$version'"
275
+
276
+ return 0
224
277
  }
225
278
 
226
279
  # quick test for debugging_on
@@ -235,16 +288,10 @@ function be_verbose() {
235
288
  [[ -n "$be_verbose" ]]
236
289
  }
237
290
 
238
- # quick test for be_quiet
239
- ###############################
240
- function be_quiet() {
241
- [[ -n "$be_quiet" ]]
242
- }
243
-
244
- # Print a message to stout if we're not in quiet mode
291
+ # Print a message to stout
245
292
  ###############################
246
293
  function say() {
247
- be_quiet || echo "$*"
294
+ echo "$*"
248
295
  }
249
296
 
250
297
  # Print a message to stdout if we're in verbose or debug mode
@@ -366,7 +413,7 @@ function all_xolo_titles() {
366
413
  read -r -d '' jscode <<ENDJAVASCRIPT
367
414
  result = Object.keys(parsed_data.titles).join('\n');
368
415
  ENDJAVASCRIPT
369
- extract_json_data "$jscode"
416
+ extract_json_data "$jscode" | sort
370
417
  }
371
418
 
372
419
  # Outputs all known titles, one per line, with versions and statuses
@@ -399,7 +446,7 @@ function all_xolo_titles_with_versions() {
399
446
  result = result.slice(0, -1);
400
447
 
401
448
  ENDJAVASCRIPT
402
- extract_json_data "$jscode"
449
+ extract_json_data "$jscode" | sort
403
450
  }
404
451
 
405
452
 
@@ -680,39 +727,24 @@ ENDJAVASCRIPT
680
727
  # Run a Jamf policy trigger
681
728
  # $1 = the policy trigger to run
682
729
  # $2 = any extra options to pass to the jamf command
683
- # be_verbose() and be_quiet() will automatically be honored
730
+ # be_verbose() will automatically be honored
684
731
  #######################################
685
732
  function run_jamf_policy_trigger() {
686
733
  local policy_trigger=$1
687
734
  local jamf_options=$2
688
735
  local jamf_verbose=''
689
- local jamf_quiet=''
690
736
  local cmd
691
737
 
692
- # debug means verbose
693
- if be_verbose ; then
694
- jamf_verbose='-verbose'
695
- else
696
- # if told to be quiet, do so
697
- if be_quiet ; then
698
- jamf_quiet=1
699
-
700
- # but if we're refreshing client data as part of
701
- # another command, always be quiet.
702
- elif [[ $policy_trigger == $UPDATE_CLIENT_DATA_TRIGGER && "$command" != 'refresh' ]] ; then
703
- jamf_quiet=1
704
- fi
705
- fi
706
-
738
+ be_verbose && jamf_verbose='-verbose'
707
739
 
708
740
  cmd="$JAMF policy -trigger $policy_trigger $jamf_options $jamf_verbose"
741
+ tempfile=$(mktemp /tmp/xolo-policy.XXXXXXXX)
742
+
709
743
  debug "Running jamf policy command: $cmd"
744
+ eval "$cmd" | tee "$tempfile"
710
745
 
711
- if [[ -n $jamf_quiet ]] ; then
712
- policy_output=$( eval "$cmd" )
713
- else
714
- policy_output=$( eval "$cmd" | tee /dev/tty )
715
- fi
746
+ policy_output=$(<"$tempfile")
747
+ rm -f "$tempfile"
716
748
 
717
749
  [[ $policy_output =~ 'Submitting log to https://' ]] && return 0
718
750
 
@@ -723,6 +755,7 @@ function run_jamf_policy_trigger() {
723
755
  # Refresh the client data
724
756
  ###############################
725
757
  function refresh_client_data() {
758
+
726
759
  # if we've already refreshed during this run, we're done
727
760
  [[ -n "$client_data_refreshed" ]] && return
728
761
 
@@ -744,8 +777,9 @@ function validate_title() {
744
777
  # die if no title given
745
778
  [[ -z "$title" ]] && die "No title given.\nUsage: $USAGE\nUse --help for more information."
746
779
 
747
- # make sure the JSON data file is up to date
748
- refresh_client_data
780
+ # make sure the JSON data file is up to date, if we are root
781
+
782
+ [[ $EUID -eq 0 ]] && refresh_client_data
749
783
 
750
784
  # die if no such title
751
785
  # all titles in an array
@@ -776,9 +810,21 @@ function validate_version() {
776
810
  version_is_valid=1
777
811
  }
778
812
 
813
+ # Install all the items on the command line, which may be titles or specific versions of titles
814
+ #################################
815
+ function install_cli_args() {
816
+ debug "Installing Targets: $targets"
817
+ for item in $targets ; do
818
+ parse_title_and_version "$item"
819
+ install
820
+ done
821
+ }
822
+
823
+
779
824
  # Install a title, or a specific version thereof
780
825
  ###############################
781
826
  function install() {
827
+
782
828
  validate_title
783
829
 
784
830
  # if no version is given, we'll find the current release
@@ -814,12 +860,25 @@ function install() {
814
860
  fi
815
861
  }
816
862
 
863
+ # uninstall CLI args, which are just titles since versions don't matter for uninstalling
864
+ ##############################
865
+ function uninstall_cli_args() {
866
+ debug "Uninstalling Targets: $targets"
867
+ for item in $targets ; do
868
+ parse_title_and_version "$item"
869
+ uninstall
870
+ done
871
+ }
872
+
817
873
  # Unnstall a title
818
874
  # This might not do anything if the title is not uninstallable,
819
875
  # or if the title is not installed
820
876
  ###############################
821
877
  function uninstall() {
822
878
  validate_title
879
+
880
+ details_for_title $title | grep -q 'Uninstallable: true' || die "Title $title is not uninstallable via xolo"
881
+
823
882
  say "Uninstalling title $title..."
824
883
 
825
884
  if run_jamf_policy_trigger "xolo-${title}-uninstall" ; then
@@ -843,8 +902,6 @@ function run_recon() {
843
902
  say 'Running jamf recon...'
844
903
  if be_verbose ; then
845
904
  $JAMF recon -verbose
846
- elif be_quiet ; then
847
- $JAMF recon &> /dev/null
848
905
  else
849
906
  $JAMF recon
850
907
  fi
@@ -861,8 +918,6 @@ function update() {
861
918
  debug "Running jamf policy..."
862
919
  if be_verbose ; then
863
920
  $JAMF policy -verbose
864
- elif be_quiet ; then
865
- $JAMF policy &> /dev/null
866
921
  else
867
922
  $JAMF policy
868
923
  fi
@@ -881,9 +936,20 @@ function list_all_titles() {
881
936
  all_xolo_titles_with_versions
882
937
  }
883
938
 
939
+ # Show detailed information about all titles, or specific versions thereof, given on the command line
940
+ ########################
941
+ function show_details_cli_args() {
942
+ debug "Showing details for targets: $targets"
943
+ for item in $targets; do
944
+ parse_title_and_version "$item"
945
+ show_details
946
+ done
947
+ }
948
+
884
949
  # Show detailed information about a title or a version thereof
885
950
  ###############################
886
951
  function show_details() {
952
+ debug "Showing details for title '$title' and version '$version'..."
887
953
  validate_title
888
954
 
889
955
  if [[ -z "$version" ]] ; then
@@ -901,7 +967,7 @@ function list_installed_titles() {
901
967
  local app_data
902
968
 
903
969
 
904
- verbose "Listing installed titles..."
970
+ verbose "Locating installed titles..."
905
971
 
906
972
  # populate the installed_apps associative array
907
973
  get_installed_apps
@@ -916,6 +982,7 @@ function list_installed_titles() {
916
982
  display_title_if_installed_by_version_script $ttl
917
983
  fi
918
984
  done <<<"$(all_xolo_titles)"
985
+ return 0
919
986
  }
920
987
 
921
988
  # given a title and some app data (name, bundle id)
@@ -1081,6 +1148,9 @@ function expire() {
1081
1148
  uninstall
1082
1149
  }
1083
1150
 
1151
+
1152
+
1153
+
1084
1154
  # MAIN
1085
1155
  ###############################
1086
1156
  ###############################
@@ -1109,14 +1179,17 @@ function main() {
1109
1179
 
1110
1180
  [[ -z "$command" ]] && die "No command given.\nUsage: $USAGE\nUse --help for more information."
1111
1181
 
1182
+ # confirm we are root for those commands that need it
1183
+ must_be_root
1184
+
1112
1185
  case "$command" in
1113
1186
  install|i)
1114
1187
  debug "processing command 'install'"
1115
- install
1188
+ install_cli_args
1116
1189
  ;;
1117
1190
  uninstall|u)
1118
1191
  debug "processing command 'uninstall'"
1119
- uninstall
1192
+ uninstall_cli_args
1120
1193
  ;;
1121
1194
  update|U)
1122
1195
  debug "processing command 'update'"
@@ -1138,7 +1211,7 @@ function main() {
1138
1211
  ;;
1139
1212
  details|d)
1140
1213
  debug "processing command 'details'"
1141
- show_details
1214
+ show_details_cli_args
1142
1215
  ;;
1143
1216
  expire|e)
1144
1217
  debug "processing command 'expire'"
@@ -1157,4 +1230,4 @@ function main() {
1157
1230
 
1158
1231
  # RUN!
1159
1232
  ###########################
1160
- main "$@"
1233
+ main "$@"
@@ -333,7 +333,7 @@ module Xolo
333
333
  vers_cmd = version_command?
334
334
  title_or_vers_command = title_or_version_command?
335
335
  add_command = add_command?
336
- edit_command?
336
+ edit_command = edit_command?
337
337
  arg_banner = Xolo::Admin::Options::COMMANDS.dig(cmd, :arg_banner)
338
338
  arg_banner ||= Xolo::Admin::Options::DFT_CMD_TITLE_ARG_BANNER
339
339
 
@@ -370,12 +370,25 @@ module Xolo
370
370
  cmd_opts.each do |opt_key, deets|
371
371
  next unless deets[:cli]
372
372
 
373
+ desc = deets[:desc]
374
+
373
375
  # Required opts are only required when adding.
374
376
  # when editing, they should already exist
375
- required = deets[:required] && add_command
376
-
377
- desc = deets[:desc]
378
- desc = "#{desc}REQUIRED" if required
377
+ if add_command
378
+ if deets[:edit_only]
379
+ next
380
+ elsif deets[:required]
381
+ desc = "#{desc}REQUIRED"
382
+ required = true
383
+ elsif deets[:title_type]
384
+ desc = "#{desc}Only used with #{deets[:title_type]} titles."
385
+ required = deets[:required]
386
+ else
387
+ required = false
388
+ end
389
+ end
390
+
391
+ next if edit_command && deets[:add_only]
379
392
 
380
393
  # booleans are CLI flags defaulting to false
381
394
  # everything else is a string that we will convert as we validate later
@@ -20,6 +20,7 @@ module Xolo
20
20
  ##############################
21
21
 
22
22
  TIMEOUT = 300
23
+ UPLOAD_TIMEOUT = 1800
23
24
  OPEN_TIMEOUT = 10
24
25
 
25
26
  PING_ROUTE = '/ping'
@@ -76,7 +77,8 @@ module Xolo
76
77
  raise Xolo::ServerError, "#{resp.status}: #{resp.body}"
77
78
  end
78
79
  rescue Faraday::UnauthorizedError
79
- raise Xolo::AuthenticationError, 'Invalid username or password'
80
+ msg = "Invalid username or password. If you recently changed your Jamf Pro password, please update it using 'xadm config'."
81
+ raise Xolo::AuthenticationError, msg
80
82
  end
81
83
 
82
84
  # @return [Hash] the SSL options for Faraday connections
@@ -180,7 +182,7 @@ module Xolo
180
182
  return @upload_cnx if @upload_cnx
181
183
 
182
184
  @upload_cnx = Faraday.new(server_url(host: host), ssl: ssl_opts) do |cnx|
183
- cnx.options[:timeout] = TIMEOUT
185
+ cnx.options[:timeout] = UPLOAD_TIMEOUT
184
186
  cnx.options[:open_timeout] = OPEN_TIMEOUT
185
187
 
186
188
  cnx.request :multipart