Sending Prowl Alerts via Bash

I’m working on some server scripting and I wanted to find a way to make sure I get proper alerts. I tried hard getting Twilio working cheaply, but that failed. So I remembered that I use Prowl for other things on my phone–so why not just send more alerts that way?

So, again with the help of ChatGPT I have made a terrible monstrosity:

#!/bin/bash

# Exit if any command fails, if an unset variable is used, or if a command in a pipeline fails
set -euo pipefail

# Default values
application="Shell Notification"
priority=0
event="Event"
message=""
logfile="/var/log/send-prowl-alert.log"
url=""

# Usage information
usage() {
    echo "Usage: $0 --message=<message> [--application=<application>] [--event=<event>] [--description=<description>] [--priority=<priority>] [--url=<url>]"
    echo "Required:"
    echo "  --message=<message>       A description of the event, generally terse"
    echo "                            Maximum of 10000 bytes"
    echo "Optional:"
    echo "  --application=<application>  The name of the application (default: 'Shell Notification')"
    echo "                               Maximum of 256 bytes"
    echo "  --event=<event>              The name of the event or subject of the notification (default: 'Event')"
    echo "                               Maximum of 1024 bytes"
    echo "  --priority=<priority>        The priority of the alert (default: 0)"
    echo "                               An integer value ranging [-2, 2] representing:"
    echo "                                   -2 Very Low"
    echo "                                   -1 Moderate"
    echo "                                    0 Normal"
    echo "                                    1 High"
    echo "                                    2 Emergency"
    echo "                               Emergency priority messages may bypass quiet hours according to the user's settings."
    echo "  --url=<url>                  The URL which should be attached to the notification"
    echo "                               Maximum of 512 bytes"
    echo "  --help                       Displays this help message"
}

# URL Encodes a string
urlencode() {
  local string="$1"
  local length="${#string}"
  local i

  for ((i = 0; i < length; i++)); do
    local c="${string:i:1}"
    case $c in
      [a-zA-Z0-9.~_-])
        printf '%s' "$c"
        ;;
      *)
        printf '%%%02X' "'$c"
        ;;
    esac
  done
}

# Check if the script is being run manually or via cron
if [[ -t 1 ]]; then
    # Output to console if being run manually
    log_message() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
else
    # Output to log file if being run via cron
    log_message() {
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "${logfile}"
        # Truncate the log file to 1 megabyte
        if [[ $(wc -c <"${logfile}") -gt 1000000 ]]; then
            tail -c 1000000 "${logfile}" > "${logfile}.tmp" && mv "${logfile}.tmp" "${logfile}"
        fi
    }
fi

# Parse arguments
for arg in "$@"; do
    case "${arg}" in
        --message=*)
            message=${arg#*=}
            ;;
        --application=*)
            application=${arg#*=}
            ;;
        --event=*)
            event=${arg#*=}
            ;;
        --priority=*)
            priority=${arg#*=}
            ;;
        --url=*)
            url=${arg#*=}
            ;;
        --help)
            usage
            exit 0
            ;;
        *)
            echo "Error: Unsupported argument ${arg}"
            usage
            exit 1
            ;;
    esac
done


# Create a variable to store error messages
errors=""

# Check if curl is installed
if ! command -v curl &> /dev/null; then
    errors+="Error: curl is not installed. Please install curl and try again.\n"
fi

# Check that a message was provided
if [[ -z "${message}" ]]; then
    errors+="Error: No message provided."
fi

# Check if the URL is valid
if [[ -n $url && ! $url =~ ^(https?://)[^\s/$.?#].[^\s]*$ ]]; then
    errors+="Error: Invalid URL.\n"
fi

# Check byte size of the parameters and append error if they exceed the max limit
if [[ "${#url}" -gt 512 ]]; then
    errors+="Error: URL exceeds maximum byte limit (512 bytes).\n"
fi

if [[ "${#application}" -gt 256 ]]; then
    errors+="Error: Application name exceeds maximum byte limit (256 bytes).\n"
fi

if [[ "${#event}" -gt 1024 ]]; then
    errors+="Error: Event name exceeds maximum byte limit (1024 bytes).\n"
fi

if [[ "${#message}" -gt 10000 ]]; then
    errors+="Error: Message exceeds maximum length (10000 bytes).\n"
fi

if [[ ! "${priority}" =~ ^-?[0-2]$ ]]; then
    errors+="Error: Invalid priority. Must be an integer between -2 and 2.\n"
fi

# Check if the API key file exists and is not empty
if [[ ! -s ~/.prowl_api_key ]]; then
    errors+="Error: The Prowl API key file does not exist or is empty. Please create a file at ~/.prowl_api_key and add your API key to it.\nExample:\n  echo 'your_api_key' > ~/.prowl_api_key\n  chmod 600 ~/.prowl_api_key\n"
fi

# Check the permissions on the API key file, if it exists
# We have to do it in a convoluted cross platform way because macos does not support `stat -c`
if [[ -f ~/.prowl_api_key ]]; then
    # Retrieve the file permissions and remove any trailing '@' symbol (indicating extended attributes)
    permissions=$(ls -l -d ~/.prowl_api_key | awk '{print $1}' | tr -d '@')

    # Check if the permissions are not set to '-rw-------'
    if [[ "$permissions" != "-rw-------" ]]; then
        # Add an error message to the 'errors' variable
        errors+="Error: The permissions on the API key file are not set correctly. Please run 'chmod 600 ~/.prowl_api_key' and try again.\n"
    fi
fi

# If any errors were detected, print the error messages and exit
if [[ -n $errors ]]; then
    echo -e "${errors}"  # -e enables interpretation of backslash escapes like \n
    exit 1
fi

# Get the Prowl API key
prowl_api_key=$(cat ~/.prowl_api_key)

# Save the alert data for logging before we encode it
alert_log_string="$application : $event : $priority : $url : $message"

# URL-encode the variables
prowl_api_key=$(urlencode "$prowl_api_key")
application=$(urlencode "$application")
event=$(urlencode "$event")
message=$(urlencode "$message")
priority=$(urlencode "$priority")
url=$(urlencode "$url")

# Send the alert
response=$(curl -s "https://api.prowlapp.com/publicapi/add?apikey=${prowl_api_key}&application=${application}&event=${event}&description=${message}&priority=${priority}&url=${url}")

# Check if the alert was sent successfully
if [[ "${response}" != *"success code=\"200\""* ]]; then
    log_message "Error sending alert: ${alert_log_string}"
    log_message "Response: ${response}"
    exit 1
fi

log_message "Alert sent successfully: $alert_log_string"
exit 0
Code language: PHP (php)

Good luck!

Other Posts Not Worth Reading

Hey, You!

Like this kind of garbage? Subscribe for more! I post like once a month or so, unless I found something interesting to write about.