cmd/age: buffer armored ciphertext before prompting

A partial solution, still missing bracketed paste support.

Updates #364
This commit is contained in:
Filippo Valsorda
2022-07-12 19:20:34 +02:00
parent 8a02f4801f
commit 36ae5671cf
4 changed files with 51 additions and 1 deletions

View File

@@ -234,6 +234,16 @@ func main() {
in = f in = f
} else { } else {
stdinInUse = true stdinInUse = true
if decryptFlag && term.IsTerminal(int(os.Stdin.Fd())) {
// If the input comes from a TTY, assume it's armored, and buffer up
// to the END line (or EOF/EOT) so that a password prompt or the
// output don't get in the way of typing the input. See Issue 364.
buf, err := bufferTerminalInput(in)
if err != nil {
errorf("failed to buffer terminal input: %v", err)
}
in = buf
}
} }
if name := outFlag; name != "" && name != "-" { if name := outFlag; name != "" && name != "-" {
f := newLazyOpener(name) f := newLazyOpener(name)

View File

@@ -1,4 +1,5 @@
# TODO: age-encrypted private keys, multiple identities, -i ordering, -e -i # TODO: age-encrypted private keys, multiple identities, -i ordering, -e -i,
# age file password prompt during encryption
[windows] skip # no pty support [windows] skip # no pty support
@@ -48,6 +49,16 @@ pty terminal
! age -d -i key_rsa_other rsa_other.age ! age -d -i key_rsa_other rsa_other.age
stderr 'mismatched private and public SSH key' stderr 'mismatched private and public SSH key'
# buffer armored ciphertext before prompting if stdin is the terminal
pty terminal
age -e -i key_ed25519 -a -o test.age input
exec cat test.age terminal # concatenated ciphertext + password
pty -stdin stdout
age -d -i key_ed25519
ptyout 'Enter passphrase'
! stderr .
cmp stdout input
-- input -- -- input --
test test
-- terminal -- -- terminal --

View File

@@ -37,6 +37,16 @@ pty terminal
age -d test.age age -d test.age
cmp stdout input cmp stdout input
# buffer armored ciphertext before prompting if stdin is the terminal
pty terminal
age -p -a -o test.age input
exec cat test.age terminal # concatenated ciphertext + password
pty -stdin stdout
age -d
ptyout 'Enter passphrase'
! stderr .
cmp stdout input
-- input -- -- input --
test test
-- terminal -- -- terminal --

View File

@@ -14,6 +14,7 @@ package main
// No capitalized initials and no periods at the end. // No capitalized initials and no periods at the end.
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@@ -21,6 +22,7 @@ import (
"os" "os"
"runtime" "runtime"
"filippo.io/age/armor"
"filippo.io/age/internal/plugin" "filippo.io/age/internal/plugin"
"golang.org/x/term" "golang.org/x/term"
) )
@@ -205,3 +207,20 @@ var pluginTerminalUI = &plugin.ClientUI{
printf("waiting on %s plugin...", name) printf("waiting on %s plugin...", name)
}, },
} }
func bufferTerminalInput(in io.Reader) (io.Reader, error) {
buf := &bytes.Buffer{}
if _, err := buf.ReadFrom(ReaderFunc(func(p []byte) (n int, err error) {
if bytes.Contains(buf.Bytes(), []byte(armor.Footer+"\n")) {
return 0, io.EOF
}
return in.Read(p)
})); err != nil {
return nil, err
}
return buf, nil
}
type ReaderFunc func(p []byte) (n int, err error)
func (f ReaderFunc) Read(p []byte) (n int, err error) { return f(p) }