Write encrypt and decrypt output only once they succeed (closes #143)
check / check (push) Waiting to run
check / check (push) Waiting to run
`secret encrypt` and `secret decrypt` emptied the file named by `--output` before reading any input, so a failure left it empty, and a file given as both `--input` and `--output` was emptied before it was read. They now write into a temporary file of mode 0600 next to it, or next to the file it is a symbolic link to, and rename that over it only on success, with the new `secret.WriteFileAtomicFunc`. An output file that cannot be written still fails. Ctrl-C, SIGTERM or a hangup removes the temporary file. A device or pipe, such as `/dev/null`, is written to directly. Judgement calls: the device and pipe case; a command started with `nohup` still ignores a hangup. Model: opus-5-5
This commit is contained in:
+22
-7
@@ -2,6 +2,7 @@ package cli
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/awnumar/memguard"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -14,12 +15,13 @@ import (
|
||||
// every memguard buffer before it returns, so the caller must do nothing
|
||||
// but exit with the code.
|
||||
func Entry() int {
|
||||
// On SIGINT or SIGTERM memguard runs this function, wipes every buffer
|
||||
// and exits with status 1. The passphrase prompt turns echo off on the
|
||||
// controlling terminal until the read finishes, so a signal there would
|
||||
// leave echo off. Only a process in the terminal's foreground process
|
||||
// group may reset it: one in the background that tries is stopped
|
||||
// instead of exiting.
|
||||
// On SIGINT, SIGTERM or SIGHUP memguard runs this function, wipes every
|
||||
// buffer and exits with status 1. The function removes the temporary
|
||||
// file that encrypt or decrypt is writing. The passphrase prompt turns
|
||||
// echo off on the controlling terminal until the read finishes, so a
|
||||
// signal there would leave echo off. Only a process in the terminal's
|
||||
// foreground process group may reset it: one in the background that
|
||||
// tries is stopped instead of exiting.
|
||||
terminal, terminalErr := os.Open(secret.TerminalPath)
|
||||
|
||||
var terminalState *term.State
|
||||
@@ -30,7 +32,20 @@ func Entry() int {
|
||||
terminalState, terminalErr = term.GetState(int(terminal.Fd()))
|
||||
}
|
||||
|
||||
signals := []os.Signal{os.Interrupt, unix.SIGTERM}
|
||||
|
||||
// A command started with nohup must go on ignoring SIGHUP, which
|
||||
// catching it would undo
|
||||
if !signal.Ignored(unix.SIGHUP) {
|
||||
signals = append(signals, unix.SIGHUP)
|
||||
}
|
||||
|
||||
memguard.CatchSignal(func(os.Signal) {
|
||||
name := temporaryOutput.Load()
|
||||
if name != nil {
|
||||
_ = os.Remove(*name)
|
||||
}
|
||||
|
||||
if terminalErr != nil {
|
||||
return
|
||||
}
|
||||
@@ -39,7 +54,7 @@ func Entry() int {
|
||||
if err == nil && foreground == unix.Getpgrp() {
|
||||
_ = term.Restore(int(terminal.Fd()), terminalState)
|
||||
}
|
||||
}, os.Interrupt, unix.SIGTERM)
|
||||
}, signals...)
|
||||
|
||||
defer memguard.Purge()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user