github.com/tommi2day/gomodules@v1.13.2-0.20240423190010-b7d55d252a27/pwlib/gpg_test.go (about) 1 package pwlib 2 3 import ( 4 "os" 5 "path" 6 "path/filepath" 7 "slices" 8 "strings" 9 "testing" 10 11 "github.com/tommi2day/gomodules/common" 12 "github.com/tommi2day/gomodules/test" 13 14 "github.com/ProtonMail/go-crypto/openpgp" 15 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 const testGPGName = "Test User" 21 const testGPGEmail = "test@example.com" 22 const testGPGPass = "123456Pass!" 23 24 func TestGPG(t *testing.T) { 25 var err error 26 var gpgid string 27 var keypass string 28 var key string 29 var entityList openpgp.EntityList 30 var entity *openpgp.Entity 31 test.Testinit(t) 32 33 secretGPGKeyFile := path.Join(test.TestData, "test.gpg.key") 34 publicGPGKeyFile := path.Join(test.TestData, "test.asc") 35 _ = os.Remove(publicGPGKeyFile) 36 _ = os.Remove(secretGPGKeyFile) 37 38 t.Run("GPG Gen Key", func(t *testing.T) { 39 keypass = testGPGPass 40 entity, gpgid, err = CreateGPGEntity(testGPGName, "TestCrypt", testGPGEmail, keypass) 41 assert.NoErrorf(t, err, "should be no error, but got %v", err) 42 assert.NotNil(t, entity, "entity should not be nil") 43 if entity == nil { 44 t.Fatal("entity should not be nil") 45 } 46 assert.NotEmpty(t, gpgid, "KeyID should not be empty") 47 assert.True(t, entity.PrivateKey.Encrypted, "encrypted flag should be true") 48 err = ExportGPGKeyPair(entity, publicGPGKeyFile, secretGPGKeyFile) 49 assert.NoErrorf(t, err, "should be no error, but got %v", err) 50 if err != nil { 51 t.Fatal("GPG keys not created as expected") 52 } 53 require.FileExists(t, publicGPGKeyFile) 54 content := "" 55 content, err = common.ReadFileToString(publicGPGKeyFile) 56 assert.NoErrorf(t, err, "File Read Error %s", err) 57 assert.Contains(t, content, "PGP PUBLIC KEY BLOCK") 58 59 require.FileExists(t, secretGPGKeyFile) 60 content, err = common.ReadFileToString(secretGPGKeyFile) 61 assert.NoErrorf(t, err, "File Read Error %s", err) 62 assert.Contains(t, content, "PGP PRIVATE KEY BLOCK") 63 }) 64 if err != nil { 65 t.Fatal("GPG keys not created as expected") 66 } 67 t.Run("GPG Read Public Key", func(t *testing.T) { 68 key, err = common.ReadFileToString(publicGPGKeyFile) 69 entityList, err = GPGReadAmoredKeyRing(key) 70 assert.NoErrorf(t, err, "should be no error, but got %v", err) 71 assert.NotNil(t, entityList, "should not be nil") 72 }) 73 74 t.Run("GPGUnlockKey", func(t *testing.T) { 75 key, err = common.ReadFileToString(secretGPGKeyFile) 76 entityList, err = GPGReadAmoredKeyRing(key) 77 assert.NoErrorf(t, err, "should be no error, but got %v", err) 78 assert.NotNil(t, entityList, "should not be nil") 79 if entityList == nil { 80 t.Fatal("entityList should not be nil") 81 } 82 entity, err = GPGSelectEntity(entityList, gpgid) 83 assert.NoErrorf(t, err, "select should be no error, but got %v", err) 84 assert.NotNil(t, entity, "entity should not be nil") 85 err = GPGUnlockKey(entity, keypass) 86 assert.NoErrorf(t, err, "should be no error, but got %v", err) 87 if entity != nil { 88 assert.False(t, entity.PrivateKey.Encrypted, "encrypted flag should be false") 89 } 90 }) 91 plaintextfile := path.Join(test.TestData, "test.gpg.txt") 92 //nolint gosec 93 err = os.WriteFile(plaintextfile, []byte(plain), 0644) 94 require.NoErrorf(t, err, "Create testdata failed") 95 cryptedfile := path.Join(test.TestData, "test.gpg.crypt") 96 t.Run("Encrypt GPG File", func(t *testing.T) { 97 err = GPGEncryptFile(plaintextfile, cryptedfile, publicGPGKeyFile) 98 assert.NoErrorf(t, err, "should be no error, but got %v", err) 99 }) 100 t.Run("Decrypt GPG File", func(t *testing.T) { 101 actual := "" 102 actual, err = GPGDecryptFile(cryptedfile, secretGPGKeyFile, keypass, "") 103 assert.NoErrorf(t, err, "should be no error, but got %v", err) 104 assert.Equal(t, plain, actual, "should be equal") 105 }) 106 } 107 108 func TestGopassSecrets(t *testing.T) { 109 var err error 110 var gpgid string 111 var keyPass string 112 113 test.Testinit(t) 114 secretGPGKeyFile := path.Join(test.TestDir, "gpg", "test.gpg.key") 115 // publicGPGKeyFile := path.Join(test.TestDir, "gpg", "test.asc") 116 gpgKeyPassFile := path.Join(test.TestDir, "gpg", "test.gpgpw") 117 storeRoot := path.Join(test.TestDir, "pwlib-store") 118 keyIDFile := path.Join(storeRoot, ".gpg-id") 119 gpgid, err = common.ReadFileToString(keyIDFile) 120 require.NoErrorf(t, err, "GetKeyId should be no error, but got %v", err) 121 keyPass, err = common.ReadFileToString(gpgKeyPassFile) 122 require.NoErrorf(t, err, "GetKeyPass should be no error, but got %v", err) 123 t.Run("Check GoPass Root OK", func(t *testing.T) { 124 actual, err := checkStoreRoot(storeRoot) 125 assert.NoErrorf(t, err, "should be no error, but got %v", err) 126 assert.Equal(t, gpgid, actual, "KeyID not match") 127 }) 128 t.Run("Check Gopass Root Err", func(t *testing.T) { 129 actual, err := checkStoreRoot(test.TestDir) 130 assert.Error(t, err, "should be error") 131 assert.Empty(t, actual, "should be empty") 132 }) 133 t.Run("Find GoPass GPG Files", func(t *testing.T) { 134 // store name is not part of result 135 sr := filepath.ToSlash(filepath.Dir(storeRoot)) 136 actual := findGPGFiles(storeRoot) 137 expected := []string{"pwlib-store/test/test1.gpg", "pwlib-store/test/test2.gpg", "pwlib-store/passphrase.gpg"} 138 assert.Equal(t, len(expected), len(actual), "len should be %d", len(expected)) 139 t.Log(actual) 140 for _, e := range expected { 141 n := path.Join(sr, e) 142 found := slices.Contains(actual, n) 143 assert.True(t, found, "%s not found in result", n) 144 } 145 }) 146 147 t.Run("List Gopass Secrets", func(t *testing.T) { 148 actual := "" 149 actual, err = GetGopassSecrets(storeRoot, secretGPGKeyFile, keyPass) 150 assert.NoErrorf(t, err, "should be no error, but got %v", err) 151 if err != nil { 152 t.Fatal(err) 153 } 154 lines := strings.Split(actual, "\n") 155 expected := []string{"pwlib-store:passphrase:", "pwlib-store/test:test1:123456", "pwlib-store/test:test2:"} 156 assert.Equal(t, len(expected), len(lines), "len should be %d", len(expected)) 157 t.Log(lines) 158 for _, e := range expected { 159 found := false 160 for _, l := range lines { 161 if strings.Contains(l, e) { 162 found = true 163 break 164 } 165 } 166 assert.True(t, found, "%s not found in result", e) 167 } 168 }) 169 t.Run("Decrypt Gopass GPG File", func(t *testing.T) { 170 actual := "" 171 filename := path.Join(storeRoot, "test", "test1.gpg") 172 actual, err = GPGDecryptFile(filename, secretGPGKeyFile, keyPass, "") 173 assert.NoErrorf(t, err, "should be no error, but got %v", err) 174 assert.Equal(t, "123456\n", actual, "should be equal") 175 }) 176 t.Run("GoPass GetPassword", func(t *testing.T) { 177 app := "test" 178 pass := "" 179 pc := NewConfig(app, storeRoot, path.Dir(secretGPGKeyFile), keyPass, typeGopass) 180 pc.PrivateKeyFile = secretGPGKeyFile 181 pass, err = pc.GetPassword("pwlib-store/test", "test1") 182 expected := "123456" 183 assert.NoErrorf(t, err, "Got unexpected error: %s", err) 184 assert.Equal(t, expected, pass, "Answer not expected. exp:%s,act:%s", expected, pass) 185 }) 186 }