From 49395673834df09b7871364c5adb210bbb7cd80e Mon Sep 17 00:00:00 2001 From: mrjk Date: Sat, 10 Feb 2018 22:06:33 -0500 Subject: [PATCH] Add: Initial code --- README.md | 0 bin/idmgr | 617 ++++++++++++++++++++++++++++++++++++++++++ lib/idmgr_mod_gpg.sh | 115 ++++++++ lib/idmgr_mod_id.sh | 206 ++++++++++++++ lib/idmgr_mod_pass.sh | 68 +++++ lib/idmgr_mod_ps1.sh | 63 +++++ lib/idmgr_mod_ssh.sh | 201 ++++++++++++++ shell/bash.sh | 169 ++++++++++++ 8 files changed, 1439 insertions(+) create mode 100644 README.md create mode 100755 bin/idmgr create mode 100644 lib/idmgr_mod_gpg.sh create mode 100644 lib/idmgr_mod_id.sh create mode 100644 lib/idmgr_mod_pass.sh create mode 100644 lib/idmgr_mod_ps1.sh create mode 100644 lib/idmgr_mod_ssh.sh create mode 100644 shell/bash.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/bin/idmgr b/bin/idmgr new file mode 100755 index 0000000..efbbd2a --- /dev/null +++ b/bin/idmgr @@ -0,0 +1,617 @@ +#!/bin/bash + + +## Documentation +########################################## +# This script handles many identity + + + +## 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 + + + +IDM_DIR_ROOT=${IDM_DIR_ROOT:-$( realpath "$(dirname $0)/../" )} + + +# Main initialisation settings +idm_init () +{ + export EDITOR=${EDITOR:-vim} + + # App variables + 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} + + # Create directories + mkdir -p $IDM_CONFIG_DIR $IDM_DIR_ID + + IDM_MOD_FILES=$(idm_mod_files) + IDM_MOD_ORDER=$(idm_mod_list) + + # Load modules + for i in $IDM_MOD_FILES ; do + source $i + done +} + + +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 "Core commands:" + printf " %-20s: %s\n" "enable " "Enable (and start) id" + printf " %-20s: %s\n" "disable " "Disable id" + printf " %-20s: %s\n" "kill " "Kill id and its associated processes" + echo + + for i in ${IDM_MOD_ORDER//:/ } ; do + local val="idm_${i}_help" + echo -n "$i: " + ${val} 2>/dev/null || \ + { + true + echo "No help" + } + echo "" + done + + echo "License:" + echo " $IDM_VERSION, $IDM_DATE" + echo " $IDM_LICENSE, $IDM_AUTHORS" + +} + + + +## Utils +########################################## + + +idm_log () +{ + local level=$1 + shift || true + local msg="$@" + + # Take from stdin if no message ... + [[ "$msg" = - ]] && msg=$( cat < /dev/stdin ) + + local color= + local reset='\033[0m' + case $level in + ERR) + color='\033[0;31m' + ;; + WARN|TIP) + 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 + printf "$color%6s$reset: %s\n" "$level" "$msg" >&2 + else + echo "Error while log output msg: $message" + fi +} + +idm_get () +{ + local item=$1 + local value=${2-} + + case $item in + all_id) + for id in $IDM_DIR_ID/*.env; do + id=${id%%\.env} + echo "${id##*/}" + done + ;; + + all_id_files) + ls $IDM_DIR_ID/*.env + ;; + + id_config) + echo "id=$value" + cat $IDM_DIR_ID/$value.env + ;; + + *) + idm_log ERR "Cannot get item '$item'" + ;; + esac +} + +idm_validate () +{ + local type=$1 + local value=${2-} + + case $type in + id) + [ "$value" != '_' ] && \ + [[ "$value" =~ ^[a-zA-Z0-9_-]+$ ]] && return + ;; + id_config) + [[ -f "$IDM_DIR_ID/$value.env" ]] && return + ;; + is_enabled) + [ ! -z "${SHELL_ID}" ] && return + ;; + is_disabled) + [ -z "${SHELL_ID}" ] && return + ;; + + *) + idm_log ERR "Cannot validate type '$type'" + ;; + esac + + return 1 +} + +# Should be replaced by idm_validate ? +idm_is_enabled () +{ + local id=${1} + idm_validate id $id || \ + idm_exit 1 ERR "You need to activate an id first" + +} + + + +idm_exit () +{ + local rc=${1:-0} + local msg lvl + + # Check exit status + if [ "$#" -eq 3 ]; then + lvl=${2:-DEBUG} + msg=${3:-} + else + lvl=DEBUG + msg=${2:-} + fi + + if [[ "$rc" -ne 0 ]]; then + idm_log $lvl "$msg (rc=$rc)" + else + idm_log $lvl "$msg" + fi + + # Remove trap + trap "" INT TERM EXIT + + # Exit for good + exit $rc +} + +idm_exit_trap () +{ + idm_log DEBUG "Exit trap" +} + +idem_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" +} + + +## IDM Internal +########################################## + + +# 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 | xargs + #) + + #idm_log DEBUG "Dependencies order: $result" + #echo $result + +} + +idm_mod_files () +{ + #p=$IDM_DIR_ROOT/lib ${PATH//:/ } + p=$IDM_DIR_LIB + find $p -name 'idmgr_mod_*.sh' | xargs +} + +idm_mod_list () +{ + local mods= + + if [ -z "${@-}" ] ; then + mods=$( idm_mod__order $(idm_mod_files) ) + else + mods=$( idm_mod__order ${@} ) + fi + + echo ":${mods// /:}:" +} + + +## Required functions +########################################## +idm_core_ls () +{ + local id=${1} + + for i in ${IDM_MOD_ORDER//:/ } ; do + local val="idm_${i}_ls" + idm_log NOTICE "List $i" + + ${val} $id 2>/dev/null || \ + { + true + idm_log INFO "No listing function for $i" + } + echo "" + done +} + + +idm_core_enable () +{ + local id=${1:-${SHELL_ID-}} + local conf + + # 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 + if [ "${SHELL_ID-}" == "$id" ]; then + idm_exit 0 INFO "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 + + for i in ${IDM_MOD_ORDER//:/ } ; do + local val="idm_${i}_enable" + #idm_log INFO "Loading $i ..." + + ${val} $id 2>/dev/null || \ + { + true + idm_log INFO "No enable function for $i" + } + echo "" + done + + ) | idm_log CODE - + + idm_log NOTICE "Identity '$id' is loaded" + +} + +idm_core_disable () +{ + local id=${1} + idm_is_enabled $id + + # Reverse module unloading + IDM_MOD_ORDER="$( idem_reverse_doted_list $IDM_MOD_ORDER )" + + # Loop over disable functions + ( + for i in ${IDM_MOD_ORDER//:/ } ; do + local val="idm_${i}_disable" + #idm_log INFO "Disable $i ..." + + ${val} $id 2>/dev/null || \ + { + true + idm_log INFO "No disable function for $i" + } + echo "" + done + ) | idm_log CODE - + + # Inform user + idm_log NOTICE "Id $id is disabled" +} + +idm_core_kill () +{ + local id=${1} + idm_is_enabled $id + + # Reverse module killing + IDM_MOD_ORDER="$( idem_reverse_doted_list $IDM_MOD_ORDER )" + + # Kill all modules + ( + for i in ${IDM_MOD_ORDER//:/ } ; do + local val="idm_${i}_kill" + #idm_log INFO "Disable $i ..." + + ${val} $id 2>/dev/null || \ + { + true + idm_log INFO "No kill function for $i" + } + echo "" + done + ) | idm_log CODE - + + # Inform user + idm_log NOTICE "Id $id is safely killed" + +} + + +## Extended functions +########################################## + +idm_core_mods() +{ + local id=${1-} + idm_mod_list +} + +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// /:}:" + +} + +idm_core_shell () +{ + IDM_SRC_WORDS=$( $IDM_DIR_ROOT/bin/idmgr sourced_words ) + + echo "IDM_DIR_ROOT='$IDM_DIR_ROOT'" + echo "IDM_SRC_WORDS='$IDM_SRC_WORDS'" + echo "IDM_BIN=${IDM_BIN:-$IDM_DIR_ROOT/bin/idmgr}" + + tail -n +2 $IDM_DIR_ROOT/shell/bash.sh +} + +idm_core_completion () +{ + 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 +} + + +## Entry points +########################################## + + +idm_exit_trap() { + rc=$? + [[ $rc -ne 0 ]] && idm_log ERR "The script exited with exit code: $rc" + exit $rc +} + +trap "idm_exit_trap" INT TERM EXIT + + +idm_menu_main () +{ + #set -x + + local menu= + local action= + local id= + local opt= + local shell_id=${SHELL_ID-:_} + + idm_init + + # 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=ls + 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 + #idm_log DEBUG "menu=$menu action=$action id=$id opt=$opt" + if [ "$( type -t idm_${menu}_${action} )" = function ]; then + idm_${menu}_${action} $id $opt + return $? + elif [ "$( type -t idm_${menu} )" = function ]; then + idm_${menu} ${action} $id $opt + return $? + fi + + idm_log DEBUG "menu=$menu action=$action id=$id opt=$opt" + idm_exit 1 "Command not matched" + + +} + + + +## 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" diff --git a/lib/idmgr_mod_gpg.sh b/lib/idmgr_mod_gpg.sh new file mode 100644 index 0000000..359a454 --- /dev/null +++ b/lib/idmgr_mod_gpg.sh @@ -0,0 +1,115 @@ +#!/bin/bash + +IDM_MOD_DEPS="id" + + +idm_gpg_help () +{ + echo "Not implemented yet" +} + +## Required functions +########################################## + +idm_gpg_enable () +{ + local id=${1} + idm_is_enabled $id + + # Source environment + if [ -f "${XDG_RUNTIME_DIR}/pgp-agent/${id}/env" ]; then + . "${XDG_RUNTIME_DIR}/pgp-agent/${id}/env" + else + unset GPG_AGENT_INFO + fi + + # Check if socket is present + if [ ! -S "${GPG_AGENT_INFO-}" ]; then + rm -f "${XDG_RUNTIME_DIR}/pgp-agent/${id}/env" + idm_gpg__start $id + fi + + # Show config to source + if [ -f "${XDG_RUNTIME_DIR}/pgp-agent/${id}/env" ]; then + cat "${XDG_RUNTIME_DIR}/pgp-agent/${id}/env" + fi + + # Export tty to the current shell + echo "export GPG_TTY=$(tty)" +} + + +idm_gpg_disable () +{ + local id=${1} + idm_is_enabled $id + echo "unset GPG_AGENT_INFO GNUPGHOME GPG_TTY" +} + +idm_gpg_kill () +{ + local id=${1} + idm_is_enabled $id + + gpgconf --kill gpg-agent + idm_log NOTICE "Kill gpg-agent ..." + + idm_gpg_disable $id + + #killall gpg-agent || true + #echo "echo 'GPG kill is not implemented yet ...'" +} + + +idm_gpg_ls () +{ + local id=${1} + idm_is_enabled $id + + gpg --list-keys | idm_log DUMP - +} + +## Internal functions +########################################## + +idm_gpg__start () +{ + local id=${1} + local gpghome=~/.config/gpg/$id + local runtime=${XDG_RUNTIME_DIR}/pgp-agent/$id + + export GPG_TTY=$(tty) + export GNUPGHOME=$gpghome + + # Ensure directories exist + if [ ! -d "$GNUPGHOME" ]; then + mkdir -p "$GNUPGHOME" + chmod 700 "$GNUPGHOME" + fi + if [ ! -d "$runtime" ]; then + mkdir -p "$runtime" + chmod 700 "$runtime" + fi + + # Generate environment file + #echo "export GPG_TTY=$GPG_TTY" > "$runtime/env" + echo "export GNUPGHOME=$gpghome" > "$runtime/env" + echo "export GPG_AGENT_INFO=$runtime/socket" >> "$runtime/env" + + # Start agent + idm_log INFO "Start gpg-agent ..." + gpg-agent --daemon --extra-socket "$runtime/socket" + +} + +## Extended functions +########################################## + +idm_gpg_new () +{ + local id=${1} + idm_is_enabled $id + + gpg --gen-key +} + diff --git a/lib/idmgr_mod_id.sh b/lib/idmgr_mod_id.sh new file mode 100644 index 0000000..d8373f5 --- /dev/null +++ b/lib/idmgr_mod_id.sh @@ -0,0 +1,206 @@ +#!/bin/bash + +IDM_MOD_DEPS="" + +## Identity functions +########################################## + + +idm_id_help () +{ + echo "Identity management:" + printf " %-20s: %s\n" "id ls" "List all disks of all policies" + printf " %-20s: %s\n" "id new " "Add new id" + printf " %-20s: %s\n" "id rm " "Remove id" + printf " %-20s: %s\n" "id edit " "Edit id" + printf " %-20s: %s\n" "id show " "Show id" + printf " %-20s: %s\n" "id dump " "Dump all id configurations" + +} + +idm_id () +{ + idm_id_ls ${@-} +} + +idm_id_rm () +{ + local id=${1} + + # Local checks + idm_validate id $id || idm_exit 1 ERR "Id '$id' is not valid" + #idm_validate id_config $id && idm_exit 1 "Configuration '$id' already exists" + + + # Delete config + if [ -f "$IDM_DIR_ID/$id.env" ] ; then + rm "$IDM_DIR_ID/$id.env" || \ + idm_exit 1 ERR "File '$IDM_DIR_ID/$id.env' could not be deleted" + else + idm_log WARN "File '$IDM_DIR_ID/$id.env' was already deleted" + fi +} + +idm_id_disable() +{ + # Disable internal variables + echo "unset SHELL_ID GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL" | idm_log CODE - +} + +idm_id_kill () { idm_id_disable ${@-}; } + +idm_id_get () +{ + local id=${1} + + if [[ "$id" == "-" && -n "${SHELL_ID-}" ]]; then + echo "${SHELL_ID-}" + return 0 + elif [[ "${id}" == "${SHELL_ID-}" ]]; then + return 0 + else + return 1 + fi + +} + +idm_id_enable() +{ + local id=${1} + local conf="$IDM_DIR_ID/$id.env" + + [ -f "$conf" ] && source "$conf" + + echo "export SHELL_ID=${id}" + echo "export GIT_AUTHOR_NAME=${id}" + echo "export GIT_AUTHOR_EMAIL=${email}" + + + + # # echo "export PATH=${XDG_OPT_HOME}/bin:$PATH" + # #echo "export SSH_CONFIG=${id}" + # #echo "export SSH_AUTH_SOCK=/tmp/ssh-S88jysAIp3qs/${id}-agent.1767" + # #echo "export LOGNAME=${id}" + # #echo "export USER=${id}" + + # #echo "export GNUPGHOME=~/.config/gnupg/$id" + # #echo "export GPG_AGENT_INFO=..." + + # #echo "export TZ=${tz-}" + # #echo "export MAIL=/var/spool/mail/${id}" + # #echo "export LANG=en_US.utf8" + # #echo "export TERM=xterm-256color" + + # XDG_OPT_HOME=~/opt/${id} + + + # # echo "export XDG_CONFIG_HOME=~/.config" + # # echo "export XDG_DATA_HOME=~/.local/share" + # # echo "export XDG_CACHE_HOME=~/.local/cache" + # # echo "export XDG_OPT_HOME=$XDG_OPT_HOME" +} + +idm_id_new () +{ + local id=${1} + + # Local checks + idm_validate id $id || idm_exit 1 "Id '$id' is not valid" + idm_validate id_config $id && idm_exit 1 "Configuration '$id' already exists" + + # Create new id + conf="$IDM_DIR_ID/$id.env" + idm_id_template $id > $conf + + # Edit id + $EDITOR "$conf" + + # Notice user + idm_log NOTICE "Id '$id' has been created:" + cat $conf | idm_log CODE - +} + + +idm_id_show () +{ + local id=${1} + local conf + + # Local checks + idm_validate id_config $id || idm_exit 1 ERR "Configuration '$id' does not exists" + + # Edit id + conf="$IDM_DIR_ID/$id.env" + + # Notice user + idm_log INFO "Id '$id' configuration:" + idm_get id_config $id | idm_log CODE - +# cat $conf | idm_log CODE +} + +idm_id_edit () +{ + local id=${1} + local md5 conf + + # Local checks + idm_validate id_config $id || idm_exit 1 ERR "Configuration '$id' does not exists" + + # Edit id + conf="$IDM_DIR_ID/$id.env" + md5=$(md5sum $conf) + $EDITOR $conf + + # Notice user + if [[ "$md5" == "$(md5sum $conf)" ]] ;then + idm_log INFO "Id '$id' has not been updated:" + else + idm_log NOTICE "Id '$id' has been updated:" + fi + cat $conf | idm_log CODE - +} + + +idm_id_ls () +{ + local active + + for id in $(idm_get all_id); do + + if [ "$id" == "${SHELL_ID-}" ]; then + active='*' + else + active=' ' + fi + + echo $( + eval "$(idm_get id_config $id)" + echo "$active:$id:$common_name ($email)" + ) + done | column -t -s: -o' ' | idm_log DUMP - +} + +idm_id_dump () +{ + for id in $(idm_get all_id); do + #idm_log NOTICE "Identity $id" + { + idm_get id_config $id + echo " " + } | idm_log CODE - + done +} + +idm_id_template () +{ + local cn=${1-} + local tz lang + + # Auto guess + tz=$( timedatectl | grep "Time zone" | awk '{print $3}' || true ) + + echo "common_name=${cn}" + echo "email=" + echo "tz=$tz" + +} diff --git a/lib/idmgr_mod_pass.sh b/lib/idmgr_mod_pass.sh new file mode 100644 index 0000000..e309624 --- /dev/null +++ b/lib/idmgr_mod_pass.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +IDM_MOD_DEPS="id gpg" + + +## Pass functions +########################################## + +idm_pass () +{ + #set -x + if [ "$#" -eq 1 ]; then + local id=$1 + idm_pass_ls $id + return 0 + else + local action=$1 + local id=$2 + shift 2 || true + local opt=${@-} + fi + + # Interncal override case + + # Fallback to command + idm_is_enabled $id + PASSWORD_STORE_DIR=~/.config/pass/${id} pass $action ${@-} + +} + +idm_pass_ls () +{ + local id=${1} + idm_is_enabled $id + + PASSWORD_STORE_DIR=~/.config/pass/${id} pass ls +} + +idm_pass_help () +{ + echo "Standard UNIX Password Manager" + printf " %-20s: %s\n" "pass ls" "List passwords" + printf " %-20s: %s\n" "pass insert|new" "Add new secret" + printf " %-20s: %s\n" "pass generate" "Generate random secret" + printf " %-20s: %s\n" "pass grep" "Search in secrets" + printf " %-20s: %s\n" "pass rm" "Delete secret" + printf " %-20s: %s\n" "pass mv" "Move secret" + printf " %-20s: %s\n" "pass cp" "Copy secret" + +} + +idm_pass_enable () +{ + local id=${1} + idm_is_enabled $id + + echo "export PASSWORD_STORE_DIR=~/.config/pass/${id}" +} + + +idm_pass_disable () +{ + local id=${1} + idm_is_enabled $id + + echo "unset PASSWORD_STORE_DIR" +} + diff --git a/lib/idmgr_mod_ps1.sh b/lib/idmgr_mod_ps1.sh new file mode 100644 index 0000000..107c6ce --- /dev/null +++ b/lib/idmgr_mod_ps1.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +IDM_MOD_DEPS="id pass gpg ssh" + +## Prompt functions +########################################## + +SHELL_PS1="${SHELL_PS1:-[\\u@\\h \\W]\\$ }" + +idm_ps1 () +{ + local action=${1-} + shift || true + + idm_ps1_ls +} + +idm_ps1_ls () +{ + local id=${1} + + #set -x + #echo "PS1=${SHELL_PS1:-${PS1-}}" + + if grep -q "($id)" <<<"${SHELL_PS1:-${PS1-}}" ; then + echo "enabled" + else + echo "disabled" + fi + +} + +idm_ps1_help () +{ + echo "Shell Prompt" + printf " %-20s: %s\n" "ps1 enable" "Enable prompt" + printf " %-20s: %s\n" "ps1 disable" "Disable prompt" +} + +idm_ps1_enable () +{ + local id=${1} + +# \033]00m\] # for shell +#\[\033]01;31m\] for ps1 + + + id="\[\033[0;34m\]($id)\[\033[00m\]" + PS1="$id ${PS1:-$SHELL_PS1}" + echo "export PS1='$PS1'" + echo "export SHELL_PS1='$PS1'" +} + +idm_ps1_disable () +{ + local id=${1} + PS1=$( sed "s/$id[^a-z]* //" <<<${PS1:-$SHELL_PS1} ) + PS1='[\u@\h \W]\$ ' + echo "export PS1='$PS1'" + echo "export SHELL_PS1='$PS1'" +} + +idm_ps1_kill () { idm_ps1_disable ${@-}; } diff --git a/lib/idmgr_mod_ssh.sh b/lib/idmgr_mod_ssh.sh new file mode 100644 index 0000000..bfc2d99 --- /dev/null +++ b/lib/idmgr_mod_ssh.sh @@ -0,0 +1,201 @@ +#!/bin/bash + + +IDM_MOD_DEPS="id gpg" + +# trap 'idm_ssh_kill' 0 + +## SSH functions +########################################## + +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 new" "Create new ssh key (ssh-keygen)" + printf " %-20s: %s\n" "ssh add" "Unlock known keypairs" + printf " %-20s: %s\n" "ssh rm" "Lock known keypairs" + printf " %-20s: %s\n" "ssh del" "Delete keypair" + + printf " %-20s: %s\n" "ssh enable" "Enable agent" + printf " %-20s: %s\n" "ssh disable" "Disable agent" + printf " %-20s: %s\n" "ssh kill" "Kill agent" + +} + +idm_ssh () +{ + # Argument maangement + if [ "$#" -eq 1 ]; then + local id=$1 + idm_ssh_ls $id + return 0 + else + local action=$1 + local id=$2 + shift 2 || true + local opt=${@-} + fi + + # Internal override case + + # Fallback to command + idm_ssh_help + return 1 + +} + + +## Required functions +########################################## + +idm_ssh_ls () +{ + local id=$1 + local opt=${2:--l} + + idm_is_enabled $id + + { ssh-add $opt || true ; } | idm_log DUMP - +} + +idm_ssh_disable () +{ + local id=$1 + idm_is_enabled $id + + # Return portion of code to clean + echo "unset SSH_AUTH_SOCK SSH_AGENT_PID" + +} + +idm_ssh_enable () +{ + local id=$1 + idm_is_enabled $id + + #set -x + + # Source environment + if [ -f "${XDG_RUNTIME_DIR}/ssh-agent/${id}/env" ] ; then + . "${XDG_RUNTIME_DIR}/ssh-agent/${id}/env" + else + unset SSH_AUTH_SOCK + fi + + # Check if the socket file is available + if [ ! -S "${SSH_AUTH_SOCK-}" ]; then + rm -f "${XDG_RUNTIME_DIR}/ssh-agent/${id}/env" + idm_ssh__start $id + fi + + # Show the things to source + cat "${XDG_RUNTIME_DIR}/ssh-agent/${id}/env" + +} + +# LOGOUT +idm_ssh_kill () { + + #set -x + + local id=$1 + local run_dir="${XDG_RUNTIME_DIR}/ssh-agent/${id}" + + idm_is_enabled $id + + #idm_log NOTICE "Cleaning ssh-agent ..." + + [ -z "${SSH_AGENT_PID-}" ] && \ + [ -f "$run_dir/env" ] && \ + . "$run_dir/env" + + # Clean ssh-agent process + if kill -0 ${SSH_AGENT_PID-} &>/dev/null; then + /usr/bin/ssh-agent -k >/dev/null + idm_log NOTICE "Kill ssh-agent ..." + fi + #eval "$(/usr/bin/ssh-agent -k 2>/dev/null)" + + # Clean ssh-agent env file + [ ! -f "${XDG_RUNTIME_DIR}/ssh-agent/${id}/env" ] || \ + rm "${XDG_RUNTIME_DIR}/ssh-agent/${id}/env" + + # Disable agent + idm_ssh_disable $id + + set +x + +} + + +## Internal functions +########################################## +idm_ssh__start() { + local id=$1 + local life=5d + local run_dir="${XDG_RUNTIME_DIR}/ssh-agent/${id}" + + if [ -z "${SSH_AUTH_SOCK-}" ] ; then + + if [ ! -d "$run_dir" ]; then + mkdir -p "$run_dir" + fi + + if [ ! -S "$run_dir/socket" ]; then + ssh-agent -a "$run_dir/socket" -t $life -s | grep ^SSH_ > "$run_dir/env" + idm_log INFO "Start ssh-agent ..." + + else + idm_log INFO "The ssh-agent is already started (but not managed by ourself)" + fi + + else + idm_log INFO "The ssh-agent is already started" + fi +} + +## Extended functions +########################################## + +idm_ssh_add () +{ + local id=$1 + local key=${2-} + local maxdepth=1 + + idm_is_enabled $id + + + if [[ ! -z $key ]]; then + pub_keys=$(find ~/.ssh/id -maxdepth $maxdepth -name "${id}_*" -name '*pub' -name "*$1*" | sort) + else + pub_keys=$(find ~/.ssh/id -maxdepth $maxdepth -name "${id}_*" -name '*pub' | sort) + fi + + # Get list of key + local key_list="" + while read -r pub_key; do + #if [[ -f "$(sed 's/\.pub$/.key/' <<< "${pub_key}" )" ]]; then + if [[ -f "${pub_key//\.pub/.key}" ]]; then + key_list="$key_list ${pub_key//\.pub/.key}" + else + #if [[ -f "$(sed 's/\.pub$//' <<< "${pub_key}" )" ]]; then + if [[ -f "${pub_key%\.pub}" ]]; then + key_list="$key_list ${pub_key%\.pub}" + fi + fi + done <<< "$pub_keys" + + [ -n "$pub_keys" ] || \ + idm_exit 0 WARN "No keys found" + + idm_log INFO "Adding keys:" + xargs -n 1 <<<$key_list | idm_log DUMP - + + echo "" + ssh-add $key_list + +} + diff --git a/shell/bash.sh b/shell/bash.sh new file mode 100644 index 0000000..ca8fa26 --- /dev/null +++ b/shell/bash.sh @@ -0,0 +1,169 @@ +#!/bin/bash + +IDM_SRC_WORDS=${IDM_SRC_WORDS-} +IDM_BIN=${IDM_BIN:-idmgr} + +i () +{ + + if grep -q ":${1:-NONE}:" <<<"${IDM_SRC_WORDS}"; then + + result="$( $IDM_BIN $@)" + + # Debug module + if [ "${ID_DEBUG-}" == "true" ]; then + if [ "${result:-NONE}" == "NONE" ]; then + echo "======= ${result:-NONE}" + else + echo ======= Shell has sourced ======= + echo "${result:-NONE}" + echo ======= + fi + fi + + # Parse output + eval "$result" + + else + $IDM_BIN $@ + fi + +} + + +# Disable when pressing C-b in shell :) +bind -x '"\C-b": i disable' + + + + +# completion file for bash + +# Copyright (C) 2012 - 2014 Jason A. Donenfeld and +# Brian Mattern . All Rights Reserved. +# This file is licensed under the GPLv2+. Please see COPYING for more information. + +_pass_complete_entries () { + prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store/}" + prefix="${prefix%/}/" + suffix=".gpg" + autoexpand=${1:-0} + + local IFS=$'\n' + local items=($(compgen -f $prefix$cur)) + + # Remember the value of the first item, to see if it is a directory. If + # it is a directory, then don't add a space to the completion + local firstitem="" + # Use counter, can't use ${#items[@]} as we skip hidden directories + local i=0 + + for item in ${items[@]}; do + [[ $item =~ /\.[^/]*$ ]] && continue + + # if there is a unique match, and it is a directory with one entry + # autocomplete the subentry as well (recursively) + if [[ ${#items[@]} -eq 1 && $autoexpand -eq 1 ]]; then + while [[ -d $item ]]; do + local subitems=($(compgen -f "$item/")) + local filtereditems=( ) + for item2 in "${subitems[@]}"; do + [[ $item2 =~ /\.[^/]*$ ]] && continue + filtereditems+=( "$item2" ) + done + if [[ ${#filtereditems[@]} -eq 1 ]]; then + item="${filtereditems[0]}" + else + break + fi + done + fi + + # append / to directories + [[ -d $item ]] && item="$item/" + + item="${item%$suffix}" + COMPREPLY+=("${item#$prefix}") + if [[ $i -eq 0 ]]; then + firstitem=$item + fi + let i+=1 + done + + # The only time we want to add a space to the end is if there is only + # one match, and it is not a directory + if [[ $i -gt 1 || ( $i -eq 1 && -d $firstitem ) ]]; then + compopt -o nospace + fi +} + +_pass_complete_folders () { + prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store/}" + prefix="${prefix%/}/" + + local IFS=$'\n' + local items=($(compgen -d $prefix$cur)) + for item in ${items[@]}; do + [[ $item == $prefix.* ]] && continue + COMPREPLY+=("${item#$prefix}/") + done +} + +_pass_complete_keys () { + local IFS=$'\n' + # Extract names and email addresses from gpg --list-keys + local keys="$(gpg2 --list-secret-keys --with-colons | cut -d : -f 10 | sort -u | sed '/^$/d')" + COMPREPLY+=($(compgen -W "${keys}" -- ${cur})) +} + +_pass() +{ + COMPREPLY=() + local cur="${COMP_WORDS[COMP_CWORD]}" + local commands="init ls find grep show insert generate edit rm mv cp git help version" + if [[ $COMP_CWORD -gt 1 ]]; then + local lastarg="${COMP_WORDS[$COMP_CWORD-1]}" + case "${COMP_WORDS[1]}" in + init) + if [[ $lastarg == "-p" || $lastarg == "--path" ]]; then + _pass_complete_folders + compopt -o nospace + else + COMPREPLY+=($(compgen -W "-p --path" -- ${cur})) + _pass_complete_keys + fi + ;; + ls|list|edit) + _pass_complete_entries + ;; + show|-*) + COMPREPLY+=($(compgen -W "-c --clip" -- ${cur})) + _pass_complete_entries 1 + ;; + insert) + COMPREPLY+=($(compgen -W "-e --echo -m --multiline -f --force" -- ${cur})) + _pass_complete_entries + ;; + generate) + COMPREPLY+=($(compgen -W "-n --no-symbols -c --clip -f --force -i --in-place" -- ${cur})) + _pass_complete_entries + ;; + cp|copy|mv|rename) + COMPREPLY+=($(compgen -W "-f --force" -- ${cur})) + _pass_complete_entries + ;; + rm|remove|delete) + COMPREPLY+=($(compgen -W "-r --recursive -f --force" -- ${cur})) + _pass_complete_entries + ;; + git) + COMPREPLY+=($(compgen -W "init push pull config log reflog rebase" -- ${cur})) + ;; + esac + else + COMPREPLY+=($(compgen -W "${commands}" -- ${cur})) + _pass_complete_entries 1 + fi +} + +complete -o filenames -F _pass pass