/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/service/identify.go
534 строки
18 KB
chrisnojima-zoom
Version 670 - clean2 (#29122)
08 июн 2026, 19:31
Не верифицирован
08 июн 2026, 19:31
1943197
Код
Авторство
О чём код?
// Copyright 2015 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. package service import ( "context" "fmt" "sync" "golang.org/x/sync/errgroup" "github.com/keybase/client/go/engine" "github.com/keybase/client/go/externals" "github.com/keybase/client/go/libkb" "github.com/keybase/client/go/offline" keybase1 "github.com/keybase/client/go/protocol/keybase1" "github.com/keybase/client/go/teams" "github.com/keybase/go-framed-msgpack-rpc/rpc" ) type RemoteIdentifyUI struct { libkb.Contextified sessionID int uicli keybase1.IdentifyUiClient logUI libkb.LogUI strict bool skipPrompt bool } var _ libkb.IdentifyUI = (*RemoteIdentifyUI)(nil) type IdentifyHandler struct { *BaseHandler libkb.Contextified service *Service } func NewIdentifyHandler(xp rpc.Transporter, g *libkb.GlobalContext, s *Service) *IdentifyHandler { return &IdentifyHandler{ BaseHandler: NewBaseHandler(g, xp), Contextified: libkb.NewContextified(g), service: s, } } func (h *IdentifyHandler) Identify2(netCtx context.Context, arg keybase1.Identify2Arg) (res keybase1.Identify2Res, err error) { netCtx = libkb.WithLogTag(netCtx, "ID2") m := libkb.NewMetaContext(netCtx, h.G()) defer h.G().CTrace(netCtx, "IdentifyHandler#Identify2", &err)() iui := h.NewRemoteIdentifyUI(arg.SessionID, h.G()) logui := h.getLogUI(arg.SessionID) uis := libkb.UIs{ LogUI: logui, IdentifyUI: iui, SessionID: arg.SessionID, } m = m.WithUIs(uis) eng := engine.NewResolveThenIdentify2(h.G(), &arg) err = engine.RunEngine2(m, eng) if err != nil { return res, err } resp, err := eng.Result(m) if err != nil { return res, err } if resp != nil { res = resp.ExportToV1() } return res, err } func (h *IdentifyHandler) IdentifyLite(netCtx context.Context, arg keybase1.IdentifyLiteArg) (ret keybase1.IdentifyLiteRes, err error) { mctx := libkb.NewMetaContext(netCtx, h.G()).WithLogTag("IDL") defer mctx.Trace("IdentifyHandler#IdentifyLite", &err)() loader := func(mctx libkb.MetaContext) (any, error) { return h.identifyLite(mctx, arg) } cacheArg := keybase1.IdentifyLiteArg{ Id: arg.Id, Assertion: arg.Assertion, IdentifyBehavior: arg.IdentifyBehavior, } servedRet, err := h.service.offlineRPCCache.Serve(mctx, arg.Oa, offline.Version(1), "identify.identifyLite", false, cacheArg, &ret, loader) if err != nil { if s, ok := servedRet.(keybase1.IdentifyLiteRes); ok { ret = s } return ret, err } if s, ok := servedRet.(keybase1.IdentifyLiteRes); ok { ret = s } return ret, nil } func (h *IdentifyHandler) identifyLite(mctx libkb.MetaContext, arg keybase1.IdentifyLiteArg) (res keybase1.IdentifyLiteRes, err error) { var au libkb.AssertionURL var parseError error if len(arg.Assertion) > 0 { // It's OK to fail this assertion; it will be off in the case of regular lookups // for users like `t_ellen` without a `type` specification au, parseError = libkb.ParseAssertionURL(mctx.G().MakeAssertionContext(mctx), arg.Assertion, true) } else { // empty assertion url required for teams.IdentifyLite au = libkb.AssertionKeybase{} } if arg.Id.IsTeamOrSubteam() || libkb.AssertionIsTeam(au) { // Now heed the parse error. if parseError != nil { return res, parseError } return teams.IdentifyLite(mctx.Ctx(), mctx.G(), arg, au) } return h.identifyLiteUser(mctx.Ctx(), arg) } func (h *IdentifyHandler) identifyLiteUser(netCtx context.Context, arg keybase1.IdentifyLiteArg) (res keybase1.IdentifyLiteRes, err error) { m := libkb.NewMetaContext(netCtx, h.G()) m.Debug("IdentifyLite on user") var uid keybase1.UID if arg.Id.Exists() { uid, err = arg.Id.AsUser() if err != nil { return res, err } } id2arg := keybase1.Identify2Arg{ SessionID: arg.SessionID, Uid: uid, UserAssertion: arg.Assertion, Reason: arg.Reason, UseDelegateUI: arg.UseDelegateUI, AlwaysBlock: arg.AlwaysBlock, NoErrorOnTrackFailure: arg.NoErrorOnTrackFailure, ForceRemoteCheck: arg.ForceRemoteCheck, NeedProofSet: arg.NeedProofSet, AllowEmptySelfID: arg.AllowEmptySelfID, NoSkipSelf: arg.NoSkipSelf, CanSuppressUI: arg.CanSuppressUI, IdentifyBehavior: arg.IdentifyBehavior, ForceDisplay: arg.ForceDisplay, } iui := h.NewRemoteIdentifyUI(arg.SessionID, h.G()) logui := h.getLogUI(arg.SessionID) uis := libkb.UIs{ LogUI: logui, IdentifyUI: iui, SessionID: arg.SessionID, } m = m.WithUIs(uis) eng := engine.NewResolveThenIdentify2(h.G(), &id2arg) err = engine.RunEngine2(m, eng) if err != nil { return res, err } resp, err := eng.Result(m) if err != nil { return res, err } res.Ul.Id = keybase1.UserOrTeamID(resp.Upk.GetUID()) res.Ul.Name = resp.Upk.GetName() res.TrackBreaks = resp.TrackBreaks return res, err } func (h *IdentifyHandler) Resolve3(ctx context.Context, arg keybase1.Resolve3Arg) (ret keybase1.UserOrTeamLite, err error) { mctx := libkb.NewMetaContext(ctx, h.G()).WithLogTag("RSLV") defer mctx.Trace(fmt.Sprintf("IdentifyHandler#Resolve3(%+v)", arg), &err)() servedRet, err := h.service.offlineRPCCache.Serve(mctx, arg.Oa, offline.Version(1), "identify.resolve3", false, arg, &ret, func(mctx libkb.MetaContext) (any, error) { return h.resolveUserOrTeam(mctx.Ctx(), arg.Assertion) }) if err != nil { return keybase1.UserOrTeamLite{}, err } if s, ok := servedRet.(keybase1.UserOrTeamLite); ok { ret = s } return ret, nil } func (h *IdentifyHandler) resolveUserOrTeam(ctx context.Context, arg string) (u keybase1.UserOrTeamLite, err error) { res := h.G().Resolver.ResolveFullExpressionNeedUsername(libkb.NewMetaContext(ctx, h.G()), arg) err = res.GetError() if err != nil { return u, err } return res.UserOrTeam(), nil } func (h *IdentifyHandler) ResolveIdentifyImplicitTeam(ctx context.Context, arg keybase1.ResolveIdentifyImplicitTeamArg) (res keybase1.ResolveIdentifyImplicitTeamRes, err error) { mctx := libkb.NewMetaContext(ctx, h.G()).WithLogTag("RIIT") defer mctx.Trace(fmt.Sprintf("IdentifyHandler#ResolveIdentifyImplicitTeam(%+v)", arg), &err)() writerAssertions, readerAssertions, err := externals.ParseAssertionsWithReaders(h.MetaContext(ctx), arg.Assertions) if err != nil { return res, err } cacheArg := keybase1.ResolveIdentifyImplicitTeamArg{ Assertions: arg.Assertions, Suffix: arg.Suffix, IsPublic: arg.IsPublic, } servedRes, err := h.service.offlineRPCCache.Serve(mctx, arg.Oa, offline.Version(1), "identify.resolveIdentifyImplicitTeam", false, cacheArg, &res, func(mctx libkb.MetaContext) (any, error) { return h.resolveIdentifyImplicitTeamHelper(mctx.Ctx(), arg, writerAssertions, readerAssertions) }) if s, ok := servedRes.(keybase1.ResolveIdentifyImplicitTeamRes); ok { // We explicitly want to return `servedRes` here, when err != // nil, as the caller might depend on it in certain cases. res = s } else if err != nil { res = keybase1.ResolveIdentifyImplicitTeamRes{} } mctx.Debug("res: {displayName: %s, teamID: %s, folderID: %s}", res.DisplayName, res.TeamID, res.FolderID) return res, err } func (h *IdentifyHandler) resolveIdentifyImplicitTeamHelper(ctx context.Context, arg keybase1.ResolveIdentifyImplicitTeamArg, writerAssertions, readerAssertions []libkb.AssertionExpression, ) (res keybase1.ResolveIdentifyImplicitTeamRes, err error) { lookupName := keybase1.ImplicitTeamDisplayName{ IsPublic: arg.IsPublic, } if len(arg.Suffix) > 0 { lookupName.ConflictInfo, err = libkb.ParseImplicitTeamDisplayNameSuffix(arg.Suffix) if err != nil { return res, err } } var resolvedAssertions []libkb.ResolvedAssertion err = teams.ResolveImplicitTeamSetUntrusted(ctx, h.G(), writerAssertions, &lookupName.Writers, &resolvedAssertions) if err != nil { return res, err } err = teams.ResolveImplicitTeamSetUntrusted(ctx, h.G(), readerAssertions, &lookupName.Readers, &resolvedAssertions) if err != nil { return res, err } lookupNameStr, err := teams.FormatImplicitTeamDisplayName(ctx, h.G(), lookupName) if err != nil { return res, err } h.G().Log.CDebugf(ctx, "ResolveIdentifyImplicitTeam looking up:'%v'", lookupNameStr) var team *teams.Team var impName keybase1.ImplicitTeamDisplayName // Lookup*ImplicitTeam is responsible for making sure the returned team has the members from lookupName. // Duplicates are also handled by Lookup*. So we might end up doing extra identifies of duplicates out here. // (Duplicates e.g. "me,chris,chris", "me,chris#chris", "me,chris@rooter#chris") if arg.Create { team, _, impName, err = teams.LookupOrCreateImplicitTeam(ctx, h.G(), lookupNameStr, arg.IsPublic) } else { team, _, impName, err = teams.LookupImplicitTeam(ctx, h.G(), lookupNameStr, arg.IsPublic, teams.ImplicitTeamOptions{}) } if err != nil { return res, err } // can be nil myUID := h.G().ActiveDevice.UID() var displayNameKBFS string if myUID.Exists() { var name libkb.NormalizedUsername name, err = h.G().GetUPAKLoader().LookupUsername(ctx, myUID) if err != nil { return res, err } // display name with the logged-in user first displayNameKBFS, err = teams.FormatImplicitTeamDisplayNameWithUserFront(ctx, h.G(), impName, name) } else { displayNameKBFS, err = teams.FormatImplicitTeamDisplayName(ctx, h.G(), impName) } if err != nil { return res, err } writers, err := team.UsersWithRoleOrAbove(keybase1.TeamRole_WRITER) if err != nil { return res, err } // Populate the result. It may get returned together with an identify error. res = keybase1.ResolveIdentifyImplicitTeamRes{ DisplayName: displayNameKBFS, TeamID: team.ID, Writers: writers, TrackBreaks: nil, FolderID: team.LatestKBFSTLFID(), } if arg.DoIdentifies { return h.resolveIdentifyImplicitTeamDoIdentifies(ctx, arg, res, resolvedAssertions) } return res, nil } func (h *IdentifyHandler) resolveIdentifyImplicitTeamDoIdentifies(ctx context.Context, arg keybase1.ResolveIdentifyImplicitTeamArg, res keybase1.ResolveIdentifyImplicitTeamRes, resolvedAssertions []libkb.ResolvedAssertion, ) (keybase1.ResolveIdentifyImplicitTeamRes, error) { // errgroup collects errors and returns the first non-nil. // subctx is canceled when the group finishes. group, subctx := errgroup.WithContext(ctx) // lock guarding res.TrackBreaks var trackBreaksLock sync.Mutex var okUsernames, brokenUsernames []string // Identify everyone who resolved in parallel, checking that they match their resolved UID and original assertions. for _, resolvedAssertion := range resolvedAssertions { group.Go(func() error { h.G().Log.CDebugf(ctx, "ResolveIdentifyImplicitTeam ID user [%s] %s", resolvedAssertion.UID, resolvedAssertion.Assertion.String()) id2arg := keybase1.Identify2Arg{ SessionID: arg.SessionID, Uid: resolvedAssertion.UID, UserAssertion: resolvedAssertion.Assertion.String(), Reason: arg.Reason, UseDelegateUI: true, AlwaysBlock: false, NoErrorOnTrackFailure: false, ForceRemoteCheck: false, NeedProofSet: false, AllowEmptySelfID: false, NoSkipSelf: false, CanSuppressUI: true, IdentifyBehavior: arg.IdentifyBehavior, ForceDisplay: false, } iui := h.NewRemoteIdentifyUI(arg.SessionID, h.G()) logui := h.getLogUI(arg.SessionID) uis := libkb.UIs{ LogUI: logui, IdentifyUI: iui, SessionID: arg.SessionID, } eng := engine.NewIdentify2WithUID(h.G(), &id2arg) m := libkb.NewMetaContext(subctx, h.G()).WithUIs(uis) err := engine.RunEngine2(m, eng) idRes, idErr := eng.Result(m) if idErr != nil { h.G().Log.CDebugf(subctx, "Failed to convert result from Identify2: %s", idErr) } if idRes != nil { trackBreaksLock.Lock() defer trackBreaksLock.Unlock() if idRes.TrackBreaks != nil && idErr == nil { if res.TrackBreaks == nil { res.TrackBreaks = make(map[keybase1.UserVersion]keybase1.IdentifyTrackBreaks) } res.TrackBreaks[idRes.Upk.ToUserVersion()] = *idRes.TrackBreaks brokenUsernames = append(brokenUsernames, idRes.Upk.GetName()) } else { okUsernames = append(okUsernames, idRes.Upk.GetName()) } } if err != nil { h.G().Log.CDebugf(subctx, "identify failed (IDres %v, TrackBreaks %v): %v", idRes != nil, idRes != nil && idRes.TrackBreaks != nil, err) return err } return nil }) } err := group.Wait() if err != nil { // Return the masked error together with a populated response. return res, libkb.NewIdentifiesFailedError() } if arg.IdentifyBehavior.NotifyGUIAboutBreaks() && len(res.TrackBreaks) > 0 { h.G().NotifyRouter.HandleIdentifyUpdate(ctx, okUsernames, brokenUsernames) } return res, err } func (h *IdentifyHandler) ResolveImplicitTeam(ctx context.Context, arg keybase1.ResolveImplicitTeamArg) (res keybase1.Folder, err error) { ctx = libkb.WithLogTag(ctx, "RIT") defer h.G().CTrace(ctx, fmt.Sprintf("ResolveImplicitTeam(%s)", arg.Id), &err)() return teams.MapImplicitTeamIDToDisplayName(ctx, h.G(), arg.Id, arg.Id.IsPublic()) } func (h *IdentifyHandler) NormalizeSocialAssertion(ctx context.Context, assertion string) (socialAssertion keybase1.SocialAssertion, err error) { ctx = libkb.WithLogTag(ctx, "NSA") defer h.G().CTrace(ctx, fmt.Sprintf("IdentifyHandler#NormalizeSocialAssertion(%s)", assertion), &err)() socialAssertion, isSocialAssertion := libkb.NormalizeSocialAssertion(h.G().MakeAssertionContext(h.MetaContext(ctx)), assertion) if !isSocialAssertion { return keybase1.SocialAssertion{}, fmt.Errorf("Invalid social assertion") } return socialAssertion, nil } func (u *RemoteIdentifyUI) newMetaContext(mctx libkb.MetaContext) (libkb.MetaContext, func()) { return mctx.WithTimeout(libkb.RemoteIdentifyUITimeout) } func (u *RemoteIdentifyUI) FinishWebProofCheck(mctx libkb.MetaContext, p keybase1.RemoteProof, lcr keybase1.LinkCheckResult) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.FinishWebProofCheck(mctx.Ctx(), keybase1.FinishWebProofCheckArg{ SessionID: u.sessionID, Rp: p, Lcr: lcr, }) } func (u *RemoteIdentifyUI) FinishSocialProofCheck(mctx libkb.MetaContext, p keybase1.RemoteProof, lcr keybase1.LinkCheckResult) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.FinishSocialProofCheck(mctx.Ctx(), keybase1.FinishSocialProofCheckArg{ SessionID: u.sessionID, Rp: p, Lcr: lcr, }) } func (u *RemoteIdentifyUI) Confirm(mctx libkb.MetaContext, io *keybase1.IdentifyOutcome) (keybase1.ConfirmResult, error) { if u.skipPrompt { mctx.Debug("skipping Confirm for %q", io.Username) return keybase1.ConfirmResult{IdentityConfirmed: true}, nil } return u.uicli.Confirm(mctx.Ctx(), keybase1.ConfirmArg{SessionID: u.sessionID, Outcome: *io}) } func (u *RemoteIdentifyUI) DisplayCryptocurrency(mctx libkb.MetaContext, c keybase1.Cryptocurrency) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.DisplayCryptocurrency(mctx.Ctx(), keybase1.DisplayCryptocurrencyArg{SessionID: u.sessionID, C: c}) } func (u *RemoteIdentifyUI) DisplayStellarAccount(mctx libkb.MetaContext, a keybase1.StellarAccount) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.DisplayStellarAccount(mctx.Ctx(), keybase1.DisplayStellarAccountArg{SessionID: u.sessionID, A: a}) } func (u *RemoteIdentifyUI) DisplayKey(mctx libkb.MetaContext, key keybase1.IdentifyKey) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.DisplayKey(mctx.Ctx(), keybase1.DisplayKeyArg{SessionID: u.sessionID, Key: key}) } func (u *RemoteIdentifyUI) ReportLastTrack(mctx libkb.MetaContext, t *keybase1.TrackSummary) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.ReportLastTrack(mctx.Ctx(), keybase1.ReportLastTrackArg{SessionID: u.sessionID, Track: t}) } func (u *RemoteIdentifyUI) DisplayTrackStatement(mctx libkb.MetaContext, s string) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.DisplayTrackStatement(mctx.Ctx(), keybase1.DisplayTrackStatementArg{Stmt: s, SessionID: u.sessionID}) } func (u *RemoteIdentifyUI) ReportTrackToken(mctx libkb.MetaContext, token keybase1.TrackToken) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.ReportTrackToken(mctx.Ctx(), keybase1.ReportTrackTokenArg{TrackToken: token, SessionID: u.sessionID}) } func (u *RemoteIdentifyUI) LaunchNetworkChecks(mctx libkb.MetaContext, id *keybase1.Identity, user *keybase1.User) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.LaunchNetworkChecks(mctx.Ctx(), keybase1.LaunchNetworkChecksArg{ SessionID: u.sessionID, Identity: *id, User: *user, }) } func (u *RemoteIdentifyUI) DisplayUserCard(mctx libkb.MetaContext, card keybase1.UserCard) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.DisplayUserCard(mctx.Ctx(), keybase1.DisplayUserCardArg{SessionID: u.sessionID, Card: card}) } func (u *RemoteIdentifyUI) Start(mctx libkb.MetaContext, username string, reason keybase1.IdentifyReason, force bool) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.Start(mctx.Ctx(), keybase1.StartArg{SessionID: u.sessionID, Username: username, Reason: reason, ForceDisplay: force}) } func (u *RemoteIdentifyUI) Cancel(mctx libkb.MetaContext) error { if u.uicli.Cli == nil { return nil } mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.Cancel(mctx.Ctx(), u.sessionID) } func (u *RemoteIdentifyUI) Finish(mctx libkb.MetaContext) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.Finish(mctx.Ctx(), u.sessionID) } func (u *RemoteIdentifyUI) Dismiss(mctx libkb.MetaContext, username string, reason keybase1.DismissReason) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() return u.uicli.Dismiss(mctx.Ctx(), keybase1.DismissArg{ SessionID: u.sessionID, Username: username, Reason: reason, }) } func (u *RemoteIdentifyUI) SetStrict(b bool) { u.strict = b } func (u *RemoteIdentifyUI) DisplayTLFCreateWithInvite(mctx libkb.MetaContext, arg keybase1.DisplayTLFCreateWithInviteArg) error { mctx, cancel := u.newMetaContext(mctx) defer cancel() arg.SessionID = u.sessionID return u.uicli.DisplayTLFCreateWithInvite(mctx.Ctx(), arg) }