github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/identify3/service.go (about) 1 package identify3 2 3 import ( 4 "fmt" 5 6 "github.com/keybase/client/go/engine" 7 "github.com/keybase/client/go/libkb" 8 keybase1 "github.com/keybase/client/go/protocol/keybase1" 9 ) 10 11 func Identify3(mctx libkb.MetaContext, ui3 keybase1.Identify3UiInterface, arg keybase1.Identify3Arg) (err error) { 12 ui1, err := NewUIAdapterMakeSession(mctx.BackgroundWithLogTags(), ui3, arg.GuiID) 13 if err != nil { 14 return err 15 } 16 i2arg := keybase1.Identify2Arg{ 17 UserAssertion: string(arg.Assertion), 18 ForceRemoteCheck: arg.IgnoreCache, 19 ForceDisplay: true, 20 IdentifyBehavior: keybase1.TLFIdentifyBehavior_GUI_PROFILE, 21 NoSkipSelf: true, 22 } 23 mctx = mctx.WithIdentifyUI(ui1) 24 eng := engine.NewResolveThenIdentify2(mctx.G(), &i2arg) 25 err = engine.RunEngine2(mctx, eng) 26 if err != nil { 27 return err 28 } 29 30 return nil 31 } 32 33 type identify3Action int 34 35 const ( 36 identify3ActionFollow identify3Action = 1 37 identify3ActionUnfollow identify3Action = 2 38 identify3ActionIgnore identify3Action = 3 39 ) 40 41 func FollowUser(mctx libkb.MetaContext, arg keybase1.Identify3FollowUserArg) (err error) { 42 var action identify3Action 43 if arg.Follow { 44 action = identify3ActionFollow 45 } else { 46 action = identify3ActionUnfollow 47 } 48 return doActionAndRemove(mctx, arg.GuiID, action) 49 } 50 51 func doAction(mctx libkb.MetaContext, guiID keybase1.Identify3GUIID, action identify3Action) error { 52 sess, err := mctx.G().Identify3State.Get(guiID) 53 if err != nil { 54 return err 55 } 56 if sess == nil { 57 return libkb.NewNotFoundError(fmt.Sprintf("session %s wasn't found", guiID)) 58 } 59 60 // Lock the session mainly because we want to protect the outcome, which unfortunately 61 // is difficult to copy. But be certain never to grab the Identify3State lock while 62 // holding the session lock (see comment below in doActionAndRemove). 63 sess.Lock() 64 defer sess.Unlock() 65 outcome := sess.OutcomeLocked() 66 67 if outcome == nil { 68 return libkb.NewNotFoundError(fmt.Sprintf("outcome for session %s wasn't ready; is there a race?", guiID)) 69 } 70 71 switch action { 72 case identify3ActionFollow, identify3ActionIgnore: 73 err = doFollow(mctx, action, outcome) 74 case identify3ActionUnfollow: 75 err = doUnfollow(mctx, outcome) 76 } 77 78 return err 79 } 80 81 func doActionAndRemove(mctx libkb.MetaContext, guiID keybase1.Identify3GUIID, action identify3Action) error { 82 err := doAction(mctx, guiID, action) 83 if err != nil { 84 return err 85 } 86 87 // It's important not to hold the session lock when calling this function, since the background expire 88 // thread in identify3 grabs the state lock and then the session locks. 89 mctx.G().Identify3State.Remove(guiID) 90 91 return err 92 } 93 94 func doUnfollow(mctx libkb.MetaContext, outcome *libkb.IdentifyOutcome) (err error) { 95 sv := libkb.KeybaseSignatureV2 96 uarg := engine.UntrackEngineArg{ 97 Username: outcome.Username, 98 SigVersion: sv, 99 } 100 eng := engine.NewUntrackEngine(mctx.G(), &uarg) 101 return engine.RunEngine2(mctx, eng) 102 } 103 104 func doFollow(mctx libkb.MetaContext, action identify3Action, outcome *libkb.IdentifyOutcome) (err error) { 105 sv := keybase1.SigVersion(2) 106 ttarg := engine.TrackTokenArg{ 107 Options: keybase1.TrackOptions{ 108 SigVersion: &sv, 109 }, 110 Outcome: outcome, 111 } 112 if action == identify3ActionIgnore { 113 ttarg.Options.ExpiringLocal = true 114 } 115 eng := engine.NewTrackToken(mctx.G(), &ttarg) 116 return engine.RunEngine2(mctx, eng) 117 } 118 119 func IgnoreUser(mctx libkb.MetaContext, guiID keybase1.Identify3GUIID) (err error) { 120 return doActionAndRemove(mctx, guiID, identify3ActionIgnore) 121 }