github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/libkbfs/keybase_service_base.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 "fmt" 9 "strings" 10 "sync" 11 "time" 12 13 "github.com/keybase/client/go/kbfs/data" 14 "github.com/keybase/client/go/kbfs/favorites" 15 "github.com/keybase/client/go/kbfs/idutil" 16 "github.com/keybase/client/go/kbfs/kbfscrypto" 17 "github.com/keybase/client/go/kbfs/kbfsmd" 18 "github.com/keybase/client/go/kbfs/tlf" 19 "github.com/keybase/client/go/kbfs/tlfhandle" 20 kbname "github.com/keybase/client/go/kbun" 21 "github.com/keybase/client/go/libkb" 22 "github.com/keybase/client/go/logger" 23 "github.com/keybase/client/go/protocol/keybase1" 24 "github.com/keybase/go-framed-msgpack-rpc/rpc" 25 "github.com/pkg/errors" 26 "golang.org/x/net/context" 27 ) 28 29 const ( 30 cacheNotWriterExpiration = 5 * time.Second 31 ) 32 33 // KeybaseServiceBase implements most of KeybaseService from protocol 34 // defined clients. 35 type KeybaseServiceBase struct { 36 context Context 37 identifyClient keybase1.IdentifyInterface 38 userClient keybase1.UserInterface 39 teamsClient keybase1.TeamsInterface 40 merkleClient keybase1.MerkleInterface 41 sessionClient keybase1.SessionInterface 42 favoriteClient keybase1.FavoriteInterface 43 kbfsClient keybase1.KbfsInterface 44 kbfsMountClient keybase1.KbfsMountInterface 45 gitClient keybase1.GitInterface 46 kvstoreClient keybase1.KvstoreInterface 47 log logger.Logger 48 49 config Config 50 merkleRoot *EventuallyConsistentMerkleRoot 51 52 sessionCacheLock sync.RWMutex 53 // Set to the zero value when invalidated. 54 cachedCurrentSession idutil.SessionInfo 55 sessionInProgressCh chan struct{} 56 57 userCacheLock sync.RWMutex 58 // Map entries are removed when invalidated. 59 userCache map[keybase1.UID]idutil.UserInfo 60 61 teamCacheLock sync.RWMutex 62 // Map entries are removed when invalidated. 63 teamCache map[keybase1.TeamID]idutil.TeamInfo 64 notWriterCache map[keybase1.TeamID]map[keybase1.UID]time.Time 65 } 66 67 // Wrapper over `KeybaseServiceBase` implementing a `merkleRootGetter` 68 // that gets the merkle root directly from the service, without using 69 // the cache. 70 type keybaseServiceMerkleGetter struct { 71 k *KeybaseServiceBase 72 } 73 74 var _ idutil.MerkleRootGetter = (*keybaseServiceMerkleGetter)(nil) 75 76 func (k *keybaseServiceMerkleGetter) GetCurrentMerkleRoot( 77 ctx context.Context) (keybase1.MerkleRootV2, time.Time, error) { 78 return k.k.getCurrentMerkleRoot(ctx) 79 } 80 81 func (k *keybaseServiceMerkleGetter) VerifyMerkleRoot( 82 _ context.Context, _ keybase1.MerkleRootV2, _ keybase1.KBFSRoot) error { 83 panic("constMerkleRootGetter doesn't verify merkle roots") 84 } 85 86 // NewKeybaseServiceBase makes a new KeybaseService. 87 func NewKeybaseServiceBase(config Config, kbCtx Context, log logger.Logger) *KeybaseServiceBase { 88 k := KeybaseServiceBase{ 89 config: config, 90 context: kbCtx, 91 log: log, 92 userCache: make(map[keybase1.UID]idutil.UserInfo), 93 teamCache: make(map[keybase1.TeamID]idutil.TeamInfo), 94 notWriterCache: make(map[keybase1.TeamID]map[keybase1.UID]time.Time), 95 } 96 if config != nil { 97 k.merkleRoot = NewEventuallyConsistentMerkleRoot( 98 config, &keybaseServiceMerkleGetter{&k}) 99 } 100 return &k 101 } 102 103 // FillClients sets the client protocol implementations needed for a KeybaseService. 104 func (k *KeybaseServiceBase) FillClients( 105 identifyClient keybase1.IdentifyInterface, 106 userClient keybase1.UserInterface, teamsClient keybase1.TeamsInterface, 107 merkleClient keybase1.MerkleInterface, 108 sessionClient keybase1.SessionInterface, 109 favoriteClient keybase1.FavoriteInterface, 110 kbfsClient keybase1.KbfsInterface, 111 kbfsMountClient keybase1.KbfsMountInterface, 112 gitClient keybase1.GitInterface, kvstoreClient keybase1.KvstoreClient) { 113 k.identifyClient = identifyClient 114 k.userClient = userClient 115 k.teamsClient = teamsClient 116 k.merkleClient = merkleClient 117 k.sessionClient = sessionClient 118 k.favoriteClient = favoriteClient 119 k.kbfsClient = kbfsClient 120 k.kbfsMountClient = kbfsMountClient 121 k.gitClient = gitClient 122 k.kvstoreClient = kvstoreClient 123 } 124 125 type addVerifyingKeyFunc func(kbfscrypto.VerifyingKey) 126 type addCryptPublicKeyFunc func(kbfscrypto.CryptPublicKey) 127 128 // processKey adds the given public key to the appropriate verifying 129 // or crypt list (as return values), and also updates the given name 130 // map and parent map in place. 131 func processKey(publicKey keybase1.PublicKeyV2NaCl, 132 addVerifyingKey addVerifyingKeyFunc, 133 addCryptPublicKey addCryptPublicKeyFunc, 134 kidNames map[keybase1.KID]string, 135 parents map[keybase1.KID]keybase1.KID) error { 136 // Import the KID to validate it. 137 key, err := libkb.ImportKeypairFromKID(publicKey.Base.Kid) 138 if err != nil { 139 return err 140 } 141 if publicKey.Base.IsSibkey { 142 addVerifyingKey(kbfscrypto.MakeVerifyingKey(key.GetKID())) 143 } else { 144 addCryptPublicKey(kbfscrypto.MakeCryptPublicKey(key.GetKID())) 145 } 146 if publicKey.DeviceDescription != "" { 147 kidNames[publicKey.Base.Kid] = publicKey.DeviceDescription 148 } 149 150 if publicKey.Parent != nil { 151 parents[publicKey.Base.Kid] = *publicKey.Parent 152 } 153 return nil 154 } 155 156 // updateKIDNamesFromParents sets the name of each KID without a name 157 // that has a a parent with a name, to that parent's name. 158 func updateKIDNamesFromParents(kidNames map[keybase1.KID]string, 159 parents map[keybase1.KID]keybase1.KID) { 160 for kid, parent := range parents { 161 if _, ok := kidNames[kid]; ok { 162 continue 163 } 164 if parentName, ok := kidNames[parent]; ok { 165 kidNames[kid] = parentName 166 } 167 } 168 } 169 170 func filterKeys(keys map[keybase1.KID]keybase1.PublicKeyV2NaCl) ( 171 verifyingKeys []kbfscrypto.VerifyingKey, 172 cryptPublicKeys []kbfscrypto.CryptPublicKey, 173 kidNames map[keybase1.KID]string, err error) { 174 kidNames = make(map[keybase1.KID]string, len(keys)) 175 parents := make(map[keybase1.KID]keybase1.KID, len(keys)) 176 177 addVerifyingKey := func(key kbfscrypto.VerifyingKey) { 178 verifyingKeys = append(verifyingKeys, key) 179 } 180 addCryptPublicKey := func(key kbfscrypto.CryptPublicKey) { 181 cryptPublicKeys = append(cryptPublicKeys, key) 182 } 183 184 for _, publicKey := range keys { 185 if publicKey.Base.Revocation != nil { 186 continue 187 } 188 189 err := processKey(publicKey, addVerifyingKey, addCryptPublicKey, 190 kidNames, parents) 191 if err != nil { 192 return nil, nil, nil, err 193 } 194 } 195 updateKIDNamesFromParents(kidNames, parents) 196 return verifyingKeys, cryptPublicKeys, kidNames, nil 197 } 198 199 func (k *KeybaseServiceBase) filterRevokedKeys( 200 ctx context.Context, 201 uid keybase1.UID, 202 keys map[keybase1.KID]keybase1.PublicKeyV2NaCl, 203 reset *keybase1.ResetSummary) ( 204 map[kbfscrypto.VerifyingKey]idutil.RevokedKeyInfo, 205 map[kbfscrypto.CryptPublicKey]idutil.RevokedKeyInfo, 206 map[keybase1.KID]string, error) { 207 verifyingKeys := make(map[kbfscrypto.VerifyingKey]idutil.RevokedKeyInfo) 208 cryptPublicKeys := make( 209 map[kbfscrypto.CryptPublicKey]idutil.RevokedKeyInfo) 210 var kidNames = map[keybase1.KID]string{} 211 var parents = map[keybase1.KID]keybase1.KID{} 212 213 for _, key := range keys { 214 var info idutil.RevokedKeyInfo 215 switch { 216 case key.Base.Revocation != nil: 217 info.Time = key.Base.Revocation.Time 218 info.MerkleRoot = key.Base.Revocation.PrevMerkleRootSigned 219 // If we don't have a prev seqno, then we already have the 220 // best merkle data we're going to get. 221 info.SetFilledInMerkle(info.MerkleRoot.Seqno <= 0) 222 info.SetSigChainLocation(key.Base.Revocation.SigChainLocation) 223 case reset != nil: 224 info.Time = keybase1.ToTime(keybase1.FromUnixTime(reset.Ctime)) 225 info.MerkleRoot.Seqno = reset.MerkleRoot.Seqno 226 info.MerkleRoot.HashMeta = reset.MerkleRoot.HashMeta 227 // If we don't have a prev seqno, then we already have the 228 // best merkle data we're going to get. 229 info.SetFilledInMerkle(info.MerkleRoot.Seqno <= 0) 230 info.SetResetInfo(reset.ResetSeqno, true) 231 default: 232 // Not revoked. 233 continue 234 } 235 236 addVerifyingKey := func(key kbfscrypto.VerifyingKey) { 237 verifyingKeys[key] = info 238 } 239 addCryptPublicKey := func(key kbfscrypto.CryptPublicKey) { 240 cryptPublicKeys[key] = info 241 } 242 err := processKey(key, addVerifyingKey, addCryptPublicKey, 243 kidNames, parents) 244 if err != nil { 245 return nil, nil, nil, err 246 } 247 } 248 updateKIDNamesFromParents(kidNames, parents) 249 return verifyingKeys, cryptPublicKeys, kidNames, nil 250 251 } 252 253 func (k *KeybaseServiceBase) getCachedCurrentSession() idutil.SessionInfo { 254 k.sessionCacheLock.RLock() 255 defer k.sessionCacheLock.RUnlock() 256 return k.cachedCurrentSession 257 } 258 259 func (k *KeybaseServiceBase) setCachedCurrentSession(s idutil.SessionInfo) { 260 k.sessionCacheLock.Lock() 261 defer k.sessionCacheLock.Unlock() 262 k.cachedCurrentSession = s 263 } 264 265 func (k *KeybaseServiceBase) getCachedUserInfo( 266 uid keybase1.UID) idutil.UserInfo { 267 k.userCacheLock.RLock() 268 defer k.userCacheLock.RUnlock() 269 return k.userCache[uid] 270 } 271 272 func (k *KeybaseServiceBase) setCachedUserInfo( 273 uid keybase1.UID, info idutil.UserInfo) { 274 k.userCacheLock.Lock() 275 defer k.userCacheLock.Unlock() 276 if info.Name == kbname.NormalizedUsername("") { 277 delete(k.userCache, uid) 278 } else { 279 k.userCache[uid] = info 280 } 281 } 282 283 func (k *KeybaseServiceBase) getCachedTeamInfo( 284 tid keybase1.TeamID) idutil.TeamInfo { 285 k.teamCacheLock.RLock() 286 defer k.teamCacheLock.RUnlock() 287 return k.teamCache[tid] 288 } 289 290 func (k *KeybaseServiceBase) setCachedTeamInfo( 291 tid keybase1.TeamID, info idutil.TeamInfo) { 292 k.teamCacheLock.Lock() 293 defer k.teamCacheLock.Unlock() 294 if info.Name == kbname.NormalizedUsername("") { 295 delete(k.teamCache, tid) 296 delete(k.notWriterCache, tid) 297 } else { 298 k.teamCache[tid] = info 299 } 300 } 301 302 func (k *KeybaseServiceBase) getCachedNotWriter( 303 tid keybase1.TeamID, uid keybase1.UID) (notWriter bool) { 304 // Full write lock because of the delete-after-expiration code 305 // below. 306 k.teamCacheLock.Lock() 307 defer k.teamCacheLock.Unlock() 308 cachedTime, notWriter := k.notWriterCache[tid][uid] 309 if !notWriter { 310 return false 311 } 312 313 if k.config.Clock().Now().Sub(cachedTime) > cacheNotWriterExpiration { 314 delete(k.notWriterCache[tid], uid) 315 return false 316 } 317 return true 318 } 319 320 func (k *KeybaseServiceBase) setCachedNotWriter( 321 tid keybase1.TeamID, uid keybase1.UID) { 322 k.teamCacheLock.Lock() 323 defer k.teamCacheLock.Unlock() 324 teamMap := k.notWriterCache[tid] 325 if teamMap == nil { 326 teamMap = make(map[keybase1.UID]time.Time) 327 k.notWriterCache[tid] = teamMap 328 } 329 teamMap[uid] = k.config.Clock().Now() 330 } 331 332 // ClearCaches implements the KeybaseService interface for 333 // KeybaseServiceBase. 334 func (k *KeybaseServiceBase) ClearCaches(ctx context.Context) { 335 k.log.CDebugf(ctx, "Clearing KBFS-side user and team caches") 336 337 k.setCachedCurrentSession(idutil.SessionInfo{}) 338 func() { 339 k.userCacheLock.Lock() 340 defer k.userCacheLock.Unlock() 341 k.userCache = make(map[keybase1.UID]idutil.UserInfo) 342 }() 343 k.teamCacheLock.Lock() 344 defer k.teamCacheLock.Unlock() 345 k.teamCache = make(map[keybase1.TeamID]idutil.TeamInfo) 346 k.notWriterCache = make(map[keybase1.TeamID]map[keybase1.UID]time.Time) 347 } 348 349 // LoggedIn implements keybase1.NotifySessionInterface. 350 func (k *KeybaseServiceBase) LoggedIn(ctx context.Context, arg keybase1.LoggedInArg) error { 351 k.log.CDebugf(ctx, "Current session logged in: %s, signedUp: %t", arg.Username, arg.SignedUp) 352 // Since we don't have the whole session, just clear the cache and 353 // repopulate it. The `CurrentSession` call executes the "logged 354 // in" flow. 355 k.setCachedCurrentSession(idutil.SessionInfo{}) 356 const sessionID = 0 357 _, err := k.CurrentSession(ctx, sessionID) 358 if err != nil { 359 k.log.CDebugf(ctx, "Getting current session failed when %s is logged "+ 360 "in, so pretending user has logged out: %v", 361 arg.Username, err) 362 if k.config != nil { 363 serviceLoggedOut(ctx, k.config) 364 } 365 return nil 366 } 367 368 return nil 369 } 370 371 // LoggedOut implements keybase1.NotifySessionInterface. 372 func (k *KeybaseServiceBase) LoggedOut(ctx context.Context) error { 373 k.log.CDebugf(ctx, "Current session logged out") 374 k.setCachedCurrentSession(idutil.SessionInfo{}) 375 if k.config != nil { 376 serviceLoggedOut(ctx, k.config) 377 } 378 return nil 379 } 380 381 // KeyfamilyChanged implements keybase1.NotifyKeyfamilyInterface. 382 func (k *KeybaseServiceBase) KeyfamilyChanged(ctx context.Context, 383 uid keybase1.UID) error { 384 k.log.CDebugf(ctx, "Key family for user %s changed", uid) 385 k.setCachedUserInfo(uid, idutil.UserInfo{}) 386 387 if k.getCachedCurrentSession().UID == uid { 388 mdServer := k.config.MDServer() 389 if mdServer != nil { 390 // Ignore any errors for now, we don't want to block this 391 // notification and it's not worth spawning a goroutine for. 392 mdServer.CheckForRekeys(context.Background()) 393 } 394 } 395 396 return nil 397 } 398 399 // ReachabilityChanged implements keybase1.ReachabiltyInterface. 400 func (k *KeybaseServiceBase) ReachabilityChanged(ctx context.Context, 401 reachability keybase1.Reachability) error { 402 k.log.CDebugf(ctx, "CheckReachability invoked: %v", reachability) 403 if reachability.Reachable == keybase1.Reachable_YES { 404 k.config.KBFSOps().PushConnectionStatusChange(GregorServiceName, nil) 405 } else { 406 k.config.KBFSOps().PushConnectionStatusChange( 407 GregorServiceName, errDisconnected{}) 408 } 409 mdServer := k.config.MDServer() 410 if mdServer != nil { 411 mdServer.CheckReachability(ctx) 412 } 413 return nil 414 } 415 416 // StartReachability implements keybase1.ReachabilityInterface. 417 func (k *KeybaseServiceBase) StartReachability(ctx context.Context) (res keybase1.Reachability, err error) { 418 return k.CheckReachability(ctx) 419 } 420 421 // CheckReachability implements keybase1.ReachabilityInterface. 422 func (k *KeybaseServiceBase) CheckReachability(ctx context.Context) (res keybase1.Reachability, err error) { 423 res.Reachable = keybase1.Reachable_NO 424 mdServer := k.config.MDServer() 425 if mdServer != nil && mdServer.IsConnected() { 426 res.Reachable = keybase1.Reachable_YES 427 } 428 return res, nil 429 } 430 431 // PaperKeyCached implements keybase1.NotifyPaperKeyInterface. 432 func (k *KeybaseServiceBase) PaperKeyCached(ctx context.Context, 433 arg keybase1.PaperKeyCachedArg) error { 434 k.log.CDebugf(ctx, "Paper key for %s cached", arg.Uid) 435 436 if k.getCachedCurrentSession().UID == arg.Uid { 437 err := k.config.KBFSOps().KickoffAllOutstandingRekeys() 438 if err != nil { 439 // Ignore and log errors here. For now the only way it could error 440 // is when the method is called on a folderBranchOps which is a 441 // developer mistake and not recoverable from code. 442 k.log.CDebugf(ctx, 443 "Calling KickoffAllOutstandingRekeys error: %s", err) 444 } 445 // Ignore any errors for now, we don't want to block this 446 // notification and it's not worth spawning a goroutine for. 447 mdServer := k.config.MDServer() 448 if mdServer != nil { 449 mdServer.CheckForRekeys(context.Background()) 450 } 451 } 452 453 return nil 454 } 455 456 // ClientOutOfDate implements keybase1.NotifySessionInterface. 457 func (k *KeybaseServiceBase) ClientOutOfDate(ctx context.Context, 458 arg keybase1.ClientOutOfDateArg) error { 459 k.log.CDebugf(ctx, "Client out of date: %v", arg) 460 return nil 461 } 462 463 // RootAuditError implements keybase1.NotifyAuditInterface. 464 func (k *KeybaseServiceBase) RootAuditError(ctx context.Context, 465 arg keybase1.RootAuditErrorArg) error { 466 k.log.CDebugf(ctx, "Merkle tree audit error: %v", arg.Message) 467 return nil 468 } 469 470 // ConvertIdentifyError converts a errors during identify into KBFS errors 471 func ConvertIdentifyError(assertion string, err error) error { 472 switch err.(type) { 473 case libkb.NotFoundError: 474 return idutil.NoSuchUserError{Input: assertion} 475 case libkb.ResolutionError: 476 return idutil.NoSuchUserError{Input: assertion} 477 } 478 return err 479 } 480 481 // Resolve implements the KeybaseService interface for KeybaseServiceBase. 482 func (k *KeybaseServiceBase) Resolve( 483 ctx context.Context, assertion string, 484 offline keybase1.OfflineAvailability) ( 485 kbname.NormalizedUsername, keybase1.UserOrTeamID, error) { 486 res, err := k.identifyClient.Resolve3( 487 ctx, keybase1.Resolve3Arg{ 488 Assertion: assertion, 489 Oa: offline, 490 }) 491 if err != nil { 492 return kbname.NormalizedUsername(""), keybase1.UserOrTeamID(""), 493 ConvertIdentifyError(assertion, err) 494 } 495 return kbname.NewNormalizedUsername(res.Name), res.Id, nil 496 } 497 498 // Identify implements the KeybaseService interface for KeybaseServiceBase. 499 func (k *KeybaseServiceBase) Identify( 500 ctx context.Context, assertion, reason string, 501 offline keybase1.OfflineAvailability) ( 502 kbname.NormalizedUsername, keybase1.UserOrTeamID, error) { 503 // setting UseDelegateUI to true here will cause daemon to use 504 // registered identify ui providers instead of terminal if any 505 // are available. If not, then it will use the terminal UI. 506 arg := keybase1.IdentifyLiteArg{ 507 Assertion: assertion, 508 UseDelegateUI: true, 509 Reason: keybase1.IdentifyReason{Reason: reason}, 510 // No need to go back and forth with the UI until the service 511 // knows for sure there's a need for a dialogue. 512 CanSuppressUI: true, 513 Oa: offline, 514 } 515 516 ei := tlfhandle.GetExtendedIdentify(ctx) 517 arg.IdentifyBehavior = ei.Behavior 518 519 res, err := k.identifyClient.IdentifyLite(ctx, arg) 520 // IdentifyLite still returns keybase1.UserPlusKeys data (sans 521 // keys), even if it gives a NoSigChainError or a UserDeletedError, 522 // and in KBFS it's fine if the user doesn't have a full sigchain 523 // (e.g., it's just like the sharing before signup case, except 524 // the user already has a UID). Both types of users are based 525 // entirely on server trust anyway. 526 switch err.(type) { 527 case nil: 528 case libkb.NoSigChainError, libkb.UserDeletedError: 529 ei.OnError(ctx) 530 // But if the username is blame, just return it, since the 531 // returned username would be useless and confusing. 532 if res.Ul.Name == "" { 533 return kbname.NormalizedUsername(""), keybase1.UserOrTeamID(""), err 534 } 535 k.log.CDebugf(ctx, 536 "Ignoring error (%s) for user %s with no sigchain; "+ 537 "error type=%T", err, res.Ul.Name, err) 538 default: 539 // If the caller is waiting for breaks, let them know we got an error. 540 ei.OnError(ctx) 541 return kbname.NormalizedUsername(""), keybase1.UserOrTeamID(""), 542 ConvertIdentifyError(assertion, err) 543 } 544 545 // This is required for every identify call. The userBreak 546 // function will take care of checking if res.TrackBreaks is nil 547 // or not. 548 name := kbname.NormalizedUsername(res.Ul.Name) 549 if res.Ul.Id.IsUser() { 550 asUser, err := res.Ul.Id.AsUser() 551 if err != nil { 552 return kbname.NormalizedUsername(""), keybase1.UserOrTeamID(""), err 553 } 554 ei.UserBreak(ctx, name, asUser, res.TrackBreaks) 555 } else if !res.Ul.Id.IsNil() { 556 ei.TeamBreak(ctx, res.Ul.Id.AsTeamOrBust(), res.TrackBreaks) 557 } 558 559 return name, res.Ul.Id, nil 560 } 561 562 // NormalizeSocialAssertion implements the KeybaseService interface for 563 // KeybaseServiceBase. 564 func (k *KeybaseServiceBase) NormalizeSocialAssertion( 565 ctx context.Context, assertion string) (keybase1.SocialAssertion, error) { 566 return k.identifyClient.NormalizeSocialAssertion(ctx, assertion) 567 } 568 569 // ResolveIdentifyImplicitTeam implements the KeybaseService interface 570 // for KeybaseServiceBase. 571 func (k *KeybaseServiceBase) ResolveIdentifyImplicitTeam( 572 ctx context.Context, assertions, suffix string, tlfType tlf.Type, 573 doIdentifies bool, reason string, 574 offline keybase1.OfflineAvailability) (idutil.ImplicitTeamInfo, error) { 575 if tlfType != tlf.Private && tlfType != tlf.Public { 576 return idutil.ImplicitTeamInfo{}, fmt.Errorf( 577 "Invalid implicit team TLF type: %s", tlfType) 578 } 579 580 arg := keybase1.ResolveIdentifyImplicitTeamArg{ 581 Assertions: assertions, 582 Suffix: suffix, 583 DoIdentifies: doIdentifies, 584 Reason: keybase1.IdentifyReason{Reason: reason}, 585 Create: true, 586 IsPublic: tlfType == tlf.Public, 587 Oa: offline, 588 } 589 590 ei := tlfhandle.GetExtendedIdentify(ctx) 591 arg.IdentifyBehavior = ei.Behavior 592 593 res, err := k.identifyClient.ResolveIdentifyImplicitTeam(ctx, arg) 594 if err != nil { 595 return idutil.ImplicitTeamInfo{}, ConvertIdentifyError(assertions, err) 596 } 597 if strings.Contains(res.DisplayName, "_implicit_team_") { 598 k.log.CWarningf( 599 ctx, "Got display name %s for assertions %s", 600 res.DisplayName, assertions) 601 } 602 name := kbname.NormalizedUsername(res.DisplayName) 603 604 // Exactly one break callback is required for every identify call. 605 if doIdentifies { 606 if len(res.TrackBreaks) > 0 { 607 // Iterate the map to get one entry, then break. 608 for userVer, breaks := range res.TrackBreaks { 609 // TODO: resolve the UID into a username so we don't have to 610 // pass in the full display name here? 611 ei.UserBreak(ctx, name, userVer.Uid, &breaks) 612 break 613 } 614 } else { 615 ei.TeamBreak(ctx, keybase1.TeamID(""), nil) 616 } 617 } 618 619 iteamInfo := idutil.ImplicitTeamInfo{ 620 Name: name, 621 TID: res.TeamID, 622 } 623 if res.FolderID != "" { 624 iteamInfo.TlfID, err = tlf.ParseID(res.FolderID.String()) 625 if err != nil { 626 return idutil.ImplicitTeamInfo{}, err 627 } 628 } 629 630 return iteamInfo, nil 631 } 632 633 // ResolveImplicitTeamByID implements the KeybaseService interface for 634 // KeybaseServiceBase. 635 func (k *KeybaseServiceBase) ResolveImplicitTeamByID( 636 ctx context.Context, teamID keybase1.TeamID) (name string, err error) { 637 arg := keybase1.ResolveImplicitTeamArg{ 638 Id: teamID, 639 } 640 641 res, err := k.identifyClient.ResolveImplicitTeam(ctx, arg) 642 if err != nil { 643 return "", err 644 } 645 return res.Name, nil 646 } 647 648 func (k *KeybaseServiceBase) checkForRevokedVerifyingKey( 649 ctx context.Context, currUserInfo idutil.UserInfo, kid keybase1.KID) ( 650 newUserInfo idutil.UserInfo, exists bool, err error) { 651 newUserInfo = currUserInfo 652 for key, info := range currUserInfo.RevokedVerifyingKeys { 653 if !key.KID().Equal(kid) { 654 continue 655 } 656 exists = true 657 if info.FilledInMerkle() { 658 break 659 } 660 661 k.log.CDebugf(ctx, "Filling in merkle info for user %s, revoked key %s", 662 currUserInfo.UID, kid) 663 664 // If possible, ask the service to give us the first merkle 665 // root that covers this revoke. Some older device revokes 666 // didn't yet include a prev field, so we can't refine the 667 // merkle root in those cases, and will be relying only on 668 // server trust. 669 if info.MerkleRoot.Seqno > 0 { 670 var res keybase1.NextMerkleRootRes 671 resetSeqno, isReset := info.ResetInfo() 672 if isReset { 673 res, err = k.userClient.FindNextMerkleRootAfterReset(ctx, 674 keybase1.FindNextMerkleRootAfterResetArg{ 675 Uid: currUserInfo.UID, 676 ResetSeqno: resetSeqno, 677 Prev: keybase1.ResetMerkleRoot{ 678 Seqno: info.MerkleRoot.Seqno, 679 HashMeta: info.MerkleRoot.HashMeta, 680 }, 681 }) 682 } else { 683 res, err = k.userClient.FindNextMerkleRootAfterRevoke(ctx, 684 keybase1.FindNextMerkleRootAfterRevokeArg{ 685 Uid: currUserInfo.UID, 686 Kid: kid, 687 Loc: info.SigChainLocation(), 688 Prev: info.MerkleRoot, 689 }) 690 } 691 if m, ok := err.(libkb.MerkleClientError); ok && m.IsOldTree() { // nolint 692 k.log.CDebugf(ctx, "Merkle root is too old for checking "+ 693 "the revoked key: %+v", err) 694 info.MerkleRoot.Seqno = 0 695 } else if err != nil { 696 return idutil.UserInfo{}, false, err 697 } else if res.Res != nil { 698 info.MerkleRoot = *res.Res 699 } 700 } 701 info.SetFilledInMerkle(true) 702 newUserInfo = currUserInfo.DeepCopy() 703 newUserInfo.RevokedVerifyingKeys[key] = info 704 k.setCachedUserInfo(newUserInfo.UID, newUserInfo) 705 break 706 } 707 708 return newUserInfo, exists, nil 709 } 710 711 // LoadUserPlusKeys implements the KeybaseService interface for 712 // KeybaseServiceBase. 713 func (k *KeybaseServiceBase) LoadUserPlusKeys( 714 ctx context.Context, uid keybase1.UID, pollForKID keybase1.KID, 715 offline keybase1.OfflineAvailability) (idutil.UserInfo, error) { 716 cachedUserInfo := k.getCachedUserInfo(uid) 717 if cachedUserInfo.Name != kbname.NormalizedUsername("") { 718 if pollForKID == keybase1.KID("") { 719 return cachedUserInfo, nil 720 } 721 // Skip the cache if pollForKID isn't present in 722 // `VerifyingKeys` or one of the revoked verifying keys. 723 for _, key := range cachedUserInfo.VerifyingKeys { 724 if key.KID().Equal(pollForKID) { 725 return cachedUserInfo, nil 726 } 727 } 728 729 // Check if the key is revoked, and fill in the merkle info in 730 // that case. 731 cachedUserInfo, exists, err := k.checkForRevokedVerifyingKey( 732 ctx, cachedUserInfo, pollForKID) 733 if err != nil { 734 return idutil.UserInfo{}, err 735 } 736 if exists { 737 return cachedUserInfo, nil 738 } 739 } 740 741 arg := keybase1.LoadUserPlusKeysV2Arg{ 742 Uid: uid, 743 PollForKID: pollForKID, 744 Oa: offline, 745 } 746 res, err := k.userClient.LoadUserPlusKeysV2(ctx, arg) 747 if err != nil { 748 return idutil.UserInfo{}, err 749 } 750 751 userInfo, err := k.processUserPlusKeys(ctx, res) 752 if err != nil { 753 return idutil.UserInfo{}, err 754 } 755 756 if pollForKID != keybase1.KID("") { 757 // Fill in merkle info if we were explicitly trying to load a 758 // revoked key. 759 userInfo, _, err = k.checkForRevokedVerifyingKey( 760 ctx, userInfo, pollForKID) 761 if err != nil { 762 return idutil.UserInfo{}, err 763 } 764 } 765 return userInfo, nil 766 } 767 768 func (k *KeybaseServiceBase) getLastWriterInfo( 769 ctx context.Context, teamInfo idutil.TeamInfo, tlfType tlf.Type, 770 user keybase1.UID, verifyingKey kbfscrypto.VerifyingKey) ( 771 idutil.TeamInfo, error) { 772 if _, ok := teamInfo.LastWriters[verifyingKey]; ok { 773 // Already cached, nothing to do. 774 return teamInfo, nil 775 } 776 777 res, err := k.teamsClient.FindNextMerkleRootAfterTeamRemovalBySigningKey( 778 ctx, keybase1.FindNextMerkleRootAfterTeamRemovalBySigningKeyArg{ 779 Uid: user, 780 SigningKey: verifyingKey.KID(), 781 Team: teamInfo.TID, 782 IsPublic: tlfType == tlf.Public, 783 }) 784 if err != nil { 785 return idutil.TeamInfo{}, err 786 } 787 788 // Copy any old data to avoid races. 789 newLastWriters := make( 790 map[kbfscrypto.VerifyingKey]keybase1.MerkleRootV2, 791 len(teamInfo.LastWriters)+1) 792 for k, v := range teamInfo.LastWriters { 793 newLastWriters[k] = v 794 } 795 newLastWriters[verifyingKey] = *res.Res 796 teamInfo.LastWriters = newLastWriters 797 return teamInfo, nil 798 } 799 800 var allowedLoadTeamRoles = map[keybase1.TeamRole]bool{ 801 keybase1.TeamRole_NONE: true, 802 keybase1.TeamRole_WRITER: true, 803 keybase1.TeamRole_READER: true, 804 } 805 806 // LoadTeamPlusKeys implements the KeybaseService interface for 807 // KeybaseServiceBase. 808 func (k *KeybaseServiceBase) LoadTeamPlusKeys( 809 ctx context.Context, tid keybase1.TeamID, tlfType tlf.Type, 810 desiredKeyGen kbfsmd.KeyGen, desiredUser keybase1.UserVersion, 811 desiredKey kbfscrypto.VerifyingKey, desiredRole keybase1.TeamRole, 812 offline keybase1.OfflineAvailability) (idutil.TeamInfo, error) { 813 if !allowedLoadTeamRoles[desiredRole] { 814 panic(fmt.Sprintf("Disallowed team role: %v", desiredRole)) 815 } 816 817 cachedTeamInfo := k.getCachedTeamInfo(tid) 818 if cachedTeamInfo.Name != kbname.NormalizedUsername("") { 819 // If the cached team info doesn't satisfy our desires, don't 820 // use it. 821 satisfiesDesires := true 822 if desiredKeyGen >= kbfsmd.FirstValidKeyGen { 823 // If `desiredKeyGen` is at most as large as the keygen in 824 // the cached latest team info, then our cached info 825 // satisfies our desires. 826 satisfiesDesires = desiredKeyGen <= cachedTeamInfo.LatestKeyGen 827 } 828 829 if satisfiesDesires && desiredUser.Uid.Exists() { 830 // If the user is in the writer map, that satisfies none, reader 831 // or writer desires. 832 satisfiesDesires = cachedTeamInfo.Writers[desiredUser.Uid] 833 if !satisfiesDesires { 834 if desiredRole == keybase1.TeamRole_NONE || 835 desiredRole == keybase1.TeamRole_READER { 836 // If the user isn't a writer, but the desired 837 // role is a reader, we need to check the reader 838 // map explicitly. 839 satisfiesDesires = cachedTeamInfo.Readers[desiredUser.Uid] 840 } else { 841 if !desiredKey.IsNil() { 842 // If the desired role was at least a writer, but 843 // the user isn't currently a writer, see if they 844 // ever were. 845 var err error 846 cachedTeamInfo, err = k.getLastWriterInfo( 847 ctx, cachedTeamInfo, tlfType, desiredUser.Uid, 848 desiredKey) 849 if err != nil { 850 return idutil.TeamInfo{}, err 851 } 852 k.setCachedTeamInfo(tid, cachedTeamInfo) 853 } 854 855 // If we have recently learned that the user is 856 // not a writer (e.g., of a public folder), we 857 // should rely on that cached info to avoid 858 // looking that up too often. 859 satisfiesDesires = k.getCachedNotWriter( 860 tid, desiredUser.Uid) 861 } 862 } 863 } 864 865 if satisfiesDesires { 866 return cachedTeamInfo, nil 867 } 868 } 869 870 arg := keybase1.LoadTeamPlusApplicationKeysArg{ 871 Id: tid, 872 Application: keybase1.TeamApplication_KBFS, 873 IncludeKBFSKeys: true, 874 Oa: offline, 875 } 876 877 if desiredKeyGen >= kbfsmd.FirstValidKeyGen { 878 arg.Refreshers.NeedApplicationsAtGenerationsWithKBFS = 879 map[keybase1.PerTeamKeyGeneration][]keybase1.TeamApplication{ 880 keybase1.PerTeamKeyGeneration(desiredKeyGen): { 881 keybase1.TeamApplication_KBFS, 882 }, 883 } 884 } 885 886 if desiredUser.Uid.Exists() && desiredKey.IsNil() { 887 arg.Refreshers.WantMembers = append( 888 arg.Refreshers.WantMembers, desiredUser) 889 arg.Refreshers.WantMembersRole = desiredRole 890 } 891 892 res, err := k.teamsClient.LoadTeamPlusApplicationKeys(ctx, arg) 893 if err != nil { 894 return idutil.TeamInfo{}, err 895 } 896 897 if tid != res.Id { 898 return idutil.TeamInfo{}, fmt.Errorf( 899 "TID doesn't match: %s vs %s", tid, res.Id) 900 } 901 902 info := idutil.TeamInfo{ 903 Name: kbname.NormalizedUsername(res.Name), 904 TID: res.Id, 905 CryptKeys: make(map[kbfsmd.KeyGen]kbfscrypto.TLFCryptKey), 906 Writers: make(map[keybase1.UID]bool), 907 Readers: make(map[keybase1.UID]bool), 908 } 909 for _, key := range res.ApplicationKeys { 910 keyGen := kbfsmd.KeyGen(key.KeyGeneration) 911 info.CryptKeys[keyGen] = 912 kbfscrypto.MakeTLFCryptKey(key.Key) 913 if keyGen > info.LatestKeyGen { 914 info.LatestKeyGen = keyGen 915 } 916 } 917 918 for _, user := range res.Writers { 919 info.Writers[user.Uid] = true 920 } 921 for _, user := range res.OnlyReaders { 922 info.Readers[user.Uid] = true 923 } 924 925 // For subteams, get the root team ID. 926 if tid.IsSubTeam() { 927 rootID, err := k.teamsClient.GetTeamRootID(ctx, tid) 928 if err != nil { 929 return idutil.TeamInfo{}, err 930 } 931 info.RootID = rootID 932 } 933 934 // Fill in `LastWriters`, only if needed. 935 if desiredUser.Uid.Exists() && desiredRole == keybase1.TeamRole_WRITER && 936 !info.Writers[desiredUser.Uid] && !desiredKey.IsNil() { 937 info, err = k.getLastWriterInfo( 938 ctx, info, tlfType, desiredUser.Uid, desiredKey) 939 if err != nil { 940 return idutil.TeamInfo{}, err 941 } 942 } 943 944 k.setCachedTeamInfo(tid, info) 945 946 if desiredUser.Uid.Exists() && !info.Writers[desiredUser.Uid] && 947 !(desiredRole == keybase1.TeamRole_NONE || 948 desiredRole == keybase1.TeamRole_READER) { 949 // Remember that this user was not a writer for a short 950 // amount of time, to avoid repeated lookups for writers 951 // in a public folder (for example). 952 k.setCachedNotWriter(tid, desiredUser.Uid) 953 } 954 955 return info, nil 956 } 957 958 // CreateTeamTLF implements the KeybaseService interface for 959 // KeybaseServiceBase. 960 func (k *KeybaseServiceBase) CreateTeamTLF( 961 ctx context.Context, teamID keybase1.TeamID, tlfID tlf.ID) (err error) { 962 return k.kbfsClient.CreateTLF(ctx, keybase1.CreateTLFArg{ 963 TeamID: teamID, 964 TlfID: keybase1.TLFID(tlfID.String()), 965 }) 966 } 967 968 // GetTeamSettings implements the KeybaseService interface for 969 // KeybaseServiceBase. 970 func (k *KeybaseServiceBase) GetTeamSettings( 971 ctx context.Context, teamID keybase1.TeamID, 972 offline keybase1.OfflineAvailability) ( 973 keybase1.KBFSTeamSettings, error) { 974 // TODO: get invalidations from the server and cache the settings? 975 return k.kbfsClient.GetKBFSTeamSettings( 976 ctx, keybase1.GetKBFSTeamSettingsArg{ 977 TeamID: teamID, 978 Oa: offline, 979 }) 980 } 981 982 func (k *KeybaseServiceBase) getCurrentMerkleRoot(ctx context.Context) ( 983 keybase1.MerkleRootV2, time.Time, error) { 984 const merkleFreshnessMs = int(time.Second * 60 / time.Millisecond) 985 res, err := k.merkleClient.GetCurrentMerkleRoot(ctx, merkleFreshnessMs) 986 if err != nil { 987 return keybase1.MerkleRootV2{}, time.Time{}, err 988 } 989 990 return res.Root, keybase1.FromTime(res.UpdateTime), nil 991 } 992 993 // GetCurrentMerkleRoot implements the KeybaseService interface for 994 // KeybaseServiceBase. 995 func (k *KeybaseServiceBase) GetCurrentMerkleRoot(ctx context.Context) ( 996 keybase1.MerkleRootV2, time.Time, error) { 997 // Refresh the cached value in the background if the cached value 998 // is older than 30s; if our cached value is more than 60s old, 999 // block. 1000 _, root, rootTime, err := k.merkleRoot.Get( 1001 ctx, 30*time.Second, 60*time.Second) 1002 return root, rootTime, err 1003 } 1004 1005 // VerifyMerkleRoot implements the KBPKI interface for KeybaseServiceBase. 1006 func (k *KeybaseServiceBase) VerifyMerkleRoot( 1007 ctx context.Context, root keybase1.MerkleRootV2, 1008 kbfsRoot keybase1.KBFSRoot) error { 1009 return k.merkleClient.VerifyMerkleRootAndKBFS(ctx, 1010 keybase1.VerifyMerkleRootAndKBFSArg{ 1011 Root: root, 1012 ExpectedKBFSRoot: kbfsRoot, 1013 }) 1014 } 1015 1016 func (k *KeybaseServiceBase) processUserPlusKeys( 1017 ctx context.Context, upk keybase1.UserPlusKeysV2AllIncarnations) ( 1018 idutil.UserInfo, error) { 1019 verifyingKeys, cryptPublicKeys, kidNames, err := filterKeys( 1020 upk.Current.DeviceKeys) 1021 if err != nil { 1022 return idutil.UserInfo{}, err 1023 } 1024 1025 revokedVerifyingKeys, revokedCryptPublicKeys, revokedKidNames, err := 1026 k.filterRevokedKeys( 1027 ctx, upk.Current.Uid, upk.Current.DeviceKeys, upk.Current.Reset) 1028 if err != nil { 1029 return idutil.UserInfo{}, err 1030 } 1031 1032 if len(revokedKidNames) > 0 { 1033 for k, v := range revokedKidNames { 1034 kidNames[k] = v 1035 } 1036 } 1037 1038 for _, incarnation := range upk.PastIncarnations { 1039 revokedVerifyingKeysPast, revokedCryptPublicKeysPast, 1040 revokedKidNames, err := 1041 k.filterRevokedKeys( 1042 ctx, incarnation.Uid, incarnation.DeviceKeys, incarnation.Reset) 1043 if err != nil { 1044 return idutil.UserInfo{}, err 1045 } 1046 1047 if len(revokedKidNames) > 0 { 1048 for k, v := range revokedKidNames { 1049 kidNames[k] = v 1050 } 1051 } 1052 1053 for k, v := range revokedVerifyingKeysPast { 1054 revokedVerifyingKeys[k] = v 1055 } 1056 for k, v := range revokedCryptPublicKeysPast { 1057 revokedCryptPublicKeys[k] = v 1058 } 1059 } 1060 1061 u := idutil.UserInfo{ 1062 Name: kbname.NewNormalizedUsername( 1063 upk.Current.Username), 1064 UID: upk.Current.Uid, 1065 VerifyingKeys: verifyingKeys, 1066 CryptPublicKeys: cryptPublicKeys, 1067 KIDNames: kidNames, 1068 EldestSeqno: upk.Current.EldestSeqno, 1069 RevokedVerifyingKeys: revokedVerifyingKeys, 1070 RevokedCryptPublicKeys: revokedCryptPublicKeys, 1071 } 1072 1073 k.setCachedUserInfo(upk.Current.Uid, u) 1074 return u, nil 1075 } 1076 1077 func (k *KeybaseServiceBase) getCachedCurrentSessionOrInProgressCh() ( 1078 cachedSession idutil.SessionInfo, inProgressCh chan struct{}, doRPC bool) { 1079 k.sessionCacheLock.Lock() 1080 defer k.sessionCacheLock.Unlock() 1081 1082 if k.cachedCurrentSession != (idutil.SessionInfo{}) { 1083 return k.cachedCurrentSession, nil, false 1084 } 1085 1086 // If someone already started the RPC, wait for them (and release 1087 // the lock). 1088 if k.sessionInProgressCh != nil { 1089 return idutil.SessionInfo{}, k.sessionInProgressCh, false 1090 } 1091 1092 k.sessionInProgressCh = make(chan struct{}) 1093 return idutil.SessionInfo{}, k.sessionInProgressCh, true 1094 } 1095 1096 func (k *KeybaseServiceBase) getCurrentSession( 1097 ctx context.Context, sessionID int) (idutil.SessionInfo, bool, error) { 1098 var cachedCurrentSession idutil.SessionInfo 1099 var inProgressCh chan struct{} 1100 doRPC := false 1101 // Loop until either we have the session info, or until we are the 1102 // sole goroutine that needs to make the RPC. Avoid holding the 1103 // session cache lock during the RPC, since that can result in a 1104 // deadlock if the RPC results in a call to `ClearCaches()`. 1105 for !doRPC { 1106 cachedCurrentSession, inProgressCh, doRPC = 1107 k.getCachedCurrentSessionOrInProgressCh() 1108 if cachedCurrentSession != (idutil.SessionInfo{}) { 1109 return cachedCurrentSession, false, nil 1110 } 1111 1112 if !doRPC { 1113 // Wait for another goroutine to finish the RPC. 1114 select { 1115 case <-inProgressCh: 1116 case <-ctx.Done(): 1117 return idutil.SessionInfo{}, false, ctx.Err() 1118 } 1119 } 1120 } 1121 1122 var s idutil.SessionInfo 1123 // Close and clear the in-progress channel, even on an error. 1124 defer func() { 1125 k.sessionCacheLock.Lock() 1126 defer k.sessionCacheLock.Unlock() 1127 k.cachedCurrentSession = s 1128 close(k.sessionInProgressCh) 1129 k.sessionInProgressCh = nil 1130 }() 1131 1132 res, err := k.sessionClient.CurrentSession(ctx, sessionID) 1133 if err != nil { 1134 if _, ok := err.(libkb.NoSessionError); ok { 1135 // Use an error with a proper OS error code attached to it. 1136 err = idutil.NoCurrentSessionError{} 1137 } 1138 return idutil.SessionInfo{}, false, err 1139 } 1140 s, err = idutil.SessionInfoFromProtocol(res) 1141 if err != nil { 1142 return idutil.SessionInfo{}, false, err 1143 } 1144 1145 k.log.CDebugf( 1146 ctx, "new session with username %s, uid %s, crypt public key %s, and verifying key %s", 1147 s.Name, s.UID, s.CryptPublicKey, s.VerifyingKey) 1148 return s, true, nil 1149 } 1150 1151 // CurrentSession implements the KeybaseService interface for KeybaseServiceBase. 1152 func (k *KeybaseServiceBase) CurrentSession( 1153 ctx context.Context, sessionID int) ( 1154 idutil.SessionInfo, error) { 1155 ctx = CtxWithRandomIDReplayable( 1156 ctx, CtxKeybaseServiceIDKey, CtxKeybaseServiceOpID, k.log) 1157 1158 s, newSession, err := k.getCurrentSession(ctx, sessionID) 1159 if err != nil { 1160 return idutil.SessionInfo{}, err 1161 } 1162 1163 if newSession && k.config != nil { 1164 // Don't hold the lock while calling `serviceLoggedIn`. 1165 _ = serviceLoggedIn(ctx, k.config, s, TLFJournalBackgroundWorkEnabled) 1166 } 1167 1168 return s, nil 1169 } 1170 1171 // FavoriteAdd implements the KeybaseService interface for KeybaseServiceBase. 1172 func (k *KeybaseServiceBase) FavoriteAdd(ctx context.Context, folder keybase1.FolderHandle) error { 1173 return k.favoriteClient.FavoriteAdd(ctx, keybase1.FavoriteAddArg{Folder: folder}) 1174 } 1175 1176 // FavoriteDelete implements the KeybaseService interface for KeybaseServiceBase. 1177 func (k *KeybaseServiceBase) FavoriteDelete(ctx context.Context, folder keybase1.FolderHandle) error { 1178 return k.favoriteClient.FavoriteIgnore(ctx, 1179 keybase1.FavoriteIgnoreArg{Folder: folder}) 1180 } 1181 1182 // FavoriteList implements the KeybaseService interface for KeybaseServiceBase. 1183 func (k *KeybaseServiceBase) FavoriteList(ctx context.Context, 1184 sessionID int) (keybase1.FavoritesResult, error) { 1185 return k.favoriteClient.GetFavorites(ctx, sessionID) 1186 } 1187 1188 // EncryptFavorites encrypts cached favorites to store on disk. 1189 func (k *KeybaseServiceBase) EncryptFavorites(ctx context.Context, dataToEncrypt []byte) (res []byte, err error) { 1190 return k.kbfsClient.EncryptFavorites(ctx, dataToEncrypt) 1191 } 1192 1193 // DecryptFavorites decrypts cached favorites stored on disk. 1194 func (k *KeybaseServiceBase) DecryptFavorites(ctx context.Context, dataToEncrypt []byte) (res []byte, err error) { 1195 return k.kbfsClient.DecryptFavorites(ctx, dataToEncrypt) 1196 } 1197 1198 // NotifyOnlineStatusChanged implements the KeybaseService interface for 1199 // KeybaseServiceBase. 1200 func (k *KeybaseServiceBase) NotifyOnlineStatusChanged(ctx context.Context, 1201 online bool) error { 1202 k.log.CDebugf(ctx, "Sending notification for onlineStatus: online=%v", online) 1203 return k.kbfsClient.FSOnlineStatusChangedEvent(ctx, online) 1204 } 1205 1206 // Notify implements the KeybaseService interface for KeybaseServiceBase. 1207 func (k *KeybaseServiceBase) Notify(ctx context.Context, notification *keybase1.FSNotification) error { 1208 return k.kbfsClient.FSEvent(ctx, *notification) 1209 } 1210 1211 // NotifyPathUpdated implements the KeybaseService interface for 1212 // KeybaseServiceBase. 1213 func (k *KeybaseServiceBase) NotifyPathUpdated( 1214 ctx context.Context, path string) error { 1215 return k.kbfsClient.FSPathUpdate(ctx, path) 1216 } 1217 1218 // NotifySyncStatus implements the KeybaseService interface for 1219 // KeybaseServiceBase. 1220 func (k *KeybaseServiceBase) NotifySyncStatus(ctx context.Context, 1221 status *keybase1.FSPathSyncStatus) error { 1222 return k.kbfsClient.FSSyncEvent(ctx, *status) 1223 } 1224 1225 // NotifyOverallSyncStatus implements the KeybaseService interface for 1226 // KeybaseServiceBase. 1227 func (k *KeybaseServiceBase) NotifyOverallSyncStatus( 1228 ctx context.Context, status keybase1.FolderSyncStatus) error { 1229 return k.kbfsClient.FSOverallSyncEvent(ctx, status) 1230 } 1231 1232 // NotifyFavoritesChanged implements the KeybaseService interface for 1233 // KeybaseServiceBase. 1234 func (k *KeybaseServiceBase) NotifyFavoritesChanged(ctx context.Context) error { 1235 return k.kbfsClient.FSFavoritesChangedEvent(ctx) 1236 } 1237 1238 // OnPathChange implements the SubscriptionNotifier interface. 1239 func (k *KeybaseServiceBase) OnPathChange( 1240 clientID SubscriptionManagerClientID, 1241 subscriptionIDs []SubscriptionID, path string, 1242 topics []keybase1.PathSubscriptionTopic) { 1243 subscriptionIDStrings := make([]string, 0, len(subscriptionIDs)) 1244 for _, sid := range subscriptionIDs { 1245 subscriptionIDStrings = append(subscriptionIDStrings, string(sid)) 1246 } 1247 err := k.kbfsClient.FSSubscriptionNotifyPathEvent( 1248 context.Background(), keybase1.FSSubscriptionNotifyPathEventArg{ 1249 ClientID: string(clientID), 1250 SubscriptionIDs: subscriptionIDStrings, 1251 Path: path, 1252 Topics: topics, 1253 }) 1254 if err != nil { 1255 k.log.CDebugf( 1256 context.TODO(), "Couldn't send path change notification: %+v", err) 1257 } 1258 } 1259 1260 // OnNonPathChange implements the SubscriptionNotifier interface. 1261 func (k *KeybaseServiceBase) OnNonPathChange( 1262 clientID SubscriptionManagerClientID, 1263 subscriptionIDs []SubscriptionID, topic keybase1.SubscriptionTopic) { 1264 subscriptionIDStrings := make([]string, 0, len(subscriptionIDs)) 1265 for _, sid := range subscriptionIDs { 1266 subscriptionIDStrings = append(subscriptionIDStrings, string(sid)) 1267 } 1268 err := k.kbfsClient.FSSubscriptionNotifyEvent(context.Background(), 1269 keybase1.FSSubscriptionNotifyEventArg{ 1270 ClientID: string(clientID), 1271 SubscriptionIDs: subscriptionIDStrings, 1272 Topic: topic, 1273 }) 1274 if err != nil { 1275 k.log.CDebugf( 1276 context.TODO(), 1277 "Couldn't send non-path change notification: %+v", err) 1278 } 1279 } 1280 1281 // FlushUserFromLocalCache implements the KeybaseService interface for 1282 // KeybaseServiceBase. 1283 func (k *KeybaseServiceBase) FlushUserFromLocalCache(ctx context.Context, 1284 uid keybase1.UID) { 1285 k.log.CDebugf(ctx, "Flushing cache for user %s", uid) 1286 k.setCachedUserInfo(uid, idutil.UserInfo{}) 1287 } 1288 1289 // CtxKeybaseServiceTagKey is the type used for unique context tags 1290 // used while servicing incoming keybase requests. 1291 type CtxKeybaseServiceTagKey int 1292 1293 const ( 1294 // CtxKeybaseServiceIDKey is the type of the tag for unique 1295 // operation IDs used while servicing incoming keybase requests. 1296 CtxKeybaseServiceIDKey CtxKeybaseServiceTagKey = iota 1297 ) 1298 1299 // CtxKeybaseServiceOpID is the display name for the unique operation 1300 // enqueued rekey ID tag. 1301 const CtxKeybaseServiceOpID = "KSID" 1302 1303 // FSEditListRequest implements keybase1.NotifyFSRequestInterface for 1304 // KeybaseServiceBase. 1305 func (k *KeybaseServiceBase) FSEditListRequest(ctx context.Context, 1306 req keybase1.FSEditListRequest) (err error) { 1307 ctx = CtxWithRandomIDReplayable(ctx, CtxKeybaseServiceIDKey, CtxKeybaseServiceOpID, 1308 k.log) 1309 k.log.CDebugf(ctx, "Edit list request for %s (public: %t)", 1310 req.Folder.Name, !req.Folder.Private) 1311 tlfHandle, err := getHandleFromFolderName( 1312 ctx, k.config.KBPKI(), k.config.MDOps(), k.config, req.Folder.Name, 1313 !req.Folder.Private) 1314 if err != nil { 1315 return err 1316 } 1317 1318 rootNode, _, err := k.config.KBFSOps(). 1319 GetOrCreateRootNode(ctx, tlfHandle, data.MasterBranch) 1320 if err != nil { 1321 return err 1322 } 1323 history, err := k.config.KBFSOps().GetEditHistory(ctx, 1324 rootNode.GetFolderBranch()) 1325 if err != nil { 1326 return err 1327 } 1328 1329 // TODO(KBFS-2996) Convert the edits to an RPC response. 1330 resp := keybase1.FSEditListArg{ 1331 RequestID: req.RequestID, 1332 Edits: history, 1333 } 1334 1335 k.log.CDebugf(ctx, "Sending edit history response with %d writer clusters", 1336 len(resp.Edits.History)) 1337 return k.kbfsClient.FSEditList(ctx, resp) 1338 } 1339 1340 // FSSyncStatusRequest implements keybase1.NotifyFSRequestInterface for 1341 // KeybaseServiceBase. 1342 func (k *KeybaseServiceBase) FSSyncStatusRequest(ctx context.Context, 1343 req keybase1.FSSyncStatusRequest) (err error) { 1344 k.log.CDebugf(ctx, "Got sync status request: %v", req) 1345 1346 resp := keybase1.FSSyncStatusArg{RequestID: req.RequestID} 1347 1348 // For now, just return the number of syncing bytes. 1349 jManager, err := GetJournalManager(k.config) 1350 if err == nil { 1351 status, _ := jManager.Status(ctx) 1352 resp.Status.TotalSyncingBytes = status.UnflushedBytes 1353 k.log.CDebugf(ctx, "Sending sync status response with %d syncing bytes", 1354 status.UnflushedBytes) 1355 } else { 1356 k.log.CDebugf(ctx, "No journal server, sending empty response") 1357 } 1358 1359 return k.kbfsClient.FSSyncStatus(ctx, resp) 1360 } 1361 1362 // TeamChangedByID implements keybase1.NotifyTeamInterface for 1363 // KeybaseServiceBase. 1364 func (k *KeybaseServiceBase) TeamChangedByID(ctx context.Context, 1365 arg keybase1.TeamChangedByIDArg) error { 1366 k.log.CDebugf(ctx, "Flushing cache for team %s "+ 1367 "(membershipChange=%t, keyRotated=%t, renamed=%t)", 1368 arg.TeamID, arg.Changes.MembershipChanged, 1369 arg.Changes.KeyRotated, arg.Changes.Renamed) 1370 k.setCachedTeamInfo(arg.TeamID, idutil.TeamInfo{}) 1371 1372 if arg.Changes.Renamed { 1373 k.config.KBFSOps().TeamNameChanged(ctx, arg.TeamID) 1374 } 1375 return nil 1376 } 1377 1378 // TeamChangedByName implements keybase1.NotifyTeamInterface for 1379 // KeybaseServiceBase. 1380 func (k *KeybaseServiceBase) TeamChangedByName(ctx context.Context, 1381 arg keybase1.TeamChangedByNameArg) error { 1382 // ignore 1383 return nil 1384 } 1385 1386 // TeamDeleted implements keybase1.NotifyTeamInterface for 1387 // KeybaseServiceBase. 1388 func (k *KeybaseServiceBase) TeamDeleted(ctx context.Context, 1389 teamID keybase1.TeamID) error { 1390 return nil 1391 } 1392 1393 // TeamExit implements keybase1.NotifyTeamInterface for KeybaseServiceBase. 1394 func (k *KeybaseDaemonRPC) TeamExit(context.Context, keybase1.TeamID) error { 1395 return nil 1396 } 1397 1398 // TeamRoleMapChanged implements keybase1.NotifyTeamInterface for KeybaseServiceBase. 1399 func (k *KeybaseDaemonRPC) TeamRoleMapChanged(context.Context, keybase1.UserTeamVersion) error { 1400 return nil 1401 } 1402 1403 // NewlyAddedToTeam implements keybase1.NotifyTeamInterface for 1404 // KeybaseServiceBase. 1405 func (k *KeybaseDaemonRPC) NewlyAddedToTeam(context.Context, keybase1.TeamID) error { 1406 return nil 1407 } 1408 1409 // TeamMetadataUpdate implements keybase1.NotifyTeamInterface for 1410 // KeybaseServiceBase. 1411 func (k *KeybaseDaemonRPC) TeamMetadataUpdate(context.Context) error { 1412 return nil 1413 } 1414 1415 // TeamAbandoned implements keybase1.NotifyTeamInterface for KeybaseServiceBase. 1416 func (k *KeybaseDaemonRPC) TeamAbandoned( 1417 ctx context.Context, tid keybase1.TeamID) error { 1418 k.log.CDebugf(ctx, "Implicit team %s abandoned", tid) 1419 k.setCachedTeamInfo(tid, idutil.TeamInfo{}) 1420 k.config.KBFSOps().TeamAbandoned(ctx, tid) 1421 return nil 1422 } 1423 1424 // AvatarUpdated implements keybase1.NotifyTeamInterface for KeybaseServiceBase. 1425 func (k *KeybaseDaemonRPC) AvatarUpdated(ctx context.Context, 1426 arg keybase1.AvatarUpdatedArg) error { 1427 return nil 1428 } 1429 1430 // TeamTreeMembershipsPartial implements keybase1.NotifyTeamInterface for KeybaseServiceBase. 1431 func (k *KeybaseDaemonRPC) TeamTreeMembershipsPartial(context.Context, 1432 keybase1.TeamTreeMembership) error { 1433 return nil 1434 } 1435 1436 // TeamTreeMembershipsDone implements keybase1.NotifyTeamInterface for KeybaseServiceBase. 1437 func (k *KeybaseDaemonRPC) TeamTreeMembershipsDone(context.Context, 1438 keybase1.TeamTreeMembershipsDoneResult) error { 1439 return nil 1440 } 1441 1442 // StartMigration implements keybase1.ImplicitTeamMigrationInterface for 1443 // KeybaseServiceBase. 1444 func (k *KeybaseServiceBase) StartMigration(ctx context.Context, 1445 folder keybase1.Folder) (err error) { 1446 mdServer := k.config.MDServer() 1447 if mdServer == nil { 1448 return errors.New("no mdserver") 1449 } 1450 // Making a favorite here to reuse the code that converts from 1451 // `keybase1.FolderType` into `tlf.Type`. 1452 fav := favorites.NewFolderFromProtocol(folder) 1453 handle, err := GetHandleFromFolderNameAndType( 1454 ctx, k.config.KBPKI(), k.config.MDOps(), k.config, fav.Name, fav.Type) 1455 if err != nil { 1456 return err 1457 } 1458 // Before taking the lock, first make sure this device can handle 1459 // the migration. 1460 tlfID := handle.TlfID() 1461 err = k.config.KBFSOps().CheckMigrationPerms(ctx, tlfID) 1462 if err != nil { 1463 k.log.CDebugf(ctx, "This device cannot migrate %s: %+v", tlfID, err) 1464 return err 1465 } 1466 return k.config.MDServer().StartImplicitTeamMigration(ctx, tlfID) 1467 } 1468 1469 // FinalizeMigration implements keybase1.ImplicitTeamMigrationInterface for 1470 // KeybaseServiceBase. 1471 func (k *KeybaseServiceBase) FinalizeMigration(ctx context.Context, 1472 folder keybase1.Folder) (err error) { 1473 fav := favorites.NewFolderFromProtocol(folder) 1474 handle, err := GetHandleFromFolderNameAndType( 1475 ctx, k.config.KBPKI(), k.config.MDOps(), k.config, fav.Name, fav.Type) 1476 if err != nil { 1477 return err 1478 } 1479 if handle.TypeForKeying() == tlf.TeamKeying { 1480 // Clear the cache for this implicit team, to ensure we get 1481 // all the latest key generations for the team info during the 1482 // migration. 1483 id := handle.FirstResolvedWriter() 1484 if id.IsTeamOrSubteam() { 1485 tid, err := id.AsTeam() 1486 if err != nil { 1487 return err 1488 } 1489 k.log.CDebugf(ctx, "Clearing team info for tid=%s, handle=%s", 1490 tid, handle.GetCanonicalPath()) 1491 k.setCachedTeamInfo(tid, idutil.TeamInfo{}) 1492 } 1493 } 1494 return k.config.KBFSOps().MigrateToImplicitTeam(ctx, handle.TlfID()) 1495 } 1496 1497 // GetTLFCryptKeys implements the TlfKeysInterface interface for 1498 // KeybaseServiceBase. 1499 func (k *KeybaseServiceBase) GetTLFCryptKeys(ctx context.Context, 1500 query keybase1.TLFQuery) (res keybase1.GetTLFCryptKeysRes, err error) { 1501 if ctx, err = tlfhandle.MakeExtendedIdentify( 1502 CtxWithRandomIDReplayable(ctx, 1503 CtxKeybaseServiceIDKey, CtxKeybaseServiceOpID, k.log), 1504 query.IdentifyBehavior, 1505 ); err != nil { 1506 return keybase1.GetTLFCryptKeysRes{}, err 1507 } 1508 1509 tlfHandle, err := getHandleFromFolderName( 1510 ctx, k.config.KBPKI(), k.config.MDOps(), k.config, query.TlfName, false) 1511 if err != nil { 1512 return res, err 1513 } 1514 1515 res.NameIDBreaks.CanonicalName = keybase1.CanonicalTlfName( 1516 tlfHandle.GetCanonicalName()) 1517 1518 keys, id, err := k.config.KBFSOps().GetTLFCryptKeys(ctx, tlfHandle) 1519 if err != nil { 1520 return res, err 1521 } 1522 res.NameIDBreaks.TlfID = keybase1.TLFID(id.String()) 1523 1524 for i, key := range keys { 1525 res.CryptKeys = append(res.CryptKeys, keybase1.CryptKey{ 1526 KeyGeneration: int(kbfsmd.FirstValidKeyGen) + i, 1527 Key: keybase1.Bytes32(key.Data()), 1528 }) 1529 } 1530 1531 if query.IdentifyBehavior.WarningInsteadOfErrorOnBrokenTracks() { 1532 res.NameIDBreaks.Breaks = tlfhandle.GetExtendedIdentify(ctx). 1533 GetTlfBreakAndClose() 1534 } 1535 1536 return res, nil 1537 } 1538 1539 // GetPublicCanonicalTLFNameAndID implements the TlfKeysInterface interface for 1540 // KeybaseServiceBase. 1541 func (k *KeybaseServiceBase) GetPublicCanonicalTLFNameAndID( 1542 ctx context.Context, query keybase1.TLFQuery) ( 1543 res keybase1.CanonicalTLFNameAndIDWithBreaks, err error) { 1544 if ctx, err = tlfhandle.MakeExtendedIdentify( 1545 CtxWithRandomIDReplayable(ctx, 1546 CtxKeybaseServiceIDKey, CtxKeybaseServiceOpID, k.log), 1547 query.IdentifyBehavior, 1548 ); err != nil { 1549 return keybase1.CanonicalTLFNameAndIDWithBreaks{}, err 1550 } 1551 1552 tlfHandle, err := getHandleFromFolderName( 1553 ctx, k.config.KBPKI(), k.config.MDOps(), k.config, query.TlfName, 1554 true /* public */) 1555 if err != nil { 1556 return res, err 1557 } 1558 1559 res.CanonicalName = keybase1.CanonicalTlfName( 1560 tlfHandle.GetCanonicalName()) 1561 1562 id, err := k.config.KBFSOps().GetTLFID(ctx, tlfHandle) 1563 if err != nil { 1564 return res, err 1565 } 1566 res.TlfID = keybase1.TLFID(id.String()) 1567 1568 if query.IdentifyBehavior.WarningInsteadOfErrorOnBrokenTracks() { 1569 res.Breaks = tlfhandle.GetExtendedIdentify(ctx).GetTlfBreakAndClose() 1570 } 1571 1572 return res, nil 1573 } 1574 1575 // EstablishMountDir asks the service for the current mount path 1576 func (k *KeybaseServiceBase) EstablishMountDir(ctx context.Context) ( 1577 string, error) { 1578 dir, err := k.kbfsMountClient.GetCurrentMountDir(ctx) 1579 if err != nil { 1580 k.log.CInfof(ctx, "GetCurrentMountDir fails - ", err) 1581 return "", err 1582 } 1583 if dir == "" { 1584 dirs, err := k.kbfsMountClient.GetAllAvailableMountDirs(ctx) 1585 if err != nil { 1586 k.log.CInfof(ctx, "GetAllAvailableMountDirs fails - ", err) 1587 return "", err 1588 } 1589 dir, err = chooseDefaultMount(ctx, dirs, k.log) 1590 if err != nil { 1591 k.log.CInfof(ctx, "chooseDefaultMount fails - ", err) 1592 return "", err 1593 } 1594 err2 := k.kbfsMountClient.SetCurrentMountDir(ctx, dir) 1595 if err2 != nil { 1596 k.log.CInfof(ctx, "SetCurrentMountDir fails - ", err2) 1597 } 1598 // Continue mounting even if we can't save the mount 1599 k.log.CDebugf(ctx, "Choosing mountdir %s from %v", dir, dirs) 1600 } 1601 return dir, err 1602 } 1603 1604 // PutGitMetadata implements the KeybaseService interface for 1605 // KeybaseServiceBase. 1606 func (k *KeybaseServiceBase) PutGitMetadata( 1607 ctx context.Context, folder keybase1.FolderHandle, repoID keybase1.RepoID, 1608 metadata keybase1.GitLocalMetadata) error { 1609 return k.gitClient.PutGitMetadata(ctx, keybase1.PutGitMetadataArg{ 1610 Folder: folder, 1611 RepoID: repoID, 1612 Metadata: metadata, 1613 }) 1614 } 1615 1616 // GetKVStoreClient implements the KeybaseService interface for 1617 // KeybaseServiceBase. 1618 func (k *KeybaseServiceBase) GetKVStoreClient() keybase1.KvstoreInterface { 1619 return k.kvstoreClient 1620 } 1621 1622 // GetKeybaseDaemonRawClient implements the KeybaseService interface for 1623 // KeybaseServiceBase. 1624 func (k *KeybaseServiceBase) GetKeybaseDaemonRawClient() rpc.GenericClient { 1625 return nil 1626 }