Skip to content

Instantly share code, notes, and snippets.

@lobianco
Last active January 4, 2016 08:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lobianco/8599515 to your computer and use it in GitHub Desktop.
Save lobianco/8599515 to your computer and use it in GitHub Desktop.
a simple bash script for managing passwords
#!/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
@lobianco
Copy link
Author

$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:

"user1","123$%^","abcdefghij","website.com","server1"
"user2","456&*(","klmnopqr","something.com","server3"
"user3","789!@#","stuvwxyz","asite.com","server2"

...where from left to right, the columns are username, FTP password, website password, website domain, and server.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment