movmaker/hooks/mvlog-authorized-notify.sh
2026-05-28 18:56:42 +00:00

46 lines
2 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
# mvlog-authorized-notify.sh - forced-command wrapper for a web-server SSH key.
# Install in worker user's authorized_keys as:
# command="/home/hbrain/source/movmaker/hooks/mvlog-authorized-notify.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAA... comment
#
# The wrapper only allows a very small set of commands originating from the web server:
# python3 /home/hbrain/source/movmaker/mvlog_worker.py --notify-job <job> [--host <web-host>] [--remote-root <remote-root>]
# It validates the job token (simple filename-safe characters) and restricts remote-root to the configured path.
WORKER_MVLOG_PATH="/home/hbrain/source/movmaker/mvlog_worker.py"
ALLOWED_REMOTE_ROOT="/var/www/html/mvlog"
cmd="${SSH_ORIGINAL_COMMAND:-}"
# Expected parts regex; allow quoted or unquoted simple tokens for job/host/root
escaped_path=$(printf '%s' "$WORKER_MVLOG_PATH" | sed 's/[\/&]/\\&/g')
regex="^python3[[:space:]]+${escaped_path}[[:space:]]+--notify-job[[:space:]]+'?([A-Za-z0-9._-]+)'?([[:space:]]+--host[[:space:]]+'?([^'[:space:]]+)'?)?([[:space:]]+--remote-root[[:space:]]+'?([^'[:space:]]+)'?)?.*$"
if [[ $cmd =~ $regex ]]; then
job="${BASH_REMATCH[1]}"
host="${BASH_REMATCH[3]:-}"
remote_root="${BASH_REMATCH[5]:-}"
# Validate simple job token again
if ! [[ $job =~ ^[A-Za-z0-9._-]+$ ]]; then
echo "invalid job token" >&2
exit 1
fi
if [ -n "$remote_root" ] && [ "$remote_root" != "$ALLOWED_REMOTE_ROOT" ]; then
echo "remote_root not allowed" >&2
exit 1
fi
# Run the notify command with validated pieces. If host omitted, use local hostname.
if [ -n "$host" ]; then
exec python3 "$WORKER_MVLOG_PATH" --notify-job "$job" --host "$host" --remote-root "$ALLOWED_REMOTE_ROOT"
else
exec python3 "$WORKER_MVLOG_PATH" --notify-job "$job" --host "$(hostname -f)" --remote-root "$ALLOWED_REMOTE_ROOT"
fi
fi
echo "Unauthorized SSH_ORIGINAL_COMMAND" >&2
exit 2