|
#!/bin/bash |
|
|
|
# Install Dependencies: sudo apt install diceware pwgen xsel |
|
|
|
INPUT="\033[1;33m" # Yellow for input |
|
OUTPUT="\033[0;36m" # Cyan for output |
|
ERROR="\033[0;31m" |
|
WARN="\033[1;93m" |
|
SUCCESS="\033[1;92m" |
|
RESET="\033[0m" # Reset color |
|
WIPE="\033[1A\033[0G" # Move cursor up & erase line |
|
|
|
echo -e "${SUCCESS}UNIQUE PASSWORD GENERATOR${RESET}" |
|
|
|
GET_PROMPT() { |
|
local PROMPT="$1" |
|
local DEFAULT="$2" |
|
declare -n RESULT="$3" |
|
|
|
echo -ne "${PROMPT}${INPUT}" |
|
IFS= read -r VALUE |
|
|
|
RESULT=${VALUE:-"$DEFAULT"} |
|
echo -ne "${RESET}${WIPE}${PROMPT}${OUTPUT}${RESULT}${RESET}\n" |
|
|
|
eval "$3=\"$RESULT\"" |
|
} |
|
|
|
GET_PROMPT "Domain or device name: " "default.com" DOMAIN |
|
GET_PROMPT "Login username: " "username" USER |
|
GET_PROMPT "Password length: " "128" LENGTH |
|
|
|
TEXT="Complexity: " |
|
echo "Choose your password character complexity: " |
|
PS3=$(echo -ne "${TEXT}${INPUT}") |
|
options=("Simple" "Special") |
|
select opt in "${options[@]}" |
|
do |
|
case $opt in |
|
"Simple") |
|
COMPLEXITY="Simple" |
|
break |
|
;; |
|
"Special") |
|
COMPLEXITY="Special" |
|
break |
|
;; |
|
*) echo -e "Invalid option $REPLY";; |
|
esac |
|
done |
|
echo -ne "${RESET}${WIPE}${TEXT}${OUTPUT}${COMPLEXITY}${RESET}\n" |
|
|
|
SEED="$DOMAIN+$USER+$SALT" |
|
|
|
if [ "$COMPLEXITY" == "Simple" ]; |
|
then PASS=$(pwgen $LENGTH 1 -H <((echo $SEED)) -cn); |
|
else PASS=$(pwgen $LENGTH 1 -H <((echo $SEED)) -cnsy); |
|
fi |
|
|
|
xsel --clipboard --clear |
|
|
|
GET_SALT() { |
|
local PROMPT="$1" |
|
declare -n RESULT="$2" |
|
local ALLOW_GENERATION="$3" # Flag to allow/disallow auto-generation |
|
|
|
echo -ne "${PROMPT}${INPUT}" |
|
RESULT="" |
|
local MASK="" |
|
|
|
# Read input character-by-character, displaying `*` |
|
while IFS= read -r -s -n1 CHAR; do |
|
[[ -z "$CHAR" ]] && break # Stop on Enter |
|
|
|
if [[ "$CHAR" == $'\x7f' ]]; then # Handle Backspace |
|
if [[ -n "$RESULT" ]]; then |
|
RESULT="${RESULT:0:-1}" # Remove last character |
|
MASK="${MASK:0:-1}" # Remove last '*' |
|
echo -ne "\b \b" # Move cursor back, erase '*' |
|
fi |
|
else |
|
RESULT+="$CHAR" # Store actual input |
|
MASK+="*" # Store mask |
|
echo -ne "*" # Display a star for each character |
|
fi |
|
done |
|
|
|
# If no input and auto-generation is allowed, generate a salt |
|
if [[ -z "$RESULT" && "$ALLOW_GENERATION" == "true" ]]; then |
|
RESULT=$(diceware -n 8 -d "_" -s 4 2>/dev/null) |
|
echo "$RESULT" | xsel --clipboard --input |
|
echo -e "$WARN[SALT COPIED TO CLIPBOARD]$RESET" |
|
MASK=$(printf '*%.0s' $(seq ${#RESULT})) # Generate the same number of '*' |
|
elif [[ -z "$RESULT" && "$ALLOW_GENERATION" == "false" ]]; then |
|
echo -e "$ERROR[Error: Salt confirmation cannot be empty]$RESET" |
|
return 1 # Exit function with error |
|
fi |
|
|
|
# Overwrite input with masked output |
|
echo -ne "\n${RESET}${WIPE}${PROMPT}${OUTPUT}${MASK}${RESET}\n" |
|
} |
|
|
|
# Get initial salt (allow auto-generation) |
|
GET_SALT "Salt phrase (blank to gen): " SALT "true" |
|
|
|
# Get confirmation (must match SALT) |
|
while true; do |
|
GET_SALT "Confirm salt phrase: " SALT_CONFIRMATION "false" |
|
|
|
if [[ "$SALT" == "$SALT_CONFIRMATION" ]]; then |
|
echo -e "$SUCCESS[SALT CONFIRMED]$RESET" |
|
|
|
# Check if clipboard is empty before clearing |
|
CLIPBOARD_CONTENT="$(xsel --clipboard --output 2>/dev/null)" |
|
|
|
if [[ -n "$CLIPBOARD_CONTENT" ]]; then |
|
xsel --clipboard --clear |
|
echo -e "$WARN[CLIPBOARD CLEARED]$RESET" |
|
fi |
|
break |
|
else |
|
echo -e "$ERROR[Error: Salt phrases do not match. Try again.]$RESET" |
|
fi |
|
done |
|
|
|
echo -n "$PASS" | xsel --clipboard --input |
|
echo -e "$WARN[COPIED PASSWORD TO CLIPBOARD]$RESET" |
|
echo "Clipboard will auto-clear in 10 seconds..." |
|
sleep 10 && xsel --clipboard --clear |
|
echo -e "$SUCCESS[CLIPBOARD CLEARED]$RESET" |