684 lines
14 KiB
Bash
Executable File
684 lines
14 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
|
|
## Initialisation
|
|
##########################################
|
|
|
|
# Get the way the script is called
|
|
IDM_PATH=${_:-_none}
|
|
IDM_ARGS=${0-}
|
|
|
|
# Ensure we are running strict mode
|
|
set -euo pipefail
|
|
|
|
# Detect how this script was started
|
|
if [[ $IDM_PATH == $IDM_ARGS ]]; then
|
|
IDM_CTX=executed
|
|
else
|
|
IDM_CTX=sourced
|
|
IDM_SOURCED_ARGS=${@:-_none}
|
|
fi
|
|
|
|
# Versionning infos
|
|
IDM_AUTHORS='mrjk'
|
|
IDM_VERSION='0.1 (beta)'
|
|
IDM_DATE='03/01/18'
|
|
IDM_LICENSE='MIT'
|
|
IDM_SCRIPT_NAME=idmgr
|
|
|
|
# Global app variables
|
|
IDM_BIN=${IDM_BIN:-$0}
|
|
IDM_DIR_ROOT=${IDM_DIR_ROOT:-$( realpath "$(dirname $0)/../" )}
|
|
|
|
IDM_CONFIG_DIR=${IDM_CONFIG_DIR:-${XDG_CONFIG_HOME:-~/.config}/idmgr}
|
|
IDM_DIR_ID=${IDM_DIR_ID:-$IDM_CONFIG_DIR/id}
|
|
IDM_DIR_LIB=${IDM_DIR_LIB:-$IDM_DIR_ROOT/lib}
|
|
IDM_DIR_CACHE=${IDM_DIR_CACHE:-${XDG_CACHE_HOME:-~/.cache}/idmgr}
|
|
|
|
|
|
# Main initialisation settings
|
|
idm_init ()
|
|
{
|
|
export EDITOR=${EDITOR:-vim}
|
|
|
|
# Create directories
|
|
mkdir -p $IDM_CONFIG_DIR $IDM_DIR_ID
|
|
|
|
IDM_MOD_FILES=$(idm_mod_files)
|
|
IDM_MOD_ORDER=$(idm_mod_list)
|
|
export IDM_TIMEOUT_USER=5
|
|
|
|
# Load modules
|
|
for i in $IDM_MOD_FILES ; do
|
|
source $i
|
|
done
|
|
}
|
|
|
|
|
|
## Required functions
|
|
##########################################
|
|
|
|
|
|
idm_core__help ()
|
|
{
|
|
echo ""
|
|
echo " idmgr - Identity Manager for your shell"
|
|
echo ""
|
|
echo "Introduction:"
|
|
echo " Identity Manager can manage your ssh keys, your pass,"
|
|
echo " your pgp keys, kerberos and many other related identity item."
|
|
echo ""
|
|
echo "Sourced commands:"
|
|
printf " %-20s: %s\n" "enable <id>" "Enable (and start) id"
|
|
printf " %-20s: %s\n" "disable id" "Disable id"
|
|
printf " %-20s: %s\n" "kill id" "Kill id and its associated processes"
|
|
printf " %-20s: %s\n" "shell " "Show bash code"
|
|
printf " %-20s: %s\n" "comp " "Show completion code"
|
|
echo
|
|
echo "Other commands:"
|
|
printf " %-20s: %s\n" "id " "List all id"
|
|
printf " %-20s: %s\n" "shred [id|user|dev|ask]" "Safely schred data (definitive)"
|
|
printf " %-20s: %s\n" "fun " "Show internal function (debug)"
|
|
printf " %-20s: %s\n" "hier " "Show cli function (debug)"
|
|
|
|
idm_core_exec_mod $id __help "\n%s" ${IDM_MOD_ORDER//:/ }
|
|
|
|
echo
|
|
lib_log NOTICE "License:"
|
|
echo " $IDM_VERSION, $IDM_DATE"
|
|
echo " $IDM_LICENSE, $IDM_AUTHORS"
|
|
|
|
}
|
|
|
|
idm_core__ls ()
|
|
{
|
|
local id=${1}
|
|
#set -x
|
|
|
|
idm_core_exec_mod $id __ls "\n%s ls" ${IDM_MOD_ORDER//:/ }
|
|
|
|
}
|
|
|
|
|
|
idm_core__enable ()
|
|
{
|
|
local id=${1:-${SHELL_ID-}}
|
|
local conf
|
|
|
|
#set -x
|
|
|
|
# Local checks
|
|
idm_validate id $id || idm_exit 1 ERR "You must provide an id"
|
|
idm_validate id_config $id || idm_exit 1 ERR "Configuration '$id' does not exists"
|
|
|
|
# Check if workspace is enabled
|
|
#idm_validate is_enabled $id
|
|
if [ "${SHELL_ID-}" == "$id" ]; then
|
|
#idm_exit 0 INFO "Your workspace is already activated"
|
|
lib_log WARN "Your workspace is already activated"
|
|
elif [ -n "${SHELL_ID-}" ]; then
|
|
idm_exit 0 WARN "Your workspace is already activated with $SHELL_ID"
|
|
fi
|
|
|
|
# Retrieve environment config
|
|
conf="$IDM_DIR_ID/$id.env"
|
|
|
|
# Notice user
|
|
{
|
|
. $conf
|
|
idm_core_exec_mod $id __enable "Enabling %s ..." ${IDM_MOD_ORDER//:/ }
|
|
} # | lib_log DUMP -
|
|
|
|
lib_log NOTICE "Identity '$id' is loaded"
|
|
|
|
}
|
|
|
|
idm_core__disable ()
|
|
{
|
|
local id=${1}
|
|
#idm_is_enabled $id
|
|
idm_validate is_enabled $id
|
|
|
|
# Reverse module unloading
|
|
IDM_MOD_ORDER="$( lib_reverse_doted_list $IDM_MOD_ORDER )"
|
|
idm_core_exec_mod $id __disable "Disabling %s ..." ${IDM_MOD_ORDER//:/ }
|
|
|
|
# Inform user
|
|
lib_log NOTICE "Id $id is disabled"
|
|
}
|
|
|
|
idm_core__kill ()
|
|
{
|
|
local id=${1}
|
|
idm_is_enabled $id
|
|
|
|
# Reverse module killing
|
|
IDM_MOD_ORDER="$( lib_reverse_doted_list $IDM_MOD_ORDER )"
|
|
idm_core_exec_mod $id __disable "Killing %s ..." ${IDM_MOD_ORDER//:/ }
|
|
|
|
# Inform user
|
|
lib_log NOTICE "Id $id is safely killed"
|
|
|
|
}
|
|
|
|
|
|
idm_core__shell ()
|
|
{
|
|
IDM_SRC_WORDS=$( $IDM_DIR_ROOT/bin/idmgr sourced_words )
|
|
|
|
echo "export IDM_BIN=${IDM_BIN:-$IDM_DIR_ROOT/bin/idmgr}"
|
|
echo "export IDM_DIR_ROOT='$IDM_DIR_ROOT'"
|
|
echo "IDM_SRC_WORDS='$IDM_SRC_WORDS'"
|
|
|
|
tail -n +2 $IDM_DIR_ROOT/shell/bash.sh
|
|
}
|
|
|
|
idm_core__comp ()
|
|
{
|
|
cat $IDM_DIR_ROOT/comp/pass.sh
|
|
cat $IDM_DIR_ROOT/comp/yadm.sh
|
|
cat $IDM_DIR_ROOT/comp/ssh.sh
|
|
cat $IDM_DIR_ROOT/comp/gpg.sh
|
|
cat $IDM_DIR_ROOT/comp/idmgr.sh
|
|
}
|
|
|
|
|
|
## Extended functions
|
|
##########################################
|
|
|
|
|
|
idm_core__fun ()
|
|
{
|
|
grep --colour=auto -IRE \
|
|
'^[a-z0-9_]* \(\)' $IDM_DIR_ROOT/{bin,lib} \
|
|
| sed "s@$IDM_DIR_ROOT/@@" \
|
|
| awk -F: '{ print $2 ":" $1 }' \
|
|
| column -t -s : \
|
|
| LC_ALL=C sort # | lib_log DUMP -
|
|
|
|
}
|
|
|
|
idm_core__hier ()
|
|
{
|
|
idm_core__fun \
|
|
| grep __ \
|
|
| sed -e 's/__/ /' -e 's/()//'
|
|
}
|
|
|
|
idm_core__sourced_words()
|
|
{
|
|
local id=${1-}
|
|
local words=
|
|
|
|
# When we are asking to output source words
|
|
words="enable disable kill shell quit q $(idm_get all_id | xargs)"
|
|
|
|
echo ":${words// /:}:"
|
|
|
|
}
|
|
|
|
|
|
## Core internal libs
|
|
##########################################
|
|
|
|
idm_core_exec_mod ()
|
|
{
|
|
local id=$1
|
|
local action=$2
|
|
local sep=$3
|
|
shift 3
|
|
local mods=${@-}
|
|
|
|
for i in $mods ; do
|
|
local val="idm_${i}${action}"
|
|
|
|
if [ "$( type -t $val )" = function ]; then
|
|
#lib_log INFO "Loading module $i ..."
|
|
[ "$sep" == "_" ] || lib_log NOTICE "$(printf "$sep" $i )"
|
|
${val} $id || \
|
|
{
|
|
# DO NOT DISABLE THIS BLOCK, that force plugin to load in anyway
|
|
true
|
|
lib_log WARN "Module $i failed in some way ... ($action)"
|
|
}
|
|
else
|
|
echo ""
|
|
lib_log INFO "Skip module $i"
|
|
fi
|
|
done
|
|
}
|
|
|
|
idm_mod_files ()
|
|
{
|
|
#p=$IDM_DIR_ROOT/lib ${PATH//:/ }
|
|
p=$IDM_DIR_LIB
|
|
find $p -name 'idmgr_mod_*.sh' | xargs
|
|
}
|
|
|
|
idm_core_mods()
|
|
{
|
|
local id=${1-}
|
|
idm_mod_list
|
|
}
|
|
|
|
|
|
idm_core_load_lib ()
|
|
{
|
|
local lib_name=${1}
|
|
local lib_args=${@-}
|
|
local env_var=IDM_LIB_${lib_name^^}
|
|
|
|
#lib_log DEBUG "$env_var=${!env_var}"
|
|
[ -z "${!env_var-}" ] || return 0
|
|
|
|
cmd="$(command -v $lib_name || true )"
|
|
|
|
if [ -x "${cmd:-_}" ]; then
|
|
|
|
. "$cmd" $lib_args
|
|
declare -g $env_var=$cmd
|
|
lib_log INFO "Loaded lib: $env_var=${!env_var}"
|
|
#set -x
|
|
|
|
else
|
|
idm_exit 1 "Could not find 'safe' executable in \$PATH (missing module dependency)"
|
|
fi
|
|
}
|
|
|
|
idm_mod_list ()
|
|
{
|
|
local mods=
|
|
|
|
if [ -z "${@-}" ] ; then
|
|
mods=$( idm_mod_order $(idm_mod_files) )
|
|
else
|
|
mods=$( idm_mod_order ${@} )
|
|
fi
|
|
|
|
echo ":${mods// /:}:"
|
|
}
|
|
|
|
|
|
# Takes a list of files to scan for deps
|
|
idm_mod_order ()
|
|
{
|
|
export IDM_MOD_FILES="$( xargs <<<$@ )"
|
|
|
|
# Generate dependency order
|
|
#result=$(
|
|
for f in $IDM_MOD_FILES; do
|
|
mod_name=${f##*mod_}
|
|
mod_name=${mod_name%\.sh}
|
|
|
|
# A bit hackish ...
|
|
IDM_MOD_DEPS=$( grep '^IDM_MOD_DEPS=' $f )
|
|
IDM_MOD_DEPS=${IDM_MOD_DEPS##*=}
|
|
IDM_MOD_DEPS=${IDM_MOD_DEPS//[^a-z0-9 ]}
|
|
IDM_MOD_DEPS="$( tr ' ' '\n' <<<${IDM_MOD_DEPS} )"
|
|
|
|
# Output
|
|
echo -e "$( xargs -n1 -I{} echo {} "$mod_name" <<<"$IDM_MOD_DEPS" )"
|
|
done | tsort | grep -v 'core' | xargs
|
|
#)
|
|
|
|
#lib_log DEBUG "Dependencies order: $result"
|
|
#echo $result
|
|
}
|
|
|
|
|
|
## Internal/Debug
|
|
|
|
idm_exit ()
|
|
{
|
|
set +x
|
|
local rc=${1:-0}
|
|
local msg lvl
|
|
#[ -p /dev/stdin ] \
|
|
# && dump="$(</dev/stdin)" \
|
|
# || dump=""
|
|
|
|
# Check exit status
|
|
if [ "$#" -eq 3 ]; then
|
|
lvl=${2:-DEBUG}
|
|
msg=${3:-}
|
|
else
|
|
lvl=DEBUG
|
|
msg=${2:-}
|
|
fi
|
|
|
|
if [[ "$rc" -ne 0 ]]; then
|
|
#lib_trace || true
|
|
lib_log $lvl "$msg (rc=$rc)"
|
|
#[ -z "$dump" ] || \
|
|
# lib_log DUMP "$dump"
|
|
else
|
|
lib_log $lvl "$msg"
|
|
fi
|
|
|
|
# Remove trap
|
|
trap "" INT TERM EXIT
|
|
|
|
# Exit for good
|
|
exit $rc
|
|
}
|
|
|
|
|
|
idm_exit_trap () {
|
|
set +x
|
|
rc=$?
|
|
if [[ $rc -ne 0 ]]; then
|
|
lib_log ERR "The script exited with exit code: $rc"
|
|
lib_trace || true
|
|
#else
|
|
# lib_log WARN "The script exit has been trapped !"
|
|
# lib_trace || true
|
|
fi
|
|
exit $rc
|
|
}
|
|
|
|
|
|
## Data, tests
|
|
|
|
# Should be replaced by idm_validate ?
|
|
# Is a wrapper for enduser !!!
|
|
idm_is_enabled ()
|
|
{
|
|
local id=${1}
|
|
idm_validate is_enabled $id
|
|
{
|
|
lib_log WARN "You need to activate an id first"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
idm_get ()
|
|
{
|
|
local item=$1
|
|
local value=${2-}
|
|
|
|
case $item in
|
|
all_id)
|
|
for id in $( find $IDM_DIR_ID -type f -name '*.env' 2>/dev/null ); do
|
|
id=${id%%\.env}
|
|
echo "${id##*/}"
|
|
done
|
|
;;
|
|
|
|
all_id_files)
|
|
ls $IDM_DIR_ID/*.env || true
|
|
;;
|
|
|
|
id_config)
|
|
if [ -f "$IDM_DIR_ID/$value.env" ]; then
|
|
echo "id=$value"
|
|
cat $IDM_DIR_ID/$value.env
|
|
else
|
|
return 1
|
|
fi
|
|
;;
|
|
|
|
*)
|
|
lib_log ERR "Cannot get item '$item'"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
idm_validate ()
|
|
{
|
|
local type=$1
|
|
local value=${2-}
|
|
|
|
case $type in
|
|
id_filter|id)
|
|
[ "$value" != '_' ] && \
|
|
[[ "$value" =~ ^[a-zA-Z0-9_-]+$ ]] && return $?
|
|
;;
|
|
id_config)
|
|
if [[ -f "$IDM_DIR_ID/$value.env" ]]; then
|
|
return 0
|
|
fi
|
|
;;
|
|
is_enabled)
|
|
if [[ -z "${value-}" && "${value-}" != '_' ]]; then
|
|
if [ -z "${SHELL_ID-}" ] ; then
|
|
return 1
|
|
else
|
|
return 0
|
|
fi
|
|
else
|
|
if [ "${value-}" == "${SHELL_ID-}" ]; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
fi
|
|
;;
|
|
is_disabled)
|
|
[ -z "${SHELL_ID-}" ] && return $?
|
|
;;
|
|
|
|
*)
|
|
lib_log ERR "Cannot validate type '$type'"
|
|
;;
|
|
esac
|
|
|
|
return 1
|
|
}
|
|
|
|
|
|
## User interface
|
|
##########################################
|
|
|
|
# This function display a user skippable timeout.
|
|
idm_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
|
|
}
|
|
|
|
|
|
## Entry points
|
|
##########################################
|
|
|
|
idm_menu_main ()
|
|
{
|
|
#set -x
|
|
|
|
local menu=
|
|
local action=
|
|
local id=
|
|
local opt=
|
|
local shell_id=${SHELL_ID:-_}
|
|
|
|
# Load external libs
|
|
#for lib in $( find $IDM_DIR_LIB -name 'idm_lib_*.sh'); do
|
|
while read -r lib; do
|
|
#. $lib || lib_log WARN "Error while loading lib $lib :/"
|
|
. ${lib:-/dev/null} || echo " WARN: Error while loading lib: ${lib:-NONE}"
|
|
done <<< "$( find $IDM_DIR_LIB -name 'idm_lib_*.sh')"
|
|
|
|
|
|
trap "idm_exit_trap" INT TERM EXIT
|
|
|
|
idm_init
|
|
#set -x
|
|
|
|
# Three way parsing
|
|
if [ "$#" -eq 0 ]; then
|
|
|
|
if [ -z "${SHELL_ID-}" ]; then
|
|
# Not activated, show all ids
|
|
menu=id
|
|
action=ls
|
|
id=_
|
|
else
|
|
# Activated, show all id settings
|
|
menu=core
|
|
action=ls
|
|
id=$shell_id
|
|
fi
|
|
|
|
else
|
|
|
|
# Check id constraint
|
|
if idm_validate id_config $1 ; then
|
|
menu=core
|
|
action=enable
|
|
id=$1
|
|
elif idm_validate id_config ${2-} ; then
|
|
menu=core
|
|
action=$1
|
|
id=$2
|
|
shift 2 && opt=${@} || true
|
|
elif idm_validate id_config ${3-} ; then
|
|
menu=$1
|
|
action=$2
|
|
id=$3
|
|
shift 3 && opt=${@} || true
|
|
|
|
# Check mod contraint
|
|
elif [[ "${IDM_MOD_ORDER}" =~ :$1: ]]; then
|
|
menu=$1
|
|
action=${2:-ls}
|
|
id=$shell_id
|
|
shift 2 && opt=${@} || true
|
|
|
|
# Free form
|
|
else
|
|
if [ "$#" -eq 1 ]; then
|
|
menu=core
|
|
action=${1}
|
|
id=$shell_id
|
|
# elif [ "$#" -eq 2 ]; then
|
|
# menu=${1}
|
|
# action=${2}
|
|
# id=$shell_id
|
|
# shift 2 && opt=${@} || true
|
|
else
|
|
menu=${1}
|
|
action=${2}
|
|
id=$shell_id
|
|
shift 2 && opt=${@} || true
|
|
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Aliases
|
|
case $action in
|
|
quit|q)
|
|
action=disable
|
|
;;
|
|
esac
|
|
|
|
# Dispatch
|
|
#lib_log DEBUG "menu=$menu action=${action:-_} id=$id opt=$opt"
|
|
#set -x
|
|
if [ "$( type -t idm_${menu}__${action:-_} )" = function ]; then
|
|
idm_${menu}__${action:-_} $id $opt
|
|
return $?
|
|
elif [ "$( type -t idm_${menu}_${action:-_} )" = function ]; then
|
|
lib_log WARN "Debug mode enabled"
|
|
idm_${menu}_${action:-_} $id $opt
|
|
return $?
|
|
elif [ "$( type -t idm_${menu} )" = function ]; then
|
|
idm_${menu} ${action:-_} $id $opt
|
|
return $?
|
|
fi
|
|
|
|
idm_exit 1 "Command not matched: menu=$menu action=$action id=$id opt=$opt"
|
|
}
|
|
|
|
|
|
## Main
|
|
##########################################
|
|
|
|
idm_menu_main $@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# OLD PIEECES OF CODE
|
|
|
|
|
|
# echo "export MANPAGER=less"
|
|
# #echo "export VIMINIT=let \$MYVIMRC='$XDG_CONFIG_HOME/vim/vimrc' \| source \$MYVIMRC"
|
|
# #echo "export VIMINIT='let \$MYVIMRC="$XDG_CONFIG_HOME/vim/vimrc"'"
|
|
|
|
# # Misc
|
|
# echo "export PYENV_ROOT=${XDG_OPT_HOME}/pyenv"
|
|
# echo "export PYTHONUSERBASE=${XDG_OPT_HOME}/python"
|
|
# echo "export PYTHONZ_ROOT=${XDG_OPT_HOME}/pythonz"
|
|
# echo "export PIPSI_BIN_DIR=${XDG_OPT_HOME}/python-venv/bin"
|
|
|
|
# echo "export LUA_CPATH=${XDG_OPT_HOME}/lua/?.so"
|
|
# echo "export LUA_PATH=${XDG_OPT_HOME}/lua/?.lua"
|
|
# echo "export LUAROCKS_CONFIG=~/.config/lua-${id}/luarocks.lua"
|
|
|
|
# echo "export GEM_HOME=${XDG_OPT_HOME}/ruby"
|
|
# echo "export GEMRC=~/.config/ruby-${id}/gemrc"
|
|
# echo "export GEM_SPEC_CACHE=${XDG_OPT_HOME}/ruby/gem/specs"
|
|
|
|
# echo "export COMPOSER_CACHE_DIR=${XDG_OPT_HOME}/composer"
|
|
# echo "export COMPOSER_HOME=${XDG_OPT_HOME}/composer"
|
|
|
|
# echo "export NPM_CONFIG_USERCONFIG=~/.config/npmrc"
|
|
# echo "export VAGRANT_HOME=${XDG_OPT_HOME}/vagrant"
|
|
# echo "export GOPATH=${XDG_OPT_HOME}/go"
|
|
|
|
|