Skip to content

Commit

Permalink
Improve type safety in encryption code
Browse files Browse the repository at this point in the history
  • Loading branch information
twpayne committed Aug 13, 2021
1 parent 1a59ced commit de5cb42
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 57 deletions.
8 changes: 4 additions & 4 deletions internal/chezmoi/ageencryption.go
Expand Up @@ -40,9 +40,9 @@ func (e *AGEEncryption) Decrypt(ciphertext []byte) ([]byte, error) {
}

// DecryptToFile implements Encryption.DecryptToFile.
func (e *AGEEncryption) DecryptToFile(plaintextFilename string, ciphertext []byte) error {
func (e *AGEEncryption) DecryptToFile(plaintextAbsPath AbsPath, ciphertext []byte) error {
//nolint:gosec
cmd := exec.Command(e.Command, append(append(e.decryptArgs(), "--output", plaintextFilename), e.Args...)...)
cmd := exec.Command(e.Command, append(append(e.decryptArgs(), "--output", string(plaintextAbsPath)), e.Args...)...)
cmd.Stdin = bytes.NewReader(ciphertext)
cmd.Stderr = os.Stderr
return chezmoilog.LogCmdRun(log.Logger, cmd)
Expand All @@ -62,9 +62,9 @@ func (e *AGEEncryption) Encrypt(plaintext []byte) ([]byte, error) {
}

// EncryptFile implements Encryption.EncryptFile.
func (e *AGEEncryption) EncryptFile(plaintextFilename string) ([]byte, error) {
func (e *AGEEncryption) EncryptFile(plaintextAbsPath AbsPath) ([]byte, error) {
//nolint:gosec
cmd := exec.Command(e.Command, append(append(e.encryptArgs(), e.Args...), plaintextFilename)...)
cmd := exec.Command(e.Command, append(append(e.encryptArgs(), e.Args...), string(plaintextAbsPath))...)
cmd.Stderr = os.Stderr
return chezmoilog.LogCmdOutput(log.Logger, cmd)
}
Expand Down
12 changes: 6 additions & 6 deletions internal/chezmoi/debugencryption.go
Expand Up @@ -30,10 +30,10 @@ func (e *DebugEncryption) Decrypt(ciphertext []byte) ([]byte, error) {
}

// DecryptToFile implements Encryption.DecryptToFile.
func (e *DebugEncryption) DecryptToFile(plaintextFilename string, ciphertext []byte) error {
err := e.encryption.DecryptToFile(plaintextFilename, ciphertext)
func (e *DebugEncryption) DecryptToFile(plaintextAbsPath AbsPath, ciphertext []byte) error {
err := e.encryption.DecryptToFile(plaintextAbsPath, ciphertext)
log.Debug().
Str("plaintextFilename", plaintextFilename).
Str("plaintextAbsPath", string(plaintextAbsPath)).
Bytes("ciphertext", chezmoilog.FirstFewBytes(ciphertext)).
Err(err).
Msg("DecryptToFile")
Expand All @@ -52,10 +52,10 @@ func (e *DebugEncryption) Encrypt(plaintext []byte) ([]byte, error) {
}

// EncryptFile implements Encryption.EncryptFile.
func (e *DebugEncryption) EncryptFile(plaintextFilename string) ([]byte, error) {
ciphertext, err := e.encryption.EncryptFile(plaintextFilename)
func (e *DebugEncryption) EncryptFile(plaintextAbsPath AbsPath) ([]byte, error) {
ciphertext, err := e.encryption.EncryptFile(plaintextAbsPath)
log.Debug().
Str("plaintextFilename", plaintextFilename).
Str("plaintextAbsPath", string(plaintextAbsPath)).
Err(err).
Bytes("ciphertext", chezmoilog.FirstFewBytes(ciphertext)).
Msg("EncryptFile")
Expand Down
4 changes: 2 additions & 2 deletions internal/chezmoi/encryption.go
Expand Up @@ -3,8 +3,8 @@ package chezmoi
// An Encryption encrypts and decrypts files and data.
type Encryption interface {
Decrypt(ciphertext []byte) ([]byte, error)
DecryptToFile(plaintextFilename string, ciphertext []byte) error
DecryptToFile(plaintextFilename AbsPath, ciphertext []byte) error
Encrypt(plaintext []byte) ([]byte, error)
EncryptFile(plaintextFilename string) ([]byte, error)
EncryptFile(plaintextFilename AbsPath) ([]byte, error)
EncryptedSuffix() string
}
21 changes: 10 additions & 11 deletions internal/chezmoi/encryption_test.go
Expand Up @@ -3,7 +3,6 @@ package chezmoi
import (
"math/rand"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -20,16 +19,16 @@ func (e *xorEncryption) Decrypt(ciphertext []byte) ([]byte, error) {
return e.xorWithKey(ciphertext), nil
}

func (e *xorEncryption) DecryptToFile(plaintextFilename string, ciphertext []byte) error {
return os.WriteFile(plaintextFilename, e.xorWithKey(ciphertext), 0o666)
func (e *xorEncryption) DecryptToFile(plaintextAbsPath AbsPath, ciphertext []byte) error {
return os.WriteFile(string(plaintextAbsPath), e.xorWithKey(ciphertext), 0o666)
}

func (e *xorEncryption) Encrypt(plaintext []byte) ([]byte, error) {
return e.xorWithKey(plaintext), nil
}

func (e *xorEncryption) EncryptFile(plaintextFilename string) ([]byte, error) {
plaintext, err := os.ReadFile(plaintextFilename)
func (e *xorEncryption) EncryptFile(plaintextAbsPath AbsPath) ([]byte, error) {
plaintext, err := os.ReadFile(string(plaintextAbsPath))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -63,11 +62,11 @@ func testEncryptionDecryptToFile(t *testing.T, encryption Encryption) {
defer func() {
assert.NoError(t, os.RemoveAll(tempDir))
}()
plaintextFilename := filepath.Join(tempDir, "plaintext")
plaintextAbsPath := AbsPath(tempDir).Join("plaintext")

require.NoError(t, encryption.DecryptToFile(plaintextFilename, actualCiphertext))
require.NoError(t, encryption.DecryptToFile(plaintextAbsPath, actualCiphertext))

actualPlaintext, err := os.ReadFile(plaintextFilename)
actualPlaintext, err := os.ReadFile(string(plaintextAbsPath))
require.NoError(t, err)
require.NotEmpty(t, actualPlaintext)
assert.Equal(t, expectedPlaintext, actualPlaintext)
Expand Down Expand Up @@ -101,10 +100,10 @@ func testEncryptionEncryptFile(t *testing.T, encryption Encryption) {
defer func() {
assert.NoError(t, os.RemoveAll(tempDir))
}()
plaintextFilename := filepath.Join(tempDir, "plaintext")
require.NoError(t, os.WriteFile(plaintextFilename, expectedPlaintext, 0o666))
plaintextAbsPath := AbsPath(tempDir).Join("plaintext")
require.NoError(t, os.WriteFile(string(plaintextAbsPath), expectedPlaintext, 0o666))

actualCiphertext, err := encryption.EncryptFile(plaintextFilename)
actualCiphertext, err := encryption.EncryptFile(plaintextAbsPath)
require.NoError(t, err)
require.NotEmpty(t, actualCiphertext)
assert.NotEqual(t, expectedPlaintext, actualCiphertext)
Expand Down
61 changes: 30 additions & 31 deletions internal/chezmoi/gpgencryption.go
Expand Up @@ -3,7 +3,6 @@ package chezmoi
import (
"os"
"os/exec"
"path/filepath"
"runtime"

"github.com/rs/zerolog/log"
Expand All @@ -23,20 +22,20 @@ type GPGEncryption struct {
// Decrypt implements Encyrption.Decrypt.
func (e *GPGEncryption) Decrypt(ciphertext []byte) ([]byte, error) {
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 {
if err := withPrivateTempDir(func(tempDirAbsPath AbsPath) error {
ciphertextAbsPath := tempDirAbsPath.Join(RelPath("ciphertext" + e.EncryptedSuffix()))
if err := os.WriteFile(string(ciphertextAbsPath), ciphertext, 0o600); err != nil {
return err
}
plaintextFilename := filepath.Join(tempDir, "plaintext")
plaintextAbsPath := tempDirAbsPath.Join("plaintext")

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

var err error
plaintext, err = os.ReadFile(plaintextFilename)
plaintext, err = os.ReadFile(string(plaintextAbsPath))
return err
}); err != nil {
return nil, err
Expand All @@ -45,34 +44,34 @@ func (e *GPGEncryption) Decrypt(ciphertext []byte) ([]byte, error) {
}

// DecryptToFile implements Encryption.DecryptToFile.
func (e *GPGEncryption) DecryptToFile(plaintextFilename string, ciphertext []byte) error {
return withPrivateTempDir(func(tempDir string) error {
ciphertextFilename := filepath.Join(tempDir, "ciphertext"+e.EncryptedSuffix())
if err := os.WriteFile(ciphertextFilename, ciphertext, 0o600); err != nil {
func (e *GPGEncryption) DecryptToFile(plaintextFilename AbsPath, ciphertext []byte) error {
return withPrivateTempDir(func(tempDirAbsPath AbsPath) error {
ciphertextAbsPath := tempDirAbsPath.Join(RelPath("ciphertext" + e.EncryptedSuffix()))
if err := os.WriteFile(string(ciphertextAbsPath), ciphertext, 0o600); err != nil {
return err
}
args := e.decryptArgs(plaintextFilename, ciphertextFilename)
args := e.decryptArgs(plaintextFilename, ciphertextAbsPath)
return e.run(args)
})
}

// Encrypt implements Encryption.Encrypt.
func (e *GPGEncryption) Encrypt(plaintext []byte) ([]byte, error) {
var ciphertext []byte
if err := withPrivateTempDir(func(tempDir string) error {
plaintextFilename := filepath.Join(tempDir, "plaintext")
if err := os.WriteFile(plaintextFilename, plaintext, 0o600); err != nil {
if err := withPrivateTempDir(func(tempDirAbsPath AbsPath) error {
plaintextAbsPath := tempDirAbsPath.Join("plaintext")
if err := os.WriteFile(string(plaintextAbsPath), plaintext, 0o600); err != nil {
return err
}
ciphertextFilename := filepath.Join(tempDir, "ciphertext"+e.EncryptedSuffix())
ciphertextAbsPath := tempDirAbsPath.Join(RelPath("ciphertext" + e.EncryptedSuffix()))

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

var err error
ciphertext, err = os.ReadFile(ciphertextFilename)
ciphertext, err = os.ReadFile(string(ciphertextAbsPath))
return err
}); err != nil {
return nil, err
Expand All @@ -81,18 +80,18 @@ func (e *GPGEncryption) Encrypt(plaintext []byte) ([]byte, error) {
}

// EncryptFile implements Encryption.EncryptFile.
func (e *GPGEncryption) EncryptFile(plaintextFilename string) ([]byte, error) {
func (e *GPGEncryption) EncryptFile(plaintextFilename AbsPath) ([]byte, error) {
var ciphertext []byte
if err := withPrivateTempDir(func(tempDir string) error {
ciphertextFilename := filepath.Join(tempDir, "ciphertext"+e.EncryptedSuffix())
if err := withPrivateTempDir(func(tempDirAbsPath AbsPath) error {
ciphertextAbsPath := tempDirAbsPath.Join(RelPath("ciphertext" + e.EncryptedSuffix()))

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

var err error
ciphertext, err = os.ReadFile(ciphertextFilename)
ciphertext, err = os.ReadFile(string(ciphertextAbsPath))
return err
}); err != nil {
return nil, err
Expand All @@ -105,17 +104,17 @@ func (e *GPGEncryption) EncryptedSuffix() string {
return e.Suffix
}

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

func (e *GPGEncryption) encryptArgs(plaintextFilename, ciphertextFilename string) []string {
func (e *GPGEncryption) encryptArgs(plaintextFilename, ciphertextFilename AbsPath) []string {
args := []string{
"--armor",
"--output", ciphertextFilename,
"--output", string(ciphertextFilename),
}
if e.Symmetric {
args = append(args, "--symmetric")
Expand All @@ -126,7 +125,7 @@ func (e *GPGEncryption) encryptArgs(plaintextFilename, ciphertextFilename string
if !e.Symmetric {
args = append(args, "--encrypt")
}
args = append(args, plaintextFilename)
args = append(args, string(plaintextFilename))
return args
}

Expand All @@ -140,7 +139,7 @@ func (e *GPGEncryption) run(args []string) error {
}

// withPrivateTempDir creates a private temporary and calls f.
func withPrivateTempDir(f func(tempDir string) error) error {
func withPrivateTempDir(f func(tempDirAbsPath AbsPath) error) error {
tempDir, err := os.MkdirTemp("", "chezmoi-encryption")
if err != nil {
return err
Expand All @@ -152,5 +151,5 @@ func withPrivateTempDir(f func(tempDir string) error) error {
}
}

return f(tempDir)
return f(AbsPath(tempDir))
}
4 changes: 2 additions & 2 deletions internal/chezmoi/noencryption.go
Expand Up @@ -11,13 +11,13 @@ type NoEncryption struct{}
func (NoEncryption) Decrypt([]byte) ([]byte, error) { return nil, errNoEncryption }

// DecryptToFile implements Encryption.DecryptToFile.
func (NoEncryption) DecryptToFile(string, []byte) error { return errNoEncryption }
func (NoEncryption) DecryptToFile(AbsPath, []byte) error { return errNoEncryption }

// Encrypt implements Encryption.Encrypt.
func (NoEncryption) Encrypt([]byte) ([]byte, error) { return nil, errNoEncryption }

// EncryptFile implements Encryption.EncryptFile.
func (NoEncryption) EncryptFile(string) ([]byte, error) { return nil, errNoEncryption }
func (NoEncryption) EncryptFile(AbsPath) ([]byte, error) { return nil, errNoEncryption }

// EncryptedSuffix implements Encryption.EncryptedSuffix.
func (NoEncryption) EncryptedSuffix() string { return "" }
2 changes: 1 addition & 1 deletion internal/cmd/editcmd.go
Expand Up @@ -123,7 +123,7 @@ func (c *Config) runEditCmd(cmd *cobra.Command, args []string, sourceState *chez
}

for _, transparentlyDecryptedFile := range transparentlyDecryptedFiles {
contents, err := c.encryption.EncryptFile(string(transparentlyDecryptedFile.decryptedAbsPath))
contents, err := c.encryption.EncryptFile(transparentlyDecryptedFile.decryptedAbsPath)
if err != nil {
return err
}
Expand Down

0 comments on commit de5cb42

Please sign in to comment.