Merge branch 'main' of https://git.hladu.xyz/scotty2586/obedy.git
This commit is contained in:
		
						commit
						fd5f5c667c
					
				|  | @ -0,0 +1,8 @@ | |||
| # Default ignored files | ||||
| /shelf/ | ||||
| /workspace.xml | ||||
| # Editor-based HTTP Client requests | ||||
| /httpRequests/ | ||||
| # Datasource local storage ignored files | ||||
| /dataSources/ | ||||
| /dataSources.local.xml | ||||
|  | @ -0,0 +1,218 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| #### SCRIP USAGE FUNCTION #### | ||||
| 
 | ||||
| # Usage function. | ||||
| usage() { | ||||
|     echo "" | ||||
|     echo "Usage: $0 [OPTIONS]" | ||||
|     echo "" | ||||
|     echo "Options:" | ||||
|     echo "  -m, --message <json-content>  The Discord webhook message JSON to be checked." | ||||
|     echo "  -d, --debug                   Turns on console output" | ||||
|     echo "  -h, --help                    Show this help message and exit." | ||||
|     echo "" | ||||
|     echo "This script will check a Discord webhook message JSON string against content" | ||||
|     echo "limits set by Discord. The message data must be within the limits in order" | ||||
|     echo "to be successfully sent. The script will return an exit number based on the" | ||||
|     echo "results of the check." | ||||
|     echo "" | ||||
|     echo " 0) The message data is within the limimts." | ||||
|     echo " 1) The message data is outside limits, but can be sent in multiple messages." | ||||
|     echo " 2) The message data is outside limits and cannot be sent." | ||||
|     echo "" | ||||
|     echo "Refer to Discord Webook documentation for more details on the webhook limits:" | ||||
|     echo "" | ||||
|     echo "  https://birdie0.github.io/discord-webhooks-guide/other/field_limits.html" | ||||
|     echo "" | ||||
| } | ||||
| 
 | ||||
| #### PARSE ARGUMENTS #### | ||||
| 
 | ||||
| # Parsed from command line arguments. | ||||
| while [[ $# -gt 0 ]]; do | ||||
|     case "$1" in | ||||
|         -m|--message) | ||||
|             jsonMessage="$2" | ||||
|             shift 2 | ||||
|             ;; | ||||
|         -d|--debug) | ||||
|             debug=true | ||||
|             shift | ||||
|             ;; | ||||
|         -h|--help) | ||||
|             usage | ||||
|             exit 0 | ||||
|             ;; | ||||
|         *) | ||||
|             echo "Invalid option: $1" >&2 | ||||
|             usage | ||||
|             exit 2 | ||||
|             ;; | ||||
|     esac | ||||
| done | ||||
| 
 | ||||
| # Check if JSON is provided and not empty | ||||
| if [ -z "${jsonMessage}" ]; then | ||||
|     echo "Error: The --message option is mandatory." >&2 | ||||
|     usage | ||||
|     exit 2 | ||||
| fi | ||||
| 
 | ||||
| #### INITIALIZATION & PARAMETERS #### | ||||
| 
 | ||||
| # Character lenght limits & object count limits (the order is important!) | ||||
| limits=( | ||||
|     'Username       .username                   80      char    1' | ||||
|     'Content        .content                    2000    char    1' | ||||
|     'Embeds         .embeds                     10      obj     0' | ||||
|     'Author         .embeds[].author.name       256     char    1' | ||||
|     'Title          .embeds[].title             256     char    1' | ||||
|     'Description    .embeds[].description       1024    char    1' | ||||
|     'Fields         .embeds[].fields            25      obj     1' | ||||
|     'Name           .embeds[].fields[].name     256     char    1' | ||||
|     'Value          .embeds[].fields[].value    1024    char    1' | ||||
|     'Footer         .embeds[].footer.text       2048    char    1' | ||||
|     'Totals         na                          6000    char    1' | ||||
|     'Total          na                          6000    char    0' | ||||
| ) | ||||
| 
 | ||||
| # Set limit parameter names | ||||
| limitParameters="name section value type critical count" | ||||
| 
 | ||||
| # Initialize result variables | ||||
| criticalResult=false | ||||
| outsideLimits=false | ||||
| results="" | ||||
| totalCharactersAllEmbeds=0 | ||||
| 
 | ||||
| #### LIMIT CHECK & RESULTS FUNCTION #### | ||||
| 
 | ||||
