/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/service/teams.go
971 строка
37 KB
zoom-ua
perf(teams): memoize and harden GetAnnotatedTeam (#29489)
11 авг 2026, 21:12
Не верифицирован
11 авг 2026, 21:12
c2029e8
Код
Авторство
О чём код?
// Copyright 2017 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. // RPC handlers for team operations package service import ( "context" "fmt" "time" "github.com/go-errors/errors" "github.com/keybase/client/go/protocol/gregor1" "github.com/keybase/client/go/kbtime" "github.com/keybase/client/go/chat/globals" "github.com/keybase/client/go/externals" "github.com/keybase/client/go/libkb" "github.com/keybase/client/go/offline" "github.com/keybase/client/go/protocol/chat1" keybase1 "github.com/keybase/client/go/protocol/keybase1" "github.com/keybase/client/go/teams" "github.com/keybase/go-framed-msgpack-rpc/rpc" ) type TeamsHandler struct { *BaseHandler globals.Contextified connID libkb.ConnectionID service *Service } var _ keybase1.TeamsInterface = (*TeamsHandler)(nil) func NewTeamsHandler(xp rpc.Transporter, id libkb.ConnectionID, g *globals.Context, service *Service) *TeamsHandler { return &TeamsHandler{ BaseHandler: NewBaseHandler(g.ExternalG(), xp), Contextified: globals.NewContextified(g), connID: id, service: service, } } func (h *TeamsHandler) UntrustedTeamExists(ctx context.Context, teamName keybase1.TeamName) (res keybase1.UntrustedTeamExistsResult, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("UntrustedTeamExists(%s)", teamName), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return teams.GetUntrustedTeamExists(mctx, teamName) } func (h *TeamsHandler) TeamCreate(ctx context.Context, arg keybase1.TeamCreateArg) (res keybase1.TeamCreateResult, err error) { ctx = libkb.WithLogTag(ctx, "TM") arg2 := keybase1.TeamCreateWithSettingsArg{ SessionID: arg.SessionID, Name: arg.Name, JoinSubteam: arg.JoinSubteam, } if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return res, err } return h.TeamCreateWithSettings(ctx, arg2) } func (h *TeamsHandler) TeamCreateFancy(ctx context.Context, arg keybase1.TeamCreateFancyArg) (teamID keybase1.TeamID, err error, ) { ctx = libkb.WithLogTag(ctx, "TM") mctx := h.MetaContext(ctx) teamInfo := arg.TeamInfo defer h.G().CTrace(ctx, fmt.Sprintf("TeamCreateFancy(%s)", teamInfo.Name), &err)() arg2 := keybase1.TeamCreateWithSettingsArg{ Name: teamInfo.Name, SessionID: arg.SessionID, Settings: teamInfo.OpenSettings, JoinSubteam: teamInfo.JoinSubteam, } teamCreateRes, err := h.TeamCreateWithSettings(ctx, arg2) if err != nil { return teamID, err } teamID = teamCreateRes.TeamID var errs []error if teamInfo.Description != "" { err = teams.SetTeamShowcase(ctx, h.G().ExternalG(), teamID, nil, /* showcase */ &teamInfo.Description, nil /* anyMemberShowcase */) if err != nil { errs = append(errs, err) mctx.Error("SetTeamShowcase failed with: %s", err) } } if teamInfo.ProfileShowcase { err = teams.SetTeamMemberShowcase(ctx, h.G().ExternalG(), teamID, true /* isShowcased */) if err != nil { errs = append(errs, err) mctx.Error("SetTeamMemberShowcase failed with: %s", err) } } if teamInfo.Avatar != nil { avatar := teamInfo.Avatar arg3 := keybase1.UploadTeamAvatarArg{ Teamname: teamInfo.Name, Filename: avatar.AvatarFilename, Crop: avatar.Crop, SendChatNotification: false, } err = teams.ChangeTeamAvatar(mctx, arg3) if err != nil { errs = append(errs, err) } } uid := gregor1.UID(h.G().GetMyUID().ToBytes()) for _, topicName := range teamInfo.ChatChannels { _, _, err = h.G().ChatHelper.NewConversation(ctx, uid, teamInfo.Name, &topicName, chat1.TopicType_CHAT, chat1.ConversationMembersType_TEAM, keybase1.TLFVisibility_PRIVATE) if err != nil { errs = append(errs, err) } } for _, subteamName := range teamInfo.Subteams { name := teamInfo.Name + "." + subteamName _, err = h.TeamCreate(ctx, keybase1.TeamCreateArg{SessionID: arg.SessionID, Name: name}) if err != nil { errs = append(errs, err) } } if len(teamInfo.Users) > 0 { arg4 := keybase1.TeamAddMembersMultiRoleArg{ SessionID: arg.SessionID, TeamID: teamID, Users: teamInfo.Users, SendChatNotification: false, EmailInviteMessage: teamInfo.EmailInviteMessage, // Add users to the default channels. AddToChannels: nil, } unaddedUsers, err := h.TeamAddMembersMultiRole(ctx, arg4) if err != nil { errs = append(errs, err) } if len(unaddedUsers.NotAdded) > 0 { errs = append(errs, fmt.Errorf("could not add members to team: %v", unaddedUsers.NotAdded)) } } if errs == nil { return teamID, nil } return teamID, libkb.CombineErrors(errs...) } func (h *TeamsHandler) TeamCreateWithSettings(ctx context.Context, arg keybase1.TeamCreateWithSettingsArg) (res keybase1.TeamCreateResult, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamCreate(%s)", arg.Name), &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return res, err } teamName, err := keybase1.TeamNameFromString(arg.Name) if err != nil { return res, err } if teamName.Depth() == 0 { return res, fmt.Errorf("empty team name") } if !teamName.IsRootTeam() { h.G().Log.CDebugf(ctx, "TeamCreate: creating a new subteam: %s", arg.Name) parentName, err := teamName.Parent() if err != nil { return res, err } addSelfAs := keybase1.TeamRole_WRITER // writer is enough to init chat channel if arg.JoinSubteam { // but if user wants to stay in team, add as admin. addSelfAs = keybase1.TeamRole_ADMIN } teamID, err := teams.CreateSubteam(ctx, h.G().ExternalG(), string(teamName.LastPart()), parentName, addSelfAs) if err != nil { return res, err } res.TeamID = *teamID // join the team to send the Create message h.G().Log.CDebugf(ctx, "TeamCreate: created subteam %s with self in as %v", arg.Name, addSelfAs) username := h.G().Env.GetUsername().String() res.ChatSent = teams.SendTeamChatCreateMessage(ctx, h.G().ExternalG(), teamName.String(), username) res.CreatorAdded = true if !arg.JoinSubteam { h.G().Log.CDebugf(ctx, "TeamCreate: leaving just-created subteam %s", arg.Name) if err := teams.Leave(ctx, h.G().ExternalG(), teamName.String(), false); err != nil { h.G().Log.CDebugf(ctx, "TeamCreate: error leaving new subteam %s: %s", arg.Name, err) return res, err } h.G().Log.CDebugf(ctx, "TeamCreate: left just-created subteam %s", arg.Name) res.CreatorAdded = false } } else { teamID, err := teams.CreateRootTeam(ctx, h.G().ExternalG(), teamName.String(), arg.Settings) if err != nil { return res, err } res.TeamID = *teamID res.CreatorAdded = true // send system message that team was created res.ChatSent = teams.SendTeamChatCreateMessage(ctx, h.G().ExternalG(), teamName.String(), h.G().Env.GetUsername().String()) } return res, nil } func (h *TeamsHandler) TeamGet(ctx context.Context, arg keybase1.TeamGetArg) (res keybase1.TeamDetails, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamGet(%s)", arg.Name), &err)() t, err := teams.GetAnnotatedTeamByName(ctx, h.G().ExternalG(), arg.Name) if err != nil { return res, err } return t.ToLegacyTeamDetails(), nil } func (h *TeamsHandler) TeamGetByID(ctx context.Context, arg keybase1.TeamGetByIDArg) (res keybase1.TeamDetails, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamGetByID(%s)", arg.Id), &err)() t, err := teams.GetAnnotatedTeam(ctx, h.G().ExternalG(), arg.Id) if err != nil { return res, err } return t.ToLegacyTeamDetails(), nil } func (h *TeamsHandler) GetAnnotatedTeam(ctx context.Context, arg keybase1.TeamID) (res keybase1.AnnotatedTeam, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("GetAnnotatedTeam(%s)", arg), &err)() return teams.GetAnnotatedTeam(ctx, h.G().ExternalG(), arg) } func (h *TeamsHandler) GetAnnotatedTeamByName(ctx context.Context, arg string) (res keybase1.AnnotatedTeam, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("GetAnnotatedTeam(%s)", arg), &err)() return teams.GetAnnotatedTeamByName(ctx, h.G().ExternalG(), arg) } func (h *TeamsHandler) TeamGetMembersByID(ctx context.Context, arg keybase1.TeamGetMembersByIDArg) (res []keybase1.TeamMemberDetails, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamGetMembersByID(%s)", arg.Id), &err)() return teams.GetAnnotatedTeamMembers(ctx, h.G().ExternalG(), arg.Id) } func (h *TeamsHandler) TeamListUnverified(ctx context.Context, arg keybase1.TeamListUnverifiedArg) (res keybase1.AnnotatedTeamList, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamList(%s)", arg.UserAssertion), &err)() x, err := teams.ListTeamsUnverified(ctx, h.G().ExternalG(), arg) if err != nil { return keybase1.AnnotatedTeamList{}, err } return *x, nil } func (h *TeamsHandler) TeamListTeammates(ctx context.Context, arg keybase1.TeamListTeammatesArg) (res keybase1.AnnotatedTeamList, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamListTeammates(%t)", arg.IncludeImplicitTeams), &err)() x, err := teams.ListAll(ctx, h.G().ExternalG(), arg) if err != nil { return keybase1.AnnotatedTeamList{}, err } return *x, nil } func (h *TeamsHandler) TeamListVerified(ctx context.Context, arg keybase1.TeamListVerifiedArg) (res keybase1.AnnotatedTeamList, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamListVerified(%s)", arg.UserAssertion), &err)() x, err := teams.ListTeamsVerified(ctx, h.G().ExternalG(), arg) if err != nil { return keybase1.AnnotatedTeamList{}, err } return *x, nil } func (h *TeamsHandler) TeamGetSubteamsUnverified(ctx context.Context, arg keybase1.TeamGetSubteamsUnverifiedArg) (res keybase1.SubteamListResult, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamGetSubteamsUnverified(%s)", arg.Name), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return teams.ListSubteamsUnverified(mctx, arg.Name) } func (h *TeamsHandler) TeamListSubteamsRecursive(ctx context.Context, arg keybase1.TeamListSubteamsRecursiveArg) (res []keybase1.TeamIDAndName, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamListSubteamsRecursive(%s)", arg.ParentTeamName), &err)() return teams.ListSubteamsRecursive(ctx, h.G().ExternalG(), arg.ParentTeamName, arg.ForceRepoll) } func (h *TeamsHandler) TeamAddMember(ctx context.Context, arg keybase1.TeamAddMemberArg) (res keybase1.TeamAddMemberResult, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamAddMember(%s,username=%q,email=%q,phone=%q)", arg.TeamID, arg.Username, arg.Email, arg.Phone), &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return res, err } assertion := arg.Username if arg.Email != "" || arg.Phone != "" { var assertionURL libkb.AssertionURL var err error if arg.Email != "" { assertionURL, err = libkb.ParseAssertionURLKeyValue(externals.MakeStaticAssertionContext(ctx), "email", arg.Email, true) } else { assertionURL, err = libkb.ParseAssertionURLKeyValue(externals.MakeStaticAssertionContext(ctx), "phone", arg.Phone, true) } if err != nil { return res, err } assertion = assertionURL.String() } result, err := teams.AddMemberByID(ctx, h.G().ExternalG(), arg.TeamID, assertion, arg.Role, arg.BotSettings, arg.EmailInviteMessage) if err != nil { return res, err } if !arg.SendChatNotification { return result, nil } if result.Invited { return result, nil } result.ChatSending = true go func() { ctx := libkb.WithLogTag(context.Background(), "BG") err := teams.SendTeamChatWelcomeMessage(ctx, h.G().ExternalG(), arg.TeamID, "", result.User.Username, chat1.ConversationMembersType_TEAM, arg.Role) if err != nil { h.G().Log.CDebugf(ctx, "send team welcome message: error: %v", err) } else { h.G().Log.CDebugf(ctx, "send team welcome message: success") } }() return result, nil } // TeamAddMembers returns err if adding members to team failed. // Adding members is "all-or-nothing", except in the case that the 1st attempt // fails due to some users having restrictive contact settings. In this // situation, we retry adding just the non-restricted members. If this 2nd attempt // succeeds, err=nil and TeamAddMembersResult contains a list of the users that // weren't added. If the 2nd attempt fails, then an err is returned as usual. func (h *TeamsHandler) TeamAddMembers(ctx context.Context, arg keybase1.TeamAddMembersArg) (res keybase1.TeamAddMembersResult, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamAddMembers(%+v", arg), &err)() var users []keybase1.UserRolePair for _, a := range arg.Assertions { users = append(users, keybase1.UserRolePair{Assertion: a, Role: arg.Role}) } arg2 := keybase1.TeamAddMembersMultiRoleArg{ TeamID: arg.TeamID, Users: users, SendChatNotification: arg.SendChatNotification, EmailInviteMessage: arg.EmailInviteMessage, } return h.TeamAddMembersMultiRole(ctx, arg2) } func (h *TeamsHandler) TeamAddMembersMultiRole(ctx context.Context, arg keybase1.TeamAddMembersMultiRoleArg) (res keybase1.TeamAddMembersResult, err error) { ctx = libkb.WithLogTag(ctx, "TM") debugString := "0" if len(arg.Users) > 0 { debugString = fmt.Sprintf("'%v'", arg.Users[0].Assertion) if len(arg.Users) > 1 { debugString = fmt.Sprintf("'%v' + %v more", arg.Users[0].Assertion, len(arg.Users)-1) } } defer h.G().CTrace(ctx, fmt.Sprintf("TeamAddMembers(%s, %s)", arg.TeamID, debugString), &err)() if len(arg.Users) == 0 { return res, fmt.Errorf("attempted to add 0 users to a team") } if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return res, err } added, notAdded, err := teams.AddMembers(ctx, h.G().ExternalG(), arg.TeamID, arg.Users, arg.EmailInviteMessage) switch err := err.(type) { case nil: case teams.AddMembersError: switch e := err.Err.(type) { case libkb.IdentifySummaryError: // Return the IdentifySummaryError, which is exportable. // Frontend presents this error specifically. return res, e default: return res, err } default: return res, err } res = keybase1.TeamAddMembersResult{NotAdded: notAdded} // AddMembers succeeded if arg.SendChatNotification { go func() { h.G().Log.CDebugf(ctx, "sending team welcome messages") ctx := libkb.WithLogTag(context.Background(), "BG") for i, res := range added { h.G().Log.CDebugf(ctx, "team welcome message for i:%v assertion:%v username:%v invite:%v, role: %v", i, arg.Users[i].Assertion, res.Username, res.Invite, arg.Users[i].Role) if !res.Invite && !res.Username.IsNil() { err := teams.SendTeamChatWelcomeMessage(ctx, h.G().ExternalG(), arg.TeamID, "", res.Username.String(), chat1.ConversationMembersType_TEAM, arg.Users[i].Role) if err != nil { h.G().Log.CDebugf(ctx, "send team welcome message [%v] err: %v", i, err) } else { h.G().Log.CDebugf(ctx, "send team welcome message [%v] success", i) } } else { h.G().Log.CDebugf(ctx, "send team welcome message [%v] skipped", i) } } h.G().Log.CDebugf(ctx, "done sending team welcome messages") }() } var usernames []string for _, user := range arg.Users { // the server handles bot membership, skip these users if !user.Role.IsBotLike() { usernames = append(usernames, user.Assertion) } } uid := gregor1.UID(h.G().GetMyUID().ToBytes()) for _, convIDStr := range arg.AddToChannels { convID, err := chat1.MakeConvID(convIDStr) if err != nil { return res, err } err = h.G().ChatHelper.BulkAddToConv(ctx, uid, convID, usernames) if err != nil { return res, err } } return res, nil } func (h *TeamsHandler) TeamRemoveMember(ctx context.Context, arg keybase1.TeamRemoveMemberArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamRemoveMember(%s, %+v)", arg.TeamID, arg), &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return err } return teams.RemoveMemberSingle(ctx, h.G().ExternalG(), arg.TeamID, arg.Member) } func (h *TeamsHandler) TeamRemoveMembers(ctx context.Context, arg keybase1.TeamRemoveMembersArg) (res keybase1.TeamRemoveMembersResult, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamRemoveMembers(%s, %v)", arg.TeamID, arg), &err)() if len(arg.Members) == 0 { return res, errors.New("no members provided to TeamRemoveMembers") } if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return res, err } return teams.RemoveMembers(ctx, h.G().ExternalG(), arg.TeamID, arg.Members, arg.NoErrorOnPartialFailure) } func (h *TeamsHandler) TeamEditMember(ctx context.Context, arg keybase1.TeamEditMemberArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamEditMember(%s,%s,%s)", arg.Name, arg.Username, arg.Role), &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return err } return teams.EditMember(ctx, h.G().ExternalG(), arg.Name, arg.Username, arg.Role, arg.BotSettings) } func (h *TeamsHandler) TeamEditMembers(ctx context.Context, arg keybase1.TeamEditMembersArg) (res keybase1.TeamEditMembersResult, err error) { ctx = libkb.WithLogTag(ctx, "TM") debugString := "0" if len(arg.Users) > 0 { debugString = fmt.Sprintf("'%v, %v'", arg.Users[0].Assertion, arg.Users[0].Role) if len(arg.Users) > 1 { debugString = fmt.Sprintf("'%v' + %v more", arg.Users[0].Assertion, len(arg.Users)-1) } } defer h.G().CTrace(ctx, fmt.Sprintf("TeamEditMembers(%s, %s)", arg.TeamID, debugString), &err)() if len(arg.Users) == 0 { return res, nil } if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return res, err } return teams.EditMembers(ctx, h.G().ExternalG(), arg.TeamID, arg.Users) } func (h *TeamsHandler) TeamSetBotSettings(ctx context.Context, arg keybase1.TeamSetBotSettingsArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamSetBotSettings(%s,%s,%v)", arg.Name, arg.Username, arg.BotSettings), &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return err } return teams.SetBotSettings(ctx, h.G().ExternalG(), arg.Name, arg.Username, arg.BotSettings) } func (h *TeamsHandler) TeamGetBotSettings(ctx context.Context, arg keybase1.TeamGetBotSettingsArg) (res keybase1.TeamBotSettings, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamGetBotSettings(%s,%s)", arg.Name, arg.Username), &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return res, err } return teams.GetBotSettings(ctx, h.G().ExternalG(), arg.Name, arg.Username) } func (h *TeamsHandler) TeamLeave(ctx context.Context, arg keybase1.TeamLeaveArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamLeave(%s)", arg.Name), &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return err } return teams.Leave(ctx, h.G().ExternalG(), arg.Name, arg.Permanent) } func (h *TeamsHandler) TeamRename(ctx context.Context, arg keybase1.TeamRenameArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamRename(%s)", arg.PrevName), &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return err } return teams.RenameSubteam(ctx, h.G().ExternalG(), arg.PrevName, arg.NewName) } func (h *TeamsHandler) TeamAcceptInvite(ctx context.Context, arg keybase1.TeamAcceptInviteArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, "TeamAcceptInvite", &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return err } // If token looks at all like Seitan, don't pass to functions that might // log or send to server. parsedToken, wasSeitany := teams.ParseSeitanTokenFromPaste(arg.Token) if wasSeitany { mctx := h.MetaContext(ctx) ui := h.getTeamsUI(arg.SessionID) _, err = teams.ParseAndAcceptSeitanToken(mctx, ui, parsedToken) return err } // Fallback to legacy email TOFU token return teams.AcceptServerTrustInvite(ctx, h.G().ExternalG(), arg.Token) } func (h *TeamsHandler) TeamRequestAccess(ctx context.Context, arg keybase1.TeamRequestAccessArg) (res keybase1.TeamRequestAccessResult, err error) { ctx = libkb.WithLogTag(ctx, "TM") h.G().CTrace(ctx, "TeamRequestAccess", &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return keybase1.TeamRequestAccessResult{}, err } return teams.RequestAccess(ctx, h.G().ExternalG(), arg.Name) } func (h *TeamsHandler) TeamAcceptInviteOrRequestAccess(ctx context.Context, arg keybase1.TeamAcceptInviteOrRequestAccessArg) (res keybase1.TeamAcceptOrRequestResult, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, "TeamAcceptInviteOrRequestAccess", &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return res, err } ui := h.getTeamsUI(arg.SessionID) // If token looks at all like Seitan, don't pass to functions that might log or send to server. maybeSeitan, keepSecret := teams.ParseSeitanTokenFromPaste(arg.TokenOrName) if keepSecret { mctx := h.MetaContext(ctx) _, err = teams.ParseAndAcceptSeitanToken(mctx, ui, maybeSeitan) return keybase1.TeamAcceptOrRequestResult{WasSeitan: true, WasToken: true}, err } return teams.TeamAcceptInviteOrRequestAccess(ctx, h.G().ExternalG(), ui, arg.TokenOrName) } func (h *TeamsHandler) TeamListRequests(ctx context.Context, arg keybase1.TeamListRequestsArg) (res []keybase1.TeamJoinRequest, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, "TeamListRequests", &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return nil, err } return teams.ListRequests(ctx, h.G().ExternalG(), arg.TeamName) } func (h *TeamsHandler) TeamListMyAccessRequests(ctx context.Context, arg keybase1.TeamListMyAccessRequestsArg) (res []keybase1.TeamName, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, "TeamListMyAccessRequests", &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return nil, err } return teams.ListMyAccessRequests(ctx, h.G().ExternalG(), arg.TeamName) } func (h *TeamsHandler) TeamIgnoreRequest(ctx context.Context, arg keybase1.TeamIgnoreRequestArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, "TeamIgnoreRequest", &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return err } return teams.IgnoreRequest(ctx, h.G().ExternalG(), arg.Name, arg.Username) } func (h *TeamsHandler) TeamTreeUnverified(ctx context.Context, arg keybase1.TeamTreeUnverifiedArg) (res keybase1.TeamTreeResult, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, "TeamTreeUnverified", &err)() return teams.TeamTreeUnverified(ctx, h.G().ExternalG(), arg) } func (h *TeamsHandler) TeamDelete(ctx context.Context, arg keybase1.TeamDeleteArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamDelete(%s)", arg.TeamID), &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return err } ui := h.getTeamsUI(arg.SessionID) return teams.Delete(ctx, h.G().ExternalG(), ui, arg.TeamID) } func (h *TeamsHandler) TeamSetSettings(ctx context.Context, arg keybase1.TeamSetSettingsArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamSetSettings(%s)", arg.TeamID), &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return err } return teams.ChangeTeamSettingsByID(ctx, h.G().ExternalG(), arg.TeamID, arg.Settings) } func (h *TeamsHandler) LoadTeamPlusApplicationKeys(ctx context.Context, arg keybase1.LoadTeamPlusApplicationKeysArg) (res keybase1.TeamPlusApplicationKeys, err error) { ctx = libkb.WithLogTag(ctx, "TM") ctx = libkb.WithLogTag(ctx, "LTPAK") defer h.G().CTrace(ctx, fmt.Sprintf("LoadTeamPlusApplicationKeys(%s)", arg.Id), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) loader := func(mctx libkb.MetaContext) (any, error) { return teams.LoadTeamPlusApplicationKeys(ctx, h.G().ExternalG(), arg.Id, arg.Application, arg.Refreshers, arg.IncludeKBFSKeys) } // argKey is a copy of arg that's going to be used for a cache key, so clear out // refreshers and sessionID, since they don't affect the cache key value. argKey := arg argKey.Refreshers = keybase1.TeamRefreshers{} argKey.SessionID = 0 argKey.IncludeKBFSKeys = false servedRes, err := h.service.offlineRPCCache.Serve(mctx, arg.Oa, offline.Version(1), "teams.loadTeamPlusApplicationKeys", true, argKey, &res, loader) if err != nil { return keybase1.TeamPlusApplicationKeys{}, err } if s, ok := servedRes.(keybase1.TeamPlusApplicationKeys); ok { res = s } return res, nil } func (h *TeamsHandler) TeamCreateSeitanToken(ctx context.Context, arg keybase1.TeamCreateSeitanTokenArg) (token keybase1.SeitanIKey, err error) { ctx = libkb.WithLogTag(ctx, "TM") if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return "", err } return teams.CreateSeitanToken(ctx, h.G().ExternalG(), arg.Teamname, arg.Role, arg.Label) } func (h *TeamsHandler) TeamCreateSeitanTokenV2(ctx context.Context, arg keybase1.TeamCreateSeitanTokenV2Arg) (token keybase1.SeitanIKeyV2, err error) { ctx = libkb.WithLogTag(ctx, "TM") if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return "", err } return teams.CreateSeitanTokenV2(ctx, h.G().ExternalG(), arg.Teamname, arg.Role, arg.Label) } func (h *TeamsHandler) TeamCreateSeitanInvitelink(ctx context.Context, arg keybase1.TeamCreateSeitanInvitelinkArg, ) (invitelink keybase1.Invitelink, err error) { ctx = libkb.WithLogTag(ctx, "TM") if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return invitelink, err } mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return teams.CreateInvitelink(mctx, arg.Teamname, arg.Role, arg.MaxUses, arg.Etime) } func (h *TeamsHandler) TeamCreateSeitanInvitelinkWithDuration(ctx context.Context, arg keybase1.TeamCreateSeitanInvitelinkWithDurationArg, ) (invitelink keybase1.Invitelink, err error) { ctx = libkb.WithLogTag(ctx, "TM") if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return invitelink, err } mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) var etimeUnixPtr *keybase1.UnixTime if arg.ExpireAfter != nil { etime, err := kbtime.AddLongDuration(h.G().Clock().Now(), *arg.ExpireAfter) if err != nil { return invitelink, err } mctx.Debug("Etime from duration %q is: %s", arg.ExpireAfter, etime.String()) etimeUnix := keybase1.ToUnixTime(etime) etimeUnixPtr = &etimeUnix } return teams.CreateInvitelink(mctx, arg.Teamname, arg.Role, arg.MaxUses, etimeUnixPtr) } func (h *TeamsHandler) GetTeamRootID(ctx context.Context, id keybase1.TeamID) (keybase1.TeamID, error) { ctx = libkb.WithLogTag(ctx, "TM") return teams.GetRootID(ctx, h.G().ExternalG(), id) } func (h *TeamsHandler) LookupImplicitTeam(ctx context.Context, arg keybase1.LookupImplicitTeamArg) (res keybase1.LookupImplicitTeamRes, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("LookupImplicitTeam(%s)", arg.Name), &err)() var team *teams.Team team, res.Name, res.DisplayName, err = teams.LookupImplicitTeam(ctx, h.G().ExternalG(), arg.Name, arg.Public, teams.ImplicitTeamOptions{}) if err == nil { res.TeamID = team.ID res.TlfID = team.LatestKBFSTLFID() } return res, err } func (h *TeamsHandler) LookupOrCreateImplicitTeam(ctx context.Context, arg keybase1.LookupOrCreateImplicitTeamArg) (res keybase1.LookupImplicitTeamRes, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("LookupOrCreateImplicitTeam(%s)", arg.Name), &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return res, err } var team *teams.Team team, res.Name, res.DisplayName, err = teams.LookupOrCreateImplicitTeam(ctx, h.G().ExternalG(), arg.Name, arg.Public) if err == nil { res.TeamID = team.ID res.TlfID = team.LatestKBFSTLFID() } return res, err } func (h *TeamsHandler) TeamReAddMemberAfterReset(ctx context.Context, arg keybase1.TeamReAddMemberAfterResetArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamReAddMemberAfterReset(%s)", arg.Id), &err)() if err := assertLoggedIn(ctx, h.G().ExternalG()); err != nil { return err } return teams.ReAddMemberAfterReset(ctx, h.G().ExternalG(), arg.Id, arg.Username) } func (h *TeamsHandler) TeamAddEmailsBulk(ctx context.Context, arg keybase1.TeamAddEmailsBulkArg) (res keybase1.BulkRes, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamAddEmailsBulk(%s)", arg.Name), &err)() return teams.AddEmailsBulk(ctx, h.G().ExternalG(), arg.Name, arg.Emails, arg.Role) } func (h *TeamsHandler) GetTeamShowcase(ctx context.Context, teamID keybase1.TeamID) (ret keybase1.TeamShowcase, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("GetTeamShowcase(%s)", teamID), &err)() return teams.GetTeamShowcase(ctx, h.G().ExternalG(), teamID) } func (h *TeamsHandler) GetTeamAndMemberShowcase(ctx context.Context, id keybase1.TeamID) (ret keybase1.TeamAndMemberShowcase, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("GetTeamAndMemberShowcase(%s)", id), &err)() return teams.GetTeamAndMemberShowcase(ctx, h.G().ExternalG(), id) } func (h *TeamsHandler) SetTeamShowcase(ctx context.Context, arg keybase1.SetTeamShowcaseArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("SetTeamShowcase(%s)", arg.TeamID), &err)() err = teams.SetTeamShowcase(ctx, h.G().ExternalG(), arg.TeamID, arg.IsShowcased, arg.Description, arg.AnyMemberShowcase) return err } func (h *TeamsHandler) SetTeamMemberShowcase(ctx context.Context, arg keybase1.SetTeamMemberShowcaseArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("SetTeamMemberShowcase(%s)", arg.TeamID), &err)() err = teams.SetTeamMemberShowcase(ctx, h.G().ExternalG(), arg.TeamID, arg.IsShowcased) return err } func (h *TeamsHandler) CanUserPerform(ctx context.Context, teamname string) (ret keybase1.TeamOperation, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("CanUserPerform(%s)", teamname), &err)() // We never want to return an error from this, the frontend has no proper reaction to an error from // this RPC call. We retry until we work. for { if ret, err = teams.CanUserPerform(ctx, h.G().ExternalG(), teamname); err == nil { break } select { case <-ctx.Done(): return ret, ctx.Err() default: } time.Sleep(5 * time.Second) } return ret, err } func (h *TeamsHandler) TeamRotateKey(ctx context.Context, arg keybase1.TeamRotateKeyArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamRotateKey(%v)", arg.TeamID), &err)() return teams.RotateKey(ctx, h.G().ExternalG(), arg) } func (h *TeamsHandler) TeamDebug(ctx context.Context, teamID keybase1.TeamID) (res keybase1.TeamDebugRes, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamDebug(%v)", teamID), &err)() return teams.TeamDebug(ctx, h.G().ExternalG(), teamID) } func (h *TeamsHandler) GetTarsDisabled(ctx context.Context, teamID keybase1.TeamID) (res bool, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("GetTarsDisabled(%s)", teamID), &err)() return teams.GetTarsDisabled(ctx, h.G().ExternalG(), teamID) } func (h *TeamsHandler) SetTarsDisabled(ctx context.Context, arg keybase1.SetTarsDisabledArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("SetTarsDisabled(%s,%t)", arg.TeamID, arg.Disabled), &err)() return teams.SetTarsDisabled(ctx, h.G().ExternalG(), arg.TeamID, arg.Disabled) } func (h *TeamsHandler) TeamProfileAddList(ctx context.Context, arg keybase1.TeamProfileAddListArg) (res []keybase1.TeamProfileAddEntry, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TeamProfileAddList(%v)", arg.Username), &err)() return teams.TeamProfileAddList(ctx, h.G().ExternalG(), arg.Username) } func (h *TeamsHandler) UploadTeamAvatar(ctx context.Context, arg keybase1.UploadTeamAvatarArg) (err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("UploadTeamAvatar(%s,%s)", arg.Teamname, arg.Filename), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return teams.ChangeTeamAvatar(mctx, arg) } func (h *TeamsHandler) TryDecryptWithTeamKey(ctx context.Context, arg keybase1.TryDecryptWithTeamKeyArg) (ret []byte, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("TryDecryptWithTeamKey(teamID:%s)", arg.TeamID), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return teams.TryDecryptWithTeamKey(mctx, arg) } func (h *TeamsHandler) FindNextMerkleRootAfterTeamRemoval(ctx context.Context, arg keybase1.FindNextMerkleRootAfterTeamRemovalArg) (res keybase1.NextMerkleRootRes, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("FindNextMerkleRootAfterTeamRemoval(%+v)", arg), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return libkb.FindNextMerkleRootAfterTeamRemoval(mctx, arg) } func (h *TeamsHandler) FindNextMerkleRootAfterTeamRemovalBySigningKey(ctx context.Context, arg keybase1.FindNextMerkleRootAfterTeamRemovalBySigningKeyArg) (res keybase1.NextMerkleRootRes, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("FindNextMerkleRootAfterTeamRemovalBySigningKey(%+v)", arg), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return teams.FindNextMerkleRootAfterRemoval(mctx, arg) } func (h *TeamsHandler) ProfileTeamLoad(ctx context.Context, arg keybase1.LoadTeamArg) (res keybase1.ProfileTeamLoadRes, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("ProfileTeamLoad(%+v)", arg), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return teams.ProfileTeamLoad(mctx, arg) } func (h *TeamsHandler) Ftl(ctx context.Context, arg keybase1.FastTeamLoadArg) (res keybase1.FastTeamLoadRes, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("Ftl(%+v)", arg), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return teams.FTL(mctx, arg) } func (h *TeamsHandler) GetTeamID(ctx context.Context, teamName string) (res keybase1.TeamID, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("GetTeamIDByName(%s)", teamName), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return teams.GetTeamIDByNameRPC(mctx, teamName) } func (h *TeamsHandler) GetTeamName(ctx context.Context, teamID keybase1.TeamID) (res keybase1.TeamName, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("GetTeamNameByID(%s)", teamID), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return teams.ResolveIDToName(mctx.Ctx(), mctx.G(), teamID) } func (h *TeamsHandler) GetTeamRoleMap(ctx context.Context) (res keybase1.TeamRoleMapAndVersion, err error) { mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return mctx.G().GetTeamRoleMapManager().Get(mctx, true /* retry on fail */) } func (h *TeamsHandler) GetUntrustedTeamInfo(ctx context.Context, name keybase1.TeamName) (info keybase1.UntrustedTeamInfo, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("GetUntrustedTeamInfo(%s)", name), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return teams.GetUntrustedTeamInfo(mctx, name) } func (h *TeamsHandler) LoadTeamTreeMembershipsAsync(ctx context.Context, arg keybase1.LoadTeamTreeMembershipsAsyncArg, ) (res keybase1.TeamTreeInitial, err error) { ctx = libkb.WithLogTag(ctx, "TM") ctx = libkb.WithLogTag(ctx, "TMTREE") defer h.G().CTrace(ctx, fmt.Sprintf("LoadTeamTreeMembershipsAsync(%s, %s, %d)", arg.TeamID, arg.Username, arg.SessionID), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) loader, err := teams.NewTreeloader(mctx, arg.Username, arg.TeamID, arg.SessionID, true /* includeAncestors */) if err != nil { return res, err } err = loader.LoadAsync(mctx) if err != nil { return res, err } return keybase1.TeamTreeInitial{Guid: arg.SessionID}, nil } func (h *TeamsHandler) GetInviteLinkDetails(ctx context.Context, inviteID keybase1.TeamInviteID) (details keybase1.InviteLinkDetails, err error) { ctx = libkb.WithLogTag(ctx, "TM") defer h.G().CTrace(ctx, fmt.Sprintf("GetInviteLinkDetails(%s)", inviteID), &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return teams.GetInviteLinkDetails(mctx, inviteID) } func (h *TeamsHandler) FindAssertionsInTeamNoResolve(ctx context.Context, arg keybase1.FindAssertionsInTeamNoResolveArg) (ret []string, err error) { ctx = libkb.WithLogTag(ctx, "TM") traceMsg := fmt.Sprintf("FindAssertionsInTeam(%s, %d)", arg.TeamID, len(arg.Assertions)) defer h.G().CTrace(ctx, traceMsg, &err)() mctx := libkb.NewMetaContext(ctx, h.G().ExternalG()) return teams.FindAssertionsInTeamNoResolve(mctx, arg.TeamID, arg.Assertions) }