1package teams
2
3import (
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
22var teamEnv struct {
23	Profile             bool
24	UserPreloadEnable   bool
25	UserPreloadParallel bool
26	UserPreloadWait     bool
27	ProofSetParallel    bool
28}
29
30func 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
39const freshnessLimit = time.Duration(1) * time.Hour
40
41// Load a Team from the TeamLoader.
42// Can be called from inside the teams package.
43func 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.
67type 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
88var _ libkb.TeamLoader = (*TeamLoader)(nil)
89
90func 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.
102func 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
113func (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
124func 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
133func (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
151func (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
169func (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.
193func (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
207type nameLookupBurstCacheKey struct {
208	teamName keybase1.TeamName
209	public   bool
210}
211
212func (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.
218func (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
245func 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
266func (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).
278func (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
398func (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.
418type 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
456type load2ResT struct {
457	team      keybase1.TeamData
458	hidden    *keybase1.HiddenTeamChain
459	didRepoll bool
460}
461
462func (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
468func (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
489func (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
498func (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
544func (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		hiddenIsFresh = true
554		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).")
555	case libkb.MerkleHiddenResponseTypeFLAGOFF:
556		hiddenIsFresh = true
557		mctx.Debug("Skipping CheckHiddenMerklePathResponseAndAddRatchets as the hidden flag is off.")
558	default:
559		hiddenIsFresh, err = hiddenPackage.CheckHiddenMerklePathResponseAndAddRatchets(mctx, hiddenResp)
560		if err != nil {
561			return false, err
562		}
563	}
564	return hiddenIsFresh, nil
565}
566
567func (l *TeamLoader) load2InnerLockedRetry(ctx context.Context, arg load2ArgT) (*load2ResT, error) {
568	ctx, tbs := l.G().CTimeBuckets(ctx)
569	mctx := libkb.NewMetaContext(ctx, l.G())
570	tracer := l.G().CTimeTracer(ctx, "TeamLoader.load2ILR", teamEnv.Profile)
571	defer tracer.Finish()
572
573	defer tbs.LogIfNonZero(ctx, "API.request")
574
575	var err error
576	var didRepoll bool
577	lkc := newLoadKeyCache()
578
579	// Fetch from cache
580	tracer.Stage("cache load")
581	tailCheckRet, frozen, tombstoned := l.storage.Get(mctx, arg.teamID, arg.public)
582	if tombstoned {
583		return nil, NewTeamTombstonedError()
584	}
585
586	// Fetch last polled time from merkle cache
587	merklePolledAt := l.merkleStorage.Get(mctx, arg.teamID, arg.public)
588
589	var ret *keybase1.TeamData
590	if !frozen && !arg.forceFullReload {
591		// Load from cache
592		ret = tailCheckRet
593	}
594
595	if ret != nil && !ret.Chain.Reader.Eq(arg.me) {
596		// Check that we are the same person as when this team was last loaded as a courtesy.
597		// This should never happen. We shouldn't be able to decrypt someone else's snapshot.
598		mctx.Warning("TeamLoader discarding snapshot for wrong user: (%v, %v) != (%v, %v)",
599			arg.me.Uid, arg.me.EldestSeqno, ret.Chain.Reader.Uid, ret.Chain.Reader.EldestSeqno)
600		ret = nil
601	}
602
603	var cachedName *keybase1.TeamName
604	if ret != nil && !ret.Name.IsNil() {
605		cachedName = &ret.Name
606	}
607
608	hiddenPackage, err := l.hiddenPackage(mctx, arg.teamID, ret, arg.me)
609	if err != nil {
610		return nil, err
611	}
612
613	teamShim := func() *TeamShim {
614		return &TeamShim{Data: ret, Hidden: hiddenPackage.ChainData()}
615	}
616
617	// Determine whether to repoll merkle.
618	discardCache, repoll := l.load2DecideRepoll(mctx, arg, teamShim(), merklePolledAt)
619	if discardCache {
620		ret = nil
621		repoll = true
622	}
623
624	tracer.Stage("deepcopy")
625	if ret != nil {
626		// If we're pulling from a previous snapshot (that, let's say, we got from a shared cache),
627		// then make sure to DeepCopy() data out of it before we start mutating it below. We used
628		// to do this every step through the new links, but that was very expensive in terms of CPU
629		// for big teams, since it was hidden quadratic behavior.
630		tmp := ret.DeepCopy()
631		ret = &tmp
632	} else {
633		mctx.Debug("TeamLoader not using snapshot")
634	}
635
636	tracer.Stage("merkle")
637	var lastSeqno keybase1.Seqno
638	var lastLinkID keybase1.LinkID
639	var hiddenIsFresh bool
640	var lastMerkleRoot *libkb.MerkleRoot
641
642	// hiddenResp will be nill iff we do not make the merkleLookupWithHidden
643	// call. If the server does not return any hidden data, we will encode that
644	// as a non nil response whose RespType is MerkleHiddenResponseTypeNONE.
645	var hiddenResp *libkb.MerkleHiddenResponse
646
647	if (ret == nil) || repoll {
648		mctx.Debug("TeamLoader looking up merkle leaf (force:%v)", arg.forceRepoll)
649
650		// Reference the merkle tree to fetch the sigchain tail leaf for the team.
651		lastSeqno, lastLinkID, hiddenResp, lastMerkleRoot, err = l.world.merkleLookupWithHidden(ctx, arg.teamID, arg.public)
652		if err != nil {
653			return nil, err
654		}
655		mctx.Debug("received lastSeqno %v, lastLinkID %v", lastSeqno, lastLinkID)
656
657		hiddenIsFresh, err = l.checkHiddenResponse(mctx, hiddenPackage, hiddenResp)
658		if err != nil {
659			return nil, err
660		}
661
662		didRepoll = true
663	} else {
664		lastSeqno = ret.Chain.LastSeqno
665		lastLinkID = ret.Chain.LastLinkID
666		hiddenIsFresh = true
667	}
668
669	// For child calls to load2, the subteam reader ID is carried up
670	// or if it doesn't exist, start at this team.
671	readSubteamID := arg.teamID
672	if arg.readSubteamID != nil {
673		readSubteamID = *arg.readSubteamID
674	}
675
676	proofSet := newProofSet(l.G())
677	var parentChildOperations []*parentChildOperation
678
679	// Backfill stubbed links that need to be filled now.
680	tracer.Stage("backfill")
681	var filledInStubbedLinks bool
682	if ret != nil && len(arg.needSeqnos) > 0 {
683		ret, proofSet, parentChildOperations, err = l.fillInStubbedLinks(
684			mctx, arg.me, arg.teamID, ret, arg.needSeqnos, readSubteamID, proofSet, parentChildOperations, lkc)
685		if err != nil {
686			return nil, err
687		}
688		filledInStubbedLinks = true
689	}
690
691	tracer.Stage("pre-fetch")
692	var fetchLinksAndOrSecrets bool
693	if ret == nil {
694		mctx.Debug("TeamLoader fetching: no cache")
695		// We have no cache
696		fetchLinksAndOrSecrets = true
697	} else if ret.Chain.LastSeqno < lastSeqno {
698		mctx.Debug("TeamLoader fetching: chain update")
699		// The cache is definitely behind
700		fetchLinksAndOrSecrets = true
701	} else if !hiddenIsFresh {
702		mctx.Debug("TeamLoader fetching: hidden chain wasn't fresh")
703		fetchLinksAndOrSecrets = true
704	} else if !l.hasSyncedSecrets(mctx, teamShim()) {
705		// The cached secrets are behind the cached chain.
706		// We may need to hit the server for secrets, even though there are no new links.
707		if arg.needAdmin {
708			mctx.Debug("TeamLoader fetching: NeedAdmin")
709			// Admins should always have up-to-date secrets. But not necessarily RKMs.
710			fetchLinksAndOrSecrets = true
711		}
712		if err := l.satisfiesNeedKeyGeneration(mctx, arg.needKeyGeneration, teamShim()); err != nil {
713			mctx.Debug("TeamLoader fetching: NeedKeyGeneration: %v", err)
714			fetchLinksAndOrSecrets = true
715		}
716		if err := l.satisfiesNeedsKBFSKeyGeneration(mctx, arg.needKBFSKeyGeneration, teamShim()); err != nil {
717			mctx.Debug("TeamLoader fetching: KBFSNeedKeyGeneration: %v", err)
718			fetchLinksAndOrSecrets = true
719		}
720		if arg.readSubteamID == nil {
721			// This is not a recursive load. We should have the keys.
722			// This may be an extra round trip for public teams you're not in.
723			mctx.Debug("TeamLoader fetching: primary load")
724			fetchLinksAndOrSecrets = true
725		}
726	}
727	// hasSyncedSecrets does not account for RKMs. So check RKM refreshers separeately.
728
729	if err := l.satisfiesNeedApplicationsAtGenerations(mctx, arg.needApplicationsAtGenerations, teamShim()); err != nil {
730		mctx.Debug("TeamLoader fetching: NeedApplicationsAtGenerations: %v", err)
731		fetchLinksAndOrSecrets = true
732	}
733	if err := l.satisfiesNeedApplicationsAtGenerationsWithKBFS(mctx,
734		arg.needApplicationsAtGenerationsWithKBFS, teamShim()); err != nil {
735		mctx.Debug("TeamLoader fetching: NeedApplicationsAtGenerationsWithKBFS: %v", err)
736		fetchLinksAndOrSecrets = true
737	}
738
739	// Pull new links from the server
740	tracer.Stage("fetch")
741	var teamUpdate *rawTeam
742	if fetchLinksAndOrSecrets {
743		lows := l.lows(mctx, ret, hiddenPackage, arg)
744		mctx.Debug("TeamLoader getting links from server (%+v)", lows)
745		teamUpdate, err = l.world.getNewLinksFromServer(ctx, arg.teamID, lows, arg.readSubteamID)
746		if err != nil {
747			return nil, err
748		}
749		mctx.Debug("TeamLoader got %v links", len(teamUpdate.Chain))
750		hiddenPackage.SetRatchetBlindingKeySet(teamUpdate.RatchetBlindingKeySet)
751	}
752
753	tracer.Stage("unpack")
754	links, err := teamUpdate.unpackLinks(mctx)
755	if err != nil {
756		return nil, err
757	}
758	var prev libkb.LinkID
759	if ret != nil {
760		prev, err = TeamSigChainState{inner: ret.Chain}.GetLatestLibkbLinkID()
761		if err != nil {
762			return nil, err
763		}
764	}
765
766	// A link which was signed by an admin. Sloppily the latest such link.
767	// Sloppy because this calculation misses out on e.g. a rotate_key signed by an admin.
768	// This value is used for skipping fullVerify on team.leave links, see `verifyLink`.
769	var fullVerifyCutoff keybase1.Seqno
770	for i := len(links) - 1; i >= 0; i-- {
771		if links[i].LinkType().RequiresAtLeastRole().IsAdminOrAbove() {
772			fullVerifyCutoff = links[i].Seqno()
773			break
774		}
775	}
776	if fullVerifyCutoff > 0 {
777		mctx.Debug("fullVerifyCutoff: %v", fullVerifyCutoff)
778	}
779
780	tracer.Stage("userPreload enable:%v parallel:%v wait:%v",
781		teamEnv.UserPreloadEnable, teamEnv.UserPreloadParallel, teamEnv.UserPreloadWait)
782	preloadCancel := l.userPreload(ctx, links, fullVerifyCutoff)
783	defer preloadCancel()
784
785	tracer.Stage("linkloop (%v)", len(links))
786	parentsCache := make(parentChainCache)
787
788	// Don't log in the middle links if there are a great many links.
789	suppressLoggingStart := 5
790	suppressLoggingUpto := len(links) - 5
791	for i, link := range links {
792		var err error
793		ret, prev, err = l.doOneLink(mctx, arg, ret, hiddenPackage, link, i, suppressLoggingStart, suppressLoggingUpto, lastSeqno, &parentChildOperations, prev, fullVerifyCutoff, readSubteamID, proofSet, lkc, &parentsCache)
794		if err != nil {
795			return nil, err
796		}
797	}
798
799	if ret == nil {
800		return nil, fmt.Errorf("team loader fault: got nil from load2")
801	}
802
803	encKID, gen, role, err := l.hiddenPackageGetter(mctx, arg.teamID, ret, arg.me)()
804	if err != nil {
805		return nil, err
806	}
807
808	// If we did get an update from the server (hiddenResp != nil) are not a
809	// restricted bot AND this is not a recursive load (arg.readSubteamID == nil),
810	// then the server should have given us hidden chain data.
811	if hiddenResp != nil && hiddenResp.RespType == libkb.MerkleHiddenResponseTypeNONE && !role.IsRestrictedBot() && arg.readSubteamID == nil {
812		return nil, libkb.NewHiddenChainDataMissingError("Not a restricted bot or recursive load, but the server did not return merkle hidden chain data")
813	}
814
815	// Update the hidden package with team metadata once we process all of the
816	// links. This is necessary since we need the role to be up to date to know
817	// if we should skip seed checks on the hidden chain if we are loading as a
818	// RESTRICTEDBOT.
819	hiddenPackage.UpdateTeamMetadata(encKID, gen, role)
820
821	// Be sure to update the hidden chain after the main chain, since the latter can "ratchet" the former
822	err = hiddenPackage.Update(mctx, teamUpdate.GetHiddenChain(), hiddenResp.GetUncommittedSeqno())
823
824	if err != nil {
825		return nil, err
826	}
827	err = hiddenPackage.CheckPTKsForDuplicates(mctx, func(g keybase1.PerTeamKeyGeneration) bool {
828		_, ok := ret.Chain.PerTeamKeys[g]
829		return ok
830	})
831	if err != nil {
832		return nil, err
833	}
834
835	// The hidden team has pointers from the hidden chain up to the visible chain; check that they
836	// match the loaded team. We should have a full load of the team, so all parent pointers
837	// better hit their mark.
838	err = hiddenPackage.CheckParentPointersOnFullLoad(mctx, ret)
839	if err != nil {
840		return nil, err
841	}
842
843	preloadCancel()
844	if len(links) > 0 {
845		tbs.Log(ctx, "TeamLoader.verifyLink")
846		tbs.Log(ctx, "TeamLoader.applyNewLink")
847		tbs.Log(ctx, "SigChain.LoadFromServer.ReadAll")
848		tbs.Log(ctx, "loadKeyCache.loadKeyV2")
849		if teamEnv.Profile {
850			tbs.Log(ctx, "LoaderContextG.loadKeyV2")
851			tbs.Log(ctx, "CachedUPAKLoader.LoadKeyV2") // note LoadKeyV2 calls Load2
852			tbs.Log(ctx, "CachedUPAKLoader.LoadV2")
853			tbs.Log(ctx, "CachedUPAKLoader.DeepCopy")
854			mctx.Debug("TeamLoader lkc cache hits: %v", lkc.cacheHits)
855		}
856	}
857
858	if !ret.Chain.LastLinkID.Eq(lastLinkID) {
859		return nil, fmt.Errorf("wrong sigchain link ID: %v != %v",
860			ret.Chain.LastLinkID, lastLinkID)
861	}
862
863	if tailCheckRet != nil {
864		// If we previously discarded cache due to forceFullReload, or left the
865		// team, froze it, and are rejoining, make sure the previous tail is
866		// still in the chain.
867		// The chain loader ensures it is part of a well-formed chain with correct prevs.
868		linkID := ret.Chain.LinkIDs[tailCheckRet.Chain.LastSeqno]
869		if !linkID.Eq(tailCheckRet.Chain.LastLinkID) {
870			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,
871				tailCheckRet.Chain.LastLinkID, ret.Frozen, linkID)
872		}
873	}
874
875	tracer.Stage("pco")
876	err = l.checkParentChildOperations(ctx,
877		arg.me, arg.teamID, ret.Chain.ParentID, readSubteamID, parentChildOperations, proofSet)
878	if err != nil {
879		return nil, err
880	}
881
882	tracer.Stage("checkproofs")
883	err = l.checkProofs(ctx, ret, proofSet)
884	if err != nil {
885		return nil, err
886	}
887
888	tracer.Stage("secrets")
889	if teamUpdate != nil {
890		if teamUpdate.SubteamReader {
891			// Only allow subteam-reader results if we are in a recursive load.
892			if arg.readSubteamID == nil {
893				return nil, fmt.Errorf("unexpected subteam reader result")
894			}
895		} else {
896			stateWrapper := newTeamSigChainState(teamShim())
897			role, err := stateWrapper.GetUserRole(arg.me)
898			if err != nil {
899				role = keybase1.TeamRole_NONE
900			}
901			// Add the secrets.
902			// If it's a public team, there might not be secrets. (If we're not in the team)
903			// Restricted bots don't have any team secrets, so we also short circuit.
904			if !role.IsRestrictedBot() && (!ret.Chain.Public || (teamUpdate.Box != nil)) {
905				err = l.addSecrets(mctx, teamShim(), arg.me, teamUpdate.Box, teamUpdate.Prevs, teamUpdate.ReaderKeyMasks)
906				if err != nil {
907					return nil, pkgErrors.Wrap(err, "loading team secrets")
908				}
909
910				err = l.computeSeedChecks(ctx, ret)
911				if err != nil {
912					return nil, err
913				}
914
915				if teamUpdate.LegacyTLFUpgrade != nil {
916					err = l.addKBFSCryptKeys(mctx, teamShim(), teamUpdate.LegacyTLFUpgrade)
917					if err != nil {
918						return nil, fmt.Errorf("loading KBFS crypt keys: %v", err)
919					}
920				}
921			}
922			if role.IsRestrictedBot() {
923				// Clear out any secrets we may have had in memory if we were a
924				// previous role that had PTK access.
925				state := teamShim().MainChain()
926				state.PerTeamKeySeedsUnverified = make(map[keybase1.PerTeamKeyGeneration]keybase1.PerTeamKeySeedItem)
927				state.ReaderKeyMasks = make(map[keybase1.TeamApplication]map[keybase1.PerTeamKeyGeneration]keybase1.MaskB64)
928				state.TlfCryptKeys = make(map[keybase1.TeamApplication][]keybase1.CryptKey)
929			}
930		}
931	}
932
933	// Note that we might have done so just above after adding secrets, but before adding
934	// KBFS crypt keys. But it's cheap to run this method twice in a row.
935	tracer.Stage("computeSeedChecks")
936	err = l.computeSeedChecks(ctx, ret)
937	if err != nil {
938		return nil, err
939	}
940
941	if !arg.skipSeedCheck && arg.readSubteamID == nil {
942		err = hiddenPackage.CheckUpdatesAgainstSeedsWithMap(mctx, ret.PerTeamKeySeedsUnverified)
943		if err != nil {
944			return nil, err
945		}
946	}
947
948	// Make sure public works out
949	if ret.Chain.Public != arg.public {
950		return nil, fmt.Errorf("team public mismatch: chain:%v != arg:%v", ret.Chain.Public, arg.public)
951	}
952	if ret.Chain.Id.IsPublic() != ret.Chain.Public {
953		return nil, fmt.Errorf("team public mismatch: id:%v != chain:%v", ret.Chain.Id.IsPublic(), ret.Chain.Public)
954	}
955
956	// Sanity check the id
957	if !ret.Chain.Id.Eq(arg.teamID) {
958		return nil, fmt.Errorf("team id mismatch: %v != %v", ret.Chain.Id.String(), arg.teamID.String())
959	}
960
961	// Recalculate the team name.
962	// This must always run to pick up changes on chain and off-chain with ancestor renames.
963	// Also because without this a subteam could claim any parent in its name.
964	tracer.Stage("namecalc")
965	newName, err := l.calculateName(ctx, ret, arg.me, readSubteamID, arg.staleOK)
966	if err != nil {
967		return nil, fmt.Errorf("error recalculating name for %v: %v", ret.Name, err)
968	}
969	if !ret.Name.Eq(newName) {
970		// This deep copy is an absurd price to pay, but these mid-team renames should be quite rare.
971		copy := ret.DeepCopy()
972		ret = &copy
973		ret.Name = newName
974	}
975
976	var needHiddenRotate bool
977	if !arg.skipNeedHiddenRotateCheck {
978		needHiddenRotate, err = l.checkNeedRotate(mctx, ret, arg.me, hiddenPackage)
979		if err != nil {
980			return nil, err
981		}
982	}
983
984	err = hiddenPackage.Commit(mctx)
985	if err != nil {
986		return nil, err
987	}
988
989	l.logIfUnsyncedSecrets(ctx, ret)
990
991	// Mutating this field is safe because only TeamLoader
992	// while holding the single-flight lock reads or writes this field.
993	ret.CachedAt = keybase1.ToTime(l.G().Clock().Now())
994
995	// Clear the untrusted seqno hint.
996	// Mutating this field is safe because only TeamLoader
997	// while holding the single-flight lock reads or writes this field.
998	ret.LatestSeqnoHint = 0
999
1000	if didRepoll {
1001		tracer.Stage("audit")
1002		auditMode := arg.auditMode
1003		// in case of restricted bots or recursive loads, do not audit the
1004		// hidden chain (as we might not have permission to see it).
1005		if (role.IsRestrictedBot() || arg.readSubteamID != nil) && auditMode == keybase1.AuditMode_STANDARD {
1006			auditMode = keybase1.AuditMode_STANDARD_NO_HIDDEN
1007		}
1008
1009		err = l.audit(ctx, readSubteamID, &ret.Chain, hiddenPackage.ChainData(), lastMerkleRoot, auditMode)
1010		if err != nil {
1011			return nil, err
1012		}
1013	} else {
1014		mctx.Debug("Skipping audit in the TeamLoader as we did not repoll merkle")
1015	}
1016
1017	// Cache the validated result if it was actually updated via the team/get endpoint. In many cases, we're not
1018	// actually mutating the teams. Also, if we wound up filling in stubbed links, let's also restore the cache.
1019	if teamUpdate != nil || filledInStubbedLinks {
1020		tracer.Stage("put")
1021		l.storage.Put(mctx, ret)
1022	}
1023
1024	// If we wound up repolling the merkle tree for this team, say that we did.
1025	if didRepoll {
1026		l.merkleStorage.Put(mctx, arg.teamID, arg.public, keybase1.ToTime(mctx.G().Clock().Now()))
1027	}
1028
1029	tracer.Stage("notify")
1030	if cachedName != nil && !cachedName.Eq(newName) {
1031		chain := TeamSigChainState{inner: ret.Chain, hidden: hiddenPackage.ChainData()}
1032		// Send a notification if we used to have the name cached and it has changed at all.
1033		changeSet := keybase1.TeamChangeSet{Renamed: true}
1034		go l.G().NotifyRouter.HandleTeamChangedByID(context.Background(), chain.GetID(), chain.GetLatestSeqno(),
1035			chain.IsImplicit(), changeSet, chain.GetLatestHiddenSeqno(), keybase1.Seqno(0), keybase1.TeamChangedSource_LOCAL_RENAME)
1036		go l.G().NotifyRouter.HandleTeamChangedByName(context.Background(), cachedName.String(), chain.GetLatestSeqno(),
1037			chain.IsImplicit(), changeSet, chain.GetLatestHiddenSeqno(), keybase1.Seqno(0), keybase1.TeamChangedSource_LOCAL_RENAME)
1038		go l.G().NotifyRouter.HandleTeamChangedByName(context.Background(), newName.String(), chain.GetLatestSeqno(),
1039			chain.IsImplicit(), changeSet, chain.GetLatestHiddenSeqno(), keybase1.Seqno(0), keybase1.TeamChangedSource_LOCAL_RENAME)
1040	}
1041
1042	// Check request constraints
1043	tracer.Stage("postcheck")
1044	err = l.load2CheckReturn(mctx, arg, teamShim())
1045	if err != nil {
1046		return nil, err
1047	}
1048
1049	load2res := load2ResT{
1050		team:      *ret,
1051		didRepoll: didRepoll,
1052	}
1053
1054	if hd := hiddenPackage.ChainData(); hd != nil {
1055		hd.NeedRotate = needHiddenRotate
1056		load2res.hidden = hd
1057	}
1058
1059	if needHiddenRotate {
1060		l.G().GetTeamBoxAuditor().MaybeScheduleDelayedBoxAuditTeam(mctx, arg.teamID)
1061	}
1062
1063	return &load2res, nil
1064}
1065
1066func (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) {
1067	return func() (encKID keybase1.KID, gen keybase1.PerTeamKeyGeneration,
1068		role keybase1.TeamRole, err error) {
1069		if team == nil {
1070			return encKID, gen, keybase1.TeamRole_NONE, nil
1071		}
1072		state := TeamSigChainState{inner: team.Chain}
1073
1074		ptk, err := state.GetLatestPerTeamKey(mctx)
1075		if err != nil {
1076			return encKID, gen, keybase1.TeamRole_NONE, err
1077		}
1078		role, err = state.GetUserRole(me)
1079		if err != nil {
1080			return encKID, gen, keybase1.TeamRole_NONE, err
1081		}
1082		return ptk.EncKID, ptk.Gen, role, nil
1083	}
1084}
1085
1086func (l *TeamLoader) hiddenPackage(mctx libkb.MetaContext, id keybase1.TeamID, team *keybase1.TeamData, me keybase1.UserVersion) (ret *hidden.LoaderPackage, err error) {
1087	getter := l.hiddenPackageGetter(mctx, id, team, me)
1088	return hidden.NewLoaderPackage(mctx, id, getter)
1089}
1090
1091func (l *TeamLoader) isAllowedKeyerOf(mctx libkb.MetaContext, chain *keybase1.TeamData, me keybase1.UserVersion, them keybase1.UserVersion) (ret bool, err error) {
1092	state := TeamSigChainState{inner: chain.Chain}
1093	mctx = mctx.WithLogTag("IAKO")
1094	defer mctx.Trace(fmt.Sprintf("TeamLoader#isAllowedKeyerOf(%s, %s)", state.GetID(), them), &err)()
1095
1096	role, err := state.GetUserRole(them)
1097	if err != nil {
1098		return false, err
1099	}
1100	switch role {
1101	case keybase1.TeamRole_WRITER, keybase1.TeamRole_ADMIN, keybase1.TeamRole_OWNER:
1102		mctx.Debug("user fits explicit role (%s)", role)
1103		return true, nil
1104	}
1105
1106	if state.GetParentID() == nil {
1107		mctx.Debug("user is not an allowed keyer of the team")
1108		return false, nil
1109	}
1110
1111	// now check implict adminship
1112	yes, err := l.isImplicitAdminOf(mctx.Ctx(), state.GetID(), state.GetParentID(), me, them)
1113	if err != nil {
1114		return false, err
1115	}
1116
1117	if yes {
1118		mctx.Debug("user is an implicit admin of the team")
1119		return true, err
1120	}
1121
1122	mctx.Debug("user is not an allowed keyer of the team")
1123
1124	return false, nil
1125
1126}
1127
1128func (l *TeamLoader) checkNeedRotate(mctx libkb.MetaContext, chain *keybase1.TeamData, me keybase1.UserVersion, hiddenPackage *hidden.LoaderPackage) (ret bool, err error) {
1129	signer := hiddenPackage.LastReaderKeyRotator(mctx)
1130	if signer == nil {
1131		mctx.Debug("not checking need rotate, since last signer of hidden chain was nil")
1132		return false, nil
1133	}
1134	return l.checkNeedRotateWithSigner(mctx, chain, me, *signer)
1135}
1136
1137func (l *TeamLoader) checkNeedRotateWithSigner(mctx libkb.MetaContext, chain *keybase1.TeamData, me keybase1.UserVersion, signer keybase1.Signer) (ret bool, err error) {
1138
1139	defer mctx.Trace(fmt.Sprintf("TeamLoader::checkNeedRotateWithSigner(%+v)", signer), &err)()
1140
1141	uv := signer.UserVersion()
1142
1143	var isKeyer, amIKeyer bool
1144
1145	amIKeyer, err = l.isAllowedKeyerOf(mctx, chain, me, me)
1146	if err != nil {
1147		return false, err
1148	}
1149	if !amIKeyer {
1150		mctx.Debug("I am not a keyer for this team, so I can't rotate it even if required")
1151		return false, nil
1152	}
1153
1154	isKeyer, err = l.isAllowedKeyerOf(mctx, chain, me, uv)
1155	if err != nil {
1156		return false, err
1157	}
1158
1159	if !isKeyer {
1160		mctx.Debug("need rotate since %+v isn't an allowed keyer of the team", uv)
1161		return true, nil
1162	}
1163
1164	var found bool
1165	var revokedAt *keybase1.KeybaseTime
1166
1167	found, revokedAt, _, err = mctx.G().GetUPAKLoader().CheckKIDForUID(mctx.Ctx(), uv.Uid, signer.K)
1168	if err != nil {
1169		return false, err
1170	}
1171
1172	if !found || revokedAt != nil {
1173		var s string
1174		if revokedAt != nil {
1175			tm := revokedAt.Unix.Time()
1176			s = fmt.Sprintf(" (revoked at %s [%s ago])", tm, mctx.G().Clock().Now().Sub(tm))
1177		}
1178		mctx.Debug("KID %s wasn't found for %+v%s", signer, s)
1179		return true, nil
1180	}
1181
1182	return false, nil
1183}
1184
1185func (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) {
1186
1187	var nilPrev libkb.LinkID
1188
1189	ctx := mctx.Ctx()
1190	if suppressLoggingStart <= i && i < suppressLoggingUpto {
1191		if i == suppressLoggingStart {
1192			mctx.Debug("TeamLoader suppressing logs until %v", suppressLoggingUpto)
1193		}
1194		ctx = WithSuppressLogging(ctx, true)
1195		mctx = mctx.WithContext(ctx)
1196	}
1197
1198	if !ShouldSuppressLogging(ctx) {
1199		mctx.Debug("TeamLoader processing link seqno:%v", link.Seqno())
1200	}
1201
1202	if link.Seqno() > lastSeqno {
1203		// This link came from a point in the chain after when we checked the merkle leaf.
1204		// Processing it would require re-checking merkle.
1205		// It would be tricky to ignore it because off-chain data is asserted to be in sync with the chain.
1206		// So, return an error that the caller will retry.
1207		mctx.Debug("TeamLoader found green link seqno:%v", link.Seqno())
1208		return nil, nilPrev, NewGreenLinkError(link.Seqno())
1209	}
1210
1211	if err := l.checkStubbed(ctx, arg, link); err != nil {
1212		return nil, nilPrev, err
1213	}
1214
1215	if !link.Prev().Eq(prev) {
1216		return nil, nilPrev, NewPrevError("team replay failed: prev chain broken at link %d (%v != %v)",
1217			i, link.Prev(), prev)
1218	}
1219
1220	if err := consumeRatchets(mctx, hiddenPackage, link); err != nil {
1221		return nil, nilPrev, err
1222	}
1223
1224	if err := checkPTKGenerationNotOnHiddenChain(mctx, hiddenPackage, link); err != nil {
1225		return nil, nilPrev, err
1226	}
1227
1228	var signer *SignerX
1229	var err error
1230	signer, err = l.verifyLink(ctx, arg.teamID, ret, arg.me, link, fullVerifyCutoff,
1231		readSubteamID, proofSet, lkc, *parentsCache)
1232	if err != nil {
1233		return nil, nilPrev, err
1234	}
1235
1236	if l.isParentChildOperation(ctx, link) {
1237		pco, err := l.toParentChildOperation(ctx, link)
1238		if err != nil {
1239			return nil, nilPrev, err
1240		}
1241		*parentChildOperations = append(*parentChildOperations, pco)
1242	}
1243
1244	ret, err = l.applyNewLink(ctx, ret, hiddenPackage.ChainData(), link, signer, arg.me)
1245	if err != nil {
1246		return nil, nilPrev, err
1247	}
1248
1249	return ret, link.LinkID(), nil
1250}
1251
1252// userPreload warms the upak cache with users who will probably need to be loaded to verify the chain.
1253// Uses teamEnv and may be disabled.
1254func (l *TeamLoader) userPreload(ctx context.Context, links []*ChainLinkUnpacked, fullVerifyCutoff keybase1.Seqno) (cancel func()) {
1255	ctx, cancel = context.WithCancel(ctx)
1256	if teamEnv.UserPreloadEnable {
1257		uidSet := make(map[keybase1.UID]struct{})
1258		for _, link := range links {
1259			// fullVerify definition copied from verifyLink
1260			fullVerify := (link.LinkType() != libkb.SigchainV2TypeTeamLeave) ||
1261				(link.Seqno() >= fullVerifyCutoff) ||
1262				(link.source.EldestSeqno == 0)
1263			if !link.isStubbed() && fullVerify {
1264				uidSet[link.inner.Body.Key.UID] = struct{}{}
1265			}
1266		}
1267		l.G().Log.CDebugf(ctx, "TeamLoader userPreload uids: %v", len(uidSet))
1268		if teamEnv.UserPreloadParallel {
1269			// Note this is full-parallel. Probably want pipelining if this is to be turned on by default.
1270			var wg sync.WaitGroup
1271			for uid := range uidSet {
1272				wg.Add(1)
1273				go func(uid keybase1.UID) {
1274					_, _, err := l.G().GetUPAKLoader().LoadV2(
1275						libkb.NewLoadUserArg(l.G()).WithUID(uid).WithPublicKeyOptional().WithNetContext(ctx))
1276					if err != nil {
1277						l.G().Log.CDebugf(ctx, "error preloading uid %v", uid)
1278					}
1279					wg.Done()
1280				}(uid)
1281			}
1282			if teamEnv.UserPreloadWait {
1283				wg.Wait()
1284			}
1285		} else {
1286			for uid := range uidSet {
1287				_, _, err := l.G().GetUPAKLoader().LoadV2(
1288					libkb.NewLoadUserArg(l.G()).WithUID(uid).WithPublicKeyOptional().WithNetContext(ctx))
1289				if err != nil {
1290					l.G().Log.CDebugf(ctx, "error preloading uid %v", uid)
1291				}
1292			}
1293		}
1294	}
1295	return cancel
1296}
1297
1298// Decide whether to repoll merkle based on load arg.
1299// Returns (discardCache, repoll)
1300// discardCache - the caller should throw out their cached copy and repoll.
1301// repoll - hit up merkle for the latest tail
1302// Considers:
1303// - NeedAdmin
1304// - NeedKeyGeneration
1305// - NeedApplicationsAtGenerations
1306// - WantMembers
1307// - ForceRepoll
1308// - Cache freshness / StaleOK
1309// - NeedSeqnos
1310// - JustUpdated
1311// - If this user is in global "force repoll" mode, where it would be too spammy to
1312//   push out individual team changed notifications, so all team loads need a repoll.
1313func (l *TeamLoader) load2DecideRepoll(mctx libkb.MetaContext, arg load2ArgT, fromCache Teamer, cachedPolledAt *keybase1.Time) (discardCache bool, repoll bool) {
1314	var reason string
1315	defer func() {
1316		if discardCache || repoll || reason != "" {
1317			mctx.Debug("load2DecideRepoll -> (discardCache:%v, repoll:%v) %v", discardCache, repoll, reason)
1318		}
1319	}()
1320	// NeedAdmin is a special constraint where we start from scratch.
1321	// Because of admin-only invite links.
1322	if arg.needAdmin {
1323		if !l.satisfiesNeedAdmin(mctx, arg.me, fromCache) {
1324			// Start from scratch if we are newly admin
1325			reason = "!satisfiesNeedAdmin"
1326			return true, true
1327		}
1328	}
1329
1330	if arg.forceRepoll {
1331		reason = "forceRepoll"
1332		return false, true
1333	}
1334
1335	// Repoll if the server has previously hinted that the team has new links.
1336	if fromCache != nil && fromCache.MainChain() != nil && fromCache.MainChain().Chain.LastSeqno < fromCache.MainChain().LatestSeqnoHint {
1337		reason = "behind seqno hint"
1338		return false, true
1339	}
1340
1341	if fromCache != nil && fromCache.HiddenChain() != nil && fromCache.HiddenChain().IsStale() {
1342		reason = "behind hidden seqno hint"
1343		return false, true
1344	}
1345
1346	// Repoll to get a new key generation
1347	if arg.needKeyGeneration > 0 {
1348		if err := l.satisfiesNeedKeyGeneration(mctx, arg.needKeyGeneration, fromCache); err != nil {
1349			reason = fmt.Sprintf("satisfiesNeedKeyGeneration -> %v", err)
1350			return false, true
1351		}
1352	}
1353	// Repoll to get new applications at generations
1354	if len(arg.needApplicationsAtGenerations) > 0 {
1355		if err := l.satisfiesNeedApplicationsAtGenerations(mctx, arg.needApplicationsAtGenerations, fromCache); err != nil {
1356			reason = fmt.Sprintf("satisfiesNeedApplicationsAtGenerations -> %v", err)
1357			return false, true
1358		}
1359	}
1360	if arg.needKBFSKeyGeneration.Generation > 0 {
1361		if err := l.satisfiesNeedsKBFSKeyGeneration(mctx, arg.needKBFSKeyGeneration, fromCache); err != nil {
1362			reason = fmt.Sprintf("satisfiesNeedsKBFSKeyGeneration -> %v", err)
1363			return false, true
1364		}
1365	}
1366
1367	if len(arg.needApplicationsAtGenerationsWithKBFS) > 0 {
1368		if err := l.satisfiesNeedApplicationsAtGenerationsWithKBFS(mctx,
1369			arg.needApplicationsAtGenerationsWithKBFS, fromCache); err != nil {
1370			reason = fmt.Sprintf("satisfiesNeedApplicationsAtGenerationsWithKBFS -> %v", err)
1371			return false, true
1372		}
1373	}
1374
1375	// Repoll because it might help get the wanted members
1376	if len(arg.wantMembers) > 0 {
1377		if err := l.satisfiesWantMembers(mctx, arg.wantMembers, arg.wantMembersRole, fromCache); err != nil {
1378			reason = fmt.Sprintf("satisfiesWantMembers -> %v", err)
1379			return false, true
1380		}
1381	}
1382
1383	// Repoll if we need a seqno not in the cache.
1384	// Does not force a repoll if we just need to fill in previous links
1385	if len(arg.needSeqnos) > 0 {
1386		if fromCache == nil || fromCache.MainChain() == nil {
1387			reason = "need seqnos and no cache"
1388			return false, true
1389		}
1390		if fromCache.MainChain().Chain.LastSeqno < l.seqnosMax(arg.needSeqnos) {
1391			reason = "need seqnos"
1392			return false, true
1393		}
1394	}
1395
1396	if fromCache == nil || fromCache.MainChain() == nil {
1397		reason = "no cache"
1398		// We need a merkle leaf when starting from scratch.
1399		return false, true
1400	}
1401
1402	cachedAt := fromCache.MainChain().CachedAt
1403	if cachedPolledAt != nil && *cachedPolledAt > cachedAt {
1404		cachedAt = *cachedPolledAt
1405	}
1406
1407	cacheIsOld := !l.isFresh(mctx, cachedAt)
1408	if cacheIsOld && !arg.staleOK {
1409		// We need a merkle leaf
1410		reason = "cacheIsOld"
1411		return false, true
1412	}
1413
1414	// InForceRepoll needs to a acquire a lock, so avoid it by checking it last.
1415	if l.InForceRepollMode(mctx) {
1416		reason = "InForceRepollMode"
1417		return false, true
1418	}
1419
1420	return false, false
1421}
1422
1423// Check whether the load produced a snapshot that can be returned to the caller.
1424// This should not check anything that is critical to the validity of the snapshot
1425// because the snapshot is put into the cache before this check.
1426// Considers:
1427// - NeedAdmin
1428// - NeedKeyGeneration
1429// - NeedSeqnos
1430func (l *TeamLoader) load2CheckReturn(mctx libkb.MetaContext, arg load2ArgT, shim Teamer) error {
1431	if arg.needAdmin {
1432		if !l.satisfiesNeedAdmin(mctx, arg.me, shim) {
1433			mctx.Debug("user %v is not an admin of team %v at seqno:%v", arg.me, arg.teamID, shim.MainChain().Chain.LastSeqno)
1434			return fmt.Errorf("user %v is not an admin of the team", arg.me)
1435		}
1436	}
1437
1438	// Repoll to get a new key generation
1439	if arg.needKeyGeneration > 0 {
1440		if err := l.satisfiesNeedKeyGeneration(mctx, arg.needKeyGeneration, shim); err != nil {
1441			return err
1442		}
1443	}
1444	if len(arg.needApplicationsAtGenerations) > 0 {
1445		if err := l.satisfiesNeedApplicationsAtGenerations(mctx, arg.needApplicationsAtGenerations, shim); err != nil {
1446			return err
1447		}
1448	}
1449	if arg.needKBFSKeyGeneration.Generation > 0 {
1450		if err := l.satisfiesNeedsKBFSKeyGeneration(mctx, arg.needKBFSKeyGeneration, shim); err != nil {
1451			return err
1452		}
1453	}
1454	if len(arg.needApplicationsAtGenerationsWithKBFS) > 0 {
1455		if err := l.satisfiesNeedApplicationsAtGenerationsWithKBFS(mctx, arg.needApplicationsAtGenerationsWithKBFS, shim); err != nil {
1456			return err
1457		}
1458	}
1459
1460	if len(arg.needSeqnos) > 0 {
1461		if err := l.checkNeededSeqnos(mctx.Ctx(), shim.MainChain(), arg.needSeqnos); err != nil {
1462			return err
1463		}
1464	}
1465
1466	return nil
1467}
1468
1469// Whether the user is an admin at the snapshot, and there are no stubbed links, and keys are up to date.
1470func (l *TeamLoader) satisfiesNeedAdmin(mctx libkb.MetaContext, me keybase1.UserVersion, team Teamer) bool {
1471	if team == nil || team.MainChain() == nil {
1472		return false
1473	}
1474	state := newTeamSigChainState(team)
1475	if state.HasAnyStubbedLinks() {
1476		return false
1477	}
1478	if !l.hasSyncedSecrets(mctx, team) {
1479		return false
1480	}
1481	role, err := state.GetUserRole(me)
1482	if err != nil {
1483		mctx.Debug("TeamLoader error getting my role: %v", err)
1484		return false
1485	}
1486	if !role.IsAdminOrAbove() {
1487		if !state.IsSubteam() {
1488			return false
1489		}
1490		yes, err := l.isImplicitAdminOf(mctx.Ctx(), state.GetID(), state.GetParentID(), me, me)
1491		if err != nil {
1492			mctx.Debug("TeamLoader error getting checking implicit admin: %s", err)
1493			return false
1494		}
1495		if !yes {
1496			return false
1497		}
1498	}
1499	return true
1500}
1501
1502// Check whether a user is an implicit admin of a team.
1503func (l *TeamLoader) isImplicitAdminOf(ctx context.Context, teamID keybase1.TeamID, ancestorID *keybase1.TeamID,
1504	me keybase1.UserVersion, uv keybase1.UserVersion) (bool, error) {
1505
1506	// IDs of ancestors that were not freshly polled.
1507	// Check them again with forceRepoll if the affirmative is not found cached.
1508	checkAgain := make(map[keybase1.TeamID]bool)
1509
1510	check1 := func(chain *TeamSigChainState) bool {
1511		role, err := chain.GetUserRole(uv)
1512		if err != nil {
1513			return false
1514		}
1515		return role.IsAdminOrAbove()
1516	}
1517
1518	i := 0
1519	for {
1520		i++
1521		if i >= 100 {
1522			// Break in case there's a bug in this loop.
1523			return false, fmt.Errorf("stuck in a loop while checking for implicit admin: %v", ancestorID)
1524		}
1525
1526		// Use load2 so that we can use subteam-reader and get secretless teams.
1527		ancestor, err := l.load2(ctx, load2ArgT{
1528			teamID:        *ancestorID,
1529			reason:        "isImplicitAdminOf-1",
1530			me:            me,
1531			readSubteamID: &teamID,
1532		})
1533		if err != nil {
1534			return false, err
1535		}
1536		// Be wary, `ancestor` could be, and is likely, a secretless team.
1537		// Do not let it out of sight.
1538		ancestorChain := TeamSigChainState{inner: ancestor.team.Chain}
1539
1540		if !ancestor.didRepoll {
1541			checkAgain[ancestorChain.GetID()] = true
1542		}
1543
1544		if check1(&ancestorChain) {
1545			return true, nil
1546		}
1547
1548		if !ancestorChain.IsSubteam() {
1549			break
1550		}
1551		// Get the next level up.
1552		ancestorID = ancestorChain.GetParentID()
1553	}
1554
1555	// The answer was not found to be yes in the cache.
1556	// Try again with the teams that were not polled as they might have unseen updates.
1557	for ancestorID := range checkAgain {
1558		ancestor, err := l.load2(ctx, load2ArgT{
1559			teamID:        ancestorID,
1560			reason:        "isImplicitAdminOf-again",
1561			me:            me,
1562			forceRepoll:   true, // Get the latest info.
1563			readSubteamID: &teamID,
1564		})
1565		if err != nil {
1566			return false, err
1567		}
1568		// Be wary, `ancestor` could be, and is likely, a secretless team.
1569		// Do not let it out of sight.
1570		ancestorChain := TeamSigChainState{inner: ancestor.team.Chain}
1571		if check1(&ancestorChain) {
1572			return true, nil
1573		}
1574	}
1575
1576	return false, nil
1577}
1578
1579func (l *TeamLoader) satisfiesNeedsKBFSKeyGeneration(mctx libkb.MetaContext,
1580	kbfs keybase1.TeamKBFSKeyRefresher, state Teamer) error {
1581	if kbfs.Generation == 0 {
1582		return nil
1583	}
1584	if state == nil {
1585		return fmt.Errorf("nil team does not contain KBFS key generation: %#v", kbfs)
1586	}
1587
1588	gen, err := newTeamSigChainState(state).GetLatestKBFSGeneration(kbfs.AppType)
1589	if err != nil {
1590		return err
1591	}
1592	if kbfs.Generation > gen {
1593		return NewKBFSKeyGenerationError(kbfs.Generation, gen)
1594	}
1595	return nil
1596}
1597
1598// Whether the snapshot has loaded at least up to the key generation and has the secret.
1599func (l *TeamLoader) satisfiesNeedKeyGeneration(mctx libkb.MetaContext, needKeyGeneration keybase1.PerTeamKeyGeneration, state Teamer) error {
1600	if needKeyGeneration == 0 {
1601		return nil
1602	}
1603	if state == nil {
1604		return fmt.Errorf("nil team does not contain key generation: %v", needKeyGeneration)
1605	}
1606	key, err := newTeamSigChainState(state).GetLatestPerTeamKey(mctx)
1607	if err != nil {
1608		return err
1609	}
1610	if needKeyGeneration > key.Gen {
1611		return fmt.Errorf("team key generation too low: %v < %v", key.Gen, needKeyGeneration)
1612	}
1613	_, ok := state.MainChain().PerTeamKeySeedsUnverified[needKeyGeneration]
1614	if !ok {
1615		return fmt.Errorf("team key secret missing for generation: %v", needKeyGeneration)
1616	}
1617	return nil
1618}
1619
1620// Whether the snapshot has loaded the reader key masks and key generations we
1621// need.
1622func (l *TeamLoader) satisfiesNeedApplicationsAtGenerations(mctx libkb.MetaContext,
1623	needApplicationsAtGenerations map[keybase1.PerTeamKeyGeneration][]keybase1.TeamApplication, team Teamer) error {
1624	if len(needApplicationsAtGenerations) == 0 {
1625		return nil
1626	}
1627	if team == nil || team.MainChain() == nil {
1628		return fmt.Errorf("nil team does not contain applications: %v", needApplicationsAtGenerations)
1629	}
1630	for ptkGen, apps := range needApplicationsAtGenerations {
1631		for _, app := range apps {
1632			if _, err := ApplicationKeyAtGeneration(mctx, team, app, ptkGen); err != nil {
1633				return err
1634			}
1635		}
1636	}
1637	return nil
1638}
1639
1640func (l *TeamLoader) satisfiesNeedApplicationsAtGenerationsWithKBFS(mctx libkb.MetaContext,
1641	needApplicationsAtGenerations map[keybase1.PerTeamKeyGeneration][]keybase1.TeamApplication,
1642	state Teamer) error {
1643	if len(needApplicationsAtGenerations) == 0 {
1644		return nil
1645	}
1646	if state == nil || state.MainChain() == nil {
1647		return fmt.Errorf("nil team does not contain applications: %v", needApplicationsAtGenerations)
1648	}
1649	for ptkGen, apps := range needApplicationsAtGenerations {
1650		for _, app := range apps {
1651			if _, err := ApplicationKeyAtGenerationWithKBFS(mctx, state, app, ptkGen); err != nil {
1652				return err
1653			}
1654		}
1655	}
1656	return nil
1657}
1658
1659// Whether the snapshot has each of `wantMembers` as a member.
1660func (l *TeamLoader) satisfiesWantMembers(mctx libkb.MetaContext,
1661	wantMembers []keybase1.UserVersion, wantMembersRole keybase1.TeamRole, state Teamer) error {
1662
1663	if wantMembersRole == keybase1.TeamRole_NONE {
1664		// Default to writer.
1665		wantMembersRole = keybase1.TeamRole_WRITER
1666	}
1667	if len(wantMembers) == 0 {
1668		return nil
1669	}
1670	if state == nil {
1671		return fmt.Errorf("nil team does not have wanted members")
1672	}
1673	for _, uv := range wantMembers {
1674		role, err := newTeamSigChainState(state).GetUserRole(uv)
1675		if err != nil {
1676			return fmt.Errorf("could not get wanted user role: %v", err)
1677		}
1678		if !role.IsOrAbove(wantMembersRole) {
1679			return fmt.Errorf("wanted user %v is a %v which is not at least %v", uv, role, wantMembersRole)
1680		}
1681	}
1682	return nil
1683}
1684
1685func (l *TeamLoader) mungeWantMembers(ctx context.Context, wantMembers []keybase1.UserVersion) (res []keybase1.UserVersion, err error) {
1686	for _, uv1 := range wantMembers {
1687		uv2 := uv1
1688		if uv2.EldestSeqno == 0 {
1689			// Lookup the latest eldest seqno for that uid.
1690			// This value may come from a cache.
1691			uv2.EldestSeqno, err = l.world.lookupEldestSeqno(ctx, uv2.Uid)
1692			if err != nil {
1693				return res, err
1694			}
1695			l.G().Log.CDebugf(ctx, "TeamLoader resolved wantMember %v -> %v", uv2.Uid, uv2.EldestSeqno)
1696		}
1697		res = append(res, uv2)
1698	}
1699	return res, err
1700}
1701
1702// Whether y is in xs.
1703func (l *TeamLoader) seqnosContains(xs []keybase1.Seqno, y keybase1.Seqno) bool {
1704	for _, x := range xs {
1705		if x.Eq(y) {
1706			return true
1707		}
1708	}
1709	return false
1710}
1711
1712// Return the max in a list of positive seqnos. Returns 0 if the list is empty
1713func (l *TeamLoader) seqnosMax(seqnos []keybase1.Seqno) (ret keybase1.Seqno) {
1714	for _, x := range seqnos {
1715		if x > ret {
1716			ret = x
1717		}
1718	}
1719	return ret
1720}
1721
1722// Whether a TeamData from the cache is fresh.
1723func (l *TeamLoader) isFresh(mctx libkb.MetaContext, cachedAt keybase1.Time) bool {
1724	if cachedAt.IsZero() {
1725		// This should never happen.
1726		mctx.Warning("TeamLoader encountered zero cached time")
1727		return false
1728	}
1729	diff := mctx.G().Clock().Now().Sub(cachedAt.Time())
1730	fresh := (diff <= freshnessLimit)
1731	if !fresh {
1732		mctx.Debug("TeamLoader cached snapshot is old: %v", diff)
1733	}
1734	return fresh
1735}
1736
1737// Whether the teams secrets are synced to the same point as its sigchain
1738// Does not check RKMs.
1739func (l *TeamLoader) hasSyncedSecrets(mctx libkb.MetaContext, team Teamer) bool {
1740	state := team.MainChain()
1741	n := len(team.MainChain().Chain.PerTeamKeys)
1742	offChainGen := len(state.PerTeamKeySeedsUnverified)
1743	mctx.Debug("TeamLoader#hasSyncedSecrets: found %d PTKs on the main chain (versus %d seeds)", n, offChainGen)
1744	if team.HiddenChain() != nil {
1745		m := len(team.HiddenChain().ReaderPerTeamKeys)
1746		mctx.Debug("TeamLoader#hasSyncedSecrets: found another %d PTKs on the hidden chain", m)
1747		n += m
1748	}
1749	return (n == offChainGen)
1750}
1751
1752func (l *TeamLoader) logIfUnsyncedSecrets(ctx context.Context, state *keybase1.TeamData) {
1753	onChainGen := keybase1.PerTeamKeyGeneration(len(state.Chain.PerTeamKeys))
1754	offChainGen := keybase1.PerTeamKeyGeneration(len(state.PerTeamKeySeedsUnverified))
1755	if onChainGen != offChainGen {
1756		l.G().Log.CDebugf(ctx, "TeamLoader unsynced secrets local:%v != chain:%v ", offChainGen, onChainGen)
1757	}
1758}
1759
1760func (l *TeamLoader) lows(mctx libkb.MetaContext, state *keybase1.TeamData, hp *hidden.LoaderPackage, arg load2ArgT) getLinksLows {
1761	var lows getLinksLows
1762	if state != nil {
1763		chain := TeamSigChainState{inner: state.Chain}
1764		lows.Seqno = chain.GetLatestSeqno()
1765		if !arg.foundRKMHole {
1766			lows.PerTeamKey = keybase1.PerTeamKeyGeneration(len(state.PerTeamKeySeedsUnverified))
1767		}
1768	}
1769	if hp != nil {
1770		lows.HiddenChainSeqno = hp.LastFullSeqno()
1771	}
1772	return lows
1773}
1774
1775func (l *TeamLoader) OnLogout(mctx libkb.MetaContext) error {
1776	l.storage.ClearMem()
1777	return nil
1778}
1779
1780func (l *TeamLoader) OnDbNuke(mctx libkb.MetaContext) error {
1781	l.storage.ClearMem()
1782	return nil
1783}
1784
1785// Clear the in-memory cache.
1786func (l *TeamLoader) ClearMem() {
1787	l.storage.ClearMem()
1788}
1789
1790func (l *TeamLoader) VerifyTeamName(ctx context.Context, id keybase1.TeamID, name keybase1.TeamName) error {
1791	if name.IsRootTeam() {
1792		if !name.ToTeamID(id.IsPublic()).Eq(id) {
1793			return NewResolveError(name, id)
1794		}
1795		return nil
1796	}
1797	teamData, _, err := l.Load(ctx, keybase1.LoadTeamArg{
1798		ID:     id,
1799		Public: id.IsPublic(),
1800	})
1801	if err != nil {
1802		return err
1803	}
1804	gotName := teamData.Name
1805	if !gotName.Eq(name) {
1806		return NewResolveError(name, id)
1807	}
1808	return nil
1809}
1810
1811// List all the admins of ancestor teams.
1812// Includes admins of the specified team only if they are also admins of ancestor teams.
1813// The specified team must be a subteam, or an error is returned.
1814// Always sends a flurry of RPCs to get the most up to date info.
1815func (l *TeamLoader) ImplicitAdmins(ctx context.Context, teamID keybase1.TeamID) (impAdmins []keybase1.UserVersion, err error) {
1816	impAdminsMap := make(map[string]keybase1.UserVersion) // map to remove dups
1817	err = l.MapTeamAncestors(ctx, func(t keybase1.TeamSigChainState, _ keybase1.TeamName) error {
1818		ancestorChain := TeamSigChainState{inner: t}
1819		// Gather the admins.
1820		adminRoles := []keybase1.TeamRole{keybase1.TeamRole_OWNER, keybase1.TeamRole_ADMIN}
1821		for _, role := range adminRoles {
1822			uvs, err := ancestorChain.GetUsersWithRole(role)
1823			if err != nil {
1824				return err
1825			}
1826			for _, uv := range uvs {
1827				impAdminsMap[uv.String()] = uv
1828			}
1829		}
1830		return nil
1831	}, teamID, "implicitAdminsAncestor", func(keybase1.TeamSigChainState) bool { return true })
1832	if err != nil {
1833		return nil, err
1834	}
1835	for _, uv := range impAdminsMap {
1836		impAdmins = append(impAdmins, uv)
1837	}
1838	return impAdmins, nil
1839}
1840
1841// MapTeamAncestors does NOT map over the team itself.
1842func (l *TeamLoader) MapTeamAncestors(
1843	ctx context.Context,
1844	f func(keybase1.TeamSigChainState, keybase1.TeamName) error,
1845	teamID keybase1.TeamID,
1846	reason string,
1847	forceFullReloadOnceToAssert func(t keybase1.TeamSigChainState) bool,
1848) (err error) {
1849	initialTeamIdx := 0
1850
1851	me, err := l.world.getMe(ctx)
1852	if err != nil {
1853		return NewMapAncestorsError(err, initialTeamIdx)
1854	}
1855
1856	// Load the argument team
1857	team, _, err := l.load1(ctx, me, keybase1.LoadTeamArg{
1858		ID:      teamID,
1859		Public:  teamID.IsPublic(),
1860		StaleOK: true, // We only use immutable fields.
1861	})
1862	if err != nil {
1863		return NewMapAncestorsError(err, initialTeamIdx)
1864	}
1865	teamChain := TeamSigChainState{inner: team.Chain}
1866	if !teamChain.IsSubteam() {
1867		return NewMapAncestorsError(
1868			fmt.Errorf("cannot map over parents of a root team: %v", teamID),
1869			initialTeamIdx,
1870		)
1871	}
1872	return l.mapTeamAncestorsHelper(ctx, f, teamID, teamChain.GetParentID(), reason, forceFullReloadOnceToAssert)
1873}
1874
1875func (l *TeamLoader) mapTeamAncestorsHelper(
1876	ctx context.Context,
1877	f func(keybase1.TeamSigChainState, keybase1.TeamName) error,
1878	teamID keybase1.TeamID,
1879	ancestorID *keybase1.TeamID,
1880	reason string,
1881	forceFullReloadOnceToAssert func(t keybase1.TeamSigChainState) bool,
1882) (err error) {
1883	i := 0
1884
1885	defer func() {
1886		if err != nil {
1887			err = NewMapAncestorsError(err, i)
1888		}
1889	}()
1890
1891	me, err := l.world.getMe(ctx)
1892	if err != nil {
1893		return err
1894	}
1895
1896	for {
1897		i++
1898		if i >= 100 {
1899			// Break in case there's a bug in this loop.
1900			return fmt.Errorf("stuck in a loop while mapping over team parents: %v", ancestorID)
1901		}
1902
1903		load2Arg := load2ArgT{
1904			teamID:        *ancestorID,
1905			reason:        reason,
1906			me:            me,
1907			forceRepoll:   true, // Get the latest info.
1908			readSubteamID: &teamID,
1909		}
1910
1911		var ancestor *load2ResT
1912		for {
1913			var err error
1914			// Use load2 so that we can use subteam-reader and get secretless teams.
1915			ancestor, err = l.load2(ctx, load2Arg)
1916			if err != nil {
1917				return err
1918			}
1919
1920			if forceFullReloadOnceToAssert == nil ||
1921				forceFullReloadOnceToAssert(ancestor.team.Chain) {
1922				break
1923			}
1924			if load2Arg.forceFullReload {
1925				return fmt.Errorf("failed to assert predicate in ancestor %v after full force reload", ancestor.team.ID())
1926			}
1927			load2Arg.forceFullReload = true
1928		}
1929
1930		// Be wary, `ancestor` could be, and is likely, a secretless team.
1931		// Do not let it out of sight.
1932		ancestorChain := TeamSigChainState{inner: ancestor.team.Chain}
1933
1934		err = f(ancestor.team.Chain, ancestor.team.Name)
1935		if err != nil {
1936			return err
1937		}
1938
1939		if !ancestorChain.IsSubteam() {
1940			break
1941		}
1942		// Get the next level up.
1943		ancestorID = ancestorChain.GetParentID()
1944	}
1945
1946	return nil
1947}
1948
1949func (l *TeamLoader) NotifyTeamRename(ctx context.Context, id keybase1.TeamID, newName string) error {
1950	// ignore newName from the server
1951
1952	// Load up the ancestor chain with ForceRepoll.
1953	// Then load down the ancestor chain without it (expect cache hits).
1954	// Not the most elegant way, but it will get the job done.
1955	// Each load on the way down will recalculate that team's name.
1956
1957	var ancestorIDs []keybase1.TeamID
1958
1959	me, err := l.world.getMe(ctx)
1960	if err != nil {
1961		return err
1962	}
1963
1964	loopID := &id
1965	for loopID != nil {
1966		load2Res, err := l.load2(ctx, load2ArgT{
1967			teamID:        *loopID,
1968			reason:        "NotifyTeamRename-force",
1969			forceRepoll:   true,
1970			readSubteamID: &id,
1971			me:            me,
1972		})
1973		if err != nil {
1974			return err
1975		}
1976		ancestorIDs = append(ancestorIDs, *loopID)
1977		chain := TeamSigChainState{inner: load2Res.team.Chain}
1978		if chain.IsSubteam() {
1979			loopID = chain.GetParentID()
1980		} else {
1981			loopID = nil
1982		}
1983	}
1984
1985	// reverse ancestorIDs so the root team appears first
1986	sort.SliceStable(ancestorIDs, func(i, j int) bool { return i > j })
1987
1988	for _, loopID := range ancestorIDs {
1989		_, err := l.load2(ctx, load2ArgT{
1990			teamID:        loopID,
1991			reason:        "NotifyTeamRename-quick",
1992			readSubteamID: &id,
1993			me:            me,
1994		})
1995		if err != nil {
1996			return err
1997		}
1998	}
1999
2000	return nil
2001}
2002
2003func (l *TeamLoader) getHeadMerkleSeqno(mctx libkb.MetaContext, readSubteamID keybase1.TeamID, state *keybase1.TeamSigChainState) (ret keybase1.Seqno, err error) {
2004	defer mctx.Trace("TeamLoader#getHeadMerkleSeqno", &err)()
2005
2006	if state.HeadMerkle != nil {
2007		return state.HeadMerkle.Seqno, nil
2008	}
2009	headSeqno := keybase1.Seqno(1)
2010	expectedLinkRaw, ok := state.LinkIDs[headSeqno]
2011	if !ok {
2012		return ret, fmt.Errorf("couldn't find head link in team state during audit")
2013	}
2014	expectedLink, err := libkb.ImportLinkID(expectedLinkRaw)
2015	if err != nil {
2016		return ret, err
2017	}
2018	teamUpdate, err := l.world.getLinksFromServer(mctx.Ctx(), state.Id, []keybase1.Seqno{headSeqno}, &readSubteamID)
2019	if err != nil {
2020		return ret, err
2021	}
2022	newLinks, err := teamUpdate.unpackLinks(mctx)
2023	if err != nil {
2024		return ret, err
2025	}
2026	if len(newLinks) != 1 {
2027		return ret, fmt.Errorf("expected only one chainlink back; got %d", len(newLinks))
2028	}
2029	headLink := newLinks[0]
2030	err = headLink.AssertInnerOuterMatch()
2031	if err != nil {
2032		return ret, err
2033	}
2034	if headLink.Seqno() != headSeqno {
2035		return ret, NewInvalidLink(headLink, "wrong head seqno; wanted 1 but got something else")
2036	}
2037	if !headLink.LinkID().Eq(expectedLink) {
2038		return ret, NewInvalidLink(headLink, "wrong head link hash: %s != %s", headLink.LinkID(), expectedLink)
2039	}
2040	if headLink.isStubbed() {
2041		return ret, NewInvalidLink(headLink, "got a stubbed head link, but wasn't expecting that")
2042	}
2043	headMerkle := headLink.inner.Body.MerkleRoot.ToMerkleRootV2()
2044	state.HeadMerkle = &headMerkle
2045	return headMerkle.Seqno, nil
2046}
2047
2048func (l *TeamLoader) audit(ctx context.Context, readSubteamID keybase1.TeamID, state *keybase1.TeamSigChainState, hiddenChain *keybase1.HiddenTeamChain, lastMerkleRoot *libkb.MerkleRoot, auditMode keybase1.AuditMode) (err error) {
2049	mctx := libkb.NewMetaContext(ctx, l.G())
2050
2051	if l.G().Env.Test.TeamSkipAudit {
2052		mctx.Debug("skipping audit in test due to flag")
2053		return nil
2054	}
2055
2056	headMerklSeqno, err := l.getHeadMerkleSeqno(mctx, readSubteamID, state)
2057	if err != nil {
2058		return err
2059	}
2060
2061	err = mctx.G().GetTeamAuditor().AuditTeam(mctx, state.Id, state.Public, headMerklSeqno, state.LinkIDs, hiddenChain.GetOuter(), state.LastSeqno, hiddenChain.GetLastCommittedSeqno(), lastMerkleRoot, auditMode)
2062	return err
2063}
2064
2065func (l *TeamLoader) ForceRepollUntil(ctx context.Context, dtime gregor.TimeOrOffset) error {
2066	l.G().Log.CDebugf(ctx, "TeamLoader#ForceRepollUntil(%+v)", dtime)
2067	l.forceRepollMutex.Lock()
2068	defer l.forceRepollMutex.Unlock()
2069	l.forceRepollUntil = dtime
2070	return nil
2071}
2072
2073func (l *TeamLoader) InForceRepollMode(mctx libkb.MetaContext) bool {
2074	l.forceRepollMutex.Lock()
2075	defer l.forceRepollMutex.Unlock()
2076	if l.forceRepollUntil == nil {
2077		return false
2078	}
2079	if !l.forceRepollUntil.Before(mctx.G().Clock().Now()) {
2080		mctx.Debug("TeamLoader#InForceRepollMode: returning true")
2081		return true
2082	}
2083	l.forceRepollUntil = nil
2084	return false
2085}
2086