achar/achar

620 lines
14 KiB
Bash

#!/bin/bash
## Title : ACHAR - Auto Completion of Hosts Add/Remove script
## Version : 0.2.2
## GIT Repo : https://git.zaks.web.za/zaks-web/achar
## Author : Ze'ev Schurmann
## Company : ZAKS Web
## Website : https://www.zaks.web.za/
## Reddit : https://www.reddit.com/r/ZAKSWeb
## License : GPL3 or Later
## Description: This tool allows for the management of bash auto completion of
## hostnames when using SSH or RSync in Bash.
##
## USAGE
##
## From the bash terminal, type:
## $ achar {command} {context}
##
## COMMANDS
##
## add - adds a host to your list of common hosts
## $ achar add username@hostname.domainname.tld
## $ achar add username@1.2.3.4
##
## disable - disables auto completion of hostnames for current system user
## $ achar disable
## * does not delete the list of hosts stored at ~/.achar/hosts
##
## enable - enables auto completion of hostnames for current system user
## $ achar enable
##
## help - displays this block of text
## $ achar help
##
## license - displays the GPL3 and Later license
## $ achar license
##
## list - list all existing hosts from your list of common hosts
## $ achar list
## * You can use context to search for a specific hostname or part there of
## $ achar list username
## $ achar list part-of-hostname
##
## remove - removes an existing host from your list of common hosts
## $ achar remove username@hostname.domainname.tld
## $ achar remove username@1.2.3.4
##
## reset - deletes all saved hosts
## $ achar reset
##
## uninstall - uninstalls achar from your system
## $ sudo achar uninstall
## # achar uninstall
## * does not delete the list of hosts stored at ~/.achar/hosts
##
## update - checks for an update to ACHAR and prompts you to install it
## $ achar update
bashrc_array=("# enable host autocompletion for ssh and rsync" "[ -f ~/.achar/completions ] && [ -f ~/.achar/hosts ] && . ~/.achar/completions")
completions_array=("# Include existing rsync completions" ". /usr/share/bash-completion/completions/rsync" "" "# Include existing ssh completions" ". /usr/share/bash-completion/completions/ssh" "" "# Function to add custom user@hostname completions" "_custom_hosts()" "{" " local cur=\"\${COMP_WORDS[COMP_CWORD]}\"" " local hosts=\$(cat ~/.achar/hosts)" " COMPREPLY=( \$(compgen -W \"\$hosts\" -- \"\$cur\") )" "}" "" "# Function to handle extended rsync completions" "_extended_rsync_completions()" "{" " local cur=\"\${COMP_WORDS[COMP_CWORD]}\"" "" " # Use custom host completions if '@' is detected" " if [[ \"\$cur\" == *@* ]]; then" " _custom_hosts" " else" " # Fallback to default rsync completion" " _rsync" " fi" "}" "" "# Extend the existing ssh completion function to include custom hosts" "_extended_ssh_completions()" "{" " local cur=\"\${COMP_WORDS[COMP_CWORD]}\"" "" " # Use custom host completions if '@' is detected" " if [[ \"\$cur\" == *@* ]]; then" " _custom_hosts" " else" " # Fallback to default ssh completion" " _ssh" " fi" "}" "" "# Preserve the original rsync completion function" "if declare -F _rsync &>/dev/null; then" " complete -r rsync" " complete -F _extended_rsync_completions rsync" "fi" "" "# Preserve the original ssh completion function" "if declare -F _ssh &>/dev/null; then" " complete -r ssh" " complete -F _extended_ssh_completions ssh" "fi")
completions_md5="a148257d1f32705ef2c1f292e72d528c"
function achar_add {
local username_and_hostname
username_and_hostname=$1
validate_achar_installation hosts
validate_host "$username_and_hostname"
if [[ -z $(cat ~/.achar/hosts | grep "$username_and_hostname") ]]; then
echo $username_and_hostname >> ~/.achar/hosts
else
echo "$username_and_hostname is already added!" >&2
exit 1
fi
}
function achar_disable {
validate_achar_installation disabled
rm ~/.achar/completions
for ((i=0; i<${#bashrc_array[@]}; i++)); do
line=$(echo "${bashrc_array[$i]}" | sed 's/[]\/$*.^|[]/\\&/g')
sed -i "/^$line$/d" ~/.bashrc
done
echo "Please start a new Bash Terminal Session for the change to take affect."
}
function achar_enable {
validate_achar_installation enabled
if [[ ! -d ~/.achar ]]; then
mkdir ~/.achar
fi
if [[ ! -f ~/.achar/hosts ]]; then
touch ~/.achar/hosts
fi
touch ~/.achar/completions
for ((i=0; i<${#completions_array[@]}; i++)); do
echo "${completions_array[$i]}" >> ~/.achar/completions
done
for ((i=0; i<${#bashrc_array[@]}; i++)); do
echo "${bashrc_array[$i]}" >> ~/.bashrc
done
echo "Please start a new Bash Terminal Session for the change to take affect."
}
function achar_help {
local script_path
script_path="${BASH_SOURCE[0]}"
echo
while read -r line; do
if [[ ${line:0:2} == "##" ]]; then
echo "${line:3}"
elif [[ ${line:0:2} == "#!" ]]; then
donothing=0
else
echo
exit 0
fi
done < "$script_path"
}
function achar_license {
echo
curl -s https://git.zaks.web.za/zaks-web/achar/raw/branch/main/LICENSE | fmt
if [[ $? != 0 ]]; then
echo "Could not get the license file." >&2
echo "Either you are not connected to the Internet or the update server is down." >&2
exit 1
fi
echo
}
function achar_list {
validate_achar_installation hosts
if [[ -z $1 ]]; then
cat ~/.achar/hosts | sort
else
cat ~/.achar/hosts | grep "$1" | sort
fi
}
function achar_remove {
local username_and_hostname
username_and_hostname=$1
validate_achar_installation hosts
validate_host $username_and_hostname
if [[ -z $(cat ~/.achar/hosts | grep "$username_and_hostname") ]]; then
echo "$username_and_hostname is not there!" >&2
exit 1
else
sed -i "/^$username_and_hostname$/d" ~/.achar/hosts
fi
}
function achar_reset {
validate_achar_installation hosts
echo "This will delete all saved hosts and"
echo "and start from scratch."
echo
echo "Press ENTER to continue or CTRL+C to STOP!"
read text
rm ~/.achar/hosts
touch ~/.achar/hosts
}
function achar_uninstall {
local script_path
local text
script_path="${BASH_SOURCE[0]}"
if [[ $(whoami) == "root" ]]; then
echo "You are about to uninstall ACHAR."
echo
echo "If you want to disable the autocompletions, then"
echo "you must run \"achar disable\" for each user."
echo "This is recommended if you are planning to install"
echo "a new version."
echo
echo "Press ENTER to continue or CTRL+C to STOP!"
read text
rm $script_path
else
echo "Please run with root privilages (sudo) in order to uninstall."
exit 1
fi
}
function achar_update {
local difference
local script_path
local stable_version_number
local -a stable_version_number_array
local test_stable
local test_version
local update_available
local -a version_line
local version_number
local -a version_number_array
script_path="${BASH_SOURCE[0]}"
version_line=($(grep '^## Version' "$script_path"))
version_number=${version_line[3]}
stable_version_number=$(curl -s https://git.zaks.web.za/zaks-web/achar/raw/branch/main/stable_version)
if [[ $? != 0 ]]; then
echo "Could not check for latest version." >&2
echo "Either you are not connected to the Internet or the update server is down." >&2
exit 1
fi
oldIFS=$IFS
IFS="."
version_number_array=($version_number)
stable_version_number_array=($stable_version_number)
IFS=$oldIFS
if [[ ${#version_number_array[@]} -gt ${#stable_version_number_array[@]} ]]; then
difference=$((${#version_number_array[@]}-${#stable_version_number_array[@]}))
for ((i=0; i<$differnce; i++)); do
$stable_version_number_array[${#stable_version_number_array[@]}]=0
done
elif [[ ${#stable_version_number_array[@]} -gt ${#version_number_array[@]} ]]; then
difference=$((${#version_number_array[@]}-${#stable_version_number_array[@]}))
for ((i=0; i<$differnce; i++)); do
$stable_version_number_array[${#stable_version_number_array[@]}]=0
done
fi
echo "Current version is $version_number"
echo "Latest version is $stable_version_number"
update_available="false"
for ((i=0; i<${#version_number_array[@]}; i++)); do
if [[ $update_available == "false" ]]; then
test_stable=${stable_version_number_array[$i]##+(0)}
test_version=${version_number_array[$i]##+(0)}
if [[ -z $test_stable ]]; then
test_stable=0
fi
if [[ -z $test_version ]]; then
test_version=0
fi
if [[ ${#stable_version_number_array[@]} -gt ${#version_number_array[@]} ]]; then
update_available="true"
fi
fi
done
if [[ $update_available == "true" ]]; then
echo "Update is avaiable!"
echo
echo "First run \"achar disable\" for all users."
echo "Then run \"achar uninstall\" as root or sudo."
echo "Lastly, follow the instructions at"
echo "https://git.zaks.web.za/zaks-web/achar"
echo "to install the latest version."
else
echo "You currently have the latest version!"
fi
}
function validate_achar_installation {
local achar_installation_error_code=""
local what_test
what_test=$1
if [[ -d ~/.achar ]]; then
achar_installation_error_code="A$achar_installation_error_code"
else
achar_installation_error_code="a$achar_installation_error_code"
fi
if [[ -f ~/.achar/hosts ]]; then
achar_installation_error_code="H$achar_installation_error_code"
else
achar_installation_error_code="h$achar_installation_error_code"
fi
if [[ -f ~/.achar/completions ]]; then
md5_test=$(cat ~/.achar/completions | md5sum)
if [[ ${md5_test:0:32} == $completions_md5 ]]; then
achar_installation_error_code="C$achar_installation_error_code"
else
echo "File corrupt: ~/.achar/completions" >&2
exit 1
fi
else
achar_installation_error_code="c$achar_installation_error_code"
fi
test=$(echo "${bashrc_array[1]}" | sed 's/[]\/$*.^|[]/\\&/g')
if [[ -z $(cat ~/.bashrc | grep "${bashrc_array[0]}") ]] || [[ -z $(cat ~/.bashrc | grep "$test") ]]; then
achar_installation_error_code="b$achar_installation_error_code"
else
achar_installation_error_code="B$achar_installation_error_code"
fi
if [[ $achar_installation_error_code == "BCHA" ]] && [[ $what_test == "enabled" ]]; then
echo "ACHAR is already enabled!"
exit 1
elif [[ $achar_installation_error_code == "bcha" ]] && [[ $what_test == "disabled" ]]; then
echo "ACHAR is already disabled!"
exit 1
elif [[ $achar_installation_error_code == "bcHA" ]] && [[ $what_test == "disabled" ]]; then
echo "ACHAR is already disabled!"
exit 1
elif [[ $achar_installation_error_code == "bcha" ]] && [[ -z $what_test ]]; then
echo "ACHAR is disabled!"
exit 1
elif [[ $achar_installation_error_code == "bcha" ]] && [[ $what_test == "hosts" ]]; then
echo "ACHAR is disabled!"
exit 1
elif [[ $achar_installation_error_code != "BCHA" ]] && [[ $achar_installation_error_code != "bcha" ]] && [[ -z $what_test ]]; then
echo "Something is wrong with your setup!" >&2
if [[ ${achar_installation_error_code:0:1} == "b" ]]; then
echo "Required code missing from ~/.bashrc" >&2
fi
if [[ ${achar_installation_error_code:1:1} == "c" ]]; then
echo "File missing: ~/.achar/completions" >&2
fi
if [[ ${achar_installation_error_code:2:1} == "h" ]]; then
echo "File missing: ~/.achar/hosts" >&2
fi
if [[ ${achar_installation_error_code:3:1} == "a" ]]; then
echo "Folder missing: ~/.achar/" >&2
fi
exit 1
fi
}
function validate_host {
local hostname
local -a temp_array
local username_and_hostname
local username
if [[ -z $1 ]]; then
echo "Unexpected Error!"
exit 1
fi
username_and_hostname="$1"
temp_array=($username_and_hostname)
if [[ ${#temp_array[@]} != 1 ]]; then
echo "Invalid Hostname!"
exit 1
fi
old_ifs=$IFS
IFS="@"
temp_array=($username_and_hostname)
IFS=$old_ifs
if [[ ${#temp_array[@]} != 2 ]]; then
echo "Invalid Hostname!"
exit 1
fi
username=${temp_array[0]}
hostname=${temp_array[1]}
if [[ $hostname =~ ^([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$ ]]; then
donothing=0
elif nslookup "$hostname" > /dev/null 2>&1; then
donothing=0
else
echo "Invalid Domain Name or IP address!"
exit 1
fi
if [[ ${username:0:1} =~ ^[0-9]$ ]] || [[ ! $username =~ ^[A-Za-z0-9_.-]+$ ]]; then
echo "Username is not a valid format!"
echo "Must contain \"A-Z\", \"a-z\", \"0-9\", \"_\", \".\" and \"-\"."
exit 1
fi
}
if [[ -z $1 ]]; then
achar_help
elif [[ ${1,,} == "add" ]]; then
if [[ -z $2 ]]; then
echo "Please include a username@hostname" >&2
exit 1
else
achar_add $2
fi
elif [[ ${1,,} == "disable" ]]; then
achar_disable
elif [[ ${1,,} == "enable" ]]; then
achar_enable
elif [[ ${1,,} == "help" ]]; then
achar_help
elif [[ ${1,,} == "license" ]]; then
achar_license
elif [[ ${1,,} == "list" ]]; then
if [[ -z $2 ]]; then
achar_list
else
achar_list $2
fi
elif [[ ${1,,} == "remove" ]]; then
if [[ -z $2 ]]; then
echo "Please include a username@hostname" >&2
exit 1
else
achar_remove $2
fi
elif [[ ${1,,} == "reset" ]]; then
achar_reset
elif [[ ${1,,} == "uninstall" ]]; then
achar_uninstall
elif [[ ${1,,} == "update" ]]; then
achar_update
else
achar_help
fi
exit 0