/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/chat/teams.go
907 строк
29 KB
zoom-ua
remove golang.org/x/net/context in favor of context (#28708)
17 дек 2025, 18:24
Не верифицирован
17 дек 2025, 18:24
67b0ffe
Код
Авторство
О чём код?
package chat import ( "context" "errors" "fmt" "strings" lru "github.com/hashicorp/golang-lru" "github.com/keybase/client/go/chat/globals" "github.com/keybase/client/go/chat/types" "github.com/keybase/client/go/chat/utils" "github.com/keybase/client/go/libkb" "github.com/keybase/client/go/protocol/chat1" "github.com/keybase/client/go/protocol/gregor1" "github.com/keybase/client/go/protocol/keybase1" "github.com/keybase/client/go/teambot" "github.com/keybase/client/go/teams" ) func getTeamCryptKey(mctx libkb.MetaContext, team *teams.Team, generation keybase1.PerTeamKeyGeneration, public, kbfsEncrypted bool, botUID *gregor1.UID, forEncryption bool, ) (res types.CryptKey, err error) { if public { return publicCryptKey, nil } if teambot.CurrentUserIsBot(mctx, botUID) { if kbfsEncrypted { return res, fmt.Errorf("TeambotKeys not supported by KBFS") } keyer := mctx.G().GetTeambotBotKeyer() if forEncryption { return keyer.GetLatestTeambotKey(mctx, team.ID, keybase1.TeamApplication_CHAT) } return keyer.GetTeambotKeyAtGeneration(mctx, team.ID, keybase1.TeamApplication_CHAT, keybase1.TeambotKeyGeneration(generation)) } if kbfsEncrypted { if botUID != nil { return res, fmt.Errorf("TeambotKeys not supported by KBFS") } kbfsKeys := team.KBFSCryptKeys(mctx.Ctx(), keybase1.TeamApplication_CHAT) for _, key := range kbfsKeys { if key.Generation() == int(generation) { return key, nil } } return res, NewDecryptionKeyNotFoundError(int(generation), kbfsEncrypted, public) } appKey, err := team.ChatKeyAtGeneration(mctx.Ctx(), generation) if err != nil { return res, err } // Need to convert this key in to a TeambotKey if botUID != nil { res, _, err = mctx.G().GetTeambotMemberKeyer().GetOrCreateTeambotKey( mctx, team.ID, *botUID, appKey) return res, err } return appKey, nil } func encryptionKeyViaFTL(m libkb.MetaContext, name string, tlfID chat1.TLFID, membersType chat1.ConversationMembersType, ) (res types.CryptKey, ni types.NameInfo, err error) { ftlRes, err := getKeyViaFTL(m, name, tlfID, membersType, 0) if err != nil { return res, ni, err } ni = types.NameInfo{ ID: tlfID, CanonicalName: ftlRes.Name.String(), } return ftlRes.ApplicationKeys[0], ni, nil } func decryptionKeyViaFTL(m libkb.MetaContext, tlfID chat1.TLFID, membersType chat1.ConversationMembersType, keyGeneration int, ) (res types.CryptKey, err error) { // We don't pass a `name` during decryption. ftlRes, err := getKeyViaFTL(m, "" /*name*/, tlfID, membersType, keyGeneration) if err != nil { return nil, err } return ftlRes.ApplicationKeys[0], nil } func getKeyViaFTL(mctx libkb.MetaContext, name string, tlfID chat1.TLFID, membersType chat1.ConversationMembersType, keyGeneration int, ) (res keybase1.FastTeamLoadRes, err error) { defer mctx.Trace(fmt.Sprintf("getKeyViaFTL(%s,%v,%d)", name, tlfID, keyGeneration), &err)() var teamID keybase1.TeamID switch membersType { case chat1.ConversationMembersType_TEAM, chat1.ConversationMembersType_IMPTEAMNATIVE: teamID, err = keybase1.TeamIDFromString(tlfID.String()) if err != nil { return res, err } case chat1.ConversationMembersType_IMPTEAMUPGRADE: teamID, err = tlfIDToTeamID.Lookup(mctx, tlfID, mctx.G().API) if err != nil { return res, err } } // The `name` parameter is optional since subteams can be renamed and // messages with the old name must be successfully decrypted. var teamNamePtr *keybase1.TeamName if name != "" { teamName, err := keybase1.TeamNameFromString(name) if err != nil { return res, err } teamNamePtr = &teamName } arg := keybase1.FastTeamLoadArg{ ID: teamID, Public: false, Applications: []keybase1.TeamApplication{keybase1.TeamApplication_CHAT}, AssertTeamName: teamNamePtr, } if keyGeneration > 0 { arg.KeyGenerationsNeeded = []keybase1.PerTeamKeyGeneration{keybase1.PerTeamKeyGeneration(keyGeneration)} } else { arg.NeedLatestKey = true } res, err = mctx.G().GetFastTeamLoader().Load(mctx, arg) if err != nil { return res, err } n := len(res.ApplicationKeys) if n != 1 { return res, NewFTLError(fmt.Sprintf("wrong number of keys back from FTL; wanted 1, but got %d", n)) } if keyGeneration > 0 && res.ApplicationKeys[0].KeyGeneration != keybase1.PerTeamKeyGeneration(keyGeneration) { return res, NewFTLError(fmt.Sprintf("wrong generation back from FTL; wanted %d but got %d", keyGeneration, res.ApplicationKeys[0].KeyGeneration)) } if res.ApplicationKeys[0].Application != keybase1.TeamApplication_CHAT { return res, NewFTLError(fmt.Sprintf("wrong application; wanted %d but got %d", keybase1.TeamApplication_CHAT, res.ApplicationKeys[0].Application)) } return res, nil } func loadTeamForDecryption(mctx libkb.MetaContext, loader *TeamLoader, name string, teamID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, keyGeneration int, kbfsEncrypted bool, botUID *gregor1.UID, ) (*teams.Team, error) { var refreshers keybase1.TeamRefreshers if !public && !teambot.CurrentUserIsBot(mctx, botUID) { // Only need keys for private teams. if !kbfsEncrypted { refreshers.NeedApplicationsAtGenerations = map[keybase1.PerTeamKeyGeneration][]keybase1.TeamApplication{ keybase1.PerTeamKeyGeneration(keyGeneration): {keybase1.TeamApplication_CHAT}, } } else { refreshers.NeedKBFSKeyGeneration = keybase1.TeamKBFSKeyRefresher{ Generation: keyGeneration, AppType: keybase1.TeamApplication_CHAT, } } } team, err := loader.loadTeam(mctx.Ctx(), teamID, name, membersType, public, func(teamID keybase1.TeamID) keybase1.LoadTeamArg { return keybase1.LoadTeamArg{ ID: teamID, Public: public, Refreshers: refreshers, StaleOK: true, } }) if err != nil { return nil, err } return team, nil } type TeamLoader struct { libkb.Contextified utils.DebugLabeler } func NewTeamLoader(g *libkb.GlobalContext) *TeamLoader { return &TeamLoader{ Contextified: libkb.NewContextified(g), DebugLabeler: utils.NewDebugLabeler(g, "TeamLoader", false), } } func (t *TeamLoader) validKBFSTLFID(tlfID chat1.TLFID, team *teams.Team) bool { tlfIDs := team.KBFSTLFIDs() for _, id := range tlfIDs { if tlfID.EqString(id) { return true } } return false } func (t *TeamLoader) validateImpTeamname(ctx context.Context, tlfName string, public bool, team *teams.Team, ) error { impTeamName, err := team.ImplicitTeamDisplayNameNoConflicts(ctx) if err != nil { return err } if impTeamName.String() != tlfName { // Try resolving both the tlf name, and the team we loaded resImpName, err := teams.ResolveImplicitTeamDisplayName(ctx, t.G(), impTeamName.String(), public) if err != nil { return err } resTlfName, err := teams.ResolveImplicitTeamDisplayName(ctx, t.G(), tlfName, public) if err != nil { return err } if resImpName.String() != resTlfName.String() { return ImpteamBadteamError{ Msg: fmt.Sprintf("mismatch TLF name to implicit team name: %s != %s (%s != %s)", impTeamName, tlfName, resImpName, resTlfName), } } } return nil } func (t *TeamLoader) loadTeam(ctx context.Context, tlfID chat1.TLFID, tlfName string, membersType chat1.ConversationMembersType, public bool, loadTeamArgOverride func(keybase1.TeamID) keybase1.LoadTeamArg, ) (team *teams.Team, err error) { mctx := libkb.NewMetaContext(ctx, t.G()) defer t.Trace(ctx, &err, "loadTeam(%s,%s,%v)", tlfName, tlfID, membersType)() // Set up load team argument construction, possibly controlled by the caller ltarg := func(teamID keybase1.TeamID) keybase1.LoadTeamArg { return keybase1.LoadTeamArg{ ID: teamID, Public: public, } } if loadTeamArgOverride != nil { ltarg = loadTeamArgOverride } switch membersType { case chat1.ConversationMembersType_TEAM, chat1.ConversationMembersType_IMPTEAMNATIVE: teamID, err := keybase1.TeamIDFromString(tlfID.String()) if err != nil { return nil, err } return teams.Load(ctx, t.G(), ltarg(teamID)) case chat1.ConversationMembersType_IMPTEAMUPGRADE: teamID, err := tlfIDToTeamID.Lookup(mctx, tlfID, t.G().API) if err != nil { return nil, err } loadAttempt := func(repoll bool) error { arg := ltarg(teamID) arg.ForceRepoll = arg.ForceRepoll || repoll team, err = teams.Load(ctx, t.G(), arg) if err != nil { return err } if !t.validKBFSTLFID(tlfID, team) { return ImpteamBadteamError{ Msg: fmt.Sprintf("TLF ID not found in team: %s", tlfID), } } return nil } if err = loadAttempt(false); err != nil { mctx.Debug("loadTeam: failed to load the team: err: %s", err) if IsOfflineError(err) == OfflineErrorKindOnline { // try again on bad team, might have had an old team cached mctx.Debug("loadTeam: non-offline error, trying again: %s", err) if err = loadAttempt(true); err != nil { return nil, err } } else { // generic error we bail out return nil, err } } // In upgraded implicit teams, make sure to check that tlfName matches // team display name. if err := t.validateImpTeamname(ctx, tlfName, public, team); err != nil { return nil, err } return team, nil } return nil, fmt.Errorf("invalid impteam members type: %v", membersType) } type TeamsNameInfoSource struct { globals.Contextified utils.DebugLabeler loader *TeamLoader } func NewTeamsNameInfoSource(g *globals.Context) *TeamsNameInfoSource { return &TeamsNameInfoSource{ Contextified: globals.NewContextified(g), DebugLabeler: utils.NewDebugLabeler(g.ExternalG(), "TeamsNameInfoSource", false), loader: NewTeamLoader(g.ExternalG()), } } func (t *TeamsNameInfoSource) LookupID(ctx context.Context, name string, _ bool) (res types.NameInfo, err error) { defer t.Trace(ctx, &err, "LookupID(%s)", name)() teamName, err := keybase1.TeamNameFromString(name) if err != nil { return res, err } id, err := teams.ResolveNameToID(ctx, t.G().ExternalG(), teamName) if err != nil { return res, err } tlfID, err := chat1.TeamIDToTLFID(id) if err != nil { return res, err } return types.NameInfo{ ID: tlfID, CanonicalName: teamName.String(), }, nil } func (t *TeamsNameInfoSource) LookupName(ctx context.Context, tlfID chat1.TLFID, _ bool, unverifiedTLFName string, ) (res types.NameInfo, err error) { defer t.Trace(ctx, &err, "LookupName(%s)", tlfID)() teamID, err := keybase1.TeamIDFromString(tlfID.String()) if err != nil { return res, err } m := libkb.NewMetaContext(ctx, t.G().ExternalG()) loadRes, err := m.G().GetFastTeamLoader().Load(m, keybase1.FastTeamLoadArg{ ID: teamID, Public: teamID.IsPublic(), }) if err != nil { return res, err } return types.NameInfo{ ID: tlfID, CanonicalName: loadRes.Name.String(), }, nil } func (t *TeamsNameInfoSource) TeamBotSettings(ctx context.Context, tlfName string, tlfID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, ) (map[keybase1.UserVersion]keybase1.TeamBotSettings, error) { team, err := NewTeamLoader(t.G().ExternalG()).loadTeam(ctx, tlfID, tlfName, membersType, public, nil) if err != nil { return nil, err } return team.TeamBotSettings() } func (t *TeamsNameInfoSource) AllCryptKeys(ctx context.Context, name string, public bool) (res types.AllCryptKeys, err error) { defer t.Trace(ctx, &err, "AllCryptKeys")() return res, errors.New("unable to list all crypt keys on teams name info source") } func (t *TeamsNameInfoSource) EncryptionKey(ctx context.Context, name string, teamID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, botUID *gregor1.UID, ) (res types.CryptKey, ni types.NameInfo, err error) { defer t.Trace(ctx, &err, "EncryptionKey(%s,%s,%v,%v)", name, teamID, public, botUID)() mctx := libkb.NewMetaContext(ctx, t.G().ExternalG()) if botUID == nil && !public { return encryptionKeyViaFTL(mctx, name, teamID, membersType) } team, err := t.loader.loadTeam(ctx, teamID, name, membersType, public, nil) if err != nil { return res, ni, err } if res, err = getTeamCryptKey(mctx, team, team.Generation(), public, false, /* kbfsEncrypted */ botUID, true /* forEncryption */); err != nil { return res, ni, err } tlfID, err := chat1.TeamIDToTLFID(team.ID) if err != nil { return res, ni, err } return res, types.NameInfo{ ID: tlfID, CanonicalName: team.Name().String(), }, nil } func (t *TeamsNameInfoSource) DecryptionKey(ctx context.Context, name string, teamID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, keyGeneration int, kbfsEncrypted bool, botUID *gregor1.UID, ) (res types.CryptKey, err error) { defer t.Trace(ctx, &err, "DecryptionKey(%s,%s,%v,%d,%v,%v)", name, teamID, public, keyGeneration, kbfsEncrypted, botUID)() mctx := libkb.NewMetaContext(ctx, t.G().ExternalG()) if botUID == nil && !kbfsEncrypted && !public { return decryptionKeyViaFTL(mctx, teamID, membersType, keyGeneration) } team, err := loadTeamForDecryption(mctx, t.loader, name, teamID, membersType, public, keyGeneration, kbfsEncrypted, botUID) if err != nil { return res, err } return getTeamCryptKey(mctx, team, keybase1.PerTeamKeyGeneration(keyGeneration), public, kbfsEncrypted, botUID, false /* forEncryption */) } func (t *TeamsNameInfoSource) EphemeralEncryptionKey(mctx libkb.MetaContext, tlfName string, tlfID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, botUID *gregor1.UID, ) (ek types.EphemeralCryptKey, err error) { if public { return ek, NewPublicTeamEphemeralKeyError() } teamID, err := keybase1.TeamIDFromString(tlfID.String()) if err != nil { return ek, err } if botUID != nil { ek, _, err = t.G().GetEKLib().GetOrCreateLatestTeambotEK(mctx, teamID, *botUID) } else { ek, _, err = t.G().GetEKLib().GetOrCreateLatestTeamEK(mctx, teamID) } return ek, err } func (t *TeamsNameInfoSource) EphemeralDecryptionKey(mctx libkb.MetaContext, tlfName string, tlfID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, botUID *gregor1.UID, generation keybase1.EkGeneration, contentCtime *gregor1.Time, ) (ek types.EphemeralCryptKey, err error) { if public { return ek, NewPublicTeamEphemeralKeyError() } teamID, err := keybase1.TeamIDFromString(tlfID.String()) if err != nil { return ek, err } if botUID != nil { return t.G().GetEKLib().GetTeambotEK(mctx, teamID, *botUID, generation, contentCtime) } return t.G().GetEKLib().GetTeamEK(mctx, teamID, generation, contentCtime) } func (t *TeamsNameInfoSource) ShouldPairwiseMAC(ctx context.Context, tlfName string, tlfID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, ) (bool, []keybase1.KID, error) { return shouldPairwiseMAC(ctx, t.G(), t.loader, tlfName, tlfID, membersType, public) } func batchLoadEncryptionKIDs(ctx context.Context, g *libkb.GlobalContext, uvs []keybase1.UserVersion) (ret []keybase1.KID, err error) { getArg := func(i int) *libkb.LoadUserArg { if i >= len(uvs) { return nil } tmp := libkb.NewLoadUserByUIDArg(ctx, g, uvs[i].Uid).WithPublicKeyOptional() return &tmp } processResult := func(i int, upak *keybase1.UserPlusKeysV2AllIncarnations) error { if upak == nil { return nil } for _, key := range upak.Current.DeviceKeys { // Include only unrevoked encryption keys. if !key.Base.IsSibkey && key.Base.Revocation == nil { ret = append(ret, key.Base.Kid) } } return nil } err = g.GetUPAKLoader().Batcher(ctx, getArg, processResult, 0) return ret, err } func shouldPairwiseMAC(ctx context.Context, g *globals.Context, loader *TeamLoader, tlfName string, tlfID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, ) (should bool, kids []keybase1.KID, err error) { if public { return false, nil, nil } defer g.CTrace(ctx, fmt.Sprintf("shouldPairwiseMAC teamID %s", tlfID.String()), &err)() team, err := loader.loadTeam(ctx, tlfID, tlfName, membersType, public, nil) if err != nil { return false, nil, err } members, err := team.Members() if err != nil { return false, nil, err } memberUVs := members.AllUserVersions() // For performance reasons, we don't try to pairwise MAC any messages in // large teams. if len(memberUVs) > libkb.MaxTeamMembersForPairwiseMAC { return false, nil, nil } unrevokedKIDs, err := batchLoadEncryptionKIDs(ctx, g.GlobalContext, memberUVs) if err != nil { return false, nil, err } if len(unrevokedKIDs) > 10*libkb.MaxTeamMembersForPairwiseMAC { // If someone on the team has a ton of devices, it could break our "100 // members" heuristic and lead to bad performance. We don't want to // silently fall back to the non-repudiable mode, because that would // create an opening for downgrade attacks, and we'd need to document // this exception everywhere we talk about repudiability. But if this // turns out to be a performance issue in practice, we might want to // add some workaround. (For example, we could choose to omit // recipients with an unreasonable number of devices.) g.Log.CWarningf(ctx, "unreasonable number of devices (%d) in recipients list", len(unrevokedKIDs)) } return true, unrevokedKIDs, nil } type ImplicitTeamsNameInfoSource struct { globals.Contextified utils.DebugLabeler *NameIdentifier loader *TeamLoader membersType chat1.ConversationMembersType } func NewImplicitTeamsNameInfoSource(g *globals.Context, membersType chat1.ConversationMembersType) *ImplicitTeamsNameInfoSource { return &ImplicitTeamsNameInfoSource{ Contextified: globals.NewContextified(g), DebugLabeler: utils.NewDebugLabeler(g.ExternalG(), "ImplicitTeamsNameInfoSource", false), NameIdentifier: NewNameIdentifier(g), loader: NewTeamLoader(g.ExternalG()), membersType: membersType, } } func (t *ImplicitTeamsNameInfoSource) lookupUpgraded() bool { return t.membersType == chat1.ConversationMembersType_IMPTEAMUPGRADE } // Identify participants of a conv. // Returns as if all IDs succeeded if ctx is in TLFIdentifyBehavior_CHAT_GUI mode. func (t *ImplicitTeamsNameInfoSource) identify(ctx context.Context, team *teams.Team, impTeamName keybase1.ImplicitTeamDisplayName) (err error) { var names []string names = append(names, impTeamName.Writers.KeybaseUsers...) names = append(names, impTeamName.Readers.KeybaseUsers...) // identify the members in the conversation identBehavior, _, ok := globals.CtxIdentifyMode(ctx) defer t.Trace(ctx, &err, "identify(%s, %v)", impTeamName.String(), identBehavior)() if !ok { return errors.New("invalid context with no chat metadata") } cb := make(chan struct{}) go func(ctx context.Context) { var idFails []keybase1.TLFIdentifyFailure idFails, err = t.Identify(ctx, names, true, func() keybase1.TLFID { return keybase1.TLFID(team.ID.String()) }, func() keybase1.CanonicalTlfName { return keybase1.CanonicalTlfName(impTeamName.String()) }) if err != nil || len(idFails) > 0 { t.Debug(ctx, "identify failed err=%v fails=%+v", err, idFails) } // ignore idFails close(cb) }(globals.BackgroundChatCtx(ctx, t.G())) switch identBehavior { case keybase1.TLFIdentifyBehavior_CHAT_GUI: // For GUI mode, let the full IDs roll in the background. We will be sending up // tracker breaks to the UI out of band with whatever chat operation has invoked us here. // CORE-10522 peg breaks will need to block sending for non-gui mode too. // Peg breaks could count as track breaks for real Identify. // That could nicely cover other applications besides chat. But the UI // for fixing track breaks doesn't quite make sense for peg breaks. // But check reset-pegs on the critical path. for _, uv := range team.AllUserVersions(ctx) { err = t.G().Pegboard.CheckUV(t.MetaContext(ctx), uv) if err != nil { // Turn peg failures into identify failures t.Debug(ctx, "pegboard rejected %v: %v", uv, err) return fmt.Errorf("A user may have reset: %v", err) } } return nil default: <-cb return err } } func (t *ImplicitTeamsNameInfoSource) transformTeamDoesNotExist(ctx context.Context, err error, name string) error { switch err.(type) { case nil: return nil case teams.TeamDoesNotExistError: return NewUnknownTLFNameError(name) default: t.Debug(ctx, "Lookup: error looking up the team: %v", err) return err } } func (t *ImplicitTeamsNameInfoSource) LookupID(ctx context.Context, name string, public bool) (res types.NameInfo, err error) { defer t.Trace(ctx, &err, "LookupID(%s)", name)() // check if name is prefixed if strings.HasPrefix(name, keybase1.ImplicitTeamPrefix) { return t.lookupInternalName(ctx, name, public) } // This is on the critical path of sends, so don't force a repoll. team, _, impTeamName, err := teams.LookupImplicitTeam(ctx, t.G().ExternalG(), name, public, teams.ImplicitTeamOptions{NoForceRepoll: true}) if err != nil { return res, t.transformTeamDoesNotExist(ctx, err, name) } if !team.ID.IsRootTeam() { panic(fmt.Sprintf("implicit team found via LookupImplicitTeam not root team: %s", team.ID)) } var tlfID chat1.TLFID if t.lookupUpgraded() { tlfIDs := team.KBFSTLFIDs() if len(tlfIDs) > 0 { // We pull the first TLF ID here for this lookup since it has the highest chance of being // correct. The upgrade wrote a bunch of TLF IDs in over the last months, but it is possible // that KBFS can add more. All the upgrade TLFs should be ahead of them though, since if the // upgrade process encounters a team with a TLF ID already in there, it will abort if they // don't match. tlfID = tlfIDs[0].ToBytes() } } else { tlfID, err = chat1.TeamIDToTLFID(team.ID) if err != nil { return res, err } } res = types.NameInfo{ ID: tlfID, CanonicalName: impTeamName.String(), } return res, nil } func (t *ImplicitTeamsNameInfoSource) LookupName(ctx context.Context, tlfID chat1.TLFID, public bool, unverifiedTLFName string, ) (res types.NameInfo, err error) { defer t.Trace(ctx, &err, "LookupName(%s)", tlfID)() team, err := t.loader.loadTeam(ctx, tlfID, unverifiedTLFName, t.membersType, public, nil) if err != nil { return res, err } impTeamName, err := team.ImplicitTeamDisplayNameNoConflicts(ctx) if err != nil { return res, err } t.Debug(ctx, "LookupName: got name: %s", impTeamName.String()) members, err := team.Members() if err != nil { return res, err } var verifiedMembers []gregor1.UID for _, member := range members.AllUIDs() { verifiedMembers = append(verifiedMembers, gregor1.UID(member.ToBytes())) } return types.NameInfo{ ID: tlfID, CanonicalName: impTeamName.String(), VerifiedMembers: verifiedMembers, }, nil } func (t *ImplicitTeamsNameInfoSource) TeamBotSettings(ctx context.Context, tlfName string, tlfID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, ) (map[keybase1.UserVersion]keybase1.TeamBotSettings, error) { team, err := NewTeamLoader(t.G().ExternalG()).loadTeam(ctx, tlfID, tlfName, membersType, public, nil) if err != nil { return nil, err } return team.TeamBotSettings() } func (t *ImplicitTeamsNameInfoSource) AllCryptKeys(ctx context.Context, name string, public bool) (res types.AllCryptKeys, err error) { defer t.Trace(ctx, &err, "AllCryptKeys")() return res, errors.New("unable to list all crypt keys in implicit team name info source") } func (t *ImplicitTeamsNameInfoSource) EncryptionKey(ctx context.Context, name string, teamID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, botUID *gregor1.UID, ) (res types.CryptKey, ni types.NameInfo, err error) { defer t.Trace(ctx, &err, "EncryptionKey(%s,%s,%v,%v)", name, teamID, public, botUID)() team, err := t.loader.loadTeam(ctx, teamID, name, membersType, public, nil) if err != nil { return res, ni, err } impTeamName, err := team.ImplicitTeamDisplayNameNoConflicts(ctx) if err != nil { return res, ni, err } if err := t.identify(ctx, team, impTeamName); err != nil { return res, ni, err } mctx := libkb.NewMetaContext(ctx, t.G().ExternalG()) if res, err = getTeamCryptKey(mctx, team, team.Generation(), public, false, /* kbfsEncrypted */ botUID, true /* forEncryption */); err != nil { return res, ni, err } return res, types.NameInfo{ ID: teamID, CanonicalName: impTeamName.String(), }, nil } func (t *ImplicitTeamsNameInfoSource) DecryptionKey(ctx context.Context, name string, teamID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, keyGeneration int, kbfsEncrypted bool, botUID *gregor1.UID, ) (res types.CryptKey, err error) { defer t.Trace(ctx, &err, "DecryptionKey(%s,%s,%v,%d,%v,%v)", name, teamID, public, keyGeneration, kbfsEncrypted, botUID)() mctx := libkb.NewMetaContext(ctx, t.G().ExternalG()) if botUID == nil && !kbfsEncrypted && !public { return decryptionKeyViaFTL(mctx, teamID, membersType, keyGeneration) } team, err := loadTeamForDecryption(mctx, t.loader, name, teamID, membersType, public, keyGeneration, kbfsEncrypted, botUID) if err != nil { return res, err } impTeamName, err := team.ImplicitTeamDisplayNameNoConflicts(ctx) if err != nil { return res, err } if err := t.identify(ctx, team, impTeamName); err != nil { return res, err } return getTeamCryptKey(mctx, team, keybase1.PerTeamKeyGeneration(keyGeneration), public, kbfsEncrypted, botUID, false /* forEncryption */) } func (t *ImplicitTeamsNameInfoSource) ephemeralLoadAndIdentify(ctx context.Context, encrypting bool, tlfName string, tlfID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, ) (teamID keybase1.TeamID, err error) { if public { return teamID, NewPublicTeamEphemeralKeyError() } team, err := t.loader.loadTeam(ctx, tlfID, tlfName, membersType, public, nil) if err != nil { return teamID, err } impTeamName, err := team.ImplicitTeamDisplayNameNoConflicts(ctx) if err != nil { return teamID, err } if err := t.identify(ctx, team, impTeamName); err != nil { return teamID, err } return team.ID, nil } func (t *ImplicitTeamsNameInfoSource) EphemeralEncryptionKey(mctx libkb.MetaContext, tlfName string, tlfID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, botUID *gregor1.UID, ) (ek types.EphemeralCryptKey, err error) { teamID, err := t.ephemeralLoadAndIdentify(mctx.Ctx(), true, tlfName, tlfID, membersType, public) if err != nil { return ek, err } if botUID != nil { ek, _, err = t.G().GetEKLib().GetOrCreateLatestTeambotEK(mctx, teamID, *botUID) } else { ek, _, err = t.G().GetEKLib().GetOrCreateLatestTeamEK(mctx, teamID) } return ek, err } func (t *ImplicitTeamsNameInfoSource) EphemeralDecryptionKey(mctx libkb.MetaContext, tlfName string, tlfID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, botUID *gregor1.UID, generation keybase1.EkGeneration, contentCtime *gregor1.Time, ) (teamEK types.EphemeralCryptKey, err error) { teamID, err := t.ephemeralLoadAndIdentify(mctx.Ctx(), false, tlfName, tlfID, membersType, public) if err != nil { return teamEK, err } if botUID != nil { return t.G().GetEKLib().GetTeambotEK(mctx, teamID, *botUID, generation, contentCtime) } return t.G().GetEKLib().GetTeamEK(mctx, teamID, generation, contentCtime) } func (t *ImplicitTeamsNameInfoSource) ShouldPairwiseMAC(ctx context.Context, tlfName string, tlfID chat1.TLFID, membersType chat1.ConversationMembersType, public bool, ) (bool, []keybase1.KID, error) { return shouldPairwiseMAC(ctx, t.G(), t.loader, tlfName, tlfID, membersType, public) } func (t *ImplicitTeamsNameInfoSource) lookupInternalName(ctx context.Context, name string, public bool) (res types.NameInfo, err error) { team, err := teams.Load(ctx, t.G().ExternalG(), keybase1.LoadTeamArg{ Name: name, Public: public, }) if err != nil { return res, err } res.CanonicalName = team.Name().String() if res.ID, err = chat1.TeamIDToTLFID(team.ID); err != nil { return res, err } return res, nil } type tlfIDToTeamIDMap struct { storage *lru.Cache } func newTlfIDToTeamIDMap() *tlfIDToTeamIDMap { s, _ := lru.New(10000) return &tlfIDToTeamIDMap{ storage: s, } } func TLFIDToTeamID(tlfID chat1.TLFID) (keybase1.TeamID, error) { return keybase1.TeamIDFromString(tlfID.String()) } // Lookup gives the server trust mapping between tlfID and teamID func (t *tlfIDToTeamIDMap) Lookup(mctx libkb.MetaContext, tlfID chat1.TLFID, api libkb.API) (res keybase1.TeamID, err error) { if iTeamID, ok := t.storage.Get(tlfID.String()); ok { return iTeamID.(keybase1.TeamID), nil } arg := libkb.NewAPIArg("team/id") arg.Args = libkb.NewHTTPArgs() arg.Args.Add("tlf_id", libkb.S{Val: tlfID.String()}) arg.SessionType = libkb.APISessionTypeREQUIRED apiRes, err := api.Get(mctx, arg) if err != nil { return res, err } st, err := apiRes.Body.AtKey("team_id").GetString() if err != nil { return res, err } teamID, err := keybase1.TeamIDFromString(st) if err != nil { return res, err } t.storage.Add(tlfID.String(), teamID) return teamID, nil } func (t *tlfIDToTeamIDMap) LookupTLFID(mctx libkb.MetaContext, teamID keybase1.TeamID, api libkb.API) (res chat1.TLFID, err error) { if iTLFID, ok := t.storage.Get(teamID.String()); ok { return iTLFID.(chat1.TLFID), nil } arg := libkb.NewAPIArg("team/tlfid") arg.Args = libkb.NewHTTPArgs() arg.Args.Add("team_id", libkb.S{Val: teamID.String()}) arg.SessionType = libkb.APISessionTypeREQUIRED apiRes, err := api.Get(mctx, arg) if err != nil { return res, err } st, err := apiRes.Body.AtKey("tlf_id").GetString() if err != nil { return res, err } tlfID, err := chat1.MakeTLFID(st) if err != nil { return res, err } t.storage.Add(teamID.String(), tlfID) return tlfID, nil } var tlfIDToTeamID = newTlfIDToTeamIDMap()