
# Copyright 2015-2024 Rivoreo

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
# IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.


_load_encryped_history_internal() {
	[ -n "$HISTORY_KEY" ] || return
	local tmp_history_file r=1
	tmp_history_file="`mktemp \"$HOME/.bash_history.$$.XXXXXX\"`" || return
	if _decrypt_history "$HISTORY_KEY" < "$ENCRYPTED_HISTORY_FILE" > "$tmp_history_file"; then
		history -r "$tmp_history_file" && r=0
	fi
	rm -f "$tmp_history_file"
	return $r
}

load_encryped_history() {
	[ "${-#*i}" = "$-" ] && return 1
	[ -f "$ENCRYPTED_HISTORY_FILE" ] || return
	begin_print_status "Loading history"
	if _load_encryped_history_internal; then
		end_print_status_ok
	else
		end_print_status_fail
	fi
}

_append_encrypted_history_internal() {
	[ -n "$HISTORY_KEY" ] || return
	local value nonce pad
	if get_encrypted_byte_count "$ENCRYPTED_HISTORY_FILE"; then
		nonce=$((value/8))
		pad=$((value%8))
	else
		nonce=0
		pad=0
		chmod 600 "$ENCRYPTED_HISTORY_FILE" >> "$ENCRYPTED_HISTORY_FILE" || return
	fi
	# bash(1) may fake the presence of /dev/stdout, try use another shell
	if [ "$1" = -e ] && sh -c "[ -h /dev/stdout ] || [ -c /dev/stdout ]" > /dev/null; then
		history -a /dev/stdout | _encrypt_history "$HISTORY_KEY" $nonce $pad >> "$ENCRYPTED_HISTORY_FILE"
		# Use $? explicitly get the expected status in bash 4.4+
		return $?
	fi
	local history_pipe="$HOME/.bash_history.$$" pid r=0
	rm -f "$history_pipe"
	mkfifo -m 600 "$history_pipe" || return
	_encrypt_history "$HISTORY_KEY" $nonce $pad < "$history_pipe" >> "$ENCRYPTED_HISTORY_FILE" & pid=$!
	history -a "$history_pipe" || r=1
	wait $pid || r=1
	rm -f "$history_pipe"
	return $r
}

append_encrypted_history() {
	[ "${-#*i}" = "$-" ] && return 1
	begin_print_status "Storing history"
	if _append_encrypted_history_internal "$@"; then
		end_print_status_ok
	else
		end_print_status_fail
	fi
}

ask_history_passphrase() {
	local passphrase
	read -rs -p "History key or passphrase? " passphrase && [ -n "$passphrase" ] || return
	echo 1>&2
	if printf %s\\n "$passphrase" | grep -Eq '^[0-9a-f]{32}$'; then
		HISTORY_KEY="$passphrase"
	elif HISTORY_KEY="`printf %s \"$passphrase\" | md5sum 2> /dev/null`"; then
		HISTORY_KEY="${HISTORY_KEY%% *}"
	elif HISTORY_KEY="`md5 -q -s \"$passphrase\" 2> /dev/null`"; then
		true
	elif HISTORY_KEY="`printf %s \"$passphrase\" | toolbox md5 -q -- - 2> /dev/null`"; then
		true
	else
		echo "Couldn't find a working md5sum(1) or md5(1) tool" 1>&2
		false
	fi
}

if [ "${-#*i}" != "$-" ]; then
	for f in "$HOME"/.bash_history.*.??????; do
		if [ -h "$f" ]; then
			rm -f "$f"
			continue
		fi
		[ -e "$f" ] || continue
		if [ ! -f "$f" ]; then
			printf "Warning: Found non-regular file '%s'\\n" "${f##*/}" 1>&2
			continue
		fi
		pid="${f##*/.bash_history.}"
		pid="${pid%.??????}"
		if printf %s\\n "$pid" | grep -Eq '^[0-9]+$'; then
			[ -d "/proc/$pid" ] || ps -p "$pid" > /dev/null && continue
		fi
		rm -f "$f" > "$f"
	done
	unset HISTFILE
	if [ -n "${HISTORY_KEY+set}" ]; then
		if printf %s\\n "$HISTORY_KEY" | grep -Eq '^[0-9a-fA-F]{32}$'; then
			# Unexport this variable for security
			declare +x HISTORY_KEY
		else
			echo "Warning: Predefined HISTORY_KEY is invalid" 1>&2
			unset HISTORY_KEY
		fi
	fi
	if [ -n "$HISTORY_KEY" ] || ask_history_passphrase; then
		[ -z "$ENCRYPTED_HISTORY_FILE" ] && ENCRYPTED_HISTORY_FILE="$HOME/.bash_history.e"
		load_encryped_history
		trap "append_encrypted_history -e" EXIT
	else
		echo "Warning: Persistent history disabled" 1>&2
		HISTORY_KEY=
	fi
fi
