#!/bin/bash -eu
### Copyright 1999-2026. WebPros International GmbH. All rights reserved.
# Removes temporary backups older than MAX_AGE days made by deployer_lib

MAX_AGE=90 # days
FAIL2BAN_DIR='/etc/fail2ban'
MODSEC_DIR_APACHE='/etc/httpd/conf/modsecurity.d/rules'
MODSEC_DIR_NGINX='/etc/nginx/modsecurity.d/rules'
REMOVAL_PATTERN='*.saved-*-*'
TIMESTAMP_PATTERN_SED='s/.\+\.saved-\([0-9]\{4\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)T\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)-.\+$/\1-\2-\3T\4:\5:\6/'

logerror() {
	IFS=' ' echo "ERROR: $*" >&2
}

logdebug() {
	if [ -n "$DEBUG_MODE" ]; then
		IFS=' ' echo "DEBUG: $*" >&2
	fi
}

die() {
	logerror "$@"
	exit 1
}

# path_in <path> <directory>...
# Returns true if the path is in one of the directories.
function path_in() {
	local path=$1
	shift

	local dir
	for dir in "$@"; do
		if [ "${path#$dir}" != "$path" ]; then
			return 0
		fi
	done
	return 1
}

function rm_path() {
	local path=$1

	if ! path_in "$path" "${DIRS[@]}"; then
		die "Path '$path' is out of a permitted directory"
	fi

	if [ "${path%$REMOVAL_PATTERN}" = "$path" ]; then
		die "Path '$path' doesn't match the removal pattern"
	fi

	logdebug "Removing '$path'"
	$DRY_RUN rm -rf "$path"
}

function main() {
	local now=$(date +%s)
	local min_timestamp=$((now - MAX_AGE * 24 * 60 * 60))
	logdebug "Removing temporary backups older than $(date --date="@$min_timestamp" --iso-8601=seconds) ($min_timestamp)"
	while IFS= read -r -d $'\0' path; do
		local timestamp_iso=$(sed "$TIMESTAMP_PATTERN_SED" <<<"$path")
		local timestamp_unix
		timestamp_unix=$(date --date="$timestamp_iso" +%s) || { logerror "The path '$path' doesn't have a valid timestamp, skipping" && continue; }
		logdebug "Examining '$path' with timestamp $timestamp_iso ($timestamp_unix)"
		if [ "$timestamp_unix" -lt "$min_timestamp" ]; then
			rm_path "$path"
		fi
	done < <(find "${DIRS[@]}" -name "$REMOVAL_PATTERN" -print0)
}

DEBUG_MODE=""
DRY_RUN=""

while [ $# -gt 0 ]; do
	case "$1" in
		-h|--help)
			cat <<-EOT
				Usage: $0 [<options>]
				Removes old temporary backups made by deployer_lib.

				Options:
				--debug                       Turn on debug mode.
				--dry-run                     Don't actually remove anything, just show commands to be performed.
				--max-age MAX_AGE             Remove temporary backups older than MAX_AGE days (default: $MAX_AGE).
				EOT
			exit 0
			;;
		--debug)
			DEBUG_MODE=1
			shift 1
			;;
		--dry-run)
			DRY_RUN="echo"
			shift 1
			;;
		--max-age)
			MAX_AGE=$2
			shift 2
			;;
		*)
			die "Unrecognized argument: $1"
			;;
	esac
done

DIRS=()
dir=""
for dir in "$FAIL2BAN_DIR" "$MODSEC_DIR_APACHE" "$MODSEC_DIR_NGINX"; do
	if [ -n "$dir" -a -d "$dir" ]; then
		DIRS+=("$dir")
	fi
done

main
