Tag: prowl

  • Sending Prowl Alerts via Bash

    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!