Last active
January 4, 2016 08:59
-
-
Save lobianco/8599515 to your computer and use it in GitHub Desktop.
a simple bash script for managing passwords
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# Written by Anthony Lobianco, 02/13/2013 | |
# | |
# a script to make managing passwords quicker and easier. | |
# | |
# USAGE | |
# ----- | |
# chmod a+x pass.sh | |
# ./pass.sh | |
# | |
# CHANGELOG | |
# --------- | |
# | |
# 1.3.5 | |
# ----- | |
# .csv file will now be sorted alphabetically after adding a new user | |
# | |
# 1.3.4 | |
# ----- | |
# fixed bug where brackets in a string would cause an error when editing a username with sed | |
# | |
# 1.3.3 | |
# ----- | |
# temporary prevention of bug with brackets in FTP password | |
# | |
# 1.3.2 | |
# ----- | |
# added logic to strip any input of all whitespace | |
# fixed bug where reading ftp password input might not account for backslashes | |
# | |
# 1.3.1 | |
# --- | |
# bug fixes when restarting script from the edit user screen | |
# | |
# 1.3 | |
# --- | |
# checks if username exists before adding new user | |
# verifies data hasn't been recently manipulated before performing delete or edit operations | |
# backs up all files before editing them and logs info into a log file | |
# | |
# 1.2.1 | |
# ----- | |
# fixed bug where copying a password also copied a newline character appended to it | |
# select list can now be chosen by number or term | |
# | |
# 1.2 | |
# --- | |
# added ability to edit and/or delete a specific user | |
# typing "exit" will completely exit the script, typing "restart" will start over | |
# | |
# 1.1 | |
# --- | |
# ability to add new users to the master list | |
# compatible with (and expects) a .csv file now, with double-quote delimited fields | |
# | |
# 1.0 | |
# ----- | |
# scans a text file for inputted user and outputs the appropriate info | |
# filters results when more than one instance of a user is found | |
# copies chosen password to clipboard | |
# | |
## Edit this information | |
# | |
# | |
# the main password file - double-quoted and comma delimited csv file (required) | |
PASS_FILE=~/pass.csv | |
# | |
# folder to store backups of password file prior to any changes (will be created | |
# if it doesn't exist) | |
# | |
BK_FOLDER=~/csv_backups | |
# | |
# log file to record edit history. (will be created if it doesn't exist) | |
LOG_FILE=~/pass.log | |
# | |
# | |
## Edit below this line at your own risk! | |
VRS=1.3.5 | |
function quit() { | |
echo " " | |
echo -e "DONE \n" | |
exit 0 | |
} | |
function trim() { | |
local var=$1 | |
echo -n "${var//[[:space:]]/}" | |
} | |
function sanitize() { | |
local var=$1 | |
# escape all backslashes first | |
var="${var//\\/\\\\}" | |
# escape slashes | |
var="${var//\//\\/}" | |
# escape asterisks | |
var="${var//\*/\\*}" | |
# escape full stops | |
var="${var//./\\.}" | |
# escape [ and ] | |
var="${var//\[/\\[}" | |
var="${var//\]/\\]}" | |
# escape ^ | |
var="${var//^/\\^}" | |
# escape & | |
var="${var//&/\\&}" | |
# escape ! | |
var="${var//\!/\\!}" | |
# escape $ | |
var="${var//\$/\\$}" | |
echo $var | |
} | |
RED=$(tput setaf 1) | |
YELLOW=$(tput setaf 3) | |
CYAN=$(tput setaf 6) | |
BOLD=$(tput bold) | |
NORMAL=$(tput sgr0) | |
echo " " | |
echo "checking files..." | |
if [ ! -f $PASS_FILE ]; then | |
echo "can't find password file, exiting" | |
exit 1 | |
fi | |
if [ ! -d $BK_FOLDER ]; then | |
mkdir $BK_FOLDER | |
fi | |
if [ ! -f $LOG_FILE ]; then | |
touch $LOG_FILE | |
fi | |
clear | |
echo -e "${BOLD}${CYAN}PASSWORD MANAGER v$VRS ${NORMAL} \n" | |
echo -e "=> NOTE: you can type ${RED}exit${NORMAL} or ${RED}restart${NORMAL} at any time \n" | |
while : | |
do | |
DATE=`eval date +%Y%m%d-%H%M%S` | |
CLEAN_DAY=`eval date +%Y-%m-%d` | |
CLEAN_TIME=`eval date +%H:%M:%S` | |
CLEAN_DATE="$CLEAN_DAY at $CLEAN_TIME" | |
echo "enter the account username or domain" | |
echo "=> (type ${RED}NEW${NORMAL} to enter a new user)" | |
echo -n "[account]: " | |
while read username | |
do | |
# delete whitespace | |
username=`trim "$username"` | |
if [[ $username = exit ]]; then | |
quit | |
elif [[ $username = restart ]]; then | |
break | |
elif [[ -z $username ]]; then | |
echo -n "[account]: " | |
continue | |
elif [[ $username = NEW ]]; then | |
echo " " | |
echo "enter new user information" | |
echo "=> (if any fields are N/A, enter a ${RED}single dash${NORMAL})" | |
echo -e "=> (domain shouldn't contain http, www, or slashes) \n" | |
echo -n "[new username]: " | |
# todo check if user exists | |
while read username | |
do | |
username=`trim "$username"` | |
grep "$username" < $PASS_FILE | awk -F '^"|","|"$' -v user="$username" '{if ($2==user) {print}}' | while read line | |
do | |
FOUND_SERVER=`echo $line | awk -F '^"|","|"$' '{print $(NF-1)}'` | |
echo "=> ${YELLOW}WARNING:${NORMAL} $username already found on $FOUND_SERVER. do you need to ${RED}restart${NORMAL}?" | |
done | |
if [[ $username = exit ]]; then | |
quit | |
elif [[ $username = restart ]]; then | |
break 2 | |
elif [[ -z $username ]]; then | |
echo -n "[new username]: " | |
else | |
break | |
fi | |
done | |
echo -n "[domain]: " | |
while read newdomain | |
do | |
newdomain=`trim "$newdomain"` | |
if [[ $newdomain = exit ]]; then | |
quit | |
elif [[ $newdomain = restart ]]; then | |
break 2 | |
elif [[ -z $newdomain ]]; then | |
echo -n "[domain]: " | |
else | |
break | |
fi | |
done | |
echo -n "[server]: " | |
while read newserver | |
do | |
newserver=`trim "$newserver"` | |
if [[ $newserver = exit ]]; then | |
quit | |
elif [[ $newserver = restart ]]; then | |
break 2 | |
elif [[ -z $newserver ]]; then | |
echo -n "[server]: " | |
else | |
break | |
fi | |
done | |
echo -n "[ftp password]: " | |
while read -r newftp | |
do | |
newftp=`trim "$newftp"` | |
if [[ $newftp = exit ]]; then | |
quit | |
elif [[ $newftp = restart ]]; then | |
break 2 | |
elif [[ -z $newftp ]]; then | |
echo -n "[ftp password]: " | |
else | |
break | |
fi | |
done | |
echo -n "[website password]: " | |
while read newweb | |
do | |
newweb=`trim "$newweb"` | |
if [[ $newweb = exit ]]; then | |
quit | |
elif [[ $newweb = restart ]]; then | |
break 2 | |
elif [[ -z $newweb ]]; then | |
echo -n "[website password]: " | |
else | |
break | |
fi | |
done | |
USERSTRING="\"$username\",\"$newftp\",\"$newweb\",\"$newdomain\",\"$newserver\"" | |
cp $PASS_FILE ${PASS_FILE}_${DATE}_NEW-${username}.csv | |
mv ${PASS_FILE}_${DATE}_NEW-${username}.csv $BK_FOLDER/ | |
sed -i '' -e '$a\' $PASS_FILE | |
echo $USERSTRING >> $PASS_FILE | |
sort $PASS_FILE -o $PASS_FILE | |
echo "${CLEAN_DATE} - NEW USER => \"${username}\"" >> $LOG_FILE | |
echo " " | |
echo "new user successfully added." | |
fi | |
MATCH1=`grep -c "${username}" < $PASS_FILE` | |
if [[ $MATCH1 -eq 0 ]]; then | |
echo " " | |
echo -n "no matches found," | |
break | |
elif [[ $MATCH1 -ne 1 ]]; then | |
echo " " | |
echo "which server?" | |
echo -n "[server]: " | |
while read server_input | |
do | |
server_input=`trim "$server_input"` | |
if [[ $server_input = exit ]]; then | |
quit | |
elif [[ $server_input = restart ]]; then | |
break 2 | |
elif [[ -z $server_input ]]; then | |
echo -n "[server]: " | |
continue | |
fi | |
MATCH2=`grep "${username}.*${server_input}\|${server_input}.*${username}" < $PASS_FILE | | |
awk -F '^"|","|"$' -v user="$username" -v server="$server_input" '{if (($2==user || $5==user) && $(NF-1)==server) {print}}' | | |
grep -c "$username"` | |
if [[ $MATCH2 -eq 0 ]]; then | |
echo " " | |
echo -n "no matches found," | |
break 2 | |
elif [[ $MATCH2 -ne 1 ]]; then | |
echo " " | |
echo -n "more than one match found - condition unaccounted for" | |
break 2 | |
else | |
# get the matched data's line number | |
RESULT=`grep "${username}.*${server_input}\|${server_input}.*${username}" < $PASS_FILE | | |
awk -F '^"|","|"$' -v user="$username" -v server="$server_input" '{if (($2==user || $5==user) && $(NF-1)==server) {print}}'` | |
LINE=`grep -F "${RESULT}" $PASS_FILE` | |
LINE_NUMBER=`grep -Fn "${RESULT}" < $PASS_FILE | cut -f1 -d:` | |
fi | |
break | |
done | |
else | |
LINE=`grep "${username}" $PASS_FILE` | |
LINE_NUMBER=`grep -n "${username}" < $PASS_FILE | cut -f1 -d:` | |
fi | |
echo "line: $LINE_NUMBER" | |
USER=`sed -n "${LINE_NUMBER}p" < $PASS_FILE | awk -F '^"|","|"$' '{print $2}' | tr -d '"'` | |
FTP_PASS=`sed -n "${LINE_NUMBER}p" < $PASS_FILE | awk -F '^"|","|"$' '{print $3}' | tr -d '"'` | |
WEB_PASS=`sed -n "${LINE_NUMBER}p" < $PASS_FILE | awk -F '^"|","|"$' '{print $4}' | tr -d '"'` | |
DOMAIN=`sed -n "${LINE_NUMBER}p" < $PASS_FILE | awk -F '^"|","|"$' '{print $5}' | tr -d '"'` | |
SERVER=`sed -n "${LINE_NUMBER}p" < $PASS_FILE | awk -F '^"|","|"$' '{print $(NF-1)}' | tr -d '"'` | |
echo " " | |
echo -e "user:\t $USER" | |
echo -e "domain:\t $DOMAIN" | |
echo -e "server:\t $SERVER" | |
echo -e "FTP:\t $FTP_PASS" | |
echo -e "web:\t $WEB_PASS \n" | |
declare -a OPTIONS | |
OPTIONS=( "copy FTP password" "copy website password" "edit this user" "delete this user" "restart" "exit" ) | |
echo "what would you like to do?" | |
select opt in "${OPTIONS[@]}"; do | |
[[ -z $opt ]] && casevar=$REPLY || casevar=$opt | |
case $casevar in | |
1|${OPTIONS[0]} ) # copy FTP password | |
echo $FTP_PASS | tr -d '\n' | pbcopy | |
echo " " | |
echo "FTP password copied." | |
break 3 | |
;; | |
2|${OPTIONS[1]} ) # copy website password | |
echo $WEB_PASS | tr -d '\n' | pbcopy | |
echo " " | |
echo "Website password copied." | |
break 3 | |
;; | |
3|${OPTIONS[2]} ) # edit user | |
echo " " | |
echo "edit user information" | |
echo "=> (${RED}leave empty${NORMAL} if no change is necessary; enter a ${RED}single dash${NORMAL} if N/A)" | |
echo -e "=> (domain shouldn't contain http, www, or slashes) \n" | |
read -p "[new username]: " edit_new_user; edit_new_user=`trim "$edit_new_user"`; | |
if [[ $edit_new_user = exit ]]; then quit; | |
elif [[ $edit_new_user = restart ]]; then break 2; | |
elif [[ -z $edit_new_user ]]; then edit_new_user=$USER; | |
fi | |
read -p "[new domain]: " edit_new_domain; edit_new_domain=`trim "$edit_new_domain"`; | |
if [[ $edit_new_domain = exit ]]; then quit; | |
elif [[ $edit_new_domain = restart ]]; then break 2; | |
elif [[ -z $edit_new_domain ]]; then edit_new_domain=$DOMAIN; | |
fi | |
echo -n "[new server]: " | |
while read edit_new_server | |
do | |
edit_new_server=`trim "$edit_new_server"` | |
if [[ $edit_new_server = exit ]]; then | |
quit | |
elif [[ $edit_new_server = restart ]]; then | |
break 3 | |
elif [[ -z $edit_new_server ]]; then | |
edit_new_server=$SERVER | |
break | |
else | |
break | |
fi | |
done | |
read -rp "[new ftp password]: " edit_new_ftp; edit_new_ftp=`trim "$edit_new_ftp"`; | |
if [[ $edit_new_ftp = exit ]]; then quit; | |
elif [[ $edit_new_ftp = restart ]]; then break 2; | |
elif [[ -z $edit_new_ftp ]]; then edit_new_ftp=$FTP_PASS; | |
fi | |
read -p "[new website password]: " edit_new_web; edit_new_web=`trim "$edit_new_web"`; | |
if [[ $edit_new_web = exit ]]; then quit; | |
elif [[ $edit_new_web = restart ]]; then break 2; | |
elif [[ -z $edit_new_web ]]; then edit_new_web=$WEB_PASS; | |
fi | |
# make sure information hasn't been changed by someone else since username searched occured | |
VERIFY_LINE=`sed -n "${LINE_NUMBER}p" $PASS_FILE` | |
if [ "$VERIFY_LINE" == "$LINE" ]; then | |
sed -i_${DATE}_EDIT-${edit_new_user}.csv -e "${LINE_NUMBER}s/$USER/$edit_new_user/" $PASS_FILE | |
sed -i '' -e "${LINE_NUMBER}s/$DOMAIN/$edit_new_domain/" $PASS_FILE | |
sed -i '' -e "${LINE_NUMBER}s/$SERVER/$edit_new_server/" $PASS_FILE | |
# didn't work but took a lot of time so I'm having trouble letting go | |
# awk -F '^"|","|"$' -v ftp="$FTP_PASS" -v newftp="$edit_new_ftp" -v line="$LINE_NUMBER" 'NR==line {if ($3==ftp) {$3=newftp; print $3}}' $PASS_FILE | |
# sanitize special characters so they will be usable in sed | |
ESCAPED_FTP=`sanitize "$FTP_PASS"` | |
ESCAPED_NEWFTP=`sanitize "$edit_new_ftp"` | |
sed -i '' -e "${LINE_NUMBER}s/$ESCAPED_FTP/$ESCAPED_NEWFTP/" $PASS_FILE | |
sed -i '' -e "${LINE_NUMBER}s/$WEB_PASS/$edit_new_web/" $PASS_FILE | |
mv ${PASS_FILE}_${DATE}_EDIT-${edit_new_user}.csv $BK_FOLDER/ | |
echo "${CLEAN_DATE} - EDIT USER => \"${edit_new_user}\"" >> $LOG_FILE | |
echo " " | |
echo "$edit_new_user edited" | |
quit | |
else | |
echo " " | |
echo "something's ... not right. someone is messing with the data" | |
quit | |
fi | |
;; | |
4|${OPTIONS[3]} ) # delete user | |
echo " " | |
echo "delete this user?" | |
echo -n "[yes/no]: " | |
while read delete_input | |
do | |
delete_input=`trim $delete_input` | |
if [[ $delete_input = exit ]]; then | |
quit | |
elif [[ $delete_input = restart ]]; then | |
break 3 | |
elif [[ $delete_input = no ]]; then | |
echo " " | |
echo "what would you like to do?" | |
break | |
elif [[ $delete_input = yes ]]; then | |
# make sure information hasn't been changed by someone else | |
VERIFY_LINE=`sed -n "${LINE_NUMBER}p" $PASS_FILE` | |
if [ "$VERIFY_LINE" == "$LINE" ]; then | |
sed -i_${DATE}_DELETE-${USER}.csv "${LINE_NUMBER}d" $PASS_FILE | |
mv ${PASS_FILE}_${DATE}_DELETE-${USER}.csv $BK_FOLDER/ | |
echo "${CLEAN_DATE} - DELETE USER => \"${USER}\"" >> $LOG_FILE | |
echo " " | |
echo "$USER deleted" | |
quit | |
else | |
echo " " | |
echo "something's ... not right. someone is messing with the data" | |
quit | |
fi | |
else | |
echo -n "[yes/no]: " | |
fi | |
done | |
;; | |
5|${OPTIONS[4]} ) # restart | |
break 2 | |
;; | |
6|${OPTIONS[5]} ) # exit | |
quit | |
;; | |
* ) echo "pick a valid option" ;; | |
esac | |
done | |
done | |
echo " " | |
echo -e "starting over...\n" | |
done | |
quit |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
$PASS_FILE
is the only mandatory variable. It should be the path to your password.csv
file, and the file should have a format similar to the following:...where from left to right, the columns are
username
,FTP password
,website password
,website domain
, andserver
.