| # Get count, check against limit and update results | ||||
| function updateResults() { | ||||
| 
 | ||||
|     local indexedSection="$1" | ||||
| 
 | ||||
|     # Get the object/character count if section is an object | ||||
|     [ "${indexedSection}" != "na" ] && count=$(jq "$indexedSection | length" <<< "${jsonMessage}") | ||||
| 
 | ||||
|     # Output info if debug enabled | ||||
|     [ ${debug} ] && echo "${name}: ${count} / ${value}" >&2 | ||||
| 
 | ||||
|     # Compare count with limit value | ||||
|     if [[ ${count} -gt ${value} ]]; then | ||||
| 
 | ||||
|         # Set 'outside limit' flag | ||||
|         outsideLimits=true | ||||
| 
 | ||||
|         # Check if limit is a critical one | ||||
|         if [ "${critical}" == "1" ]; then | ||||
| 
 | ||||
|             # Set 'critical limit' flag | ||||
|             criticalResult=true | ||||
| 
 | ||||
|         fi | ||||
| 
 | ||||
|         # Append to result if outside limit | ||||
|         results+="${name} ${indexedSection} ${value} ${type} ${critical} ${count}\n" | ||||
| 
 | ||||
|     fi | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #### CHECK CONTENT #### | ||||
| 
 | ||||
| # Check content agains each limit | ||||
| for limit in "${limits[@]}"; do | ||||
| 
 | ||||
|     # Read parameters from limit | ||||
|     IFS=' ' read -r $limitParameters <<< "$limit" | ||||
| 
 | ||||
|     # Check if limit relates to the embeds section | ||||
|     if [[ "${section}" == *"embeds[]"* ]]; then | ||||
| 
 | ||||
|         # Check each embed section individually for applicable limits | ||||
|         for (( i=0; i<$(jq ".embeds | length" <<< "${jsonMessage}"); i++ )); do | ||||
| 
 | ||||
|             # Inject array index in embeds element for correct parsing | ||||
|             embedSection="${section/embeds[]/embeds[${i}]}" | ||||
| 
 | ||||
|             # Check if section is a field section as this is an array | ||||
|             if [[ "${section}" == *"fields[]"* ]]; then | ||||
| 
 | ||||
|                 # Check each field section individually for applicable limits | ||||
|                 for (( j=0; j<$(jq ".embeds[$i].fields | length" <<< "${jsonMessage}"); j++ )); do | ||||
| 
 | ||||
|                     # Inject array index in fields element for correct parsing | ||||
|                     fieldSection="${embedSection/fields[]/fields[${j}]}" | ||||
| 
 | ||||
|                     # Check limits and update results | ||||
|                     updateResults "${fieldSection}" | ||||
| 
 | ||||
|                     # Add to total characters if character type | ||||
|                     [ "${type}" == "char" ] && ((embedTotals[$i]+=count)) | ||||
| 
 | ||||
|                 done | ||||
| 
 | ||||
|             else | ||||
| 
 | ||||
|                 # Check limits and update results | ||||
|                 updateResults "${embedSection}" | ||||
| 
 | ||||
|                 # Add to total characters if character type | ||||
|                 [ "${type}" == "char" ] && ((embedTotals[$i]+=count)) | ||||
| 
 | ||||
|             fi | ||||
| 
 | ||||
|         done | ||||
| 
 | ||||
|     elif [[ "${name}" == "Totals" ]]; then | ||||
| 
 | ||||
|         # Read the total character count for each embed section | ||||
|         for count in "${embedTotals[@]}"; do | ||||
| 
 | ||||
|             # Check agains limit and update result | ||||
|             updateResults "${section}" ${count} | ||||
| 
 | ||||
|             # Add to the overall total character count | ||||
|             ((totalCharactersAllEmbeds+=count)) | ||||
| 
 | ||||
|         done | ||||
| 
 | ||||
|     elif [[ "${name}" == "Total" ]]; then | ||||
| 
 | ||||
|         # Get the total character count for all embeds | ||||
|         count=${totalCharactersAllEmbeds} | ||||
| 
 | ||||
|         # Check agains limit and update result | ||||
|         updateResults "${section}" ${count} | ||||
| 
 | ||||
|     else | ||||
| 
 | ||||
|         # Check agains limit and update result | ||||
|         updateResults "${section}" | ||||
| 
 | ||||
|     fi | ||||
| 
 | ||||
| 
 | ||||
| done | ||||
| 
 | ||||
| #### RETURN RESULTS #### | ||||
| 
 | ||||
| # Output results | ||||
| [ ${debug} ] && [ -n "${results}" ] && echo -e "${results%??}" >&2 | ||||
| 
 | ||||
| # Exit with appropriate status | ||||
| if ${criticalResult}; then | ||||
| 
 | ||||
|     exit 2 | ||||
| 
 | ||||
| elif ${outsideLimits}; then | ||||
| 
 | ||||
|     exit 1 | ||||
| 
 | ||||
| else | ||||
| 
 | ||||
|     exit 0 | ||||
| 
 | ||||
| fi | ||||
|  | @ -0,0 +1,191 @@ | |||
| #!/usr/bin/bash | ||||
| 
 | ||||
| #### SET PATHS #### | ||||
| 
 | ||||
| # Get path to where script is located. | ||||
| scriptPath=$(echo "${0%/*}") | ||||
| 
 | ||||
| # Set other paths. | ||||
| limitCheckScrip=${scriptPath}/discord-webhook-data-limit-check.sh | ||||
| lastMessageFile=${scriptPath}/discord-webhook-last-message.json | ||||
| 
 | ||||
| #### SCRIP USAGE FUNCTION #### | ||||
| 
 | ||||
| # Usage function. | ||||
| usage() { | ||||
|     echo "" | ||||
|     echo "Usage: $0 [OPTIONS]" | ||||
|     echo "" | ||||
|     echo "Options:" | ||||
|     echo "  -c, --content <content>   Set the content of the Discord message." | ||||
|     echo "  -e, --embeds <embeds>     Set the embeds of the Discord message." | ||||
|     echo "  -f, --file <file-path>    Set the file attachment path (optional)." | ||||
|     echo "  -d, --debug               Turns on console output" | ||||
|     echo "  -h, --help                Show this help message and exit." | ||||
|     echo "" | ||||
|     echo "Refer to the Discord documentation for more information on Webhooks" | ||||
|     echo "" | ||||
|     echo "  https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks" | ||||
|     echo "" | ||||
| } | ||||
| 
 | ||||
| ### SEND WEBHOOK FUNCTION ### | ||||
| 
 | ||||
| # Send Discord notification with or without payloaad. | ||||
| sendWebhook() { | ||||
| 
 | ||||
|     local discordJsonData="$1" | ||||
|     local includeAttachment="$2" | ||||
| 
 | ||||
|     # Write last message that was attmepted to be sent to file | ||||
|     echo "${discordJsonData}" > ${lastMessageFile} | ||||
| 
 | ||||
|     # Check if attachment pathe exits and if is should be included in the message | ||||
|     if [ -z "${discordAttachmentPath}" ] || [ "${includeAttachment}" = "false" ]; then | ||||
| 
 | ||||
|         # Send message without attachment | ||||
|         echo ${discordWebhookBase}"/"${discordID}"/"${discordToken} | ||||
|         echo "$discordJsonData" | ||||
|         response=$(curl -H "Content-Type: application/json" -d "$discordJsonData" ${discordWebhookBase}"/"${discordID}"/"${discordToken}) | ||||
| 
 | ||||
|     else | ||||
| 
 | ||||
|         # Send message with attachment | ||||
|         response=$(curl -s -F payload_json="${discordJsonData}" -F "file1=@${discordAttachmentPath}" ${discordWebhookBase}"/"${discordID}"/"${discordToken}) | ||||
| 
 | ||||
|     fi | ||||
| 
 | ||||
|     # Check if curl was successful | ||||
|     if [ $? -ne 0 ]; then | ||||
|         echo "Error: Failed to send webhook message." >&2 | ||||
|         exit 1 | ||||
|     fi | ||||
| 
 | ||||
|     # Output curl reposnse if debug enabled | ||||
|     [ ${debug} ] && echo "${response}" >&2 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #### PARSE ARGUMENTS #### | ||||
| 
 | ||||
| # Parsed from command line arguments. | ||||
| while [[ $# -gt 0 ]]; do | ||||
|     case "$1" in | ||||
|         -c|--content) | ||||
|             discordMessageContent="$2" | ||||
|             shift 2 | ||||
|             ;; | ||||
|         -e|--embeds) | ||||
|             discordMessageEmbeds="$2" | ||||
|             shift 2 | ||||
|             ;; | ||||
|         -f|--file) | ||||
|             discordAttachmentPath="$2" | ||||
|             shift 2 | ||||
|             ;; | ||||
|         -d|--debug) | ||||
|             debug=true | ||||
|             shift | ||||
|             ;; | ||||
|         -h|--help) | ||||
|             usage | ||||
|             exit 0 | ||||
|             ;; | ||||
|         *) | ||||
|             echo "Invalid option: $1" >&2 | ||||
|             usage | ||||
|             exit 1 | ||||
|             ;; | ||||
|     esac | ||||
| done | ||||
| 
 | ||||
