Skip to content

Commit

Permalink
Use temporary files, instead of stdin/stdout, when calling gpg
Browse files Browse the repository at this point in the history
  • Loading branch information
twpayne committed May 24, 2021
1 parent cbed432 commit d858159
Showing 1 changed file with 105 additions and 38 deletions.
143 changes: 105 additions & 38 deletions internal/chezmoi/gpgencryption.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package chezmoi

import (
"bytes"
"os"
"os/exec"
"path/filepath"
"runtime"

"github.com/rs/zerolog/log"

Expand All @@ -21,69 +22,135 @@ type GPGEncryption struct {

// Decrypt implements Encyrption.Decrypt.
func (e *GPGEncryption) Decrypt(ciphertext []byte) ([]byte, error) {
args := append([]string{"--decrypt"}, e.Args...)
//nolint:gosec
cmd := exec.Command(e.Command, args...)
cmd.Stdin = bytes.NewReader(ciphertext)
cmd.Stderr = os.Stderr
return chezmoilog.LogCmdOutput(log.Logger, cmd)
var plaintext []byte
if err := withPrivateTempDir(func(tempDir string) error {
ciphertextFilename := filepath.Join(tempDir, "ciphertext"+e.EncryptedSuffix())
if err := os.WriteFile(ciphertextFilename, ciphertext, 0o600); err != nil {
return err
}
plaintextFilename := filepath.Join(tempDir, "plaintext")

args := e.decryptArgs(plaintextFilename, ciphertextFilename)
if err := e.run(args); err != nil {
return err
}

var err error
plaintext, err = os.ReadFile(plaintextFilename)
return err
}); err != nil {
return nil, err
}
return plaintext, nil
}

// DecryptToFile implements Encryption.DecryptToFile.
func (e *GPGEncryption) DecryptToFile(plaintextFilename string, ciphertext []byte) error {
args := append([]string{
"--decrypt",
"--output", plaintextFilename,
"--yes",
}, e.Args...)
//nolint:gosec
cmd := exec.Command(e.Command, args...)
cmd.Stdin = bytes.NewReader(ciphertext)
cmd.Stderr = os.Stderr
return chezmoilog.LogCmdRun(log.Logger, cmd)
return withPrivateTempDir(func(tempDir string) error {
ciphertextFilename := filepath.Join(tempDir, "ciphertext"+e.EncryptedSuffix())
if err := os.WriteFile(ciphertextFilename, ciphertext, 0o600); err != nil {
return err
}
args := e.decryptArgs(plaintextFilename, ciphertextFilename)
return e.run(args)
})
}

// Encrypt implements Encryption.Encrypt.
func (e *GPGEncryption) Encrypt(plaintext []byte) ([]byte, error) {
args := append(e.encryptArgs(), e.Args...)
//nolint:gosec
cmd := exec.Command(e.Command, args...)
cmd.Stdin = bytes.NewReader(plaintext)
cmd.Stderr = os.Stderr
return chezmoilog.LogCmdOutput(log.Logger, cmd)
var ciphertext []byte
if err := withPrivateTempDir(func(tempDir string) error {
plaintextFilename := filepath.Join(tempDir, "plaintext")
if err := os.WriteFile(plaintextFilename, plaintext, 0o600); err != nil {
return err
}
ciphertextFilename := filepath.Join(tempDir, "ciphertext"+e.EncryptedSuffix())

args := e.encryptArgs(plaintextFilename, ciphertextFilename)
if err := e.run(args); err != nil {
return err
}

var err error
ciphertext, err = os.ReadFile(ciphertextFilename)
return err
}); err != nil {
return nil, err
}
return ciphertext, nil
}

// EncryptFile implements Encryption.EncryptFile.
func (e *GPGEncryption) EncryptFile(plaintextFilename string) (ciphertext []byte, err error) {
f, err := os.Open(plaintextFilename)
if err != nil {
func (e *GPGEncryption) EncryptFile(plaintextFilename string) ([]byte, error) {
var ciphertext []byte
if err := withPrivateTempDir(func(tempDir string) error {
ciphertextFilename := filepath.Join(tempDir, "ciphertext"+e.EncryptedSuffix())

args := e.encryptArgs(plaintextFilename, ciphertextFilename)
if err := e.run(args); err != nil {
return err
}

var err error
ciphertext, err = os.ReadFile(ciphertextFilename)
return err
}); err != nil {
return nil, err
}
defer f.Close()
args := append(e.encryptArgs(), e.Args...)
//nolint:gosec
cmd := exec.Command(e.Command, args...)
cmd.Stdin = f
cmd.Stderr = os.Stderr
return chezmoilog.LogCmdOutput(log.Logger, cmd)
return ciphertext, nil
}

// EncryptedSuffix implements Encryption.EncryptedSuffix.
func (e *GPGEncryption) EncryptedSuffix() string {
return e.Suffix
}

func (e *GPGEncryption) encryptArgs() []string {
func (e *GPGEncryption) decryptArgs(plaintextFilename, ciphertextFilename string) []string {
args := []string{"--output", plaintextFilename}
args = append(args, e.Args...)
args = append(args, "--decrypt", ciphertextFilename)
return args
}

func (e *GPGEncryption) encryptArgs(plaintextFilename, ciphertextFilename string) []string {
args := []string{
"--armor",
"--output", ciphertextFilename,
}
if e.Symmetric {
args = append(args, "--symmetric")
} else {
} else if e.Recipient != "" {
args = append(args, "--recipient", e.Recipient)
}
args = append(args, e.Args...)
if !e.Symmetric {
args = append(args, "--encrypt")
if e.Recipient != "" {
args = append(args, "--recipient", e.Recipient)
}
}
args = append(args, plaintextFilename)
return args
}

func (e *GPGEncryption) run(args []string) error {
//nolint:gosec
cmd := exec.Command(e.Command, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return chezmoilog.LogCmdRun(log.Logger, cmd)
}

// withPrivateTempDir creates a private temporary and calls f.
func withPrivateTempDir(f func(tempDir string) error) error {
tempDir, err := os.MkdirTemp("", "chezmoi-encryption")
if err != nil {
return err
}
defer os.RemoveAll(tempDir)
if runtime.GOOS != "windows" {
if err := os.Chmod(tempDir, 0o700); err != nil {
return err
}
}

return f(tempDir)
}

0 comments on commit d858159

Please sign in to comment.