#!/bin/bash
set -eu
### --help Info: создаст или выведет ssh-ключ указанного типа
### --help Info:
### --help Info: по-умолчанию RSA
### --help Info:
### --help Usage: ssh_keys create|get_public|get_private|authorize_key|trust_host
### --help Usage:           [--type=rsa] [--name=<id_$TYPE>] [--path="$HOME/.ssh"] [--password=""]
### --help Usage:
### --help Usage:    create - создать ключ указанного типа
### --help Usage:
### --help Usage:    get_public - получить публичный ключ
### --help Usage:
### --help Usage:    get_private - получить приватный ключ
### --help Usage:
### --help Usage:    authorize_key - добавить ключ в authorized_keys
### --help Usage:
### --help Usage:    revoke_key - удалить ключ из authorized_keys
### --help Usage:
### --help Usage:    trust_host - добавить фингерпринт хоста в список известных
### --help Usage:
### --help Usage:    untrust_host - удалить фингерпринт хоста из список известных
### --help Usage:
### --help Usage:     --type - тип ключа, rsa|ecdsa|ed25519
### --help Usage:              по-умолчанию RSA
### --help Usage:
### --help Usage:     --name - имя приватного ключа
### --help Usage:              по-умолчанию тип и префикс "id_", например "id_rsa"
### --help Usage:              публичный ключ всегда получает суфикс .pub, например "id_rsa.pub"
### --help Usage:
### --help Usage:     --path - папка, в которой нужно найти или создать ключ
### --help Usage:              по-умолчанию $HOME/.ssh
### --help Usage:
### --help Usage:     --password - указать пароль ключа для create, если он необходим
### --help Usage:
### --help Example: ssh_keys create
### --help Example: ssh_keys public
### --help Example: ssh_keys public --type=ed25519
### --help Example:
__SILENT=TRUE
. /opt/fox_utils/crab_sys.sh
sys::arg_parse "$@"

declare TYPE
declare FILES_PATH
declare NAME
declare NAME_PUB
declare PRIV
declare PUB
declare PSW

TYPE="${ARG_TYPE:-"rsa"}"
NAME="${ARG_NAME:-"id_$TYPE"}"
NAME_PUB="${NAME}.pub"
FILES_PATH="${ARG_PATH:-"$HOME/.ssh"}"
PRIV="$FILES_PATH/$NAME"
PUB="$FILES_PATH/$NAME_PUB"
PSW="${ARG_PASSWORD:-}"


create(){
	local args
	if [[ ! -f "$PRIV" ]]; then
		args=( -f "$PRIV" -t "$TYPE" -N "$PSW" )
		if [[ $TYPE == rsa ]]; then
			args+=( -b 4096 )
		elif [[ $TYPE == ecdsa ]]; then
			args+=( -b 384 )
		fi
		ssh-keygen "${args[@]}"
		echo "Созданы приватный и публичный $TYPE ключи $PRIV $PUB"
	fi
	if [[ ! -f "$PUB" ]]; then
		ssh-keygen -y -f "$PRIV" > "$PUB"
		echo "Создан публичный $TYPE ключ $PUB"
	fi
	return 0
}


authorize_key(){
	local key_to_authorize authorized_keys
	shift
	key_to_authorize="$@"
	authorized_keys="$FILES_PATH/authorized_keys"
	if grep -q -F "$key_to_authorize" "$authorized_keys"; then
		echo "Ключ уже добавлен в $authorized_keys"
		return 0
	fi
	echo "Добавляем указанный ключ в $authorized_keys"
	echo "$key_to_authorize" >> "$authorized_keys"
	return 0
}


revoke_key(){
	local key_to_revoke authorized_keys
	shift
	key_to_revoke="$@"
	authorized_keys="$FILES_PATH/authorized_keys"
	if ! grep -q -F "$key_to_revoke" "$authorized_keys"; then
		return 0
	fi
	echo "Удаляем указанный ключ из $authorized_keys"
	ex -c "g/${key_to_revoke//\//\\/}/d" -cx "$authorized_keys"
	return 0
}


trust_host(){
	local host known_hosts tmp_file fingerprint ret
	host="$ARG_2"
	known_hosts="$FILES_PATH/known_hosts"
	tmp_file="/tmp/ssh_keys_keyscan.$$"
	# retry - для сбоев сети
	for _ in 1 2 3 4 5; do
		if ssh-keygen -F "$host" | grep "$TYPE" >&2; then
			echo "Фингерпритнт $TYPE хоста $host уже в списке доверенных"
			return 0
		fi
		ssh-keyscan -t "${TYPE}" "$host" >> "$known_hosts" && ret=0 || ret=1
		((ret == 0)) && break
		sleep 1
	done
	[[ -f "$tmp_file" ]] && rm -f "$tmp_file"
	return "$ret"
}


untrust_host(){
	local host
	host="$ARG_2"
	ssh-keygen -R "$host"
	return 0
}


get_private(){
	create >&2
	cat "$PRIV"
	return 0
}


get_public(){
	create >&2
	cat "$PUB"
	return 0
}


"$ARG_1" "$@"


exit 0
