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  }