From 38223d8f775df814bbcb2a28c4c157f4996de965 Mon Sep 17 00:00:00 2001 From: Amolith Date: Tue, 1 Jul 2025 10:12:25 -0600 Subject: [PATCH] initial commit --- .claude/settings.local.json | 8 ++ README.md | 79 +++++++++++++++++++ mumblingherald | 146 ++++++++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+) create mode 100644 .claude/settings.local.json create mode 100644 README.md create mode 100755 mumblingherald diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000000000000000000000000000000000000..71cfaf121de412d3d55791ba937b09b5904a1167 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "Bash(shellcheck:*)" + ], + "deny": [] + } +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a840f5bdd407734370281122edc113bfed70105a --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ + + +# The Mumbling Herald + +A grumpy old herald who watches your Mumble server and announces comings and goings via XMPP. + +## Full setup + +- Create a herald user with minimal permissions + ```bash + sudo useradd -r -s /bin/false -d /var/lib/mumblingherald -m mumblingherald + sudo usermod -a -G mumble-server mumblingherald # if mumble-server group exists for log access + ``` +- Copy script to user's directory, make it executable, and set ownership + ```bash + sudo cp mumblingherald /var/lib/mumblingherald + sudo chown mumblingherald:mumblingherald /var/lib/mumblingherald/mumblingherald + sudo chmod 700 /var/lib/mumblingherald/mumblingherald + ``` +- Edit the script to configure details + - `MUMBLE_LOG_FILE`: path to your Mumble server log + - `XMPP_RECIPIENTS`: recipient JID for notifications + - `MONITORED_CHANNELS`: display name of channels to watch +- Install go-sendxmpp + - Download the latest binary from the [go-sendxmpp releases page](https://salsa.debian.org/mdosch/go-sendxmpp/-/releases) + - Extract and copy to system location + ```bash + sudo cp go-sendxmpp /usr/local/bin/ + sudo chmod 755 /usr/local/bin/go-sendxmpp + ``` +- Create config directory + ```bash + sudo -u mumblingherald mkdir -p /var/lib/mumblingherald/.config/go-sendxmpp + ``` +- Create XMPP config in `/var/lib/mumblingherald/.config/go-sendxmpp/config` (edit values!) + ```bash + username: herald@your-xmpp-server.com + password: your-password + ``` + - Correct permissions + ```bash + chmod 600 /var/lib/mumblingherald/.config/go-sendxmpp/config + ``` +- Create systemd service in `/etc/systemd/system/mumblingherald.service` + ```ini + [Unit] + Description=The Mumbling Herald - Mumble event notifier over XMPP + After=network.target + [Service] + Type=simple + User=mumblingherald + Group=mumble-server + WorkingDirectory=/var/lib/mumblingherald + Environment=HOME=/var/lib/mumblingherald + ExecStart=/var/lib/mumblingherald/mumblingherald + Restart=always + RestartSec=5 + [Install] + WantedBy=multi-user.target + ``` +- Start the herald + ```bash + sudo systemctl daemon-reload + sudo systemctl enable --now mumblingherald + ``` +- Check status + ```bash + sudo systemctl status mumblingherald + ``` + +## Logs + +```bash +sudo journalctl -u mumblingherald -f +``` diff --git a/mumblingherald b/mumblingherald new file mode 100755 index 0000000000000000000000000000000000000000..6deadc34645a547fe9e9842f75b67b9cdf4abb92 --- /dev/null +++ b/mumblingherald @@ -0,0 +1,146 @@ +#!/bin/bash + +# SPDX-FileCopyrightText: Amolith +# +# SPDX-License-Identifier: Unlicense + +# TheMumblingHerald +# Monitors Mumble server logs and sends XMPP notifications when users join specified channels + +# Configuration +MUMBLE_LOG_FILE="/var/log/mumble-server/mumble-server.log" +XMPP_CONFIG_FILE="$HOME/.config/go-sendxmpp/config" +XMPP_RECIPIENTS="groupchat@conference.example.com" + +# List of channels to monitor (channel names) +# Add or remove channels as needed +MONITORED_CHANNELS=( + "Room 4" + "Room 5" +) + +# Function to check if a channel should be monitored +is_monitored_channel() { + local channel="$1" + for monitored in "${MONITORED_CHANNELS[@]}"; do + if [[ "$channel" == "$monitored" ]]; then + return 0 + fi + done + return 1 +} + +# Arrays of varied messages for the mumbling herald +# shellcheck disable=SC2034 +JOIN_MESSAGES=( + "➡️ {USERNAME} stumbles into {CHANNEL}" + "➡️ {USERNAME} wanders into {CHANNEL}" + "➡️ *clears throat* {USERNAME} appears in {CHANNEL}" + "➡️ {USERNAME} shuffles into {CHANNEL}" + "➡️ Behold! {USERNAME} manifests in {CHANNEL}" + "➡️ {USERNAME} finds their way to {CHANNEL}" + "➡️ Lo! {USERNAME} enters {CHANNEL}" + "➡️ {USERNAME} materializes in {CHANNEL}" +) + +# shellcheck disable=SC2034 +LEAVE_MESSAGES=( + "⬅️ Oh, what? *ahem* {USERNAME} fled... somewhere *waves hand*" + "⬅️ {USERNAME} vanishes into the void..." + "⬅️ {USERNAME} disappeared! Just like that..." + "⬅️ *waves dismissively* Off goes {USERNAME}..." + "⬅️ Farewell to thee, {USERNAME}..." + "⬅️ {USERNAME} has made their exit..." + "⬅️ {USERNAME} has fled our realm..." + "⬅️ *sighs* And thus {USERNAME} departs..." +) + +# Function to get a random message from an array +get_random_message() { + local -n arr=$1 + echo "${arr[$RANDOM % ${#arr[@]}]}" +} + +# Function to send XMPP notification +send_notification() { + local message="$1" + echo "$message" | go-sendxmpp -c -f "$XMPP_CONFIG_FILE" "$XMPP_RECIPIENTS" +} + +# Function to parse log line and extract user move information +parse_move_event() { + local log_line="$1" + + # Extract user and destination channel + # Format: 2025-07-01 14:07:32.352 1 => <28:Amolith(5)> Moved Amolith:28(5) to Room 5[53:20] + if [[ "$log_line" =~ \[0-9-]+\ [0-9:.]+.*\>\ Moved\ ([^:]+):[0-9]+\([0-9]+\)\ to\ ([^\[]+)\[ ]]; then + local username="${BASH_REMATCH[1]}" + local channel="${BASH_REMATCH[2]}" + + # Check if this channel should be monitored + if is_monitored_channel "$channel"; then + local join_msg + join_msg=$(get_random_message JOIN_MESSAGES) + local message="${join_msg//\{USERNAME\}/$username}" + message="${message//\{CHANNEL\}/$channel}" + echo "*herald mumbles something about $username*" + send_notification "$message" + fi + fi +} + +# Function to parse log line and extract user disconnect information +parse_disconnect_event() { + local log_line="$1" + + # Extract user from disconnect event + # Format: 2025-07-01 14:19:46.484 1 => <28:Amolith(5)> Connection closed: The remote host closed the connection [1] + if [[ "$log_line" =~ \[0-9-]+\ [0-9:.]+.*\<[0-9]+:([^\(]+)\([0-9]+\)\>\ Connection\ closed: ]]; then + local username="${BASH_REMATCH[1]}" + + local leave_msg + leave_msg=$(get_random_message LEAVE_MESSAGES) + local message="${leave_msg//\{USERNAME\}/$username}" + echo "*herald notices someone's absence and sighs*" + send_notification "$message" + fi +} + +# Main monitoring loop +echo "🗣️ Shaking the mumbling herald awake..." +echo "📜 Herald will watch these sacred halls: ${MONITORED_CHANNELS[*]}" +echo "👁️ Peering into the mystical log: $MUMBLE_LOG_FILE" +echo "📨 Herald will announce to: $XMPP_RECIPIENTS" +echo "🛑 Press Ctrl+C to put the herald back to sleep" +echo + +# Check if log file exists +if [[ ! -f "$MUMBLE_LOG_FILE" ]]; then + echo "💀 *herald panics* The sacred scroll is missing! $MUMBLE_LOG_FILE" + echo "🔧 Fix the MUMBLE_LOG_FILE path, good sir!" + exit 1 +fi + +# Check if go-sendxmpp is available +if ! command -v go-sendxmpp &>/dev/null; then + echo "📯 *herald looks confused* Where's my speaking trumpet? (go-sendxmpp missing)" + echo "📦 Install go-sendxmpp so I can herald properly!" + exit 1 +fi + +# Check if XMPP config file exists +if [[ ! -f "$XMPP_CONFIG_FILE" ]]; then + echo "⚠️ *herald squints* My address book seems to be missing: $XMPP_CONFIG_FILE" + echo "📝 Please inscribe your XMPP credentials!" +fi + +# Start tailing the log file and processing events +echo "👂 *herald puts ear to the wall and begins listening intently*" +tail -F "$MUMBLE_LOG_FILE" | while read -r line; do + # Process lines that contain "Moved" or "Connection closed" events + if [[ "$line" == *"Moved"* ]]; then + parse_move_event "$line" + elif [[ "$line" == *"Connection closed"* ]]; then + parse_disconnect_event "$line" + fi +done