/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/teams/loader_ctx.go
353 строки
13 KB
zoom-ua
gofumpt (#28710)
17 дек 2025, 17:16
Не верифицирован
17 дек 2025, 17:16
cda510b
Код
Авторство
О чём код?
package teams import ( "context" "encoding/json" "fmt" "strings" "sync" "time" "github.com/keybase/client/go/libkb" "github.com/keybase/client/go/protocol/keybase1" "github.com/keybase/client/go/sig3" "github.com/keybase/client/go/teams/hidden" ) // Things TeamLoader uses that are mocked out for tests. type LoaderContext interface { // Get new links from the server. getNewLinksFromServer(ctx context.Context, teamID keybase1.TeamID, lows getLinksLows, readSubteamID *keybase1.TeamID) (*rawTeam, error) // Get full links from the server. // Does not guarantee that the server returned the correct links, nor that they are unstubbed. getLinksFromServer(ctx context.Context, teamID keybase1.TeamID, requestSeqnos []keybase1.Seqno, readSubteamID *keybase1.TeamID) (*rawTeam, error) getMe(context.Context) (keybase1.UserVersion, error) // Lookup the eldest seqno of a user. Can use the cache. lookupEldestSeqno(context.Context, keybase1.UID) (keybase1.Seqno, error) // Get the current user's per-user-key's derived encryption key (full). perUserEncryptionKey(ctx context.Context, userSeqno keybase1.Seqno) (*libkb.NaclDHKeyPair, error) merkleLookup(ctx context.Context, teamID keybase1.TeamID, public bool) (r1 keybase1.Seqno, r2 keybase1.LinkID, err error) merkleLookupWithHidden(ctx context.Context, teamID keybase1.TeamID, public bool) (r1 keybase1.Seqno, r2 keybase1.LinkID, hiddenResp *libkb.MerkleHiddenResponse, lastMerkleRoot *libkb.MerkleRoot, err error) merkleLookupTripleInPast(ctx context.Context, isPublic bool, leafID keybase1.UserOrTeamID, root keybase1.MerkleRootV2) (triple *libkb.MerkleTriple, err error) forceLinkMapRefreshForUser(ctx context.Context, uid keybase1.UID) (linkMap linkMapT, err error) loadKeyV2(ctx context.Context, uid keybase1.UID, kid keybase1.KID, lkc *loadKeyCache) (keybase1.UserVersion, *keybase1.PublicKeyV2NaCl, linkMapT, error) } // The main LoaderContext is G. type LoaderContextG struct { libkb.Contextified // Cache of size=1 for caching merkle leaf lookups at the checkpoint, since in practice // we hit this is rapid succession. cacheMu sync.RWMutex cachedSeqno keybase1.Seqno cachedLeaf *libkb.MerkleGenericLeaf } var _ LoaderContext = (*LoaderContextG)(nil) func NewLoaderContextFromG(g *libkb.GlobalContext) LoaderContext { return &LoaderContextG{ Contextified: libkb.NewContextified(g), } } type rawTeam struct { ID keybase1.TeamID `json:"id"` Name keybase1.TeamName `json:"name"` Status libkb.AppStatus `json:"status"` Chain []json.RawMessage `json:"chain"` Box *TeamBox `json:"box"` Prevs map[keybase1.PerTeamKeyGeneration]prevKeySealedEncoded `json:"prevs"` ReaderKeyMasks []keybase1.ReaderKeyMask `json:"reader_key_masks"` // Whether the user is only being allowed to view the chain // because they are a member of a descendent team. SubteamReader bool `json:"subteam_reader"` Showcase keybase1.TeamShowcase `json:"showcase"` LegacyTLFUpgrade []keybase1.TeamGetLegacyTLFUpgrade `json:"legacy_tlf_upgrade"` HiddenChain []sig3.ExportJSON `json:"hidden"` RatchetBlindingKeySet *hidden.RatchetBlindingKeySet `json:"ratchet_blinding_keys"` } func (r *rawTeam) GetAppStatus() *libkb.AppStatus { return &r.Status } func (r *rawTeam) GetHiddenChain() []sig3.ExportJSON { if r == nil { return nil } return r.HiddenChain } func (r *rawTeam) unpackLinks(mctx libkb.MetaContext) (links []*ChainLinkUnpacked, err error) { if r == nil { return nil, nil } defer mctx.PerfTrace(fmt.Sprintf("TeamLoad: unpackLinks(%v, %d)", r.ID, len(r.Chain)), &err)() start := time.Now() defer func() { if len(links) == 0 { return } var message string if err == nil { message = fmt.Sprintf("Unpacking links %d for %s", len(r.Chain), r.ID) } else { message = fmt.Sprintf("Failed to unpack links for %s", r.ID) } mctx.G().RuntimeStats.PushPerfEvent(keybase1.PerfEvent{ EventType: keybase1.PerfEventType_TEAMCHAIN, Message: message, Ctime: keybase1.ToTime(start), }) }() parsedLinks, err := r.parseLinks(mctx.Ctx()) if err != nil { return nil, err } for _, pLink := range parsedLinks { pLink2 := pLink link, err := unpackChainLink(&pLink2) if err != nil { return nil, err } if !link.isStubbed() { if !link.innerTeamID.Eq(r.ID) { return nil, fmt.Errorf("link has wrong team ID in response: %v != %v", link.innerTeamID, r.ID) } } links = append(links, link) } return links, nil } func (r *rawTeam) parseLinks(ctx context.Context) ([]SCChainLink, error) { var links []SCChainLink for _, raw := range r.Chain { link, err := ParseTeamChainLink(string(raw)) if err != nil { return nil, err } links = append(links, link) } return links, nil } // Get new links from the server. func (l *LoaderContextG) getNewLinksFromServer(ctx context.Context, teamID keybase1.TeamID, lows getLinksLows, readSubteamID *keybase1.TeamID, ) (*rawTeam, error) { return l.getLinksFromServerCommon(ctx, teamID, &lows, nil, readSubteamID) } // Get full links from the server. // Does not guarantee that the server returned the correct links, nor that they are unstubbed. func (l *LoaderContextG) getLinksFromServer(ctx context.Context, teamID keybase1.TeamID, requestSeqnos []keybase1.Seqno, readSubteamID *keybase1.TeamID, ) (*rawTeam, error) { return l.getLinksFromServerCommon(ctx, teamID, nil, requestSeqnos, readSubteamID) } func (l *LoaderContextG) getLinksFromServerCommon(ctx context.Context, teamID keybase1.TeamID, lows *getLinksLows, requestSeqnos []keybase1.Seqno, readSubteamID *keybase1.TeamID, ) (*rawTeam, error) { mctx := libkb.NewMetaContext(ctx, l.G()) arg := libkb.NewAPIArg("team/get") arg.SessionType = libkb.APISessionTypeREQUIRED if teamID.IsPublic() { arg.SessionType = libkb.APISessionTypeOPTIONAL } arg.Args = libkb.HTTPArgs{ "id": libkb.S{Val: teamID.String()}, "public": libkb.B{Val: teamID.IsPublic()}, } if lows != nil { arg.Args["low"] = libkb.I{Val: int(lows.Seqno)} arg.Args["per_team_key_low"] = libkb.I{Val: int(lows.PerTeamKey)} arg.Args["hidden_low"] = libkb.I{Val: int(lows.HiddenChainSeqno)} } if len(requestSeqnos) > 0 { arg.Args["seqnos"] = libkb.S{Val: seqnosToString(requestSeqnos)} } if readSubteamID != nil { arg.Args["read_subteam_id"] = libkb.S{Val: readSubteamID.String()} } var rt rawTeam if err := mctx.G().API.GetDecode(mctx, arg, &rt); err != nil { return nil, err } if !rt.ID.Eq(teamID) { return nil, fmt.Errorf("server returned wrong team ID: %v != %v", rt.ID, teamID) } return &rt, nil } func seqnosToString(v []keybase1.Seqno) string { var s []string for _, e := range v { s = append(s, fmt.Sprintf("%d", int(e))) } return strings.Join(s, ",") } func (l *LoaderContextG) getMe(ctx context.Context) (res keybase1.UserVersion, err error) { uid := l.G().ActiveDevice.UID() // If we're logged out, we still should be able to access the team loader // for public teams. So we'll just return a nil UID here, and it should just work. if uid.IsNil() { return res, nil } return l.G().GetMeUV(ctx) } func (l *LoaderContextG) lookupEldestSeqno(ctx context.Context, uid keybase1.UID) (keybase1.Seqno, error) { // Lookup the latest eldest seqno for that uid. // This value may come from a cache. upak, err := loadUPAK2(ctx, l.G(), uid, false /*forcePoll */) if err != nil { return keybase1.Seqno(1), err } return upak.Current.EldestSeqno, nil } func (l *LoaderContextG) perUserEncryptionKey(ctx context.Context, userSeqno keybase1.Seqno) (*libkb.NaclDHKeyPair, error) { return perUserEncryptionKey(l.MetaContext(ctx), userSeqno) } func perUserEncryptionKey(m libkb.MetaContext, userSeqno keybase1.Seqno) (*libkb.NaclDHKeyPair, error) { kr, err := m.G().GetPerUserKeyring(m.Ctx()) if err != nil { return nil, err } return kr.GetEncryptionKeyBySeqnoOrSync(m, userSeqno) } func (l *LoaderContextG) merkleLookupWithHidden(ctx context.Context, teamID keybase1.TeamID, public bool) (r1 keybase1.Seqno, r2 keybase1.LinkID, hiddenResp *libkb.MerkleHiddenResponse, lastMerkleRoot *libkb.MerkleRoot, err error) { leaf, hiddenResp, lastMerkleRoot, err := l.G().GetMerkleClient().LookupTeamWithHidden(l.MetaContext(ctx), teamID, hidden.ProcessHiddenResponseFunc) if err != nil { return r1, r2, nil, nil, err } r1, r2, err = l.processMerkleReply(ctx, teamID, public, leaf) if err != nil { return r1, r2, nil, nil, err } return r1, r2, hiddenResp, lastMerkleRoot, err } func (l *LoaderContextG) merkleLookup(ctx context.Context, teamID keybase1.TeamID, public bool) (r1 keybase1.Seqno, r2 keybase1.LinkID, err error) { leaf, err := l.G().GetMerkleClient().LookupTeam(l.MetaContext(ctx), teamID) if err != nil { return r1, r2, err } r1, r2, err = l.processMerkleReply(ctx, teamID, public, leaf) return r1, r2, err } func (l *LoaderContextG) processMerkleReply(ctx context.Context, teamID keybase1.TeamID, public bool, leaf *libkb.MerkleTeamLeaf) (r1 keybase1.Seqno, r2 keybase1.LinkID, err error) { if !leaf.TeamID.Eq(teamID) { return r1, r2, fmt.Errorf("merkle returned wrong leaf: %v != %v", leaf.TeamID.String(), teamID.String()) } if public { if leaf.Public == nil { l.G().Log.CDebugf(ctx, "TeamLoader hidden error: merkle returned nil leaf") return r1, r2, NewTeamDoesNotExistError(public, "%s", teamID.String()) } return leaf.Public.Seqno, leaf.Public.LinkID.Export(), nil } if leaf.Private == nil { l.G().Log.CDebugf(ctx, "TeamLoader hidden error: merkle returned nil leaf") return r1, r2, NewTeamDoesNotExistError(public, "%s", teamID.String()) } return leaf.Private.Seqno, leaf.Private.LinkID.Export(), nil } func (l *LoaderContextG) getCachedCheckpointLookup(leafID keybase1.UserOrTeamID, seqno keybase1.Seqno) *libkb.MerkleGenericLeaf { l.cacheMu.RLock() defer l.cacheMu.RUnlock() if l.cachedLeaf == nil || !l.cachedLeaf.LeafID.Equal(leafID) || !l.cachedSeqno.Eq(seqno) { return nil } ret := l.cachedLeaf.PartialClone() return &ret } func (l *LoaderContextG) putCachedCheckpoint(seqno keybase1.Seqno, leaf *libkb.MerkleGenericLeaf) { l.cacheMu.Lock() defer l.cacheMu.Unlock() tmp := leaf.PartialClone() l.cachedLeaf = &tmp l.cachedSeqno = seqno } func (l *LoaderContextG) merkleLookupTripleAtCheckpoint(mctx libkb.MetaContext, leafID keybase1.UserOrTeamID, seqno keybase1.Seqno) (leaf *libkb.MerkleGenericLeaf, err error) { ret := l.getCachedCheckpointLookup(leafID, seqno) if ret != nil { mctx.VLogf(libkb.VLog0, "hit checkpoint cache") return ret, nil } mc := l.G().MerkleClient leaf, _, err = mc.LookupLeafAtSeqno(mctx, leafID, seqno) if leaf != nil && err == nil { l.putCachedCheckpoint(seqno, leaf) } return leaf, err } func (l *LoaderContextG) merkleLookupTripleInPast(ctx context.Context, isPublic bool, leafID keybase1.UserOrTeamID, root keybase1.MerkleRootV2) (triple *libkb.MerkleTriple, err error) { mctx := l.MetaContext(ctx) mc := l.G().MerkleClient checkpoint := mc.FirstExaminableHistoricalRoot(mctx) var leaf *libkb.MerkleGenericLeaf // If we're trying to lookup a leaf from before the checkpoint, just bump forward to the checkpoint. // The checkpoint is consindered to be a legitimate version of Tree. if checkpoint != nil && root.Seqno < *checkpoint { mctx.Debug("Bumping up pre-checkpoint merkle fetch to checkpoint at %d for %s", *checkpoint, leafID) leaf, err = l.merkleLookupTripleAtCheckpoint(mctx, leafID, *checkpoint) } else { leaf, err = mc.LookupLeafAtHashMeta(mctx, leafID, root.HashMeta) } if err != nil { return nil, err } if isPublic { triple = leaf.Public } else { triple = leaf.Private } if triple == nil { return nil, fmt.Errorf("unexpected nil leaf for %v", leafID) } return triple, nil } func (l *LoaderContextG) forceLinkMapRefreshForUser(ctx context.Context, uid keybase1.UID) (linkMap linkMapT, err error) { arg := libkb.NewLoadUserArg(l.G()).WithNetContext(ctx).WithUID(uid).WithForcePoll(true) upak, _, err := l.G().GetUPAKLoader().LoadV2(arg) if err != nil { return nil, err } return upak.SeqnoLinkIDs, nil } func (l *LoaderContextG) loadKeyV2(ctx context.Context, uid keybase1.UID, kid keybase1.KID, lkc *loadKeyCache) ( uv keybase1.UserVersion, pubKey *keybase1.PublicKeyV2NaCl, linkMap linkMapT, err error, ) { ctx, tbs := l.G().CTimeBuckets(ctx) defer tbs.Record("LoaderContextG.loadKeyV2")() return lkc.loadKeyV2(l.MetaContext(ctx), uid, kid) }