github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/ephemeral/team_ek_box_storage_test.go (about) 1 package ephemeral 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 8 "github.com/keybase/client/go/libkb" 9 "github.com/keybase/client/go/protocol/keybase1" 10 "github.com/stretchr/testify/require" 11 ) 12 13 func TestTeamEKBoxStorage(t *testing.T) { 14 tc, mctx, _ := ephemeralKeyTestSetup(t) 15 defer tc.Cleanup() 16 17 merkleRootPtr, err := tc.G.GetMerkleClient().FetchRootFromServer(mctx, libkb.EphemeralKeyMerkleFreshness) 18 require.NoError(t, err) 19 merkleRoot := *merkleRootPtr 20 21 // Login hooks should have run 22 deviceEKStorage := tc.G.GetDeviceEKStorage() 23 deviceEKMaxGen, err := deviceEKStorage.MaxGeneration(mctx, false) 24 require.True(t, deviceEKMaxGen > 0) 25 require.NoError(t, err) 26 27 userEKBoxStorage := tc.G.GetUserEKBoxStorage() 28 userEKMaxGen, err := userEKBoxStorage.MaxGeneration(mctx, false) 29 require.True(t, userEKMaxGen > 0) 30 require.NoError(t, err) 31 32 teamID := createTeam(tc) 33 invalidID := teamID + keybase1.TeamID("foo") 34 35 teamEKMetadata, err := publishNewTeamEK(mctx, teamID, merkleRoot, nil) 36 require.NoError(t, err) 37 38 s := tc.G.GetTeamEKBoxStorage() 39 40 // Test invalid teamID 41 nonexistent2, err := s.Get(mctx, invalidID, teamEKMetadata.Generation+1, nil) 42 require.Error(t, err) 43 _, ok := err.(EphemeralKeyError) 44 require.False(t, ok) 45 require.Equal(t, keybase1.TeamEphemeralKey{}, nonexistent2) 46 47 // Test get valid & unbox 48 ek, err := s.Get(mctx, teamID, teamEKMetadata.Generation, nil) 49 require.NoError(t, err) 50 51 // Make sure we don't pollute bot storage 52 botS := tc.G.GetTeambotEKBoxStorage() 53 botNonexistant, err := botS.Get(mctx, teamID, teamEKMetadata.Generation, nil) 54 require.Error(t, err) 55 require.IsType(t, EphemeralKeyError{}, err) 56 ekErr := err.(EphemeralKeyError) 57 require.Equal(t, DefaultHumanErrMsg, ekErr.HumanError()) 58 require.Equal(t, keybase1.TeamEphemeralKey{}, botNonexistant) 59 60 verifyTeamEK(t, teamEKMetadata, ek) 61 62 // Test Get nonexistent 63 nonexistent, err := s.Get(mctx, teamID, teamEKMetadata.Generation+1, nil) 64 require.Error(t, err) 65 require.IsType(t, EphemeralKeyError{}, err) 66 ekErr = err.(EphemeralKeyError) 67 require.Equal(t, DefaultHumanErrMsg, ekErr.HumanError()) 68 require.Equal(t, keybase1.TeamEphemeralKey{}, nonexistent) 69 70 // include the cached error in the max 71 maxGeneration, err := s.MaxGeneration(mctx, teamID, true) 72 require.NoError(t, err) 73 require.EqualValues(t, 2, maxGeneration) 74 75 // Test MaxGeneration 76 maxGeneration, err = s.MaxGeneration(mctx, teamID, false) 77 require.NoError(t, err) 78 require.EqualValues(t, 1, maxGeneration) 79 80 // Invalid id 81 maxGeneration2, err := s.MaxGeneration(mctx, invalidID, false) 82 require.NoError(t, err) 83 require.EqualValues(t, -1, maxGeneration2) 84 85 // NOTE: We don't expose Delete on the interface put on the GlobalContext 86 // since they should never be called, only DeleteExpired should be used. 87 // GetAll is also not exposed since it' only needed for tests. 88 rawTeamEKBoxStorage := NewTeamEKBoxStorage(NewTeamEphemeralKeyer()) 89 teamEKs, err := rawTeamEKBoxStorage.GetAll(mctx, teamID) 90 require.NoError(t, err) 91 require.Equal(t, 1, len(teamEKs)) 92 93 ek, ok = teamEKs[teamEKMetadata.Generation] 94 require.True(t, ok) 95 96 verifyTeamEK(t, teamEKMetadata, ek) 97 98 // Test invalid 99 teamEKs2, err := rawTeamEKBoxStorage.GetAll(mctx, invalidID) 100 require.NoError(t, err) 101 require.Equal(t, 0, len(teamEKs2)) 102 103 // Let's delete our userEK and verify we will refetch and unbox properly 104 rawUserEKBoxStorage := NewUserEKBoxStorage() 105 err = rawUserEKBoxStorage.Delete(mctx, userEKMaxGen) 106 require.NoError(t, err) 107 108 userEKBoxStorage.ClearCache() 109 110 ek, err = s.Get(mctx, teamID, teamEKMetadata.Generation, nil) 111 require.NoError(t, err) 112 verifyTeamEK(t, teamEKMetadata, ek) 113 114 // No let's the deviceEK which we can't recover from 115 rawDeviceEKStorage := NewDeviceEKStorage(mctx) 116 err = rawDeviceEKStorage.Delete(mctx, deviceEKMaxGen, "") 117 require.NoError(t, err) 118 119 deviceEKStorage.ClearCache() 120 deviceEK, err := deviceEKStorage.Get(mctx, deviceEKMaxGen) 121 require.Error(t, err) 122 _, ok = err.(libkb.UnboxError) 123 require.True(t, ok) 124 require.Equal(t, keybase1.DeviceEk{}, deviceEK) 125 126 bad, err := s.Get(mctx, teamID, teamEKMetadata.Generation, nil) 127 require.Error(t, err) 128 require.IsType(t, EphemeralKeyError{}, err) 129 ekErr = err.(EphemeralKeyError) 130 require.Equal(t, DefaultHumanErrMsg, ekErr.HumanError()) 131 require.Equal(t, keybase1.TeamEphemeralKey{}, bad) 132 133 // test delete 134 err = rawTeamEKBoxStorage.Delete(mctx, teamID, teamEKMetadata.Generation) 135 require.NoError(t, err) 136 // delete invalid 137 err = rawTeamEKBoxStorage.Delete(mctx, invalidID, teamEKMetadata.Generation) 138 require.NoError(t, err) 139 140 teamEKs, err = rawTeamEKBoxStorage.GetAll(mctx, teamID) 141 require.NoError(t, err) 142 require.Equal(t, 0, len(teamEKs)) 143 144 s.ClearCache() 145 146 maxGeneration3, err := s.MaxGeneration(mctx, teamID, false) 147 require.NoError(t, err) 148 require.EqualValues(t, -1, maxGeneration3) 149 150 expired, err := s.DeleteExpired(mctx, teamID, merkleRoot) 151 expected := []keybase1.EkGeneration(nil) 152 require.NoError(t, err) 153 require.Equal(t, expected, expired) 154 155 // Verify we store failures in the cache 156 t.Logf("cache failures") 157 nonexistent, err = rawTeamEKBoxStorage.Get(mctx, teamID, teamEKMetadata.Generation+1, nil) 158 require.Error(t, err) 159 require.Equal(t, keybase1.TeamEphemeralKey{}, nonexistent) 160 cache, found, err := rawTeamEKBoxStorage.getCacheForTeamID(mctx, teamID) 161 require.NoError(t, err) 162 require.True(t, found) 163 require.Len(t, cache, 1) 164 165 cacheItem, ok := cache[teamEKMetadata.Generation+1] 166 require.True(t, ok) 167 require.True(t, cacheItem.HasError()) 168 } 169 170 // If we change the key format intentionally, we have to introduce some form of 171 // migration or versioning between the keys. This test should blow up if we 172 // break it unintentionally. 173 func TestTeamEKStorageKeyFormat(t *testing.T) { 174 tc, mctx, _ := ephemeralKeyTestSetup(t) 175 defer tc.Cleanup() 176 177 s := NewTeamEKBoxStorage(NewTeamEphemeralKeyer()) 178 uv, err := tc.G.GetMeUV(context.TODO()) 179 require.NoError(t, err) 180 181 teamID := createTeam(tc) 182 183 key, err := s.dbKey(mctx, teamID) 184 require.NoError(t, err) 185 expected := fmt.Sprintf("teamEphemeralKeyBox-%s-%s-%s-%s-%d", keybase1.TeamEphemeralKeyType_TEAM, 186 teamID, mctx.G().Env.GetUsername(), uv.EldestSeqno, teamEKBoxStorageDBVersion) 187 require.Equal(t, expected, key.Key) 188 189 s = NewTeamEKBoxStorage(NewTeambotEphemeralKeyer()) 190 key, err = s.dbKey(mctx, teamID) 191 require.NoError(t, err) 192 expected = fmt.Sprintf("teamEphemeralKeyBox-%s-%s-%s-%s-%d", keybase1.TeamEphemeralKeyType_TEAMBOT, 193 teamID, mctx.G().Env.GetUsername(), uv.EldestSeqno, teamEKBoxStorageDBVersion) 194 require.Equal(t, expected, key.Key) 195 }