github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/untrack.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 "github.com/keybase/client/go/libkb" 8 keybase1 "github.com/keybase/client/go/protocol/keybase1" 9 ) 10 11 type UntrackEngineArg struct { 12 Username libkb.NormalizedUsername 13 Me *libkb.User 14 SigVersion libkb.SigVersion 15 } 16 17 type UntrackEngine struct { 18 arg *UntrackEngineArg 19 signingKeyPub libkb.GenericKey 20 untrackStatementBytes []byte 21 untrackStatement *libkb.ProofMetadataRes 22 libkb.Contextified 23 } 24 25 // NewUntrackEngine creates a default UntrackEngine for tracking theirName. 26 func NewUntrackEngine(g *libkb.GlobalContext, arg *UntrackEngineArg) *UntrackEngine { 27 if arg.SigVersion == libkb.KeybaseNullSigVersion { 28 arg.SigVersion = libkb.GetDefaultSigVersion(g) 29 } 30 31 return &UntrackEngine{ 32 arg: arg, 33 Contextified: libkb.NewContextified(g), 34 } 35 } 36 37 func (e *UntrackEngine) Name() string { 38 return "Untrack" 39 } 40 41 func (e *UntrackEngine) Prereqs() Prereqs { 42 return Prereqs{ 43 Device: true, 44 } 45 } 46 47 func (e *UntrackEngine) RequiredUIs() []libkb.UIKind { 48 return []libkb.UIKind{} 49 } 50 51 func (e *UntrackEngine) SubConsumers() []libkb.UIConsumer { 52 return []libkb.UIConsumer{} 53 } 54 55 func (e *UntrackEngine) Run(m libkb.MetaContext) (err error) { 56 defer m.Trace("UntrackEngine#Run", &err)() 57 58 e.arg.Me, err = e.loadMe() 59 if err != nil { 60 return 61 } 62 63 them, remoteLink, localLink, err := e.loadThem(m) 64 if err != nil { 65 return 66 } 67 68 e.signingKeyPub, err = e.arg.Me.SigningKeyPub() 69 if err != nil { 70 return 71 } 72 73 e.untrackStatement, err = e.arg.Me.UntrackingProofFor(m, e.signingKeyPub, e.arg.SigVersion, them) 74 if err != nil { 75 return 76 } 77 78 e.untrackStatementBytes, err = e.untrackStatement.J.Marshal() 79 if err != nil { 80 return 81 } 82 83 e.G().Log.Debug("| Untracking statement: %s", string(e.untrackStatementBytes)) 84 85 didUntrack := false 86 87 if localLink != nil { 88 err = e.storeLocalUntrack(m, them) 89 if err != nil { 90 return 91 } 92 didUntrack = true 93 } 94 95 if remoteLink != nil && !remoteLink.IsRevoked() { 96 err = e.storeRemoteUntrack(m, them) 97 if err != nil { 98 return 99 } 100 didUntrack = true 101 } 102 103 if !didUntrack { 104 err = libkb.NewUntrackError("User %s is already untracked", e.arg.Username) 105 return 106 } 107 108 e.G().UserChanged(m.Ctx(), e.arg.Me.GetUID()) 109 e.G().UserChanged(m.Ctx(), them.GetUID()) 110 111 e.G().NotifyRouter.HandleTrackingChanged(e.arg.Me.GetUID(), e.arg.Me.GetNormalizedName(), false) 112 e.G().NotifyRouter.HandleTrackingChanged(them.GetUID(), them.GetNormalizedName(), false) 113 m.G().IdentifyDispatch.NotifyTrackingSuccess(m, them.GetUID()) 114 115 return 116 } 117 118 func (e *UntrackEngine) loadMe() (me *libkb.User, err error) { 119 return libkb.LoadMe(libkb.NewLoadUserArg(e.G())) 120 } 121 122 func (e *UntrackEngine) loadThem(m libkb.MetaContext) (them *libkb.User, remoteLink, localLink *libkb.TrackChainLink, err error) { 123 var rLink *libkb.TrackChainLink 124 trackMap := e.arg.Me.IDTable().GetTrackMap() 125 if links, ok := trackMap[e.arg.Username]; ok && (len(links) > 0) { 126 rLink = links[len(links)-1] 127 } 128 129 var uid keybase1.UID 130 uidTrusted := false 131 if rLink != nil { 132 if uid, err = rLink.GetTrackedUID(); err != nil { 133 return 134 } 135 uidTrusted = true 136 } 137 138 if uid.IsNil() { 139 res := e.G().Resolver.Resolve(m, e.arg.Username.String()) 140 if err = res.GetError(); err != nil { 141 return 142 } 143 144 // This is an untrusted uid. 145 uid = res.GetUID() 146 if uid.IsNil() { 147 err = libkb.NewUntrackError("Could not resolve uid for @%s", e.arg.Username) 148 return 149 } 150 } 151 152 lLink, err := libkb.LocalTrackChainLinkFor(m, e.arg.Me.GetUID(), uid) 153 if err != nil { 154 return 155 } 156 157 if rLink == nil && lLink == nil { 158 err = libkb.NewUntrackError("You are not tracking %s", e.arg.Username) 159 return 160 } 161 162 if !uidTrusted { 163 if lLink == nil { 164 err = libkb.NewUntrackError("Could not verify resolved uid for @%s", e.arg.Username) 165 return 166 } 167 168 var trackedUsername libkb.NormalizedUsername 169 trackedUsername, err = lLink.GetTrackedUsername() 170 if err != nil { 171 return 172 } 173 174 if !e.arg.Username.Eq(trackedUsername) { 175 err = libkb.NewUntrackError("Username mismatch: expected @%s, got @%s", e.arg.Username, trackedUsername) 176 return 177 } 178 } 179 180 them = libkb.NewUserThin(e.arg.Username.String(), uid) 181 remoteLink = rLink 182 localLink = lLink 183 return 184 } 185 186 func (e *UntrackEngine) storeLocalUntrack(m libkb.MetaContext, them *libkb.User) error { 187 // Also do a removal in case of expiring local tracks 188 return libkb.RemoveLocalTracks(m, e.arg.Me.GetUID(), them.GetUID()) 189 } 190 191 func (e *UntrackEngine) storeRemoteUntrack(m libkb.MetaContext, them *libkb.User) (err error) { 192 defer m.Trace("UntrackEngine#StoreRemoteUntrack", &err)() 193 194 me := e.arg.Me 195 arg := libkb.SecretKeyArg{ 196 Me: me, 197 KeyType: libkb.DeviceSigningKeyType, 198 } 199 var signingKey libkb.GenericKey 200 if signingKey, err = e.G().Keyrings.GetSecretKeyWithPrompt(m, m.SecretKeyPromptArg(arg, "untracking signature")); err != nil { 201 return 202 } 203 204 sigVersion := e.arg.SigVersion 205 sig, sigID, linkID, err := libkb.MakeSig( 206 m, 207 signingKey, 208 libkb.LinkTypeUntrack, 209 e.untrackStatementBytes, 210 false, /* hasRevokes */ 211 keybase1.SeqType_PUBLIC, 212 false, /* ignoreIfUnsupported */ 213 me, 214 sigVersion) 215 216 if err != nil { 217 return 218 } 219 220 httpsArgs := libkb.HTTPArgs{ 221 "sig_id_base": libkb.S{Val: sigID.StripSuffix().String()}, 222 "sig_id_short": libkb.S{Val: sigID.ToShortID()}, 223 "sig": libkb.S{Val: sig}, 224 "uid": libkb.UIDArg(them.GetUID()), 225 "type": libkb.S{Val: "untrack"}, 226 "signing_kid": e.signingKeyPub.GetKID(), 227 } 228 229 if sigVersion == libkb.KeybaseSignatureV2 { 230 httpsArgs["sig_inner"] = libkb.S{Val: string(e.untrackStatementBytes)} 231 } 232 233 _, err = m.G().API.Post(m, libkb.APIArg{ 234 Endpoint: "follow", 235 SessionType: libkb.APISessionTypeREQUIRED, 236 Args: httpsArgs, 237 }) 238 if err != nil { 239 return err 240 } 241 return libkb.MerkleCheckPostedUserSig(m, me.GetUID(), e.untrackStatement.Seqno, linkID) 242 }