#!/bin/bash
# set -x

####################################################################################################
# Script Name:  Get-LastMDMPush.sh
# By:  Zack Thompson / Created:  11/3/2023
# Version:  1.0.0 / Updated:  11/3/2023 / By:  ZT
#
# Description:  This script gets the time stamp of the
#	last Push Notification received by the MDM Client.
#
####################################################################################################

##################################################
# Set variables for your environment

# Pass a value in the first argument to "test" the script and not write to the local EA files.
testing="${1}"

# Jamf Pro Server URL
jamf_pro_server=$( /usr/bin/defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url )

# APNS Cert Topic
# Can be obtained from https://identity.apple.com/pushcert/ 
# 	or https://<jps.url.org>:8443/pushNotificationCertificate.html
if [[ "${jamf_pro_server}" =~ .*production.* ]]; then
	apple_mgmt_cert="com.apple.mgmt.External.<INSERT_APNs_TOPIC_GUID_HERE"
elif [[ "${jamf_pro_server}" =~ .*development.* ]]; then
	apple_mgmt_cert="com.apple.mgmt.External.INSERT_APNs_TOPIC_GUID_HERE"
fi

# The number of days before reporting device as "inactive."
last_connected_variance=7

# The date format expected from date fields generated by `apns_stats`.
default_date_format="%b %d, %Y at %H:%M:%S %p"

# The format of the date string that will be used for reporting.
jamfpro_ea_date_format="%Y-%m-%d %H:%M:%S"

# Locally log EA value for historical reference (since Jamf Pro only ever has the last value).
# Supported actions:
#   true - Do locally Log
#   false - Do not log locally
locally_log="true"
local_ea_history="/opt/ManagedFrameworks/EA_History.log"
local_ea_history_identifier="Last MDM Push Received:  "
local_ea_inventory="/opt/ManagedFrameworks/Inventory.plist"
local_ea_inventory_identifier="apns_mdm_health"

##################################################
# Functions

write_to_ea_inventory() {

	# Arguments
	# $1 = (str) Plist key that the message value will be assigned too
	# $2 = (str) Message that will be assigned to the key

	local key="${1}"
	local value="${2}"

	if [[ "${locally_log}" == "true" && -z "${testing}" ]]; then

		if [[ ! -e "${local_ea_inventory}" ]]; then

			/bin/mkdir -p "$( /usr/bin/dirname "${local_ea_inventory}" )"
			/usr/bin/touch "${local_ea_inventory}"

		fi

		/usr/bin/defaults write "${local_ea_inventory}" "${key}" "${value}"

	fi

}

write_to_ea_history() {

	# Arguments
	# $1 = (str) Message that will be written to a log file

	local message="${1}"

	time_stamp=$( /bin/date +%Y-%m-%d\ %H:%M:%S )

	if [[ "${locally_log}" == "true" && -z "${testing}" ]]; then

		if [[ ! -e "${local_ea_history}" ]]; then

			/bin/mkdir -p "$( /usr/bin/dirname "${local_ea_history}" )"
			/usr/bin/touch "${local_ea_history}"

		fi

		echo "${time_stamp} | ${local_ea_history_identifier}${message}" >> "${local_ea_history}"

	else

		echo "${time_stamp} | ${local_ea_history_identifier}${message}"

	fi

}

report_result() {

	# Arguments
	# $1 = (str) Message that will be recorded to the configured locations

	local message="${1}"

	write_to_ea_history "${message}"
	write_to_ea_inventory "${local_ea_inventory_identifier}" "${message}"
	echo "<result>${message}</result>"
	exit 0

}

check_last_connection() {

	# Check if the last connected date is older than date variance.
	# Arguments
	# $1 = (str) a date in string format
	# $2 = (str) the expected format of the date string
	# $3 = (int) date variance; in number of days
	# $4 = (str) Additional message to prefix the output

	fixed_date="$( fixup_space_in_string "${1}" )"

	if [[
		$( convert_date "${fixed_date}" "${2}" "%s" ) \
		-lt $( /bin/date -j -v-"${3}"d +"%s" )
	]]; then

		echo "${4} > [WARNING] Last connection was over seven days:  ${fixed_date}"

	else

		echo "${4} > Last connection was less than seven days:  ${fixed_date}"

	fi

}