| # Check if JSON is provided and not empty | ||||
| if [ -z "${discordMessageContent}" ] && [ -z "${discordMessageEmbeds}" ]; then | ||||
|     echo "Error: Either a message 'content' or message 'embed' is required." >&2 | ||||
|     usage | ||||
|     exit 1 | ||||
| fi | ||||
| 
 | ||||
| #### DISCORD VARIABLES #### | ||||
| 
 | ||||
| # Discord webhook address base. | ||||
| discordWebhookBase="https://discord.com/api/webhooks" | ||||
| 
 | ||||
| # Import secret variables. | ||||
| source ${scriptPath}/discord-variables.sh | ||||
| 
 | ||||
| # Discord secret variables. | ||||
| discordToken=${DISCORD_TOKEN} | ||||
| discordID=${DISCORD_ID} | ||||
| discordUsername=${DISCORD_USER} | ||||
| discordAvatarURL=${DISCORD_AVATAR_URL} | ||||
| discordRoleID=${DISCORD_ROLE_ID} | ||||
| 
 | ||||
| #### REPLACE ROLES #### | ||||
| 
 | ||||
| # Replace @admin mention with correct ID. | ||||
| discordMessageEmbeds=$(echo "${discordMessageEmbeds}" | sed 's/\@admin/\<\@\&'${discordRoleID}'/g') | ||||
| 
 | ||||
