Skip to content

Instantly share code, notes, and snippets.

@ulasozguler
Created August 28, 2026 09:43
Show Gist options
  • Select an option

  • Save ulasozguler/bd6cf99cebed9255933fc018fec261ab to your computer and use it in GitHub Desktop.

Select an option

Save ulasozguler/bd6cf99cebed9255933fc018fec261ab to your computer and use it in GitHub Desktop.
Gather.town smart object script. Set URL and SECRET.
#!/bin/bash
KEY_HEX=$(printf %s "${SECRET#whsec_}" | base64 -d | od -An -tx1 | tr -d ' \n')
sign_and_send() {
local BODY="$1"
local WEBHOOK_ID=$(uuidgen)
local TS=$(date +%s)
local SIG=$(printf '%s' "${WEBHOOK_ID}.${TS}.${BODY}" \
| openssl dgst -sha256 -mac hmac -macopt hexkey:"$KEY_HEX" -binary | base64)
curl -sS -o - -w '\nHTTP %{http_code}\n' -X POST "$URL" \
-H "content-type: application/json" \
-H "webhook-id: $WEBHOOK_ID" \
-H "webhook-timestamp: $TS" \
-H "webhook-signature: v1,$SIG" \
--data-raw "$BODY"
}
set_status() {
local STATE="$1"
case "$STATE" in
off|on|question|alert|working) ;;
*) echo "invalid state: '$STATE' (allowed: off on question alert working)" >&2; return 2 ;;
esac
sign_and_send "{\"type\":\"status.set\",\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"data\":{\"state\":\"$STATE\"}}"
}
reset_status() {
sign_and_send "{\"type\":\"status.reset\",\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}"
}
json_escape() {
printf %s "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/\t/\\t/g' | tr -d '\n\r'
}
activity_add() {
local ID="$1" TEXT="$2" LINK="$3"
if [ -z "$ID" ] || [ -z "$TEXT" ]; then
echo "usage: $0 activity add <id> <text> [url]" >&2; return 2
fi
local DATA="{\"id\":\"$(json_escape "$ID")\",\"text\":\"$(json_escape "$TEXT")\""
[ -n "$LINK" ] && DATA="$DATA,\"url\":\"$(json_escape "$LINK")\""
DATA="$DATA}"
sign_and_send "{\"type\":\"activity.add\",\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"data\":$DATA}"
}
activity_remove() {
local ID="$1"
if [ -z "$ID" ]; then echo "usage: $0 activity remove <id>" >&2; return 2; fi
sign_and_send "{\"type\":\"activity.remove\",\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"data\":{\"id\":\"$(json_escape "$ID")\"}}"
}
activity_clear() {
sign_and_send "{\"type\":\"activity.clear\",\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}"
}
usage() {
cat >&2 <<USAGE
usage: $0 <command>
ping health check; prints preset + current state
status <off|on|question|alert|working>
reset status back to off
activity add <id> <text> [url] add or update a feed entry by id
activity remove <id>
activity clear empty the feed
USAGE
}
case "${1:-ping}" in
ping) sign_and_send '{"type":"webhook.ping"}' ;;
status) set_status "$2" ;;
reset) reset_status ;;
activity)
case "$2" in
add) activity_add "$3" "$4" "$5" ;;
remove) activity_remove "$3" ;;
clear) activity_clear ;;
*) usage; exit 64 ;;
esac
;;
*) usage; exit 64 ;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment