1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
#!/usr/bin/env bash
readonly red=$(tput setaf 1)
readonly green=$(tput setaf 2)
readonly yellow=$(tput setaf 3)
readonly Bred=$(tput setab 1)
readonly reset=$(tput sgr0)
readonly Bold=$(tput bold)
readonly underline=$(tput smul)
readonly nounderline=$(tput rmul)
_die() {
echo -e "${red}${Bold}Error:${reset} ${@}" >&2
exit 1
}
cmd_report_usage() {
echo
cat <<-EOF
Usage:
$PROGRAM report [-c|--color] [-l|--length] [<password file>]
Report last change's date and age of all passwords or given
password
Options:
-c, --color Show old password (more than 2 years) in yellow
-l, --length Show password length indication
-h, --help Show this help
Password length indication:
very short Less than 8 characters
short Less than 13 characters
medium Less than 17 characters
long 17 characters or more
EOF
}
cmd_report() {
local file="$1"
check_sneaky_paths "$file"
[ ! -d "$PREFIX/.git" ] && _die "Your password store does not use .git, can't show report"
if [ -z "$file" ]; then
_cmd_report_all_passwords
else
if [ -d "${PREFIX}/${file}" ]; then
_cmd_report_all_passwords "$file"
else
_cmd_report_password ${file%/}
fi
fi
}
_cmd_report_all_passwords() {
pass_prefix="$1"
git -C "$PREFIX" ls-tree -r --name-only HEAD | grep "^${pass_prefix}" | grep -E "\.gpg$" | while read filename ; do
_cmd_report_password "$filename"
done
}
_cmd_report_password() {
local file="$1"
if [ ! -f "${PREFIX}/${file}" ]; then
if [ ! -f "${PREFIX}/${file}.gpg" ]; then
_die "$file: no such file or directory"
else
file="${file}.gpg"
fi
fi
local password_data=$(git -C "$PREFIX" blame -L 1,1 -p ${file} | sed -n '1 s/^\([0-9a-f]\+\) .*$/\1/ p ; $ s/^\s\+\(.*\)$/\1/ p')
local commit=$(echo $password_data | cut -d' ' -f1)
local length=$(echo $password_data | cut -d' ' -f2- | wc -c)
local date=$(git -C "$PREFIX" show --date=short --format="%cd %cr" --no-patch $commit)
_print_report "$file" "$length" "$date"
}
# $1: filename
# $2: length
# $3: date
_print_report() {
local password=${1/%.gpg/}
local length=$2
local date=${3% *}
local age=${3#* }
local format_date_width=14
local format_age_width=28
local format_length_indication_width=11
local format_age="%-${format_age_width}s"
local format_length_indication=" "
local format_password="%s"
local local_format_password=$format_password
local local_format_age=$format_age
local local_format_length_indication=""
local length_indication=""
[ "$COLOR" = 1 ] && echo $age | grep -q "years" \
&& local_format_age="${yellow}%-${format_age_width}s${reset}" \
&& local_format_password="${yellow}%s${reset}"
if [[ "$LENGTH" -eq 1 ]]; then
format_length_indication="%-${format_length_indication_width}s"
if [[ $length -lt 8 ]]; then
length_indication="very short"
local_format_length_indication="${Bred}${format_length_indication}${reset}"
local_format_password="${Bred}${format_password}${reset}"
elif [[ $length -lt 13 ]]; then
length_indication="short"
local_format_length_indication="${red}${format_length_indication}${reset}"
local_format_password="${red}${format_password}${reset}"
elif [[ $length -lt 17 ]]; then
length_indication="medium"
local_format_length_indication="${yellow}${format_length_indication}${reset}"
local_format_password="${yellow}${format_password}${reset}"
else
length_indication="long"
local_format_length_indication="${green}${format_length_indication}${reset}"
fi
# Add spaces for final format
local_format_length_indication=" ${local_format_length_indication} "
fi
[ "$COLOR" = 1 ] \
&& format_password=$local_format_password \
&& format_length_indication=$local_format_length_indication \
&& format_age=$local_format_age
local format="%-${format_date_width}s ${format_age}${format_length_indication}${format_password}\n"
[ "$LENGTH" = 1 ] \
&& printf "${format}" "$date" "$age" "$length_indication" "$password" \
|| printf "${format}" "$date" "$age" "$password"
}
COLOR=0
LENGTH=0
# Getopt options
small_arg="chl"
long_arg="color,help,length"
opts="$($GETOPT -o $small_arg -l $long_arg -n "$PROGRAM $COMMAND" -- "$@")"
err=$?
eval set -- "$opts"
while true; do case $1 in
-c|--color) COLOR=1; shift ;;
-l|--length) LENGTH=1; shift ;;
-h|--help) shift; cmd_report_usage; exit 0 ;;
--) shift; break ;;
esac done
[[ $err -ne 0 ]] && cmd_report_usage && exit 1
cmd_report "$@"
|