github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/service/kbfs.go (about)

     1  // Copyright 2015 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package service
     5  
     6  import (
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/keybase/client/go/encrypteddb"
    11  
    12  	"golang.org/x/net/context"
    13  
    14  	"github.com/keybase/client/go/chat"
    15  	"github.com/keybase/client/go/chat/globals"
    16  	"github.com/keybase/client/go/libkb"
    17  	"github.com/keybase/client/go/offline"
    18  	"github.com/keybase/client/go/protocol/chat1"
    19  	"github.com/keybase/client/go/protocol/keybase1"
    20  	"github.com/keybase/client/go/teams"
    21  	"github.com/keybase/client/go/tlfupgrade"
    22  	"github.com/keybase/go-framed-msgpack-rpc/rpc"
    23  )
    24  
    25  type KBFSHandler struct {
    26  	*BaseHandler
    27  	libkb.Contextified
    28  	globals.ChatContextified
    29  	service *Service
    30  }
    31  
    32  func NewKBFSHandler(xp rpc.Transporter, g *libkb.GlobalContext, cg *globals.ChatContext, service *Service) *KBFSHandler {
    33  	return &KBFSHandler{
    34  		BaseHandler:      NewBaseHandler(g, xp),
    35  		Contextified:     libkb.NewContextified(g),
    36  		ChatContextified: globals.NewChatContextified(cg),
    37  		service:          service,
    38  	}
    39  }
    40  
    41  func (h *KBFSHandler) FSOnlineStatusChangedEvent(_ context.Context, online bool) error {
    42  	h.G().NotifyRouter.HandleFSOnlineStatusChanged(online)
    43  	return nil
    44  }
    45  
    46  func (h *KBFSHandler) FSEvent(_ context.Context, arg keybase1.FSNotification) error {
    47  	h.G().NotifyRouter.HandleFSActivity(arg)
    48  
    49  	h.checkConversationRekey(arg)
    50  
    51  	return nil
    52  }
    53  
    54  func (h *KBFSHandler) FSPathUpdate(_ context.Context, path string) error {
    55  	h.G().NotifyRouter.HandleFSPathUpdated(path)
    56  	return nil
    57  }
    58  
    59  func (h *KBFSHandler) FSEditList(ctx context.Context, arg keybase1.FSEditListArg) error {
    60  	h.G().NotifyRouter.HandleFSEditListResponse(ctx, arg)
    61  	return nil
    62  }
    63  
    64  func (h *KBFSHandler) FSEditListRequest(ctx context.Context, arg keybase1.FSEditListRequest) error {
    65  	h.G().NotifyRouter.HandleFSEditListRequest(ctx, arg)
    66  	return nil
    67  }
    68  
    69  func (h *KBFSHandler) FSSyncStatus(ctx context.Context, arg keybase1.FSSyncStatusArg) (err error) {
    70  	h.G().NotifyRouter.HandleFSSyncStatus(ctx, arg)
    71  	return nil
    72  }
    73  
    74  func (h *KBFSHandler) FSSyncEvent(ctx context.Context, arg keybase1.FSPathSyncStatus) (err error) {
    75  	h.G().NotifyRouter.HandleFSSyncEvent(ctx, arg)
    76  	return nil
    77  }
    78  
    79  func (h *KBFSHandler) FSOverallSyncEvent(
    80  	_ context.Context, arg keybase1.FolderSyncStatus) (err error) {
    81  	h.G().NotifyRouter.HandleFSOverallSyncStatusChanged(arg)
    82  	return nil
    83  }
    84  
    85  func (h *KBFSHandler) FSFavoritesChangedEvent(_ context.Context) (err error) {
    86  	h.G().NotifyRouter.HandleFSFavoritesChanged()
    87  	return nil
    88  }
    89  
    90  func (h *KBFSHandler) FSSubscriptionNotifyEvent(_ context.Context, arg keybase1.FSSubscriptionNotifyEventArg) error {
    91  	h.G().NotifyRouter.HandleFSSubscriptionNotify(keybase1.FSSubscriptionNotifyArg(arg))
    92  	return nil
    93  }
    94  
    95  func (h *KBFSHandler) FSSubscriptionNotifyPathEvent(_ context.Context, arg keybase1.FSSubscriptionNotifyPathEventArg) error {
    96  	h.G().NotifyRouter.HandleFSSubscriptionNotifyPath(keybase1.FSSubscriptionNotifyPathArg(arg))
    97  	return nil
    98  }
    99  
   100  // checkConversationRekey looks for rekey finished notifications and tries to
   101  // find any conversations associated with the rekeyed TLF.  If it finds any,
   102  // it will send ChatThreadsStale notifications for them.
   103  func (h *KBFSHandler) checkConversationRekey(arg keybase1.FSNotification) {
   104  	if arg.NotificationType != keybase1.FSNotificationType_REKEYING {
   105  		return
   106  	}
   107  	h.G().Log.Debug("received rekey notification for %s, code: %v", arg.Filename, arg.StatusCode)
   108  	if arg.StatusCode != keybase1.FSStatusCode_FINISH {
   109  		return
   110  	}
   111  
   112  	uid := h.G().Env.GetUID()
   113  	if uid.IsNil() {
   114  		h.G().Log.Debug("received rekey finished notification for %s, but have no UID", arg.Filename)
   115  		return
   116  	}
   117  
   118  	h.G().Log.Debug("received rekey finished notification for %s, checking for conversations", arg.Filename)
   119  
   120  	h.notifyConversation(uid, arg.Filename)
   121  }
   122  
   123  // findFolderList returns the type of KBFS folder list containing the
   124  // given file, e.g., "private", "public", "team", etc.
   125  func findFolderList(filename string) string {
   126  	// KBFS always sets the filenames in the protocol to be like
   127  	// `/keybase/private/alice/...`, regardless of the OS.  So we just
   128  	// need to split by `/` and take the third component.
   129  	components := strings.Split(filename, "/")
   130  	if len(components) < 3 {
   131  		return ""
   132  	}
   133  	return components[2]
   134  }
   135  
   136  func (h *KBFSHandler) notifyConversation(uid keybase1.UID, filename string) {
   137  	tlf := filepath.Base(filename)
   138  	public := findFolderList(filename) == "public"
   139  
   140  	g := globals.NewContext(h.G(), h.ChatG())
   141  	ctx := globals.ChatCtx(context.Background(), g, keybase1.TLFIdentifyBehavior_CHAT_SKIP,
   142  		nil, chat.NewCachingIdentifyNotifier(g))
   143  	h.ChatG().FetchRetrier.Rekey(ctx, tlf, chat1.ConversationMembersType_KBFS, public)
   144  }
   145  
   146  func (h *KBFSHandler) CreateTLF(ctx context.Context, arg keybase1.CreateTLFArg) error {
   147  	return teams.CreateTLF(ctx, h.G(), arg)
   148  }
   149  
   150  func (h *KBFSHandler) GetKBFSTeamSettings(ctx context.Context, arg keybase1.GetKBFSTeamSettingsArg) (ret keybase1.KBFSTeamSettings, err error) {
   151  	mctx := libkb.NewMetaContext(ctx, h.G()).WithLogTag("SETTINGS")
   152  	loader := func(mctx libkb.MetaContext) (interface{}, error) {
   153  		return teams.GetKBFSTeamSettings(mctx.Ctx(), mctx.G(), arg.TeamID.IsPublic(), arg.TeamID)
   154  	}
   155  	servedRet, err := h.service.offlineRPCCache.Serve(mctx, arg.Oa, offline.Version(1), "kbfs.getKBFSTeamSettings", false, arg, &ret, loader)
   156  	if err != nil {
   157  		return keybase1.KBFSTeamSettings{}, err
   158  	}
   159  	if s, ok := servedRet.(keybase1.KBFSTeamSettings); ok {
   160  		ret = s
   161  	}
   162  	return ret, nil
   163  }
   164  
   165  func (h *KBFSHandler) UpgradeTLF(ctx context.Context, arg keybase1.UpgradeTLFArg) error {
   166  	return tlfupgrade.UpgradeTLFForKBFS(ctx, h.G(), arg.TlfName, arg.Public)
   167  }
   168  
   169  // getKeyFn returns a function that gets an encryption key for storing
   170  // favorites.
   171  func (h *KBFSHandler) getKeyFn() func(context.Context) ([32]byte, error) {
   172  	keyFn := func(ctx context.Context) ([32]byte, error) {
   173  		return encrypteddb.GetSecretBoxKey(ctx, h.G(),
   174  			libkb.EncryptionReasonKBFSFavorites, "encrypting kbfs favorites")
   175  	}
   176  	return keyFn
   177  }
   178  
   179  // EncryptFavorites encrypts cached favorites to store on disk.
   180  func (h *KBFSHandler) EncryptFavorites(ctx context.Context,
   181  	dataToDecrypt []byte) (res []byte, err error) {
   182  	return encrypteddb.EncodeBox(ctx, dataToDecrypt, h.getKeyFn())
   183  }
   184  
   185  // DecryptFavorites decrypts cached favorites stored on disk.
   186  func (h *KBFSHandler) DecryptFavorites(ctx context.Context,
   187  	dataToEncrypt []byte) (res []byte, err error) {
   188  	err = encrypteddb.DecodeBox(ctx, dataToEncrypt, h.getKeyFn(), &res)
   189  	return res, err
   190  }