#!/bin/sh # Install as root:root 0755 at /usr/local/sbin/han-message-safety-mode. set -eu MODE_FILE=/etc/han-chat/message-safety-mode.env COMPOSE=/usr/local/sbin/han-vm2-compose LOCK=/run/lock/han-message-safety-mode.lock MODE_GROUP=han-message-safety if [ "$#" -eq 1 ] && [ "$1" = standard ]; then mock=false text=false file=false elif [ "$#" -eq 5 ] && [ "$1" = mock ] && [ "$2" = --text-free ] && { [ "$3" = true ] || [ "$3" = false ]; } && [ "$4" = --file-free ] && { [ "$5" = true ] || [ "$5" = false ]; }; then mock=true text=$3 file=$5 else echo "usage: han-message-safety-mode standard | mock --text-free true|false --file-free true|false" >&2 exit 64 fi [ "$(id -u)" -eq 0 ] || { echo "must run through approved sudo rule" >&2 exit 77 } [ -x "$COMPOSE" ] || { echo "fixed compose launcher is unavailable" >&2 exit 69 } exec 9>"$LOCK" /usr/bin/flock -n 9 || { echo "another mode transition is active" >&2 exit 75 } directory=$(dirname "$MODE_FILE") /usr/bin/install -d -o root -g root -m 0700 "$directory" temporary=$(/usr/bin/mktemp "$directory/.message-safety-mode.XXXXXX") backup=$(/usr/bin/mktemp "$directory/.message-safety-mode.backup.XXXXXX") cleanup() { /usr/bin/rm -f "$temporary" "$backup" } trap cleanup EXIT HUP INT TERM if [ -f "$MODE_FILE" ]; then /usr/bin/cp --preserve=mode,ownership "$MODE_FILE" "$backup" else : >"$backup" /usr/bin/chmod 0600 "$backup" fi old_mode=$(/usr/bin/awk -F= ' $1 == "MESSAGE_SAFETY_MOCK_ENABLED" {mock=$2} $1 == "MESSAGE_SAFETY_MOCK_TEXT_FREE" {text=$2} $1 == "MESSAGE_SAFETY_MOCK_FILE_FREE" {file=$2} END {printf "mock=%s,text=%s,file=%s", mock, text, file} ' "$backup") { printf 'MESSAGE_SAFETY_MOCK_ENABLED=%s\n' "$mock" printf 'MESSAGE_SAFETY_MOCK_TEXT_FREE=%s\n' "$text" printf 'MESSAGE_SAFETY_MOCK_FILE_FREE=%s\n' "$file" } >"$temporary" /usr/bin/chown root:"$MODE_GROUP" "$temporary" /usr/bin/chmod 0640 "$temporary" /usr/bin/mv -fT "$temporary" "$MODE_FILE" restart_api() { "$COMPOSE" config --quiet && "$COMPOSE" up -d --no-deps --force-recreate message-safety-api } healthy=false if restart_api; then attempt=0 while [ "$attempt" -lt 30 ]; do container=$("$COMPOSE" ps -q message-safety-api) if [ -n "$container" ]; then status=$(/usr/bin/docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container") if [ "$status" = healthy ]; then healthy=true break fi fi attempt=$((attempt + 1)) /usr/bin/sleep 2 done fi if [ "$healthy" != true ]; then if [ -s "$backup" ]; then /usr/bin/cp "$backup" "$temporary" else printf '%s\n' \ 'MESSAGE_SAFETY_MOCK_ENABLED=false' \ 'MESSAGE_SAFETY_MOCK_TEXT_FREE=false' \ 'MESSAGE_SAFETY_MOCK_FILE_FREE=false' >"$temporary" fi /usr/bin/chown root:"$MODE_GROUP" "$temporary" /usr/bin/chmod 0640 "$temporary" /usr/bin/mv -fT "$temporary" "$MODE_FILE" restart_api || true /usr/bin/logger -p authpriv.err -t han-message-safety-mode "transition failed; previous policy restored" exit 1 fi /usr/bin/logger -p authpriv.notice -t han-message-safety-mode \ "transition succeeded old=$old_mode new=mock=$mock,text=$text,file=$file actor=${SUDO_USER:-root}"