github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/teams/teams.go (about)

     1  package teams
     2  
     3  import (
     4  	"crypto/rand"
     5  	"crypto/sha256"
     6  	"encoding/base64"
     7  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	"sort"
    11  	"time"
    12  
    13  	"github.com/keybase/go-codec/codec"
    14  
    15  	"golang.org/x/crypto/nacl/secretbox"
    16  	"golang.org/x/net/context"
    17  
    18  	"github.com/keybase/client/go/libkb"
    19  	"github.com/keybase/client/go/protocol/gregor1"
    20  	"github.com/keybase/client/go/protocol/keybase1"
    21  	"github.com/keybase/client/go/sig3"
    22  	hidden "github.com/keybase/client/go/teams/hidden"
    23  	jsonw "github.com/keybase/go-jsonw"
    24  )
    25  
    26  // Teamer is an interface that can fit a materialized Team (just below) or intermediary temporary products
    27  // that are available during the team load process. It has access to both the main and hidden chain data
    28  // so that we can ask questions like "what is the maximal on-chain PTK generation."
    29  type Teamer interface {
    30  	MainChain() *keybase1.TeamData
    31  	HiddenChain() *keybase1.HiddenTeamChain
    32  }
    33  
    34  // A snapshot of a team's state.
    35  // Not threadsafe.
    36  type Team struct {
    37  	libkb.Contextified
    38  
    39  	ID     keybase1.TeamID
    40  	Data   *keybase1.TeamData
    41  	Hidden *keybase1.HiddenTeamChain
    42  
    43  	keyManager *TeamKeyManager
    44  
    45  	// rotated is set by rotateBoxes after rotating team key.
    46  	rotated bool
    47  }
    48  
    49  // Used to order multiple signatures to post
    50  type teamSectionWithLinkType struct {
    51  	linkType libkb.LinkType
    52  	section  SCTeamSection
    53  }
    54  
    55  func (t *Team) MainChain() *keybase1.TeamData          { return t.Data }
    56  func (t *Team) HiddenChain() *keybase1.HiddenTeamChain { return t.Hidden }
    57  
    58  var _ Teamer = (*Team)(nil)
    59  
    60  func NewTeam(ctx context.Context, g *libkb.GlobalContext, teamData *keybase1.TeamData, hidden *keybase1.HiddenTeamChain) *Team {
    61  	return &Team{
    62  		Contextified: libkb.NewContextified(g),
    63  
    64  		ID:     teamData.ID(),
    65  		Data:   teamData,
    66  		Hidden: hidden,
    67  	}
    68  }
    69  
    70  func (t *Team) CanSkipKeyRotation() bool {
    71  	// Only applies for >=200 member teams.
    72  	const MinTeamSize = 200
    73  	// Aim for one rotation every 24h.
    74  	const KeyRotateInterval = time.Duration(24) * time.Hour
    75  
    76  	if t.IsImplicit() {
    77  		// Do not do this optimization for implicit teams.
    78  		return false
    79  	}
    80  
    81  	if t.IsOpen() {
    82  		// Skip all rotations in open teams.
    83  		return true
    84  	}
    85  
    86  	// If cannot decide because of an error, return default false.
    87  	members, err := t.UsersWithRoleOrAbove(keybase1.TeamRole_BOT)
    88  	if err != nil {
    89  		return false
    90  	}
    91  	if len(members) < MinTeamSize {
    92  		// Not a big team
    93  		return false
    94  	}
    95  
    96  	now := t.G().Clock().Now()
    97  	duration := now.Sub(time.Unix(int64(t.chain().GetLatestPerTeamKeyCTime()), 0))
    98  	if duration > KeyRotateInterval { //nolint
    99  		// Last key rotation was more than predefined interval.
   100  		return false
   101  	}
   102  	// Team is big and key was rotated recently - can skip rotation.
   103  	return true
   104  }
   105  
   106  func (t *Team) calculateAndCacheMemberCount(ctx context.Context) (int, error) {
   107  	m := libkb.NewMetaContext(ctx, t.G())
   108  	members, err := t.Members()
   109  	if err != nil {
   110  		m.Debug("| Failed to get Members() for team %q: %v", t.ID, err)
   111  		return 0, err
   112  	}
   113  
   114  	memberUIDs := make(map[keybase1.UID]bool)
   115  	for _, uv := range members.AllUserVersions() {
   116  		memberUIDs[uv.Uid] = true
   117  	}
   118  
   119  	inviteMDs := t.chain().ActiveInvites()
   120  	for _, inviteMD := range inviteMDs {
   121  		invite := inviteMD.Invite
   122  		invID := invite.Id
   123  		category, err := invite.Type.C()
   124  		if err != nil {
   125  			m.Debug("| Failed parsing invite %q in team %q: %v", invID, t.ID, err)
   126  			return 0, err
   127  		}
   128  
   129  		if category == keybase1.TeamInviteCategory_KEYBASE {
   130  			uv, err := invite.KeybaseUserVersion()
   131  			if err != nil {
   132  				m.Debug("| Failed parsing invite %q in team %q: %v", invID, t.ID, err)
   133  				return 0, err
   134  			}
   135  
   136  			memberUIDs[uv.Uid] = true
   137  		}
   138  
   139  	}
   140  	count := len(memberUIDs) - len(members.Bots) - len(members.RestrictedBots)
   141  	t.G().TeamMemberCountCache.Set(t.ID, count)
   142  	return count, nil
   143  }
   144  
   145  func (t *Team) chain() *TeamSigChainState {
   146  	return &TeamSigChainState{inner: t.Data.Chain, hidden: t.Hidden}
   147  }
   148  
   149  func (t *Team) Name() keybase1.TeamName {
   150  	return t.Data.Name
   151  }
   152  
   153  func (t *Team) Generation() keybase1.PerTeamKeyGeneration {
   154  	return t.chain().GetLatestGeneration()
   155  }
   156  
   157  func (t *Team) IsPublic() bool {
   158  	return t.chain().IsPublic()
   159  }
   160  
   161  func (t *Team) IsImplicit() bool {
   162  	return t.chain().IsImplicit()
   163  }
   164  
   165  func (t *Team) IsSubteam() bool {
   166  	return t.chain().IsSubteam()
   167  }
   168  
   169  func (t *Team) IsOpen() bool {
   170  	return t.chain().IsOpen()
   171  }
   172  
   173  func (t *Team) OpenTeamJoinAs() keybase1.TeamRole {
   174  	return t.chain().inner.OpenTeamJoinAs
   175  }
   176  
   177  func (t *Team) KBFSTLFIDs() []keybase1.TLFID {
   178  	return t.chain().inner.TlfIDs
   179  }
   180  
   181  func (t *Team) LatestKBFSTLFID() (res keybase1.TLFID) {
   182  	ids := t.KBFSTLFIDs()
   183  	if len(ids) > 0 {
   184  		res = ids[len(ids)-1]
   185  	}
   186  	return res
   187  }
   188  
   189  func (t *Team) KBFSCryptKeys(ctx context.Context, appType keybase1.TeamApplication) []keybase1.CryptKey {
   190  	return t.Data.TlfCryptKeys[appType]
   191  }
   192  
   193  func (t *Team) getKeyManager(ctx context.Context) (km *TeamKeyManager, err error) {
   194  	if t.keyManager == nil {
   195  		gen := t.chain().GetLatestGeneration()
   196  		item, err := GetAndVerifyPerTeamKey(t.MetaContext(ctx), t, gen)
   197  		if err != nil {
   198  			return nil, err
   199  		}
   200  		t.keyManager, err = NewTeamKeyManagerWithSeedItem(t.ID, item)
   201  		if err != nil {
   202  			return nil, err
   203  		}
   204  	}
   205  	return t.keyManager, nil
   206  }
   207  
   208  func (t *Team) SharedSecret(ctx context.Context) (ret keybase1.PerTeamKeySeed, err error) {
   209  	defer t.G().CTrace(ctx, "Team#SharedSecret", &err)()
   210  	km, err := t.getKeyManager(ctx)
   211  	if err != nil {
   212  		return ret, err
   213  	}
   214  	return km.SharedSecret(), nil
   215  }
   216  
   217  func (t *Team) KBFSKey(ctx context.Context) (keybase1.TeamApplicationKey, error) {
   218  	return t.ApplicationKey(ctx, keybase1.TeamApplication_KBFS)
   219  }
   220  
   221  func (t *Team) ChatKey(ctx context.Context) (keybase1.TeamApplicationKey, error) {
   222  	return t.ApplicationKey(ctx, keybase1.TeamApplication_CHAT)
   223  }
   224  
   225  func (t *Team) GitMetadataKey(ctx context.Context) (keybase1.TeamApplicationKey, error) {
   226  	return t.ApplicationKey(ctx, keybase1.TeamApplication_GIT_METADATA)
   227  }
   228  
   229  func (t *Team) SeitanInviteTokenKeyLatest(ctx context.Context) (keybase1.TeamApplicationKey, error) {
   230  	return t.ApplicationKey(ctx, keybase1.TeamApplication_SEITAN_INVITE_TOKEN)
   231  }
   232  
   233  func (t *Team) SaltpackEncryptionKeyLatest(ctx context.Context) (keybase1.TeamApplicationKey, error) {
   234  	return t.ApplicationKey(ctx, keybase1.TeamApplication_SALTPACK)
   235  }
   236  
   237  func (t *Team) ChatKeyAtGeneration(ctx context.Context, generation keybase1.PerTeamKeyGeneration) (keybase1.TeamApplicationKey, error) {
   238  	return t.ApplicationKeyAtGeneration(ctx, keybase1.TeamApplication_CHAT, generation)
   239  }
   240  
   241  func (t *Team) SaltpackEncryptionKeyAtGeneration(ctx context.Context, generation keybase1.PerTeamKeyGeneration) (keybase1.TeamApplicationKey, error) {
   242  	return t.ApplicationKeyAtGeneration(ctx, keybase1.TeamApplication_SALTPACK, generation)
   243  }
   244  
   245  func (t *Team) SeitanInviteTokenKeyAtGeneration(ctx context.Context, generation keybase1.PerTeamKeyGeneration) (keybase1.TeamApplicationKey, error) {
   246  	return t.ApplicationKeyAtGeneration(ctx, keybase1.TeamApplication_SEITAN_INVITE_TOKEN, generation)
   247  }
   248  
   249  func (t *Team) SigningKID(ctx context.Context) (kid keybase1.KID, err error) {
   250  	gen := t.chain().GetLatestGeneration()
   251  	chainKey, err := newTeamSigChainState(t).GetPerTeamKeyAtGeneration(gen)
   252  	if err != nil {
   253  		return kid, err
   254  	}
   255  	return chainKey.SigKID, nil
   256  }
   257  
   258  func (t *Team) SigningKey(ctx context.Context) (key libkb.NaclSigningKeyPair, err error) {
   259  	km, err := t.getKeyManager(ctx)
   260  	if err != nil {
   261  		return key, err
   262  	}
   263  	return km.SigningKey()
   264  }
   265  
   266  func (t *Team) EncryptionKey(ctx context.Context) (key libkb.NaclDHKeyPair, err error) {
   267  	km, err := t.getKeyManager(ctx)
   268  	if err != nil {
   269  		return key, err
   270  	}
   271  	return km.EncryptionKey()
   272  }
   273  
   274  func (t *Team) encryptionKeyAtGen(ctx context.Context, gen keybase1.PerTeamKeyGeneration) (key libkb.NaclDHKeyPair, err error) {
   275  	item, err := GetAndVerifyPerTeamKey(libkb.NewMetaContext(ctx, t.G()), t, gen)
   276  	if err != nil {
   277  		return key, err
   278  	}
   279  	keyManager, err := NewTeamKeyManagerWithSeedItem(t.ID, item)
   280  	if err != nil {
   281  		return key, err
   282  	}
   283  	return keyManager.EncryptionKey()
   284  }
   285  
   286  func (t *Team) IsMember(ctx context.Context, uv keybase1.UserVersion) bool {
   287  	role, err := t.MemberRole(ctx, uv)
   288  	if err != nil {
   289  		t.G().Log.CDebugf(ctx, "error getting user role: %s", err)
   290  		return false
   291  	}
   292  	return role != keybase1.TeamRole_NONE
   293  }
   294  
   295  func (t *Team) MemberCtime(ctx context.Context, uv keybase1.UserVersion) *keybase1.Time {
   296  	return t.chain().MemberCtime(uv)
   297  }
   298  
   299  func (t *Team) MemberRole(ctx context.Context, uv keybase1.UserVersion) (keybase1.TeamRole, error) {
   300  	return t.chain().GetUserRole(uv)
   301  }
   302  
   303  func (t *Team) WasMostRecentlyAddedByInvitelink(uv keybase1.UserVersion) bool {
   304  	chain := t.chain().inner
   305  	logPoints, ok := chain.UserLog[uv]
   306  	if !ok {
   307  		return false
   308  	}
   309  	latestLogPointAddedAtIdx := len(logPoints) - 1
   310  	for _, inviteMD := range chain.InviteMetadatas {
   311  		for _, usedInvite := range inviteMD.UsedInvites {
   312  			if usedInvite.Uv == uv {
   313  				invitelinkLogPointAddedAtIdx := usedInvite.LogPoint
   314  				if invitelinkLogPointAddedAtIdx == latestLogPointAddedAtIdx {
   315  					return true
   316  				}
   317  				// don't exit early otherwise, since there might be a newer invite
   318  			}
   319  		}
   320  	}
   321  	return false
   322  }
   323  
   324  func (t *Team) myRole(ctx context.Context) (keybase1.TeamRole, error) {
   325  	uv, err := t.currentUserUV(ctx)
   326  	if err != nil {
   327  		return keybase1.TeamRole_NONE, err
   328  	}
   329  	role, err := t.MemberRole(ctx, uv)
   330  	return role, err
   331  }
   332  
   333  func (t *Team) UserVersionByUID(ctx context.Context, uid keybase1.UID) (keybase1.UserVersion, error) {
   334  	return t.chain().GetLatestUVWithUID(uid)
   335  }
   336  
   337  func (t *Team) AllUserVersionsByUID(ctx context.Context, uid keybase1.UID) []keybase1.UserVersion {
   338  	return t.chain().GetAllUVsWithUID(uid)
   339  }
   340  
   341  func (t *Team) AllUserVersions(ctx context.Context) []keybase1.UserVersion {
   342  	return t.chain().GetAllUVs()
   343  }
   344  
   345  func (t *Team) UsersWithRole(role keybase1.TeamRole) ([]keybase1.UserVersion, error) {
   346  	return t.chain().GetUsersWithRole(role)
   347  }
   348  
   349  func (t *Team) UsersWithRoleOrAbove(role keybase1.TeamRole) ([]keybase1.UserVersion, error) {
   350  	return t.chain().GetUsersWithRoleOrAbove(role)
   351  }
   352  
   353  func (t *Team) UserLastJoinTime(u keybase1.UserVersion) (time keybase1.Time, err error) {
   354  	return t.chain().GetUserLastJoinTime(u)
   355  }
   356  
   357  // UserLastRoleChangeTime returns the time of the last role change for user
   358  // in team. If the user left the team as a last change, the time of such leave
   359  // event is returned. If the user was never in the team, then this function
   360  // returns time=0 and wasMember=false.
   361  func (t *Team) UserLastRoleChangeTime(u keybase1.UserVersion) (time keybase1.Time, wasMember bool) {
   362  	return t.chain().GetUserLastRoleChangeTime(u)
   363  }
   364  
   365  func (t *Team) Settings() keybase1.TeamSettings {
   366  	return keybase1.TeamSettings{
   367  		Open:   t.IsOpen(),
   368  		JoinAs: t.chain().inner.OpenTeamJoinAs,
   369  	}
   370  }
   371  
   372  func (t *Team) Members() (keybase1.TeamMembers, error) {
   373  	var members keybase1.TeamMembers
   374  
   375  	x, err := t.UsersWithRole(keybase1.TeamRole_OWNER)
   376  	if err != nil {
   377  		return keybase1.TeamMembers{}, err
   378  	}
   379  	members.Owners = x
   380  
   381  	x, err = t.UsersWithRole(keybase1.TeamRole_ADMIN)
   382  	if err != nil {
   383  		return keybase1.TeamMembers{}, err
   384  	}
   385  	members.Admins = x
   386  
   387  	x, err = t.UsersWithRole(keybase1.TeamRole_WRITER)
   388  	if err != nil {
   389  		return keybase1.TeamMembers{}, err
   390  	}
   391  	members.Writers = x
   392  
   393  	x, err = t.UsersWithRole(keybase1.TeamRole_READER)
   394  	if err != nil {
   395  		return keybase1.TeamMembers{}, err
   396  	}
   397  	members.Readers = x
   398  
   399  	x, err = t.UsersWithRole(keybase1.TeamRole_BOT)
   400  	if err != nil {
   401  		return keybase1.TeamMembers{}, err
   402  	}
   403  	members.Bots = x
   404  
   405  	x, err = t.UsersWithRole(keybase1.TeamRole_RESTRICTEDBOT)
   406  	if err != nil {
   407  		return keybase1.TeamMembers{}, err
   408  	}
   409  	members.RestrictedBots = x
   410  
   411  	return members, nil
   412  }
   413  
   414  func (t *Team) ImplicitTeamDisplayName(ctx context.Context) (res keybase1.ImplicitTeamDisplayName, err error) {
   415  	return t.implicitTeamDisplayName(ctx, false)
   416  }
   417  
   418  func (t *Team) ImplicitTeamDisplayNameNoConflicts(ctx context.Context) (res keybase1.ImplicitTeamDisplayName, err error) {
   419  	return t.implicitTeamDisplayName(ctx, true)
   420  }
   421  
   422  func (t *Team) implicitTeamDisplayName(ctx context.Context, skipConflicts bool) (res keybase1.ImplicitTeamDisplayName, err error) {
   423  	defer t.G().CTrace(ctx, "Team.ImplicitTeamDisplayName", &err)()
   424  
   425  	impName := keybase1.ImplicitTeamDisplayName{
   426  		IsPublic:     t.IsPublic(),
   427  		ConflictInfo: nil, // TODO should we know this here?
   428  	}
   429  
   430  	seenKBUsers := make(map[string]bool)
   431  	members, err := t.Members()
   432  	if err != nil {
   433  		return res, err
   434  	}
   435  	// Add the keybase owners
   436  	for _, member := range members.Owners {
   437  		name, err := t.G().GetUPAKLoader().LookupUsername(ctx, member.Uid)
   438  		if err != nil {
   439  			return res, err
   440  		}
   441  		impName.Writers.KeybaseUsers = append(impName.Writers.KeybaseUsers, name.String())
   442  	}
   443  	// Add the keybase readers
   444  	for _, member := range members.Readers {
   445  		name, err := t.G().GetUPAKLoader().LookupUsername(ctx, member.Uid)
   446  		if err != nil {
   447  			return res, err
   448  		}
   449  		impName.Readers.KeybaseUsers = append(impName.Readers.KeybaseUsers, name.String())
   450  	}
   451  	// Mark all the usernames we know about
   452  	for _, name := range append(impName.Writers.KeybaseUsers, impName.Readers.KeybaseUsers...) {
   453  		seenKBUsers[name] = true
   454  	}
   455  
   456  	// Add the invites
   457  	isFullyResolved := true
   458  
   459  	inviteMDs := t.chain().ActiveInvites()
   460  	for _, inviteMD := range inviteMDs {
   461  		invite := inviteMD.Invite
   462  		invtyp, err := invite.Type.C()
   463  		if err != nil {
   464  			t.G().Log.CDebugf(ctx, "ImplicitTeamDisplayName: failed to compute type of invite: %s", err.Error())
   465  			continue
   466  		}
   467  		switch invtyp {
   468  		case keybase1.TeamInviteCategory_SBS:
   469  			sa := keybase1.SocialAssertion{
   470  				User:    string(invite.Name),
   471  				Service: keybase1.SocialAssertionService(string(invite.Type.Sbs())),
   472  			}
   473  			switch invite.Role {
   474  			case keybase1.TeamRole_OWNER:
   475  				impName.Writers.UnresolvedUsers = append(impName.Writers.UnresolvedUsers, sa)
   476  			case keybase1.TeamRole_READER:
   477  				impName.Readers.UnresolvedUsers = append(impName.Readers.UnresolvedUsers, sa)
   478  			default:
   479  				return res, fmt.Errorf("implicit team contains invite to role: %v (%v)", invite.Role, invite.Id)
   480  			}
   481  			isFullyResolved = false
   482  		case keybase1.TeamInviteCategory_KEYBASE:
   483  			// Check to make sure we don't already have the user in the name
   484  			uv, err := invite.KeybaseUserVersion()
   485  			if err != nil {
   486  				return res, err
   487  			}
   488  			normalizedUsername, err := t.G().GetUPAKLoader().LookupUsername(ctx, uv.Uid)
   489  			if err != nil {
   490  				return res, err
   491  			}
   492  			username := normalizedUsername.String()
   493  
   494  			if seenKBUsers[username] {
   495  				continue
   496  			}
   497  			seenKBUsers[username] = true
   498  			switch invite.Role {
   499  			case keybase1.TeamRole_OWNER:
   500  				impName.Writers.KeybaseUsers = append(impName.Writers.KeybaseUsers, username)
   501  			case keybase1.TeamRole_READER:
   502  				impName.Readers.KeybaseUsers = append(impName.Readers.KeybaseUsers, username)
   503  			default:
   504  				return res, fmt.Errorf("implicit team contains invite to role: %v (%v)", invite.Role,
   505  					invite.Id)
   506  			}
   507  		case keybase1.TeamInviteCategory_PHONE, keybase1.TeamInviteCategory_EMAIL:
   508  			typ, err := invite.Type.String()
   509  			if err != nil {
   510  				return res, fmt.Errorf("Failed to handle invite type %v: %s", invtyp, err)
   511  			}
   512  			sa := keybase1.SocialAssertion{
   513  				User:    string(invite.Name),
   514  				Service: keybase1.SocialAssertionService(typ),
   515  			}
   516  			switch invite.Role {
   517  			case keybase1.TeamRole_OWNER:
   518  				impName.Writers.UnresolvedUsers = append(impName.Writers.UnresolvedUsers, sa)
   519  			case keybase1.TeamRole_READER:
   520  				impName.Readers.UnresolvedUsers = append(impName.Readers.UnresolvedUsers, sa)
   521  			default:
   522  				return res, fmt.Errorf("implicit team contains invite to role: %v (%v)", invite.Role, invite.Id)
   523  			}
   524  			isFullyResolved = false
   525  		case keybase1.TeamInviteCategory_UNKNOWN:
   526  			return res, fmt.Errorf("unknown invite type in implicit team: %q", invite.Type.Unknown())
   527  		default:
   528  			return res, fmt.Errorf("unrecognized invite type in implicit team: %v", invtyp)
   529  		}
   530  	}
   531  	if !skipConflicts {
   532  		impName, err = GetConflictInfo(ctx, t.G(), t.ID, isFullyResolved, impName)
   533  		if err != nil {
   534  			return res, err
   535  		}
   536  	}
   537  	return impName, nil
   538  }
   539  
   540  func (t *Team) ImplicitTeamDisplayNameString(ctx context.Context) (string, error) {
   541  	impName, err := t.ImplicitTeamDisplayName(ctx)
   542  	if err != nil {
   543  		return "", err
   544  	}
   545  	return FormatImplicitTeamDisplayName(ctx, t.G(), impName)
   546  }
   547  
   548  func (t *Team) NextSeqno() keybase1.Seqno {
   549  	return t.CurrentSeqno() + 1
   550  }
   551  
   552  func (t *Team) CurrentSeqno() keybase1.Seqno {
   553  	return t.chain().GetLatestSeqno()
   554  }
   555  
   556  func (t *Team) AllApplicationKeys(ctx context.Context, application keybase1.TeamApplication) (res []keybase1.TeamApplicationKey, err error) {
   557  	return AllApplicationKeys(t.MetaContext(ctx), t, application, t.chain().GetLatestGeneration())
   558  }
   559  
   560  func (t *Team) AllApplicationKeysWithKBFS(ctx context.Context, application keybase1.TeamApplication) (res []keybase1.TeamApplicationKey, err error) {
   561  	return AllApplicationKeysWithKBFS(t.MetaContext(ctx), t, application,
   562  		t.chain().GetLatestGeneration())
   563  }
   564  
   565  // ApplicationKey returns the most recent key for an application.
   566  func (t *Team) ApplicationKey(ctx context.Context, application keybase1.TeamApplication) (keybase1.TeamApplicationKey, error) {
   567  	latestGen := t.chain().GetLatestGeneration()
   568  	return t.ApplicationKeyAtGeneration(ctx, application, latestGen)
   569  }
   570  
   571  func (t *Team) ApplicationKeyAtGeneration(ctx context.Context,
   572  	application keybase1.TeamApplication, generation keybase1.PerTeamKeyGeneration) (res keybase1.TeamApplicationKey, err error) {
   573  	return ApplicationKeyAtGeneration(t.MetaContext(ctx), t, application, generation)
   574  }
   575  
   576  func (t *Team) ApplicationKeyAtGenerationWithKBFS(ctx context.Context,
   577  	application keybase1.TeamApplication, generation keybase1.PerTeamKeyGeneration) (res keybase1.TeamApplicationKey, err error) {
   578  	return ApplicationKeyAtGenerationWithKBFS(t.MetaContext(ctx), t, application, generation)
   579  }
   580  
   581  func (t *Team) TeamBotSettings() (map[keybase1.UserVersion]keybase1.TeamBotSettings, error) {
   582  	botSettings := t.chain().TeamBotSettings()
   583  	// It's possible that we added a RESTRICTEDBOT member without posting any
   584  	// settings for them. Fill in default values (no access) for those members
   585  	restrictedBots, err := t.UsersWithRole(keybase1.TeamRole_RESTRICTEDBOT)
   586  	if err != nil {
   587  		return nil, err
   588  	}
   589  	for _, uv := range restrictedBots {
   590  		if _, ok := botSettings[uv]; !ok {
   591  			botSettings[uv] = keybase1.TeamBotSettings{}
   592  		}
   593  	}
   594  	return botSettings, nil
   595  }
   596  
   597  func addSummaryHash(section *SCTeamSection, boxes *PerTeamSharedSecretBoxes) error {
   598  	if boxes == nil {
   599  		return nil
   600  	}
   601  	bps := boxes.boxPublicSummary
   602  	if bps == nil || bps.IsEmpty() {
   603  		return nil
   604  	}
   605  	bsh := SCTeamBoxSummaryHash(bps.HashHexEncoded())
   606  	section.BoxSummaryHash = &bsh
   607  	return nil
   608  }
   609  
   610  func (t *Team) Rotate(ctx context.Context, rt keybase1.RotationType) (err error) {
   611  	return t.rotate(ctx, rt)
   612  }
   613  
   614  func (t *Team) rotate(ctx context.Context, rt keybase1.RotationType) (err error) {
   615  	mctx := t.MetaContext(ctx).WithLogTag("ROT")
   616  	defer mctx.Trace(fmt.Sprintf("Team#rotate(%s,%s)", t.ID, rt), &err)()
   617  
   618  	rt, err = hidden.CheckFeatureGateForSupportWithRotationType(mctx, t.ID, rt)
   619  	if err != nil {
   620  		return err
   621  	}
   622  
   623  	// initialize key manager
   624  	if _, err := t.SharedSecret(mctx.Ctx()); err != nil {
   625  		return err
   626  	}
   627  
   628  	mr, err := t.G().MerkleClient.FetchRootFromServer(mctx, libkb.TeamMerkleFreshnessForAdmin)
   629  	if err != nil {
   630  		return err
   631  	}
   632  
   633  	// load an empty member set (no membership changes)
   634  	memSet := newMemberSet()
   635  
   636  	// Try to get the admin perms if they are available, if not, proceed anyway
   637  	var admin *SCTeamAdmin
   638  	admin, err = t.getAdminPermission(mctx.Ctx())
   639  	if err != nil {
   640  		mctx.Debug("Rotate: unable to get admin permission: %v, attempting without admin section", err)
   641  		admin = nil
   642  	}
   643  
   644  	if err := t.ForceMerkleRootUpdate(mctx.Ctx()); err != nil {
   645  		return err
   646  	}
   647  
   648  	section := SCTeamSection{
   649  		ID:       SCTeamID(t.ID),
   650  		Admin:    admin,
   651  		Implicit: t.IsImplicit(),
   652  		Public:   t.IsPublic(),
   653  	}
   654  
   655  	// create the team section of the signature
   656  	section.Members, err = memSet.Section()
   657  	if err != nil {
   658  		return err
   659  	}
   660  
   661  	// rotate the team key for all current members
   662  	secretBoxes, perTeamKeySection, teamEKPayload, err := t.rotateBoxes(mctx.Ctx(), memSet)
   663  	if err != nil {
   664  		return err
   665  	}
   666  	section.PerTeamKey = perTeamKeySection
   667  
   668  	err = addSummaryHash(&section, secretBoxes)
   669  	if err != nil {
   670  		return err
   671  	}
   672  
   673  	// post the change to the server
   674  	payloadArgs := sigPayloadArgs{
   675  		secretBoxes:   secretBoxes,
   676  		teamEKPayload: teamEKPayload,
   677  	}
   678  
   679  	if rt == keybase1.RotationType_VISIBLE {
   680  		err = t.rotatePostVisible(mctx.Ctx(), section, mr, payloadArgs)
   681  	} else {
   682  		err = t.rotatePostHidden(mctx.Ctx(), section, mr, payloadArgs)
   683  	}
   684  	if err != nil {
   685  		return err
   686  	}
   687  
   688  	t.storeTeamEKPayload(mctx.Ctx(), teamEKPayload)
   689  	createTeambotKeys(t.G(), t.ID, memSet.restrictedBotRecipientUids())
   690  
   691  	return nil
   692  }
   693  
   694  func (t *Team) rotatePostVisible(ctx context.Context, section SCTeamSection, mr *libkb.MerkleRoot, payloadArgs sigPayloadArgs) error {
   695  	ratchet, err := t.makeRatchet(ctx)
   696  	if err != nil {
   697  		return err
   698  	}
   699  	section.Ratchets = ratchet.ToTeamSection()
   700  	payloadArgs.ratchetBlindingKeys = ratchet.ToSigPayload()
   701  
   702  	latestSeqno, err := t.postChangeItem(ctx, section, libkb.LinkTypeRotateKey, mr, payloadArgs)
   703  	if err != nil {
   704  		return err
   705  	}
   706  	return t.notify(ctx, keybase1.TeamChangeSet{KeyRotated: true}, latestSeqno)
   707  }
   708  
   709  func (t *Team) rotatePostHidden(ctx context.Context, section SCTeamSection, mr *libkb.MerkleRoot, payloadArgs sigPayloadArgs) error {
   710  	mctx := libkb.NewMetaContext(ctx, t.G())
   711  
   712  	// Generate a "sig multi item" that we POST up to the API endpoint
   713  	smi, ratchet, err := t.rotateHiddenGenerateSigMultiItem(mctx, section, mr)
   714  	if err != nil {
   715  		return err
   716  	}
   717  
   718  	links := []libkb.SigMultiItem{*smi}
   719  
   720  	err = t.precheckLinksToPost(ctx, links)
   721  	if err != nil {
   722  		return err
   723  	}
   724  
   725  	// Combine the "sig multi item" above with the various off-chain items, like boxes.
   726  	payload := t.sigPayload(links, payloadArgs)
   727  
   728  	// Post the changes up to the server
   729  	err = t.postMulti(mctx, payload)
   730  	if err != nil {
   731  		return err
   732  	}
   733  
   734  	// Inform local caching that we've ratcheted forward the hidden chain with a change
   735  	// that we made.
   736  	tmp := mctx.G().GetHiddenTeamChainManager().Ratchet(mctx, t.ID, *ratchet)
   737  	if tmp != nil {
   738  		mctx.Warning("Failed to ratchet forward team chain: %s", tmp.Error())
   739  	}
   740  
   741  	// We rotated the key but didn't change the visibile chain.
   742  	// TODO: We should be able to send a local notification here with
   743  	// new hidden chain seqno.
   744  	return t.notifyNoChainChange(ctx, keybase1.TeamChangeSet{KeyRotated: true})
   745  }
   746  
   747  func teamAdminToSig3ChainLocation(admin *SCTeamAdmin) (*sig3.ChainLocation, error) {
   748  	if admin == nil {
   749  		return nil, nil
   750  	}
   751  	id, err := admin.TeamID.ToTeamID()
   752  	if err != nil {
   753  		return nil, err
   754  	}
   755  	s3id, err := sig3.ImportTeamID(id)
   756  	if err != nil {
   757  		return nil, err
   758  	}
   759  	return &sig3.ChainLocation{
   760  		TeamID:    *s3id,
   761  		Seqno:     admin.Seqno,
   762  		ChainType: admin.SeqType,
   763  	}, nil
   764  
   765  }
   766  
   767  func (t *Team) rotateHiddenGenerateSigMultiItem(mctx libkb.MetaContext, section SCTeamSection, mr *libkb.MerkleRoot) (ret *libkb.SigMultiItem, ratchets *keybase1.HiddenTeamChainRatchetSet, err error) {
   768  
   769  	currentSeqno := t.CurrentSeqno()
   770  	lastLinkID := t.chain().GetLatestLinkID()
   771  
   772  	mainChainPrev := keybase1.LinkTriple{
   773  		Seqno:   currentSeqno,
   774  		SeqType: keybase1.SeqType_SEMIPRIVATE,
   775  		LinkID:  lastLinkID,
   776  	}
   777  
   778  	me, err := loadMeForSignatures(mctx.Ctx(), mctx.G())
   779  	if err != nil {
   780  		return nil, nil, err
   781  	}
   782  	deviceSigningKey, err := t.G().ActiveDevice.SigningKey()
   783  	if err != nil {
   784  		return nil, nil, err
   785  	}
   786  	hiddenPrev, err := t.G().GetHiddenTeamChainManager().Tail(mctx, t.ID)
   787  	if err != nil {
   788  		return nil, nil, err
   789  	}
   790  
   791  	sk, err := t.keyManager.SigningKey()
   792  	if err != nil {
   793  		return nil, nil, err
   794  	}
   795  
   796  	ek, err := t.keyManager.EncryptionKey()
   797  	if err != nil {
   798  		return nil, nil, err
   799  	}
   800  
   801  	admin, err := teamAdminToSig3ChainLocation(section.Admin)
   802  	if err != nil {
   803  		return nil, nil, err
   804  	}
   805  
   806  	ret, ratchets, err = hidden.GenerateKeyRotation(mctx, hidden.GenerateKeyRotationParams{
   807  		TeamID:           t.ID,
   808  		IsPublic:         t.IsPublic(),
   809  		IsImplicit:       t.IsImplicit(),
   810  		MerkleRoot:       mr,
   811  		Me:               me,
   812  		SigningKey:       deviceSigningKey,
   813  		MainPrev:         mainChainPrev,
   814  		HiddenPrev:       hiddenPrev,
   815  		Gen:              t.keyManager.Generation(),
   816  		NewSigningKey:    sk,
   817  		NewEncryptionKey: ek,
   818  		Check:            t.keyManager.Check(),
   819  		Admin:            admin,
   820  	})
   821  
   822  	return ret, ratchets, err
   823  }
   824  
   825  func (t *Team) isAdminOrOwner(m keybase1.UserVersion) (res bool, err error) {
   826  	role, err := t.chain().GetUserRole(m)
   827  	if err != nil {
   828  		return false, err
   829  	}
   830  	if role.IsAdminOrAbove() {
   831  		res = true
   832  	}
   833  	return res, nil
   834  }
   835  
   836  func (t *Team) getDowngradedUsers(ctx context.Context, ms *memberSet) (uids []keybase1.UID, err error) {
   837  
   838  	for _, member := range ms.None {
   839  		// Load member first to check if their eldest_seqno has not changed.
   840  		// If it did, the member was nuked and we do not need to lease.
   841  		_, err := loadMember(ctx, t.G(), member.version, true)
   842  		switch err.(type) {
   843  		case nil:
   844  		case libkb.AccountResetError:
   845  			continue
   846  		default:
   847  			return nil, err
   848  		}
   849  
   850  		uids = append(uids, member.version.Uid)
   851  	}
   852  
   853  	for _, member := range ms.nonAdmins() {
   854  		admin, err := t.isAdminOrOwner(member.version)
   855  		if err != nil {
   856  			return nil, err
   857  		}
   858  		if admin {
   859  			uids = append(uids, member.version.Uid)
   860  		}
   861  	}
   862  
   863  	return uids, nil
   864  }
   865  
   866  type ChangeMembershipOptions struct {
   867  	// Pass "permanent" flag, user will not be able to request access
   868  	// to the team again, admin will have to add them back.
   869  	Permanent bool
   870  
   871  	// Do not rotate team key, even on member removals. Server will
   872  	// queue CLKR if client sends removals without rotation.
   873  	SkipKeyRotation bool
   874  }
   875  
   876  func (t *Team) ChangeMembershipWithOptions(ctx context.Context, req keybase1.TeamChangeReq, opts ChangeMembershipOptions) (err error) {
   877  	defer t.G().CTrace(ctx, "Team.ChangeMembershipWithOptions", &err)()
   878  
   879  	if t.IsSubteam() && len(req.Owners) > 0 {
   880  		return NewSubteamOwnersError()
   881  	}
   882  
   883  	// create the change membership section + secretBoxes
   884  	section, secretBoxes, implicitAdminBoxes, teamEKPayload, memberSet, ratchet, err := t.changeMembershipSection(ctx, req, opts.SkipKeyRotation)
   885  	if err != nil {
   886  		return err
   887  	}
   888  
   889  	if err := t.ForceMerkleRootUpdate(ctx); err != nil {
   890  		return err
   891  	}
   892  
   893  	var merkleRoot *libkb.MerkleRoot
   894  	var lease *libkb.Lease
   895  
   896  	downgrades, err := t.getDowngradedUsers(ctx, memberSet)
   897  	if err != nil {
   898  		return err
   899  	}
   900  
   901  	if len(downgrades) != 0 {
   902  		lease, merkleRoot, err = libkb.RequestDowngradeLeaseByTeam(ctx, t.G(), t.ID, downgrades)
   903  		if err != nil {
   904  			return err
   905  		}
   906  		defer func() {
   907  			// We must cancel in the case of an error in postMulti, but it's safe to cancel
   908  			// if everything worked. So we always cancel the lease on the way out of this function.
   909  			// See CORE-6473 for a case in which this was needed. And also the test
   910  			// `TestOnlyOwnerLeaveThenUpgradeFriend`.
   911  			err := libkb.CancelDowngradeLease(ctx, t.G(), lease.LeaseID)
   912  			if err != nil {
   913  				t.G().Log.CWarningf(ctx, "Failed to cancel downgrade lease: %s", err.Error())
   914  			}
   915  		}()
   916  	}
   917  	// post the change to the server
   918  	sigPayloadArgs := sigPayloadArgs{
   919  		secretBoxes:         secretBoxes,
   920  		implicitAdminBoxes:  implicitAdminBoxes,
   921  		lease:               lease,
   922  		teamEKPayload:       teamEKPayload,
   923  		ratchetBlindingKeys: ratchet.ToSigPayload(),
   924  	}
   925  
   926  	if opts.Permanent {
   927  		sigPayloadArgs.prePayload = libkb.JSONPayload{"permanent": true}
   928  	}
   929  
   930  	// Add a ChangeMembership section and possibly a BotSettings section.
   931  	sections := []teamSectionWithLinkType{
   932  		{
   933  			linkType: libkb.LinkTypeChangeMembership,
   934  			section:  section,
   935  		},
   936  	}
   937  
   938  	// If we are adding any restricted bots add a bot_settings link
   939  	if len(req.RestrictedBots) > 0 {
   940  		section, _, err := t.botSettingsSection(ctx, req.RestrictedBots, ratchet, merkleRoot)
   941  		if err != nil {
   942  			return err
   943  		}
   944  		sections = append(sections, teamSectionWithLinkType{
   945  			linkType: libkb.LinkTypeTeamBotSettings,
   946  			section:  section,
   947  		})
   948  	}
   949  
   950  	payload, latestSeqno, err := t.changeItemsPayload(ctx, sections, merkleRoot, sigPayloadArgs)
   951  	if err != nil {
   952  		return err
   953  	}
   954  
   955  	var recipients, botRecipients []keybase1.UserVersion
   956  	for uv := range memberSet.recipients {
   957  		recipients = append(recipients, uv)
   958  	}
   959  	for uv := range memberSet.restrictedBotRecipients {
   960  		botRecipients = append(botRecipients, uv)
   961  	}
   962  	newMemSet := newMemberSet()
   963  	_, err = newMemSet.loadGroup(ctx, t.G(), recipients, storeMemberKindRecipient, true)
   964  	if err != nil {
   965  		return err
   966  	}
   967  	_, err = newMemSet.loadGroup(ctx, t.G(), botRecipients, storeMemberKindRestrictedBotRecipient, true)
   968  	if err != nil {
   969  		return err
   970  	}
   971  	if !memberSet.recipients.Eq(newMemSet.recipients) {
   972  		return BoxRaceError{inner: fmt.Errorf("team box summary changed during sig creation; retry required")}
   973  	}
   974  
   975  	err = t.postMulti(libkb.NewMetaContext(ctx, t.G()), payload)
   976  	if err != nil {
   977  		return err
   978  	}
   979  
   980  	err = t.notify(ctx, keybase1.TeamChangeSet{MembershipChanged: true}, latestSeqno)
   981  	if err != nil {
   982  		return err
   983  	}
   984  	t.storeTeamEKPayload(ctx, teamEKPayload)
   985  	createTeambotKeys(t.G(), t.ID, memberSet.restrictedBotRecipientUids())
   986  
   987  	return nil
   988  }
   989  
   990  func (t *Team) ChangeMembership(ctx context.Context, req keybase1.TeamChangeReq) error {
   991  	return t.ChangeMembershipWithOptions(ctx, req, ChangeMembershipOptions{})
   992  }
   993  
   994  func (t *Team) downgradeIfOwnerOrAdmin(ctx context.Context) (needsReload bool, err error) {
   995  	defer t.G().CTrace(ctx, "Team#downgradeIfOwnerOrAdmin", &err)()
   996  
   997  	uv, err := t.currentUserUV(ctx)
   998  	if err != nil {
   999  		return false, err
  1000  	}
  1001  
  1002  	role, err := t.MemberRole(ctx, uv)
  1003  	if err != nil {
  1004  		return false, err
  1005  	}
  1006  
  1007  	if role.IsAdminOrAbove() {
  1008  		reqs := keybase1.TeamChangeReq{Writers: []keybase1.UserVersion{uv}}
  1009  		if err := t.ChangeMembership(ctx, reqs); err != nil {
  1010  			return false, err
  1011  		}
  1012  
  1013  		return true, nil
  1014  	}
  1015  
  1016  	return false, nil
  1017  }
  1018  
  1019  func (t *Team) makeRatchet(ctx context.Context) (ret *hidden.Ratchet, err error) {
  1020  	return t.chain().makeHiddenRatchet(libkb.NewMetaContext(ctx, t.G()))
  1021  }
  1022  
  1023  func (t *Team) Leave(ctx context.Context, permanent bool) error {
  1024  	// If we are owner or admin, we have to downgrade ourselves first.
  1025  	needsReload, err := t.downgradeIfOwnerOrAdmin(ctx)
  1026  	if err != nil {
  1027  		return err
  1028  	}
  1029  	if needsReload {
  1030  		t, err = Load(ctx, t.G(), keybase1.LoadTeamArg{
  1031  			ID:          t.ID,
  1032  			Public:      t.IsPublic(),
  1033  			ForceRepoll: true,
  1034  		})
  1035  		if err != nil {
  1036  			return err
  1037  		}
  1038  	}
  1039  
  1040  	// Check if we are an implicit admin with no explicit membership
  1041  	// in order to give a nice error.
  1042  	role, err := t.myRole(ctx)
  1043  	if err != nil {
  1044  		role = keybase1.TeamRole_NONE
  1045  	}
  1046  	if role == keybase1.TeamRole_NONE {
  1047  		_, err := t.getAdminPermission(ctx)
  1048  		switch err.(type) {
  1049  		case nil, *AdminPermissionRequiredError:
  1050  			return NewImplicitAdminCannotLeaveError()
  1051  		}
  1052  	}
  1053  
  1054  	ratchet, err := t.makeRatchet(ctx)
  1055  	if err != nil {
  1056  		return err
  1057  	}
  1058  
  1059  	section := SCTeamSection{
  1060  		ID:       SCTeamID(t.ID),
  1061  		Implicit: t.IsImplicit(),
  1062  		Public:   t.IsPublic(),
  1063  		Ratchets: ratchet.ToTeamSection(),
  1064  	}
  1065  
  1066  	sigPayloadArgs := sigPayloadArgs{
  1067  		prePayload:          libkb.JSONPayload{"permanent": permanent},
  1068  		ratchetBlindingKeys: ratchet.ToSigPayload(),
  1069  	}
  1070  	latestSeqno, err := t.postChangeItem(ctx, section, libkb.LinkTypeLeave, nil, sigPayloadArgs)
  1071  	if err != nil {
  1072  		return err
  1073  	}
  1074  
  1075  	return t.notify(ctx, keybase1.TeamChangeSet{MembershipChanged: true}, latestSeqno)
  1076  }
  1077  
  1078  func (t *Team) deleteRoot(ctx context.Context) error {
  1079  	m := t.MetaContext(ctx)
  1080  	uv, err := t.currentUserUV(ctx)
  1081  	if err != nil {
  1082  		return err
  1083  	}
  1084  
  1085  	role, err := t.MemberRole(ctx, uv)
  1086  	if err != nil {
  1087  		return err
  1088  	}
  1089  
  1090  	if role != keybase1.TeamRole_OWNER {
  1091  		return libkb.AppStatusError{
  1092  			Code: int(keybase1.StatusCode_SCTeamSelfNotOwner),
  1093  			Name: "SELF_NOT_OWNER",
  1094  			Desc: "You must be an owner to delete a team",
  1095  		}
  1096  	}
  1097  
  1098  	ratchet, err := t.makeRatchet(ctx)
  1099  	if err != nil {
  1100  		return err
  1101  	}
  1102  
  1103  	teamSection := SCTeamSection{
  1104  		ID:       SCTeamID(t.ID),
  1105  		Implicit: t.IsImplicit(),
  1106  		Public:   t.IsPublic(),
  1107  		Ratchets: ratchet.ToTeamSection(),
  1108  	}
  1109  
  1110  	mr, err := t.G().MerkleClient.FetchRootFromServer(t.MetaContext(ctx), libkb.TeamMerkleFreshnessForAdmin)
  1111  	if err != nil {
  1112  		return err
  1113  	}
  1114  	if mr == nil {
  1115  		return errors.New("No merkle root available for team delete root")
  1116  	}
  1117  
  1118  	sigMultiItem, latestSeqno, err := t.sigTeamItem(ctx, teamSection, libkb.LinkTypeDeleteRoot, mr)
  1119  	if err != nil {
  1120  		return err
  1121  	}
  1122  
  1123  	sigPayloadArgs := sigPayloadArgs{
  1124  		ratchetBlindingKeys: ratchet.ToSigPayload(),
  1125  	}
  1126  	payload := t.sigPayload([]libkb.SigMultiItem{sigMultiItem}, sigPayloadArgs)
  1127  	err = t.postMulti(m, payload)
  1128  	if err != nil {
  1129  		return err
  1130  	}
  1131  	return t.HintLatestSeqno(m, latestSeqno)
  1132  }
  1133  
  1134  func (t *Team) deleteSubteam(ctx context.Context) error {
  1135  	m := t.MetaContext(ctx)
  1136  
  1137  	// subteam delete consists of two links:
  1138  	// 1. delete_subteam in parent chain
  1139  	// 2. delete_up_pointer in subteam chain
  1140  
  1141  	if t.IsImplicit() {
  1142  		return fmt.Errorf("unsupported delete of implicit subteam")
  1143  	}
  1144  
  1145  	parentID := t.chain().GetParentID()
  1146  	parentTeam, err := Load(ctx, t.G(), keybase1.LoadTeamArg{
  1147  		ID:          *parentID,
  1148  		Public:      t.IsPublic(),
  1149  		ForceRepoll: true,
  1150  	})
  1151  	switch {
  1152  	case err == nil:
  1153  	case IsTeamReadError(err):
  1154  		return fmt.Errorf("failed to load parent team; you must be an admin of a parent team to delete a subteam: %w", err)
  1155  	default:
  1156  		return fmt.Errorf("failed to load parent team: %w", err)
  1157  	}
  1158  
  1159  	admin, err := parentTeam.getAdminPermission(ctx)
  1160  	switch err.(type) {
  1161  	case nil:
  1162  	case *AdminPermissionRequiredError:
  1163  		return fmt.Errorf("failed to get admin permission from parent team; you must be an admin of a parent team to delete a subteam: %w", err)
  1164  	default:
  1165  		return fmt.Errorf("failed to get admin permission from parent team: %w", err)
  1166  	}
  1167  
  1168  	subteamName := SCTeamName(t.Data.Name.String())
  1169  
  1170  	entropy, err := makeSCTeamEntropy()
  1171  	if err != nil {
  1172  		return err
  1173  	}
  1174  	parentRatchet, err := parentTeam.makeRatchet(ctx)
  1175  	if err != nil {
  1176  		return err
  1177  	}
  1178  	parentSection := SCTeamSection{
  1179  		ID: SCTeamID(parentTeam.ID),
  1180  		Subteam: &SCSubteam{
  1181  			ID:   SCTeamID(t.ID),
  1182  			Name: subteamName, // weird this is required
  1183  		},
  1184  		Admin:    admin,
  1185  		Public:   t.IsPublic(),
  1186  		Entropy:  entropy,
  1187  		Ratchets: parentRatchet.ToTeamSection(),
  1188  	}
  1189  
  1190  	mr, err := t.G().MerkleClient.FetchRootFromServer(t.MetaContext(ctx), libkb.TeamMerkleFreshnessForAdmin)
  1191  	if err != nil {
  1192  		return err
  1193  	}
  1194  	if mr == nil {
  1195  		return errors.New("No merkle root available for team delete subteam")
  1196  	}
  1197  
  1198  	sigParent, _, err := parentTeam.sigTeamItem(ctx, parentSection, libkb.LinkTypeDeleteSubteam, mr)
  1199  	if err != nil {
  1200  		return err
  1201  	}
  1202  
  1203  	subRatchet, err := t.makeRatchet(ctx)
  1204  	if err != nil {
  1205  		return err
  1206  	}
  1207  	subSection := SCTeamSection{
  1208  		ID:   SCTeamID(t.ID),
  1209  		Name: &subteamName, // weird this is required
  1210  		Parent: &SCTeamParent{
  1211  			ID:      SCTeamID(parentTeam.ID),
  1212  			Seqno:   parentTeam.chain().GetLatestSeqno() + 1, // the seqno of the *new* parent link
  1213  			SeqType: seqTypeForTeamPublicness(parentTeam.IsPublic()),
  1214  		},
  1215  		Public:   t.IsPublic(),
  1216  		Admin:    admin,
  1217  		Ratchets: subRatchet.ToTeamSection(),
  1218  	}
  1219  	sigSub, latestSeqno, err := t.sigTeamItem(ctx, subSection, libkb.LinkTypeDeleteUpPointer, mr)
  1220  	if err != nil {
  1221  		return err
  1222  	}
  1223  
  1224  	payload := make(libkb.JSONPayload)
  1225  	payload["sigs"] = []interface{}{sigParent, sigSub}
  1226  
  1227  	var ratchetSet hidden.RatchetBlindingKeySet
  1228  	if parentRatchet != nil {
  1229  		ratchetSet.Add(*parentRatchet)
  1230  	}
  1231  	if subRatchet != nil {
  1232  		ratchetSet.Add(*subRatchet)
  1233  	}
  1234  	err = ratchetSet.AddToJSONPayload(payload)
  1235  	if err != nil {
  1236  		return err
  1237  	}
  1238  
  1239  	err = t.postMulti(m, payload)
  1240  	if err != nil {
  1241  		return err
  1242  	}
  1243  	return t.HintLatestSeqno(m, latestSeqno)
  1244  }
  1245  
  1246  func (t *Team) NumActiveInvites() int {
  1247  	return t.chain().NumActiveInvites()
  1248  }
  1249  
  1250  func (t *Team) HasActiveInvite(mctx libkb.MetaContext, name keybase1.TeamInviteName, typ string) (bool, error) {
  1251  	it, err := TeamInviteTypeFromString(mctx, typ)
  1252  	if err != nil {
  1253  		return false, err
  1254  	}
  1255  	return t.chain().HasActiveInvite(name, it)
  1256  }
  1257  
  1258  func (t *Team) FindActiveKeybaseInvite(uid keybase1.UID) (keybase1.TeamInvite, keybase1.UserVersion, bool) {
  1259  	return t.chain().FindActiveKeybaseInvite(uid)
  1260  }
  1261  
  1262  func (t *Team) GetActiveAndObsoleteInvites() (ret map[keybase1.TeamInviteID]keybase1.TeamInvite) {
  1263  	ret = make(map[keybase1.TeamInviteID]keybase1.TeamInvite)
  1264  	for inviteID, inviteMD := range t.chain().inner.InviteMetadatas {
  1265  		code, err := inviteMD.Status.Code()
  1266  		if err != nil {
  1267  			continue
  1268  		}
  1269  		switch code {
  1270  		case keybase1.TeamInviteMetadataStatusCode_ACTIVE, keybase1.TeamInviteMetadataStatusCode_OBSOLETE:
  1271  			ret[inviteID] = inviteMD.Invite
  1272  		}
  1273  	}
  1274  	return ret
  1275  }
  1276  
  1277  // If uv.Uid is set, then username is ignored.
  1278  // Otherwise resolvedUsername and uv are ignored.
  1279  func (t *Team) InviteMember(ctx context.Context, username string, role keybase1.TeamRole, resolvedUsername libkb.NormalizedUsername, uv keybase1.UserVersion) (keybase1.TeamAddMemberResult, error) {
  1280  	// if a user version was previously loaded, then there is a keybase user for username, but
  1281  	// without a PUK or without any keys.
  1282  	if uv.Uid.Exists() {
  1283  		return t.inviteKeybaseMember(libkb.NewMetaContext(ctx, t.G()), uv, role, resolvedUsername)
  1284  	}
  1285  
  1286  	// If a social, or email, or other type of invite, assert it's not an owner.
  1287  	if role.IsOrAbove(keybase1.TeamRole_OWNER) {
  1288  		return keybase1.TeamAddMemberResult{}, errors.New("You cannot invite an owner to a team.")
  1289  	}
  1290  
  1291  	return t.inviteSBSMember(ctx, username, role)
  1292  }
  1293  
  1294  func (t *Team) InviteEmailPhoneMember(ctx context.Context, name string, role keybase1.TeamRole, typ string) error {
  1295  	t.G().Log.CDebugf(ctx, "team %s invite %s member %s", t.Name(), typ, name)
  1296  
  1297  	if role == keybase1.TeamRole_OWNER {
  1298  		return errors.New("You cannot invite an owner to a team over email.")
  1299  	}
  1300  
  1301  	invite := SCTeamInvite{
  1302  		Type: typ,
  1303  		Name: keybase1.TeamInviteName(name),
  1304  		ID:   NewInviteID(),
  1305  	}
  1306  	return t.postInvite(ctx, invite, role)
  1307  }
  1308  
  1309  func (t *Team) inviteKeybaseMember(mctx libkb.MetaContext, uv keybase1.UserVersion, role keybase1.TeamRole, resolvedUsername libkb.NormalizedUsername) (res keybase1.TeamAddMemberResult, err error) {
  1310  	mctx.Debug("team %s invite keybase member %s", t.Name(), uv)
  1311  
  1312  	invite := SCTeamInvite{
  1313  		Type: "keybase",
  1314  		Name: uv.TeamInviteName(),
  1315  		ID:   NewInviteID(),
  1316  	}
  1317  
  1318  	existing, err := t.HasActiveInvite(mctx, invite.Name, invite.Type)
  1319  	if err != nil {
  1320  		return res, err
  1321  	}
  1322  
  1323  	if existing {
  1324  		return res, libkb.ExistsError{Msg: "An invite for this user already exists."}
  1325  	}
  1326  
  1327  	if t.IsSubteam() && role == keybase1.TeamRole_OWNER {
  1328  		return res, NewSubteamOwnersError()
  1329  	}
  1330  
  1331  	invList := []SCTeamInvite{invite}
  1332  	cancelList := []SCTeamInviteID{}
  1333  
  1334  	var invites SCTeamInvites
  1335  	switch role {
  1336  	case keybase1.TeamRole_ADMIN:
  1337  		invites.Admins = &invList
  1338  	case keybase1.TeamRole_WRITER:
  1339  		invites.Writers = &invList
  1340  	case keybase1.TeamRole_READER:
  1341  		invites.Readers = &invList
  1342  	case keybase1.TeamRole_OWNER:
  1343  		invites.Owners = &invList
  1344  	}
  1345  
  1346  	// Inviting keybase PUKless member has to remove old invites for that
  1347  	// uid first, or it will bounce off the server with an error. There is
  1348  	// no hard limit in team player to disallow multiple keybase invites
  1349  	// for the same UID, but there is a soft serverside check when
  1350  	// signature is posted.
  1351  	for inviteID, existingInvite := range t.GetActiveAndObsoleteInvites() {
  1352  		// KeybaseUserVersion checks if invite is KEYBASE and errors
  1353  		// if not, we can blindly call it for all invites, and continue
  1354  		// to next one if we get an error.
  1355  		existingUV, err := existingInvite.KeybaseUserVersion()
  1356  		if err != nil {
  1357  			continue
  1358  		}
  1359  
  1360  		if existingUV.Uid != uv.Uid {
  1361  			continue
  1362  		}
  1363  
  1364  		if uv.EldestSeqno != 0 && existingUV.EldestSeqno > uv.EldestSeqno {
  1365  			// We probably know invitee by their outdated EldestSeqno. There
  1366  			// is also a server check for this case.
  1367  			return res, libkb.ExistsError{
  1368  				Msg: fmt.Sprintf("An invite for this user already exists, with higher EldestSeqno (%d > %d)", existingUV.EldestSeqno, uv.EldestSeqno),
  1369  			}
  1370  		}
  1371  
  1372  		mctx.Debug("Canceling old Keybase invite: %+v", existingInvite)
  1373  		cancelList = append(cancelList, SCTeamInviteID(inviteID))
  1374  	}
  1375  
  1376  	if len(cancelList) != 0 {
  1377  		mctx.Debug("Total %d old invites will be canceled.", len(cancelList))
  1378  		invites.Cancel = &cancelList
  1379  	}
  1380  
  1381  	mctx.Debug("Adding invite: %+v", invite)
  1382  	if err := t.postTeamInvites(mctx.Ctx(), invites); err != nil {
  1383  		return res, err
  1384  	}
  1385  	return keybase1.TeamAddMemberResult{Invited: true, User: &keybase1.User{Uid: uv.Uid, Username: resolvedUsername.String()}}, nil
  1386  }
  1387  
  1388  func (t *Team) inviteSBSMember(ctx context.Context, username string, role keybase1.TeamRole) (keybase1.TeamAddMemberResult, error) {
  1389  	// parse username to get social
  1390  	typ, name, err := parseSocialAssertion(libkb.NewMetaContext(ctx, t.G()), username)
  1391  	if err != nil {
  1392  		return keybase1.TeamAddMemberResult{}, err
  1393  	}
  1394  	t.G().Log.CDebugf(ctx, "team %s invite sbs member %s/%s", t.Name(), typ, name)
  1395  
  1396  	invite := SCTeamInvite{
  1397  		Type: typ,
  1398  		Name: keybase1.TeamInviteName(name),
  1399  		ID:   NewInviteID(),
  1400  	}
  1401  
  1402  	if err := t.postInvite(ctx, invite, role); err != nil {
  1403  		return keybase1.TeamAddMemberResult{}, err
  1404  	}
  1405  
  1406  	return keybase1.TeamAddMemberResult{Invited: true}, nil
  1407  }
  1408  
  1409  func (t *Team) InviteSeitan(ctx context.Context, role keybase1.TeamRole, label keybase1.SeitanKeyLabel) (ikey SeitanIKey, err error) {
  1410  	defer t.G().CTrace(ctx, fmt.Sprintf("InviteSeitan: team: %v, role: %v", t.Name(), role), &err)()
  1411  
  1412  	ikey, err = GenerateIKey()
  1413  	if err != nil {
  1414  		return ikey, err
  1415  	}
  1416  
  1417  	sikey, err := ikey.GenerateSIKey()
  1418  	if err != nil {
  1419  		return ikey, err
  1420  	}
  1421  
  1422  	inviteID, err := sikey.GenerateTeamInviteID()
  1423  	if err != nil {
  1424  		return ikey, err
  1425  	}
  1426  
  1427  	_, encoded, err := ikey.GeneratePackedEncryptedKey(ctx, t, label)
  1428  	if err != nil {
  1429  		return ikey, err
  1430  	}
  1431  
  1432  	invite := SCTeamInvite{
  1433  		Type: "seitan_invite_token",
  1434  		Name: keybase1.TeamInviteName(encoded),
  1435  		ID:   inviteID,
  1436  	}
  1437  
  1438  	if err := t.postInvite(ctx, invite, role); err != nil {
  1439  		return ikey, err
  1440  	}
  1441  
  1442  	return ikey, err
  1443  }
  1444  
  1445  func (t *Team) InviteSeitanV2(ctx context.Context, role keybase1.TeamRole, label keybase1.SeitanKeyLabel) (ikey SeitanIKeyV2, err error) {
  1446  	defer t.G().CTrace(ctx, fmt.Sprintf("InviteSeitanV2: team: %v, role: %v", t.Name(), role), &err)()
  1447  
  1448  	ikey, err = GenerateIKeyV2()
  1449  	if err != nil {
  1450  		return ikey, err
  1451  	}
  1452  
  1453  	sikey, err := ikey.GenerateSIKey()
  1454  	if err != nil {
  1455  		return ikey, err
  1456  	}
  1457  
  1458  	inviteID, err := sikey.GenerateTeamInviteID()
  1459  	if err != nil {
  1460  		return ikey, err
  1461  	}
  1462  
  1463  	_, encoded, err := sikey.GeneratePackedEncryptedKey(ctx, t, label)
  1464  	if err != nil {
  1465  		return ikey, err
  1466  	}
  1467  
  1468  	invite := SCTeamInvite{
  1469  		Type: "seitan_invite_token",
  1470  		Name: keybase1.TeamInviteName(encoded),
  1471  		ID:   inviteID,
  1472  	}
  1473  
  1474  	if err := t.postInvite(ctx, invite, role); err != nil {
  1475  		return ikey, err
  1476  	}
  1477  
  1478  	return ikey, err
  1479  }
  1480  
  1481  func (t *Team) InviteInvitelink(
  1482  	ctx context.Context,
  1483  	role keybase1.TeamRole,
  1484  	maxUses keybase1.TeamInviteMaxUses,
  1485  	etime *keybase1.UnixTime,
  1486  ) (ikey keybase1.SeitanIKeyInvitelink, inviteID SCTeamInviteID, err error) {
  1487  	defer t.G().CTrace(ctx, fmt.Sprintf("InviteInviteLink: team: %v, role: %v, etime: %v, maxUses: %v", t.Name(), role, etime, maxUses), &err)()
  1488  
  1489  	if role.IsAdminOrAbove() {
  1490  		return ikey, inviteID, fmt.Errorf("cannot create invitelink to add as %v", role)
  1491  	}
  1492  
  1493  	ikey, err = GenerateSeitanIKeyInvitelink()
  1494  	if err != nil {
  1495  		return ikey, inviteID, err
  1496  	}
  1497  
  1498  	sikey, err := GenerateSIKeyInvitelink(ikey)
  1499  	if err != nil {
  1500  		return ikey, inviteID, err
  1501  	}
  1502  
  1503  	inviteID, err = sikey.GenerateTeamInviteID()
  1504  	if err != nil {
  1505  		return ikey, inviteID, err
  1506  	}
  1507  
  1508  	// label is hardcoded for now, but could change in the future
  1509  	label := keybase1.NewSeitanKeyLabelWithGeneric(keybase1.SeitanKeyLabelGeneric{L: "link"})
  1510  
  1511  	_, encoded, err := GeneratePackedEncryptedKeyInvitelink(ctx, ikey, t, label)
  1512  	if err != nil {
  1513  		return ikey, inviteID, err
  1514  	}
  1515  
  1516  	invite := SCTeamInvite{
  1517  		Type:    "invitelink",
  1518  		Name:    keybase1.TeamInviteName(encoded),
  1519  		ID:      inviteID,
  1520  		Etime:   etime,
  1521  		MaxUses: &maxUses,
  1522  	}
  1523  
  1524  	if err := t.postInvite(ctx, invite, role); err != nil {
  1525  		return ikey, inviteID, err
  1526  	}
  1527  
  1528  	return ikey, inviteID, err
  1529  }
  1530  
  1531  func (t *Team) postInvite(ctx context.Context, invite SCTeamInvite, role keybase1.TeamRole) error {
  1532  	existing, err := t.HasActiveInvite(t.MetaContext(ctx), invite.Name, invite.Type)
  1533  	if err != nil {
  1534  		return err
  1535  	}
  1536  	if existing {
  1537  		return libkb.ExistsError{Msg: "An invite for this user already exists."}
  1538  	}
  1539  
  1540  	if t.IsSubteam() && role == keybase1.TeamRole_OWNER {
  1541  		return NewSubteamOwnersError()
  1542  	}
  1543  
  1544  	invList := []SCTeamInvite{invite}
  1545  	var invites SCTeamInvites
  1546  	switch role {
  1547  	case keybase1.TeamRole_RESTRICTEDBOT, keybase1.TeamRole_BOT:
  1548  		return fmt.Errorf("bot roles disallowed for invites")
  1549  	case keybase1.TeamRole_READER:
  1550  		invites.Readers = &invList
  1551  	case keybase1.TeamRole_WRITER:
  1552  		invites.Writers = &invList
  1553  	case keybase1.TeamRole_ADMIN:
  1554  		invites.Admins = &invList
  1555  	case keybase1.TeamRole_OWNER:
  1556  		invites.Owners = &invList
  1557  	}
  1558  	if invites.Len() == 0 {
  1559  		return fmt.Errorf("invalid invite, 0 members invited")
  1560  	}
  1561  
  1562  	return t.postTeamInvites(ctx, invites)
  1563  }
  1564  
  1565  func (t *Team) postTeamInvites(ctx context.Context, invites SCTeamInvites) error {
  1566  	m := t.MetaContext(ctx)
  1567  
  1568  	admin, err := t.getAdminPermission(ctx)
  1569  	if err != nil {
  1570  		return err
  1571  	}
  1572  
  1573  	if t.IsSubteam() && invites.Owners != nil && len(*invites.Owners) > 0 {
  1574  		return NewSubteamOwnersError()
  1575  	}
  1576  
  1577  	entropy, err := makeSCTeamEntropy()
  1578  	if err != nil {
  1579  		return err
  1580  	}
  1581  
  1582  	ratchet, err := t.makeRatchet(ctx)
  1583  	if err != nil {
  1584  		return err
  1585  	}
  1586  
  1587  	teamSection := SCTeamSection{
  1588  		ID:       SCTeamID(t.ID),
  1589  		Admin:    admin,
  1590  		Invites:  &invites,
  1591  		Implicit: t.IsImplicit(),
  1592  		Public:   t.IsPublic(),
  1593  		Entropy:  entropy,
  1594  		Ratchets: ratchet.ToTeamSection(),
  1595  	}
  1596  
  1597  	mr, err := t.G().MerkleClient.FetchRootFromServer(t.MetaContext(ctx), libkb.TeamMerkleFreshnessForAdmin)
  1598  	if err != nil {
  1599  		return err
  1600  	}
  1601  	if mr == nil {
  1602  		return errors.New("No merkle root available for team invite")
  1603  	}
  1604  
  1605  	sigMultiItem, latestSeqno, err := t.sigTeamItem(ctx, teamSection, libkb.LinkTypeInvite, mr)
  1606  	if err != nil {
  1607  		return err
  1608  	}
  1609  
  1610  	sigMulti := []libkb.SigMultiItem{sigMultiItem}
  1611  	err = t.precheckLinksToPost(ctx, sigMulti)
  1612  	if err != nil {
  1613  		return err
  1614  	}
  1615  
  1616  	sigPayloadArgs := sigPayloadArgs{
  1617  		ratchetBlindingKeys: ratchet.ToSigPayload(),
  1618  	}
  1619  
  1620  	payload := t.sigPayload(sigMulti, sigPayloadArgs)
  1621  	err = t.postMulti(m, payload)
  1622  	if err != nil {
  1623  		return err
  1624  	}
  1625  
  1626  	return t.notify(ctx, keybase1.TeamChangeSet{MembershipChanged: true}, latestSeqno)
  1627  }
  1628  
  1629  // NOTE since this function uses `Load` and not `load2`, readSubteamID cannot
  1630  // be passed through, this call will fail if a user is not a member of the
  1631  // parent team (or child of the parent team) for which the validator validates
  1632  func (t *Team) traverseUpUntil(ctx context.Context, validator func(t *Team) bool) (targetTeam *Team, err error) {
  1633  	targetTeam = t
  1634  	for {
  1635  		if validator(targetTeam) {
  1636  			return targetTeam, nil
  1637  		}
  1638  		parentID := targetTeam.chain().GetParentID()
  1639  		if parentID == nil {
  1640  			return nil, nil
  1641  		}
  1642  		targetTeam, err = Load(ctx, t.G(), keybase1.LoadTeamArg{
  1643  			ID:     *parentID,
  1644  			Public: parentID.IsPublic(),
  1645  			// This is in a cold path anyway, so might as well trade reliability
  1646  			// at the expense of speed.
  1647  			ForceRepoll: true,
  1648  		})
  1649  		if err != nil {
  1650  			return nil, err
  1651  		}
  1652  	}
  1653  }
  1654  
  1655  func (t *Team) getAdminPermission(ctx context.Context) (admin *SCTeamAdmin, err error) {
  1656  	uv, err := t.currentUserUV(ctx)
  1657  	if err != nil {
  1658  		return nil, err
  1659  	}
  1660  
  1661  	targetTeam, err := t.traverseUpUntil(ctx, func(s *Team) bool {
  1662  		return s.chain().GetAdminUserLogPoint(uv) != nil
  1663  	})
  1664  	if err != nil {
  1665  		return nil, err
  1666  	}
  1667  	if targetTeam == nil {
  1668  		return nil, NewAdminPermissionRequiredError()
  1669  	}
  1670  
  1671  	logPoint := targetTeam.chain().GetAdminUserLogPoint(uv)
  1672  	ret := SCTeamAdmin{
  1673  		TeamID:  SCTeamID(targetTeam.ID),
  1674  		Seqno:   logPoint.SigMeta.SigChainLocation.Seqno,
  1675  		SeqType: logPoint.SigMeta.SigChainLocation.SeqType,
  1676  	}
  1677  	return &ret, nil
  1678  }
  1679  
  1680  func (t *Team) changeMembershipSection(ctx context.Context, req keybase1.TeamChangeReq, skipKeyRotation bool) (SCTeamSection, *PerTeamSharedSecretBoxes, map[keybase1.TeamID]*PerTeamSharedSecretBoxes, *teamEKPayload, *memberSet, *hidden.Ratchet, error) {
  1681  	// initialize key manager
  1682  	if _, err := t.SharedSecret(ctx); err != nil {
  1683  		return SCTeamSection{}, nil, nil, nil, nil, nil, err
  1684  	}
  1685  
  1686  	admin, err := t.getAdminPermission(ctx)
  1687  	if err != nil {
  1688  		return SCTeamSection{}, nil, nil, nil, nil, nil, err
  1689  	}
  1690  
  1691  	if t.IsSubteam() && len(req.Owners) > 0 {
  1692  		return SCTeamSection{}, nil, nil, nil, nil, nil, NewSubteamOwnersError()
  1693  	}
  1694  
  1695  	// load the member set specified in req
  1696  	memSet, err := newMemberSetChange(ctx, t.G(), req)
  1697  	if err != nil {
  1698  		return SCTeamSection{}, nil, nil, nil, nil, nil, err
  1699  	}
  1700  
  1701  	ratchet, err := t.makeRatchet(ctx)
  1702  	if err != nil {
  1703  		return SCTeamSection{}, nil, nil, nil, nil, nil, err
  1704  	}
  1705  
  1706  	section := SCTeamSection{
  1707  		ID:       SCTeamID(t.ID),
  1708  		Admin:    admin,
  1709  		Implicit: t.IsImplicit(),
  1710  		Public:   t.IsPublic(),
  1711  		Ratchets: ratchet.ToTeamSection(),
  1712  	}
  1713  
  1714  	section.Members, err = memSet.Section()
  1715  	if err != nil {
  1716  		return SCTeamSection{}, nil, nil, nil, nil, nil, err
  1717  	}
  1718  
  1719  	// create secret boxes for recipients, possibly rotating the key
  1720  	secretBoxes, implicitAdminBoxes, perTeamKeySection, teamEKPayload, err := t.recipientBoxes(ctx, memSet, skipKeyRotation)
  1721  	if err != nil {
  1722  		return SCTeamSection{}, nil, nil, nil, nil, nil, err
  1723  	}
  1724  
  1725  	section.PerTeamKey = perTeamKeySection
  1726  
  1727  	err = addSummaryHash(&section, secretBoxes)
  1728  	if err != nil {
  1729  		return SCTeamSection{}, nil, nil, nil, nil, nil, err
  1730  	}
  1731  
  1732  	section.CompletedInvites = req.CompletedInvites
  1733  	section.UsedInvites = makeSCMapInviteIDUVMap(req.UsedInvites)
  1734  
  1735  	section.Implicit = t.IsImplicit()
  1736  	section.Public = t.IsPublic()
  1737  
  1738  	if len(section.CompletedInvites) > 0 && section.Members == nil {
  1739  		// Just mooted invites is fine - if TeamChangeReq is empty,
  1740  		// changeMembershipSection returned nil members. But we need
  1741  		// empty Members in order to have a valid link.
  1742  		section.Members = &SCTeamMembers{}
  1743  	}
  1744  
  1745  	return section, secretBoxes, implicitAdminBoxes, teamEKPayload, memSet, ratchet, nil
  1746  }
  1747  
  1748  func (t *Team) changeItemsPayload(ctx context.Context, sections []teamSectionWithLinkType,
  1749  	merkleRoot *libkb.MerkleRoot, sigPayloadArgs sigPayloadArgs) (libkb.JSONPayload, keybase1.Seqno, error) {
  1750  
  1751  	var readySigs []libkb.SigMultiItem
  1752  	nextSeqno := t.NextSeqno()
  1753  	latestLinkID := t.chain().GetLatestLinkID()
  1754  
  1755  	for _, section := range sections {
  1756  		sigMultiItem, linkID, err := t.sigTeamItemRaw(ctx, section.section,
  1757  			section.linkType, nextSeqno, latestLinkID, merkleRoot)
  1758  		if err != nil {
  1759  			return nil, keybase1.Seqno(0), err
  1760  		}
  1761  		nextSeqno++
  1762  		latestLinkID = linkID
  1763  		readySigs = append(readySigs, sigMultiItem)
  1764  	}
  1765  
  1766  	if err := t.precheckLinksToPost(ctx, readySigs); err != nil {
  1767  		return nil, keybase1.Seqno(0), err
  1768  	}
  1769  
  1770  	payload := t.sigPayload(readySigs, sigPayloadArgs)
  1771  	return payload, nextSeqno - 1, nil
  1772  }
  1773  
  1774  func (t *Team) changeItemPayload(ctx context.Context, section SCTeamSection, linkType libkb.LinkType,
  1775  	merkleRoot *libkb.MerkleRoot, sigPayloadArgs sigPayloadArgs) (libkb.JSONPayload, keybase1.Seqno, error) {
  1776  	// create the change item
  1777  	sigMultiItem, latestSeqno, err := t.sigTeamItem(ctx, section, linkType, merkleRoot)
  1778  	if err != nil {
  1779  		return nil, keybase1.Seqno(0), err
  1780  	}
  1781  
  1782  	sigMulti := []libkb.SigMultiItem{sigMultiItem}
  1783  	err = t.precheckLinksToPost(ctx, sigMulti)
  1784  	if err != nil {
  1785  		return nil, keybase1.Seqno(0), err
  1786  	}
  1787  
  1788  	// make the payload
  1789  	payload := t.sigPayload(sigMulti, sigPayloadArgs)
  1790  	return payload, latestSeqno, nil
  1791  }
  1792  
  1793  func (t *Team) postChangeItem(ctx context.Context, section SCTeamSection, linkType libkb.LinkType, merkleRoot *libkb.MerkleRoot, sigPayloadArgs sigPayloadArgs) (keybase1.Seqno, error) {
  1794  	payload, latestSeqno, err := t.changeItemPayload(ctx, section, linkType, merkleRoot, sigPayloadArgs)
  1795  	if err != nil {
  1796  		return keybase1.Seqno(0), err
  1797  	}
  1798  	// send it to the server
  1799  	err = t.postMulti(libkb.NewMetaContext(ctx, t.G()), payload)
  1800  	if err != nil {
  1801  		return keybase1.Seqno(0), err
  1802  	}
  1803  	return latestSeqno, nil
  1804  }
  1805  
  1806  func (t *Team) currentUserUV(ctx context.Context) (keybase1.UserVersion, error) {
  1807  	return t.G().GetMeUV(ctx)
  1808  }
  1809  
  1810  func loadMeForSignatures(ctx context.Context, g *libkb.GlobalContext) (libkb.UserForSignatures, error) {
  1811  	return libkb.LoadSelfForTeamSignatures(ctx, g)
  1812  }
  1813  
  1814  func usesPerTeamKeys(linkType libkb.LinkType) bool {
  1815  	switch linkType {
  1816  	case libkb.LinkTypeLeave:
  1817  		return false
  1818  	case libkb.LinkTypeInvite:
  1819  		return false
  1820  	case libkb.LinkTypeDeleteRoot:
  1821  		return false
  1822  	case libkb.LinkTypeDeleteSubteam:
  1823  		return false
  1824  	case libkb.LinkTypeDeleteUpPointer:
  1825  		return false
  1826  	case libkb.LinkTypeKBFSSettings:
  1827  		return false
  1828  	}
  1829  
  1830  	return true
  1831  }
  1832  
  1833  func (t *Team) sigTeamItem(ctx context.Context, section SCTeamSection, linkType libkb.LinkType, merkleRoot *libkb.MerkleRoot) (libkb.SigMultiItem, keybase1.Seqno, error) {
  1834  	nextSeqno := t.NextSeqno()
  1835  	lastLinkID := t.chain().GetLatestLinkID()
  1836  
  1837  	sig, _, err := t.sigTeamItemRaw(ctx, section, linkType, nextSeqno, lastLinkID, merkleRoot)
  1838  	return sig, nextSeqno, err
  1839  }
  1840  
  1841  func (t *Team) sigTeamItemRaw(ctx context.Context, section SCTeamSection, linkType libkb.LinkType, nextSeqno keybase1.Seqno, lastLinkID keybase1.LinkID, merkleRoot *libkb.MerkleRoot) (libkb.SigMultiItem, keybase1.LinkID, error) {
  1842  	me, err := loadMeForSignatures(ctx, t.G())
  1843  	if err != nil {
  1844  		return libkb.SigMultiItem{}, "", err
  1845  	}
  1846  	deviceSigningKey, err := t.G().ActiveDevice.SigningKey()
  1847  	if err != nil {
  1848  		return libkb.SigMultiItem{}, "", err
  1849  	}
  1850  	latestLinkID, err := libkb.ImportLinkID(lastLinkID)
  1851  	if err != nil {
  1852  		return libkb.SigMultiItem{}, "", err
  1853  	}
  1854  
  1855  	sig, err := ChangeSig(t.G(), me, latestLinkID, nextSeqno, deviceSigningKey, section, linkType, merkleRoot)
  1856  	if err != nil {
  1857  		return libkb.SigMultiItem{}, "", err
  1858  	}
  1859  
  1860  	var signingKey libkb.NaclSigningKeyPair
  1861  	var encryptionKey libkb.NaclDHKeyPair
  1862  	if usesPerTeamKeys(linkType) {
  1863  		signingKey, err = t.keyManager.SigningKey()
  1864  		if err != nil {
  1865  			return libkb.SigMultiItem{}, "", err
  1866  		}
  1867  		encryptionKey, err = t.keyManager.EncryptionKey()
  1868  		if err != nil {
  1869  			return libkb.SigMultiItem{}, "", err
  1870  		}
  1871  		if section.PerTeamKey != nil {
  1872  			// need a reverse sig
  1873  
  1874  			// set a nil value (not empty) for reverse_sig (fails without this)
  1875  			err := sig.SetValueAtPath("body.team.per_team_key.reverse_sig", jsonw.NewNil())
  1876  			if err != nil {
  1877  				return libkb.SigMultiItem{}, "", err
  1878  			}
  1879  			reverseSig, _, _, err := libkb.SignJSON(sig, signingKey)
  1880  			if err != nil {
  1881  				return libkb.SigMultiItem{}, "", err
  1882  			}
  1883  			err = sig.SetValueAtPath("body.team.per_team_key.reverse_sig", jsonw.NewString(reverseSig))
  1884  			if err != nil {
  1885  				return libkb.SigMultiItem{}, "", err
  1886  			}
  1887  		}
  1888  	}
  1889  
  1890  	seqType := seqTypeForTeamPublicness(t.IsPublic())
  1891  
  1892  	sigJSON, err := sig.Marshal()
  1893  	if err != nil {
  1894  		return libkb.SigMultiItem{}, "", err
  1895  	}
  1896  	v2Sig, _, newLinkID, err := libkb.MakeSigchainV2OuterSig(
  1897  		t.MetaContext(ctx),
  1898  		deviceSigningKey,
  1899  		linkType,
  1900  		nextSeqno,
  1901  		sigJSON,
  1902  		latestLinkID,
  1903  		libkb.SigHasRevokes(false),
  1904  		seqType,
  1905  		libkb.SigIgnoreIfUnsupported(false),
  1906  		nil,
  1907  	)
  1908  	if err != nil {
  1909  		return libkb.SigMultiItem{}, "", err
  1910  	}
  1911  
  1912  	sigMultiItem := libkb.SigMultiItem{
  1913  		Sig:        v2Sig,
  1914  		SigningKID: deviceSigningKey.GetKID(),
  1915  		Type:       string(linkType),
  1916  		SeqType:    seqType,
  1917  		SigInner:   string(sigJSON),
  1918  		TeamID:     t.ID,
  1919  	}
  1920  	if usesPerTeamKeys(linkType) {
  1921  		sigMultiItem.PublicKeys = &libkb.SigMultiItemPublicKeys{
  1922  			Encryption: encryptionKey.GetKID(),
  1923  			Signing:    signingKey.GetKID(),
  1924  		}
  1925  	}
  1926  
  1927  	return sigMultiItem, keybase1.LinkID(newLinkID.String()), nil
  1928  }
  1929  
  1930  func (t *Team) recipientBoxes(ctx context.Context, memSet *memberSet, skipKeyRotation bool) (
  1931  	*PerTeamSharedSecretBoxes, map[keybase1.TeamID]*PerTeamSharedSecretBoxes,
  1932  	*SCPerTeamKey, *teamEKPayload, error) {
  1933  
  1934  	// get device key
  1935  	deviceEncryptionKey, err := t.G().ActiveDevice.EncryptionKey()
  1936  	if err != nil {
  1937  		return nil, nil, nil, nil, err
  1938  	}
  1939  
  1940  	// First create all the subteam per-team-key boxes for new implicit admins.
  1941  	// We'll return these whether or not we're doing a rotation below.
  1942  	// TODO: Should we no-op this if the admins+owners aren't actually new?
  1943  	var implicitAdminBoxes map[keybase1.TeamID]*PerTeamSharedSecretBoxes
  1944  	adminAndOwnerRecipients := memSet.adminAndOwnerRecipients()
  1945  	if len(adminAndOwnerRecipients) > 0 {
  1946  		implicitAdminBoxes = map[keybase1.TeamID]*PerTeamSharedSecretBoxes{}
  1947  		subteams, err := t.loadAllTransitiveSubteams(ctx, true /*forceRepoll*/)
  1948  		if err != nil {
  1949  			return nil, nil, nil, nil, err
  1950  		}
  1951  		for _, subteam := range subteams {
  1952  			subteamBoxes, err := subteam.keyManager.SharedSecretBoxes(t.MetaContext(ctx), deviceEncryptionKey, adminAndOwnerRecipients)
  1953  			if err != nil {
  1954  				return nil, nil, nil, nil, err
  1955  			}
  1956  			implicitAdminBoxes[subteam.ID] = subteamBoxes
  1957  		}
  1958  	}
  1959  
  1960  	// if there are any removals happening, need to rotate the
  1961  	// team key, and recipients will be all the users in the team
  1962  	// after the removal.
  1963  	if memSet.HasRemoval() {
  1964  		if !skipKeyRotation {
  1965  			// key is rotating, so recipients needs to be all the remaining members
  1966  			// of the team after the removal (and including any new members in this
  1967  			// change)
  1968  			t.G().Log.CDebugf(ctx, "recipientBoxes: Team change request contains removal, rotating team key")
  1969  			boxes, perTeamKey, teamEKPayload, err := t.rotateBoxes(ctx, memSet)
  1970  			return boxes, implicitAdminBoxes, perTeamKey, teamEKPayload, err
  1971  		}
  1972  
  1973  		// If we don't rotate key, continue with the usual boxing.
  1974  		t.G().Log.CDebugf(ctx, "recipientBoxes: Skipping key rotation")
  1975  	}
  1976  
  1977  	// don't need keys for existing or restricted bot members, so remove them from the set
  1978  	memSet.removeExistingMembers(ctx, t)
  1979  	t.G().Log.CDebugf(ctx, "team change request: %d new members", len(memSet.recipients))
  1980  	if len(memSet.recipients) == 0 {
  1981  		return nil, implicitAdminBoxes, nil, nil, nil
  1982  	}
  1983  
  1984  	boxes, err := t.keyManager.SharedSecretBoxes(t.MetaContext(ctx), deviceEncryptionKey, memSet.recipients)
  1985  	if err != nil {
  1986  		return nil, nil, nil, nil, err
  1987  	}
  1988  	// No SCPerTeamKey section or teamEKPayload when the key isn't rotated
  1989  	return boxes, implicitAdminBoxes, nil, nil, err
  1990  }
  1991  
  1992  func (t *Team) rotateBoxes(ctx context.Context, memSet *memberSet) (*PerTeamSharedSecretBoxes, *SCPerTeamKey, *teamEKPayload, error) {
  1993  	// get device key
  1994  	deviceEncryptionKey, err := t.G().ActiveDevice.EncryptionKey()
  1995  	if err != nil {
  1996  		return nil, nil, nil, err
  1997  	}
  1998  
  1999  	// rotate the team key for all current members except restricted bots.
  2000  	existing, err := t.Members()
  2001  	if err != nil {
  2002  		return nil, nil, nil, err
  2003  	}
  2004  	if err := memSet.AddRemainingRecipients(ctx, t.G(), existing); err != nil {
  2005  		return nil, nil, nil, err
  2006  	}
  2007  
  2008  	// Without adding extra admins, get get the recipients for the new teamEK
  2009  	recipients := memSet.recipientUids()
  2010  
  2011  	if t.IsSubteam() {
  2012  		// rotate needs to be keyed for all admins above it
  2013  		allParentAdmins, err := t.G().GetTeamLoader().ImplicitAdmins(ctx, t.ID)
  2014  		if err != nil {
  2015  			return nil, nil, nil, err
  2016  		}
  2017  		_, err = memSet.loadGroup(ctx, t.G(), allParentAdmins, storeMemberKindRecipient, true)
  2018  		if err != nil {
  2019  			return nil, nil, nil, err
  2020  		}
  2021  	}
  2022  
  2023  	t.rotated = true
  2024  
  2025  	boxes, key, err := t.keyManager.RotateSharedSecretBoxes(t.MetaContext(ctx), deviceEncryptionKey, memSet.recipients)
  2026  	if err != nil {
  2027  		return nil, nil, nil, err
  2028  	}
  2029  
  2030  	// Once we have the new PTK, let's make the new teamEK
  2031  	teamEKPayload, err := t.teamEKPayload(ctx, recipients)
  2032  	return boxes, key, teamEKPayload, err
  2033  }
  2034  
  2035  type teamEKPayload struct {
  2036  	sig      string
  2037  	boxes    *[]keybase1.TeamEkBoxMetadata
  2038  	metadata keybase1.TeamEkMetadata
  2039  	box      *keybase1.TeamEkBoxed
  2040  }
  2041  
  2042  func (t *Team) teamEKPayload(ctx context.Context, recipients []keybase1.UID) (*teamEKPayload, error) {
  2043  	ekLib := t.G().GetEKLib()
  2044  	if ekLib == nil || len(recipients) == 0 {
  2045  		return nil, nil
  2046  	}
  2047  
  2048  	sigKey, err := t.SigningKey(ctx)
  2049  	if err != nil {
  2050  		return nil, err
  2051  	}
  2052  	mctx := libkb.NewMetaContext(ctx, t.G())
  2053  	sig, boxes, metadata, box, err := ekLib.PrepareNewTeamEK(mctx, t.ID, sigKey, recipients)
  2054  	if err != nil {
  2055  		return nil, err
  2056  	}
  2057  
  2058  	return &teamEKPayload{
  2059  		sig:      sig,
  2060  		boxes:    boxes,
  2061  		metadata: metadata,
  2062  		box:      box,
  2063  	}, nil
  2064  }
  2065  
  2066  func (t *Team) storeTeamEKPayload(ctx context.Context, teamEKPayload *teamEKPayload) {
  2067  	// Add the new teamEK box to local storage, if it was created above.
  2068  	if teamEKPayload != nil && teamEKPayload.box != nil {
  2069  		mctx := libkb.NewMetaContext(ctx, t.G())
  2070  		boxed := keybase1.NewTeamEphemeralKeyBoxedWithTeam(*teamEKPayload.box)
  2071  		if err := t.G().GetTeamEKBoxStorage().Put(mctx, t.ID, teamEKPayload.metadata.Generation, boxed); err != nil {
  2072  			t.G().Log.CErrorf(ctx, "error while saving teamEK box: %s", err)
  2073  		}
  2074  	}
  2075  }
  2076  
  2077  // createTeambotKeys generates teambotKeys and teambotEKs for the given bot
  2078  // member list. Runs in the background on member addition or team rotation.
  2079  func createTeambotKeys(g *libkb.GlobalContext, teamID keybase1.TeamID, bots []keybase1.UID) {
  2080  	mctx := libkb.NewMetaContextBackground(g)
  2081  	go func() {
  2082  		var err error
  2083  		defer mctx.Trace(fmt.Sprintf("createTeambotKeys: %d bot members", len(bots)), &err)()
  2084  		if len(bots) == 0 {
  2085  			return
  2086  		}
  2087  
  2088  		// Load the team in case we need to grab the latest PTK generation after a rotation.
  2089  		team, err := Load(mctx.Ctx(), g, keybase1.LoadTeamArg{
  2090  			ID: teamID,
  2091  		})
  2092  		if err != nil {
  2093  			return
  2094  		}
  2095  
  2096  		ekLib := mctx.G().GetEKLib()
  2097  		keyer := mctx.G().GetTeambotMemberKeyer()
  2098  		makeChatKey, makeKVStoreKey := true, true
  2099  		chatKey, err := team.ChatKey(mctx.Ctx())
  2100  		if err != nil {
  2101  			mctx.Debug("unable to get teamApplication key %v, aborting TeambotKey appkey creation", err)
  2102  			makeChatKey = false
  2103  		}
  2104  		kvStoreKey, err := team.ApplicationKey(mctx.Ctx(), keybase1.TeamApplication_KVSTORE)
  2105  		if err != nil {
  2106  			mctx.Debug("unable to get teamApplication key %v, aborting TeambotKey creation", err)
  2107  			makeKVStoreKey = false
  2108  		}
  2109  
  2110  		for _, uid := range bots {
  2111  			guid := gregor1.UID(uid.ToBytes())
  2112  			if ekLib != nil {
  2113  				if teambotEK, created, err := ekLib.GetOrCreateLatestTeambotEK(mctx, teamID, guid); err != nil {
  2114  					mctx.Debug("unable to GetOrCreateLatestTeambotEK for %v, %v", guid, err)
  2115  				} else {
  2116  					mctx.Debug("published TeambotEK generation %d for %v, newly created: %v", teambotEK.Generation(), uid, created)
  2117  				}
  2118  			}
  2119  			if keyer != nil {
  2120  				if makeChatKey {
  2121  					if teambotKey, created, err := keyer.GetOrCreateTeambotKey(mctx, teamID, guid, chatKey); err != nil {
  2122  						mctx.Debug("unable to GetOrCreateTeambotKey application %v, uid: %v, %v",
  2123  							keybase1.TeamApplication_CHAT, guid, err)
  2124  					} else {
  2125  						mctx.Debug("published TeambotKey app: %v generation %d for %v, newly created: %v",
  2126  							keybase1.TeamApplication_CHAT, teambotKey.Generation(), uid, created)
  2127  					}
  2128  				}
  2129  				if makeKVStoreKey {
  2130  					if teambotKey, created, err := keyer.GetOrCreateTeambotKey(mctx, teamID, guid, kvStoreKey); err != nil {
  2131  						mctx.Debug("unable to GetOrCreateTeambotKey application %v, uid: %v, %v",
  2132  							keybase1.TeamApplication_KVSTORE, guid, err)
  2133  					} else {
  2134  						mctx.Debug("published TeambotKey app: %v generation %d for %v, newly created: %v",
  2135  							keybase1.TeamApplication_KVSTORE, teambotKey.Generation(), uid, created)
  2136  					}
  2137  				}
  2138  			}
  2139  		}
  2140  	}()
  2141  }
  2142  
  2143  type sigPayloadArgs struct {
  2144  	secretBoxes         *PerTeamSharedSecretBoxes
  2145  	implicitAdminBoxes  map[keybase1.TeamID]*PerTeamSharedSecretBoxes
  2146  	lease               *libkb.Lease
  2147  	prePayload          libkb.JSONPayload
  2148  	legacyTLFUpgrade    *keybase1.TeamGetLegacyTLFUpgrade
  2149  	teamEKBoxes         *[]keybase1.TeamEkBoxMetadata
  2150  	teamEKPayload       *teamEKPayload
  2151  	ratchetBlindingKeys hidden.EncodedRatchetBlindingKeySet
  2152  }
  2153  
  2154  func (t *Team) sigPayload(sigMulti []libkb.SigMultiItem, args sigPayloadArgs) libkb.JSONPayload {
  2155  	payload := libkb.JSONPayload{}
  2156  	// copy the prepayload so we don't mutate it
  2157  	for k, v := range args.prePayload {
  2158  		payload[k] = v
  2159  	}
  2160  	payload["sigs"] = sigMulti
  2161  	if args.secretBoxes != nil {
  2162  		payload["per_team_key"] = args.secretBoxes
  2163  	}
  2164  	if args.implicitAdminBoxes != nil {
  2165  		payload["implicit_team_keys"] = args.implicitAdminBoxes
  2166  	}
  2167  	if args.lease != nil {
  2168  		payload["downgrade_lease_id"] = args.lease.LeaseID
  2169  	}
  2170  	if args.legacyTLFUpgrade != nil {
  2171  		payload["legacy_tlf_upgrade"] = args.legacyTLFUpgrade
  2172  	}
  2173  	args.ratchetBlindingKeys.AddToJSONPayload(payload)
  2174  	if args.teamEKBoxes != nil && len(*args.teamEKBoxes) > 0 {
  2175  		payload["team_ek_rebox"] = libkb.JSONPayload{
  2176  			"boxes":   args.teamEKBoxes,
  2177  			"team_id": t.ID,
  2178  		}
  2179  	} else if args.teamEKPayload != nil {
  2180  		if args.teamEKPayload.boxes != nil && len(*args.teamEKPayload.boxes) > 0 {
  2181  			payload["team_ek"] = libkb.JSONPayload{
  2182  				"sig":     args.teamEKPayload.sig,
  2183  				"boxes":   args.teamEKPayload.boxes,
  2184  				"team_id": t.ID,
  2185  			}
  2186  		}
  2187  	}
  2188  
  2189  	if t.G().VDL.DumpPayload() {
  2190  		pretty, err := json.MarshalIndent(payload, "", "\t")
  2191  		if err != nil {
  2192  			t.G().Log.Info("json marshal error: %s", err)
  2193  		} else {
  2194  			t.G().Log.Info("payload: %s", pretty)
  2195  		}
  2196  	}
  2197  
  2198  	return payload
  2199  }
  2200  
  2201  func (t *Team) postMulti(mctx libkb.MetaContext, payload libkb.JSONPayload) error {
  2202  	_, err := t.G().API.PostJSON(mctx, libkb.APIArg{
  2203  		Endpoint:    "sig/multi",
  2204  		SessionType: libkb.APISessionTypeREQUIRED,
  2205  		JSONPayload: payload,
  2206  	})
  2207  	return err
  2208  }
  2209  
  2210  // ForceMerkleRootUpdate will call LookupTeam on MerkleClient to
  2211  // update cached merkle root to include latest team sigs. Needed if
  2212  // client wants to create a signature that refers to an adminship,
  2213  // signature's merkle_root has to be more fresh than adminship's.
  2214  func (t *Team) ForceMerkleRootUpdate(ctx context.Context) error {
  2215  	return ForceMerkleRootUpdateByTeamID(t.MetaContext(ctx), t.ID)
  2216  }
  2217  
  2218  func ForceMerkleRootUpdateByTeamID(mctx libkb.MetaContext, teamID keybase1.TeamID) error {
  2219  	_, err := mctx.G().GetMerkleClient().LookupTeam(mctx, teamID)
  2220  	return err
  2221  }
  2222  
  2223  // All admins, owners, and implicit admins of this team.
  2224  func (t *Team) AllAdmins(ctx context.Context) ([]keybase1.UserVersion, error) {
  2225  	set := make(map[keybase1.UserVersion]bool)
  2226  
  2227  	owners, err := t.UsersWithRole(keybase1.TeamRole_OWNER)
  2228  	if err != nil {
  2229  		return nil, err
  2230  	}
  2231  	for _, m := range owners {
  2232  		set[m] = true
  2233  	}
  2234  
  2235  	admins, err := t.UsersWithRole(keybase1.TeamRole_ADMIN)
  2236  	if err != nil {
  2237  		return nil, err
  2238  	}
  2239  	for _, m := range admins {
  2240  		set[m] = true
  2241  	}
  2242  
  2243  	if t.IsSubteam() {
  2244  		imp, err := t.G().GetTeamLoader().ImplicitAdmins(ctx, t.ID)
  2245  		if err != nil {
  2246  			return nil, err
  2247  		}
  2248  		for _, m := range imp {
  2249  			set[m] = true
  2250  		}
  2251  	}
  2252  
  2253  	var all []keybase1.UserVersion
  2254  	for uv := range set {
  2255  		all = append(all, uv)
  2256  	}
  2257  	return all, nil
  2258  }
  2259  
  2260  // Restriction inherited from ListSubteams:
  2261  // Only call this on a Team that has been loaded with NeedAdmin.
  2262  // Otherwise, you might get incoherent answers due to links that
  2263  // were stubbed over the life of the cached object.
  2264  func (t *Team) loadAllTransitiveSubteams(ctx context.Context, forceRepoll bool) ([]*Team, error) {
  2265  	subteams := []*Team{}
  2266  	for _, idAndName := range t.chain().ListSubteams() {
  2267  		// Load each subteam...
  2268  		subteam, err := Load(ctx, t.G(), keybase1.LoadTeamArg{
  2269  			ID:          idAndName.Id,
  2270  			Public:      t.IsPublic(),
  2271  			NeedAdmin:   true,
  2272  			ForceRepoll: true,
  2273  		})
  2274  		if err != nil {
  2275  			return nil, err
  2276  		}
  2277  
  2278  		// Force loading the key manager.
  2279  		// TODO: Should this be the default, so that we don't need to do it here?
  2280  		_, err = subteam.SharedSecret(ctx)
  2281  		if err != nil {
  2282  			return nil, err
  2283  		}
  2284  
  2285  		subteams = append(subteams, subteam)
  2286  
  2287  		// ...and then recursively load each subteam's children.
  2288  		recursiveSubteams, err := subteam.loadAllTransitiveSubteams(ctx, forceRepoll)
  2289  		if err != nil {
  2290  			return nil, err
  2291  		}
  2292  		subteams = append(subteams, recursiveSubteams...)
  2293  	}
  2294  	return subteams, nil
  2295  }
  2296  
  2297  func (t *Team) PostTeamSettings(ctx context.Context, settings keybase1.TeamSettings, rotate bool) error {
  2298  	if _, err := t.SharedSecret(ctx); err != nil {
  2299  		return err
  2300  	}
  2301  
  2302  	admin, err := t.getAdminPermission(ctx)
  2303  	if err != nil {
  2304  		return err
  2305  	}
  2306  
  2307  	mr, err := t.G().MerkleClient.FetchRootFromServer(t.MetaContext(ctx), libkb.TeamMerkleFreshnessForAdmin)
  2308  	if err != nil {
  2309  		return err
  2310  	}
  2311  
  2312  	scSettings, err := CreateTeamSettings(settings.Open, settings.JoinAs)
  2313  	if err != nil {
  2314  		return err
  2315  	}
  2316  
  2317  	ratchet, err := t.makeRatchet(ctx)
  2318  	if err != nil {
  2319  		return err
  2320  	}
  2321  
  2322  	section := SCTeamSection{
  2323  		ID:       SCTeamID(t.ID),
  2324  		Admin:    admin,
  2325  		Settings: &scSettings,
  2326  		Implicit: t.IsImplicit(),
  2327  		Public:   t.IsPublic(),
  2328  		Ratchets: ratchet.ToTeamSection(),
  2329  	}
  2330  
  2331  	payloadArgs := sigPayloadArgs{
  2332  		ratchetBlindingKeys: ratchet.ToSigPayload(),
  2333  	}
  2334  	var maybeEKPayload *teamEKPayload
  2335  	var botMembers []keybase1.UID
  2336  	if rotate {
  2337  		// Create empty Members section. We are not changing memberships, but
  2338  		// it's needed for key rotation.
  2339  		memSet := newMemberSet()
  2340  		section.Members, err = memSet.Section()
  2341  		if err != nil {
  2342  			return err
  2343  		}
  2344  		secretBoxes, perTeamKeySection, teamEKPayload, err := t.rotateBoxes(ctx, memSet)
  2345  		if err != nil {
  2346  			return err
  2347  		}
  2348  		section.PerTeamKey = perTeamKeySection
  2349  		payloadArgs.secretBoxes = secretBoxes
  2350  		payloadArgs.teamEKPayload = teamEKPayload
  2351  		maybeEKPayload = teamEKPayload // for storeTeamEKPayload, after post succeeds
  2352  		botMembers = memSet.restrictedBotRecipientUids()
  2353  	}
  2354  	latestSeqno, err := t.postChangeItem(ctx, section, libkb.LinkTypeSettings, mr, payloadArgs)
  2355  	if err != nil {
  2356  		return err
  2357  	}
  2358  
  2359  	if rotate {
  2360  		err := t.notify(ctx, keybase1.TeamChangeSet{KeyRotated: true, Misc: true}, latestSeqno)
  2361  		if err != nil {
  2362  			return err
  2363  		}
  2364  		t.storeTeamEKPayload(ctx, maybeEKPayload)
  2365  		createTeambotKeys(t.G(), t.ID, botMembers)
  2366  	} else {
  2367  		err := t.notify(ctx, keybase1.TeamChangeSet{Misc: true}, latestSeqno)
  2368  		if err != nil {
  2369  			return err
  2370  		}
  2371  	}
  2372  	return nil
  2373  }
  2374  
  2375  func (t *Team) botSettingsSection(ctx context.Context, bots map[keybase1.UserVersion]keybase1.TeamBotSettings,
  2376  	ratchet *hidden.Ratchet, merkleRoot *libkb.MerkleRoot) (SCTeamSection, *hidden.Ratchet, error) {
  2377  	if _, err := t.SharedSecret(ctx); err != nil {
  2378  		return SCTeamSection{}, nil, err
  2379  	}
  2380  
  2381  	admin, err := t.getAdminPermission(ctx)
  2382  	if err != nil {
  2383  		return SCTeamSection{}, nil, err
  2384  	}
  2385  
  2386  	scBotSettings, err := CreateTeamBotSettings(bots)
  2387  	if err != nil {
  2388  		return SCTeamSection{}, nil, err
  2389  	}
  2390  	if ratchet == nil {
  2391  		ratchet, err = t.makeRatchet(ctx)
  2392  		if err != nil {
  2393  			return SCTeamSection{}, nil, err
  2394  		}
  2395  	}
  2396  
  2397  	section := SCTeamSection{
  2398  		ID:          SCTeamID(t.ID),
  2399  		Implicit:    t.IsImplicit(),
  2400  		Public:      t.IsPublic(),
  2401  		Admin:       admin,
  2402  		BotSettings: &scBotSettings,
  2403  		Ratchets:    ratchet.ToTeamSection(),
  2404  	}
  2405  	return section, ratchet, nil
  2406  }
  2407  
  2408  func (t *Team) PostTeamBotSettings(ctx context.Context, bots map[keybase1.UserVersion]keybase1.TeamBotSettings) error {
  2409  
  2410  	mr, err := t.G().MerkleClient.FetchRootFromServer(t.MetaContext(ctx), libkb.TeamMerkleFreshnessForAdmin)
  2411  	if err != nil {
  2412  		return err
  2413  	}
  2414  
  2415  	section, ratchet, err := t.botSettingsSection(ctx, bots, nil, mr)
  2416  	if err != nil {
  2417  		return err
  2418  	}
  2419  
  2420  	payloadArgs := sigPayloadArgs{
  2421  		ratchetBlindingKeys: ratchet.ToSigPayload(),
  2422  	}
  2423  	_, err = t.postChangeItem(ctx, section, libkb.LinkTypeTeamBotSettings, mr, payloadArgs)
  2424  	return err
  2425  }
  2426  
  2427  func (t *Team) precheckLinksToPost(ctx context.Context, sigMultiItems []libkb.SigMultiItem) (err error) {
  2428  	uv, err := t.currentUserUV(ctx)
  2429  	if err != nil {
  2430  		return err
  2431  	}
  2432  	return precheckLinksToPost(ctx, t.G(), sigMultiItems, t.chain(), uv)
  2433  }
  2434  
  2435  // Try to run `post` (expected to post new team sigchain links).
  2436  // Retry it several times if it fails due to being behind the latest team sigchain state or due to other retryable errors.
  2437  // Passes the attempt number (initially 0) to `post`.
  2438  func RetryIfPossible(ctx context.Context, g *libkb.GlobalContext, post func(ctx context.Context, attempt int) error) (err error) {
  2439  	mctx := libkb.NewMetaContext(ctx, g)
  2440  	defer mctx.Trace("RetryIfPossible", &err)()
  2441  	const nRetries = 3
  2442  	for i := 0; i < nRetries; i++ {
  2443  		mctx.Debug("| RetryIfPossible(%v)", i)
  2444  		err = post(mctx.Ctx(), i)
  2445  		switch {
  2446  		case isSigOldSeqnoError(err):
  2447  			mctx.Debug("| retrying due to SigOldSeqnoError %d", i)
  2448  		case isStaleBoxError(err):
  2449  			mctx.Debug("| retrying due to StaleBoxError %d", i)
  2450  		case isTeamBadGenerationError(err):
  2451  			mctx.Debug("| retrying due to Bad Generation Error (%s) %d", err, i)
  2452  		case isSigBadTotalOrder(err):
  2453  			mctx.Debug("| retrying since update would violate total ordering for team %d", i)
  2454  		case isSigMissingRatchet(err):
  2455  			mctx.Debug("| retrying since the server wanted a ratchet and we didn't provide one %d", i)
  2456  		case isHiddenAppendPrecheckError(err):
  2457  			mctx.Debug("| retrying since we hit a hidden append precheck error")
  2458  		case libkb.IsEphemeralRetryableError(err):
  2459  			mctx.Debug("| retrying since we hit a retryable ephemeral error %v, attempt %d", err, i)
  2460  		default:
  2461  			return err
  2462  		}
  2463  	}
  2464  	mctx.Debug("| RetryIfPossible exhausted attempts")
  2465  	if err == nil {
  2466  		// Should never happen
  2467  		return fmt.Errorf("failed retryable team operation")
  2468  	}
  2469  	// Return the error from the final round
  2470  	return err
  2471  }
  2472  
  2473  func isHiddenAppendPrecheckError(err error) bool {
  2474  	perr, ok := err.(PrecheckAppendError)
  2475  	if !ok {
  2476  		return false
  2477  	}
  2478  	_, ok = perr.Inner.(hidden.LoaderError)
  2479  	return ok
  2480  }
  2481  
  2482  func isSigOldSeqnoError(err error) bool {
  2483  	return libkb.IsAppStatusCode(err, keybase1.StatusCode_SCSigOldSeqno)
  2484  }
  2485  
  2486  func isSigBadTotalOrder(err error) bool {
  2487  	return libkb.IsAppStatusCode(err, keybase1.StatusCode_SCSigBadTotalOrder)
  2488  }
  2489  
  2490  func isSigMissingRatchet(err error) bool {
  2491  	return libkb.IsAppStatusCode(err, keybase1.StatusCode_SCSigMissingRatchet)
  2492  }
  2493  
  2494  func isTeamBadGenerationError(err error) bool {
  2495  	return libkb.IsAppStatusCode(err, keybase1.StatusCode_SCTeamBadGeneration)
  2496  }
  2497  
  2498  func (t *Team) marshal(incoming interface{}) ([]byte, error) {
  2499  	var data []byte
  2500  	mh := codec.MsgpackHandle{WriteExt: true}
  2501  	enc := codec.NewEncoderBytes(&data, &mh)
  2502  	if err := enc.Encode(incoming); err != nil {
  2503  		return nil, err
  2504  	}
  2505  	return data, nil
  2506  }
  2507  
  2508  func (t *Team) boxKBFSCryptKeys(ctx context.Context, key keybase1.TeamApplicationKey,
  2509  	kbfsKeys []keybase1.CryptKey) (string, keybase1.TeamEncryptedKBFSKeysetHash, error) {
  2510  
  2511  	marshaledKeys, err := t.marshal(kbfsKeys)
  2512  	if err != nil {
  2513  		return "", "", err
  2514  	}
  2515  
  2516  	var nonce [libkb.NaclDHNonceSize]byte
  2517  	if _, err := rand.Read(nonce[:]); err != nil {
  2518  		return "", "", err
  2519  	}
  2520  
  2521  	var encKey [libkb.NaclSecretBoxKeySize]byte = key.Material()
  2522  	sealed := secretbox.Seal(nil, marshaledKeys, &nonce, &encKey)
  2523  	dat := keybase1.TeamEncryptedKBFSKeyset{
  2524  		V: 1,
  2525  		N: nonce[:],
  2526  		E: sealed,
  2527  	}
  2528  
  2529  	marshaledSealedDat, err := t.marshal(dat)
  2530  	if err != nil {
  2531  		return "", "", err
  2532  	}
  2533  
  2534  	encStr := base64.StdEncoding.EncodeToString(marshaledSealedDat)
  2535  	sbytes := sha256.Sum256([]byte(encStr))
  2536  	return encStr, keybase1.TeamEncryptedKBFSKeysetHashFromBytes(sbytes[:]), nil
  2537  }
  2538  
  2539  func (t *Team) AssociateWithTLFKeyset(ctx context.Context, tlfID keybase1.TLFID,
  2540  	cryptKeys []keybase1.CryptKey, appType keybase1.TeamApplication) (err error) {
  2541  	m := t.MetaContext(ctx)
  2542  	defer m.Trace("Team.AssociateWithTLFKeyset", &err)()
  2543  
  2544  	// If we get no crypt keys, just associate TLF ID and bail
  2545  	if len(cryptKeys) == 0 {
  2546  		m.Debug("AssociateWithTLFKeyset: no crypt keys given, aborting")
  2547  		return nil
  2548  	}
  2549  
  2550  	// Sort crypt keys by generation (just in case they aren't naturally)
  2551  	sort.Slice(cryptKeys, func(i, j int) bool {
  2552  		return cryptKeys[i].KeyGeneration < cryptKeys[j].KeyGeneration
  2553  	})
  2554  
  2555  	latestKey, err := t.ApplicationKey(ctx, appType)
  2556  	if err != nil {
  2557  		return err
  2558  	}
  2559  	encStr, hash, err := t.boxKBFSCryptKeys(ctx, latestKey, cryptKeys)
  2560  	if err != nil {
  2561  		return err
  2562  	}
  2563  
  2564  	ratchet, err := t.makeRatchet(ctx)
  2565  	if err != nil {
  2566  		return err
  2567  	}
  2568  
  2569  	upgrade := SCTeamKBFSLegacyUpgrade{
  2570  		AppType:          appType,
  2571  		KeysetHash:       hash,
  2572  		LegacyGeneration: cryptKeys[len(cryptKeys)-1].Generation(),
  2573  		TeamGeneration:   latestKey.KeyGeneration,
  2574  	}
  2575  	teamSection := SCTeamSection{
  2576  		ID:       SCTeamID(t.ID),
  2577  		Implicit: t.IsImplicit(),
  2578  		Public:   t.IsPublic(),
  2579  		KBFS: &SCTeamKBFS{
  2580  			Keyset: &upgrade,
  2581  		},
  2582  		Ratchets: ratchet.ToTeamSection(),
  2583  	}
  2584  
  2585  	mr, err := m.G().MerkleClient.FetchRootFromServer(m, libkb.TeamMerkleFreshnessForAdmin)
  2586  	if err != nil {
  2587  		return err
  2588  	}
  2589  	if mr == nil {
  2590  		return errors.New("No merkle root available for KBFS settings update")
  2591  	}
  2592  
  2593  	sigMultiItem, latestSeqno, err := t.sigTeamItem(ctx, teamSection, libkb.LinkTypeKBFSSettings, mr)
  2594  	if err != nil {
  2595  		return err
  2596  	}
  2597  
  2598  	payload := t.sigPayload([]libkb.SigMultiItem{sigMultiItem}, sigPayloadArgs{
  2599  		legacyTLFUpgrade: &keybase1.TeamGetLegacyTLFUpgrade{
  2600  			EncryptedKeyset:  encStr,
  2601  			LegacyGeneration: cryptKeys[len(cryptKeys)-1].Generation(),
  2602  			TeamGeneration:   latestKey.KeyGeneration,
  2603  			AppType:          appType,
  2604  		},
  2605  		ratchetBlindingKeys: ratchet.ToSigPayload(),
  2606  	})
  2607  
  2608  	err = t.postMulti(m, payload)
  2609  	if err != nil {
  2610  		return err
  2611  	}
  2612  
  2613  	return t.HintLatestSeqno(m, latestSeqno)
  2614  }
  2615  
  2616  func (t *Team) AssociateWithTLFID(ctx context.Context, tlfID keybase1.TLFID) (err error) {
  2617  	m := t.MetaContext(ctx)
  2618  	defer m.Trace("Team.AssociateWithTLFID", &err)()
  2619  
  2620  	if tlfID.Eq(t.LatestKBFSTLFID()) {
  2621  		m.Debug("No updated needed, TLFID already set to %s", tlfID)
  2622  		return nil
  2623  	}
  2624  
  2625  	ratchet, err := t.makeRatchet(ctx)
  2626  	if err != nil {
  2627  		return err
  2628  	}
  2629  
  2630  	teamSection := SCTeamSection{
  2631  		ID:       SCTeamID(t.ID),
  2632  		Implicit: t.IsImplicit(),
  2633  		Public:   t.IsPublic(),
  2634  		KBFS: &SCTeamKBFS{
  2635  			TLF: &SCTeamKBFSTLF{
  2636  				ID: tlfID,
  2637  			},
  2638  		},
  2639  		Ratchets: ratchet.ToTeamSection(),
  2640  	}
  2641  
  2642  	mr, err := m.G().MerkleClient.FetchRootFromServer(m, libkb.TeamMerkleFreshnessForAdmin)
  2643  	if err != nil {
  2644  		return err
  2645  	}
  2646  	if mr == nil {
  2647  		return errors.New("No merkle root available for KBFS settings update")
  2648  	}
  2649  
  2650  	sigMultiItem, latestSeqno, err := t.sigTeamItem(ctx, teamSection, libkb.LinkTypeKBFSSettings, mr)
  2651  	if err != nil {
  2652  		return err
  2653  	}
  2654  
  2655  	sigPayloadArgs := sigPayloadArgs{
  2656  		ratchetBlindingKeys: ratchet.ToSigPayload(),
  2657  	}
  2658  	payload := t.sigPayload([]libkb.SigMultiItem{sigMultiItem}, sigPayloadArgs)
  2659  	err = t.postMulti(libkb.NewMetaContext(ctx, t.G()), payload)
  2660  	if err != nil {
  2661  		return err
  2662  	}
  2663  	return t.HintLatestSeqno(m, latestSeqno)
  2664  }
  2665  
  2666  func (t *Team) notifyNoChainChange(ctx context.Context, changes keybase1.TeamChangeSet) error {
  2667  	return t.notify(ctx, changes, t.CurrentSeqno())
  2668  }
  2669  
  2670  // Send notifyrouter messages.
  2671  // Modifies `changes`
  2672  // Update to the latest seqno that we're passing though, don't make any assumptions about number of sigs.
  2673  // Note that we're probably going to be getting this same notification a second time, since it will
  2674  // bounce off a gregor and back to us. But they are idempotent, so it should be fine to be double-notified.
  2675  func (t *Team) notify(ctx context.Context, changes keybase1.TeamChangeSet, latestSeqno keybase1.Seqno) error {
  2676  	changes.KeyRotated = changes.KeyRotated || t.rotated
  2677  	m := libkb.NewMetaContext(ctx, t.G())
  2678  	var err error
  2679  	if latestSeqno > 0 {
  2680  		err = HintLatestSeqno(m, t.ID, latestSeqno)
  2681  	}
  2682  	t.G().NotifyRouter.HandleTeamChangedByBothKeys(ctx, t.ID, t.Name().String(), latestSeqno, t.IsImplicit(),
  2683  		changes, keybase1.Seqno(0) /* hiddenSeqno */, keybase1.Seqno(0) /* offchainSeqno */, keybase1.TeamChangedSource_LOCAL)
  2684  	return err
  2685  }
  2686  
  2687  func (t *Team) HintLatestSeqno(m libkb.MetaContext, n keybase1.Seqno) error {
  2688  	return HintLatestSeqno(m, t.ID, n)
  2689  }
  2690  
  2691  func HintLatestSeqno(m libkb.MetaContext, id keybase1.TeamID, n keybase1.Seqno) error {
  2692  	err := m.G().GetTeamLoader().HintLatestSeqno(m.Ctx(), id, n)
  2693  	if err != nil {
  2694  		m.Warning("error in TeamLoader#HintLatestSeqno: %v", err)
  2695  	}
  2696  	e2 := m.G().GetFastTeamLoader().HintLatestSeqno(m, id, n)
  2697  	if e2 != nil {
  2698  		m.Warning("error in FastTeamLoader#HintLatestSeqno: %v", err)
  2699  	}
  2700  	if err != nil {
  2701  		return err
  2702  	}
  2703  	return e2
  2704  }
  2705  
  2706  func HintLatestHiddenSeqno(m libkb.MetaContext, id keybase1.TeamID, n keybase1.Seqno) error {
  2707  	err := m.G().GetHiddenTeamChainManager().HintLatestSeqno(m, id, n)
  2708  	if err != nil {
  2709  		m.Warning("error in HintLatestHiddenSeqno: %v", err)
  2710  	}
  2711  	return err
  2712  }
  2713  
  2714  func (t *Team) refreshUIDMapper(ctx context.Context, g *libkb.GlobalContext) {
  2715  	for uv := range t.chain().inner.UserLog {
  2716  		_, err := g.UIDMapper.InformOfEldestSeqno(ctx, g, uv)
  2717  		if err != nil {
  2718  			g.Log.CDebugf(ctx, "Error informing eldest seqno: %+v", err.Error())
  2719  		}
  2720  	}
  2721  	for _, inviteMD := range t.chain().ActiveInvites() {
  2722  		invite := inviteMD.Invite
  2723  		invtype, err := invite.Type.C()
  2724  		if err != nil {
  2725  			g.Log.CDebugf(ctx, "Error in invite %s: %s", invite.Id, err.Error())
  2726  			continue
  2727  		}
  2728  		if invtype == keybase1.TeamInviteCategory_KEYBASE {
  2729  			uv, err := invite.KeybaseUserVersion()
  2730  			if err != nil {
  2731  				g.Log.CDebugf(ctx, "Error in parsing invite %s: %s", invite.Id, err.Error())
  2732  			}
  2733  			_, err = g.UIDMapper.InformOfEldestSeqno(ctx, g, uv)
  2734  			if err != nil {
  2735  				g.Log.CDebugf(ctx, "Error informing eldest seqno: %+v", err.Error())
  2736  			}
  2737  		}
  2738  	}
  2739  }
  2740  
  2741  func UpgradeTLFIDToImpteam(ctx context.Context, g *libkb.GlobalContext, tlfName string, tlfID keybase1.TLFID,
  2742  	public bool, appType keybase1.TeamApplication, cryptKeys []keybase1.CryptKey) (err error) {
  2743  	defer g.CTrace(ctx, fmt.Sprintf("UpgradeTLFIDToImpteam(%s)", tlfID), &err)()
  2744  
  2745  	var team *Team
  2746  	if team, _, _, err = LookupOrCreateImplicitTeam(ctx, g, tlfName, public); err != nil {
  2747  		return err
  2748  	}
  2749  
  2750  	// Associate the imp team with the TLF ID
  2751  	if team.LatestKBFSTLFID().IsNil() {
  2752  		if err = team.AssociateWithTLFID(ctx, tlfID); err != nil {
  2753  			return err
  2754  		}
  2755  	} else {
  2756  		if team.LatestKBFSTLFID().String() != tlfID.String() {
  2757  			return fmt.Errorf("implicit team already associated with different TLF ID: teamID: %s tlfID: %s",
  2758  				team.ID, tlfID)
  2759  		}
  2760  	}
  2761  
  2762  	// Reload the team
  2763  	if team, err = Load(ctx, g, keybase1.LoadTeamArg{
  2764  		ID:          team.ID,
  2765  		Public:      public,
  2766  		ForceRepoll: true,
  2767  	}); err != nil {
  2768  		return err
  2769  	}
  2770  
  2771  	// Post the crypt keys
  2772  	return team.AssociateWithTLFKeyset(ctx, tlfID, cryptKeys, appType)
  2773  }
  2774  
  2775  func TeamInviteTypeFromString(mctx libkb.MetaContext, inviteTypeStr string) (keybase1.TeamInviteType, error) {
  2776  	switch inviteTypeStr {
  2777  	case "keybase":
  2778  		return keybase1.NewTeamInviteTypeDefault(keybase1.TeamInviteCategory_KEYBASE), nil
  2779  	case "email":
  2780  		return keybase1.NewTeamInviteTypeDefault(keybase1.TeamInviteCategory_EMAIL), nil
  2781  	case "seitan_invite_token":
  2782  		return keybase1.NewTeamInviteTypeDefault(keybase1.TeamInviteCategory_SEITAN), nil
  2783  	case "phone":
  2784  		return keybase1.NewTeamInviteTypeDefault(keybase1.TeamInviteCategory_PHONE), nil
  2785  	case "invitelink":
  2786  		return keybase1.NewTeamInviteTypeDefault(keybase1.TeamInviteCategory_INVITELINK), nil
  2787  	case "twitter", "github", "facebook", "reddit", "hackernews", "pgp", "http", "https", "dns":
  2788  		return keybase1.NewTeamInviteTypeWithSbs(keybase1.TeamInviteSocialNetwork(inviteTypeStr)), nil
  2789  	default:
  2790  		if mctx.G().GetProofServices().GetServiceType(mctx.Ctx(), inviteTypeStr) != nil {
  2791  			return keybase1.NewTeamInviteTypeWithSbs(keybase1.TeamInviteSocialNetwork(inviteTypeStr)), nil
  2792  		}
  2793  
  2794  		isDev := mctx.G().Env.GetRunMode() == libkb.DevelRunMode
  2795  		if isDev && inviteTypeStr == "rooter" {
  2796  			return keybase1.NewTeamInviteTypeWithSbs(keybase1.TeamInviteSocialNetwork(inviteTypeStr)), nil
  2797  		}
  2798  		// Don't want to break existing clients if we see an unknown invite type.
  2799  		return keybase1.NewTeamInviteTypeWithUnknown(inviteTypeStr), nil
  2800  	}
  2801  }
  2802  
  2803  func FreezeTeam(mctx libkb.MetaContext, teamID keybase1.TeamID) error {
  2804  	err3 := mctx.G().GetHiddenTeamChainManager().Freeze(mctx, teamID)
  2805  	if err3 != nil {
  2806  		mctx.Debug("error freezing in hidden team chain manager: %v", err3)
  2807  	}
  2808  	err1 := mctx.G().GetTeamLoader().Freeze(mctx.Ctx(), teamID)
  2809  	if err1 != nil {
  2810  		mctx.Debug("error freezing in team cache: %v", err1)
  2811  	}
  2812  	err2 := mctx.G().GetFastTeamLoader().Freeze(mctx, teamID)
  2813  	if err2 != nil {
  2814  		mctx.Debug("error freezing in fast team cache: %v", err2)
  2815  	}
  2816  	return libkb.CombineErrors(err1, err2, err3)
  2817  }
  2818  
  2819  func TombstoneTeam(mctx libkb.MetaContext, teamID keybase1.TeamID) error {
  2820  	err3 := mctx.G().GetHiddenTeamChainManager().Tombstone(mctx, teamID)
  2821  	if err3 != nil {
  2822  		mctx.Debug("error tombstoning in hidden team chain manager: %v", err3)
  2823  		if _, ok := err3.(hidden.TombstonedError); ok {
  2824  			err3 = nil
  2825  		}
  2826  	}
  2827  	err1 := mctx.G().GetTeamLoader().Tombstone(mctx.Ctx(), teamID)
  2828  	if err1 != nil {
  2829  		mctx.Debug("error tombstoning in team cache: %v", err1)
  2830  		if _, ok := err1.(TeamTombstonedError); ok {
  2831  			err1 = nil
  2832  		}
  2833  	}
  2834  	err2 := mctx.G().GetFastTeamLoader().Tombstone(mctx, teamID)
  2835  	if err2 != nil {
  2836  		mctx.Debug("error tombstoning in fast team cache: %v", err2)
  2837  		if _, ok := err2.(TeamTombstonedError); ok {
  2838  			err2 = nil
  2839  		}
  2840  	}
  2841  	return libkb.CombineErrors(err1, err2, err3)
  2842  }
  2843  
  2844  type TeamShim struct {
  2845  	Data   *keybase1.TeamData
  2846  	Hidden *keybase1.HiddenTeamChain
  2847  }
  2848  
  2849  func (t *TeamShim) MainChain() *keybase1.TeamData          { return t.Data }
  2850  func (t *TeamShim) HiddenChain() *keybase1.HiddenTeamChain { return t.Hidden }
  2851  
  2852  var _ Teamer = (*TeamShim)(nil)
  2853  
  2854  func KeySummary(t Teamer) string {
  2855  	if t == nil {
  2856  		return "Ø"
  2857  	}
  2858  	return fmt.Sprintf("{main:%s, hidden:%s}", t.MainChain().KeySummary(), t.HiddenChain().KeySummary())
  2859  }
  2860  
  2861  type TeamInfo struct {
  2862  	libkb.AppStatusEmbed
  2863  	Name          string
  2864  	InTeam        bool `json:"in_team"`
  2865  	Open          bool
  2866  	Description   string
  2867  	PublicAdmins  []string `json:"public_admins"`
  2868  	NumMembers    int      `json:"num_members"`
  2869  	PublicMembers []struct {
  2870  		Role     keybase1.TeamRole
  2871  		UID      keybase1.UID
  2872  		Username string
  2873  		FullName string `json:"full_name"`
  2874  	} `json:"public_members"`
  2875  }
  2876  
  2877  func GetUntrustedTeamInfo(mctx libkb.MetaContext, name keybase1.TeamName) (info keybase1.UntrustedTeamInfo, err error) {
  2878  	arg := libkb.APIArg{
  2879  		Endpoint:    "team/mentiondesc",
  2880  		SessionType: libkb.APISessionTypeREQUIRED,
  2881  		Args: libkb.HTTPArgs{
  2882  			"name":                libkb.S{Val: name.String()},
  2883  			"include_all_members": libkb.B{Val: true}, // refers to members who showcased the team on their profile only
  2884  		},
  2885  	}
  2886  
  2887  	var resp TeamInfo
  2888  	if err = mctx.G().API.GetDecode(mctx, arg, &resp); err != nil {
  2889  		mctx.Debug("GetUntrustedTeamInfo: failed to get team info: %s", err)
  2890  	}
  2891  	if err != nil {
  2892  		return info, err
  2893  	}
  2894  
  2895  	teamName, err := keybase1.TeamNameFromString(resp.Name)
  2896  	if err != nil {
  2897  		return info, err
  2898  	}
  2899  
  2900  	teamInfo := keybase1.UntrustedTeamInfo{
  2901  		Name:         teamName,
  2902  		Description:  resp.Description,
  2903  		InTeam:       resp.InTeam,
  2904  		NumMembers:   resp.NumMembers,
  2905  		Open:         resp.Open,
  2906  		PublicAdmins: resp.PublicAdmins,
  2907  	}
  2908  
  2909  	for _, mem := range resp.PublicMembers {
  2910  		teamInfo.PublicMembers = append(teamInfo.PublicMembers, keybase1.TeamMemberRole{
  2911  			Uid:      mem.UID,
  2912  			FullName: keybase1.FullName(mem.FullName),
  2913  			Role:     mem.Role,
  2914  			Username: mem.Username,
  2915  		})
  2916  	}
  2917  
  2918  	return teamInfo, nil
  2919  }
  2920  
  2921  func GetUntrustedTeamExists(mctx libkb.MetaContext, name keybase1.TeamName) (teamExistsResult keybase1.UntrustedTeamExistsResult, err error) {
  2922  	type resType struct {
  2923  		libkb.AppStatusEmbed
  2924  		Exists bool                `json:"exists"`
  2925  		Sc     keybase1.StatusCode `json:"sc"`
  2926  	}
  2927  	var res resType
  2928  	err = mctx.G().API.GetDecode(mctx, libkb.APIArg{
  2929  		Endpoint:    "team/exists",
  2930  		SessionType: libkb.APISessionTypeREQUIRED,
  2931  		Args: libkb.HTTPArgs{
  2932  			"teamName": libkb.S{Val: name.String()},
  2933  		},
  2934  	}, &res)
  2935  	if err != nil {
  2936  		mctx.Debug("GetUntrustedTeamInfo: failed to get team info: %s", err)
  2937  		return teamExistsResult, err
  2938  	}
  2939  
  2940  	return keybase1.UntrustedTeamExistsResult{
  2941  		Exists: res.Exists,
  2942  		Status: res.Sc,
  2943  	}, nil
  2944  }