github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/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 }