github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/resolve_identify2.go (about)

     1  // Copyright 2015 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package engine
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  
    10  	gregor "github.com/keybase/client/go/gregor"
    11  	"github.com/keybase/client/go/libkb"
    12  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    13  )
    14  
    15  type ResolveThenIdentify2 struct {
    16  	libkb.Contextified
    17  	arg                   *keybase1.Identify2Arg
    18  	i2eng                 *Identify2WithUID
    19  	testArgs              *Identify2WithUIDTestArgs
    20  	responsibleGregorItem gregor.Item
    21  	queriedName           libkb.NormalizedUsername
    22  
    23  	// When tracking is being performed, the identify engine is used with a tracking ui.
    24  	// These options are sent to the ui based on command line options.
    25  	// For normal identify, safe to leave these in their default zero state.
    26  	trackOptions keybase1.TrackOptions
    27  }
    28  
    29  var _ (Engine2) = (*ResolveThenIdentify2)(nil)
    30  
    31  func NewResolveThenIdentify2(g *libkb.GlobalContext, arg *keybase1.Identify2Arg) *ResolveThenIdentify2 {
    32  	return &ResolveThenIdentify2{
    33  		Contextified: libkb.NewContextified(g),
    34  		arg:          arg,
    35  	}
    36  }
    37  
    38  func NewResolveThenIdentify2WithTrack(g *libkb.GlobalContext, arg *keybase1.Identify2Arg, topts keybase1.TrackOptions) *ResolveThenIdentify2 {
    39  	return &ResolveThenIdentify2{
    40  		Contextified: libkb.NewContextified(g),
    41  		arg:          arg,
    42  		trackOptions: topts,
    43  	}
    44  }
    45  
    46  // Name is the unique engine name.
    47  func (e *ResolveThenIdentify2) Name() string {
    48  	return "ResolveThenIdentify2"
    49  }
    50  
    51  // GetPrereqs returns the engine prereqs.
    52  func (e *ResolveThenIdentify2) Prereqs() Prereqs {
    53  	return Prereqs{}
    54  }
    55  
    56  // RequiredUIs returns the required UIs.
    57  func (e *ResolveThenIdentify2) RequiredUIs() []libkb.UIKind {
    58  	return []libkb.UIKind{}
    59  }
    60  
    61  // SubConsumers returns the other UI consumers for this engine.
    62  func (e *ResolveThenIdentify2) SubConsumers() []libkb.UIConsumer {
    63  	return []libkb.UIConsumer{
    64  		&Identify2WithUID{
    65  			arg: e.arg,
    66  		},
    67  	}
    68  }
    69  
    70  func (e *ResolveThenIdentify2) resolveUID(m libkb.MetaContext) (err error) {
    71  	if !e.arg.Uid.IsNil() {
    72  		return nil
    73  	}
    74  
    75  	// if no uid and no assertion, then if logged in use self uid:
    76  	if len(e.arg.UserAssertion) == 0 && e.arg.AllowEmptySelfID {
    77  		ok, uid := isLoggedIn(m)
    78  		if ok {
    79  			e.arg.Uid = uid
    80  			return nil
    81  		}
    82  		return libkb.LoginRequiredError{Context: "to identify without specifying a user assertion"}
    83  	}
    84  
    85  	rres := m.G().Resolver.ResolveFullExpressionWithBody(m, e.arg.UserAssertion)
    86  	if err = rres.GetError(); err != nil {
    87  		m.Debug("ResolveThenIdentify2#resolveUID: failing assertion for arg %+v", e.arg)
    88  		return err
    89  	}
    90  	e.arg.Uid = rres.GetUID()
    91  	if rres.WasKBAssertion() && !e.arg.NeedProofSet {
    92  		m.Debug("Assertion was 'KB' and we don't need proofset: %s", e.arg.UserAssertion)
    93  		// the resolve assertion was a keybase username or UID, so remove it
    94  		// from identify2 arg to allow cache hits on UID.
    95  		e.arg.UserAssertion = ""
    96  		// But still check on that way out that the username matches the UID
    97  		e.queriedName = rres.GetNormalizedQueriedUsername()
    98  	}
    99  
   100  	// An optimization --- plumb through the resolve body for when we load the
   101  	// user. This will save a round trip to the server.
   102  	e.i2eng.ResolveBody = rres.GetBody()
   103  
   104  	return nil
   105  }
   106  
   107  func (e *ResolveThenIdentify2) nameResolutionPostAssertion(m libkb.MetaContext) (err error) {
   108  	// Check the server for cheating on a Name->UID resolution. After we do a userload (by UID),
   109  	// we should have a merkle-verified idea of what the corresponding name is, so we check it
   110  	// as a post-assertion here.
   111  	if e.queriedName.IsNil() {
   112  		return nil
   113  	}
   114  	res, err := e.Result(m)
   115  	if err != nil {
   116  		return err
   117  	}
   118  	if !libkb.NewNormalizedUsername(res.Upk.GetName()).Eq(e.queriedName) {
   119  		return libkb.NewUIDMismatchError("bad user returned for " + e.queriedName.String())
   120  	}
   121  	return nil
   122  }
   123  
   124  func (e *ResolveThenIdentify2) Run(m libkb.MetaContext) (err error) {
   125  	m = m.WithLogTag("ID2")
   126  
   127  	defer m.Trace("ResolveThenIdentify2#Run", &err)()
   128  
   129  	e.i2eng = NewIdentify2WithUID(m.G(), e.arg)
   130  	if e.responsibleGregorItem != nil {
   131  		e.i2eng.SetResponsibleGregorItem(e.responsibleGregorItem)
   132  	}
   133  	e.i2eng.trackOptions = e.trackOptions
   134  
   135  	if err = e.resolveUID(m); err != nil {
   136  		return err
   137  	}
   138  
   139  	// For testing
   140  	e.i2eng.testArgs = e.testArgs
   141  	if err = RunEngine2(m, e.i2eng); err != nil {
   142  		return err
   143  	}
   144  
   145  	if err = e.nameResolutionPostAssertion(m); err != nil {
   146  		return err
   147  	}
   148  	return nil
   149  }
   150  
   151  func (e *ResolveThenIdentify2) Result(m libkb.MetaContext) (*keybase1.Identify2ResUPK2, error) {
   152  	if e.i2eng == nil {
   153  		return nil, errors.New("ResolveThenIdentify2#Result: no result available if the engine did not run")
   154  	}
   155  	return e.i2eng.Result(m)
   156  }
   157  
   158  func (e *ResolveThenIdentify2) SetResponsibleGregorItem(item gregor.Item) {
   159  	e.responsibleGregorItem = item
   160  }
   161  
   162  func (e *ResolveThenIdentify2) TrackToken() keybase1.TrackToken {
   163  	return e.i2eng.TrackToken()
   164  }
   165  
   166  func (e *ResolveThenIdentify2) ConfirmResult() keybase1.ConfirmResult {
   167  	return e.i2eng.ConfirmResult()
   168  }
   169  
   170  func (e *ResolveThenIdentify2) GetProofSet() *libkb.ProofSet {
   171  	if e.i2eng == nil {
   172  		return nil
   173  	}
   174  	return e.i2eng.GetProofSet()
   175  }
   176  
   177  func (e *ResolveThenIdentify2) GetIdentifyOutcome() *libkb.IdentifyOutcome {
   178  	if e.i2eng == nil {
   179  		return nil
   180  	}
   181  	return e.i2eng.GetIdentifyOutcome()
   182  }
   183  
   184  // ResolveAndCheck takes as input a name (joe), social assertion (joe@twitter)
   185  // or compound assertion (joe+joe@twitter+3883883773222@pgp) and resolves
   186  // it to a user, verifying the result. Pass into it a MetaContext without any UIs set,
   187  // since it is meant to run without any UI interaction. Tracking statements
   188  // are optionally taken into account (see flag). No ID2-specific caching will be used,
   189  // but the UPAK cache will be used, and busted with ForceRepoll semantics. The output, on success,
   190  // is a populated UserPlusKeysV2.
   191  func ResolveAndCheck(m libkb.MetaContext, s string, useTracking bool) (ret keybase1.UserPlusKeysV2, err error) {
   192  
   193  	m = m.WithLogTag("RAC")
   194  	defer m.Trace(fmt.Sprintf("ResolveAndCheck(%q,%t)", s, useTracking), &err)()
   195  
   196  	arg := keybase1.Identify2Arg{
   197  		UserAssertion:         s,
   198  		CanSuppressUI:         true,
   199  		ActLoggedOut:          !useTracking,
   200  		NoErrorOnTrackFailure: !useTracking,
   201  		IdentifyBehavior:      keybase1.TLFIdentifyBehavior_RESOLVE_AND_CHECK,
   202  	}
   203  	eng := NewResolveThenIdentify2(m.G(), &arg)
   204  	if err = RunEngine2(m, eng); err != nil {
   205  		return ret, err
   206  	}
   207  	res, err := eng.Result(m)
   208  	if err != nil {
   209  		return ret, err
   210  	}
   211  	// Success path.
   212  	return res.Upk.Current, nil
   213  }