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

     1  package libkb
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"fmt"
     6  	"os"
     7  
     8  	"path/filepath"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func TestErasableKVStore(t *testing.T) {
    15  	tc := SetupTest(t, "libkb store encryption", 1)
    16  	defer tc.Cleanup()
    17  	mctx := NewMetaContextForTest(tc)
    18  
    19  	subDir := ""
    20  	s := NewFileErasableKVStore(mctx, subDir, func(_ MetaContext, noise NoiseBytes) ([32]byte, error) {
    21  		return sha256.Sum256(noise[:]), nil
    22  	})
    23  
    24  	key := "test-key.key"
    25  	expected := "value"
    26  	err := s.Put(mctx, key, expected)
    27  	require.NoError(t, err)
    28  	var val string
    29  	err = s.Get(mctx, key, &val)
    30  	require.NoError(t, err)
    31  	require.Equal(t, expected, val)
    32  
    33  	// create a tmp file in the storage dir, ensure we clean it up when calling
    34  	// `AllKeys`
    35  	tmp, err := os.CreateTemp(s.storageDir, key)
    36  	require.NoError(t, err)
    37  	for i := 0; i < 5; i++ {
    38  		keys, err := s.AllKeys(mctx, ".key")
    39  		require.NoError(t, err)
    40  		require.Equal(t, []string{key}, keys)
    41  		exists, err := FileExists(tmp.Name())
    42  		require.NoError(t, err)
    43  		if !exists {
    44  			break
    45  		}
    46  	}
    47  
    48  	// Test noise file corruption
    49  	noiseName := fmt.Sprintf("%s%s", key, noiseSuffix)
    50  	storageDir := getStorageDir(mctx, subDir)
    51  	noiseFilePath := filepath.Join(storageDir, noiseName)
    52  	noise, err := os.ReadFile(noiseFilePath)
    53  	require.NoError(t, err)
    54  
    55  	// flip one bit
    56  	corruptedNoise := make([]byte, len(noise))
    57  	copy(corruptedNoise, noise)
    58  	corruptedNoise[0] ^= 0x01
    59  
    60  	err = os.WriteFile(noiseFilePath, corruptedNoise, PermFile)
    61  	require.NoError(t, err)
    62  
    63  	var corrupt string
    64  	err = s.Get(mctx, key, &corrupt)
    65  	require.Error(t, err)
    66  	uerr, ok := err.(UnboxError)
    67  	require.True(t, ok)
    68  	require.Equal(t, fmt.Sprintf("ErasableKVStore UnboxError (info=noise hashes do not match): secretbox.Open failure. Stored noise hash: %x, current noise hash: %x, equal: %v", s.noiseHash(noise), s.noiseHash(corruptedNoise), false), uerr.Error())
    69  	require.NotEqual(t, expected, corrupt)
    70  
    71  	err = s.Erase(mctx, key)
    72  	require.NoError(t, err)
    73  
    74  	keys, err := s.AllKeys(mctx, ".key")
    75  	require.NoError(t, err)
    76  	require.Equal(t, []string(nil), keys)
    77  
    78  	s2 := NewFileErasableKVStore(mctx, "nah", func(_ MetaContext, noise NoiseBytes) ([32]byte, error) {
    79  		return sha256.Sum256(noise[:]), nil
    80  	})
    81  	key2 := "mynewkey"
    82  	expected2 := []byte("yellow_submarine")
    83  	err = s2.Put(mctx, key2, expected2)
    84  	require.NoError(t, err)
    85  
    86  	s3 := NewFileErasableKVStore(mctx, "nah", func(_ MetaContext, noise NoiseBytes) ([32]byte, error) {
    87  		return sha256.Sum256(noise[:]), nil
    88  	})
    89  	var val2 []byte
    90  	err = s3.Get(mctx, key2, &val2)
    91  	require.NoError(t, err)
    92  	require.Equal(t, expected2, val2)
    93  }