diff --git a/Installomator.sh b/Installomator.sh index 81b56c7..49b3924 100755 --- a/Installomator.sh +++ b/Installomator.sh @@ -20,9 +20,11 @@ export PATH=/usr/bin:/bin:/usr/sbin:/sbin # NOTE: adjust these variables: -# set to 0 for production, 1 for debugging +# set to 0 for production, 1 or 2 for debugging # while debugging, items will be downloaded to the parent directory of this script # also no actual installation will be performed +# debug mode 1 will download to the directory the script is run in, but will not check the version +# debug mode 2 will download to the temp directory, check for blocking processes, check the version, but will not install anything or remove the current version DEBUG=1 # notify behavior @@ -37,29 +39,36 @@ NOTIFY=success BLOCKING_PROCESS_ACTION=tell_user # options: # - ignore continue even when blocking processes are found -# - quit app will be told to quit nicely, if running +# - quit app will be told to quit nicely if running # - quit_kill told to quit twice, then it will be killed -# Could be great for service apps, if they do not respawn +# Could be great for service apps if they do not respawn # - silent_fail exit script without prompt or installation -# - prompt_user show a user dialog for each blocking process found -# abort after three attempts to quit -# (only if user accepts to quit the apps, otherwise -# the update is cancelled). +# - prompt_user show a user dialog for each blocking process found, +# user can choose "Quit and Update" or "Not Now". +# When "Quit and Update" is chosen, blocking process +# will be told to quit. Installomator will wait 30 seconds +# before checking again in case Save dialogs etc are being responded to. +# Installomator will abort if quitting after three tries does not succeed. +# "Not Now" will exit Installomator. # - prompt_user_then_kill # show a user dialog for each blocking process found, -# attempt to quit two times, kill the process finally +# user can choose "Quit and Update" or "Not Now". +# When "Quit and Update" is chosen, blocking process +# will be terminated. Installomator will abort if terminating +# after two tries does not succeed. "Not Now" will exit Installomator. # - prompt_user_loop # Like prompt-user, but clicking "Not Now", will just wait an hour, # and then it will ask again. # WARNING! It might block the MDM agent on the machine, as -# the scripts gets stuct in waiting until the hour has passed, +# the script will not exit, it will pause until the hour has passed, # possibly blocking for other management actions in this time. # - tell_user User will be showed a notification about the important update, -# but user is only allowed to quit and continue, and then we -# ask the app to quit. +# but user is only allowed to Quit and Continue, and then we +# ask the app to quit. This is default. # - tell_user_then_kill -# Show dialog 2 times, and if the quitting fails, the -# blocking processes will be killed. +# User will be showed a notification about the important update, +# but user is only allowed to Quit and Continue. If the quitting fails, +# the blocking processes will be terminated. # - kill kill process without prompting or giving the user a chance to save @@ -79,18 +88,25 @@ LOGO=appstore # App Store apps handling IGNORE_APP_STORE_APPS=no # options: -# - no If installed app is from App Store (which include VPP installed apps) -# it will not be touched, no matter it's version (default) -# - yes Replace App Store (and VPP) version of app and handle future +# - no If the installed app is from App Store (which include VPP installed apps) +# it will not be touched, no matter its version (default) +# - yes Replace App Store (and VPP) version of the app and handle future # updates using Installomator, even if latest version. # Shouldn’t give any problems for the user in most cases. -# Known bad example: Slack will loose all settings. +# Known bad example: Slack will lose all settings. +# Owner of copied apps +SYSTEMOWNER=0 +# options: +# - 0 Current user will be owner of copied apps, just like if they +# installed it themselves (default). +# - 1 root:wheel will be set on the copied app. +# Useful for shared machines. # install behavior INSTALL="" # options: -# - When not set, software will only be installed +# - When not set, the software will only be installed # if it is newer/different in version # - force Install even if it’s the same version @@ -98,9 +114,29 @@ INSTALL="" # Re-opening of closed app REOPEN="yes" # options: -# - yes App wil be reopened if it was closed +# - yes App will be reopened if it was closed # - no App not reopened +# Only let Installomator return the name of the label +# RETURN_LABEL_NAME=0 +# options: +# - 1 Installomator will return the name of the label and exit, so last line of +# output will be that name. When Installomator is locally installed and we +# use DEPNotify, then DEPNotify can present a more nice name to the user, +# instead of just the label name. + + +# Interrupt Do Not Disturb (DND) full screen apps +INTERRUPT_DND="yes" +# options: +# - yes Script will run without checking for DND full screen apps. +# - no Script will exit when an active DND full screen app is detected. + +# Comma separated list of app names to ignore when evaluating DND +IGNORE_DND_APPS="" +# example that will ignore browsers when evaluating DND: +# IGNORE_DND_APPS="firefox,Google Chrome,Safari,Microsoft Edge,Opera,Amphetamine,caffeinate" + # NOTE: How labels work @@ -124,7 +160,7 @@ REOPEN="yes" # # - packageID: (optional) # The package ID of a pkg -# If given, will be used to find version of installed software, instead of searching for an app. +# If given, will be used to find the version of installed software, instead of searching for an app. # Usefull if a pkg does not install an app. # See label installomator_st # @@ -132,9 +168,15 @@ REOPEN="yes" # URL to download the dmg. # Can be generated with a series of commands (see BBEdit for an example). # +# - curlOptions: (array, optional) +# Options to the curl command, needed for curl to be able to download the software. +# Usually used for adding extra headers that some servers need in order to serve the file. +# curlOptions=( -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15" ) +# (See “mocha”-labels, for examples on labels, and buildLabel.sh for header-examples.) +# # - appNewVersion: (optional) # Version of the downloaded software. -# If given, it will be compared to installed version, to see if download is different. +# If given, it will be compared to the installed version, to see if the download is different. # It does not check for newer or not, only different. # # - versionKey: (optional) @@ -188,7 +230,7 @@ REOPEN="yes" # blockingProcesses=( NONE ) # # - pkgName: (optional, only used for pkgInDmg, dmgInZip, and appInDmgInZip) -# File name of the pkg/dmg file _inside_ the dmg or zip +# File name or path to the pkg/dmg file _inside_ the dmg or zip. # When not given the pkgName is derived from the $name # # - updateTool: @@ -205,10 +247,10 @@ REOPEN="yes" # # - CLIInstaller: # - CLIArguments: -# If the downloaded dmg is actually an installer that we can call using CLI, we can +# If the downloaded dmg is an installer that we can call using CLI, we can # use these two variables for what to call. # We need to define `name` for the installed app (to be version checked), as well as -# `installerTool` for the installer app (if named differently that `name`. Installomator +# `installerTool` for the installer app (if named differently than `name`. Installomator # will add the path to the folder/disk image with the binary, and it will be called like this: `$CLIInstaller $CLIArguments` # For most installations `CLIInstaller` should contain the `installerTool` for the CLI call @@ -222,29 +264,74 @@ REOPEN="yes" # installer that should be located after mounting/expanding the downloaded archive. # See label adobecreativeclouddesktop # -VERSION="9.0dev" -VERSIONDATE="2021-11-23" +### Logging +# Logging behavior +LOGGING="INFO" +# options: +# - DEBUG Everything is logged +# - INFO (default) normal logging level +# - WARN only warning +# - ERROR only errors +# - REQ ???? + +# MDM profile name +MDMProfileName="" +# options: +# - MDM Profile Addigy has this name on the profile +# - Mosyle Corporation MDM Mosyle uses this name on the profile +# From the LOGO variable we can know if Addigy og Mosyle is used, so if that variable +# is either of these, and this variable is empty, then we will auto detect this. + +# Datadog logging used +datadogAPI="" +# Simply add your own API key for this in order to have logs sent to Datadog +# See more here: https://www.datadoghq.com/product/log-management/ + +# Log Date format used when parsing logs for debugging, this is the default used by +# install.log, override this in the case statements if you need something custom per +# application (See adobeillustrator). Using stadard GNU Date formatting. +LogDateFormat="%Y-%m-%d %H:%M:%S" + +# Get the start time for parsing install.log if we fail. +starttime=$(date "+$LogDateFormat") + +# Check if we have rosetta installed +if [[ $(/usr/bin/arch) == "arm64" ]]; then + if ! arch -x86_64 /usr/bin/true >/dev/null 2>&1; then # pgrep oahd >/dev/null 2>&1 + rosetta2=no + fi +fi +VERSION="9.0" +VERSIONDATE="2022-02-08" # MARK: Functions -cleanupAndExit() { # $1 = exit code, $2 message - if [[ -n $2 && $1 -ne 0 ]]; then - printlog "ERROR: $2" - fi - if [ "$DEBUG" -eq 0 ]; then - # remove the temporary working directory when done - printlog "Deleting $tmpDir" - rm -Rf "$tmpDir" - fi - +cleanupAndExit() { # $1 = exit code, $2 message, $3 level if [ -n "$dmgmount" ]; then # unmount disk image - printlog "Unmounting $dmgmount" - hdiutil detach "$dmgmount" + printlog "Unmounting $dmgmount" DEBUG + unmountingOut=$(hdiutil detach "$dmgmount" 2>&1) + printlog "Debugging enabled, Unmounting output was:\n$unmountingOut" DEBUG fi + if [ "$DEBUG" -ne 1 ]; then + # remove the temporary working directory when done (only if DEBUG is not used) + printlog "Deleting $tmpDir" DEBUG + deleteTmpOut=$(rm -Rfv "$tmpDir") + printlog "Debugging enabled, Deleting tmpDir output was:\n$deleteTmpOut" DEBUG + fi + # If we closed any processes, reopen the app again reopenClosedProcess - printlog "################## End Installomator, exit code $1 \n\n" + if [[ -n $2 && $1 -ne 0 ]]; then + printlog "ERROR: $2" $3 + fi + printlog "################## End Installomator, exit code $1 \n\n" REQ + + # if label is wrong and we wanted name of the label, then return ################## + if [[ $RETURN_LABEL_NAME -eq 1 ]]; then + 1=0 # If only label name should be returned we exit without any errors + echo "#" + fi exit "$1" } @@ -286,26 +373,84 @@ displaynotification() { # $1: message $2: title fi } - -# MARK: Logging -log_location="/private/var/log/Installomator.log" - printlog(){ - + [ -z "$2" ] && 2=INFO + log_message=$1 + log_priority=$2 timestamp=$(date +%F\ %T) - - if [[ "$(whoami)" == "root" ]]; then - echo "$timestamp" "$label" "$1" | tee -a $log_location - else - echo "$timestamp" "$label" "$1" + + # Check to make sure that the log isn't the same as the last, if it is then don't log and increment a timer. + if [[ ${log_message} == ${previous_log_message} ]]; then + let logrepeat=$logrepeat+1 + return fi + previous_log_message=$log_message + + # Once we finally stop getting duplicate logs output the number of times we got a duplicate. + if [[ $logrepeat -gt 1 ]];then + echo "$timestamp" : "${log_priority} : $label : Last Log repeated ${logrepeat} times" | tee -a $log_location + + if [[ ! -z $datadogAPI ]]; then + curl -s -X POST https://http-intake.logs.datadoghq.com/v1/input -H "Content-Type: text/plain" -H "DD-API-KEY: $datadogAPI" -d "${log_priority} : $mdmURL : $APPLICATION : $VERSION : $SESSION : Last Log repeated ${logrepeat} times" > /dev/null + fi + logrepeat=0 + fi + + # If the datadogAPI key value is set and our logging level is greater than or equal to our set level + # then post to Datadog's HTTPs endpoint. + if [[ -n $datadogAPI && ${levels[$log_priority]} -ge ${levels[$datadogLoggingLevel]} ]]; then + while IFS= read -r logmessage; do + curl -s -X POST https://http-intake.logs.datadoghq.com/v1/input -H "Content-Type: text/plain" -H "DD-API-KEY: $datadogAPI" -d "${log_priority} : $mdmURL : Installomator-${label} : ${VERSIONDATE//-/} : $SESSION : ${logmessage}" > /dev/null + done <<< "$log_message" + fi + + # Extra spaces + space_char="" + if [[ ${#log_priority} -eq 3 ]]; then + space_char=" " + elif [[ ${#log_priority} -eq 4 ]]; then + space_char=" " + fi + # If our logging level is greaterthan or equal to our set level then output locally. + if [[ ${levels[$log_priority]} -ge ${levels[$LOGGING]} ]]; then + while IFS= read -r logmessage; do + if [[ "$(whoami)" == "root" ]]; then + echo "$timestamp" : "${log_priority}${space_char} : $label : ${logmessage}" | tee -a $log_location + else + echo "$timestamp" : "${log_priority}${space_char} : $label : ${logmessage}" + fi + done <<< "$log_message" + fi +} + +# Used to remove dupplicate lines in large log output, +# for example from msupdate command after it finishes running. +deduplicatelogs() { + loginput=${1:-"Log"} + logoutput="" + # Read each line of the incoming log individually, match it with the previous. + # If it matches increment logrepeate then skip to the next line. + while read log; do + if [[ $log == $previous_log ]];then + let logrepeat=$logrepeat+1 + continue + fi + + previous_log="$log" + if [[ $logrepeat -gt 1 ]];then + logoutput+="Last Log repeated ${logrepeat} times\n" + logrepeat=0 + fi + + logoutput+="$log\n" + done <<< "$loginput" } # will get the latest release download from a github repo downloadURLFromGit() { # $1 git user name, $2 git repo name gitusername=${1?:"no git user name"} gitreponame=${2?:"no git repo name"} - + if [[ $type == "pkgInDmg" ]]; then filetype="dmg" elif [[ $type == "pkgInZip" ]]; then @@ -313,7 +458,7 @@ downloadURLFromGit() { # $1 git user name, $2 git repo name else filetype=$type fi - + if [ -n "$archiveName" ]; then downloadURL=$(curl --silent --fail "https://api.github.com/repos/$gitusername/$gitreponame/releases/latest" \ | awk -F '"' "/browser_download_url/ && /$archiveName\"/ { print \$4; exit }") @@ -322,8 +467,7 @@ downloadURLFromGit() { # $1 git user name, $2 git repo name | awk -F '"' "/browser_download_url/ && /$filetype\"/ { print \$4; exit }") fi if [ -z "$downloadURL" ]; then - cleanupAndExit 9 "could not retrieve download URL for $gitusername/$gitreponame" - #exit 9 + cleanupAndExit 9 "could not retrieve download URL for $gitusername/$gitreponame" ERROR else echo "$downloadURL" return 0 @@ -335,7 +479,7 @@ versionFromGit() { # $1 git user name, $2 git repo name gitusername=${1?:"no git user name"} gitreponame=${2?:"no git repo name"} - + appNewVersion=$(curl --silent --fail "https://api.github.com/repos/$gitusername/$gitreponame/releases/latest" | grep tag_name | cut -d '"' -f 4 | sed 's/[^0-9\.]//g') if [ -z "$appNewVersion" ]; then printlog "could not retrieve version number for $gitusername/$gitreponame" @@ -349,7 +493,7 @@ versionFromGit() { # Handling of differences in xpath between Catalina and Big Sur xpath() { - # the xpath tool changes in Big Sur and now requires the `-e` option + # the xpath tool changes in Big Sur and now requires the `-e` option if [[ $(sw_vers -buildVersion) > "20A" ]]; then /usr/bin/xpath -e $@ # alternative: switch to xmllint (which is not perl) @@ -369,7 +513,7 @@ getAppVersion() { printlog "Custom App Version detection is used, found $appversion" return fi - + # pkgs contains a version number, then we don't have to search for an app if [[ $packageID != "" ]]; then appversion="$(pkgutil --pkg-info-plist ${packageID} 2>/dev/null | grep -A 1 pkg-version | tail -1 | sed -E 's/.*>([0-9.]*)<.*/\1/g')" @@ -381,7 +525,7 @@ getAppVersion() { printlog "No version found using packageID $packageID" fi fi - + # get app in /Applications, or /Applications/Utilities, or find using Spotlight if [[ -d "/Applications/$appName" ]]; then applist="/Applications/$appName" @@ -391,9 +535,9 @@ getAppVersion() { applist=$(mdfind "kind:application $appName" -0 ) fi if [[ -z applist ]]; then - printlog "No previous app found" + printlog "No previous app found" DEBUG else - printlog "App(s) found: ${applist}" + printlog "App(s) found: ${applist}" DEBUG fi appPathArray=( ${(0)applist} ) @@ -404,7 +548,7 @@ getAppVersion() { installedAppPath=$filteredAppPaths[1] #appversion=$(mdls -name kMDItemVersion -raw $installedAppPath ) appversion=$(defaults read $installedAppPath/Contents/Info.plist $versionKey) #Not dependant on Spotlight indexing - printlog "found app at $installedAppPath, version $appversion" + printlog "found app at $installedAppPath, version $appversion, on versionKey $versionKey" updateDetected="YES" # Is current app from App Store if [[ -d "$installedAppPath"/Contents/_MASReceipt ]];then @@ -413,7 +557,7 @@ getAppVersion() { printlog "Replacing App Store apps, no matter the version" appversion=0 else - cleanupAndExit 1 "App previously installed from App Store, and we respect that" + cleanupAndExit 1 "App previously installed from App Store, and we respect that" ERROR fi fi else @@ -425,9 +569,9 @@ getAppVersion() { } checkRunningProcesses() { - # don't check in DEBUG mode - if [[ $DEBUG -ne 0 ]]; then - printlog "DEBUG mode, not checking for blocking processes" + # don't check in DEBUG mode 1 + if [[ $DEBUG -eq 1 ]]; then + printlog "DEBUG mode 1, not checking for blocking processes" DEBUG return fi @@ -438,7 +582,7 @@ checkRunningProcesses() { if pgrep -xq "$x"; then printlog "found blocking process $x" appClosed=1 - + case $BLOCKING_PROCESS_ACTION in quit|quit_kill) printlog "telling app $x to quit" @@ -460,7 +604,7 @@ checkRunningProcesses() { prompt_user|prompt_user_then_kill) button=$(displaydialog "Quit “$x” to continue updating? (Leave this dialogue if you want to activate this update later)." "The application “$x” needs to be updated.") if [[ $button = "Not Now" ]]; then - cleanupAndExit 10 "user aborted update" + cleanupAndExit 10 "user aborted update" ERROR else if [[ $i > 2 && $BLOCKING_PROCESS_ACTION = "prompt_user_then_kill" ]]; then printlog "Changing BLOCKING_PROCESS_ACTION to kill" @@ -505,7 +649,7 @@ checkRunningProcesses() { fi ;; silent_fail) - cleanupAndExit 12 "blocking process '$x' found, aborting" + cleanupAndExit 12 "blocking process '$x' found, aborting" ERROR ;; esac @@ -516,28 +660,28 @@ checkRunningProcesses() { done if [[ $countedProcesses -ne 0 ]]; then - cleanupAndExit 11 "could not quit all processes, aborting..." + cleanupAndExit 11 "could not quit all processes, aborting..." ERROR fi - printlog "no more blocking processes, continue with update" + printlog "no more blocking processes, continue with update" REQ } reopenClosedProcess() { # If Installomator closed any processes, let's get the app opened again # credit: Søren Theilgaard (@theilgaard) - + # don't reopen if REOPEN is not "yes" if [[ $REOPEN != yes ]]; then printlog "REOPEN=no, not reopening anything" return fi - # don't reopen in DEBUG mode - if [[ $DEBUG -ne 0 ]]; then - printlog "DEBUG mode, not reopening anything" + # don't reopen in DEBUG mode 1 + if [[ $DEBUG -eq 1 ]]; then + printlog "DEBUG mode 1, not reopening anything" DEBUG return fi - + if [[ $appClosed == 1 ]]; then printlog "Telling app $appName to open" #runAsUser osascript -e "tell app \"$appName\" to open" @@ -547,7 +691,7 @@ reopenClosedProcess() { processuser=$(ps aux | grep -i "${appName}" | grep -vi "grep" | awk '{print $1}') printlog "Reopened ${appName} as $processuser" else - printlog "App not closed, so no reopen." + printlog "App not closed, so no reopen." DEBUG fi } @@ -557,89 +701,116 @@ installAppWithPath() { # $1: path to app to install in $targetDir # check if app exists if [ ! -e "$appPath" ]; then - cleanupAndExit 8 "could not find: $appPath" + cleanupAndExit 8 "could not find: $appPath" DEBUG fi # verify with spctl - printlog "Verifying: $appPath" - if ! teamID=$(spctl -a -vv "$appPath" 2>&1 | awk '/origin=/ {print $NF }' | tr -d '()' ); then - cleanupAndExit 4 "Error verifying $appPath" - fi + printlog "Verifying: $appPath" INFO + printlog "App size: $(du -sh "$appPath")" DEBUG + appVerify=$(spctl -a -vv "$appPath" 2>&1 ) + appVerifyStatus=$(echo $?) + teamID=$(echo $appVerify | awk '/origin=/ {print $NF }' | tr -d '()' ) + deduplicatelogs "$appVerify" - printlog "Team ID matching: $teamID (expected: $expectedTeamID )" + if [[ $appVerifyStatus -ne 0 ]] ; then + #if ! teamID=$(spctl -a -vv "$appPath" 2>&1 | awk '/origin=/ {print $NF }' | tr -d '()' ); then + cleanupAndExit 4 "Error verifying $appPath error:\n$logoutput" ERROR + fi + printlog "Debugging enabled, App Verification output was:\n$logoutput" DEBUG + printlog "Team ID matching: $teamID (expected: $expectedTeamID )" INFO if [ "$expectedTeamID" != "$teamID" ]; then - cleanupAndExit 5 "Team IDs do not match" + cleanupAndExit 5 "Team IDs do not match" ERROR fi - # versioncheck - # credit: Søren Theilgaard (@theilgaard) + # app versioncheck appNewVersion=$(defaults read $appPath/Contents/Info.plist $versionKey) if [[ -n $appNewVersion && $appversion == $appNewVersion ]]; then - printlog "Downloaded version of $name is $appNewVersion, same as installed." + printlog "Downloaded version of $name is $appNewVersion on versionKey $versionKey, same as installed." if [[ $INSTALL != "force" ]]; then message="$name, version $appNewVersion, is the latest version." if [[ $currentUser != "loginwindow" && $NOTIFY == "all" ]]; then printlog "notifying" displaynotification "$message" "No update for $name!" fi - cleanupAndExit 0 "No new version to install" + cleanupAndExit 0 "No new version to install" INFO else printlog "Using force to install anyway." fi else - printlog "Downloaded version of $name is $appNewVersion (replacing version $appversion)." + printlog "Downloaded version of $name is $appNewVersion on versionKey $versionKey (replacing version $appversion)." fi - # skip install for DEBUG - if [ "$DEBUG" -ne 0 ]; then - printlog "DEBUG enabled, skipping remove, copy and chown steps" + # macOS versioncheck + minimumOSversion=$(defaults read $appPath/Contents/Info.plist LSMinimumSystemVersion 2>/dev/null ) + if [[ -n $minimumOSversion && $minimumOSversion =~ '[0-9.]*' ]]; then + printlog "App has LSMinimumSystemVersion: $minimumOSversion" + if ! is-at-least $minimumOSversion $installedOSversion; then + printlog "App requires higher System Version than installed: $installedOSversion" + message="Cannot install $name, version $appNewVersion, as it is not compatible with the running system version." + if [[ $currentUser != "loginwindow" && $NOTIFY == "all" ]]; then + printlog "notifying" + displaynotification "$message" "Error updating $name!" + fi + cleanupAndExit 6 "Installed macOS is too old for this app." INFO + fi + fi + + # skip install for DEBUG 1 + if [ "$DEBUG" -eq 1 ]; then + printlog "DEBUG mode 1 enabled, skipping remove, copy and chown steps" DEBUG return 0 fi - # check for root - if [ "$(whoami)" != "root" ]; then - # not running as root - cleanupAndExit 6 "not running as root, exiting" + # skip install for DEBUG 2 + if [ "$DEBUG" -eq 2 ]; then + printlog "DEBUG mode 2 enabled, not installing anything, exiting" DEBUG + cleanupAndExit 0 fi - + # Test if variable CLIInstaller is set if [[ -z $CLIInstaller ]]; then - + # remove existing application if [ -e "$targetDir/$appName" ]; then - printlog "Removing existing $targetDir/$appName" - rm -Rf "$targetDir/$appName" + printlog "Removing existing $targetDir/$appName" DEBUG + deleteAppOut=$(rm -Rfv "$targetDir/$appName" 2>&1) + tempName="$targetDir/$appName" + tempNameLength=$((${#tempName} + 10)) + deleteAppOut=$(echo $deleteAppOut | cut -c 1-$tempNameLength) + deduplicatelogs "$deleteAppOut" + printlog "Debugging enabled, App removing output was:\n$logoutput" DEBUG fi # copy app to /Applications printlog "Copy $appPath to $targetDir" if ! ditto "$appPath" "$targetDir/$appName"; then - cleanupAndExit 7 "Error while copying" + cleanupAndExit 7 "Error while copying" ERROR fi # set ownership to current user - if [ "$currentUser" != "loginwindow" ]; then + if [[ "$currentUser" != "loginwindow" && $SYSTEMOWNER -ne 1 ]]; then printlog "Changing owner to $currentUser" chown -R "$currentUser" "$targetDir/$appName" else - printlog "No user logged in, not changing user" + printlog "No user logged in or SYSTEMOWNER=1, setting owner to root:wheel" + chown -R root:wheel "$targetDir/$appName" fi elif [[ ! -z $CLIInstaller ]]; then mountname=$(dirname $appPath) - printlog "CLIInstaller exists, running installer command $mountname/$CLIInstaller $CLIArguments" #INFO + printlog "CLIInstaller exists, running installer command $mountname/$CLIInstaller $CLIArguments" INFO CLIoutput=$("$mountname/$CLIInstaller" "${CLIArguments[@]}" 2>&1) CLIstatus=$(echo $?) - logoutput="$CLIoutput" # dedupliatelogs "$CLIoutput" + deduplicatelogs "$CLIoutput" if [ $CLIstatus -ne 0 ] ; then - cleanupAndExit 3 "Error installing $mountname/$CLIInstaller $CLIArguments error:\n$logoutput" #ERROR + cleanupAndExit 3 "Error installing $mountname/$CLIInstaller $CLIArguments error:\n$logoutput" ERROR else - printlog "Succesfully ran $mountname/$CLIInstaller $CLIArguments" + printlog "Succesfully ran $mountname/$CLIInstaller $CLIArguments" INFO fi - printlog "Debugging enabled, update tool output was:\n$logoutput" #DEBUG + printlog "Debugging enabled, update tool output was:\n$logoutput" DEBUG fi } @@ -648,16 +819,21 @@ mountDMG() { # mount the dmg printlog "Mounting $tmpDir/$archiveName" # always pipe 'Y\n' in case the dmg requires an agreement - if ! dmgmount=$(echo 'Y'$'\n' | hdiutil attach "$tmpDir/$archiveName" -nobrowse -readonly | tail -n 1 | cut -c 54- ); then - cleanupAndExit 3 "Error mounting $tmpDir/$archiveName" + dmgmountOut=$(echo 'Y'$'\n' | hdiutil attach "$tmpDir/$archiveName" -nobrowse -readonly ) + dmgmountStatus=$(echo $?) + dmgmount=$(echo $dmgmountOut | tail -n 1 | cut -c 54- ) + deduplicatelogs "$dmgmountOut" + + if [[ $dmgmountStatus -ne 0 ]] ; then + #if ! dmgmount=$(echo 'Y'$'\n' | hdiutil attach "$tmpDir/$archiveName" -nobrowse -readonly | tail -n 1 | cut -c 54- ); then + cleanupAndExit 3 "Error mounting $tmpDir/$archiveName error:\n$logoutput" ERROR fi - if [[ ! -e $dmgmount ]]; then - printlog "Error mounting $tmpDir/$archiveName" - cleanupAndExit 3 + cleanupAndExit 3 "Error accessing mountpoint for $tmpDir/$archiveName error:\n$logoutput" ERROR fi - - printlog "Mounted: $dmgmount" + printlog "Debugging enabled, dmgmount output was:\n$logoutput" DEBUG + + printlog "Mounted: $dmgmount" INFO } installFromDMG() { @@ -668,34 +844,44 @@ installFromDMG() { installFromPKG() { # verify with spctl printlog "Verifying: $archiveName" + printlog "File list: $(ls -lh "$archiveName")" DEBUG + printlog "File type: $(file "$archiveName")" DEBUG + spctlOut=$(spctl -a -vv -t install "$archiveName" 2>&1 ) + spctlStatus=$(echo $?) + printlog "spctlOut is $spctlOut" DEBUG - if ! spctlout=$(spctl -a -vv -t install "$archiveName" 2>&1 ); then - printlog "Error verifying $archiveName" - cleanupAndExit 4 + teamID=$(echo $spctlOut | awk -F '(' '/origin=/ {print $2 }' | tr -d '()' ) + # Apple signed software has no teamID, grab entire origin instead + if [[ -z $teamID ]]; then + teamID=$(echo $spctlOut | awk -F '=' '/origin=/ {print $NF }') fi + + deduplicatelogs "$spctlOut" - teamID=$(echo $spctlout | awk -F '(' '/origin=/ {print $2 }' | tr -d '()' ) + if [[ $spctlStatus -ne 0 ]] ; then + #if ! spctlout=$(spctl -a -vv -t install "$archiveName" 2>&1 ); then + cleanupAndExit 4 "Error verifying $archiveName error:\n$logoutput" ERROR + fi # Apple signed software has no teamID, grab entire origin instead if [[ -z $teamID ]]; then teamID=$(echo $spctlout | awk -F '=' '/origin=/ {print $NF }') fi - printlog "Team ID: $teamID (expected: $expectedTeamID )" if [ "$expectedTeamID" != "$teamID" ]; then - printlog "Team IDs do not match!" - cleanupAndExit 5 + cleanupAndExit 5 "Team IDs do not match!" ERROR fi # Check version of pkg to be installed if packageID is set if [[ $packageID != "" && $appversion != "" ]]; then printlog "Checking package version." - pkgutil --expand "$archiveName" "$archiveName"_pkg - #printlog "$(cat "$archiveName"_pkg/Distribution | xpath '//installer-gui-script/pkg-ref[@id][@version]' 2>/dev/null)" - appNewVersion=$(cat "$archiveName"_pkg/Distribution | xpath '//installer-gui-script/pkg-ref[@id][@version]' 2>/dev/null | grep -i "$packageID" | tr ' ' '\n' | grep -i version | cut -d \" -f 2) #sed -E 's/.*\"([0-9.]*)\".*/\1/g' - rm -r "$archiveName"_pkg + baseArchiveName=$(basename $archiveName) + expandedPkg="$tmpDir/${baseArchiveName}_pkg" + pkgutil --expand "$archiveName" "$expandedPkg" + appNewVersion=$(cat "$expandedPkg"/Distribution | xpath 'string(//installer-gui-script/pkg-ref[@id][@version]/@version)' 2>/dev/null ) + rm -r "$expandedPkg" printlog "Downloaded package $packageID version $appNewVersion" if [[ $appversion == $appNewVersion ]]; then printlog "Downloaded version of $name is the same as installed." @@ -705,47 +891,63 @@ installFromPKG() { printlog "notifying" displaynotification "$message" "No update for $name!" fi - cleanupAndExit 0 "No new version to install" + cleanupAndExit 0 "No new version to install" INFO else printlog "Using force to install anyway." fi fi fi - - # skip install for DEBUG - if [ "$DEBUG" -ne 0 ]; then - printlog "DEBUG enabled, skipping installation" + + # skip install for DEBUG 1 + if [ "$DEBUG" -eq 1 ]; then + printlog "DEBUG enabled, skipping installation" DEBUG return 0 fi - # check for root - if [ "$(whoami)" != "root" ]; then - # not running as root - cleanupAndExit 6 "not running as root, exiting" + # skip install for DEBUG 2 + if [ "$DEBUG" -eq 2 ]; then + cleanupAndExit 0 "DEBUG mode 2 enabled, exiting" DEBUG fi # install pkg printlog "Installing $archiveName to $targetDir" - if ! installer -pkg "$archiveName" -tgt "$targetDir" ; then - printlog "error installing $archiveName" - cleanupAndExit 9 + pkgInstall=$(installer -verbose -dumplog -pkg "$archiveName" -tgt "$targetDir" 2>&1) + pkgInstallStatus=$(echo $?) + sleep 1 + pkgEndTime=$(date "+$LogDateFormat") + pkgInstall+=$(echo "\nOutput of /var/log/install.log below this line.\n") + pkgInstall+=$(echo "----------------------------------------------------------\n") + pkgInstall+=$(awk -v "b=$starttime" -v "e=$pkgEndTime" -F ',' '$1 >= b && $1 <= e' /var/log/install.log) + deduplicatelogs "$pkgInstall" + + if [[ $pkgInstallStatus -ne 0 ]] && [[ $logoutput == *"requires Rosetta 2"* ]] && [[ $rosetta2 == no ]]; then + printlog "Package requires Rosetta 2, Installing Rosetta 2 and Installing Package" INFO + /usr/sbin/softwareupdate --install-rosetta --agree-to-license + rosetta2=yes + installFromPKG fi + + if [[ $pkginstallstatus -ne 0 ]] ; then + #if ! installer -pkg "$archiveName" -tgt "$targetDir" ; then + cleanupAndExit 9 "Error installing $archiveName error:\n$logoutput" ERROR + fi + printlog "Debugging enabled, installer output was:\n$logoutput" DEBUG } installFromZIP() { # unzip the archive printlog "Unzipping $archiveName" - + # tar -xf "$archiveName" # note: when you expand a zip using tar in Mojave the expanded # app will never pass the spctl check # unzip -o -qq "$archiveName" - + # note: githubdesktop fails spctl verification when expanded # with unzip - + ditto -x -k "$archiveName" "$tmpDir" installAppWithPath "$tmpDir/$appName" } @@ -762,16 +964,27 @@ installPkgInDmg() { # locate pkg in dmg if [[ -z $pkgName ]]; then # find first file ending with 'pkg' - findfiles=$(find "$dmgmount" -iname "*.pkg" -maxdepth 1 ) + findfiles=$(find "$dmgmount" -iname "*.pkg" -type f -maxdepth 1 ) filearray=( ${(f)findfiles} ) if [[ ${#filearray} -eq 0 ]]; then - cleanupAndExit 20 "couldn't find pkg in dmg $archiveName" + cleanupAndExit 20 "couldn't find pkg in dmg $archiveName" ERROR fi archiveName="${filearray[1]}" printlog "found pkg: $archiveName" else - # it is now safe to overwrite archiveName for installFromPKG - archiveName="$dmgmount/$pkgName" + if ls "$tmpDir/$pkgName" ; then + archiveName="$tmpDir/$pkgName" + else + # try searching for pkg + findfiles=$(find "$tmpDir" -iname "$pkgName") + filearray=( ${(f)findfiles} ) + if [[ ${#filearray} -eq 0 ]]; then + cleanupAndExit 20 "couldn't find pkg “$pkgName” in zip $archiveName" ERROR + fi + # it is now safe to overwrite archiveName for installFromPKG + archiveName="${filearray[1]}" + printlog "found pkg: $archiveName" + fi fi # installFromPkgs @@ -786,17 +999,28 @@ installPkgInZip() { # locate pkg in zip if [[ -z $pkgName ]]; then # find first file ending with 'pkg' - findfiles=$(find "$tmpDir" -iname "*.pkg" -maxdepth 2 ) + findfiles=$(find "$tmpDir" -iname "*.pkg" -type f -maxdepth 2 ) filearray=( ${(f)findfiles} ) if [[ ${#filearray} -eq 0 ]]; then - cleanupAndExit 20 "couldn't find pkg in zip $archiveName" + cleanupAndExit 20 "couldn't find pkg in zip $archiveName" ERROR fi - archiveName="${filearray[1]}" # it is now safe to overwrite archiveName for installFromPKG + archiveName="${filearray[1]}" printlog "found pkg: $archiveName" else - # it is now safe to overwrite archiveName for installFromPKG - archiveName="$tmpDir/$pkgName" + if [[ -s "$tmpDir/$pkgName" ]]; then + archiveName="$tmpDir/$pkgName" + else + # try searching for pkg + findfiles=$(find "$tmpDir" -iname "$pkgName") + filearray=( ${(f)findfiles} ) + if [[ ${#filearray} -eq 0 ]]; then + cleanupAndExit 20 "couldn't find pkg “$pkgName” in zip $archiveName" ERROR + fi + # it is now safe to overwrite archiveName for installFromPKG + archiveName="${filearray[1]}" + printlog "found pkg: $archiveName" + fi fi # installFromPkgs @@ -814,7 +1038,7 @@ installAppInDmgInZip() { findfiles=$(find "$tmpDir" -iname "*.dmg" -maxdepth 2 ) filearray=( ${(f)findfiles} ) if [[ ${#filearray} -eq 0 ]]; then - cleanupAndExit 20 "couldn't find dmg in zip $archiveName" + cleanupAndExit 20 "couldn't find dmg in zip $archiveName" ERROR fi archiveName="$(basename ${filearray[1]})" # it is now safe to overwrite archiveName for installFromDMG @@ -833,12 +1057,29 @@ runUpdateTool() { if [[ -x $updateTool ]]; then printlog "running $updateTool $updateToolArguments" if [[ -n $updateToolRunAsCurrentUser ]]; then - runAsUser $updateTool ${updateToolArguments} + updateOutput=$(runAsUser $updateTool ${updateToolArguments} 2>&1) + updateStatus=$(echo $?) else - $updateTool ${updateToolArguments} + updateOutput=$($updateTool ${updateToolArguments} 2>&1) + updateStatus=$(echo $?) fi - if [[ $? -ne 0 ]]; then - cleanupAndExit 15 "Error running $updateTool" + sleep 1 + updateEndTime=$(date "+$updateToolLogDateFormat") + deduplicatelogs $updateOutput + if [[ -n $updateToolLog ]]; then + updateOutput+=$(echo "Output of Installer log of $updateToolLog below this line.\n") + updateOutput+=$(echo "----------------------------------------------------------\n") + updateOutput+=$(awk -v "b=$updatestarttime" -v "e=$updateEndTime" -F ',' '$1 >= b && $1 <= e' $updateToolLog) + fi + + if [[ $updateStatus -ne 0 ]]; then + printlog "Error running $updateTool, Procceding with normal installation. Exit Status: $updateStatus Error:\n$logoutput" WARN + return 1 + if [[ $type == updateronly ]]; then + cleanupAndExit 77 "No Download URL Set, this is an update only application and the updater failed" WARN + fi + elif [[ $updateStatus -eq 0 ]]; then + printlog "Debugging enabled, update tool output was:\n$logoutput" DEBUG fi else printlog "couldn't find $updateTool, continuing normally" @@ -870,11 +1111,38 @@ finishing() { fi } +# Detect if there is an app actively making a display sleep assertion, e.g. +# KeyNote, PowerPoint, Zoom, or Webex. +# See: https://developer.apple.com/documentation/iokit/iopmlib_h/iopmassertiontypes +hasDisplaySleepAssertion() { + # Get the names of all apps with active display sleep assertions + local apps="$(/usr/bin/pmset -g assertions | /usr/bin/awk '/NoDisplaySleepAssertion | PreventUserIdleDisplaySleep/ && match($0,/\(.+\)/) && ! /coreaudiod/ {gsub(/^.*\(/,"",$0); gsub(/\).*$/,"",$0); print};')" + + if [[ ! "${apps}" ]]; then + # No display sleep assertions detected + return 1 + fi + + # Create an array of apps that need to be ignored + local ignore_array=("${(@s/,/)IGNORE_DND_APPS}") + + for app in ${(f)apps}; do + if (( ! ${ignore_array[(Ie)${app}]} )); then + # Relevant app with display sleep assertion detected + printlog "Display sleep assertion detected by ${app}." + return 0 + fi + done + + # No relevant display sleep assertion detected + return 1 +} # MARK: check minimal macOS requirement autoload is-at-least -if ! is-at-least 10.14 $(sw_vers -productVersion); then +installedOSversion=$(sw_vers -productVersion) +if ! is-at-least 10.14 $installedOSversion; then printlog "Installomator requires at least macOS 10.14 Mojave." exit 98 fi @@ -915,21 +1183,61 @@ if [[ $label == "version" ]]; then exit 0 fi -printlog "################## Start Installomator v. $VERSION" -printlog "################## $label" +# MARK: Logging +log_location="/private/var/log/Installomator.log" + +# Check if we're in debug mode, if so then set logging to DEBUG, otherwise default to INFO +# if no log level is specified. +if [[ $DEBUG -ne 0 ]]; then + LOGGING=DEBUG +elif [[ -z $LOGGING ]]; then + LOGGING=INFO + datadogLoggingLevel=INFO +fi + +# Associate logging levels with a numerical value so that we are able to identify what +# should be removed. For example if the LOGGING=ERROR only printlog statements with the +# level REQ and ERROR will be displayed. LOGGING=DEBUG will show all printlog statements. +# If a printlog statement has no level set it's automatically assigned INFO. + +declare -A levels=(DEBUG 0 INFO 1 WARN 2 ERROR 3 REQ 4) + +# If we are able to detect an MDM URL (Jamf Pro) or another identifier for a customer/instance we grab it here, this is useful if we're centrally logging multiple MDM instances. +if [[ -f /Library/Preferences/com.jamfsoftware.jamf.plist ]]; then + mdmURL=$(defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url) +elif [[ -n "$MDMProfileName" ]]; then + mdmURL=$(sudo profiles show | grep -A3 "$MDMProfileName" | sed -n -e 's/^.*organization: //p') +else + mdmURL="Unknown" +fi + +# Generate a session key for this run, this is useful to idenify streams when we're centrally logging. +SESSION=$RANDOM + +# Mark: START +printlog "################## Start Installomator v. $VERSION, date $VERSIONDATE" REQ +printlog "################## Version: $VERSION" INFO +printlog "################## Date: $VERSIONDATE" INFO +printlog "################## $label" INFO # Check for DEBUG mode if [[ $DEBUG -gt 0 ]]; then - printlog "DEBUG mode $DEBUG enabled." + printlog "DEBUG mode $DEBUG enabled." DEBUG fi # How we get version number from app -# (alternative is "CFBundleVersion", that can be used in labels) -versionKey="CFBundleShortVersionString" +if [[ -z $versionKey ]]; then + versionKey="CFBundleShortVersionString" +fi # get current user currentUser=$(scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ { print $3 }') +# MARK: check for root +if [[ "$(whoami)" != "root" && "$DEBUG" -eq 0 ]]; then + # not running as root + cleanupAndExit 6 "not running as root, exiting" +fi # MARK: labels in case statement case $label in @@ -1114,7 +1422,6 @@ amazonworkspaces) expectedTeamID="94KV3E626L" ;; androidfiletransfer) - #credit: Sam Ess (saess-sep) name="Android File Transfer" type="dmg" downloadURL="https://dl.google.com/dl/androidjumper/mtp/current/AndroidFileTransfer.dmg" @@ -1146,14 +1453,21 @@ applenyfonts) type="pkgInDmg" downloadURL="https://devimages-cdn.apple.com/design/resources/download/NY.dmg" packageID="com.apple.pkg.NYFonts" - expectedTeamID="Development Update" + expectedTeamID="Software Update" + ;; +applesfarabic) + name="San Francisco Arabic" + type="pkgInDmg" + downloadURL="https://devimages-cdn.apple.com/design/resources/download/SF-Arabic.dmg" + packageID="com.apple.pkg.SFArabicFonts" + expectedTeamID="Software Update" ;; applesfcompact) name="San Francisco Compact" type="pkgInDmg" downloadURL="https://devimages-cdn.apple.com/design/resources/download/SF-Compact.dmg" packageID="com.apple.pkg.SanFranciscoCompact" - expectedTeamID="Development Update" + expectedTeamID="Software Update" ;; applesfmono) name="San Francisco Mono" @@ -1167,14 +1481,14 @@ applesfpro) type="pkgInDmg" downloadURL="https://devimages-cdn.apple.com/design/resources/download/SF-Pro.dmg" packageID="com.apple.pkg.SanFranciscoPro" - expectedTeamID="Development Update" + expectedTeamID="Software Update" ;; applesfsymbols|\ sfsymbols) name="SF Symbols" type="pkgInDmg" - downloadURL=$( curl -fs "https://developer.apple.com/sf-symbols/" | grep -oe "https.*\.dmg" | head -1 ) - appNewVersion=$( echo "$downloadURL" | head -1 | sed -E 's/.*SF-Symbols-([0-9.]*)\..*/\1/g') + downloadURL=$( curl -fs "https://developer.apple.com/sf-symbols/" | grep -oe "https.*Symbols.*\.dmg" | head -1 ) + appNewVersion=$( echo "$downloadURL" | sed -E 's/.*SF-Symbols-([0-9.]*)\..*/\1/g') expectedTeamID="Software Update" ;; aquaskk) @@ -1225,7 +1539,7 @@ audacity) authydesktop) name="Authy Desktop" type="dmg" - downloadURL="https://electron.authy.com/download?channel=stable&arch=x64&platform=darwin&version=latest&product=authy" + downloadURL=$(curl -s -w '%{redirect_url}' -o /dev/null "https://electron.authy.com/download?channel=stable&arch=x64&platform=darwin&version=latest&product=authy" | sed 's/\ /%20/g') appNewVersion="$(curl -sfL --output /dev/null -r 0-0 "${downloadURL}" --remote-header-name --remote-name -w "%{url_effective}\n" | grep -o -E '([a-zA-Z0-9\_.%-]*)\.(dmg|pkg|zip|tbz)$' | sed -E 's/.*-([0-9.]*)\.dmg/\1/g')" expectedTeamID="9EVH78F4V4" ;; @@ -1238,10 +1552,8 @@ autodmg) expectedTeamID="5KQ3D3FG5H" ;; autopkgr) - # credit: Søren Theilgaard (@theilgaard) name="AutoPkgr" type="dmg" - #downloadURL=$(curl -fs "https://api.github.com/repos/lindegroup/autopkgr/releases/latest" | awk -F '"' "/browser_download_url/ && /dmg/ && ! /sig/ && ! /CLI/ && ! /sha256/ { print \$4 }") downloadURL=$(downloadURLFromGit lindegroup autopkgr) appNewVersion=$(versionFromGit lindegroup autopkgr) expectedTeamID="JVY2ZR6SEF" @@ -1339,15 +1651,9 @@ bluejeans) expectedTeamID="HE4P42JBGN" ;; boxdrive) - # credit: Isaac Ordonez, Mann consulting (@mannconsulting) name="Box" type="pkg" - if [[ $(arch) == "arm64" ]]; then - #Note: https://support.box.com/hc/en-us/articles/1500004479962-Box-Drive-support-on-devices-with-M1-chips - downloadURL="https://e3.boxcdn.net/desktop/pre-releases/mac/BoxDrive.2.20.140-M1-beta.pkg" - elif [[ $(arch) == "i386" ]]; then - downloadURL="https://e3.boxcdn.net/box-installers/desktop/releases/mac/Box.pkg" - fi + downloadURL="https://e3.boxcdn.net/box-installers/desktop/releases/mac/Box.pkg" expectedTeamID="M683GB7CPW" ;; boxsync) @@ -1363,18 +1669,21 @@ boxtools) expectedTeamID="M683GB7CPW" ;; brave) - # credit: @securitygeneration name="Brave Browser" type="dmg" if [[ $(arch) != "i386" ]]; then printlog "Architecture: arm64 (not i386)" - downloadURL=$(curl -fsIL https://laptop-updates.brave.com/latest/osxarm64/release | grep -i "^location" | awk '{print $2}' | tr -d '\r\n') + downloadURL=$(curl -fsIL https://laptop-updates.brave.com/latest/osxarm64/release | grep -i "^location" | sed -E 's/.*(https.*\.dmg).*/\1/g') + appNewVersion="$(curl -fsL "https://updates.bravesoftware.com/sparkle/Brave-Browser/stable-arm64/appcast.xml" | xpath '//rss/channel/item[last()]/enclosure/@sparkle:version' 2>/dev/null | cut -d '"' -f 2)" + #appNewVersion="96.$(curl -fsL "https://updates.bravesoftware.com/sparkle/Brave-Browser/stable-arm64/appcast.xml" | xpath '//rss/channel/item[last()]/enclosure/@sparkle:shortVersionString' 2>/dev/null | cut -d '"' -f 2 | cut -d "." -f1-3)" else printlog "Architecture: i386" - downloadURL=$(curl -fsIL https://laptop-updates.brave.com/latest/osx/release | grep -i "^location" | awk '{print $2}' | tr -d '\r\n') + downloadURL=$(curl -fsIL https://laptop-updates.brave.com/latest/osx/release | grep -i "^location" | sed -E 's/.*(https.*\.dmg).*/\1/g') + appNewVersion="$(curl -fsL "https://updates.bravesoftware.com/sparkle/Brave-Browser/stable/appcast.xml" | xpath '//rss/channel/item[last()]/enclosure/@sparkle:version' 2>/dev/null | cut -d '"' -f 2)" + #appNewVersion="96.$(curl -fsL "https://updates.bravesoftware.com/sparkle/Brave-Browser/stable/appcast.xml" | xpath '//rss/channel/item[last()]/enclosure/@sparkle:shortVersionString' 2>/dev/null | cut -d '"' -f 2 | cut -d "." -f1-3)" fi -# downloadURL=$(curl --location --fail --silent "https://updates.bravesoftware.com/sparkle/Brave-Browser/stable/appcast.xml" | xpath '//rss/channel/item[last()]/enclosure/@url' 2>/dev/null | cut -d '"' -f 2) - appNewVersion=$(curl --location --fail --silent "https://updates.bravesoftware.com/sparkle/Brave-Browser/stable/appcast.xml" | xpath '//rss/channel/item[last()]/enclosure/@sparkle:shortVersionString' 2>/dev/null | cut -d '"' -f 2) + versionKey="CFBundleVersion" +# downloadURL=$(curl -fsL "https://updates.bravesoftware.com/sparkle/Brave-Browser/stable/appcast.xml" | xpath '//rss/channel/item[last()]/enclosure/@url' 2>/dev/null | cut -d '"' -f 2) expectedTeamID="KL8N8XSYF4" ;; bugdom) @@ -1430,11 +1739,12 @@ canva) name="Canva" type="dmg" if [[ $(arch) == "arm64" ]]; then - downloadURL=$(curl -fsLI -H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" -H "accept-encoding: gzip, deflate, br" -H "accept-language: en-US,en;q=0.9" -H "Referrer Policy: strict-origin-when-cross-origin" -H "upgrade-insecure-requests: 1" -H "sec-fetch-dest: document" -H "sec-gpc: 1" -H "sec-fetch-user: ?1" -H "sec-fetch-mode: navigate" -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15" "https://www.canva.com/download/mac/arm/canva-desktop/" | grep -i "^location" | cut -d " " -f2 | tr -d '\r') + downloadURL=https://desktop-release.canva.com/Canva-latest-arm64.dmg + appNewVersion=$( curl -fsLI -H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" -H "accept-encoding: gzip, deflate, br" -H "accept-language: en-US,en;q=0.9" -H "Referrer Policy: strict-origin-when-cross-origin" -H "upgrade-insecure-requests: 1" -H "sec-fetch-dest: document" -H "sec-gpc: 1" -H "sec-fetch-user: ?1" -H "sec-fetch-mode: navigate" -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15" "https://www.canva.com/download/mac/arm/canva-desktop/" | grep -i "^location" | cut -d " " -f2 | tr -d '\r' | sed -E 's/.*\/[a-zA-Z]*-([0-9.]*)-*.*\.dmg/\1/g' ) elif [[ $(arch) == "i386" ]]; then - downloadURL=$(curl -fsLI -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15" -H "accept-encoding: gzip, deflate, br" -H "Referrer Policy: strict-origin-when-cross-origin" -H "upgrade-insecure-requests: 1" -H "sec-fetch-dest: document" -H "sec-gpc: 1" -H "sec-fetch-user: ?1" -H "accept-language: en-US,en;q=0.9" -H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" -H "sec-fetch-mode: navigate" "https://www.canva.com/download/mac/intel/canva-desktop/" | grep -i "^location" | cut -d " " -f2 | tr -d '\r') + downloadURL=https://desktop-release.canva.com/Canva-latest.dmg + appNewVersion=$( curl -fsLI -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15" -H "accept-encoding: gzip, deflate, br" -H "Referrer Policy: strict-origin-when-cross-origin" -H "upgrade-insecure-requests: 1" -H "sec-fetch-dest: document" -H "sec-gpc: 1" -H "sec-fetch-user: ?1" -H "accept-language: en-US,en;q=0.9" -H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" -H "sec-fetch-mode: navigate" "https://www.canva.com/download/mac/intel/canva-desktop/" | grep -i "^location" | cut -d " " -f2 | tr -d '\r' | sed -E 's/.*\/[a-zA-Z]*-([0-9.]*)-*.*\.dmg/\1/g' ) fi - appNewVersion=$( echo "${downloadURL}" | sed -E 's/.*\/[a-zA-Z]*-([0-9.]*)\..*/\1/g' ) expectedTeamID="5HD2ARTBFS" ;; chatwork) @@ -1487,10 +1797,13 @@ cloudya) expectedTeamID="X26F74J8TH" ;; code42) - # credit: Isaac Ordonez, Mann consulting (@mannconsulting) name="Code42" type="pkgInDmg" - downloadURL=https://download.code42.com/installs/agent/latest-mac.dmg + if [[ $(arch) == i386 ]]; then + downloadURL="https://download.code42.com/installs/agent/latest-mac.dmg" + elif [[ $(arch) == arm64 ]]; then + downloadURL="https://download.code42.com/installs/agent/latest-mac-arm64.dmg" + fi expectedTeamID="9YV9435DHD" blockingProcesses=( NONE ) ;; @@ -1539,12 +1852,19 @@ cyberduck) appNewVersion=$(curl -fs https://version.cyberduck.io/changelog.rss | xpath '//rss/channel/item/enclosure/@sparkle:shortVersionString' 2>/dev/null | cut -d '"' -f 2 ) expectedTeamID="G69SCX94XU" ;; +daisydisk) + name="DaisyDisk" + type="zip" + downloadURL="https://daisydiskapp.com/downloads/DaisyDisk.zip" + appNewVersion=$( curl -fs 'https://daisydiskapp.com/downloads/appcastReleaseNotes.php?appEdition=Standard' | grep Version | head -1 | sed -E 's/.*Version ([0-9.]*).*/\1/g' ) + expectedTeamID="4CBU3JHV97" + ;; dangerzone) - # credit: Micah Lee (@micahflee) name="Dangerzone" type="dmg" - downloadURL=$(curl -s https://dangerzone.rocks/ | grep https://github.com/firstlookmedia/dangerzone/releases/download | grep \.dmg | cut -d'"' -f2) - expectedTeamID="P24U45L8P5" + downloadURL="$(downloadURLFromGit firstlookmedia dangerzone)" + appNewVersion="$(versionFromGit firstlookmedia dangerzone)" + expectedTeamID="N9B95FDWH4" ;; darktable) # credit: Søren Theilgaard (@theilgaard) @@ -1576,10 +1896,11 @@ defaultfolderx) ;; depnotify) name="DEPNotify" - type="zip" - downloadURL="https://files.nomad.menu/DEPNotify.zip" + type="pkg" + #packageID="menu.nomad.depnotify" + downloadURL="https://files.nomad.menu/DEPNotify.pkg" + #appNewVersion=$() expectedTeamID="VRPY9KHGX6" - targetDir="/Applications/Utilities" ;; desktoppr) name="desktoppr" @@ -1628,17 +1949,24 @@ discord) downloadURL="https://discordapp.com/api/download?platform=osx" expectedTeamID="53Q6R32WPB" ;; +diskspace) + name="diskspace" + type="pkg" + packageID="com.scriptingosx.diskspace" + downloadURL="$(downloadURLFromGit scriptingosx diskspace)" + appNewVersion="$(versionFromGit scriptingosx diskspace)" + expectedTeamID="JME5BW3F3R" + ;; docker) - # credit: @securitygeneration name="Docker" type="dmg" - #downloadURL="https://download.docker.com/mac/stable/Docker.dmg" if [[ $(arch) == arm64 ]]; then downloadURL="https://desktop.docker.com/mac/stable/arm64/Docker.dmg" + appNewVersion=$( curl -fs "https://desktop.docker.com/mac/main/arm64/appcast.xml" | xpath '(//rss/channel/item/enclosure/@sparkle:shortVersionString)[last()]' 2>/dev/null | cut -d '"' -f2 ) elif [[ $(arch) == i386 ]]; then downloadURL="https://desktop.docker.com/mac/stable/amd64/Docker.dmg" + appNewVersion=$( curl -fs "https://desktop.docker.com/mac/main/amd64/appcast.xml" | xpath '(//rss/channel/item/enclosure/@sparkle:shortVersionString)[last()]' 2>/dev/null | cut -d '"' -f2 ) fi - appNewVersion=$(curl -ifs https://docs.docker.com/docker-for-mac/release-notes/ | grep ">Docker Desktop Community" | head -1 | sed -n -e 's/^.*Community //p' | cut -d '<' -f1) expectedTeamID="9BNSXJN65R" ;; drift) @@ -1686,7 +2014,7 @@ eraseinstall) eshareosx) name="e-Share" type="pkg" - packageID="com.ncryptedcloud.e-Share.pkg" + #packageID="com.ncryptedcloud.e-Share.pkg" downloadURL=https://www.ncryptedcloud.com/static/downloads/osx/$(curl -fs https://www.ncryptedcloud.com/static/downloads/osx/ | grep -o -i "href.*\".*\"" | cut -d '"' -f2) versionKey="CFBundleVersion" appNewVersion=$( echo "${downloadURL}" | sed -E 's/.*\/[a-zA-Z\-]*_([0-9.]*)\.pkg/\1/g' ) @@ -1702,7 +2030,7 @@ etrecheck) evernote) name="Evernote" type="dmg" - downloadURL=$(curl -fs -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15)" "https://evernote.com/download" | grep -i ".dmg" | cut -d '"' -f2) + downloadURL=$(curl -fs -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15)" "https://evernote.com/download" | grep -i ".dmg" | grep -ioe "href.*" | cut -d '"' -f2) appNewVersion=$( echo "${downloadURL}" | sed -E 's/.*\/[a-zA-Z]*-([0-9.]*)-.*/\1/g' ) expectedTeamID="Q79WDW8YH9" appName="Evernote.app" @@ -1747,13 +2075,12 @@ favro) ferdi) name="Ferdi" type="zip" - if [[ $(arch) == i386 ]]; then - downloadURL=$(curl --silent --fail "https://api.github.com/repos/getferdi/ferdi/releases/latest" \ - | awk -F '"' "/browser_download_url/ && /mac.zip/ && ! /blockmap/ && ! /arm64-mac/ && ! /AppImage/{ print \$4 }") - elif [[ $(arch) == arm64 ]]; then - downloadURL=$(downloadURLFromGit getferdi ferdi ) - archiveName="arm64-mac.zip" - fi + if [[ $(arch) == "arm64" ]]; then + archiveName="arm64-mac.zip" + elif [[ $(arch) == "i386" ]]; then + archiveName="Ferdi-[0-9.]*-mac.zip" + fi + downloadURL="$(downloadURLFromGit getferdi ferdi)" appNewVersion=$(versionFromGit getferdi ferdi ) expectedTeamID="B6J9X9DWFL" ;; @@ -1862,10 +2189,23 @@ flowjo) expectedTeamID="C79HU5AD9V" appName="FlowJo.app" ;; +flux) + name="Flux" + type="zip" + downloadURL="https://justgetflux.com/mac/Flux.zip" + expectedTeamID="VZKSA7H9J9" + ;; + front) name="Front" type="dmg" - downloadURL="https://dl.frontapp.com/macos/Front.dmg" + if [[ $(arch) == "arm64" ]]; then + downloadURL="https://dl.frontapp.com/macos/Front-arm64.dmg" + appNewVersion=$(curl -fs "https://dl.frontapp.com/desktop/updates/latest/mac-arm64/latest-mac.yml" | grep -i version | cut -d " " -f2) + elif [[ $(arch) == "i386" ]]; then + downloadURL="https://dl.frontapp.com/macos/Front.dmg" + appNewVersion=$(curl -fs "https://dl.frontapp.com/desktop/updates/latest/mac/latest-mac.yml" | grep -i version | cut -d " " -f2) + fi expectedTeamID="X549L7572J" Company="FrontApp. Inc." ;; @@ -1894,12 +2234,11 @@ githubdesktop) expectedTeamID="VEKTX9H2N7" ;; golang) - # credit: Søren Theilgaard (@theilgaard) name="GoLang" type="pkg" packageID="org.golang.go" - downloadURL="$(curl -fsIL "https://golang.org$(curl -fs "https://golang.org/dl/" | grep -i "downloadBox" | grep "pkg" | tr '"' '\n' | grep "pkg")" | grep -i "^location" | awk '{print $2}' | tr -d '\r\n')" - appNewVersion="$( echo "${downloadURL}" | sed -E 's/.*\/(go[0-9.]*)\..*/\1/g' )" # Version includes letters "go" + downloadURL="https://go.dev$(curl -fs "https://go.dev/dl/" | grep -i "downloadBox" | grep "pkg" | tr '"' '\n' | grep "pkg")" + appNewVersion="$( echo "${downloadURL}" | sed -E 's/.*\/(go[0-9.]*)\..*/\1/g' )" # Version includes letters "go" in the beginning expectedTeamID="EQHXZ8M8AV" blockingProcesses=( NONE ) ;; @@ -1983,12 +2322,14 @@ gpgsuite) pkgName="Install.pkg" downloadURL=$(curl -s https://gpgtools.org/ | grep https://releases.gpgtools.org/GPG_Suite- | grep Download | cut -d'"' -f4) expectedTeamID="PKV8ZPD836" + blockingProcesses=( "GPG Keychain" ) ;; gpgsync) - # credit: Micah Lee (@micahflee) name="GPG Sync" type="pkg" - downloadURL="https://github.com$(curl -s -L https://github.com/firstlookmedia/gpgsync/releases/latest | grep /firstlookmedia/gpgsync/releases/download | grep \.pkg | cut -d'"' -f2)" + packageID="org.firstlook.gpgsync" + downloadURL="$(downloadURLFromGit firstlookmedia gpgsync)" + appNewVersion="$(versionFromGit firstlookmedia gpgsync)" expectedTeamID="P24U45L8P5" ;; grandperspective) @@ -2071,6 +2412,13 @@ hyper) appNewVersion=$(versionFromGit vercel hyper) expectedTeamID="JW6Y669B67" ;; +ibarcoder) + name="iBarcoder" + type="dmg" + downloadURL="https://cristallight.com/Downloads/mac/ibarcoder.dmg" + appNewVersion="$(curl -fs "https://cristallight.com/iBarcoder/" | grep -i version: | head -1 | awk '{print $2}')" + expectedTeamID="JAXVB9AH9M" + ;; icons) # credit: Mischa van der Bent (@mischavdbent) name="Icons" @@ -2079,6 +2427,13 @@ icons) appNewVersion=$(versionFromGit sap macOS-icon-generator ) expectedTeamID="7R5ZEU67FQ" ;; +iina) + name="IINA" + type="dmg" + downloadURL=$(downloadURLFromGit iina iina ) + appNewVersion=$(versionFromGit iina iina ) + expectedTeamID="67CQ77V27R" + ;; imazingprofileeditor) # Credit: Bilal Habib @Pro4TLZZ name="iMazing Profile Editor" @@ -2129,6 +2484,13 @@ iterm2) expectedTeamID="H7V7XYVQ7D" blockingProcesses=( iTerm2 ) ;; +itsycal) + name="Itsycal" + type="zip" + downloadURL=$(curl -fs https://s3.amazonaws.com/itsycal/itsycal-apple-silicon.xml | xpath '(//rss/channel/item/enclosure/@url)[1]' 2>/dev/null | head -1 | cut -d '"' -f 2) + appNewVersion=$(curl -fs https://s3.amazonaws.com/itsycal/itsycal-apple-silicon.xml | xpath '(//rss/channel/item/enclosure/@sparkle:shortVersionString)[1]' 2>/dev/null | head -1 | cut -d '"' -f 2) + expectedTeamID="HFT3T55WND" + ;; jabradirect) name="Jabra Direct" type="pkgInDmg" @@ -2395,20 +2757,25 @@ lexarrecoverytool) expectedTeamID="Y8HM6WR2DV" ;; libreoffice) - # credit: Micah Lee (@micahflee) name="LibreOffice" type="dmg" - downloadURL="https://download.documentfoundation.org/libreoffice/stable/$(curl -s https://www.libreoffice.org/download/download/ | grep dl_version_number | head -n 1 | cut -d'>' -f3 | cut -d'<' -f1)/mac/x86_64/LibreOffice_$(curl -s https://www.libreoffice.org/download/download/ | grep dl_version_number | head -n 1 | cut -d'>' -f3 | cut -d'<' -f1)_MacOS_x86-64.dmg" + if [[ $(arch) == "arm64" ]]; then + downloadURL="https://download.documentfoundation.org/libreoffice/stable/$(curl -s https://www.libreoffice.org/download/download/ | grep dl_version_number | head -n 1 | cut -d'>' -f3 | cut -d'<' -f1)/mac/aarch64/LibreOffice_$(curl -s https://www.libreoffice.org/download/download/ | grep dl_version_number | head -n 1 | cut -d'>' -f3 | cut -d'<' -f1)_MacOS_aarch64.dmg" + elif [[ $(arch) == "i386" ]]; then + downloadURL="https://download.documentfoundation.org/libreoffice/stable/$(curl -s https://www.libreoffice.org/download/download/ | grep dl_version_number | head -n 1 | cut -d'>' -f3 | cut -d'<' -f1)/mac/x86_64/LibreOffice_$(curl -s https://www.libreoffice.org/download/download/ | grep dl_version_number | head -n 1 | cut -d'>' -f3 | cut -d'<' -f1)_MacOS_x86-64.dmg" + fi appNewVersion=$( echo "${downloadURL}" | sed -E 's/.*\/[a-zA-Z]*_([0-9.]*)_.*/\1/g' ) expectedTeamID="7P5S3ZLCN7" + blockingProcesses=( soffice ) ;; logitechoptions) - # credit: AP Orlebeke (@apizz) name="Logitech Options" type="pkgInZip" - downloadURL=$(curl -fs -L https://www.logitech.com/en-us/product/options | grep -m 1 -o "https.*zip" | sed 's/\"//' | awk '{print $1}') - #appNewVersion=$(curl -fs -L https://www.logitech.com/en-us/product/options | grep -m 1 -o "https.*zip" | sed 's/\"//' | awk '{print $1}' | sed -E 's/.*_([0-9\.]*)[-\.].*/\1/' ) - pkgName="LogiMgr Installer ${appNewVersion}.app/Contents/Resources/LogiMgr.pkg" + #downloadURL=$(curl -fs "https://support.logi.com/api/v2/help_center/en-us/articles.json?label_names=webcontent=productdownload,webos=mac-macos-x-11.0" | tr "," "\n" | grep -A 10 "macOS" | grep -oie "https.*/.*/options/.*\.zip" | head -1) + downloadURL="https://download01.logi.com/web/ftp/pub/techsupport/options/options_installer.zip" + appNewVersion=$(curl -fs "https://support.logi.com/api/v2/help_center/en-us/articles.json?label_names=webcontent=productdownload,webos=mac-macos-x-11.0" | tr "," "\n" | grep -A 10 "macOS" | grep -B 5 -ie "https.*/.*/options/.*\.zip" | grep "Software Version" | sed 's/\\u[0-9a-z][0-9a-z][0-9a-z][0-9a-z]//g' | grep -ioe "Software Version.*[0-9.]*" | tr "/" "\n" | grep -oe "[0-9.]*" | head -1) + #pkgName="LogiMgr Installer "*".app/Contents/Resources/LogiMgr.pkg" + pkgName=LogiMgr.pkg expectedTeamID="QED4VVPZWA" ;; logseq) @@ -2432,6 +2799,13 @@ loom) appNewVersion=$(curl -fs https://s3-us-west-2.amazonaws.com/loom.desktop.packages/loom-inc-production/desktop-packages/latest-mac.yml | awk '/version/ {print $2}' ) expectedTeamID="QGD2ZPXZZG" ;; +lowprofile) + name="Low Profile" + type="dmg" + downloadURL="$(downloadURLFromGit ninxsoft LowProfile)" + appNewVersion="$(versionFromGit ninxsoft LowProfile)" + expectedTeamID="7K3HVCLV7Z" + ;; lucifer) # credit: Drew Diver (@grumpydrew on MacAdmins Slack) name="Lucifer" @@ -2522,9 +2896,9 @@ mattermost) type="dmg" archiveName="mac-universal.dmg" downloadURL=$(downloadURLFromGit mattermost desktop) - appNewVersion=$(versionFromGit mattermost desktop ) + appNewVersion=$(versionFromGit mattermost desktop) expectedTeamID="UQ8HT4Q2XM" - Mattermost Helper (Renderer).app app.asar + blockingProcesses=( "Mattermost Helper.app" "Mattermost Helper (Renderer).app" "Mattermost Helper (GPU).app" "Mattermost Helper (Plugin).app" ) ;; menumeters) name="MenuMeters" @@ -2800,6 +3174,94 @@ miro) downloadURL="https://desktop.miro.com/platforms/darwin/Miro.dmg" expectedTeamID="M3GM7MFY7U" ;; +mobikinassistantforandroid) + name="MobiKin Assistant for Android" + type="dmg" + downloadURL="https://www.mobikin.com/downloads/mobikin-android-assistant.dmg" + versionKey="CFBundleVersion" + appNewVersion=$(curl -fs https://www.mobikin.com/assistant-for-android-mac/ | grep -i "version:" | sed -E 's/.*Version: ([0-9.]*)<.*/\1/g') + expectedTeamID="YNL42PA5C4" + ;; +mochakeyboard) + name="Mocha Keyboard" + type="appInDmgInZip" + downloadURL="https://mochasoft.dk/mochakeyboard.dmg.zip" + curlOptions=( -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15" +-H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" +-H "accept-encoding: gzip, deflate, br" +-H "accept-language: en-US,en;q=0.9" +-H "sec-fetch-dest: document" +-H "sec-fetch-mode: navigate" +-H "sec-fetch-user: ?1" +-H "sec-gpc: 1" +-H "upgrade-insecure-requests: 1" ) + appNewVersion="" + expectedTeamID="RR9F5EPNVW" + ;; +mochatelnet) + name="Telnet" + type="appInDmgInZip" + downloadURL="https://mochasoft.dk/telnet.dmg.zip" + curlOptions=( -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15" +-H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" +-H "accept-encoding: gzip, deflate, br" +-H "accept-language: en-US,en;q=0.9" +-H "sec-fetch-dest: document" +-H "sec-fetch-mode: navigate" +-H "sec-fetch-user: ?1" +-H "sec-gpc: 1" +-H "upgrade-insecure-requests: 1" ) + appNewVersion="" + expectedTeamID="RR9F5EPNVW" + ;; +mochatn3270) + name="TN3270" + type="appInDmgInZip" + downloadURL="https://mochasoft.dk/tn3270.dmg.zip" + curlOptions=( -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15" +-H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" +-H "accept-encoding: gzip, deflate, br" +-H "accept-language: en-US,en;q=0.9" +-H "sec-fetch-dest: document" +-H "sec-fetch-mode: navigate" +-H "sec-fetch-user: ?1" +-H "sec-gpc: 1" +-H "upgrade-insecure-requests: 1" ) + appNewVersion="" + expectedTeamID="RR9F5EPNVW" + ;; +mochatn3812) + name="TN3812" + type="appInDmgInZip" + downloadURL="https://mochasoft.dk/tn3812.dmg.zip" + curlOptions=( -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15" +-H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" +-H "accept-encoding: gzip, deflate, br" +-H "accept-language: en-US,en;q=0.9" +-H "sec-fetch-dest: document" +-H "sec-fetch-mode: navigate" +-H "sec-fetch-user: ?1" +-H "sec-gpc: 1" +-H "upgrade-insecure-requests: 1" ) + appNewVersion="" + expectedTeamID="Frydendal" + ;; +mochatn5250) + name="TN5250" + type="appInDmgInZip" + downloadURL="https://mochasoft.dk/tn5250.dmg.zip" + curlOptions=( -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15" +-H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" +-H "accept-encoding: gzip, deflate, br" +-H "accept-language: en-US,en;q=0.9" +-H "sec-fetch-dest: document" +-H "sec-fetch-mode: navigate" +-H "sec-fetch-user: ?1" +-H "sec-gpc: 1" +-H "upgrade-insecure-requests: 1" ) + appNewVersion="" + expectedTeamID="RR9F5EPNVW" + ;; montereyblocker) name="montereyblocker" type="pkg" @@ -3018,7 +3480,6 @@ ottomatic) appNewVersion=$(versionFromGit jorio OttoMatic) expectedTeamID="RVNL7XC27G" ;; - overflow) name="Overflow" type="dmg" @@ -3042,6 +3503,13 @@ pandoc) archiveName="mac.pkg" expectedTeamID="5U2WKE6DES" ;; +paretosecurity) + name="Pareto Security" + type="dmg" + downloadURL=$(downloadURLFromGit ParetoSecurity pareto-mac) + appNewVersion=$(versionFromGit ParetoSecurity pareto-mac) + expectedTeamID="PM784W7B8X" + ;; parsec) name="Parsec" type="pkg" @@ -3102,6 +3570,19 @@ prism9) downloadURL="https://cdn.graphpad.com/downloads/prism/9/InstallPrism9.dmg" expectedTeamID="YQ2D36NS9M" ;; +pritunl) + name="Pritunl" + type="pkgInZip" + packageID="com.pritunl.pkg.Pritunl" + if [[ $(arch) == "arm64" ]]; then + archiveName="Pritunl.arm64.pkg.zip" + elif [[ $(arch) == "i386" ]]; then + archiveName="Pritunl.pkg.zip" + fi + downloadURL=$(downloadURLFromGit pritunl pritunl-client-electron) + appNewVersion=$(versionFromGit pritunl pritunl-client-electron) + expectedTeamID="U22BLATN63" + ;; privileges) # credit: Erik Stam (@erikstam) name="Privileges" @@ -3117,6 +3598,7 @@ proctortrack) downloadURL="https://storage.googleapis.com/verificientstatic/ProctortrackApp/Production/Proctortrack.zip" expectedTeamID="SNHZD6TJE6" ;; +promiseutility|\ promiseutilityr) name="Promise Utility" type="pkgInDmg" @@ -3124,13 +3606,21 @@ promiseutilityr) downloadURL="https://www.promise.com/DownloadFile.aspx?DownloadFileUID=6533" expectedTeamID="268CCUR4WN" ;; +protonvpn) + name="ProtonVPN" + type="dmg" + downloadURL=$(curl -fs "https://protonvpn.com/download" | grep -Eo "(http|https)://[a-zA-Z0-9./?=_%:-]*\.dmg" | head -1) + appNewVersion=$(echo $downloadURL | sed -e 's/^.*\/Proton.*_v\([0-9.]*\)\.dmg/\1/g') + expectedTeamID="J6S6Q257EK" + ;; proxyman) - name="Proxyman" - type="dmg" - downloadURL="https://proxyman.io/release/osx/Proxyman_latest.dmg" - expectedTeamID="3X57WP8E8V" - appNewVersion=$(curl -s -L https://github.com/ProxymanApp/Proxyman | grep -o 'releases/tag/.*\>' | awk -F '/' '{print $3}') - ;; + name="Proxyman" + type="dmg" + #downloadURL="https://proxyman.io/release/osx/Proxyman_latest.dmg" + downloadURL="$(downloadURLFromGit ProxymanApp Proxyman)" + appNewVersion="$(versionFromGit ProxymanApp Proxyman)" + expectedTeamID="3X57WP8E8V" + ;; pymol) name="PyMOL" type="dmg" @@ -3151,6 +3641,15 @@ ramboxce) appNewVersion=$(versionFromGit ramboxapp community-edition ) expectedTeamID="7F292FPD69" ;; +rancherdesktop) + name="Rancher.Desktop-1.0.0-mac" + type="zip" + archiveName="Rancher.Desktop-[0-9.]*-mac.zip" + downloadURL="$(downloadURLFromGit rancher-sandbox rancher-desktop)" + appNewVersion="$(versionFromGit rancher-sandbox rancher-desktop)" + expectedTeamID="2Q6FHJR3H3" + appName="Rancher Desktop.app" + ;; rectangle) name="Rectangle" type="dmg" @@ -3166,6 +3665,20 @@ redeye) appNewVersion=$( curl -fs "https://www.hexedbits.com/redeye/" | grep "Latest version" | sed -E 's/.*Latest version ([0-9.]*),.*/\1/g' ) expectedTeamID="5VRJU68BZ5" ;; +remotedesktopmanagerenterprise) + name="Remote Desktop Manager" + type="dmg" + downloadURL=$(curl -fs https://remotedesktopmanager.com/home/thankyou/rdmmacbin | grep -oe "http.*\.dmg" | head -1) + appNewVersion=$(echo "$downloadURL" | sed -E 's/.*\.Mac\.([0-9.]*)\.dmg/\1/g') + expectedTeamID="N592S9ASDB" + ;; +remotedesktopmanagerfree) + name="Remote Desktop Manager Free" + type="dmg" + downloadURL=$(curl -fs https://remotedesktopmanager.com/home/thankyou/rdmmacfreebin | grep -oe "http.*\.dmg" | head -1) + appNewVersion=$(echo "$downloadURL" | sed -E 's/.*\.Mac\.([0-9.]*)\.dmg/\1/g') + expectedTeamID="N592S9ASDB" + ;; remotix) name="Remotix" type="dmg" @@ -3307,6 +3820,21 @@ screenflick) downloadURL="https://www.araelium.com/screenflick/downloads/Screenflick.zip" expectedTeamID="28488A87JB" ;; +sdnotary) + name="SD Notary" + type="zip" + downloadURL=$(curl -fs https://latenightsw.com/sd-notary-notarizing-made-easy/ | grep -io "https://.*/.*\.zip") + appNewVersion=$(echo "$downloadURL" | sed -E 's/.*\/[a-zA-Z]*([0-9.]*)-.*\.zip/\1/g') + expectedTeamID="Z7S6X96M3X" + ;; +secretive) + name="Secretive" + type="zip" + downloadURL=$(downloadURLFromGit maxgoedjen secretive) + appNewVersion=$(versionFromGit maxgoedjen secretive) + expectedTeamID="Z72PRUAWF6" + ;; + sequelpro) name="Sequel Pro" type="dmg" @@ -3330,10 +3858,9 @@ sidekick) expectedTeamID="N975558CUS" ;; signal) - # credit: Søren Theilgaard (@theilgaard) name="Signal" type="dmg" - downloadURL=https://updates.signal.org/desktop/$(curl -fs https://updates.signal.org/desktop/latest-mac.yml | awk '/url/ && /dmg/ {print $3}') + downloadURL=https://updates.signal.org/desktop/$(curl -fs https://updates.signal.org/desktop/latest-mac.yml | awk '/url/ && /dmg/ {print $3}' | grep -i universal) appNewVersion=$(curl -fs https://updates.signal.org/desktop/latest-mac.yml | grep version | awk '{print $2}') expectedTeamID="U68MSDN6DR" ;; @@ -3540,6 +4067,14 @@ tableaudesktop) downloadURL="https://www.tableau.com/downloads/desktop/mac" expectedTeamID="QJ4XPRK37C" ;; +tableaupublic) + name="Tableau Public" + type="pkgInDmg" + packageID="com.tableausoftware.tableaudesktop" + downloadURL=$(curl -fs https://www.tableau.com/downloads/public/mac | awk '/TableauPublic/' | xmllint --recover --html --xpath "//a/text()" -) + appNewVersion=$( echo $downloadURL | sed -E 's/.*TableauPublic-([-0-9]*)\.dmg/\1/g' | tr "-" "." ) + expectedTeamID="QJ4XPRK37C" + ;; tableaureader) name="Tableau Reader" type="pkgInDmg" @@ -3551,7 +4086,7 @@ tageditor) name="Tag Editor" type="dmg" downloadURL="https://amvidia.com/downloads/tag-editor-mac.dmg" - appNewVersion=curl -sf "https://amvidia.com/tag-editor" | grep -o -E '"softwareVersion":.'"{8}" | sed 's/\"//g' | awk -F ': ' '{print $2}' + appNewVersion=$(curl -sf "https://amvidia.com/tag-editor" | grep -o -E '"softwareVersion":.'"{8}" | sed -E 's/.*"([0-9.]*).*/\1/g') expectedTeamID="F2TH9XX9CJ" ;; talkdeskcallbar) @@ -3611,9 +4146,9 @@ telegram) ;; textexpander) name="TextExpander" - type="zip" - downloadURL="https://textexpander.com/cgi-bin/redirect.pl?cmd=download&platform=osx" - appNewVersion=$( curl -fsIL "https://textexpander.com/cgi-bin/redirect.pl?cmd=download&platform=osx" | grep -i "^location" | awk '{print $2}' | tail -1 | cut -d "_" -f2 | sed -nre 's/^[^0-9]*(([0-9]+\.)*[0-9]+).*/\1/p' ) + type="dmg" + downloadURL="https://cgi.textexpander.com/cgi-bin/redirect.pl?cmd=download&platform=osx" + appNewVersion=$( curl -fsIL "https://cgi.textexpander.com/cgi-bin/redirect.pl?cmd=download&platform=osx" | grep -i "^location" | awk '{print $2}' | tail -1 | cut -d "_" -f2 | sed -nre 's/^[^0-9]*(([0-9]+\.)*[0-9]+).*/\1/p' ) expectedTeamID="7PKJ6G4DXL" ;; textmate) @@ -3645,6 +4180,13 @@ thunderbird) expectedTeamID="43AQ936H96" blockingProcesses=( thunderbird ) ;; +tidal) + name="TIDAL" + type="dmg" + downloadURL="https://download.tidal.com/desktop/TIDAL.dmg" + appNewVersion=$(curl -fs https://update.tidal.com/updates/latest\?v\=1 | cut -d '"' -f4 | sed -E 's/https.*\/TIDAL\.([0-9.]*)\.zip/\1/g') + expectedTeamID="GK2243L7KB" + ;; toggltrack) name="Toggl Track" type="dmg" @@ -3656,7 +4198,7 @@ tom4aconverter) name="To M4A Converter" type="dmg" downloadURL="https://amvidia.com/downloads/to-m4a-converter-mac.dmg" - appNewVersion=curl -sf "https://amvidia.com/to-m4a-converter" | grep -o -E '"softwareVersion":.'"{8}" | sed 's/\"//g' | awk -F ': ' '{print $2}' + appNewVersion=$(curl -sf "https://amvidia.com/to-m4a-converter" | grep -o -E '"softwareVersion":.'"{8}" | sed 's/\"//g' | awk -F ': ' '{print $2}') expectedTeamID="F2TH9XX9CJ" ;; torbrowser) @@ -3746,6 +4288,13 @@ veracrypt) appNewVersion=$( echo "${downloadURL}" | sed -E 's/.*\/[a-zA-Z]*_([0-9.]*.*)\.dmg/\1/g' ) expectedTeamID="Z933746L2S" ;; +vimac) + name="Vimac" + type="zip" + downloadURL=$(curl -fs "https://vimacapp.com/latest-release-metadata" | tr ',' '\n' | awk -F\" '/download_url/ {print $4}') + appNewVersion=$(curl -fs "https://vimacapp.com/latest-release-metadata" | tr ',' '\n' | awk -F\" '/short_version/ {print $4}') + expectedTeamID="LQ2VH8VB84" + ;; virtualbox) # credit: AP Orlebeke (@apizz) name="VirtualBox" @@ -3801,15 +4350,16 @@ vscodium) wacomdrivers) name="Wacom Desktop Center" type="pkgInDmg" - downloadURL="$(curl -fs https://www.wacom.com/en-us/support/product-support/drivers | grep -e "drivers/mac/professional.*dmg" | head -1 | sed -e 's/data-download-link="//g' -e 's/"//' | awk '{$1=$1}{ print }' | sed 's/\r//')" + downloadURL="$(curl -fs https://www.wacom.com/en-us/support/product-support/drivers | grep -e "drivers/mac/professional.*dmg" | head -1 | tr '"' "\n" | grep -i http)" expectedTeamID="EG27766DY7" - pkgName="Install Wacom Tablet.pkg" - appNewVersion="$(curl -fs https://www.wacom.com/en-us/support/product-support/drivers | grep mac/professional/releasenotes | head -1 | awk -F"|" '{print $1}' | awk -F"Driver" '{print $3}' | sed -e 's/ (.*//g' | tr -d ' ')" + #pkgName="Install Wacom Tablet.pkg" + appNewVersion="$(curl -fs https://www.wacom.com/en-us/support/product-support/drivers | grep mac/professional/releasenotes | head -1 | tr '"' "\n" | grep -e "Driver [0-9][-0-9.]*" | sed -E 's/Driver ([-0-9.]*).*/\1/g')" ;; wallyezflash) name="Wally" type="dmg" downloadURL="https://configure.zsa.io/wally/osx" + # 2022-02-07: Info.plist is totally wrong defined and contains no version information #appNewVersion=$(curl -fsIL "${downloadURL}" | grep -i ^location | head -1 | sed -E 's/.*\/[a-zA-Z\-]*-([0-9.]*)\..*/\1/g') expectedTeamID="V32BWKSNYH" #versionKey="CFBundleVersion" @@ -3859,11 +4409,14 @@ wickrpro) expectedTeamID="W8RC3R952A" ;; wireshark) - # credit: Oh4sh0 https://github.com/Oh4sh0 name="Wireshark" type="dmg" - downloadURL="https://1.as.dl.wireshark.org/osx/Wireshark%20Latest%20Intel%2064.dmg" - appNewVersion=$(curl -fs https://www.wireshark.org/download.html | grep "Stable Release" | grep -o "(.*.)" | cut -f2 | head -1 | awk -F '[()]' '{print $2}') + if [[ $(arch) == i386 ]]; then + downloadURL="https://1.as.dl.wireshark.org/osx/Wireshark%20Latest%20Intel%2064.dmg" + elif [[ $(arch) == arm64 ]]; then + downloadURL="https://1.as.dl.wireshark.org/osx/Wireshark%20Latest%20Arm%2064.dmg" + fi + appNewVersion=$(curl -fs https://www.wireshark.org/download.html | grep -i "href.*_stable" | sed -E 's/.*\(([0-9.]*)\).*/\1/g') expectedTeamID="7Z6EMTD2C6" ;; wwdc) @@ -3989,9 +4542,9 @@ zulujdk11) type="pkgInDmg" packageID="com.azulsystems.zulu.11" if [[ $(arch) == i386 ]]; then - downloadURL=$(curl -fs "https://www.azul.com/downloads/zulu-community/" | xmllint --html --format - 2>/dev/null | tr , '\n' | grep -o "https:.*/zulu11.*ca-jdk11.*x64.dmg" | sed 's/\\//g') + downloadURL=https://cdn.azul.com/zulu/bin/$(curl -fs "https://cdn.azul.com/zulu/bin/" | grep -Eio '">zulu11.*ca-jdk11.*x64.dmg(.*)' | cut -c3- | sed 's/<\/a>//' | sed -E 's/([0-9.]*)M//' | awk '{print $2 $1}' | sort | cut -c11- | tail -1) elif [[ $(arch) == arm64 ]]; then - downloadURL=$(curl -fs "https://www.azul.com/downloads/zulu-community/" | xmllint --html --format - 2>/dev/null | tr , '\n' | grep -o "https:.*/zulu11.*ca-jdk11.*aarch64.dmg" | sed 's/\\//g') + downloadURL=https://cdn.azul.com/zulu/bin/$(curl -fs "https://cdn.azul.com/zulu/bin/" | grep -Eio '">zulu11.*ca-jdk11.*aarch64.dmg(.*)' | cut -c3- | sed 's/<\/a>//' | sed -E 's/([0-9.]*)M//' | awk '{print $2 $1}' | sort | cut -c11- | tail -1) fi expectedTeamID="TDTHCUPYFR" appCustomVersion(){ java -version 2>&1 | grep Runtime | awk '{print $4}' | sed -e "s/.*Zulu//" | cut -d '-' -f 1 | sed -e "s/+/\./" } @@ -4015,9 +4568,22 @@ zulujdk15) type="pkgInDmg" packageID="com.azulsystems.zulu.15" if [[ $(arch) == i386 ]]; then - downloadURL=$(curl -fs "https://www.azul.com/downloads/zulu-community/" | xmllint --html --format - 2>/dev/null | tr , '\n' | grep -o "https:.*/zulu15.*ca-jdk15.*x64.dmg" | sed 's/\\//g') + downloadURL=https://cdn.azul.com/zulu/bin/$(curl -fs "https://cdn.azul.com/zulu/bin/" | grep -Eio '">zulu15.*ca-jdk15.*x64.dmg(.*)' | cut -c3- | sed 's/<\/a>//' | sed -E 's/([0-9.]*)M//' | awk '{print $2 $1}' | sort | cut -c11- | tail -1) elif [[ $(arch) == arm64 ]]; then - downloadURL=$(curl -fs "https://www.azul.com/downloads/zulu-community/" | xmllint --html --format - 2>/dev/null | tr , '\n' | grep -o "https:.*/zulu15.*ca-jdk15.*aarch64.dmg" | sed 's/\\//g') + downloadURL=https://cdn.azul.com/zulu/bin/$(curl -fs "https://cdn.azul.com/zulu/bin/" | grep -Eio '">zulu15.*ca-jdk15.*aarch64.dmg(.*)' | cut -c3- | sed 's/<\/a>//' | sed -E 's/([0-9.]*)M//' | awk '{print $2 $1}' | sort | cut -c11- | tail -1) + fi + expectedTeamID="TDTHCUPYFR" + appCustomVersion(){ java -version 2>&1 | grep Runtime | awk '{print $4}' | sed -e "s/.*Zulu//" | cut -d '-' -f 1 | sed -e "s/+/\./" } + appNewVersion=$(echo "$downloadURL" | cut -d "-" -f 1 | sed -e "s/.*zulu//") # Cannot be compared to anything + ;; +zulujdk17) + name="Zulu JDK 17" + type="pkgInDmg" + packageID="com.azulsystems.zulu.17" + if [[ $(arch) == i386 ]]; then + downloadURL=https://cdn.azul.com/zulu/bin/$(curl -fs "https://cdn.azul.com/zulu/bin/" | grep -Eio '">zulu17.*ca-jdk17.*x64.dmg(.*)' | cut -c3- | sed 's/<\/a>//' | sed -E 's/([0-9.]*)M//' | awk '{print $2 $1}' | sort | cut -c11- | tail -1) + elif [[ $(arch) == arm64 ]]; then + downloadURL=https://cdn.azul.com/zulu/bin/$(curl -fs "https://cdn.azul.com/zulu/bin/" | grep -Eio '">zulu17.*ca-jdk17.*aarch64.dmg(.*)' | cut -c3- | sed 's/<\/a>//' | sed -E 's/([0-9.]*)M//' | awk '{print $2 $1}' | sort | cut -c11- | tail -1) fi expectedTeamID="TDTHCUPYFR" appCustomVersion(){ java -version 2>&1 | grep Runtime | awk '{print $4}' | sed -e "s/.*Zulu//" | cut -d '-' -f 1 | sed -e "s/+/\./" } @@ -4043,11 +4609,26 @@ zulujdk8) ;; esac +# Are we only asked to return label name +if [[ $RETURN_LABEL_NAME -eq 1 ]]; then + printlog "Only returning label name." + printlog "$name" + echo "$name" + exit +fi # MARK: application download and installation starts here +if [[ ${INTERRUPT_DND} = "no" ]]; then + # Check if a fullscreen app is active + if hasDisplaySleepAssertion; then + cleanupAndExit 1 "active display sleep assertion detected, aborting" + fi +fi + printlog "BLOCKING_PROCESS_ACTION=${BLOCKING_PROCESS_ACTION}" printlog "NOTIFY=${NOTIFY}" +printlog "LOGGING=${LOGGING}" # Finding LOGO to use in dialogs case $LOGO in @@ -4066,14 +4647,17 @@ case $LOGO in mosyleb) # Mosyle Business LOGO="/Applications/Self-Service.app/Contents/Resources/AppIcon.icns" + if [[ -z $MDMProfileName ]]; then; MDMProfileName="Mosyle Corporation MDM"; fi ;; mosylem) # Mosyle Manager (education) LOGO="/Applications/Manager.app/Contents/Resources/AppIcon.icns" + if [[ -z $MDMProfileName ]]; then; MDMProfileName="Mosyle Corporation MDM"; fi ;; addigy) # Addigy LOGO="/Library/Addigy/macmanage/MacManage.app/Contents/Resources/atom.icns" + if [[ -z $MDMProfileName ]]; then; MDMProfileName="MDM Profile"; fi ;; esac if [[ ! -a "${LOGO}" ]]; then @@ -4085,6 +4669,8 @@ if [[ ! -a "${LOGO}" ]]; then fi printlog "LOGO=${LOGO}" +printlog "Label type: $type" + # MARK: extract info from data if [ -z "$archiveName" ]; then case $type in @@ -4105,6 +4691,7 @@ if [ -z "$archiveName" ]; then ;; esac fi +printlog "archiveName: $archiveName" DEBUG if [ -z "$appName" ]; then # when not given derive from name @@ -4134,7 +4721,7 @@ if [[ -z $blockingProcesses ]]; then fi # MARK: determine tmp dir -if [ "$DEBUG" -ne 0 ]; then +if [ "$DEBUG" -eq 1 ]; then # for debugging use script dir as working directory tmpDir=$(dirname "$0") else @@ -4143,7 +4730,7 @@ else fi # MARK: change directory to temporary working directory -printlog "Changing directory to $tmpDir" +printlog "Changing directory to $tmpDir" DEBUG if ! cd "$tmpDir"; then printlog "error changing directory $tmpDir" cleanupAndExit 1 @@ -4154,15 +4741,14 @@ getAppVersion printlog "appversion: $appversion" # MARK: Exit if new version is the same as installed version (appNewVersion specified) -# credit: Søren Theilgaard (@theilgaard) -if [[ $INSTALL == "force" ]]; then - printlog "Using force to install, so not using updateTool." +if [[ "$type" != "updateronly" && ($INSTALL == "force" || $IGNORE_APP_STORE_APPS == "yes") ]]; then + printlog "Label is not of type “updateronly”, and it’s set to use force to install or ignoring app store apps, so not using updateTool." updateTool="" fi if [[ -n $appNewVersion ]]; then printlog "Latest version of $name is $appNewVersion" if [[ $appversion == $appNewVersion ]]; then - if [[ $DEBUG -eq 0 ]]; then + if [[ $DEBUG -ne 1 ]]; then printlog "There is no newer version available." if [[ $INSTALL != "force" ]]; then message="$name, version $appNewVersion, is the latest version." @@ -4173,7 +4759,7 @@ if [[ -n $appNewVersion ]]; then cleanupAndExit 0 "No newer version." fi else - printlog "DEBUG mode enabled, not exiting, but there is no new version of app." + printlog "DEBUG mode 1 enabled, not exiting, but there is no new version of app." fi fi else @@ -4183,7 +4769,7 @@ fi # MARK: check if this is an Update and we can use updateTool if [[ (-n $appversion && -n "$updateTool") || "$type" == "updateronly" ]]; then printlog "appversion & updateTool" - if [[ $DEBUG -eq 0 ]]; then + if [[ $DEBUG -ne 1 ]]; then if runUpdateTool; then finishing cleanupAndExit 0 @@ -4192,16 +4778,16 @@ if [[ (-n $appversion && -n "$updateTool") || "$type" == "updateronly" ]]; then cleanupAndExit 0 fi # otherwise continue else - printlog "DEBUG mode enabled, not running update tool" + printlog "DEBUG mode 1 enabled, not running update tool" fi fi # MARK: download the archive -if [ -f "$archiveName" ] && [ "$DEBUG" -ne 0 ]; then - printlog "$archiveName exists and DEBUG enabled, skipping download" +if [ -f "$archiveName" ] && [ "$DEBUG" -eq 1 ]; then + printlog "$archiveName exists and DEBUG mode 1 enabled, skipping download" else - # download the dmg - printlog "Downloading $downloadURL to $archiveName" + # download + printlog "Downloading $downloadURL to $archiveName" REQ if [[ $currentUser != "loginwindow" && $NOTIFY == "all" ]]; then printlog "notifying" if [[ $updateDetected == "YES" ]]; then @@ -4210,19 +4796,28 @@ else displaynotification "Downloading new $name" "Download in progress …" fi fi - if ! curl --location --fail --silent "$downloadURL" -o "$archiveName"; then + curlDownload=$(curl -v -fsL --show-error ${curlOptions} "$downloadURL" -o "$archiveName" 2>&1) + curlDownloadStatus=$(echo $?) + deduplicatelogs "$curlDownload" + if [[ $curlDownloadStatus -ne 0 ]]; then + #if ! curl --location --fail --silent "$downloadURL" -o "$archiveName"; then printlog "error downloading $downloadURL" message="$name update/installation failed. This will be logged, so IT can follow up." if [[ $currentUser != "loginwindow" && $NOTIFY == "all" ]]; then printlog "notifying" if [[ $updateDetected == "YES" ]]; then - displaynotification "$message" "Error updating $name" + displaynotification "$message" "Error updating $name" ERROR else - displaynotification "$message" "Error installing $name" + displaynotification "$message" "Error installing $name" ERROR fi fi - cleanupAndExit 2 + printlog "File list: $(ls -lh "$archiveName")" ERROR + printlog "File type: $(file "$archiveName")" ERROR + cleanupAndExit 2 "Error downloading $downloadURL error:\n$logoutput" ERROR fi + printlog "File list: $(ls -lh "$archiveName")" DEBUG + printlog "File type: $(file "$archiveName")" DEBUG + printlog "curl output was:\n$logoutput" DEBUG fi # MARK: when user is logged in, and app is running, prompt user to quit app @@ -4239,7 +4834,7 @@ else fi # MARK: install the download -printlog "Installing $name" +printlog "Installing $name" REQ if [[ $currentUser != "loginwindow" && $NOTIFY == "all" ]]; then printlog "notifying" if [[ $updateDetected == "YES" ]]; then @@ -4251,7 +4846,7 @@ fi if [ -n "$installerTool" ]; then # installerTool defined, and we use that for installation - printlog "installerTool used: $installerTool" + printlog "installerTool used: $installerTool" REQ appName="$installerTool" fi diff --git a/Labels.txt b/Labels.txt index dd319a3..91483c3 100644 --- a/Labels.txt +++ b/Labels.txt @@ -368,6 +368,7 @@ vagrant vanilla veracrypt vimac +virtualbox viscosity visualstudiocode vivaldi diff --git a/fragments/labels/vimac.sh b/fragments/labels/vimac.sh index bfc5f06..967dcfc 100644 --- a/fragments/labels/vimac.sh +++ b/fragments/labels/vimac.sh @@ -4,4 +4,4 @@ vimac) downloadURL=$(curl -fs "https://vimacapp.com/latest-release-metadata" | tr ',' '\n' | awk -F\" '/download_url/ {print $4}') appNewVersion=$(curl -fs "https://vimacapp.com/latest-release-metadata" | tr ',' '\n' | awk -F\" '/short_version/ {print $4}') expectedTeamID="LQ2VH8VB84" - ;; \ No newline at end of file + ;; diff --git a/utils/assemble.sh b/utils/assemble.sh index 016ff98..7531173 100755 --- a/utils/assemble.sh +++ b/utils/assemble.sh @@ -9,8 +9,6 @@ install_location="/usr/local/Installomator/" signature="Developer ID Installer: Armin Briegel (JME5BW3F3R)" # notarization -dev_team="JME5BW3F3R" # asc-provider -dev_account="developer@scriptingosx.com" dev_keychain_label="notary-scriptingosx" # parse arguments