mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-27 15:10:30 +00:00
* Config: do to not store decryption variables globally * save session variables as unexported fields in config * unexport internal encryption helper functions * add encryption/decryption tests * fix yes/no prompt returns flipped boolean * add a test to ensure prompting for encryption works * fix possible NPE when failing * don't return salt if there's error
300 lines
7.0 KiB
Go
300 lines
7.0 KiB
Go
package config
|
|
|
|
import (
|
|
"bytes"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestPromptForConfigEncryption(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
confirm, err := promptForConfigEncryption()
|
|
if confirm {
|
|
t.Error("promptForConfigEncryption return incorrect bool")
|
|
}
|
|
if err == nil {
|
|
t.Error("Expected error as there is no input")
|
|
}
|
|
}
|
|
|
|
func TestPromptForConfigKey(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
byteyBite, err := PromptForConfigKey(true)
|
|
if err == nil && len(byteyBite) > 1 {
|
|
t.Errorf("PromptForConfigKey: %s", err)
|
|
}
|
|
|
|
_, err = PromptForConfigKey(false)
|
|
if err == nil {
|
|
t.Error("Expected error")
|
|
}
|
|
}
|
|
|
|
func TestEncryptConfigFile(t *testing.T) {
|
|
_, err := EncryptConfigFile([]byte("test"), nil)
|
|
if err == nil {
|
|
t.Fatal("Expected error")
|
|
}
|
|
|
|
c := &Config{
|
|
sessionDK: []byte("a"),
|
|
}
|
|
_, err = c.encryptConfigFile([]byte("test"))
|
|
if err == nil {
|
|
t.Fatal("Expected error")
|
|
}
|
|
|
|
sessDk, salt, err := makeNewSessionDK([]byte("asdf"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
c = &Config{
|
|
sessionDK: sessDk,
|
|
storedSalt: salt,
|
|
}
|
|
_, err = c.encryptConfigFile([]byte("test"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestDecryptConfigFile(t *testing.T) {
|
|
result, err := EncryptConfigFile([]byte("test"), []byte("key"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err = DecryptConfigFile(result, nil)
|
|
if err == nil {
|
|
t.Fatal("Expected error")
|
|
}
|
|
|
|
_, err = DecryptConfigFile([]byte("test"), nil)
|
|
if err == nil {
|
|
t.Fatal("Expected error")
|
|
}
|
|
|
|
_, err = DecryptConfigFile([]byte("test"), []byte("AAAAAAAAAAAAAAAA"))
|
|
if err == nil {
|
|
t.Fatalf("Expected %s", errAESBlockSize)
|
|
}
|
|
|
|
result, err = EncryptConfigFile([]byte("test"), []byte("key"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err = DecryptConfigFile(result, []byte("key"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestConfirmECS(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ECStest := []byte(EncryptConfirmString)
|
|
if !ConfirmECS(ECStest) {
|
|
t.Errorf("TestConfirmECS: Error finding ECS.")
|
|
}
|
|
}
|
|
|
|
func TestRemoveECS(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ECStest := []byte(EncryptConfirmString)
|
|
isremoved := removeECS(ECStest)
|
|
|
|
if string(isremoved) != "" {
|
|
t.Errorf("TestConfirmECS: Error ECS not deleted.")
|
|
}
|
|
}
|
|
|
|
func TestMakeNewSessionDK(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, _, err := makeNewSessionDK(nil)
|
|
if err == nil {
|
|
t.Fatal("makeNewSessionDK passed with nil key")
|
|
}
|
|
}
|
|
|
|
func TestEncryptTwiceReusesSaltButNewCipher(t *testing.T) {
|
|
c := &Config{}
|
|
c.EncryptConfig = 1
|
|
tempDir, err := ioutil.TempDir("", "")
|
|
if err != nil {
|
|
t.Fatalf("Problem creating temp dir at %s: %s\n", tempDir, err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
// Prepare input
|
|
passFile, err := ioutil.TempFile(tempDir, "*.pw")
|
|
if err != nil {
|
|
t.Fatalf("Problem creating temp file at %s: %s\n", tempDir, err)
|
|
}
|
|
passFile.WriteString("pass\npass\n")
|
|
passFile.Close()
|
|
|
|
// Temporarily replace Stdin with a custom input
|
|
oldIn := os.Stdin
|
|
defer func() { os.Stdin = oldIn }()
|
|
os.Stdin, err = os.Open(passFile.Name())
|
|
if err != nil {
|
|
t.Fatalf("Problem opening temp file at %s: %s\n", passFile.Name(), err)
|
|
}
|
|
|
|
// Save encrypted config
|
|
enc1 := filepath.Join(tempDir, "encrypted.dat")
|
|
err = c.SaveConfig(enc1, false)
|
|
if err != nil {
|
|
t.Fatalf("Problem storing config in file %s: %s\n", enc1, err)
|
|
}
|
|
// Save again
|
|
enc2 := filepath.Join(tempDir, "encrypted2.dat")
|
|
err = c.SaveConfig(enc2, false)
|
|
if err != nil {
|
|
t.Fatalf("Problem storing config in file %s: %s\n", enc2, err)
|
|
}
|
|
data1, err := ioutil.ReadFile(enc1)
|
|
if err != nil {
|
|
t.Fatalf("Problem reading file %s: %s\n", enc1, err)
|
|
}
|
|
data2, err := ioutil.ReadFile(enc2)
|
|
if err != nil {
|
|
t.Fatalf("Problem reading file %s: %s\n", enc2, err)
|
|
}
|
|
// legth of prefix + salt
|
|
l := len(EncryptConfirmString+SaltPrefix) + SaltRandomLength
|
|
// Even though prefix, including salt with the random bytes is the same
|
|
if !bytes.Equal(data1[:l], data2[:l]) {
|
|
t.Error("Salt is not reused.")
|
|
}
|
|
// the cipher text should not be
|
|
if bytes.Equal(data1, data2) {
|
|
t.Error("Encryption key must have been reused as cipher texts are the same")
|
|
}
|
|
}
|
|
|
|
func TestSaveAndReopenEncryptedConfig(t *testing.T) {
|
|
c := &Config{}
|
|
c.Name = "myCustomName"
|
|
c.EncryptConfig = 1
|
|
tempDir, err := ioutil.TempDir("", "")
|
|
if err != nil {
|
|
t.Fatalf("Problem creating temp dir at %s: %s\n", tempDir, err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
// Prepare password
|
|
passFile, err := ioutil.TempFile(tempDir, "*.pw")
|
|
if err != nil {
|
|
t.Fatalf("Problem creating temp file at %s: %s\n", tempDir, err)
|
|
}
|
|
passFile.WriteString("pass\npass\n")
|
|
passFile.Close()
|
|
|
|
// Temporarily replace Stdin with a custom input
|
|
cleanup := setAnswersFile(t, passFile.Name())
|
|
defer cleanup()
|
|
|
|
// Save encrypted config
|
|
enc := filepath.Join(tempDir, "encrypted.dat")
|
|
err = c.SaveConfig(enc, false)
|
|
if err != nil {
|
|
t.Fatalf("Problem storing config in file %s: %s\n", enc, err)
|
|
}
|
|
|
|
// Prepare password input for decryption
|
|
passFile, err = os.Open(passFile.Name())
|
|
if err != nil {
|
|
t.Fatalf("Problem opening temp file at %s: %s\n", passFile.Name(), err)
|
|
}
|
|
defer passFile.Close()
|
|
os.Stdin = passFile
|
|
|
|
// Clean session
|
|
readConf := &Config{}
|
|
// Load with no existing state, key is read from the prepared file
|
|
err = readConf.ReadConfig(enc, true)
|
|
|
|
// Verify
|
|
if err != nil {
|
|
t.Fatalf("Problem reading config in file %s: %s\n", enc, err)
|
|
}
|
|
|
|
if c.Name != readConf.Name || c.EncryptConfig != readConf.EncryptConfig {
|
|
t.Error("Loaded conf not the same as original")
|
|
}
|
|
}
|
|
|
|
// setAnswersFile sets the given file as the current stdin
|
|
// returns the close function to defer for reverting the stdin
|
|
func setAnswersFile(t *testing.T, answerFile string) func() {
|
|
oldIn := os.Stdin
|
|
|
|
inputFile, err := os.Open(answerFile)
|
|
if err != nil {
|
|
t.Fatalf("Problem opening temp file at %s: %s\n", answerFile, err)
|
|
}
|
|
os.Stdin = inputFile
|
|
return func() {
|
|
inputFile.Close()
|
|
os.Stdin = oldIn
|
|
}
|
|
}
|
|
|
|
func TestReadConfigWithPrompt(t *testing.T) {
|
|
// Prepare temp dir
|
|
tempDir, err := ioutil.TempDir("", "")
|
|
if err != nil {
|
|
t.Fatalf("Problem creating temp dir at %s: %s\n", tempDir, err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
// Ensure we'll get the prompt when loading
|
|
c := &Config{
|
|
EncryptConfig: 0,
|
|
}
|
|
|
|
// Save config
|
|
testConfigFile := filepath.Join(tempDir, "config.json")
|
|
err = c.SaveConfig(testConfigFile, false)
|
|
if err != nil {
|
|
t.Fatalf("Problem saving config file in %s: %s\n", tempDir, err)
|
|
}
|
|
|
|
// Answers to the prompt
|
|
responseFile, err := ioutil.TempFile(tempDir, "*.in")
|
|
if err != nil {
|
|
t.Fatalf("Problem creating temp file at %s: %s\n", tempDir, err)
|
|
}
|
|
responseFile.WriteString("y\npass\npass\n")
|
|
responseFile.Close()
|
|
|
|
// Temporarily replace Stdin with a custom input
|
|
cleanup := setAnswersFile(t, responseFile.Name())
|
|
defer cleanup()
|
|
|
|
// Run the test
|
|
c = &Config{}
|
|
c.ReadConfig(testConfigFile, false)
|
|
|
|
// Verify results
|
|
data, err := ioutil.ReadFile(testConfigFile)
|
|
if err != nil {
|
|
t.Fatalf("Problem reading saved file at %s: %s\n", testConfigFile, err)
|
|
}
|
|
if c.EncryptConfig != fileEncryptionEnabled {
|
|
t.Error("Config encryption flag should be set after prompts")
|
|
}
|
|
if !ConfirmECS(data) {
|
|
t.Error("Config file should be encrypted after prompts")
|
|
}
|
|
}
|