convert_date(){

	# Convert a formatted date string into another format
	# Arguments
	# $1 = (str) a date in string format
	# $2 = (str) the expected format of the date string
	# $3 = (str) the desired format of the string

	/bin/date -j -f "${2}" "$( fixup_space_in_string "${1}" )" +"${3}"

}

fixup_space_in_string(){

	# Convert unicode spaces in a string into a basic space
	# Arguments
	# $1 = (str) a string

	/usr/bin/sed 's/[[:space:]]/ /g' <<< "${1}"

}

##################################################
# Bits staged, collect the information...

# Check APNS status for the MDM Client service
apns_stats=$( /System/Library/PrivateFrameworks/ApplePushService.framework/apsctl status )

# Device Channel
device_apns_stats=$( /usr/bin/osascript -l JavaScript << EndOfScript

	var apns_stats=\`$apns_stats\`

	apns_stats.match(
		/(^\s+application port name:\s+)com.apple.aps.mdmclient.daemon.push.production(.|\n)+?(?=\1)/gm
	)

EndOfScript
)

write_to_ea_history "${device_apns_stats}"

device_last_push_date=$(
	echo "${device_apns_stats}" | \
	/usr/bin/awk -F 'last push notification:' '{print $2}' | \
	/usr/bin/awk -F ' \\(' '{print $1}' | \
	/usr/bin/xargs
)
device_last_push_topic=$(
	echo "${device_apns_stats}" | \
	/usr/bin/awk -F 'last push notification topic:' '{print $2}' | \
	/usr/bin/xargs
)

# User Channel
user_apns_stats=$( /usr/bin/osascript -l JavaScript << EndOfScript

	var apns_stats=\`$apns_stats\`

	apns_stats.match(
		/(^\s+application port name:\s+)com.apple.aps.mdmclient.agent.push.production(.|\n)+?(?=\1)/gm
	)

EndOfScript
)

write_to_ea_history "${user_apns_stats}"

user_last_push_date=$(
	echo "${user_apns_stats}" | \
	/usr/bin/awk -F 'last push notification:' '{print $2}' | \
	/usr/bin/awk -F ' \\(' '{print $1}' | \
	/usr/bin/xargs
)
user_last_push_topic=$(
	echo "${user_apns_stats}" | \
	/usr/bin/awk -F 'last push notification topic:' '{print $2}' | \
	/usr/bin/xargs
)

if [[
	"${apple_mgmt_cert}" == "${device_last_push_topic}" &&
	"${apple_mgmt_cert}" == "${user_last_push_topic}"
]]; then
	write_to_ea_history "APNS Topic matches"
else
	write_to_ea_history "[ERROR] APNS Topic does not match!"

	if [[ "${apple_mgmt_cert}" != "${device_last_push_topic}" ]]; then
		write_to_ea_history "Device APNS Topic mismatch:  ${device_last_push_topic}"
	fi

	if [[ "${apple_mgmt_cert}" == "${user_last_push_topic}" ]]; then
		write_to_ea_history "User APNS Topic mismatch:  ${user_last_push_topic}"
	fi

fi

# Check if the more recent date is older than seven days
write_to_ea_history "$(
	check_last_connection "${device_last_push_date}" \
		"${default_date_format}" $last_connected_variance "Device Push"
)"
write_to_ea_history "$(
	check_last_connection "${user_last_push_date}" \
		"${default_date_format}" $last_connected_variance "User Push"
)"

# Convert dates to epoch to easily compare
if [[
	$( convert_date "${device_last_push_date}" "${default_date_format}" "%s" ) -gt \
	$( convert_date "${user_last_push_date}" "${default_date_format}" "%s" )
]]; then

	# Convert dates for logging
	write_to_ea_history "Reporting device channel date"
	report_result "$(
		convert_date "${device_last_push_date}" "${default_date_format}" "${jamfpro_ea_date_format}"
	)"

else

	# Convert dates for logging
	write_to_ea_history "Reporting user channel date"
	report_result "$(
		convert_date "${user_last_push_date}" "${default_date_format}" "${jamfpro_ea_date_format}"
	)"

fi