| #### BUILD DISCORD MESSAGE #### | ||||
| 
 | ||||
| # Complete the Discord JSON string. | ||||
| discordJson='{ | ||||
|   "username":"'"${discordUsername}"'", | ||||
|   "content":"'"${discordMessageContent}"'", | ||||
|   "avatar_url":"'"${discordAvatarURL}"'", | ||||
|   "embeds": [ '${discordMessageEmbeds%?}' ] | ||||
| }' | ||||
| 
 | ||||
| #### MESSAGE LIMIT CHECK & SEND #### | ||||
| 
 | ||||
| # Call script to perform limit checks (pass on debug argument if debug enabled) | ||||
| ${limitCheckScrip} -m "${discordJson}" ${debug:+-d} | ||||
| 
 | ||||
| # Send full, split or drop message based in limit check | ||||
| case ${?} in | ||||
| 
 | ||||
|     # Send full message | ||||
|     0) | ||||
|         # Output info if debug enabled | ||||
|         [ ${debug} ] && echo "Content within limits. Sending full webhook message." >&2 | ||||
| 
 | ||||
|         # Send full Json | ||||
|         sendWebhook "${discordJson}" true | ||||
|         ;; | ||||
| 
 | ||||
|     # Split message in multiple webhooks | ||||
|     1) | ||||
|         # Output info if debug enabled | ||||
|         [ ${debug} ] && echo "Content to large, but within manageable limits. Splitting webhook message" >&2 | ||||
| 
 | ||||
|         # Remove embeds section | ||||
|         discordJsonMinusEmbeds=$(jq "del(.embeds)" <<< "${discordJson}") | ||||
| 
 | ||||
|         # Send message without embeds | ||||
|         sendWebhook "${discordJsonMinusEmbeds}" true | ||||
| 
 | ||||
|         # Get number of embeds in original message | ||||
|         embedsCount=$(jq ".embeds | length" <<< "${discordJson}") | ||||
| 
 | ||||
|         # Send each embed as a separate message | ||||
|         for (( index=0; index<$embedsCount; index++ )); do | ||||
| 
 | ||||
|             # Get current embed in embeds section | ||||
|             embed=$(jq ".embeds[$index]" <<< "${discordJson}") | ||||
| 
 | ||||
|             # Replace embeds in orignal message with current single embed and remove content section | ||||
|             discordJsonSingleEmbed=$(jq ".embeds=[$embed] | del(.content)" <<< "${discordJson}") | ||||
| 
 | ||||
|             # Send message with single embed and without the rest of the data | ||||
|             sendWebhook "${discordJsonSingleEmbed}" false | ||||
| 
 | ||||
|         done | ||||
|         ;; | ||||
| 
 | ||||
|     # Drop message and exit with error | ||||
|     *) | ||||
|         echo "Error: Limit check failed or content outside manageable limits. Unable to send webhook." >&2 | ||||
|         exit 1 | ||||
|         ;; | ||||
| 
 | ||||
| esac | ||||
		Loading…
	
		Reference in New Issue