diff options
-rw-r--r-- | README.md | 20 | ||||
-rwxr-xr-x | otp.bash | 45 | ||||
-rw-r--r-- | pass-otp.1 | 13 | ||||
-rwxr-xr-x | test/code.t | 4 | ||||
-rwxr-xr-x | test/insert.t | 91 | ||||
-rwxr-xr-x | test/uri.t | 2 |
6 files changed, 109 insertions, 66 deletions
@@ -31,22 +31,25 @@ More information may be found in the pass-otp(1) man page. ## Examples -Insert a TOTP token: +Prompt for an OTP token, hiding input: ``` -$ pass otp insert otpauth://totp/totp-secret?secret=AAAAAAAAAAAAAAAA totp-secret +$ pass otp insert totp-secret +Enter otpauth:// URI for totp-secret: +Retype otpauth:// URI for totp-secret: ``` -Have `pass-otp` prompt you for a token (avoids potential shell history leakage): +Prompt for an OTP token, echoing input: ``` -$ pass otp insert totp-secret +$ pass otp insert -e totp-secret +Enter otpauth:// URI for totp-secret: otpauth://totp/totp-secret?secret=AAAAAAAAAAAAAAAA&issuer=totp-secret ``` Pipe an `otpauth://` URI into a passfile: ``` -$ cat totp-uri.txt | pass otp insert totp-secret +$ cat totp-secret.txt | pass otp insert totp-secret ``` Use [zbar](http://zbar.sourceforge.net/) to decode a QR image into a passfile: @@ -89,12 +92,19 @@ $ pass otp uri -q totp-secret ## Installation +### From git + ``` git clone https://github.com/tadfisher/pass-otp cd pass-otp sudo make install ``` +### Arch Linux + +`pass-otp` is available in the +[Arch User Repository](https://aur.archlinux.org/packages/pass-otp/). + ## Requirements - `pass` 1.7.0 or later for extenstion support @@ -90,10 +90,10 @@ Usage: 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 [--force,-f] [--echo,-e] [uri] pass-name - Insert a new OTP key URI. If one is not supplied, it will be read from - stdin. Optionally, echo the input. Prompt before overwriting existing - password unless forced. + $PROGRAM otp insert [--force,-f] [--echo,-e] [pass-name] + Prompt for and insert a new OTP key URI. If pass-name is not supplied, + use the URI label. Optionally, echo the input. Prompt before overwriting + existing password unless forced. This command accepts input from stdin. $PROGRAM otp uri [--clip,-c] [--qrcode,-q] pass-name Display the key URI stored in pass-name. Optionally, put it on the @@ -118,31 +118,38 @@ cmd_otp_insert() { --) shift; break ;; esac done - [[ $err -ne 0 || ($# -ne 1 && $# -ne 2) ]] && die "Usage: $PROGRAM $COMMAND insert [--force,-f] [uri] pass-name" + [[ $err -ne 0 ]] && die "Usage: $PROGRAM $COMMAND insert [--force,-f] [pass-name]" - local path uri + local prompt path uri if [[ $# -eq 1 ]]; then path="$1" - if [[ -t 0 ]]; then - if [[ $echo -eq 0 ]]; then - read -r -p "Enter otpauth:// URI for $path: " -s uri || exit 1 - echo - read -r -p "Retype otpauth:// URI for $path: " -s uri_again || exit 1 - echo - [[ "$uri" == "$uri_again" ]] || die "Error: the entered URIs do not match." - else - read -r -p "Enter otpauth:// URI for $path: " -e uri - fi + prompt="$path" + else + prompt="this token" + fi + + if [[ -t 0 ]]; then + if [[ $echo -eq 0 ]]; then + read -r -p "Enter otpauth:// URI for $prompt: " -s uri || exit 1 + echo + read -r -p "Retype otpauth:// URI for $prompt: " -s uri_again || exit 1 + echo + [[ "$uri" == "$uri_again" ]] || die "Error: the entered URIs do not match." else - read -r uri + read -r -p "Enter otpauth:// URI for $prompt: " -e uri fi else - uri="$1" - path="$2" + read -r uri fi otp_parse_uri "$uri" + if [[ -z "$path" ]]; then + [[ -n "$otp_issuer" ]] && path+="$otp_issuer/" + path+="$otp_accountname" + yesno "Insert into $path?" + fi + otp_insert "$path" $force "$otp_uri" "Add OTP secret for $path to store." } @@ -37,16 +37,17 @@ and then restore the clipboard after 45 (or \fIPASSWORD_STORE_CLIP_TIME\fP) seconds. This command is alternatively named \fBshow\fP. .TP -\fBotp insert\fP [ \fI--force\fP, \fI-f\fP ] [ \fI--echo\fP, \fI-e\fP ] [ \fIuri\fP ] \fIpass-name\fP +\fBotp insert\fP [ \fI--force\fP, \fI-f\fP ] [ \fI--echo\fP, \fI-e\fP ] [ \fIpass-name\fP ] -Insert a new OTP secret specified by \fIuri\fP into the password store at -\fIpass-name\fP. \fIuri\fP must be formatted according to the Key Uri Format; +Prompt for and insert a new OTP secret into the password store at +\fIpass-name\fP. The secret must be formatted according to the Key Uri Format; see the documentation at .UR https://\:github.\:com/\:google/\:google-authenticator/\:wiki/\:Key-Uri-Format .UE . -If \fIuri\fP is not specified, it will be consumed from stdin; specify -\fI--echo\fP or \fI-e\fP to show a visible prompt when running this command -interactively. Prompt before overwriting an existing password, unless +The URI is consumed from stdin; specify \fI--echo\fP or \fI-e\fP to echo input +when running this command interactively. If \fIpass-name\fP is not specified, +convert the \fIissuer:accountname\fP URI label to a path in the form of +\fIisser/accountname\fP. Prompt before overwriting an existing password, unless \fI--force\fP or \fI-f\fP is specified. This command is alternatively named \fBadd\fP. diff --git a/test/code.t b/test/code.t index 095cdd5..4faea03 100755 --- a/test/code.t +++ b/test/code.t @@ -8,7 +8,7 @@ test_expect_success 'Generates TOTP code' ' uri="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example" test_pass_init && - "$PASS" otp insert "$uri" passfile && + "$PASS" otp insert passfile <<< "$uri" && code=$("$PASS" otp passfile) && [[ ${#code} -eq 6 ]] ' @@ -18,7 +18,7 @@ test_expect_success 'Generates HOTP code and increments counter' ' inc="otpauth://hotp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&counter=11&issuer=Example" test_pass_init && - "$PASS" otp insert "$uri" passfile && + "$PASS" otp insert passfile <<< "$uri" && code=$("$PASS" otp passfile) && [[ ${#code} -eq 6 ]] && [[ $("$PASS" otp uri passfile) == "$inc" ]] diff --git a/test/insert.t b/test/insert.t index b4af4f5..e0d2441 100755 --- a/test/insert.t +++ b/test/insert.t @@ -4,87 +4,112 @@ export test_description="Tests pass otp insert commands" . ./setup.sh -test_expect_success 'Inserts a key URI' ' +test_expect_success 'Reads non-terminal input' ' uri="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example" test_pass_init && - "$PASS" otp insert "$uri" passfile && + "$PASS" otp insert passfile <<< "$uri" && [[ $("$PASS" show passfile) == "$uri" ]] ' -test_expect_success 'Prompts before overwriting key URI' ' - uri1="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Foo" - uri2="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Bar" +test_expect_success 'Reads terminal input in noecho mode' ' + uri="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example" test_pass_init - "$PASS" otp insert "$uri1" passfile expect <<EOD - spawn "$PASS" otp insert "$uri2" passfile + spawn "$PASS" otp insert passfile expect { - "An entry already exists" { - send "n\r" + "Enter" { + send "$uri\r" + exp_continue + } + "Retype" { + send "$uri\r" exp_continue } eof } EOD - [[ $("$PASS" show passfile) == "$uri1" ]] -' - -test_expect_success 'Force overwrites key URI' ' - uri1="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Foo" - uri2="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Bar" - - test_pass_init && - "$PASS" otp insert "$uri1" passfile && - "$PASS" otp insert -f "$uri2" passfile && - [[ $("$PASS" show passfile) == "$uri2" ]] + [[ $("$PASS" show passfile) == "$uri" ]] ' -test_expect_success 'Reads non-terminal input' ' +test_expect_success 'Reads terminal input in echo mode' ' uri="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example" - test_pass_init && - "$PASS" otp insert passfile <<< "$uri" && + test_pass_init + expect <<EOD + spawn "$PASS" otp insert -e passfile + expect { + "Enter" { + send "$uri\r" + exp_continue + } + eof + } +EOD [[ $("$PASS" show passfile) == "$uri" ]] ' -test_expect_success 'Reads terminal input in noecho mode' ' - uri="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example" +test_expect_success 'Prompts before overwriting key URI' ' + uri1="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Foo" + uri2="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Bar" test_pass_init + "$PASS" otp insert passfile <<< "$uri1" || return 1 expect <<EOD - spawn "$PASS" otp insert passfile + spawn "$PASS" otp insert -e passfile expect { "Enter" { - send "$uri\r" + send "$uri2\r" exp_continue } - "Retype" { - send "$uri\r" + "An entry already exists" { + send "n\r" exp_continue } eof } EOD - [[ $("$PASS" show passfile) == "$uri" ]] + [[ $("$PASS" show passfile) == "$uri1" ]] ' -test_expect_success 'Reads terminal input in echo mode' ' +test_expect_success 'Generates default pass-name from label' ' + uri="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example" + + test_pass_init + "$PASS" otp insert <<< "$uri" + [[ $("$PASS" show "Example/alice@google.com") == "$uri" ]] +' + +test_expect_success 'Prompts when inserting default pass-name from terminal' ' uri="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example" test_pass_init expect <<EOD - spawn "$PASS" otp insert -e passfile + spawn "$PASS" otp insert -e expect { "Enter" { send "$uri\r" exp_continue } + "Insert into Example/alice@google.com?" { + send "y\r" + exp_continue + } eof } EOD - [[ $("$PASS" show passfile) == "$uri" ]] + [[ $("$PASS" show "Example/alice@google.com") == "$uri" ]] +' + +test_expect_success 'Force overwrites key URI' ' + uri1="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Foo" + uri2="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Bar" + + test_pass_init && + "$PASS" otp insert passfile <<< "$uri1" && + "$PASS" otp insert -f passfile <<< "$uri2" && + [[ $("$PASS" show passfile) == "$uri2" ]] ' test_done @@ -8,7 +8,7 @@ test_expect_success 'Shows key URI in single-line passfile' ' uri="otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example" test_pass_init && - "$PASS" otp insert "$uri" passfile && + "$PASS" otp insert passfile <<< "$uri" && [[ $("$PASS" otp uri passfile) == "$uri" ]] ' |