Created
January 18, 2024 21:00
-
-
Save hateshape/ef33ec245a9bebffacca8e880526361e to your computer and use it in GitHub Desktop.
OTP to your clipboard via CLI shenanigans and meh codes
This file contains hidden or 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 | |
################################## INFOS ################################## | |
# Depends on exported otpauth-migration://offline from Google authenticator | |
# dependencies: expect oathtool otp_export python3-protobuf python3-urllib3 xclip zbarimg | |
# shellcheck disable=SC1087 disable=SC2128 | |
########################################################################### | |
addkeys() { | |
if [[ -s "$OTPEXPORTTMP" && -n "$OTPEXPORTTMP" ]]; then | |
OTPEXPORT=$(zbarimg -q "$OTPEXPORTTMP" | sed 's#QR-Code:##g') | |
elif [[ ! -s "$OTPEXPORTTMP" && -n "$OTPEXPORTTMP" ]]; then | |
OTPEXPORT="$OTPEXPORTTMP" | |
else | |
die "something something key add error. Still your fault though." | |
fi | |
TMPOTPEXPORT="/tmp/.temp_otp_export" | |
TMPOTPEXPORTJSON="/tmp/.temp_otp_export.json" | |
if [[ -n "$OTPEXPORT" ]]; then | |
python3 "$TOOLS/otp_export/parse.py" "$OTPEXPORT" >"$TMPOTPEXPORT" | |
NAMECOUNT=$(grep -c "name:" "$TMPOTPEXPORT") | |
SECRETCOUNT=$(grep -c "otpauth:" "$TMPOTPEXPORT") | |
if [[ "$NAMECOUNT" == $SECRETCOUNT ]]; then | |
echo | |
jq -n -R -c ' | |
reduce (inputs | select(length > 0)) as $item ([]; | |
if ($item | index("otpauth")) then | |
. + [ {otpauth: $item | gsub("^ +otpauth: +"; "")} ] | |
elif ($item | index("name")) then | |
.[-1] += {name: $item | gsub("^ +name: +"; "")} | |
elif ($item | index("secret")) then | |
.[-1] += {secret: $item | gsub("^ +secret: +"; "")} | |
else | |
. | |
end | |
) | |
' "$TMPOTPEXPORT" | jq "{otp_parameters: .}" | jq 'walk(if type == "string" then gsub("^[[:space:]]+"; "") else . end)' >"$TMPOTPEXPORTJSON" | |
fi | |
fi | |
for ((i = 0; i < $(jq ".otp_parameters" "$TMPOTPEXPORTJSON" | jq length); i++)); do | |
TMPNAME=$(jq -r ".otp_parameters[$i].name" "$TMPOTPEXPORTJSON") | |
TMPSECRET=$(jq -r ".otp_parameters[$i].otpauth" "$TMPOTPEXPORTJSON" | cut -d\= -f2) | |
echo "$TMPSECRET" | gpg --quiet --symmetric --out "$OTPDIR/$TMPNAME" --batch --passphrase "$PASSPHRASE" | |
unset TMPNAME TMPSECRET | |
done | |
if [[ -s "$TMPOTPEXPORT" ]]; then rm "$TMPOTPEXPORT"; fi | |
if [[ -s "$TMPOTPEXPORTJSON" ]]; then rm "$TMPOTPEXPORTJSON"; fi | |
} | |
keyme() { | |
SECRET_NAME=$1 | |
READ_SECRET_SECRET="$(gpg --passphrase "$PASSPHRASE" --batch --quiet <"$OTPDIR/$SECRET_NAME" | sed 's#&issuer##g')" | |
oathtool --base32 --totp "$READ_SECRET_SECRET" | |
} | |
listkey() { | |
if [[ -d "$OTPDIR" ]]; then | |
ls -1 "$OTPDIR" | |
elif [[ ! -d "$OTPDIR" ]]; then | |
mkdir -p "$OTPDIR" | |
chmod 0700 "$OTPDIR" | |
ls -1 "$OTPDIR" | |
fi | |
} | |
toolsexist() { | |
APTTOOLSNEEDED="" | |
which expect &>/dev/null || APTTOOLSNEEDED+="expect," | |
which oathtool &>/dev/null || APTTOOLSNEEDED+="oathtool," | |
which zbarimg &>/dev/null || APTTOOLSNEEDED+="xclip," | |
which zbarimg &>/dev/null || APTTOOLSNEEDED+="zbarimg," | |
for PYTHONMODULE in python3-protobuf python3-urllib3; do | |
python3 -c "import $PYTHONMODULE" &>/dev/null | |
PYTHONMODULEEXISTS=$(echo $?) | |
if [[ "$PYTHONMODULEEXISTS" == 0 ]]; then | |
APTTOOLSNEEDED+="$PYTHONMODULE," | |
fi | |
unset PYTHONMODULEEXISTS | |
done | |
if [[ ! "$APTTOOLSNEEDED" == "" ]]; then | |
APTTOOLSNEEDED=$(echo $APTTOOLSNEEDED | awk 'BEGIN{FS=OFS=","}{NF--; print}') | |
echo -e "${YELLOWYELLOW}[ERROR]${WHITEWHITE} Dependencies Not Met!\n${YELLOWYELLOW}[ERROR]${WHITEWHITE} You cant do anything right, can you? If you need tools to run a script, maybe install them first, mmmmm'k? Until you have the tools, be gone${RESET}" | |
echo -e "${YELLOWYELLOW}[ERROR]${WHITEWHITE} Tools Needed:${ORANGEORANGE} $APTTOOLSNEEDED ${RESET}" | |
echo | |
exit | |
fi | |
} | |
filesexist() { | |
FILESNEEDED="" | |
# Script Specific Files | |
[[ -f "$TOOLS/otp_export/parse.py" ]] || FILESNEEDED+="otp_export§" | |
if [[ ! "$FILESNEEDED" == "" ]]; then | |
FILESNEEDED=$(echo $FILESNEEDED | awk 'BEGIN{FS=OFS="§"}{NF--; print}') | |
echo -e "${YELLOWYELLOW}[ERROR]${WHITEWHITE} Dependencies Not Met!\n${YELLOWYELLOW}[ERROR]${WHITEWHITE} You cant do anything right, can you? If you need tools to run a script, maybe install them first, mmmmm'k? Until you have the tools, be gone${RESET}" | |
echo -e "${YELLOWYELLOW}[ERROR]${WHITEWHITE} Files Needed:${ORANGEORANGE} $FILESNEEDED ${RESET}" | |
echo -e "${WHITEWHITE} => git clone https://github.com/qistoph/otp_export $TOOLS/otp_export${RESET}" | |
echo | |
exit | |
fi | |
} | |
howitdone() { | |
echo -e "${LEVEL1} Usage:${LEVEL2} $FILEBASENAME${LEVEL3} [-h]${RESET}" | |
echo -e "\n${LEVEL3} Script options${RESET}" | |
SCRIPTOPTIONS=$( | |
cat <<EOF | |
${ORANGEORANGE}-a, --add-key ${RESET}Add new key otpauth-migration://offline?data=XXX] | |
${ORANGEORANGE}-g, --get-totp ${RESET}Get OTP key by name | |
${ORANGEORANGE}-l, --list-otp ${RESET}List existing keys | |
${ORANGEORANGE}-qr, --qr-code ${RESET}Use QR code image [/path/to/qrcode] | |
EOF | |
) | |
echo -e "$SCRIPTOPTIONS" | |
echo -e "\n${RESET} Helpful options${RESET}" | |
HELPFULOPTIONS=$( | |
cat <<EOF | |
${ORANGEORANGE}-h, --help ${RESET}Print this help and exit | |
${ORANGEORANGE}-v, --verbose ${RESET}Script Debug | |
EOF | |
) | |
echo -e "$HELPFULOPTIONS\n" | |
exit | |
} | |
die() { | |
local msg=$1 | |
local code=${2-1} # default exit status 1 | |
echo -e "${ORANGEORANGE}We got us an error. It's your bad no doubt ... try again or just quit please${RESET}" | |
echo -e "${ORANGEORANGE}If you care, error information: ${WHITEWHITE}$msg${RESET}" | |
exit "$code" | |
} | |
parse_params() { | |
# default values of variables set from params | |
# Exporting GAUTH Secrets: https://support.google.com/accounts/answer/1066447?hl=en&co=GENIE.Platform%3DAndroid | |
PASSPHRASE='IF-YOU-SMART-CHANGEME-CHANGEME' | |
OTPDIR="$HOME/.config/otp" | |
TOOLS="/opt/tools" | |
FILEBASENAME=$(basename "${BASH_SOURCE[0]}") | |
# Look-n-Feels | |
RESET='\033[00m' | |
ORANGEORANGE='\e[38;5;209m' | |
YELLOWYELLOW='\e[38;5;179m' | |
WHITEWHITE='\e[38;5;15m' | |
export RESET ORANGEORANGE | |
if [[ "$#" -eq 0 ]]; then | |
howitdone | |
exit | |
fi | |
while :; do | |
case "${1-}" in | |
-h | --help) howitdone ;; | |
-v | --verbose) set -x ;; | |
-a | --add-key) | |
OTPEXPORTTMP="${2-}" | |
shift | |
;; | |
-g | --get-totp) | |
KEYNAME="${2-}" | |
shift | |
;; | |
-l | --list-otp) | |
listkey | |
;; | |
-qr | --qr-code) | |
OTPEXPORTTMP="${2-}" | |
shift | |
;; | |
-?*) die "Unknown option: $1" ;; | |
*) break ;; | |
esac | |
shift | |
done | |
args=("$@") | |
return 0 | |
} | |
parse_params "$@" | |
toolsexist | |
filesexist | |
mkdir -p "$OTPDIR" | |
if [[ -n "$OTPEXPORTTMP" ]]; then | |
addkeys $OTPEXPORTTMP | |
elif [[ -n "$KEYNAME" ]]; then | |
KEYNAME=$(echo "$KEYNAME") | |
keyme "$KEYNAME" | xargs echo -n | xclip -selection clipboard | |
elif [[ -n "$OTPEXPORTTMP" ]]; then | |
listkey | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment