You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

156 lines
4.6 KiB

  1. #!/bin/bash
  2. ## Send a notification with NTFY and check if the config file is complete
  3. if [[ "$UID" == "0" ]]; then
  4. NTFY_CONFIG_DIR="${NTFY_CONFIG_DIR:-/etc/ntfy}"
  5. else
  6. NTFY_CONFIG_DIR="${NTFY_CONFIG_DIR:-~/.config/ntfy}"
  7. fi
  8. NTFY_CONFIG_FILE="$NTFY_CONFIG_DIR/ntfy.conf"
  9. SERVER="https://ntfy.0k.io"
  10. [ -f "$NTFY_CONFIG_DIR/topics.yml" ] || {
  11. echo "Error: no 'topics.yml' file found in $NTFY_CONFIG_DIR" >&2
  12. echo " Please setup the topics for the notification channels in this file." >&2
  13. exit 1
  14. }
  15. if ! [ -e "$NTFY_CONFIG_FILE" ]; then
  16. mkdir -p "${NTFY_CONFIG_FILE%/*}"
  17. ## default option to change if needed
  18. echo "SERVER=$SERVER" > "$NTFY_CONFIG_FILE"
  19. elif ! grep -q "^SERVER=" "$NTFY_CONFIG_FILE"; then
  20. echo "SERVER=$SERVER" >> "$NTFY_CONFIG_FILE"
  21. fi
  22. source "$NTFY_CONFIG_FILE" || {
  23. echo "Error: could not source '$NTFY_CONFIG_FILE'" >&2
  24. exit 1
  25. }
  26. SERVER="${SERVER%/}"
  27. for var in SERVER LOGIN PASSWORD; do
  28. if ! [ -v "$var" ]; then
  29. echo "Error: missing $var in $NTFY_CONFIG_FILE"
  30. exit 1
  31. fi
  32. done
  33. exname=${0##*/}
  34. channels=()
  35. usage="Usage: $exname [-c CHANNEL...] [-t TITLE ] MESSAGE
  36. ----------------------------------------------
  37. --- Send MESSAGE with TITLE to the differents topics defined by a CHANNEL. ---
  38. --- If no CHANNEL is provided, the message will be sent to the default channel. ---
  39. ----------------------------------------------
  40. -c CHANNEL: One or multiple channels. If no CHANNEL is provided,
  41. the message will be sent to the main channel.
  42. You can provide multiple channels with -c channel1 -c channel2 ...
  43. topics are configured in $NTFY_CONFIG_DIR/topics.yml
  44. -t TITLE: If no TITLE is provided, the message will be sent with the hostname as title.
  45. - MESSAGE: The message to send.
  46. "
  47. while [ "$#" -gt 0 ]; do
  48. arg="$1"
  49. shift
  50. case "$arg" in
  51. -h|--help)
  52. echo "$usage"
  53. exit 0
  54. ;;
  55. -c|--channel)
  56. [ -n "$1" ] || {
  57. echo "Error: no argument for channel option." >&2
  58. echo "$usage" >&2
  59. exit 1
  60. }
  61. IFS=", " channels+=($1)
  62. shift
  63. ;;
  64. -t|--title)
  65. [ -n "$1" ] || {
  66. echo "Error: no argument for title option." >&2
  67. echo "$usage" >&2
  68. exit 1
  69. }
  70. title="$1"
  71. shift
  72. ;;
  73. *)
  74. [ -z "$message" ] && { message="$arg"; continue; }
  75. echo "Error : Unexpected positional argument '$arg'." >&2
  76. echo "$usage" >&2
  77. exit 1
  78. ;;
  79. esac
  80. done
  81. [ -n "$message" ] || {
  82. echo "Error: missing message." >&2
  83. echo "$usage" >&2
  84. exit 1
  85. }
  86. read-0() {
  87. local eof='' IFS=''
  88. while [ "$1" ]; do
  89. read -r -d '' -- "$1" || eof=1
  90. shift
  91. done
  92. [ -z "$eof" ]
  93. }
  94. curl_opts=(
  95. -s
  96. -u "$LOGIN:$PASSWORD"
  97. -d "$message"
  98. )
  99. title="[$(hostname)] $title"
  100. title="${title%%+([[:space:]])}"
  101. curl_opts+=(-H "Title: $title")
  102. declare -A sent_topic=()
  103. if [ "${#channels[@]}" -eq 0 ]; then
  104. channels=("main")
  105. fi
  106. for channel in "${channels[@]}"; do
  107. channel_quoted=$(printf "%q" "$channel")
  108. content=$(cat "$NTFY_CONFIG_DIR/topics.yml")
  109. while read-0 channel_regex topics; do
  110. [[ "$channel" =~ ^$channel_regex$ ]] || continue
  111. rematch=("${BASH_REMATCH[@]}")
  112. while read-0 topic; do
  113. ttopic=$(printf "%s" "$topic" | yq "type")
  114. if [ "$ttopic" != '!!str' ]; then
  115. echo "Error: Unexpected '$ttopic' type for value of channel $channel." >&2
  116. exit 1
  117. fi
  118. topic=$(printf "%s" "$topic" | yq -r " \"\" + .")
  119. if ! [[ "$topic" =~ ^[a-zA-Z0-9\$\{\}*\ \,_.-]+$ ]]; then
  120. echo "Error: Invalid topic value '$topic' expression in $channel channel." >&2
  121. exit 1
  122. fi
  123. new_topics=($(set -- "${rematch[@]}"; eval echo "${topic//\*/\\*}"))
  124. for new_topic in "${new_topics[@]}"; do
  125. [ -n "${sent_topic["$new_topic"]}" ] && continue
  126. sent_topic["$new_topic"]=1
  127. if ! out=$(curl "${curl_opts[@]}" "$SERVER/${new_topic}"); then
  128. echo "Error: could not send message to $new_topic." >&2
  129. echo "curl command:" >&2
  130. echo " curl ${curl_opts[@]} $SERVER/${new_topic}" >&2
  131. echo "$out" | sed 's/^/ | /' >&2
  132. exit 1
  133. fi
  134. done
  135. done < <(printf "%s" "$topics" | yq e -0 '.[]')
  136. done < <(printf "%s" "$content" | yq e -0 'to_entries | .[] | [.key, .value] |.[]')
  137. done