github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/teams/loader.go (about) 1 package teams 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "sort" 8 "sync" 9 "time" 10 11 "golang.org/x/net/context" 12 13 "github.com/keybase/client/go/gregor" 14 "github.com/keybase/client/go/libkb" 15 "github.com/keybase/client/go/protocol/keybase1" 16 hidden "github.com/keybase/client/go/teams/hidden" 17 storage "github.com/keybase/client/go/teams/storage" 18 pkgErrors "github.com/pkg/errors" 19 ) 20 21 // Show detailed team profiling 22 var teamEnv struct { 23 Profile bool 24 UserPreloadEnable bool 25 UserPreloadParallel bool 26 UserPreloadWait bool 27 ProofSetParallel bool 28 } 29 30 func init() { 31 teamEnv.Profile = os.Getenv("KEYBASE_TEAM_PROF") == "1" 32 teamEnv.UserPreloadEnable = os.Getenv("KEYBASE_TEAM_PE") == "1" 33 teamEnv.UserPreloadParallel = os.Getenv("KEYBASE_TEAM_PP") == "1" 34 teamEnv.UserPreloadWait = os.Getenv("KEYBASE_TEAM_PW") == "1" 35 teamEnv.ProofSetParallel = os.Getenv("KEYBASE_TEAM_SP") == "0" 36 } 37 38 // How long until the tail of a team sigchain is considered non-fresh 39 const freshnessLimit = time.Duration(1) * time.Hour 40 41 // Load a Team from the TeamLoader. 42 // Can be called from inside the teams package. 43 func Load(ctx context.Context, g *libkb.GlobalContext, lArg keybase1.LoadTeamArg) (*Team, error) { 44 teamData, hidden, err := g.GetTeamLoader().Load(ctx, lArg) 45 if err != nil { 46 return nil, err 47 } 48 team := NewTeam(ctx, g, teamData, hidden) 49 50 if lArg.RefreshUIDMapper { 51 // If we just loaded the group, then inform the UIDMapper of any UID->EldestSeqno 52 // mappings, so that we're guaranteed they aren't stale. 53 team.refreshUIDMapper(ctx, g) 54 } 55 56 // OK if it errors; just move on and return the team. 57 _, _ = team.calculateAndCacheMemberCount(ctx) 58 59 return team, nil 60 } 61 62 // Loader of keybase1.TeamData objects. Handles caching. 63 // Because there is one of this global object and it is attached to G, 64 // its Load interface must return a keybase1.TeamData not a teams.Team. 65 // To load a teams.Team use the package-level function Load. 66 // Threadsafe. 67 type TeamLoader struct { 68 libkb.Contextified 69 world LoaderContext 70 storage *storage.Storage 71 merkleStorage *storage.Merkle 72 // Single-flight locks per team ID. 73 // (Private and public loads of the same ID will block each other, should be fine) 74 locktab *libkb.LockTable 75 76 // Cache lookups of team name -> ID for a few seconds, to absorb bursts of lookups 77 // from the frontend 78 nameLookupBurstCache *libkb.BurstCache 79 80 // We can get pushed by the server into "force repoll" mode, in which we're 81 // not getting cache invalidations. An example: when Coyne or Nojima revokes 82 // a device. We want to cut down on notification spam. So instead, all attempts 83 // to load a team result in a preliminary poll for freshness, which this state is enabled. 84 forceRepollMutex sync.RWMutex 85 forceRepollUntil gregor.TimeOrOffset 86 } 87 88 var _ libkb.TeamLoader = (*TeamLoader)(nil) 89 90 func NewTeamLoader(g *libkb.GlobalContext, world LoaderContext, storage *storage.Storage, merkleStorage *storage.Merkle) *TeamLoader { 91 return &TeamLoader{ 92 Contextified: libkb.NewContextified(g), 93 world: world, 94 storage: storage, 95 merkleStorage: merkleStorage, 96 nameLookupBurstCache: libkb.NewBurstCache(g, 100, 10*time.Second, "SubteamNameToID"), 97 locktab: libkb.NewLockTable(), 98 } 99 } 100 101 // NewTeamLoaderAndInstall creates a new loader and installs it into G. 102 func NewTeamLoaderAndInstall(g *libkb.GlobalContext) *TeamLoader { 103 world := NewLoaderContextFromG(g) 104 st := storage.NewStorage(g) 105 mst := storage.NewMerkle() 106 l := NewTeamLoader(g, world, st, mst) 107 g.SetTeamLoader(l) 108 g.AddLogoutHook(l, "teamLoader") 109 g.AddDbNukeHook(l, "teamLoader") 110 return l 111 } 112 113 func (l *TeamLoader) Load(ctx context.Context, lArg keybase1.LoadTeamArg) (res *keybase1.TeamData, hidden *keybase1.HiddenTeamChain, err error) { 114 me, err := l.world.getMe(ctx) 115 if err != nil { 116 return nil, nil, err 117 } 118 if me.IsNil() && !lArg.Public { 119 return nil, nil, libkb.NewLoginRequiredError("login required to load a private team") 120 } 121 return l.load1(ctx, me, lArg) 122 } 123 124 func newFrozenChain(chain *keybase1.TeamSigChainState) keybase1.TeamSigChainState { 125 return keybase1.TeamSigChainState{ 126 Id: chain.Id, 127 Public: chain.Public, 128 LastSeqno: chain.LastSeqno, 129 LastLinkID: chain.LastLinkID, 130 } 131 } 132 133 func (l *TeamLoader) Freeze(ctx context.Context, teamID keybase1.TeamID) (err error) { 134 defer l.G().CTrace(ctx, fmt.Sprintf("TeamLoader#Freeze(%s)", teamID), &err)() 135 lock := l.locktab.AcquireOnName(ctx, l.G(), teamID.String()) 136 defer lock.Release(ctx) 137 mctx := libkb.NewMetaContext(ctx, l.G()) 138 td, frozen, tombstoned := l.storage.Get(mctx, teamID, teamID.IsPublic()) 139 if frozen || td == nil { 140 return nil 141 } 142 newTD := &keybase1.TeamData{ 143 Frozen: true, 144 Tombstoned: tombstoned, 145 Chain: newFrozenChain(&td.Chain), 146 } 147 l.storage.Put(mctx, newTD) 148 return nil 149 } 150 151 func (l *TeamLoader) Tombstone(ctx context.Context, teamID keybase1.TeamID) (err error) { 152 defer l.G().CTrace(ctx, fmt.Sprintf("TeamLoader#Tombstone(%s)", teamID), &err)() 153 lock := l.locktab.AcquireOnName(ctx, l.G(), teamID.String()) 154 defer lock.Release(ctx) 155 mctx := libkb.NewMetaContext(ctx, l.G()) 156 td, frozen, tombstoned := l.storage.Get(mctx, teamID, teamID.IsPublic()) 157 if tombstoned || td == nil { 158 return nil 159 } 160 newTD := &keybase1.TeamData{ 161 Frozen: frozen, 162 Tombstoned: true, 163 Chain: newFrozenChain(&td.Chain), 164 } 165 l.storage.Put(mctx, newTD) 166 return nil 167 } 168 169 func (l *TeamLoader) HintLatestSeqno(ctx context.Context, teamID keybase1.TeamID, seqno keybase1.Seqno) error { 170 // Single-flight lock by team ID. 171 lock := l.locktab.AcquireOnName(ctx, l.G(), teamID.String()) 172 defer lock.Release(ctx) 173 mctx := libkb.NewMetaContext(ctx, l.G()) 174 175 // Load from the cache 176 td, frozen, tombstoned := l.storage.Get(mctx, teamID, teamID.IsPublic()) 177 if frozen || tombstoned || td == nil { 178 // Nothing to store the hint on. 179 return nil 180 } 181 182 if seqno < td.LatestSeqnoHint { 183 // The hint is behind the times, ignore. 184 return nil 185 } 186 187 td.LatestSeqnoHint = seqno 188 l.storage.Put(mctx, td) 189 return nil 190 } 191 192 // Get whether a team is open. Returns an arbitrarily stale answer. 193 func (l *TeamLoader) IsOpenCached(ctx context.Context, teamID keybase1.TeamID) (bool, error) { 194 // Single-flight lock by team ID. 195 lock := l.locktab.AcquireOnName(ctx, l.G(), teamID.String()) 196 defer lock.Release(ctx) 197 mctx := libkb.NewMetaContext(ctx, l.G()) 198 199 // Load from the cache 200 td, frozen, tombstoned := l.storage.Get(mctx, teamID, teamID.IsPublic()) 201 if frozen || tombstoned || td == nil { 202 return false, fmt.Errorf("team not available data:%v frozen:%v tombstoned:%v", td != nil, frozen, tombstoned) 203 } 204 return td.Chain.Open, nil 205 } 206 207 type nameLookupBurstCacheKey struct { 208 teamName keybase1.TeamName 209 public bool 210 } 211 212 func (n nameLookupBurstCacheKey) String() string { 213 return fmt.Sprintf("%s:%v", n.teamName.String(), n.public) 214 } 215 216 // Resolve a team name to a team ID. 217 // Will always hit the server for subteams. The server can lie in this return value. 218 func (l *TeamLoader) ResolveNameToIDUntrusted(ctx context.Context, teamName keybase1.TeamName, public bool, allowCache bool) (id keybase1.TeamID, err error) { 219 220 defer l.G().CVTrace(ctx, libkb.VLog0, fmt.Sprintf("resolveNameToUIDUntrusted(%s,%v,%v)", teamName.String(), public, allowCache), &err)() 221 222 // For root team names, just hash. 223 if teamName.IsRootTeam() { 224 return teamName.ToTeamID(public), nil 225 } 226 227 if !allowCache { 228 return resolveNameToIDUntrustedAPICall(ctx, l.G(), teamName, public) 229 } 230 231 var idVoidPointer interface{} 232 key := nameLookupBurstCacheKey{teamName, public} 233 idVoidPointer, err = l.nameLookupBurstCache.Load(ctx, key, l.makeNameLookupBurstCacheLoader(ctx, l.G(), key)) 234 if err != nil { 235 return keybase1.TeamID(""), err 236 } 237 if idPointer, ok := idVoidPointer.(*keybase1.TeamID); ok && idPointer != nil { 238 id = *idPointer 239 } else { 240 return keybase1.TeamID(""), errors.New("bad cast out of nameLookupBurstCache") 241 } 242 return id, nil 243 } 244 245 func resolveNameToIDUntrustedAPICall(ctx context.Context, g *libkb.GlobalContext, teamName keybase1.TeamName, public bool) (id keybase1.TeamID, err error) { 246 mctx := libkb.NewMetaContext(ctx, g) 247 arg := libkb.NewAPIArg("team/get") 248 arg.SessionType = libkb.APISessionTypeREQUIRED 249 arg.Args = libkb.HTTPArgs{ 250 "name": libkb.S{Val: teamName.String()}, 251 "lookup_only": libkb.B{Val: true}, 252 "public": libkb.B{Val: public}, 253 } 254 255 var rt rawTeam 256 if err := mctx.G().API.GetDecode(mctx, arg, &rt); err != nil { 257 return id, err 258 } 259 id = rt.ID 260 if !id.Exists() { 261 return id, fmt.Errorf("could not resolve team name: %v", teamName.String()) 262 } 263 return id, nil 264 } 265 266 func (l *TeamLoader) makeNameLookupBurstCacheLoader(ctx context.Context, g *libkb.GlobalContext, key nameLookupBurstCacheKey) libkb.BurstCacheLoader { 267 return func() (obj interface{}, err error) { 268 id, err := resolveNameToIDUntrustedAPICall(ctx, g, key.teamName, key.public) 269 if err != nil { 270 return nil, err 271 } 272 return &id, nil 273 } 274 } 275 276 // Load1 unpacks the loadArg, calls load2, and does some final checks. 277 // The key difference between load1 and load2 is that load2 is recursive (for subteams). 278 func (l *TeamLoader) load1(ctx context.Context, me keybase1.UserVersion, lArg keybase1.LoadTeamArg) (data *keybase1.TeamData, hiddenChain *keybase1.HiddenTeamChain, err error) { 279 mctx := libkb.NewMetaContext(ctx, l.G()) 280 err = l.checkArg(ctx, lArg) 281 if err != nil { 282 return nil, nil, err 283 } 284 285 var teamName *keybase1.TeamName 286 if len(lArg.Name) > 0 { 287 teamNameParsed, err := keybase1.TeamNameFromString(lArg.Name) 288 if err != nil { 289 return nil, nil, fmt.Errorf("invalid team name: %v", err) 290 } 291 teamName = &teamNameParsed 292 } 293 294 teamID := lArg.ID 295 // Resolve the name to team ID. Will always hit the server for subteams. 296 // It is safe for the answer to be wrong because the name is checked on the way out, 297 // and the merkle tree check guarantees one sigchain per team id. 298 if !teamID.Exists() { 299 teamID, err = l.ResolveNameToIDUntrusted(ctx, *teamName, lArg.Public, lArg.AllowNameLookupBurstCache) 300 if err != nil { 301 mctx.Debug("TeamLoader looking up team by name failed: %v -> %v", *teamName, err) 302 if code, ok := libkb.GetAppStatusCode(err); ok && code == keybase1.StatusCode_SCTeamNotFound { 303 mctx.Debug("replacing error: %v", err) 304 return nil, nil, NewTeamDoesNotExistError(lArg.Public, teamName.String()) 305 } 306 return nil, nil, err 307 } 308 } 309 310 defer func() { 311 if hidden.ShouldClearSupportFlagOnError(err) { 312 mctx.Debug("Clearing support hidden chain flag for team %s because of error %v in team loader (load1)", teamID, err) 313 mctx.G().GetHiddenTeamChainManager().ClearSupportFlagIfFalse(mctx, teamID) 314 } 315 }() 316 317 mungedForceRepoll := lArg.ForceRepoll 318 mungedWantMembers, err := l.mungeWantMembers(ctx, lArg.Refreshers.WantMembers) 319 if err != nil { 320 mctx.Debug("TeamLoader munge failed: %v", err) 321 // drop the error and just force a repoll. 322 mungedForceRepoll = true 323 mungedWantMembers = nil 324 } 325 326 ret, err := l.load2(ctx, load2ArgT{ 327 teamID: teamID, 328 329 needAdmin: lArg.NeedAdmin, 330 needKeyGeneration: lArg.Refreshers.NeedKeyGeneration, 331 needApplicationsAtGenerations: lArg.Refreshers.NeedApplicationsAtGenerations, 332 needApplicationsAtGenerationsWithKBFS: lArg.Refreshers.NeedApplicationsAtGenerationsWithKBFS, 333 needKBFSKeyGeneration: lArg.Refreshers.NeedKBFSKeyGeneration, 334 wantMembers: mungedWantMembers, 335 wantMembersRole: lArg.Refreshers.WantMembersRole, 336 forceFullReload: lArg.ForceFullReload, 337 forceRepoll: mungedForceRepoll, 338 staleOK: lArg.StaleOK, 339 public: lArg.Public, 340 auditMode: lArg.AuditMode, 341 skipNeedHiddenRotateCheck: lArg.SkipNeedHiddenRotateCheck, 342 343 needSeqnos: nil, 344 readSubteamID: nil, 345 346 me: me, 347 }) 348 switch err := err.(type) { 349 case TeamDoesNotExistError: 350 if teamName == nil { 351 return nil, nil, err 352 } 353 // Replace the not found error so that it has a name instead of team ID. 354 // If subteams are involved the name might not correspond to the ID 355 // but it's better to have this understandable error message that's accurate 356 // most of the time than one with an ID that's always accurate. 357 mctx.Debug("replacing error: %v", err) 358 return nil, nil, NewTeamDoesNotExistError(lArg.Public, teamName.String()) 359 case nil: 360 default: 361 return nil, nil, err 362 } 363 if ret == nil { 364 return nil, nil, fmt.Errorf("team loader fault: got nil from load2") 365 } 366 367 // Public teams are allowed to be behind on secrets since you can load a 368 // public team you're not in. Restricted bot members don't have any secrets 369 // and are also exempt. 370 if !l.hasSyncedSecrets(mctx, ret.teamShim()) && 371 !(ret.team.Chain.Public || ret.team.Chain.UserRole(me).IsRestrictedBot()) { 372 // this should not happen 373 return nil, nil, fmt.Errorf("missing secrets for team") 374 } 375 376 // Check team name on the way out 377 // The snapshot may have already been written to cache, but that should be ok, 378 // because the cache is keyed by ID. 379 if teamName != nil { 380 // (TODO: this won't work for renamed level 3 teams or above. There's work on this in miles/teamloader-names) 381 if !teamName.Eq(ret.team.Name) { 382 return nil, nil, fmt.Errorf("team name mismatch: %v != %v", ret.team.Name, teamName.String()) 383 } 384 } 385 386 if ShouldRunBoxAudit(mctx) { 387 newMctx, shouldReload := VerifyBoxAudit(mctx, teamID) 388 if shouldReload { 389 return l.load1(newMctx.Ctx(), me, lArg) 390 } 391 } else { 392 mctx.Debug("Box auditor feature flagged off; not checking jail during team load...") 393 } 394 395 return &ret.team, ret.hidden, nil 396 } 397 398 func (l *TeamLoader) checkArg(ctx context.Context, lArg keybase1.LoadTeamArg) error { 399 hasID := lArg.ID.Exists() 400 hasName := len(lArg.Name) > 0 401 if hasID { 402 id, err := keybase1.TeamIDFromString(lArg.ID.String()) 403 if err != nil { 404 return fmt.Errorf("team load arg has invalid ID: %q", lArg.ID) 405 } 406 if id.IsPublic() != lArg.Public { 407 return libkb.NewTeamVisibilityError(lArg.Public, id.IsPublic()) 408 } 409 } 410 if !hasID && !hasName { 411 return fmt.Errorf("team load arg must have either ID or Name") 412 } 413 return nil 414 } 415 416 // Mostly the same as the public keybase.LoadTeamArg 417 // but only supports loading by ID, and has neededSeqnos. 418 type load2ArgT struct { 419 teamID keybase1.TeamID 420 421 reason string // optional tag for debugging why this load is happening 422 423 needAdmin bool 424 needKeyGeneration keybase1.PerTeamKeyGeneration 425 needApplicationsAtGenerations map[keybase1.PerTeamKeyGeneration][]keybase1.TeamApplication 426 needApplicationsAtGenerationsWithKBFS map[keybase1.PerTeamKeyGeneration][]keybase1.TeamApplication 427 needKBFSKeyGeneration keybase1.TeamKBFSKeyRefresher 428 // wantMembers here is different from wantMembers on LoadTeamArg: 429 // The EldestSeqno's should not be 0. 430 wantMembers []keybase1.UserVersion 431 wantMembersRole keybase1.TeamRole 432 forceFullReload bool 433 forceRepoll bool 434 staleOK bool 435 public bool 436 skipNeedHiddenRotateCheck bool 437 skipSeedCheck bool 438 foundRKMHole bool // if the previous load found an RKM hole, this is set 439 440 auditMode keybase1.AuditMode 441 442 needSeqnos []keybase1.Seqno 443 // Non-nil if we are loading an ancestor for the greater purpose of 444 // loading a subteam. This parameter helps the server figure out whether 445 // to give us a subteam-reader version of the team. 446 // If and only if this is set, load2 is allowed to return a secret-less TeamData. 447 // Load1 can return secret-less TeamData if the team is public or the 448 // current user is a restricted bot member. 449 readSubteamID *keybase1.TeamID 450 451 // If the user is logged out, this will be a nil UserVersion, meaning 452 /// me.IsNil() will be true. 453 me keybase1.UserVersion 454 } 455 456 type load2ResT struct { 457 team keybase1.TeamData 458 hidden *keybase1.HiddenTeamChain 459 didRepoll bool 460 } 461 462 func (l load2ResT) teamShim() *TeamShim { 463 return &TeamShim{Data: &l.team, Hidden: l.hidden} 464 } 465 466 // Load2 does the rest of the work loading a team. 467 // It is `playchain` described in the pseudocode in teamplayer.txt 468 func (l *TeamLoader) load2(ctx context.Context, arg load2ArgT) (ret *load2ResT, err error) { 469 ctx = libkb.WithLogTag(ctx, "LT") // Load team 470 if arg.reason != "" { 471 ctx = libkb.WithLogTag(ctx, "LT2") // Load team recursive 472 } 473 mctx := libkb.NewMetaContext(ctx, l.G()) 474 475 traceLabel := fmt.Sprintf("TeamLoader#load2(%v, public:%v)", arg.teamID, arg.public) 476 if len(arg.reason) > 0 { 477 traceLabel = traceLabel + " '" + arg.reason + "'" 478 } 479 480 defer l.G().CTrace(ctx, traceLabel, &err)() 481 ret, err = l.load2Inner(ctx, arg) 482 if hidden.ShouldClearSupportFlagOnError(err) { 483 mctx.Debug("Clearing support hidden chain flag for team %s because of error %v in team loader (load2)", arg.teamID, err) 484 mctx.G().GetHiddenTeamChainManager().ClearSupportFlagIfFalse(mctx, arg.teamID) 485 } 486 return ret, err 487 } 488 489 func (l *TeamLoader) load2Inner(ctx context.Context, arg load2ArgT) (*load2ResT, error) { 490 491 // Single-flight lock by team ID. 492 lock := l.locktab.AcquireOnName(ctx, l.G(), arg.teamID.String()) 493 defer lock.Release(ctx) 494 495 return l.load2InnerLocked(ctx, arg) 496 } 497 498 func (l *TeamLoader) load2InnerLocked(ctx context.Context, arg load2ArgT) (res *load2ResT, err error) { 499 const nRetries = 3 500 for i := 0; i < nRetries; i++ { 501 res, err = l.load2InnerLockedRetry(ctx, arg) 502 switch pkgErrors.Cause(err).(type) { 503 case nil: 504 return res, nil 505 case MissingReaderKeyMaskError: 506 l.G().Log.CDebugf(ctx, "Got MissingReaderKeyMaskError (%s); retrying with forceFullReload=true", err.Error()) 507 arg.foundRKMHole = true 508 origErr := err 509 res, err = l.load2InnerLockedRetry(ctx, arg) 510 if err == nil { 511 l.G().Log.CDebugf(ctx, "Found an holes in RKMS in which busting the cache saved the day (original error was: %s)", origErr.Error()) 512 } 513 return res, err 514 case ProofError: 515 if arg.forceRepoll { 516 return res, err 517 } 518 // Something went wrong, throw out the cache and try again. 519 l.G().Log.CDebugf(ctx, "Got proof error (%s); trying again with forceRepoll=true", err.Error()) 520 arg.forceRepoll = true 521 arg.forceFullReload = true 522 origErr := err 523 res, err = l.load2InnerLockedRetry(ctx, arg) 524 if err == nil { 525 l.G().Log.CDebugf(ctx, "Found an unexpected TeamLoader case in which busting the cache saved the day (original error was: %s)", origErr.Error()) 526 } 527 return res, err 528 case GreenLinkError: 529 // Try again 530 l.G().Log.CDebugf(ctx, "TeamLoader retrying after green link") 531 arg.forceRepoll = true 532 continue 533 } 534 return res, err 535 } 536 if err == nil { 537 // Should never happen 538 return res, fmt.Errorf("failed retryable team load") 539 } 540 // Return the last error 541 return res, err 542 } 543 544 func (l *TeamLoader) checkHiddenResponse(mctx libkb.MetaContext, hiddenPackage *hidden.LoaderPackage, hiddenResp *libkb.MerkleHiddenResponse) (hiddenIsFresh bool, err error) { 545 if hiddenResp.CommittedHiddenTail != nil { 546 mctx.Debug("hiddenResp: %+v UncommittedSeqno %+v CommittedSeqno %v", hiddenResp, hiddenResp.UncommittedSeqno, hiddenResp.CommittedHiddenTail.Seqno) 547 } else { 548 mctx.Debug("hiddenResp: %+v UncommittedSeqno %+v", hiddenResp, hiddenResp.UncommittedSeqno) 549 } 550 551 switch hiddenResp.RespType { 552 case libkb.MerkleHiddenResponseTypeNONE: 553 mctx.Debug("Skipping CheckHiddenMerklePathResponseAndAddRatchets as no hidden data was received. If the server had to show us the hidden chain and didn't, we will error out later (once we can establish our role in the team).") 554 return true, nil 555 case libkb.MerkleHiddenResponseTypeFLAGOFF: 556 mctx.Debug("Skipping CheckHiddenMerklePathResponseAndAddRatchets as the hidden flag is off.") 557 return true, nil 558 default: 559 return hiddenPackage.CheckHiddenMerklePathResponseAndAddRatchets(mctx, hiddenResp) 560 } 561 } 562 563 func (l *TeamLoader) load2InnerLockedRetry(ctx context.Context, arg load2ArgT) (*load2ResT, error) { 564 ctx, tbs := l.G().CTimeBuckets(ctx) 565 mctx := libkb.NewMetaContext(ctx, l.G()) 566 tracer := l.G().CTimeTracer(ctx, "TeamLoader.load2ILR", teamEnv.Profile) 567 defer tracer.Finish() 568 569 defer tbs.LogIfNonZero(ctx, "API.request") 570 571 var err error 572 var didRepoll bool 573 lkc := newLoadKeyCache() 574 575 // Fetch from cache 576 tracer.Stage("cache load") 577 tailCheckRet, frozen, tombstoned := l.storage.Get(mctx, arg.teamID, arg.public) 578 if tombstoned { 579 return nil, NewTeamTombstonedError() 580 } 581 582 // Fetch last polled time from merkle cache 583 merklePolledAt := l.merkleStorage.Get(mctx, arg.teamID, arg.public) 584 585 var ret *keybase1.TeamData 586 if !frozen && !arg.forceFullReload { 587 // Load from cache 588 ret = tailCheckRet 589 } 590 591 if ret != nil && !ret.Chain.Reader.Eq(arg.me) { 592 // Check that we are the same person as when this team was last loaded as a courtesy. 593 // This should never happen. We shouldn't be able to decrypt someone else's snapshot. 594 mctx.Warning("TeamLoader discarding snapshot for wrong user: (%v, %v) != (%v, %v)", 595 arg.me.Uid, arg.me.EldestSeqno, ret.Chain.Reader.Uid, ret.Chain.Reader.EldestSeqno) 596 ret = nil 597 } 598 599 var cachedName *keybase1.TeamName 600 if ret != nil && !ret.Name.IsNil() { 601 cachedName = &ret.Name 602 } 603 604 hiddenPackage, err := l.hiddenPackage(mctx, arg.teamID, ret, arg.me) 605 if err != nil { 606 return nil, err 607 } 608 609 teamShim := func() *TeamShim { 610 return &TeamShim{Data: ret, Hidden: hiddenPackage.ChainData()} 611 } 612 613 // Determine whether to repoll merkle. 614 discardCache, repoll := l.load2DecideRepoll(mctx, arg, teamShim(), merklePolledAt) 615 if discardCache { 616 ret = nil 617 repoll = true 618 } 619 620 tracer.Stage("deepcopy") 621 if ret != nil { 622 // If we're pulling from a previous snapshot (that, let's say, we got from a shared cache), 623 // then make sure to DeepCopy() data out of it before we start mutating it below. We used 624 // to do this every step through the new links, but that was very expensive in terms of CPU 625 // for big teams, since it was hidden quadratic behavior. 626 tmp := ret.DeepCopy() 627 ret = &tmp 628 } else { 629 mctx.Debug("TeamLoader not using snapshot") 630 } 631 632 tracer.Stage("merkle") 633 var lastSeqno keybase1.Seqno 634 var lastLinkID keybase1.LinkID 635 var hiddenIsFresh bool 636 var lastMerkleRoot *libkb.MerkleRoot 637 638 // hiddenResp will be nill iff we do not make the merkleLookupWithHidden 639 // call. If the server does not return any hidden data, we will encode that 640 // as a non nil response whose RespType is MerkleHiddenResponseTypeNONE. 641 var hiddenResp *libkb.MerkleHiddenResponse 642 643 if (ret == nil) || repoll { 644 mctx.Debug("TeamLoader looking up merkle leaf (force:%v)", arg.forceRepoll) 645 646 // Reference the merkle tree to fetch the sigchain tail leaf for the team. 647 lastSeqno, lastLinkID, hiddenResp, lastMerkleRoot, err = l.world.merkleLookupWithHidden(ctx, arg.teamID, arg.public) 648 if err != nil { 649 return nil, err 650 } 651 mctx.Debug("received lastSeqno %v, lastLinkID %v", lastSeqno, lastLinkID) 652 653 hiddenIsFresh, err = l.checkHiddenResponse(mctx, hiddenPackage, hiddenResp) 654 if err != nil { 655 return nil, err 656 } 657 658 didRepoll = true 659 } else { 660 lastSeqno = ret.Chain.LastSeqno 661 lastLinkID = ret.Chain.LastLinkID 662 hiddenIsFresh = true 663 } 664 665 // For child calls to load2, the subteam reader ID is carried up 666 // or if it doesn't exist, start at this team. 667 readSubteamID := arg.teamID 668 if arg.readSubteamID != nil { 669 readSubteamID = *arg.readSubteamID 670 } 671 672 proofSet := newProofSet(l.G()) 673 var parentChildOperations []*parentChildOperation 674 675 // Backfill stubbed links that need to be filled now. 676 tracer.Stage("backfill") 677 var filledInStubbedLinks bool 678 if ret != nil && len(arg.needSeqnos) > 0 { 679 ret, proofSet, parentChildOperations, err = l.fillInStubbedLinks( 680 mctx, arg.me, arg.teamID, ret, arg.needSeqnos, readSubteamID, proofSet, parentChildOperations, lkc) 681 if err != nil { 682 return nil, err 683 } 684 filledInStubbedLinks = true 685 } 686 687 tracer.Stage("pre-fetch") 688 var fetchLinksAndOrSecrets bool 689 if ret == nil { 690 mctx.Debug("TeamLoader fetching: no cache") 691 // We have no cache 692 fetchLinksAndOrSecrets = true 693 } else if ret.Chain.LastSeqno < lastSeqno { 694 mctx.Debug("TeamLoader fetching: chain update") 695 // The cache is definitely behind 696 fetchLinksAndOrSecrets = true 697 } else if !hiddenIsFresh { 698 mctx.Debug("TeamLoader fetching: hidden chain wasn't fresh") 699 fetchLinksAndOrSecrets = true 700 } else if !l.hasSyncedSecrets(mctx, teamShim()) { 701 // The cached secrets are behind the cached chain. 702 // We may need to hit the server for secrets, even though there are no new links. 703 if arg.needAdmin { 704 mctx.Debug("TeamLoader fetching: NeedAdmin") 705 // Admins should always have up-to-date secrets. But not necessarily RKMs. 706 fetchLinksAndOrSecrets = true 707 } 708 if err := l.satisfiesNeedKeyGeneration(mctx, arg.needKeyGeneration, teamShim()); err != nil { 709 mctx.Debug("TeamLoader fetching: NeedKeyGeneration: %v", err) 710 fetchLinksAndOrSecrets = true 711 } 712 if err := l.satisfiesNeedsKBFSKeyGeneration(mctx, arg.needKBFSKeyGeneration, teamShim()); err != nil { 713 mctx.Debug("TeamLoader fetching: KBFSNeedKeyGeneration: %v", err) 714 fetchLinksAndOrSecrets = true 715 } 716 if arg.readSubteamID == nil { 717 // This is not a recursive load. We should have the keys. 718 // This may be an extra round trip for public teams you're not in. 719 mctx.Debug("TeamLoader fetching: primary load") 720 fetchLinksAndOrSecrets = true 721 } 722 } 723 // hasSyncedSecrets does not account for RKMs. So check RKM refreshers separeately. 724 725 if err := l.satisfiesNeedApplicationsAtGenerations(mctx, arg.needApplicationsAtGenerations, teamShim()); err != nil { 726 mctx.Debug("TeamLoader fetching: NeedApplicationsAtGenerations: %v", err) 727 fetchLinksAndOrSecrets = true 728 } 729 if err := l.satisfiesNeedApplicationsAtGenerationsWithKBFS(mctx, 730 arg.needApplicationsAtGenerationsWithKBFS, teamShim()); err != nil { 731 mctx.Debug("TeamLoader fetching: NeedApplicationsAtGenerationsWithKBFS: %v", err) 732 fetchLinksAndOrSecrets = true 733 } 734 735 // Pull new links from the server 736 tracer.Stage("fetch") 737 var teamUpdate *rawTeam 738 if fetchLinksAndOrSecrets { 739 lows := l.lows(mctx, ret, hiddenPackage, arg) 740 mctx.Debug("TeamLoader getting links from server (%+v)", lows) 741 teamUpdate, err = l.world.getNewLinksFromServer(ctx, arg.teamID, lows, arg.readSubteamID) 742 if err != nil { 743 return nil, err 744 } 745 mctx.Debug("TeamLoader got %v links", len(teamUpdate.Chain)) 746 hiddenPackage.SetRatchetBlindingKeySet(teamUpdate.RatchetBlindingKeySet) 747 } 748 749 tracer.Stage("unpack") 750 links, err := teamUpdate.unpackLinks(mctx) 751 if err != nil { 752 return nil, err 753 } 754 var prev libkb.LinkID 755 if ret != nil { 756 prev, err = TeamSigChainState{inner: ret.Chain}.GetLatestLibkbLinkID() 757 if err != nil { 758 return nil, err 759 } 760 } 761 762 // A link which was signed by an admin. Sloppily the latest such link. 763 // Sloppy because this calculation misses out on e.g. a rotate_key signed by an admin. 764 // This value is used for skipping fullVerify on team.leave links, see `verifyLink`. 765 var fullVerifyCutoff keybase1.Seqno 766 for i := len(links) - 1; i >= 0; i-- { 767 if links[i].LinkType().RequiresAtLeastRole().IsAdminOrAbove() { 768 fullVerifyCutoff = links[i].Seqno() 769 break 770 } 771 } 772 if fullVerifyCutoff > 0 { 773 mctx.Debug("fullVerifyCutoff: %v", fullVerifyCutoff) 774 } 775 776 tracer.Stage("userPreload enable:%v parallel:%v wait:%v", 777 teamEnv.UserPreloadEnable, teamEnv.UserPreloadParallel, teamEnv.UserPreloadWait) 778 preloadCancel := l.userPreload(ctx, links, fullVerifyCutoff) 779 defer preloadCancel() 780 781 tracer.Stage("linkloop (%v)", len(links)) 782 parentsCache := make(parentChainCache) 783 784 // Don't log in the middle links if there are a great many links. 785 suppressLoggingStart := 5 786 suppressLoggingUpto := len(links) - 5 787 for i, link := range links { 788 var err error 789 ret, prev, err = l.doOneLink(mctx, arg, ret, hiddenPackage, link, i, suppressLoggingStart, suppressLoggingUpto, lastSeqno, &parentChildOperations, prev, fullVerifyCutoff, readSubteamID, proofSet, lkc, &parentsCache) 790 if err != nil { 791 return nil, err 792 } 793 } 794 795 if ret == nil { 796 return nil, fmt.Errorf("team loader fault: got nil from load2") 797 } 798 799 encKID, gen, role, err := l.hiddenPackageGetter(mctx, arg.teamID, ret, arg.me)() 800 if err != nil { 801 return nil, err 802 } 803 804 // If we did get an update from the server (hiddenResp != nil) are not a 805 // restricted bot AND this is not a recursive load (arg.readSubteamID == nil), 806 // then the server should have given us hidden chain data. 807 if hiddenResp != nil && hiddenResp.RespType == libkb.MerkleHiddenResponseTypeNONE && !role.IsRestrictedBot() && arg.readSubteamID == nil { 808 return nil, libkb.NewHiddenChainDataMissingError("Not a restricted bot or recursive load, but the server did not return merkle hidden chain data") 809 } 810 811 // Update the hidden package with team metadata once we process all of the 812 // links. This is necessary since we need the role to be up to date to know 813 // if we should skip seed checks on the hidden chain if we are loading as a 814 // RESTRICTEDBOT. 815 hiddenPackage.UpdateTeamMetadata(encKID, gen, role) 816 817 // Be sure to update the hidden chain after the main chain, since the latter can "ratchet" the former 818 err = hiddenPackage.Update(mctx, teamUpdate.GetHiddenChain(), hiddenResp.GetUncommittedSeqno()) 819 820 if err != nil { 821 return nil, err 822 } 823 err = hiddenPackage.CheckPTKsForDuplicates(mctx, func(g keybase1.PerTeamKeyGeneration) bool { 824 _, ok := ret.Chain.PerTeamKeys[g] 825 return ok 826 }) 827 if err != nil { 828 return nil, err 829 } 830 831 // The hidden team has pointers from the hidden chain up to the visible chain; check that they 832 // match the loaded team. We should have a full load of the team, so all parent pointers 833 // better hit their mark. 834 err = hiddenPackage.CheckParentPointersOnFullLoad(mctx, ret) 835 if err != nil { 836 return nil, err 837 } 838 839 preloadCancel() 840 if len(links) > 0 { 841 tbs.Log(ctx, "TeamLoader.verifyLink") 842 tbs.Log(ctx, "TeamLoader.applyNewLink") 843 tbs.Log(ctx, "SigChain.LoadFromServer.ReadAll") 844 tbs.Log(ctx, "loadKeyCache.loadKeyV2") 845 if teamEnv.Profile { 846 tbs.Log(ctx, "LoaderContextG.loadKeyV2") 847 tbs.Log(ctx, "CachedUPAKLoader.LoadKeyV2") // note LoadKeyV2 calls Load2 848 tbs.Log(ctx, "CachedUPAKLoader.LoadV2") 849 tbs.Log(ctx, "CachedUPAKLoader.DeepCopy") 850 mctx.Debug("TeamLoader lkc cache hits: %v", lkc.cacheHits) 851 } 852 } 853 854 if !ret.Chain.LastLinkID.Eq(lastLinkID) { 855 return nil, fmt.Errorf("wrong sigchain link ID: %v != %v", 856 ret.Chain.LastLinkID, lastLinkID) 857 } 858 859 if tailCheckRet != nil { 860 // If we previously discarded cache due to forceFullReload, or left the 861 // team, froze it, and are rejoining, make sure the previous tail is 862 // still in the chain. 863 // The chain loader ensures it is part of a well-formed chain with correct prevs. 864 linkID := ret.Chain.LinkIDs[tailCheckRet.Chain.LastSeqno] 865 if !linkID.Eq(tailCheckRet.Chain.LastLinkID) { 866 return nil, fmt.Errorf("got wrong sigchain link ID for seqno %d: expected %v from previous cache entry (frozen=%t); got %v in new chain", tailCheckRet.Chain.LastSeqno, 867 tailCheckRet.Chain.LastLinkID, ret.Frozen, linkID) 868 } 869 } 870 871 tracer.Stage("pco") 872 err = l.checkParentChildOperations(ctx, 873 arg.me, arg.teamID, ret.Chain.ParentID, readSubteamID, parentChildOperations, proofSet) 874 if err != nil { 875 return nil, err 876 } 877 878 tracer.Stage("checkproofs") 879 err = l.checkProofs(ctx, ret, proofSet) 880 if err != nil { 881 return nil, err 882 } 883 884 tracer.Stage("secrets") 885 if teamUpdate != nil { 886 if teamUpdate.SubteamReader { 887 // Only allow subteam-reader results if we are in a recursive load. 888 if arg.readSubteamID == nil { 889 return nil, fmt.Errorf("unexpected subteam reader result") 890 } 891 } else { 892 stateWrapper := newTeamSigChainState(teamShim()) 893 role, err := stateWrapper.GetUserRole(arg.me) 894 if err != nil { 895 role = keybase1.TeamRole_NONE 896 } 897 // Add the secrets. 898 // If it's a public team, there might not be secrets. (If we're not in the team) 899 // Restricted bots don't have any team secrets, so we also short circuit. 900 if !role.IsRestrictedBot() && (!ret.Chain.Public || (teamUpdate.Box != nil)) { 901 err = l.addSecrets(mctx, teamShim(), arg.me, teamUpdate.Box, teamUpdate.Prevs, teamUpdate.ReaderKeyMasks) 902 if err != nil { 903 return nil, pkgErrors.Wrap(err, "loading team secrets") 904 } 905 906 err = l.computeSeedChecks(ctx, ret) 907 if err != nil { 908 return nil, err 909 } 910 911 if teamUpdate.LegacyTLFUpgrade != nil { 912 err = l.addKBFSCryptKeys(mctx, teamShim(), teamUpdate.LegacyTLFUpgrade) 913 if err != nil { 914 return nil, fmt.Errorf("loading KBFS crypt keys: %v", err) 915 } 916 } 917 } 918 if role.IsRestrictedBot() { 919 // Clear out any secrets we may have had in memory if we were a 920 // previous role that had PTK access. 921 state := teamShim().MainChain() 922 state.PerTeamKeySeedsUnverified = make(map[keybase1.PerTeamKeyGeneration]keybase1.PerTeamKeySeedItem) 923 state.ReaderKeyMasks = make(map[keybase1.TeamApplication]map[keybase1.PerTeamKeyGeneration]keybase1.MaskB64) 924 state.TlfCryptKeys = make(map[keybase1.TeamApplication][]keybase1.CryptKey) 925 } 926 } 927 } 928 929 // Note that we might have done so just above after adding secrets, but before adding 930 // KBFS crypt keys. But it's cheap to run this method twice in a row. 931 tracer.Stage("computeSeedChecks") 932 err = l.computeSeedChecks(ctx, ret) 933 if err != nil { 934 return nil, err 935 } 936 937 if !arg.skipSeedCheck && arg.readSubteamID == nil { 938 err = hiddenPackage.CheckUpdatesAgainstSeedsWithMap(mctx, ret.PerTeamKeySeedsUnverified) 939 if err != nil { 940 return nil, err 941 } 942 } 943 944 // Make sure public works out 945 if ret.Chain.Public != arg.public { 946 return nil, fmt.Errorf("team public mismatch: chain:%v != arg:%v", ret.Chain.Public, arg.public) 947 } 948 if ret.Chain.Id.IsPublic() != ret.Chain.Public { 949 return nil, fmt.Errorf("team public mismatch: id:%v != chain:%v", ret.Chain.Id.IsPublic(), ret.Chain.Public) 950 } 951 952 // Sanity check the id 953 if !ret.Chain.Id.Eq(arg.teamID) { 954 return nil, fmt.Errorf("team id mismatch: %v != %v", ret.Chain.Id.String(), arg.teamID.String()) 955 } 956 957 // Recalculate the team name. 958 // This must always run to pick up changes on chain and off-chain with ancestor renames. 959 // Also because without this a subteam could claim any parent in its name. 960 tracer.Stage("namecalc") 961 newName, err := l.calculateName(ctx, ret, arg.me, readSubteamID, arg.staleOK) 962 if err != nil { 963 return nil, fmt.Errorf("error recalculating name for %v: %v", ret.Name, err) 964 } 965 if !ret.Name.Eq(newName) { 966 // This deep copy is an absurd price to pay, but these mid-team renames should be quite rare. 967 copy := ret.DeepCopy() 968 ret = © 969 ret.Name = newName 970 } 971 972 var needHiddenRotate bool 973 if !arg.skipNeedHiddenRotateCheck { 974 needHiddenRotate, err = l.checkNeedRotate(mctx, ret, arg.me, hiddenPackage) 975 if err != nil { 976 return nil, err 977 } 978 } 979 980 err = hiddenPackage.Commit(mctx) 981 if err != nil { 982 return nil, err 983 } 984 985 l.logIfUnsyncedSecrets(ctx, ret) 986 987 // Mutating this field is safe because only TeamLoader 988 // while holding the single-flight lock reads or writes this field. 989 ret.CachedAt = keybase1.ToTime(l.G().Clock().Now()) 990 991 // Clear the untrusted seqno hint. 992 // Mutating this field is safe because only TeamLoader 993 // while holding the single-flight lock reads or writes this field. 994 ret.LatestSeqnoHint = 0 995 996 if didRepoll { 997 tracer.Stage("audit") 998 auditMode := arg.auditMode 999 // in case of restricted bots or recursive loads, do not audit the 1000 // hidden chain (as we might not have permission to see it). 1001 if (role.IsRestrictedBot() || arg.readSubteamID != nil) && auditMode == keybase1.AuditMode_STANDARD { 1002 auditMode = keybase1.AuditMode_STANDARD_NO_HIDDEN 1003 } 1004 1005 err = l.audit(ctx, readSubteamID, &ret.Chain, hiddenPackage.ChainData(), lastMerkleRoot, auditMode) 1006 if err != nil { 1007 return nil, err 1008 } 1009 } else { 1010 mctx.Debug("Skipping audit in the TeamLoader as we did not repoll merkle") 1011 } 1012 1013 // Cache the validated result if it was actually updated via the team/get endpoint. In many cases, we're not 1014 // actually mutating the teams. Also, if we wound up filling in stubbed links, let's also restore the cache. 1015 if teamUpdate != nil || filledInStubbedLinks { 1016 tracer.Stage("put") 1017 l.storage.Put(mctx, ret) 1018 } 1019 1020 // If we wound up repolling the merkle tree for this team, say that we did. 1021 if didRepoll { 1022 l.merkleStorage.Put(mctx, arg.teamID, arg.public, keybase1.ToTime(mctx.G().Clock().Now())) 1023 } 1024 1025 tracer.Stage("notify") 1026 if cachedName != nil && !cachedName.Eq(newName) { 1027 chain := TeamSigChainState{inner: ret.Chain, hidden: hiddenPackage.ChainData()} 1028 // Send a notification if we used to have the name cached and it has changed at all. 1029 changeSet := keybase1.TeamChangeSet{Renamed: true} 1030 go l.G().NotifyRouter.HandleTeamChangedByID(context.Background(), chain.GetID(), chain.GetLatestSeqno(), 1031 chain.IsImplicit(), changeSet, chain.GetLatestHiddenSeqno(), keybase1.Seqno(0), keybase1.TeamChangedSource_LOCAL_RENAME) 1032 go l.G().NotifyRouter.HandleTeamChangedByName(context.Background(), cachedName.String(), chain.GetLatestSeqno(), 1033 chain.IsImplicit(), changeSet, chain.GetLatestHiddenSeqno(), keybase1.Seqno(0), keybase1.TeamChangedSource_LOCAL_RENAME) 1034 go l.G().NotifyRouter.HandleTeamChangedByName(context.Background(), newName.String(), chain.GetLatestSeqno(), 1035 chain.IsImplicit(), changeSet, chain.GetLatestHiddenSeqno(), keybase1.Seqno(0), keybase1.TeamChangedSource_LOCAL_RENAME) 1036 } 1037 1038 // Check request constraints 1039 tracer.Stage("postcheck") 1040 err = l.load2CheckReturn(mctx, arg, teamShim()) 1041 if err != nil { 1042 return nil, err 1043 } 1044 1045 load2res := load2ResT{ 1046 team: *ret, 1047 didRepoll: didRepoll, 1048 } 1049 1050 if hd := hiddenPackage.ChainData(); hd != nil { 1051 hd.NeedRotate = needHiddenRotate 1052 load2res.hidden = hd 1053 } 1054 1055 if needHiddenRotate { 1056 l.G().GetTeamBoxAuditor().MaybeScheduleDelayedBoxAuditTeam(mctx, arg.teamID) 1057 } 1058 1059 return &load2res, nil 1060 } 1061 1062 func (l *TeamLoader) hiddenPackageGetter(mctx libkb.MetaContext, id keybase1.TeamID, team *keybase1.TeamData, me keybase1.UserVersion) func() (encKID keybase1.KID, gen keybase1.PerTeamKeyGeneration, role keybase1.TeamRole, err error) { 1063 return func() (encKID keybase1.KID, gen keybase1.PerTeamKeyGeneration, 1064 role keybase1.TeamRole, err error) { 1065 if team == nil { 1066 return encKID, gen, keybase1.TeamRole_NONE, nil 1067 } 1068 state := TeamSigChainState{inner: team.Chain} 1069 1070 ptk, err := state.GetLatestPerTeamKey(mctx) 1071 if err != nil { 1072 return encKID, gen, keybase1.TeamRole_NONE, err 1073 } 1074 role, err = state.GetUserRole(me) 1075 if err != nil { 1076 return encKID, gen, keybase1.TeamRole_NONE, err 1077 } 1078 return ptk.EncKID, ptk.Gen, role, nil 1079 } 1080 } 1081 1082 func (l *TeamLoader) hiddenPackage(mctx libkb.MetaContext, id keybase1.TeamID, team *keybase1.TeamData, me keybase1.UserVersion) (ret *hidden.LoaderPackage, err error) { 1083 getter := l.hiddenPackageGetter(mctx, id, team, me) 1084 return hidden.NewLoaderPackage(mctx, id, getter) 1085 } 1086 1087 func (l *TeamLoader) isAllowedKeyerOf(mctx libkb.MetaContext, chain *keybase1.TeamData, me keybase1.UserVersion, them keybase1.UserVersion) (ret bool, err error) { 1088 state := TeamSigChainState{inner: chain.Chain} 1089 mctx = mctx.WithLogTag("IAKO") 1090 defer mctx.Trace(fmt.Sprintf("TeamLoader#isAllowedKeyerOf(%s, %s)", state.GetID(), them), &err)() 1091 1092 role, err := state.GetUserRole(them) 1093 if err != nil { 1094 return false, err 1095 } 1096 switch role { 1097 case keybase1.TeamRole_WRITER, keybase1.TeamRole_ADMIN, keybase1.TeamRole_OWNER: 1098 mctx.Debug("user fits explicit role (%s)", role) 1099 return true, nil 1100 } 1101 1102 if state.GetParentID() == nil { 1103 mctx.Debug("user is not an allowed keyer of the team") 1104 return false, nil 1105 } 1106 1107 // now check implict adminship 1108 yes, err := l.isImplicitAdminOf(mctx.Ctx(), state.GetID(), state.GetParentID(), me, them) 1109 if err != nil { 1110 return false, err 1111 } 1112 1113 if yes { 1114 mctx.Debug("user is an implicit admin of the team") 1115 return true, err 1116 } 1117 1118 mctx.Debug("user is not an allowed keyer of the team") 1119 1120 return false, nil 1121 1122 } 1123 1124 func (l *TeamLoader) checkNeedRotate(mctx libkb.MetaContext, chain *keybase1.TeamData, me keybase1.UserVersion, hiddenPackage *hidden.LoaderPackage) (ret bool, err error) { 1125 signer := hiddenPackage.LastReaderKeyRotator(mctx) 1126 if signer == nil { 1127 mctx.Debug("not checking need rotate, since last signer of hidden chain was nil") 1128 return false, nil 1129 } 1130 return l.checkNeedRotateWithSigner(mctx, chain, me, *signer) 1131 } 1132 1133 func (l *TeamLoader) checkNeedRotateWithSigner(mctx libkb.MetaContext, chain *keybase1.TeamData, me keybase1.UserVersion, signer keybase1.Signer) (ret bool, err error) { 1134 1135 defer mctx.Trace(fmt.Sprintf("TeamLoader::checkNeedRotateWithSigner(%+v)", signer), &err)() 1136 1137 uv := signer.UserVersion() 1138 1139 var isKeyer, amIKeyer bool 1140 1141 amIKeyer, err = l.isAllowedKeyerOf(mctx, chain, me, me) 1142 if err != nil { 1143 return false, err 1144 } 1145 if !amIKeyer { 1146 mctx.Debug("I am not a keyer for this team, so I can't rotate it even if required") 1147 return false, nil 1148 } 1149 1150 isKeyer, err = l.isAllowedKeyerOf(mctx, chain, me, uv) 1151 if err != nil { 1152 return false, err 1153 } 1154 1155 if !isKeyer { 1156 mctx.Debug("need rotate since %+v isn't an allowed keyer of the team", uv) 1157 return true, nil 1158 } 1159 1160 var found bool 1161 var revokedAt *keybase1.KeybaseTime 1162 1163 found, revokedAt, _, err = mctx.G().GetUPAKLoader().CheckKIDForUID(mctx.Ctx(), uv.Uid, signer.K) 1164 if err != nil { 1165 return false, err 1166 } 1167 1168 if !found || revokedAt != nil { 1169 var s string 1170 if revokedAt != nil { 1171 tm := revokedAt.Unix.Time() 1172 s = fmt.Sprintf(" (revoked at %s [%s ago])", tm, mctx.G().Clock().Now().Sub(tm)) 1173 } 1174 mctx.Debug("KID %s wasn't found for %+v%s", signer, s) 1175 return true, nil 1176 } 1177 1178 return false, nil 1179 } 1180 1181 func (l *TeamLoader) doOneLink(mctx libkb.MetaContext, arg load2ArgT, ret *keybase1.TeamData, hiddenPackage *hidden.LoaderPackage, link *ChainLinkUnpacked, i int, suppressLoggingStart int, suppressLoggingUpto int, lastSeqno keybase1.Seqno, parentChildOperations *[](*parentChildOperation), prev libkb.LinkID, fullVerifyCutoff keybase1.Seqno, readSubteamID keybase1.TeamID, proofSet *proofSetT, lkc *loadKeyCache, parentsCache *parentChainCache) (*keybase1.TeamData, libkb.LinkID, error) { 1182 1183 var nilPrev libkb.LinkID 1184 1185 ctx := mctx.Ctx() 1186 if suppressLoggingStart <= i && i < suppressLoggingUpto { 1187 if i == suppressLoggingStart { 1188 mctx.Debug("TeamLoader suppressing logs until %v", suppressLoggingUpto) 1189 } 1190 ctx = WithSuppressLogging(ctx, true) 1191 mctx = mctx.WithContext(ctx) 1192 } 1193 1194 if !ShouldSuppressLogging(ctx) { 1195 mctx.Debug("TeamLoader processing link seqno:%v", link.Seqno()) 1196 } 1197 1198 if link.Seqno() > lastSeqno { 1199 // This link came from a point in the chain after when we checked the merkle leaf. 1200 // Processing it would require re-checking merkle. 1201 // It would be tricky to ignore it because off-chain data is asserted to be in sync with the chain. 1202 // So, return an error that the caller will retry. 1203 mctx.Debug("TeamLoader found green link seqno:%v", link.Seqno()) 1204 return nil, nilPrev, NewGreenLinkError(link.Seqno()) 1205 } 1206 1207 if err := l.checkStubbed(ctx, arg, link); err != nil { 1208 return nil, nilPrev, err 1209 } 1210 1211 if !link.Prev().Eq(prev) { 1212 return nil, nilPrev, NewPrevError("team replay failed: prev chain broken at link %d (%v != %v)", 1213 i, link.Prev(), prev) 1214 } 1215 1216 if err := consumeRatchets(mctx, hiddenPackage, link); err != nil { 1217 return nil, nilPrev, err 1218 } 1219 1220 if err := checkPTKGenerationNotOnHiddenChain(mctx, hiddenPackage, link); err != nil { 1221 return nil, nilPrev, err 1222 } 1223 1224 var signer *SignerX 1225 var err error 1226 signer, err = l.verifyLink(ctx, arg.teamID, ret, arg.me, link, fullVerifyCutoff, 1227 readSubteamID, proofSet, lkc, *parentsCache) 1228 if err != nil { 1229 return nil, nilPrev, err 1230 } 1231 1232 if l.isParentChildOperation(ctx, link) { 1233 pco, err := l.toParentChildOperation(ctx, link) 1234 if err != nil { 1235 return nil, nilPrev, err 1236 } 1237 *parentChildOperations = append(*parentChildOperations, pco) 1238 } 1239 1240 ret, err = l.applyNewLink(ctx, ret, hiddenPackage.ChainData(), link, signer, arg.me) 1241 if err != nil { 1242 return nil, nilPrev, err 1243 } 1244 1245 return ret, link.LinkID(), nil 1246 } 1247 1248 // userPreload warms the upak cache with users who will probably need to be loaded to verify the chain. 1249 // Uses teamEnv and may be disabled. 1250 func (l *TeamLoader) userPreload(ctx context.Context, links []*ChainLinkUnpacked, fullVerifyCutoff keybase1.Seqno) (cancel func()) { 1251 ctx, cancel = context.WithCancel(ctx) 1252 if teamEnv.UserPreloadEnable { 1253 uidSet := make(map[keybase1.UID]struct{}) 1254 for _, link := range links { 1255 // fullVerify definition copied from verifyLink 1256 fullVerify := (link.LinkType() != libkb.SigchainV2TypeTeamLeave) || 1257 (link.Seqno() >= fullVerifyCutoff) || 1258 (link.source.EldestSeqno == 0) 1259 if !link.isStubbed() && fullVerify { 1260 uidSet[link.inner.Body.Key.UID] = struct{}{} 1261 } 1262 } 1263 l.G().Log.CDebugf(ctx, "TeamLoader userPreload uids: %v", len(uidSet)) 1264 if teamEnv.UserPreloadParallel { 1265 // Note this is full-parallel. Probably want pipelining if this is to be turned on by default. 1266 var wg sync.WaitGroup 1267 for uid := range uidSet { 1268 wg.Add(1) 1269 go func(uid keybase1.UID) { 1270 _, _, err := l.G().GetUPAKLoader().LoadV2( 1271 libkb.NewLoadUserArg(l.G()).WithUID(uid).WithPublicKeyOptional().WithNetContext(ctx)) 1272 if err != nil { 1273 l.G().Log.CDebugf(ctx, "error preloading uid %v", uid) 1274 } 1275 wg.Done() 1276 }(uid) 1277 } 1278 if teamEnv.UserPreloadWait { 1279 wg.Wait() 1280 } 1281 } else { 1282 for uid := range uidSet { 1283 _, _, err := l.G().GetUPAKLoader().LoadV2( 1284 libkb.NewLoadUserArg(l.G()).WithUID(uid).WithPublicKeyOptional().WithNetContext(ctx)) 1285 if err != nil { 1286 l.G().Log.CDebugf(ctx, "error preloading uid %v", uid) 1287 } 1288 } 1289 } 1290 } 1291 return cancel 1292 } 1293 1294 // Decide whether to repoll merkle based on load arg. 1295 // Returns (discardCache, repoll) 1296 // discardCache - the caller should throw out their cached copy and repoll. 1297 // repoll - hit up merkle for the latest tail 1298 // Considers: 1299 // - NeedAdmin 1300 // - NeedKeyGeneration 1301 // - NeedApplicationsAtGenerations 1302 // - WantMembers 1303 // - ForceRepoll 1304 // - Cache freshness / StaleOK 1305 // - NeedSeqnos 1306 // - JustUpdated 1307 // - If this user is in global "force repoll" mode, where it would be too spammy to 1308 // push out individual team changed notifications, so all team loads need a repoll. 1309 func (l *TeamLoader) load2DecideRepoll(mctx libkb.MetaContext, arg load2ArgT, fromCache Teamer, cachedPolledAt *keybase1.Time) (discardCache bool, repoll bool) { 1310 var reason string 1311 defer func() { 1312 if discardCache || repoll || reason != "" { 1313 mctx.Debug("load2DecideRepoll -> (discardCache:%v, repoll:%v) %v", discardCache, repoll, reason) 1314 } 1315 }() 1316 // NeedAdmin is a special constraint where we start from scratch. 1317 // Because of admin-only invite links. 1318 if arg.needAdmin { 1319 if !l.satisfiesNeedAdmin(mctx, arg.me, fromCache) { 1320 // Start from scratch if we are newly admin 1321 reason = "!satisfiesNeedAdmin" 1322 return true, true 1323 } 1324 } 1325 1326 if arg.forceRepoll { 1327 reason = "forceRepoll" 1328 return false, true 1329 } 1330 1331 // Repoll if the server has previously hinted that the team has new links. 1332 if fromCache != nil && fromCache.MainChain() != nil && fromCache.MainChain().Chain.LastSeqno < fromCache.MainChain().LatestSeqnoHint { 1333 reason = "behind seqno hint" 1334 return false, true 1335 } 1336 1337 if fromCache != nil && fromCache.HiddenChain() != nil && fromCache.HiddenChain().IsStale() { 1338 reason = "behind hidden seqno hint" 1339 return false, true 1340 } 1341 1342 // Repoll to get a new key generation 1343 if arg.needKeyGeneration > 0 { 1344 if err := l.satisfiesNeedKeyGeneration(mctx, arg.needKeyGeneration, fromCache); err != nil { 1345 reason = fmt.Sprintf("satisfiesNeedKeyGeneration -> %v", err) 1346 return false, true 1347 } 1348 } 1349 // Repoll to get new applications at generations 1350 if len(arg.needApplicationsAtGenerations) > 0 { 1351 if err := l.satisfiesNeedApplicationsAtGenerations(mctx, arg.needApplicationsAtGenerations, fromCache); err != nil { 1352 reason = fmt.Sprintf("satisfiesNeedApplicationsAtGenerations -> %v", err) 1353 return false, true 1354 } 1355 } 1356 if arg.needKBFSKeyGeneration.Generation > 0 { 1357 if err := l.satisfiesNeedsKBFSKeyGeneration(mctx, arg.needKBFSKeyGeneration, fromCache); err != nil { 1358 reason = fmt.Sprintf("satisfiesNeedsKBFSKeyGeneration -> %v", err) 1359 return false, true 1360 } 1361 } 1362 1363 if len(arg.needApplicationsAtGenerationsWithKBFS) > 0 { 1364 if err := l.satisfiesNeedApplicationsAtGenerationsWithKBFS(mctx, 1365 arg.needApplicationsAtGenerationsWithKBFS, fromCache); err != nil { 1366 reason = fmt.Sprintf("satisfiesNeedApplicationsAtGenerationsWithKBFS -> %v", err) 1367 return false, true 1368 } 1369 } 1370 1371 // Repoll because it might help get the wanted members 1372 if len(arg.wantMembers) > 0 { 1373 if err := l.satisfiesWantMembers(mctx, arg.wantMembers, arg.wantMembersRole, fromCache); err != nil { 1374 reason = fmt.Sprintf("satisfiesWantMembers -> %v", err) 1375 return false, true 1376 } 1377 } 1378 1379 // Repoll if we need a seqno not in the cache. 1380 // Does not force a repoll if we just need to fill in previous links 1381 if len(arg.needSeqnos) > 0 { 1382 if fromCache == nil || fromCache.MainChain() == nil { 1383 reason = "need seqnos and no cache" 1384 return false, true 1385 } 1386 if fromCache.MainChain().Chain.LastSeqno < l.seqnosMax(arg.needSeqnos) { 1387 reason = "need seqnos" 1388 return false, true 1389 } 1390 } 1391 1392 if fromCache == nil || fromCache.MainChain() == nil { 1393 reason = "no cache" 1394 // We need a merkle leaf when starting from scratch. 1395 return false, true 1396 } 1397 1398 cachedAt := fromCache.MainChain().CachedAt 1399 if cachedPolledAt != nil && *cachedPolledAt > cachedAt { 1400 cachedAt = *cachedPolledAt 1401 } 1402 1403 cacheIsOld := !l.isFresh(mctx, cachedAt) 1404 if cacheIsOld && !arg.staleOK { 1405 // We need a merkle leaf 1406 reason = "cacheIsOld" 1407 return false, true 1408 } 1409 1410 // InForceRepoll needs to a acquire a lock, so avoid it by checking it last. 1411 if l.InForceRepollMode(mctx) { 1412 reason = "InForceRepollMode" 1413 return false, true 1414 } 1415 1416 return false, false 1417 } 1418 1419 // Check whether the load produced a snapshot that can be returned to the caller. 1420 // This should not check anything that is critical to the validity of the snapshot 1421 // because the snapshot is put into the cache before this check. 1422 // Considers: 1423 // - NeedAdmin 1424 // - NeedKeyGeneration 1425 // - NeedSeqnos 1426 func (l *TeamLoader) load2CheckReturn(mctx libkb.MetaContext, arg load2ArgT, shim Teamer) error { 1427 if arg.needAdmin { 1428 if !l.satisfiesNeedAdmin(mctx, arg.me, shim) { 1429 mctx.Debug("user %v is not an admin of team %v at seqno:%v", arg.me, arg.teamID, shim.MainChain().Chain.LastSeqno) 1430 return fmt.Errorf("user %v is not an admin of the team", arg.me) 1431 } 1432 } 1433 1434 // Repoll to get a new key generation 1435 if arg.needKeyGeneration > 0 { 1436 if err := l.satisfiesNeedKeyGeneration(mctx, arg.needKeyGeneration, shim); err != nil { 1437 return err 1438 } 1439 } 1440 if len(arg.needApplicationsAtGenerations) > 0 { 1441 if err := l.satisfiesNeedApplicationsAtGenerations(mctx, arg.needApplicationsAtGenerations, shim); err != nil { 1442 return err 1443 } 1444 } 1445 if arg.needKBFSKeyGeneration.Generation > 0 { 1446 if err := l.satisfiesNeedsKBFSKeyGeneration(mctx, arg.needKBFSKeyGeneration, shim); err != nil { 1447 return err 1448 } 1449 } 1450 if len(arg.needApplicationsAtGenerationsWithKBFS) > 0 { 1451 if err := l.satisfiesNeedApplicationsAtGenerationsWithKBFS(mctx, arg.needApplicationsAtGenerationsWithKBFS, shim); err != nil { 1452 return err 1453 } 1454 } 1455 1456 if len(arg.needSeqnos) > 0 { 1457 if err := l.checkNeededSeqnos(mctx.Ctx(), shim.MainChain(), arg.needSeqnos); err != nil { 1458 return err 1459 } 1460 } 1461 1462 return nil 1463 } 1464 1465 // Whether the user is an admin at the snapshot, and there are no stubbed links, and keys are up to date. 1466 func (l *TeamLoader) satisfiesNeedAdmin(mctx libkb.MetaContext, me keybase1.UserVersion, team Teamer) bool { 1467 if team == nil || team.MainChain() == nil { 1468 return false 1469 } 1470 state := newTeamSigChainState(team) 1471 if state.HasAnyStubbedLinks() { 1472 return false 1473 } 1474 if !l.hasSyncedSecrets(mctx, team) { 1475 return false 1476 } 1477 role, err := state.GetUserRole(me) 1478 if err != nil { 1479 mctx.Debug("TeamLoader error getting my role: %v", err) 1480 return false 1481 } 1482 if !role.IsAdminOrAbove() { 1483 if !state.IsSubteam() { 1484 return false 1485 } 1486 yes, err := l.isImplicitAdminOf(mctx.Ctx(), state.GetID(), state.GetParentID(), me, me) 1487 if err != nil { 1488 mctx.Debug("TeamLoader error getting checking implicit admin: %s", err) 1489 return false 1490 } 1491 if !yes { 1492 return false 1493 } 1494 } 1495 return true 1496 } 1497 1498 // Check whether a user is an implicit admin of a team. 1499 func (l *TeamLoader) isImplicitAdminOf(ctx context.Context, teamID keybase1.TeamID, ancestorID *keybase1.TeamID, 1500 me keybase1.UserVersion, uv keybase1.UserVersion) (bool, error) { 1501 1502 // IDs of ancestors that were not freshly polled. 1503 // Check them again with forceRepoll if the affirmative is not found cached. 1504 checkAgain := make(map[keybase1.TeamID]bool) 1505 1506 check1 := func(chain *TeamSigChainState) bool { 1507 role, err := chain.GetUserRole(uv) 1508 if err != nil { 1509 return false 1510 } 1511 return role.IsAdminOrAbove() 1512 } 1513 1514 i := 0 1515 for { 1516 i++ 1517 if i >= 100 { 1518 // Break in case there's a bug in this loop. 1519 return false, fmt.Errorf("stuck in a loop while checking for implicit admin: %v", ancestorID) 1520 } 1521 1522 // Use load2 so that we can use subteam-reader and get secretless teams. 1523 ancestor, err := l.load2(ctx, load2ArgT{ 1524 teamID: *ancestorID, 1525 reason: "isImplicitAdminOf-1", 1526 me: me, 1527 readSubteamID: &teamID, 1528 }) 1529 if err != nil { 1530 return false, err 1531 } 1532 // Be wary, `ancestor` could be, and is likely, a secretless team. 1533 // Do not let it out of sight. 1534 ancestorChain := TeamSigChainState{inner: ancestor.team.Chain} 1535 1536 if !ancestor.didRepoll { 1537 checkAgain[ancestorChain.GetID()] = true 1538 } 1539 1540 if check1(&ancestorChain) { 1541 return true, nil 1542 } 1543 1544 if !ancestorChain.IsSubteam() { 1545 break 1546 } 1547 // Get the next level up. 1548 ancestorID = ancestorChain.GetParentID() 1549 } 1550 1551 // The answer was not found to be yes in the cache. 1552 // Try again with the teams that were not polled as they might have unseen updates. 1553 for ancestorID := range checkAgain { 1554 ancestor, err := l.load2(ctx, load2ArgT{ 1555 teamID: ancestorID, 1556 reason: "isImplicitAdminOf-again", 1557 me: me, 1558 forceRepoll: true, // Get the latest info. 1559 readSubteamID: &teamID, 1560 }) 1561 if err != nil { 1562 return false, err 1563 } 1564 // Be wary, `ancestor` could be, and is likely, a secretless team. 1565 // Do not let it out of sight. 1566 ancestorChain := TeamSigChainState{inner: ancestor.team.Chain} 1567 if check1(&ancestorChain) { 1568 return true, nil 1569 } 1570 } 1571 1572 return false, nil 1573 } 1574 1575 func (l *TeamLoader) satisfiesNeedsKBFSKeyGeneration(mctx libkb.MetaContext, 1576 kbfs keybase1.TeamKBFSKeyRefresher, state Teamer) error { 1577 if kbfs.Generation == 0 { 1578 return nil 1579 } 1580 if state == nil { 1581 return fmt.Errorf("nil team does not contain KBFS key generation: %#v", kbfs) 1582 } 1583 1584 gen, err := newTeamSigChainState(state).GetLatestKBFSGeneration(kbfs.AppType) 1585 if err != nil { 1586 return err 1587 } 1588 if kbfs.Generation > gen { 1589 return NewKBFSKeyGenerationError(kbfs.Generation, gen) 1590 } 1591 return nil 1592 } 1593 1594 // Whether the snapshot has loaded at least up to the key generation and has the secret. 1595 func (l *TeamLoader) satisfiesNeedKeyGeneration(mctx libkb.MetaContext, needKeyGeneration keybase1.PerTeamKeyGeneration, state Teamer) error { 1596 if needKeyGeneration == 0 { 1597 return nil 1598 } 1599 if state == nil { 1600 return fmt.Errorf("nil team does not contain key generation: %v", needKeyGeneration) 1601 } 1602 key, err := newTeamSigChainState(state).GetLatestPerTeamKey(mctx) 1603 if err != nil { 1604 return err 1605 } 1606 if needKeyGeneration > key.Gen { 1607 return fmt.Errorf("team key generation too low: %v < %v", key.Gen, needKeyGeneration) 1608 } 1609 _, ok := state.MainChain().PerTeamKeySeedsUnverified[needKeyGeneration] 1610 if !ok { 1611 return fmt.Errorf("team key secret missing for generation: %v", needKeyGeneration) 1612 } 1613 return nil 1614 } 1615 1616 // Whether the snapshot has loaded the reader key masks and key generations we 1617 // need. 1618 func (l *TeamLoader) satisfiesNeedApplicationsAtGenerations(mctx libkb.MetaContext, 1619 needApplicationsAtGenerations map[keybase1.PerTeamKeyGeneration][]keybase1.TeamApplication, team Teamer) error { 1620 if len(needApplicationsAtGenerations) == 0 { 1621 return nil 1622 } 1623 if team == nil || team.MainChain() == nil { 1624 return fmt.Errorf("nil team does not contain applications: %v", needApplicationsAtGenerations) 1625 } 1626 for ptkGen, apps := range needApplicationsAtGenerations { 1627 for _, app := range apps { 1628 if _, err := ApplicationKeyAtGeneration(mctx, team, app, ptkGen); err != nil { 1629 return err 1630 } 1631 } 1632 } 1633 return nil 1634 } 1635 1636 func (l *TeamLoader) satisfiesNeedApplicationsAtGenerationsWithKBFS(mctx libkb.MetaContext, 1637 needApplicationsAtGenerations map[keybase1.PerTeamKeyGeneration][]keybase1.TeamApplication, 1638 state Teamer) error { 1639 if len(needApplicationsAtGenerations) == 0 { 1640 return nil 1641 } 1642 if state == nil || state.MainChain() == nil { 1643 return fmt.Errorf("nil team does not contain applications: %v", needApplicationsAtGenerations) 1644 } 1645 for ptkGen, apps := range needApplicationsAtGenerations { 1646 for _, app := range apps { 1647 if _, err := ApplicationKeyAtGenerationWithKBFS(mctx, state, app, ptkGen); err != nil { 1648 return err 1649 } 1650 } 1651 } 1652 return nil 1653 } 1654 1655 // Whether the snapshot has each of `wantMembers` as a member. 1656 func (l *TeamLoader) satisfiesWantMembers(mctx libkb.MetaContext, 1657 wantMembers []keybase1.UserVersion, wantMembersRole keybase1.TeamRole, state Teamer) error { 1658 1659 if wantMembersRole == keybase1.TeamRole_NONE { 1660 // Default to writer. 1661 wantMembersRole = keybase1.TeamRole_WRITER 1662 } 1663 if len(wantMembers) == 0 { 1664 return nil 1665 } 1666 if state == nil { 1667 return fmt.Errorf("nil team does not have wanted members") 1668 } 1669 for _, uv := range wantMembers { 1670 role, err := newTeamSigChainState(state).GetUserRole(uv) 1671 if err != nil { 1672 return fmt.Errorf("could not get wanted user role: %v", err) 1673 } 1674 if !role.IsOrAbove(wantMembersRole) { 1675 return fmt.Errorf("wanted user %v is a %v which is not at least %v", uv, role, wantMembersRole) 1676 } 1677 } 1678 return nil 1679 } 1680 1681 func (l *TeamLoader) mungeWantMembers(ctx context.Context, wantMembers []keybase1.UserVersion) (res []keybase1.UserVersion, err error) { 1682 for _, uv1 := range wantMembers { 1683 uv2 := uv1 1684 if uv2.EldestSeqno == 0 { 1685 // Lookup the latest eldest seqno for that uid. 1686 // This value may come from a cache. 1687 uv2.EldestSeqno, err = l.world.lookupEldestSeqno(ctx, uv2.Uid) 1688 if err != nil { 1689 return res, err 1690 } 1691 l.G().Log.CDebugf(ctx, "TeamLoader resolved wantMember %v -> %v", uv2.Uid, uv2.EldestSeqno) 1692 } 1693 res = append(res, uv2) 1694 } 1695 return res, err 1696 } 1697 1698 // Whether y is in xs. 1699 func (l *TeamLoader) seqnosContains(xs []keybase1.Seqno, y keybase1.Seqno) bool { 1700 for _, x := range xs { 1701 if x.Eq(y) { 1702 return true 1703 } 1704 } 1705 return false 1706 } 1707 1708 // Return the max in a list of positive seqnos. Returns 0 if the list is empty 1709 func (l *TeamLoader) seqnosMax(seqnos []keybase1.Seqno) (ret keybase1.Seqno) { 1710 for _, x := range seqnos { 1711 if x > ret { 1712 ret = x 1713 } 1714 } 1715 return ret 1716 } 1717 1718 // Whether a TeamData from the cache is fresh. 1719 func (l *TeamLoader) isFresh(mctx libkb.MetaContext, cachedAt keybase1.Time) bool { 1720 if cachedAt.IsZero() { 1721 // This should never happen. 1722 mctx.Warning("TeamLoader encountered zero cached time") 1723 return false 1724 } 1725 diff := mctx.G().Clock().Now().Sub(cachedAt.Time()) 1726 fresh := (diff <= freshnessLimit) 1727 if !fresh { 1728 mctx.Debug("TeamLoader cached snapshot is old: %v", diff) 1729 } 1730 return fresh 1731 } 1732 1733 // Whether the teams secrets are synced to the same point as its sigchain 1734 // Does not check RKMs. 1735 func (l *TeamLoader) hasSyncedSecrets(mctx libkb.MetaContext, team Teamer) bool { 1736 state := team.MainChain() 1737 n := len(team.MainChain().Chain.PerTeamKeys) 1738 offChainGen := len(state.PerTeamKeySeedsUnverified) 1739 mctx.Debug("TeamLoader#hasSyncedSecrets: found %d PTKs on the main chain (versus %d seeds)", n, offChainGen) 1740 if team.HiddenChain() != nil { 1741 m := len(team.HiddenChain().ReaderPerTeamKeys) 1742 mctx.Debug("TeamLoader#hasSyncedSecrets: found another %d PTKs on the hidden chain", m) 1743 n += m 1744 } 1745 return (n == offChainGen) 1746 } 1747 1748 func (l *TeamLoader) logIfUnsyncedSecrets(ctx context.Context, state *keybase1.TeamData) { 1749 onChainGen := keybase1.PerTeamKeyGeneration(len(state.Chain.PerTeamKeys)) 1750 offChainGen := keybase1.PerTeamKeyGeneration(len(state.PerTeamKeySeedsUnverified)) 1751 if onChainGen != offChainGen { 1752 l.G().Log.CDebugf(ctx, "TeamLoader unsynced secrets local:%v != chain:%v ", offChainGen, onChainGen) 1753 } 1754 } 1755 1756 func (l *TeamLoader) lows(mctx libkb.MetaContext, state *keybase1.TeamData, hp *hidden.LoaderPackage, arg load2ArgT) getLinksLows { 1757 var lows getLinksLows 1758 if state != nil { 1759 chain := TeamSigChainState{inner: state.Chain} 1760 lows.Seqno = chain.GetLatestSeqno() 1761 if !arg.foundRKMHole { 1762 lows.PerTeamKey = keybase1.PerTeamKeyGeneration(len(state.PerTeamKeySeedsUnverified)) 1763 } 1764 } 1765 if hp != nil { 1766 lows.HiddenChainSeqno = hp.LastFullSeqno() 1767 } 1768 return lows 1769 } 1770 1771 func (l *TeamLoader) OnLogout(mctx libkb.MetaContext) error { 1772 l.storage.ClearMem() 1773 return nil 1774 } 1775 1776 func (l *TeamLoader) OnDbNuke(mctx libkb.MetaContext) error { 1777 l.storage.ClearMem() 1778 return nil 1779 } 1780 1781 // Clear the in-memory cache. 1782 func (l *TeamLoader) ClearMem() { 1783 l.storage.ClearMem() 1784 } 1785 1786 func (l *TeamLoader) VerifyTeamName(ctx context.Context, id keybase1.TeamID, name keybase1.TeamName) error { 1787 if name.IsRootTeam() { 1788 if !name.ToTeamID(id.IsPublic()).Eq(id) { 1789 return NewResolveError(name, id) 1790 } 1791 return nil 1792 } 1793 teamData, _, err := l.Load(ctx, keybase1.LoadTeamArg{ 1794 ID: id, 1795 Public: id.IsPublic(), 1796 }) 1797 if err != nil { 1798 return err 1799 } 1800 gotName := teamData.Name 1801 if !gotName.Eq(name) { 1802 return NewResolveError(name, id) 1803 } 1804 return nil 1805 } 1806 1807 // List all the admins of ancestor teams. 1808 // Includes admins of the specified team only if they are also admins of ancestor teams. 1809 // The specified team must be a subteam, or an error is returned. 1810 // Always sends a flurry of RPCs to get the most up to date info. 1811 func (l *TeamLoader) ImplicitAdmins(ctx context.Context, teamID keybase1.TeamID) (impAdmins []keybase1.UserVersion, err error) { 1812 impAdminsMap := make(map[string]keybase1.UserVersion) // map to remove dups 1813 err = l.MapTeamAncestors(ctx, func(t keybase1.TeamSigChainState, _ keybase1.TeamName) error { 1814 ancestorChain := TeamSigChainState{inner: t} 1815 // Gather the admins. 1816 adminRoles := []keybase1.TeamRole{keybase1.TeamRole_OWNER, keybase1.TeamRole_ADMIN} 1817 for _, role := range adminRoles { 1818 uvs, err := ancestorChain.GetUsersWithRole(role) 1819 if err != nil { 1820 return err 1821 } 1822 for _, uv := range uvs { 1823 impAdminsMap[uv.String()] = uv 1824 } 1825 } 1826 return nil 1827 }, teamID, "implicitAdminsAncestor", func(keybase1.TeamSigChainState) bool { return true }) 1828 if err != nil { 1829 return nil, err 1830 } 1831 for _, uv := range impAdminsMap { 1832 impAdmins = append(impAdmins, uv) 1833 } 1834 return impAdmins, nil 1835 } 1836 1837 // MapTeamAncestors does NOT map over the team itself. 1838 func (l *TeamLoader) MapTeamAncestors( 1839 ctx context.Context, 1840 f func(keybase1.TeamSigChainState, keybase1.TeamName) error, 1841 teamID keybase1.TeamID, 1842 reason string, 1843 forceFullReloadOnceToAssert func(t keybase1.TeamSigChainState) bool, 1844 ) (err error) { 1845 initialTeamIdx := 0 1846 1847 me, err := l.world.getMe(ctx) 1848 if err != nil { 1849 return NewMapAncestorsError(err, initialTeamIdx) 1850 } 1851 1852 // Load the argument team 1853 team, _, err := l.load1(ctx, me, keybase1.LoadTeamArg{ 1854 ID: teamID, 1855 Public: teamID.IsPublic(), 1856 StaleOK: true, // We only use immutable fields. 1857 }) 1858 if err != nil { 1859 return NewMapAncestorsError(err, initialTeamIdx) 1860 } 1861 teamChain := TeamSigChainState{inner: team.Chain} 1862 if !teamChain.IsSubteam() { 1863 return NewMapAncestorsError( 1864 fmt.Errorf("cannot map over parents of a root team: %v", teamID), 1865 initialTeamIdx, 1866 ) 1867 } 1868 return l.mapTeamAncestorsHelper(ctx, f, teamID, teamChain.GetParentID(), reason, forceFullReloadOnceToAssert) 1869 } 1870 1871 func (l *TeamLoader) mapTeamAncestorsHelper( 1872 ctx context.Context, 1873 f func(keybase1.TeamSigChainState, keybase1.TeamName) error, 1874 teamID keybase1.TeamID, 1875 ancestorID *keybase1.TeamID, 1876 reason string, 1877 forceFullReloadOnceToAssert func(t keybase1.TeamSigChainState) bool, 1878 ) (err error) { 1879 i := 0 1880 1881 defer func() { 1882 if err != nil { 1883 err = NewMapAncestorsError(err, i) 1884 } 1885 }() 1886 1887 me, err := l.world.getMe(ctx) 1888 if err != nil { 1889 return err 1890 } 1891 1892 for { 1893 i++ 1894 if i >= 100 { 1895 // Break in case there's a bug in this loop. 1896 return fmt.Errorf("stuck in a loop while mapping over team parents: %v", ancestorID) 1897 } 1898 1899 load2Arg := load2ArgT{ 1900 teamID: *ancestorID, 1901 reason: reason, 1902 me: me, 1903 forceRepoll: true, // Get the latest info. 1904 readSubteamID: &teamID, 1905 } 1906 1907 var ancestor *load2ResT 1908 for { 1909 var err error 1910 // Use load2 so that we can use subteam-reader and get secretless teams. 1911 ancestor, err = l.load2(ctx, load2Arg) 1912 if err != nil { 1913 return err 1914 } 1915 1916 if forceFullReloadOnceToAssert == nil || 1917 forceFullReloadOnceToAssert(ancestor.team.Chain) { 1918 break 1919 } 1920 if load2Arg.forceFullReload { 1921 return fmt.Errorf("failed to assert predicate in ancestor %v after full force reload", ancestor.team.ID()) 1922 } 1923 load2Arg.forceFullReload = true 1924 } 1925 1926 // Be wary, `ancestor` could be, and is likely, a secretless team. 1927 // Do not let it out of sight. 1928 ancestorChain := TeamSigChainState{inner: ancestor.team.Chain} 1929 1930 err = f(ancestor.team.Chain, ancestor.team.Name) 1931 if err != nil { 1932 return err 1933 } 1934 1935 if !ancestorChain.IsSubteam() { 1936 break 1937 } 1938 // Get the next level up. 1939 ancestorID = ancestorChain.GetParentID() 1940 } 1941 1942 return nil 1943 } 1944 1945 func (l *TeamLoader) NotifyTeamRename(ctx context.Context, id keybase1.TeamID, newName string) error { 1946 // ignore newName from the server 1947 1948 // Load up the ancestor chain with ForceRepoll. 1949 // Then load down the ancestor chain without it (expect cache hits). 1950 // Not the most elegant way, but it will get the job done. 1951 // Each load on the way down will recalculate that team's name. 1952 1953 var ancestorIDs []keybase1.TeamID 1954 1955 me, err := l.world.getMe(ctx) 1956 if err != nil { 1957 return err 1958 } 1959 1960 loopID := &id 1961 for loopID != nil { 1962 load2Res, err := l.load2(ctx, load2ArgT{ 1963 teamID: *loopID, 1964 reason: "NotifyTeamRename-force", 1965 forceRepoll: true, 1966 readSubteamID: &id, 1967 me: me, 1968 }) 1969 if err != nil { 1970 return err 1971 } 1972 ancestorIDs = append(ancestorIDs, *loopID) 1973 chain := TeamSigChainState{inner: load2Res.team.Chain} 1974 if chain.IsSubteam() { 1975 loopID = chain.GetParentID() 1976 } else { 1977 loopID = nil 1978 } 1979 } 1980 1981 // reverse ancestorIDs so the root team appears first 1982 sort.SliceStable(ancestorIDs, func(i, j int) bool { return i > j }) 1983 1984 for _, loopID := range ancestorIDs { 1985 _, err := l.load2(ctx, load2ArgT{ 1986 teamID: loopID, 1987 reason: "NotifyTeamRename-quick", 1988 readSubteamID: &id, 1989 me: me, 1990 }) 1991 if err != nil { 1992 return err 1993 } 1994 } 1995 1996 return nil 1997 } 1998 1999 func (l *TeamLoader) getHeadMerkleSeqno(mctx libkb.MetaContext, readSubteamID keybase1.TeamID, state *keybase1.TeamSigChainState) (ret keybase1.Seqno, err error) { 2000 defer mctx.Trace("TeamLoader#getHeadMerkleSeqno", &err)() 2001 2002 if state.HeadMerkle != nil { 2003 return state.HeadMerkle.Seqno, nil 2004 } 2005 headSeqno := keybase1.Seqno(1) 2006 expectedLinkRaw, ok := state.LinkIDs[headSeqno] 2007 if !ok { 2008 return ret, fmt.Errorf("couldn't find head link in team state during audit") 2009 } 2010 expectedLink, err := libkb.ImportLinkID(expectedLinkRaw) 2011 if err != nil { 2012 return ret, err 2013 } 2014 teamUpdate, err := l.world.getLinksFromServer(mctx.Ctx(), state.Id, []keybase1.Seqno{headSeqno}, &readSubteamID) 2015 if err != nil { 2016 return ret, err 2017 } 2018 newLinks, err := teamUpdate.unpackLinks(mctx) 2019 if err != nil { 2020 return ret, err 2021 } 2022 if len(newLinks) != 1 { 2023 return ret, fmt.Errorf("expected only one chainlink back; got %d", len(newLinks)) 2024 } 2025 headLink := newLinks[0] 2026 err = headLink.AssertInnerOuterMatch() 2027 if err != nil { 2028 return ret, err 2029 } 2030 if headLink.Seqno() != headSeqno { 2031 return ret, NewInvalidLink(headLink, "wrong head seqno; wanted 1 but got something else") 2032 } 2033 if !headLink.LinkID().Eq(expectedLink) { 2034 return ret, NewInvalidLink(headLink, "wrong head link hash: %s != %s", headLink.LinkID(), expectedLink) 2035 } 2036 if headLink.isStubbed() { 2037 return ret, NewInvalidLink(headLink, "got a stubbed head link, but wasn't expecting that") 2038 } 2039 headMerkle := headLink.inner.Body.MerkleRoot.ToMerkleRootV2() 2040 state.HeadMerkle = &headMerkle 2041 return headMerkle.Seqno, nil 2042 } 2043 2044 func (l *TeamLoader) audit(ctx context.Context, readSubteamID keybase1.TeamID, state *keybase1.TeamSigChainState, hiddenChain *keybase1.HiddenTeamChain, lastMerkleRoot *libkb.MerkleRoot, auditMode keybase1.AuditMode) (err error) { 2045 mctx := libkb.NewMetaContext(ctx, l.G()) 2046 2047 if l.G().Env.Test.TeamSkipAudit { 2048 mctx.Debug("skipping audit in test due to flag") 2049 return nil 2050 } 2051 2052 headMerklSeqno, err := l.getHeadMerkleSeqno(mctx, readSubteamID, state) 2053 if err != nil { 2054 return err 2055 } 2056 2057 err = mctx.G().GetTeamAuditor().AuditTeam(mctx, state.Id, state.Public, headMerklSeqno, state.LinkIDs, hiddenChain.GetOuter(), state.LastSeqno, hiddenChain.GetLastCommittedSeqno(), lastMerkleRoot, auditMode) 2058 return err 2059 } 2060 2061 func (l *TeamLoader) ForceRepollUntil(ctx context.Context, dtime gregor.TimeOrOffset) error { 2062 l.G().Log.CDebugf(ctx, "TeamLoader#ForceRepollUntil(%+v)", dtime) 2063 l.forceRepollMutex.Lock() 2064 defer l.forceRepollMutex.Unlock() 2065 l.forceRepollUntil = dtime 2066 return nil 2067 } 2068 2069 func (l *TeamLoader) InForceRepollMode(mctx libkb.MetaContext) bool { 2070 l.forceRepollMutex.Lock() 2071 defer l.forceRepollMutex.Unlock() 2072 if l.forceRepollUntil == nil { 2073 return false 2074 } 2075 if !l.forceRepollUntil.Before(mctx.G().Clock().Now()) { 2076 mctx.Debug("TeamLoader#InForceRepollMode: returning true") 2077 return true 2078 } 2079 l.forceRepollUntil = nil 2080 return false 2081 }