1// +build darwin 2 3package libkb 4 5import ( 6 "encoding/base64" 7 "testing" 8 9 keychain "github.com/keybase/go-keychain" 10 "github.com/stretchr/testify/require" 11) 12 13func TestSecretStoreDarwin(t *testing.T) { 14 tc := SetupTest(t, "secret store darwin", 1) 15 defer tc.Cleanup() 16 17 mctx := NewMetaContextForTest(tc) 18 secretStore := KeychainSecretStore{} 19 nu := NormalizedUsername("username") 20 21 defer func() { 22 err := secretStore.ClearSecret(mctx, nu) 23 require.NoError(tc.T, err) 24 }() 25 26 serviceName := secretStore.serviceName(mctx) 27 accessGroup := secretStore.accessGroup(mctx) 28 29 expectedSecret1 := []byte("test secret 1test secret 1test s") 30 expectedSecret2 := []byte("test secret 2test secret 2test s") 31 encodedSecret1 := base64.StdEncoding.EncodeToString(expectedSecret1) 32 encodedSecret2 := base64.StdEncoding.EncodeToString(expectedSecret2) 33 lkSec1, err := newLKSecFullSecretFromBytes(expectedSecret1) 34 require.NoError(t, err) 35 36 err = secretStore.StoreSecret(mctx, nu, lkSec1) 37 require.NoError(t, err) 38 39 secret, err := secretStore.RetrieveSecret(mctx, nu) 40 require.NoError(t, err) 41 require.Equal(t, string(expectedSecret1), string(secret.Bytes())) 42 43 t.Logf("Corrupt keychain, add new secret") 44 // corrupt the secret in the keychain by writing into a new slot 45 // forcing us to use a new keychain slot when writing the new item 46 account := newKeychainSlottedAccount(nu, 1) 47 item := keychain.NewGenericPassword(serviceName, account.String(), 48 "", []byte(encodedSecret2), accessGroup) 49 err = keychain.AddItem(item) 50 require.NoError(t, err) 51 52 // We now readout expectedSecret2 since it is the latest entry. 53 secret, err = secretStore.RetrieveSecret(mctx, nu) 54 require.NoError(t, err) 55 require.Equal(t, string(expectedSecret2), string(secret.Bytes())) 56 57 // Now write expectedSecret1 back into the store, which will overwrite secret2 58 err = secretStore.StoreSecret(mctx, nu, lkSec1) 59 require.NoError(t, err) 60 61 secret, err = secretStore.RetrieveSecret(mctx, nu) 62 require.NoError(t, err) 63 require.Equal(t, string(expectedSecret1), string(secret.Bytes())) 64 65 // verify our keychain state 66 for i := 0; i < 2; i++ { 67 account := newKeychainSlottedAccount(nu, i) 68 query := keychain.NewItem() 69 query.SetSecClass(keychain.SecClassGenericPassword) 70 query.SetService(serviceName) 71 query.SetAccount(account.String()) 72 query.SetAccessGroup(accessGroup) 73 query.SetReturnData(true) 74 query.SetReturnAttributes(true) 75 results, err := keychain.QueryItem(query) 76 require.NoError(t, err) 77 require.Len(t, results, 1) 78 res := results[0] 79 80 require.Equal(t, secretStore.serviceName(mctx), res.Service) 81 require.Equal(t, account.String(), res.Account) 82 require.Equal(t, secretStore.accessGroup(mctx), res.AccessGroup) 83 require.Equal(t, "", res.Description) 84 require.Equal(t, encodedSecret1, string(res.Data)) 85 } 86 87 // Although we have 3 keychain items, we technically only have one user in 88 // the store. 89 users, err := secretStore.GetUsersWithStoredSecrets(mctx) 90 require.NoError(t, err) 91 require.Len(t, users, 1) 92 93 err = secretStore.ClearSecret(mctx, nu) 94 require.NoError(t, err) 95 96 for i := 0; i < 2; i++ { 97 account := newKeychainSlottedAccount(nu, i) 98 query := keychain.NewItem() 99 query.SetSecClass(keychain.SecClassGenericPassword) 100 query.SetService(serviceName) 101 query.SetAccount(account.String()) 102 query.SetAccessGroup(accessGroup) 103 query.SetReturnData(true) 104 query.SetReturnAttributes(true) 105 results, err := keychain.QueryItem(query) 106 require.NoError(t, err) 107 require.Nil(t, results) 108 } 109 110 users, err = secretStore.GetUsersWithStoredSecrets(mctx) 111 require.NoError(t, err) 112 require.Len(t, users, 0) 113} 114 115func TestPrimeSecretStoreDarwin(t *testing.T) { 116 tc := SetupTest(t, "secret_store_darwin", 1) 117 defer tc.Cleanup() 118 tc.G.Env.Test.SecretStorePrimingDisabled = false 119 120 mctx := NewMetaContextForTest(tc) 121 secretStore := KeychainSecretStore{} 122 err := PrimeSecretStore(mctx, secretStore) 123 require.NoError(t, err) 124} 125