-
Notifications
You must be signed in to change notification settings - Fork 1
/
oathtool_from_otpauth_uri
executable file
·147 lines (118 loc) · 3.88 KB
/
oathtool_from_otpauth_uri
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
#!/usr/bin/env sh
script_name="$0"
usage_str="$script_name [-h] [otpauth_uri] [oathtool options...]"
descr_str=\
"Invokes oathtool with the parameters from a otpauth:// uri passed as the first
parameter, or from standard input."
echo_err () {
echo "${script_name}: $*" >&2
}
# uri_get_query_value <uri> <query_key>
uri_get_query_value() {
# Remove leading part up to the end of "<query_key>="
_qkv="${1##*$2=}"
# If the string is the same, then <query_key> is not present
if [ "$_qkv" = "$1" ]; then
return 1
fi
# Remove the trailing portion of the URI (after the next "&") pass
echo "${_qkv%%&*}"
return 0
}
# uri_get_path_segment <uri> <one-based-counter>
uri_get_path_segment() {
# Isolate the path
_path="${1#*://}"
_path="${_path%%\?*}"
# Remove path segments one by one
_segment_ctr="$2"
while [ "$_segment_ctr" -gt 1 ]; do
_segment_ctr=$(( _segment_ctr - 1))
_new_path="${_path#*/}"
if [ "$_new_path" = "$_path" ]; then
# If the string remains the same, it means there are no more path
# segments to remove. It's safe to break the loop setting _path to
# an empty string, signaling the nonexistence of the segment
_path=""
break
else
_path="$_new_path"
fi
done
# Remove the remaining path
if [ -n "$_path" ]; then
echo "${_path%%/*}"
else
return 1
fi
}
# Show help and description if the first argument is -h
if [ "$1" = "-h" ]; then
echo "Usage: $usage_str"
echo "$descr_str"
exit 0
fi
# Obtain the otpauth:// uri from argument or stdin
otpauth_uri=""
if [ "${1%%://*}" = "otpauth" ]; then
otpauth_uri="$1"
shift
else
read -r otpauth_uri
if [ "${otpauth_uri%%://*}" != "otpauth" ]; then
echo_err "Input is not an otpauth:// URI. Aborting."
exit 2
fi
fi
# Parse the otpauth URI parts for passing to oathtool
# OTP Type
otp_type="$(uri_get_path_segment "$otpauth_uri" 1)"
if [ "$otp_type" != "hotp" ] && [ "$otp_type" != "totp" ]; then
echo_err "Invalid otpauth URI: Invalid type '$otp_type'. Aborting."
exit 2
fi
# Secret
secret=$(uri_get_query_value "$otpauth_uri" secret)
if [ -z "$secret" ]; then
echo_err "Missing secret parameter on URI. Aborting."
exit 2
fi
# Remove any padding from the end of the secret string
# While no padding should be included with the secret, according to the
# key uri spec, it doesn't hurt to remove it at this stage.
# Source: https://github.com/google/google-authenticator/wiki/Key-Uri-Format#secret
secret=$(echo "$secret" | sed 's/\(=\|%3D\)\+$//i')
# Algorithm, only for TOTP
if [ "$otp_type" = "totp" ]; then
totp_algorithm=$(uri_get_query_value "$otpauth_uri" algorithm)
if [ -n "$totp_algorithm" ]; then
# oathtool only supports lower-case algorithms
totp_algorithm="$(echo "$totp_algorithm" | tr "[:upper:]" "[:lower:]")"
fi
fi
# Digits (defaults to 6)
otp_digits="$(uri_get_query_value "$otpauth_uri" digits)"
otp_digits="${otp_digits:-6}"
# Counter, required, only for HOTP
if [ "$otp_type" = "hotp" ]; then
hotp_counter="$(uri_get_query_value "$otpauth_uri" counter)"
if [ -z "$hotp_counter" ]; then
echo_err "Missing counter parameter on URI. Aborting."
exit 2
fi
fi
# Period, in seconds, only for TOTP (defaults to 30)
if [ "$otp_type" = "totp" ]; then
totp_period="$(uri_get_query_value "$otpauth_uri" period)"
totp_period="${totp_period:-30}"
fi
# shellcheck disable=SC2086
# otpauth:// URIs always include the secret encoded in Base32
oathtool --base32 \
--$otp_type${totp_algorithm:+="$totp_algorithm"} \
--digits="$otp_digits" \
${hotp_counter:+--counter=$hotp_counter} \
${totp_period:+--time-step-size=${totp_period}s} \
"$@" "$secret"
# References:
# - https://github.com/google/google-authenticator/wiki/Key-Uri-Format