Remove otp_insert_spec and related insert commands
This commit is contained in:
parent
045214ea38
commit
318febc9ec
175
otp.bash
175
otp.bash
|
@ -18,17 +18,6 @@
|
|||
|
||||
OATH=$(which oathtool)
|
||||
|
||||
otp_urlencode() {
|
||||
local LANG=C
|
||||
for ((i=0; i<${#1}; i++)); do
|
||||
if [[ ${1:$i:1} =~ ^[a-zA-Z0-9\.\~_-]$ ]]; then
|
||||
printf "%s" "${1:$i:1}"
|
||||
else
|
||||
printf '%%%02X' "'${1:$i:1}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Parse a Key URI per: https://github.com/google/google-authenticator/wiki/Key-Uri-Format
|
||||
# Vars are consumed by caller
|
||||
# shellcheck disable=SC2034
|
||||
|
@ -47,6 +36,7 @@ otp_parse_uri() {
|
|||
|
||||
otp_accountname=${BASH_REMATCH[6]}
|
||||
[[ -z $otp_accountname ]] && otp_accountname=${BASH_REMATCH[4]} || otp_issuer=${BASH_REMATCH[4]}
|
||||
[[ -z $otp_accountname ]] && die "Invalid key URI (missing accountname): $otp_uri"
|
||||
|
||||
local p=${BASH_REMATCH[7]}
|
||||
local IFS=\&; local params=(${p[@]}); unset IFS
|
||||
|
@ -72,49 +62,6 @@ otp_parse_uri() {
|
|||
[[ "$otp_type" == 'hotp' ]] && [[ ! "$otp_counter" =~ $pattern ]] && die "Invalid key URI (missing counter): $otp_uri"
|
||||
}
|
||||
|
||||
otp_build_uri() {
|
||||
local type="$1" issuer="$2" accountname="$3" secret="$4" algorithm="$5" \
|
||||
digits="$6" period="$7" counter="$8"
|
||||
|
||||
local uri="otpauth://$type/"
|
||||
|
||||
local pattern='^[^:]+$'
|
||||
if [[ -n "$issuer" ]]; then
|
||||
[[ "$issuer" =~ $pattern ]] || die "Invalid character in issuer: ':'"
|
||||
issuer=$(otp_urlencode "$issuer")
|
||||
fi
|
||||
|
||||
[[ -z "$accountname" ]] && die "Missing accountname"
|
||||
[[ "$accountname" =~ $pattern ]] || die "Invalid character in accountname: ':'"
|
||||
accountname=$(otp_urlencode "$accountname")
|
||||
|
||||
if [[ -n "$issuer" ]]; then
|
||||
uri+="$issuer:$accountname"
|
||||
else
|
||||
uri+="$accountname"
|
||||
fi
|
||||
|
||||
[[ -z "$secret" ]] && die "Missing secret"; uri+="?secret=$secret"
|
||||
|
||||
case "$1" in
|
||||
totp)
|
||||
[[ -n "$algorithm" ]] && uri+="&algorithm=$algorithm"
|
||||
[[ -n "$digits" ]] && uri+="&digits=$digits"
|
||||
[[ -n "$period" ]] && uri+="&period=$period"
|
||||
;;
|
||||
|
||||
hotp)
|
||||
[[ -z "$counter" ]] && die "Missing counter"; uri+="&counter=$counter"
|
||||
;;
|
||||
|
||||
*) die "Invalid OTP type '$1'" ;;
|
||||
esac
|
||||
|
||||
[[ -n "$issuer" ]] && uri+="&issuer=$issuer"
|
||||
|
||||
echo "$uri"
|
||||
}
|
||||
|
||||
otp_insert() {
|
||||
local path="${1%/}"
|
||||
local passfile="$PREFIX/$path.gpg"
|
||||
|
@ -132,103 +79,23 @@ otp_insert() {
|
|||
|
||||
$GPG -e "${GPG_RECIPIENT_ARGS[@]}" -o "$passfile" "${GPG_OPTS[@]}" <<<"$contents" || die "OTP secret encryption aborted."
|
||||
|
||||
[[ -z "$message" ]] && message="Add OTP secret for $path to store."
|
||||
|
||||
git_add_file "$passfile" "$message"
|
||||
}
|
||||
|
||||
otp_insert_uri() {
|
||||
local opts force=0
|
||||
opts="$($GETOPT -o f -l force -n "$PROGRAM" -- "$@")"
|
||||
local err=$?
|
||||
eval set -- "$opts"
|
||||
while true; do case $1 in
|
||||
-f|--force) force=1; shift ;;
|
||||
--) shift; break ;;
|
||||
esac done
|
||||
|
||||
[[ $err -ne 0 || $# -ne 2 ]] && die "Usage: $PROGRAM $COMMAND insert [--force,-f] uri pass-name"
|
||||
|
||||
local uri="$1"
|
||||
|
||||
otp_parse_uri "$uri"
|
||||
|
||||
otp_insert "$2" $force "$otp_uri"
|
||||
}
|
||||
|
||||
otp_insert_spec() {
|
||||
local opts contents secret issuer accountname algorithm period digits counter force=0
|
||||
local type="$1"; shift
|
||||
|
||||
opts="$($GETOPT -o s:i:n:a:p:d:f -l secret:,issuer:,accountname:,algorithm:,period:,digits:,force -n "$PROGRAM" -- "$@")"
|
||||
local err=$?
|
||||
eval set -- "$opts"
|
||||
while true; do case "$1" in
|
||||
-s|--secret) secret="$2"; shift 2 ;;
|
||||
-i|--issuer) issuer="$2"; shift 2 ;;
|
||||
-n|--accountname) accountname="$2"; shift 2 ;;
|
||||
-a|--algorithm) algorithm="$2"; shift 2 ;;
|
||||
-p|--period) period="$2"; shift 2 ;;
|
||||
-d|--digits) digits="$2"; shift 2 ;;
|
||||
-f|--force) force=1; shift ;;
|
||||
--) shift; break ;;
|
||||
esac done
|
||||
|
||||
[[ $type == "totp" && ($err -ne 0 || $# -ne 1) ]] &&
|
||||
die "Usage: $PROGRAM $COMMAND insert totp [--secret=key,s key] [--issuer=issuer,-i issuer] [--accountname=name,-n name] [--algorithm=algorithm,-a algorithm] [--period=seconds,-p seconds] [--digits=digits,-d digits] [--force,-f] pass-name"
|
||||
|
||||
[[ $type == "hotp" && ($err -ne 0 || $# -ne 2) ]] &&
|
||||
die "Usage: $PROGRAM $COMMAND insert hotp [--secret=key,s key] [--issuer=issuer,-i issuer] [--accountname=accountname,-n accountname] [--digits=digits,-d digits] [--force,-f] pass-name counter"
|
||||
|
||||
local path="$1" counter="$2"
|
||||
|
||||
[[ -n "$algorithm" ]] && case $algorithm in
|
||||
sha1|sha256|sha512) ;;
|
||||
*) die "Invalid algorithm '$algorithm'. May be one of 'sha1', 'sha256', or 'sha512'" ;;
|
||||
esac
|
||||
|
||||
[[ -n "$digits" ]] && case $digits in
|
||||
6|8) ;;
|
||||
*) die "Invalid digits '$digits'. May be one of '6' or '8'" ;;
|
||||
esac
|
||||
|
||||
if [[ -z $secret ]]; then
|
||||
read -r -p "Enter secret (base32-encoded): " -s secret || die "Missing secret"
|
||||
fi
|
||||
|
||||
# Populate issuer and accountname from either options or path
|
||||
if [[ -z $accountname ]]; then
|
||||
accountname="$(basename "$path")"
|
||||
if [[ -z "$issuer" ]]; then
|
||||
issuer="$(basename "$(dirname "$path")")"
|
||||
[[ "$issuer" == "." ]] && unset issuer
|
||||
fi
|
||||
fi
|
||||
|
||||
local uri; uri=$(otp_build_uri "$type" "$issuer" "$accountname" "$secret" "$algorithm" "$period" "$digits" "$counter")
|
||||
|
||||
otp_insert "$1" $force "$uri"
|
||||
}
|
||||
|
||||
cmd_otp_usage() {
|
||||
cat <<-_EOF
|
||||
Usage:
|
||||
$PROGRAM otp [show] [--clip,-c] pass-name
|
||||
Generate an OTP code and optionally put it on the clipboard.
|
||||
If put on the clipboard, it will be cleared in $CLIP_TIME seconds.
|
||||
$PROGRAM otp insert totp [--secret=key,-s key] [--algorithm alg,-a alg]
|
||||
[--period=seconds,-p seconds]
|
||||
[--digits=digits,-d digits] [--force,-f] pass-name
|
||||
Insert new TOTP secret. Prompt before overwriting existing password
|
||||
$PROGRAM otp insert [--force,-f] uri pass-name
|
||||
Insert new OTP key URI. Prompt before overwriting existing password
|
||||
unless forced.
|
||||
$PROGRAM otp insert hotp [--secret=secret,-s secret]
|
||||
[--digits=digits,-d digits] [--force,-f]
|
||||
pass-name counter
|
||||
Insert new HOTP secret with initial counter. Prompt before overwriting
|
||||
existing password unless forced.
|
||||
$PROGRAM otp uri [--clip,-c] [--qrcode,-q] pass-name
|
||||
Create a secret key URI suitable for importing into other TOTP clients.
|
||||
Optionally, put it on the clipboard, or display a QR code.
|
||||
Display the key URI stored in pass-name. Optionally, put it on the
|
||||
clipboard, or display a QR code.
|
||||
$PROGRAM otp validate uri
|
||||
Test if the given URI is a valid OTP key URI.
|
||||
|
||||
More information may be found in the pass-otp(1) man page.
|
||||
_EOF
|
||||
|
@ -236,13 +103,27 @@ _EOF
|
|||
}
|
||||
|
||||
cmd_otp_insert() {
|
||||
case "$1" in
|
||||
totp|hotp) otp_insert_spec "$@" ;;
|
||||
*) otp_insert_uri "$@" ;;
|
||||
esac
|
||||
local opts force=0
|
||||
opts="$($GETOPT -o f -l force -n "$PROGRAM" -- "$@")"
|
||||
local err=$?
|
||||
eval set -- "$opts"
|
||||
while true; do case $1 in
|
||||
-f|--force) force=1; shift ;;
|
||||
--) shift; break ;;
|
||||
esac done
|
||||
|
||||
[[ $err -ne 0 || $# -ne 2 ]] && die "Usage: $PROGRAM $COMMAND insert [--force,-f] uri pass-name"
|
||||
|
||||
local uri="$1"
|
||||
|
||||
otp_parse_uri "$uri"
|
||||
|
||||
otp_insert "$2" $force "$otp_uri" "Add OTP secret for $2 to store."
|
||||
}
|
||||
|
||||
cmd_otp_code() {
|
||||
[[ -z "$OATH" ]] && die "Failed to generate OTP code: oathtool is not installed."
|
||||
|
||||
local opts clip=0
|
||||
opts="$($GETOPT -o c -l clip -n "$PROGRAM" -- "$@")"
|
||||
local err=$?
|
||||
|
@ -272,15 +153,15 @@ cmd_otp_code() {
|
|||
totp)
|
||||
cmd="$OATH -b --totp"
|
||||
[[ -n "$otp_algorithm" ]] && cmd+="=$otp_algorithm"
|
||||
[[ -n "$otp_period" ]] && cmd+=" --time-step-size=$period"s
|
||||
[[ -n "$otp_digits" ]] && cmd+=" --digits=$digits"
|
||||
[[ -n "$otp_period" ]] && cmd+=" --time-step-size=$otp_period"s
|
||||
[[ -n "$otp_digits" ]] && cmd+=" --digits=$otp_digits"
|
||||
cmd+=" $otp_secret"
|
||||
;;
|
||||
|
||||
hotp)
|
||||
local counter=$((otp_counter+1))
|
||||
cmd="$OATH -b --hotp --counter=$counter"
|
||||
[[ -n "$otp_digits" ]] && cmd+=" --digits=$digits"
|
||||
[[ -n "$otp_digits" ]] && cmd+=" --digits=$otp_digits"
|
||||
cmd+=" $otp_secret"
|
||||
;;
|
||||
esac
|
||||
|
|
66
pass-otp.1
66
pass-otp.1
|
@ -23,18 +23,18 @@ utility with the
|
|||
command for adding OTP secrets, generating OTP codes, and displaying secret key
|
||||
URIs using the standard \fIotpauth://\fP scheme.
|
||||
|
||||
If no COMMAND is specified, COMMAND defaults to \fBshow\fP.
|
||||
If no COMMAND is specified, COMMAND defaults to \fBcode\fP.
|
||||
|
||||
.SH COMMANDS
|
||||
|
||||
.TP
|
||||
\fBotp show\fP [ \fI--clip\fP, \fI-c\fP ] \fIpass-name\fP
|
||||
\fBotp code\fP [ \fI--clip\fP, \fI-c\fP ] \fIpass-name\fP
|
||||
|
||||
Generate and print an OTP code from the secret key stored in \fIpass-name\fP. If
|
||||
\fI--clip\fP or \fI-c\fP is specified, do not print the code but instead copy it to the clipboard using
|
||||
.BR xclip (1)
|
||||
and then restore the clipboard after 45 (or \fIPASSWORD_STORE_CLIP_TIME\fP)
|
||||
seconds.
|
||||
seconds. This command is alternatively named \fBshow\fP.
|
||||
|
||||
.TP
|
||||
\fBotp insert\fP [ \fI--force\fP, \fI-f\fP ] \fIuri\fP \fIpass-name\fP
|
||||
|
@ -49,31 +49,11 @@ Prompt before overwriting an existing password, unless
|
|||
\fBadd\fP.
|
||||
|
||||
.TP
|
||||
\fBotp insert totp\fP [ \fI--secret\fP=\fIkey\fP, \fI-s\fP \fIkey\fP ] [ \fI--issuer\fP=\fIissuer\fP, \fI-i\fP \fIissuer\fP ] [ \fI--accountname\fP=\fIname\fP, \fI-n\fP \fIname\fP ] [ \fI--algorithm\fP=\fIalgorithm\fP, \fI-a\fP \fIalgorithm\fP ] [ \fI--period\fP=\fIperiod\fP, \fI-p\fP \fIperiod\fP ] [ \fI--digits\fP=\fIdigits\fP, \fI-d\fP \fIdigits\fP ] [ \fI--force\fP, \fI-f\fP ] \fIpass-name\fP
|
||||
\fBotp uri\fP [ \fI--clip\fP, \fI-c\fP | \fI--qrcode\fP, \fI-q\fP ] \fIpass-name\fP
|
||||
|
||||
Insert a new TOTP secret into the password store called \fIpass-name\fP. If
|
||||
\fI--secret\fP or \fI-s\fP are not specified, this will read \fIKEY\fP from
|
||||
standard in. Prompt before overwriting an existing password, unless
|
||||
\fI--force\fP or \fI-f\fP is specified. This command is alternatively named
|
||||
\fBadd totp\fP.
|
||||
|
||||
.TP
|
||||
\fBotp insert hotp\fP [ \fI--secret\fP=\fIkey\fP, \fI-s\fP \fIkey\fP ] [ \fI--issuer\fP=\fIissuer\fP, \fI-i\fP \fIissuer\fP ] [ \fI--accountname\fP=\fIname\fP, \fI-n\fP \fIname\fP ] [ \fI--digits\fP=\fIdigits\fP, \fI-d\fP \fIdigits\fP ] [ \fI--force\fP, \fI-f\fP ] \fIpass-name\fP \fIcounter\fP
|
||||
|
||||
Insert a new HOTP secret into the password store called \fIpass-name\fP. A
|
||||
\fIcounter\fP argument is required, which is an integer specifying the initial
|
||||
HOTP counter stored alongside the secret. If
|
||||
\fI--secret\fP or \fI-s\fP are not specified, this will read \fIKEY\fP from
|
||||
standard in. Prompt before overwriting an existing password, unless
|
||||
\fI--force\fP or \fI-f\fP is specified. This command is alternatively named
|
||||
\fBadd hotp\fP.
|
||||
|
||||
.TP
|
||||
\fBotp uri\fP [ \fI--clip\fP, \fI-c\fP | \fI--qrcode\fP, \fI-q\fP ] pass-name
|
||||
|
||||
Create and print a URI encoding the secret key and OTP parameters using the
|
||||
standard \fIotpauth://\fP scheme. If \fI--clip\fP or \fI-c\fP is specified, do
|
||||
not print the URI but instead copy it to the clipboard using
|
||||
Print the key URI stored in \fIpass-name\fP to stdout. If \fI--clip\fP or
|
||||
\fI-c\fP is specified, do not print the URI but instead copy it to the clipboard
|
||||
using
|
||||
.BR xclip (1)
|
||||
and then restore the clipboard after 45 (or \fIPASSWORD_STORE_CLIP_TIME\fP)
|
||||
seconds. If \fI--qrcode\fP or \fI-q\fP is specified, do not print the URI but
|
||||
|
@ -81,6 +61,14 @@ instead display a QR code using
|
|||
.BR qrencode (1)
|
||||
either to the terminal or graphically if supported.
|
||||
|
||||
.TP
|
||||
\fBotp validate\fP \fIuri\fP
|
||||
|
||||
Test a URI string for validity according to the Key Uri Format. For more
|
||||
information about this format, see the documentation at
|
||||
.UR https://\:github.\:com/\:google/\:google-authenticator/\:wiki/\:Key-Uri-Format
|
||||
.UE .
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
.TP
|
||||
|
@ -89,30 +77,10 @@ Put the OTP code in the clipboard.
|
|||
|
||||
.TP
|
||||
\fB\-f\fP, \fB--force\fP
|
||||
Force to update and do not wait for user instruction.
|
||||
Force update and do not wait for user instruction.
|
||||
|
||||
.TP
|
||||
\fB-s\fP \fIkey\fP, \fB--secret\fR=\fIkey\fP
|
||||
Provide a secret \fIkey\fP. This key must be base32-encoded.
|
||||
|
||||
.TP
|
||||
\fB-a\fP \fIalgorithm\fP, \fB--algorithm\fP=\fIalgorithm\fP
|
||||
Specify the \fIalgorithm\fP for a TOTP secret. Accepted values are \fIsha1\fP,
|
||||
\fIsha256\fP, and \fIsha512\fP. This option defaults to \fIsha1\fP.
|
||||
|
||||
.TP
|
||||
\fB-p\fP \fIperiod\fP, \fB--period\fP=\fIperiod\fP
|
||||
Specify the \fIperiod\fP for a TOTP secret, in seconds. This option defaults to
|
||||
\fI30\fP.
|
||||
|
||||
.TP
|
||||
\fB-d\fP \fIdigits\fP, \fB--digits\fP=\fIdigits\fP
|
||||
Specify the number of \fIdigits\fP this secret should generate when used with
|
||||
\fBshow\fP. Accepted values are \fI6\fP and \fI8\fP. This option defaults to
|
||||
\fI6\fP.
|
||||
|
||||
.TP
|
||||
\fB\-h\fB, \-\-help\fR
|
||||
\fBhelp\fP, \fB\-h\fB, \-\-help\fR
|
||||
Show usage message.
|
||||
|
||||
.SH SEE ALSO
|
||||
|
|
|
@ -32,42 +32,4 @@ test_expect_success 'Force overwrites key URI' '
|
|||
[[ $("$PASS" show passfile) == "$uri2" ]]
|
||||
'
|
||||
|
||||
test_expect_success 'Inserts a basic TOTP key' '
|
||||
uri="otpauth://totp/passfile?secret=AAAAAAAAAAAAAAAAAAAAA"
|
||||
|
||||
test_pass_init &&
|
||||
"$PASS" otp insert totp -s AAAAAAAAAAAAAAAAAAAAA passfile &&
|
||||
[[ $("$PASS" show passfile) == "$uri" ]]
|
||||
'
|
||||
|
||||
test_expect_success 'Inserts a TOTP key with issuer in path' '
|
||||
uri="otpauth://totp/example.com:passfile?secret=AAAAAAAAAAAAAAAAAAAAA&issuer=example.com"
|
||||
|
||||
test_pass_init &&
|
||||
"$PASS" otp insert totp -s AAAAAAAAAAAAAAAAAAAAA example.com/passfile &&
|
||||
[[ $("$PASS" show example.com/passfile) == "$uri" ]]
|
||||
'
|
||||
|
||||
test_expect_success 'Inserts a TOTP key with issuer in nested path' '
|
||||
uri="otpauth://totp/foo:passfile?secret=AAAAAAAAAAAAAAAAAAAAA&issuer=foo"
|
||||
|
||||
test_pass_init &&
|
||||
"$PASS" otp insert totp -s AAAAAAAAAAAAAAAAAAAAA example.com/foo/passfile &&
|
||||
[[ $("$PASS" show example.com/foo/passfile) == "$uri" ]]
|
||||
'
|
||||
|
||||
test_expect_success 'Inserts a TOTP key with spaces in path' '
|
||||
uri="otpauth://totp/example%20dot%20com:pass%20file?secret=AAAAAAAAAAAAAAAAAAAAA&issuer=example%20dot%20com"
|
||||
test_pass_init &&
|
||||
"$PASS" otp insert totp -s AAAAAAAAAAAAAAAAAAAAA "example dot com/pass file" &&
|
||||
[[ $("$PASS" show "example dot com/pass file") == "$uri" ]]
|
||||
'
|
||||
|
||||
test_expect_success 'Commits insert to git' '
|
||||
test_pass_init &&
|
||||
pass git init &&
|
||||
"$PASS" otp insert totp -s AAAAAAAAAAAAAAAAAAAAA passfile &&
|
||||
git log --no-decorate -1 | grep "Add OTP secret for passfile to store."
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
Loading…
Reference in New Issue