github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/teams/loadkeycache.go (about) 1 package teams 2 3 import ( 4 "github.com/keybase/client/go/libkb" 5 "github.com/keybase/client/go/protocol/keybase1" 6 ) 7 8 type uvAndKey struct { 9 UV keybase1.UserVersion 10 Key keybase1.PublicKeyV2NaCl 11 } 12 13 // loadKeyCache is a short-lived cache for loading keys and linkmaps for TeamLoader. 14 // It must be short-lived since it has no expiration or eviction. 15 // Not threadsafe. 16 type loadKeyCache struct { 17 userKeyCache map[keybase1.UID]map[keybase1.KID]uvAndKey 18 userLinkMapCache map[keybase1.UID]map[keybase1.Seqno]keybase1.LinkID 19 cacheHits int64 20 } 21 22 func newLoadKeyCache() *loadKeyCache { 23 return &loadKeyCache{ 24 userKeyCache: make(map[keybase1.UID]map[keybase1.KID]uvAndKey), 25 userLinkMapCache: make(map[keybase1.UID]map[keybase1.Seqno]keybase1.LinkID), 26 } 27 } 28 29 func (c *loadKeyCache) loadKeyV2(mctx libkb.MetaContext, uid keybase1.UID, kid keybase1.KID) ( 30 uv keybase1.UserVersion, pubKey *keybase1.PublicKeyV2NaCl, linkMap linkMapT, err error) { 31 mctx, tbs := mctx.WithTimeBuckets() 32 defer tbs.Record("loadKeyCache.loadKeyV2")() 33 34 // Look in the cache first 35 m2, ok := c.userKeyCache[uid] 36 if ok { 37 v, ok := m2[kid] 38 if ok { 39 c.cacheHits++ 40 return v.UV, &v.Key, c.userLinkMapCache[uid], nil 41 } 42 } 43 44 // Load the user. LoadKeyV2 handles punching through the cache when needed. 45 user, upak, _, err := mctx.G().GetUPAKLoader().LoadKeyV2(mctx.Ctx(), uid, kid) 46 if err != nil { 47 return uv, pubKey, linkMap, err 48 } 49 if user == nil || upak == nil { 50 return uv, pubKey, linkMap, libkb.NotFoundError{} 51 } 52 53 // Put all the user's keys into the cache 54 c.userLinkMapCache[uid] = upak.SeqnoLinkIDs 55 if c.userKeyCache[uid] == nil { 56 c.userKeyCache[uid] = make(map[keybase1.KID]uvAndKey) 57 } 58 for _, user := range append(upak.PastIncarnations, upak.Current) { 59 pubKey, ok := user.DeviceKeys[kid] 60 if ok { 61 c.userKeyCache[uid][kid] = uvAndKey{ 62 UV: user.ToUserVersion(), 63 Key: pubKey, 64 } 65 } 66 } 67 68 // Get from the just-updated cache 69 v, ok := c.userKeyCache[uid][kid] 70 if !ok { 71 return uv, nil, nil, libkb.NotFoundError{Msg: "Not found: Key for user"} 72 } 73 return v.UV, &v.Key, c.userLinkMapCache[uid], nil 74 }