From a97f2e79a20da739ddd8b2f54ad9b6f6c924792a Mon Sep 17 00:00:00 2001 From: josh <josh@elixxir.io> Date: Thu, 9 Sep 2021 15:18:37 -0700 Subject: [PATCH] Handle file pathing edge cases --- api/mnemonic.go | 30 +++++++++++++++++++++++++++--- api/mnemonic_test.go | 8 +++++++- bindings/mnemonic.go | 1 + 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 bindings/mnemonic.go diff --git a/api/mnemonic.go b/api/mnemonic.go index f7cd2b8cf..fd3ce7259 100644 --- a/api/mnemonic.go +++ b/api/mnemonic.go @@ -14,9 +14,11 @@ import ( xxMnemonic "gitlab.com/xx_network/crypto/mnemonic" "gitlab.com/xx_network/primitives/utils" "golang.org/x/crypto/chacha20poly1305" + "path/filepath" + "strings" ) -const mnemonicFile = "/.recovery" +const mnemonicFile = ".recovery" // StoreSecretWithMnemonic creates a mnemonic and uses it to encrypt the secret. // This encrypted data saved in storage. @@ -24,12 +26,18 @@ func StoreSecretWithMnemonic(secret []byte, path string) (string, error) { // Use fastRNG for RNG ops (AES fortuna based RNG using system RNG) rng := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG).GetStream() + // Ensure path is appended by filepath separator "/" + if !strings.HasSuffix(path, string(filepath.Separator)) { + path = path + string(filepath.Separator) + } + // Create a mnemonic mnemonic, err := xxMnemonic.GenerateMnemonic(rng, 32) if err != nil { return "", errors.Errorf("Failed to generate mnemonic: %v", err) } + // Decode mnemonic decodedMnemonic, err := xxMnemonic.DecodeMnemonic(mnemonic) if err != nil { return "", errors.Errorf("Failed to decode mnemonic: %v", err) @@ -42,7 +50,8 @@ func StoreSecretWithMnemonic(secret []byte, path string) (string, error) { } // Save encrypted secret to file - err = utils.WriteFileDef(path+mnemonicFile, ciphertext) + recoveryFile := path + mnemonicFile + err = utils.WriteFileDef(recoveryFile, ciphertext) if err != nil { return "", errors.Errorf("Failed to save mnemonic information to file") } @@ -53,16 +62,31 @@ func StoreSecretWithMnemonic(secret []byte, path string) (string, error) { // LoadSecretWithMnemonic loads the encrypted secret from storage and decrypts // the secret using the given mnemonic. func LoadSecretWithMnemonic(mnemonic, path string) (secret []byte, err error) { - data, err := utils.ReadFile(path + mnemonicFile) + // Ensure path is appended by filepath separator "/" + if !strings.HasSuffix(path, string(filepath.Separator)) { + path = path + string(filepath.Separator) + } + + // Ensure that the recovery file exists + recoveryFile := path + mnemonicFile + if !utils.Exists(recoveryFile) { + return nil, errors.Errorf("Recovery file does not exist. " + + "Did you properly set up recovery or provide an incorrect filepath?") + } + + // Read file from storage + data, err := utils.ReadFile(recoveryFile) if err != nil { return nil, errors.Errorf("Failed to load mnemonic information: %v", err) } + // Decode mnemonic decodedMnemonic, err := xxMnemonic.DecodeMnemonic(mnemonic) if err != nil { return nil, errors.Errorf("Failed to decode mnemonic: %v", err) } + // Decrypt the stored secret secret, err = decryptWithMnemonic(data, decodedMnemonic) if err != nil { return nil, errors.Errorf("Failed to decrypt secret: %v", err) diff --git a/api/mnemonic_test.go b/api/mnemonic_test.go index b9f7715be..66b2f13df 100644 --- a/api/mnemonic_test.go +++ b/api/mnemonic_test.go @@ -19,7 +19,7 @@ import ( func TestStoreSecretWithMnemonic(t *testing.T) { secret := []byte("test123") - storageDir := "ignore.1" + storageDir := "ignore.1/" mnemonic, err := StoreSecretWithMnemonic(secret, storageDir) if err != nil { t.Errorf("StoreSecretWithMnemonic error; %v", err) @@ -90,6 +90,12 @@ func TestLoadSecretWithMnemonic(t *testing.T) { t.Fatalf("Loaded secret does not match original data."+ "\n\tExpected: %v\n\tReceived: %v", secret, received) } + + _, err = LoadSecretWithMnemonic(mnemonic, "badDirectory") + if err == nil { + t.Fatalf("LoadSecretWithMnemonic should error when provided a path " + + "where a recovery file does not exist.") + } } // Prng is a PRNG that satisfies the csprng.Source interface. diff --git a/bindings/mnemonic.go b/bindings/mnemonic.go new file mode 100644 index 000000000..95f91744f --- /dev/null +++ b/bindings/mnemonic.go @@ -0,0 +1 @@ +package bindings -- GitLab