From d07b8aa2619b78dd22d093d23da890e8ceba26fb Mon Sep 17 00:00:00 2001 From: Shulhan Date: Sat, 23 Sep 2023 16:09:51 +0700 Subject: all: allow empty passphrase when running command Even thought the private key exist, not every command execution require private key. In case it is required and private key is nil, it will return an error during decryption. --- awwan.go | 23 ++++++++++++++++++++--- awwan_test.go | 20 ++++++++++++-------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/awwan.go b/awwan.go index a3fbddc..6230255 100644 --- a/awwan.go +++ b/awwan.go @@ -64,6 +64,10 @@ var ( newLine = []byte("\n") ) +// errPrivateKeyMissing returned when private key file is missing or not +// loaded when command require loading encrypted file. +var errPrivateKeyMissing = errors.New(`private key is missing or not loaded`) + // Awwan is the service that run script in local or remote. // Awwan contains cache of sessions and cache of environment files. type Awwan struct { @@ -174,7 +178,7 @@ func (aww *Awwan) Encrypt(file string) (fileVault string, err error) { var logp = `Encrypt` if aww.privateKey == nil { - return ``, fmt.Errorf(`%s: missing private key %s`, logp, defFilePrivateKey) + return ``, fmt.Errorf(`%s: %w`, logp, errPrivateKeyMissing) } var src []byte @@ -453,7 +457,7 @@ func (aww *Awwan) loadPrivateKey() (err error) { ok bool ) - pkey, err = libcrypto.LoadPrivateKeyInteractive(aww.termrw, fileKey) + _, err = os.Stat(fileKey) if err != nil { if errors.Is(err, fs.ErrNotExist) { return nil @@ -461,6 +465,19 @@ func (aww *Awwan) loadPrivateKey() (err error) { return err } + fmt.Printf("--- Loading private key file %q (enter to skip passphrase) ...\n", fileKey) + + pkey, err = libcrypto.LoadPrivateKeyInteractive(aww.termrw, fileKey) + if err != nil { + if errors.Is(err, libcrypto.ErrEmptyPassphrase) { + // Ignore empty passphrase error, in case the + // command does not need to decrypt files when + // running. + return nil + } + return err + } + aww.privateKey, ok = pkey.(*rsa.PrivateKey) if !ok { return fmt.Errorf(`the private key type must be RSA, got %T`, pkey) @@ -471,7 +488,7 @@ func (aww *Awwan) loadPrivateKey() (err error) { func decrypt(pkey *rsa.PrivateKey, cipher []byte) (plain []byte, err error) { if pkey == nil { - return nil, fmt.Errorf(`missing private key file %q`, defFilePrivateKey) + return nil, errPrivateKeyMissing } var ( diff --git a/awwan_test.go b/awwan_test.go index 4e2a17a..ff67466 100644 --- a/awwan_test.go +++ b/awwan_test.go @@ -37,6 +37,10 @@ func TestAwwanDecrypt(t *testing.T) { fileVault: `.awwan.env.vault`, passphrase: "news3cret\r", expError: `Decrypt: DecryptOaep: crypto/rsa: decryption error`, + }, { + baseDir: filepath.Join(`testdata`, `decrypt-with-passphrase`), + fileVault: `.awwan.env.vault`, + expError: `Decrypt: private key is missing or not loaded`, }} var ( @@ -88,6 +92,10 @@ func TestAwwanEncrypt(t *testing.T) { baseDir: filepath.Join(`testdata`, `encrypt-with-passphrase`), file: `.awwan.env`, passphrase: "s3cret\r", + }, { + baseDir: filepath.Join(`testdata`, `encrypt-with-passphrase`), + file: `.awwan.env`, + expError: `Encrypt: private key is missing or not loaded`, }, { baseDir: filepath.Join(`testdata`, `encrypt-with-passphrase`), file: `.awwan.env`, @@ -116,14 +124,10 @@ func TestAwwanEncrypt(t *testing.T) { var aww = Awwan{} filePlain = filepath.Join(c.baseDir, c.file) - if len(c.passphrase) != 0 { - // Write the passphrase to standard input to be read - // interactively. - mockrw.BufRead.WriteString(c.passphrase) - aww.termrw = &mockrw - } else { - aww.termrw = nil - } + // Write the passphrase to standard input to be read + // interactively. + mockrw.BufRead.WriteString(c.passphrase) + aww.termrw = &mockrw err = aww.init(c.baseDir) if err != nil { -- cgit v1.3