github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libkbfs/mdserver_local_shared.go (about) 1 // Copyright 2016 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package libkbfs 6 7 import ( 8 "sync" 9 10 "github.com/keybase/client/go/kbfs/kbfscodec" 11 "github.com/keybase/client/go/kbfs/kbfscrypto" 12 "github.com/keybase/client/go/kbfs/kbfsmd" 13 "github.com/keybase/client/go/kbfs/tlf" 14 "github.com/keybase/client/go/protocol/keybase1" 15 "github.com/pkg/errors" 16 "golang.org/x/net/context" 17 ) 18 19 // TODO: Have the functions below wrap their errors. 20 21 // Helper to aid in enforcement that only specified public keys can 22 // access TLF metadata. mergedMasterHead can be nil, in which case 23 // true is returned. 24 func isReader(ctx context.Context, teamMemChecker kbfsmd.TeamMembershipChecker, 25 currentUID keybase1.UID, mergedMasterHead kbfsmd.RootMetadata, 26 extra kbfsmd.ExtraMetadata) (bool, error) { 27 h, err := mergedMasterHead.MakeBareTlfHandle(extra) 28 if err != nil { 29 return false, err 30 } 31 32 if h.Type() == tlf.SingleTeam { 33 isReader, err := teamMemChecker.IsTeamReader( 34 ctx, h.Writers[0].AsTeamOrBust(), currentUID, 35 keybase1.OfflineAvailability_NONE) 36 if err != nil { 37 return false, kbfsmd.ServerError{Err: err} 38 } 39 return isReader, nil 40 } 41 42 return h.IsReader(currentUID.AsUserOrTeam()), nil 43 } 44 45 // Helper to aid in enforcement that only specified public keys can 46 // access TLF metadata. mergedMasterHead can be nil, in which case 47 // true is returned. 48 func isWriterOrValidRekey(ctx context.Context, 49 teamMemChecker kbfsmd.TeamMembershipChecker, codec kbfscodec.Codec, 50 currentUID keybase1.UID, verifyingKey kbfscrypto.VerifyingKey, 51 mergedMasterHead, newMd kbfsmd.RootMetadata, prevExtra, extra kbfsmd.ExtraMetadata) ( 52 bool, error) { 53 h, err := mergedMasterHead.MakeBareTlfHandle(prevExtra) 54 if err != nil { 55 return false, err 56 } 57 58 if h.Type() == tlf.SingleTeam { 59 isWriter, err := teamMemChecker.IsTeamWriter( 60 ctx, h.Writers[0].AsTeamOrBust(), currentUID, verifyingKey, 61 keybase1.OfflineAvailability_NONE) 62 if err != nil { 63 return false, kbfsmd.ServerError{Err: err} 64 } 65 // Team TLFs can't be rekeyed, so readers aren't ever valid. 66 return isWriter, nil 67 } 68 69 if h.IsWriter(currentUID.AsUserOrTeam()) { 70 return true, nil 71 } 72 73 if h.IsReader(currentUID.AsUserOrTeam()) { 74 // if this is a reader, are they acting within their 75 // restrictions? 76 return newMd.IsValidRekeyRequest( 77 codec, mergedMasterHead, currentUID, prevExtra, extra) 78 } 79 80 return false, nil 81 } 82 83 // mdServerLocalTruncateLockManager manages the truncate locks for a 84 // set of TLFs. Note that it is not goroutine-safe. 85 type mdServerLocalTruncateLockManager struct { 86 // TLF ID -> device crypt public key. 87 locksDb map[tlf.ID]kbfscrypto.CryptPublicKey 88 } 89 90 func newMDServerLocalTruncatedLockManager() mdServerLocalTruncateLockManager { 91 return mdServerLocalTruncateLockManager{ 92 locksDb: make(map[tlf.ID]kbfscrypto.CryptPublicKey), 93 } 94 } 95 96 func (m mdServerLocalTruncateLockManager) truncateLock( 97 deviceKey kbfscrypto.CryptPublicKey, id tlf.ID) (bool, error) { 98 lockKey, ok := m.locksDb[id] 99 if !ok { 100 m.locksDb[id] = deviceKey 101 return true, nil 102 } 103 104 if lockKey == deviceKey { 105 // idempotent 106 return true, nil 107 } 108 109 // Locked by someone else. 110 return false, kbfsmd.ServerErrorLocked{} 111 } 112 113 func (m mdServerLocalTruncateLockManager) truncateUnlock( 114 deviceKey kbfscrypto.CryptPublicKey, id tlf.ID) (bool, error) { 115 lockKey, ok := m.locksDb[id] 116 if !ok { 117 // Already unlocked. 118 return true, nil 119 } 120 121 if lockKey == deviceKey { 122 delete(m.locksDb, id) 123 return true, nil 124 } 125 126 // Locked by someone else. 127 return false, kbfsmd.ServerErrorLocked{} 128 } 129 130 // mdServerLocalUpdateManager manages the observers for a set of TLFs 131 // referenced by multiple mdServerLocal instances sharing the same 132 // data. It is goroutine-safe. 133 type mdServerLocalUpdateManager struct { 134 // Protects observers and sessionHeads. 135 lock sync.Mutex 136 observers map[tlf.ID]map[mdServerLocal]chan<- error 137 sessionHeads map[tlf.ID]mdServerLocal 138 } 139 140 func newMDServerLocalUpdateManager() *mdServerLocalUpdateManager { 141 return &mdServerLocalUpdateManager{ 142 observers: make(map[tlf.ID]map[mdServerLocal]chan<- error), 143 sessionHeads: make(map[tlf.ID]mdServerLocal), 144 } 145 } 146 147 func (m *mdServerLocalUpdateManager) setHead(id tlf.ID, server mdServerLocal) { 148 m.lock.Lock() 149 defer m.lock.Unlock() 150 151 m.sessionHeads[id] = server 152 153 // now fire all the observers that aren't from this session 154 for k, v := range m.observers[id] { 155 if k != server { 156 v <- nil 157 close(v) 158 delete(m.observers[id], k) 159 } 160 } 161 if len(m.observers[id]) == 0 { 162 delete(m.observers, id) 163 } 164 } 165 166 func (m *mdServerLocalUpdateManager) registerForUpdate( 167 id tlf.ID, currHead, currMergedHeadRev kbfsmd.Revision, 168 server mdServerLocal) <-chan error { 169 m.lock.Lock() 170 defer m.lock.Unlock() 171 172 c := make(chan error, 1) 173 if currMergedHeadRev > currHead && server != m.sessionHeads[id] { 174 c <- nil 175 close(c) 176 return c 177 } 178 179 if _, ok := m.observers[id]; !ok { 180 m.observers[id] = make(map[mdServerLocal]chan<- error) 181 } 182 183 // Otherwise, this is a legit observer. This assumes that each 184 // client will be using a unique instance of MDServerLocal. 185 if _, ok := m.observers[id][server]; ok { 186 // If the local node registers something twice, it indicates a 187 // fatal bug. Note that in the real MDServer implementation, 188 // we should allow this, in order to make the RPC properly 189 // idempotent. 190 panic(errors.Errorf("Attempted double-registration for MDServerLocal %v", 191 server)) 192 } 193 m.observers[id][server] = c 194 return c 195 } 196 197 func (m *mdServerLocalUpdateManager) cancel(id tlf.ID, server mdServerLocal) { 198 m.lock.Lock() 199 defer m.lock.Unlock() 200 201 // Cancel the registration for this server only. 202 for k, v := range m.observers[id] { 203 if k == server { 204 v <- errors.New("Registration canceled") 205 close(v) 206 delete(m.observers[id], k) 207 } 208 } 209 if len(m.observers[id]) == 0 { 210 delete(m.observers, id) 211 } 212 } 213 214 type keyBundleGetter func(tlf.ID, kbfsmd.TLFWriterKeyBundleID, kbfsmd.TLFReaderKeyBundleID) ( 215 *kbfsmd.TLFWriterKeyBundleV3, *kbfsmd.TLFReaderKeyBundleV3, error) 216 217 func getExtraMetadata(kbg keyBundleGetter, brmd kbfsmd.RootMetadata) (kbfsmd.ExtraMetadata, error) { 218 tlfID := brmd.TlfID() 219 wkbID := brmd.GetTLFWriterKeyBundleID() 220 rkbID := brmd.GetTLFReaderKeyBundleID() 221 if (wkbID == kbfsmd.TLFWriterKeyBundleID{}) != 222 (rkbID == kbfsmd.TLFReaderKeyBundleID{}) { 223 return nil, errors.Errorf( 224 "wkbID is empty (%t) != rkbID is empty (%t)", 225 wkbID == kbfsmd.TLFWriterKeyBundleID{}, 226 rkbID == kbfsmd.TLFReaderKeyBundleID{}) 227 } 228 229 if wkbID == (kbfsmd.TLFWriterKeyBundleID{}) { 230 return nil, nil 231 } 232 233 wkb, rkb, err := kbg(tlfID, wkbID, rkbID) 234 if err != nil { 235 return nil, err 236 } 237 238 return kbfsmd.NewExtraMetadataV3(*wkb, *rkb, false, false), nil 239 }