github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/secret_store_darwin_test.go (about)

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