diff --git a/lib/idmgr_lib_cli.sh b/lib/idmgr_lib_cli.sh new file mode 100644 index 0000000..913f23a --- /dev/null +++ b/lib/idmgr_lib_cli.sh @@ -0,0 +1,158 @@ + +lib_log () +{ + + set +x + [[ "${1-}" =~ ERR|WARN|TIP|NOTICE|INFO|DEBUG|RUN|CODE|DUMP|DEPRECATED|ASK ]] || + { + lib_log ERR "Wrong message level while calling '${1-}'" + return 1 + } + + local level=$1 + shift || true + local msg="$@" + + # Take from stdin if no message ... + [ "$msg" = - ] && msg=$( cat < /dev/stdin ) + [ -z "$msg" ] && { + echo + return 0 + } + + if [ "$( wc -l <<<"$msg" )" -gt 1 ]; then + while read -r line; do + lib_log $level $line + done <<< "$msg" + return + fi + + local color= + local reset='\033[0m' + case $level in + ERR) + color='\033[0;31m' + ;; + WARN|TIP|DEPRECATED) + color='\033[0;33m' + ;; + NOTICE) + color='\033[0;32m' + ;; + INFO) + color='\033[0;37m' + ;; + DEBUG) + color='\033[0;31m' + ;; + RUN) + color='\033[0;34m' + ;; + CODE) + echo "$msg" + return + ;; + DUMP) + color='\033[0;36m' + echo -e "$color$msg$reset" | sed 's/^/ /' + return + ;; + PREFIX) + color='\033[0;34m' + ;; + esac + + if [[ -n "$level" ]]; then + >&2 printf "$color%*.6s$reset: %s\n" 6 "${level}_____" "$msg" # >&2 + else + echo "Error while log output msg: $msg" + fi +} + +# export PS4='+[${SECONDS}s][${BASH_SOURCE}:${LINENO}]: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'; set -x; +# export PS4='.[${SECONDS}s] \[\e[36m\] ${FUNCNAME[0]:+${FUNCNAME[0]}()[${LINENO}]: }\[\e[m\]'; set -x; +# export PS4='. $( f="${FUNCNAME[0]:+${FUNCNAME[0]//}}"; printf "%10s:%00d %00d %10s| " ${BASH_SOURCE#$HOME/} ${LINENO} ${SECONDS} "$f")' ; set -x; +# export PS4='. $(f="${FUNCNAME[0]:+${FUNCNAME[0]//}}"; s=${BASH_SOURCE#$HOME/}; l=${LINENO}; t=${SECONDS}; printf "%00d %0d %16.50s() " $l $t "$f")' ; set -x; +# export PS4=' \[\e[36m\]> $(f="${FUNCNAME[0]:+${FUNCNAME[0]//}}"; s=${BASH_SOURCE#$HOME/}; l=${LINENO}; t=${SECONDS}; printf "%00d %0d %s():" $l $t "$f")\[\e[m\]\n' ; set -x; +# export LOG="lib_log_wrap \$FUNCNAME " + + + + +lib_trace () +{ + local msg=${@} + local traces= + + ( + echo "Stack trace:" + for i in {0..10}; do + trace=$(caller $i 2>&1 || true ) + if [ -z "$trace" ] ; then + continue + else + #lib_log DEBUG "Trace $i: $trace" + #traces="${traces}${trace}\n" + echo "$trace" + fi + done | tac | column -t + [ -z "$msg" ] || echo "Trace ctx: $msg" + ) | >&2 lib_log DUMP - +} + + + +## CLI lib +############################# + + +# This function display a user skippable timeout. +lib_cli_timeout () +{ + local default_rc=${1:-1} + local wait_time=${2:-$IDM_TIMEOUT_USER} + local start=$(date '+%s') + local human_word go_word + + # Humanise ... + [ "$default_rc" -ge 0 ] || default_rc=1 + if [ "$default_rc" -eq 0 ]; then + human_word="abort" + go_word=Q + elif [ "$default_rc" -ne 0 ]; then + human_word="continue" + go_word=Y + fi + + # Notifying user + local human_date="$(date -d@$wait_time -u '+%Hh%Mm%Ss' | sed 's/00.//g' )" + local human_msg="Type '$go_word' to $human_word ($human_date):" + + # Wait user input or timeout ... + local answer= + local rc=0 + read -t $wait_time -p " ASK: ${human_msg} " answer || rc=$? + local remaining=$(( $wait_time - ( $(date '+%s') - $start ) )) + + # Make a decision + if [[ "$rc" -eq 142 ]]; then + # We timeout, so GO! (142 is the timeout return code) + echo + return $default_rc + elif [[ "$answer" == "$go_word" ]]; then + # User asked to GO! + return 0 + elif [[ $remaining -le 0 ]]; then + # Whatever, time passed, so GO! + return $default_rc + elif [[ "$rc" -ne 0 ]]; then + # Hmm, something wrong, we quit with error... + urm_log ERROR "Something went wrong (return code=$rc)" + return 1 + fi + + # We loop back + idm_cli_timeout $default_rc $remaining +} + + diff --git a/lib/idmgr_lib_std.sh b/lib/idmgr_lib_std.sh index 25db80c..44123ee 100644 --- a/lib/idmgr_lib_std.sh +++ b/lib/idmgr_lib_std.sh @@ -4,97 +4,24 @@ ## Special libraries ############################# -lib_shred () -{ - lib_lob WARN "Will destroy all your secrets! (nor implemented yet)" -} ## Standard libraries ############################# -lib_require_bin () { - local bin=$1 - shift 1 || true - local opts=${@-} - if command -v "$bin" &> /dev/null; then - declare -g ${bin^^}="$bin $opts" - return 0 - else - lib_log ERR "Missing '$bin'" - return 1 - fi -} - - -# Nifty trick to set var from pipes -lib_set_var () { read "$@" <&0; } - -# # Take an environment var name, an a list of vars to inject -# lib_vars_inject () -# { -# local env_name=$1 -# shift 1 -# -# # Check if not already loaded -# if [ "${last_env_name}" == "$env_name" ]; then -# return 0 -# fi -# last_env_name=$env_name -# -# # check if valid environment -# [ "$( type -t idm_vars_${env_name} )" = function ] || return 1 -# -# # Inject var list -# for var in ${@-}; do -# name=${env}_${var} -# $i=${!name} -# done -# } - - -lib_trace () -{ - local msg=${@} - local traces= - - ( - echo "Stack trace:" - for i in {0..10}; do - trace=$(caller $i 2>&1 || true ) - if [ -z "$trace" ] ; then - continue - else - #lib_log DEBUG "Trace $i: $trace" - #traces="${traces}${trace}\n" - echo "$trace" - fi - done | tac | column -t - [ -z "$msg" ] || echo "Trace ctx: $msg" - ) | >&2 lib_log DUMP - -} - -lib_reverse_doted_list () -{ - local list=$1 - awk 'BEGIN{FS=OFS=":"} {s=$NF; for (i=NF-1; i>=1; i--) s = s OFS $i; print s}' <<<"$list" -} lib_parse_filerules () { local id=$1 local f=$2 - #set -x local YADM_ENCRYPT="$2" ENCRYPT_INCLUDE_FILES=() ENCRYPT_EXCLUDE_FILES=() - #cd_work "Parsing encrypt" || return cd ~ - exclude_pattern="^!(.+)" if [ -f "$YADM_ENCRYPT" ] ; then #; parse both included/excluded @@ -105,17 +32,13 @@ lib_parse_filerules () if [[ "$pattern" =~ $exclude_pattern ]]; then for ex_file in ${BASH_REMATCH[1]}; do for f in $( find $ex_file -type f ); do - #if [ -e "$ex_file" ]; then ENCRYPT_EXCLUDE_FILES+=("$f") - #fi done done else for in_file in $pattern; do for f in $( find $in_file -type f ); do - #if [ -e "$in_file" ]; then ENCRYPT_INCLUDE_FILES+=("$f") - #fi done done fi @@ -144,106 +67,6 @@ lib_parse_filerules () -lib_log () -{ - - set +x - [[ "${1-}" =~ ERR|WARN|TIP|NOTICE|INFO|DEBUG|RUN|CODE|DUMP|DEPRECATED|ASK ]] || - { - lib_log ERR "Wrong message level while calling '${1-}'" - return 1 - } - - local level=$1 - shift || true - local msg="$@" - - # Take from stdin if no message ... - [ "$msg" = - ] && msg=$( cat < /dev/stdin ) - [ -z "$msg" ] && { - echo - return 0 - } - - if [ "$( wc -l <<<"$msg" )" -gt 1 ]; then - while read -r line; do - lib_log $level $line - done <<< "$msg" - return - fi - - local color= - local reset='\033[0m' - case $level in - ERR) - color='\033[0;31m' - ;; - WARN|TIP|DEPRECATED) - color='\033[0;33m' - ;; - NOTICE) - color='\033[0;32m' - ;; - INFO) - color='\033[0;37m' - ;; - DEBUG) - color='\033[0;31m' - ;; - RUN) - color='\033[0;34m' - ;; - CODE) - echo "$msg" - return - ;; - DUMP) - color='\033[0;36m' - echo -e "$color$msg$reset" | sed 's/^/ /' - return - ;; - PREFIX) - color='\033[0;34m' - ;; - esac - - if [[ -n "$level" ]]; then - >&2 printf "$color%*.6s$reset: %s\n" 6 "${level}_____" "$msg" # >&2 - else - echo "Error while log output msg: $msg" - fi -} - -# export PS4='+[${SECONDS}s][${BASH_SOURCE}:${LINENO}]: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'; set -x; -# export PS4='.[${SECONDS}s] \[\e[36m\] ${FUNCNAME[0]:+${FUNCNAME[0]}()[${LINENO}]: }\[\e[m\]'; set -x; -# export PS4='. $( f="${FUNCNAME[0]:+${FUNCNAME[0]//}}"; printf "%10s:%00d %00d %10s| " ${BASH_SOURCE#$HOME/} ${LINENO} ${SECONDS} "$f")' ; set -x; -# export PS4='. $(f="${FUNCNAME[0]:+${FUNCNAME[0]//}}"; s=${BASH_SOURCE#$HOME/}; l=${LINENO}; t=${SECONDS}; printf "%00d %0d %16.50s() " $l $t "$f")' ; set -x; -# export PS4=' \[\e[36m\]> $(f="${FUNCNAME[0]:+${FUNCNAME[0]//}}"; s=${BASH_SOURCE#$HOME/}; l=${LINENO}; t=${SECONDS}; printf "%00d %0d %s():" $l $t "$f")\[\e[m\]\n' ; set -x; - #export LOG="lib_log_wrap \$FUNCNAME " - - -#lib_date_diff () -#{ -# -#} - -lib_date_diff_human () -{ - local early_date=$1 - local late_date=${2:-$(date '+%s')} - local diff - - diff=$(( $late_date - $early_date )) - data="$(date -d@$diff -u '+%yy %jd %Hh %Mm %Ss')" - - IFS=, read -r y d h m s <<<"${data// /,}" - y=$(( ${y::-1} - 70 ))y - d=$(( ${d::-1} - 1 ))d - - #echo " $y $d $h $m $s" - echo " $y $d $h $m $s" | sed -E -e 's/ 00*/ /g' -e 's/ [ydhms]//g' | xargs - -} @@ -301,8 +124,10 @@ lib_vars_load () } -## UI lib -############################# + + + + ## Id lib diff --git a/lib/idmgr_lib_utils.sh b/lib/idmgr_lib_utils.sh new file mode 100644 index 0000000..9c80b3f --- /dev/null +++ b/lib/idmgr_lib_utils.sh @@ -0,0 +1,61 @@ + + + + + +lib_date_diff_human () +{ + local early_date=$1 + local late_date=${2:-$(date '+%s')} + local diff + + diff=$(( $late_date - $early_date )) + data="$(date -d@$diff -u '+%yy %jd %Hh %Mm %Ss')" + + IFS=, read -r y d h m s <<<"${data// /,}" + y=$(( ${y::-1} - 70 ))y + d=$(( ${d::-1} - 1 ))d + + echo " $y $d $h $m $s" | sed -E -e 's/ 00*/ /g' -e 's/ [ydhms]//g' | xargs +} + + + +# Nifty trick to set var from pipes +lib_set_var () { read "$@" <&0; } + +lib_reverse_doted_list () +{ + local list=$1 + awk 'BEGIN{FS=OFS=":"} {s=$NF; for (i=NF-1; i>=1; i--) s = s OFS $i; print s}' <<<"$list" +} + + + +# Ensure a binary is available in PATH and declare a global variable +# to call the binary with some prefixed options if any. +# Example: +# lib_require_bin ansible --dry +# Creates : ANSIBLE_BIN var with valude: "ansible --dry" +lib_require_bin () { + local bin=$1 + shift 1 || true + local opts=${@-} + + if command -v "$bin" &> /dev/null; then + local var_name=${bin^^}_BIN + declare -g ${var_name//-/_}="$bin $opts" + return 0 + else + lib_log ERR "Missing '$bin'" + return 1 + fi +} + + +# Securely delete a file or a folder +# lib_shred [DIR/FILE] +lib_shred () +{ + lib_log WARN "Will destroy all your secrets! (nor implemented yet)" +} diff --git a/lib/idmgr_mod_gpg.sh b/lib/idmgr_mod_gpg.sh index 8f14d80..9c6fbf8 100644 --- a/lib/idmgr_mod_gpg.sh +++ b/lib/idmgr_mod_gpg.sh @@ -454,7 +454,7 @@ lib_gpg_decrypt_dir () # Check required bin lib_require_bin tar || idm_exit 1 lib_require_bin gpg2 || idm_exit 1 - export GPG=${GPG2:-$GPG} + export GPG=${GPG2:-$GPG_BIN} tar_opts=" -C ${dst%/*} -zx " if [ ! -z "$key" ]; then @@ -463,7 +463,7 @@ lib_gpg_decrypt_dir () gpg_opts+="-d" fi - $GPG $gpg_opts $src | $TAR $tar_opts || \ + $GPG_BIN $gpg_opts $src | $TAR_BIN $tar_opts || \ idm_exit 1 ERR "Could not decrypt file: $src into $dst" } @@ -479,7 +479,7 @@ lib_gpg_encrypt_dir () # Check required bin lib_require_bin tar || idm_exit 1 lib_require_bin gpg2 || idm_exit 1 - export GPG=${GPG2:-$GPG} + export GPG=${GPG2:-$GPG_BIN} #GPG_KEY="$(yadm config yadm.gpg-recipient || true )" #GPG_KEY="${GPG_DEFAULT_ID-}" @@ -537,8 +537,8 @@ lib_gpg_encrypt_dir () #set -x # Encrypt all the stuffs - $TAR -C "${src%/*}" -cz "${src##*/}" 2>/dev/null | \ - $GPG -a $gpg_opts --yes -o $dst || \ + $TAR_BIN -C "${src%/*}" -cz "${src##*/}" 2>/dev/null | \ + $GPG_BIN -a $gpg_opts --yes -o $dst || \ idm_exit 1 ERR "Could not encrypt directory: $src" #set +x @@ -546,7 +546,7 @@ lib_gpg_encrypt_dir () # File descritor tests ... #exec 3<> /tmp/foo #>&3 echo "$pass" - #{ echo "$pass\n" >&3 ; $TAR -C "$(dirname $src)" -cz "$src" 2>/dev/null; } | \ + #{ echo "$pass\n" >&3 ; $TAR_BIN -C "$(dirname $src)" -cz "$src" 2>/dev/null; } | \ #exec 3>&- #close fd 3. } diff --git a/lib/idmgr_mod_id.sh b/lib/idmgr_mod_id.sh index fc42bea..bad5b85 100644 --- a/lib/idmgr_mod_id.sh +++ b/lib/idmgr_mod_id.sh @@ -39,9 +39,9 @@ idm_id__enable () [ -f "$conf" ] && source "$conf" - echo "export SHELL_ID=${id}" - echo "export GIT_AUTHOR_NAME=${common_name:-$id}" - echo "export GIT_AUTHOR_EMAIL=${email}" + echo "export SHELL_ID='${id}'" + echo "export GIT_AUTHOR_NAME='${common_name:-$id}'" + echo "export GIT_AUTHOR_EMAIL='${email}'" # echo "export PATH=${XDG_OPT_HOME}/bin:$PATH" # echo "export SSH_CONFIG=${id}" @@ -183,14 +183,18 @@ idm_id__dump () idm_id_template () { local cn=${1-} + local hostname=${2-} local tz lang # Auto guess tz=$( timedatectl | grep "Time zone" | awk '{print $3}' || true ) echo "common_name=${cn}" + echo "login=${cn}" echo "email=" echo "tz=$tz" + echo "public=false" + echo "hostname=${hostname:-$(hostname -f)}" } idm_id__rm () diff --git a/lib/idmgr_mod_ssh.sh b/lib/idmgr_mod_ssh.sh index e2fbcd7..c6f81b5 100644 --- a/lib/idmgr_mod_ssh.sh +++ b/lib/idmgr_mod_ssh.sh @@ -10,8 +10,8 @@ idm_ssh__help () { echo "Secure Shell" -# printf " %-20s: %s\n" "info" "Info submenu" printf " %-20s: %s\n" "ssh ls" "List unlocked keys" + printf " %-20s: %s\n" "ssh pub" "Show public keys" printf " %-20s: %s\n" "ssh tree" "Show keypairs tree" printf " %-20s: %s\n" "ssh new [dir]" "Create new ssh key dest dir" printf " %-20s: %s\n" "ssh add" "Unlock known keypairs" @@ -21,6 +21,21 @@ idm_ssh__help () printf " %-20s: %s\n" "ssh enable" "Enable agent" printf " %-20s: %s\n" "ssh disable" "Disable agent" printf " %-20s: %s\n" "ssh kill" "Kill agent" + + cat </dev/null | sed 's/^/ /' } @@ -144,6 +158,17 @@ idm_ssh__tree () fi } +idm_ssh__pub () +{ + local id=$1 + local path="$HOME/.ssh" + if lib_id_has_config $id &>/dev/null; then + path="$HOME/.ssh/$id" + fi + + head -n 3 "$path"/*.pub +} + idm_ssh__new () { local id=${1-} @@ -161,9 +186,9 @@ idm_ssh__new () # Guess defaults default=$(id -un) if lib_id_has_config $id &>/dev/null; then - default=$id + default=${login:-$id} if [ -z "$dest" ]; then - dest="$HOME/.ssh/$default" + dest="$HOME/.ssh/$id" fi else dest=${dest:-.} @@ -179,7 +204,7 @@ idm_ssh__new () # Host name - default="$(hostname -f)" + default="${hostname:-$(hostname -f)}" while ! grep -q '[a-zA-Z0-9.-]\+' <<< "$key_host"; do read -rp "> Hostname [$default]: " ans #echo "" @@ -349,7 +374,6 @@ idm_ssh__add () #lib_id_is_enabled $id lib_id_is_enabled $id - if [[ ! -z "$key" ]]; then pub_keys=$( { @@ -358,10 +382,12 @@ idm_ssh__add () # New mode (test) find ~/.ssh/$id -maxdepth $maxdepth -name "${id}_*" -name '*pub' -name "*$1*" | sort + #find ~/.ssh/$id -maxdepth $maxdepth -name '*pub' | sort } | sort | uniq ) else - pub_keys=$(find ~/.ssh/$id -maxdepth $maxdepth -name "${id}_*" -name '*pub' | sort) + #pub_keys=$(find ~/.ssh/$id -maxdepth $maxdepth -name "${id}_*" -name '*pub' | sort) + pub_keys=$(find ~/.ssh/$id -maxdepth $maxdepth -name '*pub' | sort) fi #echo "$pub_keys"