github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/buffered_identify_ui.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 "path" 8 "runtime" 9 "sync" 10 11 "github.com/keybase/client/go/libkb" 12 keybase1 "github.com/keybase/client/go/protocol/keybase1" 13 ) 14 15 type start struct { 16 s string 17 r keybase1.IdentifyReason 18 f bool 19 } 20 21 type proofCheck struct { 22 social bool 23 p keybase1.RemoteProof 24 l keybase1.LinkCheckResult 25 } 26 27 type launchNetworkChecks struct { 28 i *keybase1.Identity 29 u *keybase1.User 30 } 31 32 type bufferedIdentifyUI struct { 33 libkb.Contextified 34 sync.Mutex 35 raw libkb.IdentifyUI 36 confirmIfSuppressed keybase1.ConfirmResult 37 bufferedMode bool 38 start *start 39 proofChecks []proofCheck 40 cryptocurrency []keybase1.Cryptocurrency 41 stellar *keybase1.StellarAccount 42 launchNetworkChecks *launchNetworkChecks 43 keys []keybase1.IdentifyKey 44 lastTrack **keybase1.TrackSummary 45 suppressed bool 46 userCard *keybase1.UserCard 47 } 48 49 var _ libkb.IdentifyUI = (*bufferedIdentifyUI)(nil) 50 51 func newBufferedIdentifyUI(g *libkb.GlobalContext, u libkb.IdentifyUI, c keybase1.ConfirmResult) *bufferedIdentifyUI { 52 return &bufferedIdentifyUI{ 53 Contextified: libkb.NewContextified(g), 54 raw: u, 55 confirmIfSuppressed: c, 56 bufferedMode: true, 57 } 58 } 59 60 func (b *bufferedIdentifyUI) Start(m libkb.MetaContext, s string, r keybase1.IdentifyReason, f bool) error { 61 b.Lock() 62 defer b.Unlock() 63 b.start = &start{s, r, f} 64 return b.flush(m, false) 65 } 66 67 func (b *bufferedIdentifyUI) flush(m libkb.MetaContext, trackingBroke bool) (err error) { 68 69 // Look up the calling function for debugging purposes 70 pc := make([]uintptr, 10) // at least 1 entry needed 71 runtime.Callers(2, pc) 72 f := runtime.FuncForPC(pc[0]) 73 caller := path.Base(f.Name()) 74 75 m.Debug("+ bufferedIdentifyUI#flush(%v) [caller=%s, buffered=%v, suppressed=%v]", trackingBroke, caller, b.bufferedMode, b.suppressed) 76 77 if !trackingBroke && b.bufferedMode { 78 m.Debug("- bufferedIdentifyUI#flush: short-circuit") 79 return nil 80 } 81 82 defer func() { 83 b.flushCleanup() 84 m.Debug("- bufferedIdentifyUI#flush -> %v", err) 85 }() 86 87 if b.start != nil { 88 err = b.raw.Start(m, b.start.s, b.start.r, b.start.f) 89 if err != nil { 90 return err 91 } 92 } 93 94 for _, k := range b.keys { 95 err = b.raw.DisplayKey(m, k) 96 if err != nil { 97 return err 98 } 99 } 100 101 if b.lastTrack != nil { 102 err = b.raw.ReportLastTrack(m, *b.lastTrack) 103 if err != nil { 104 return err 105 } 106 } 107 108 if b.launchNetworkChecks != nil { 109 err = b.raw.LaunchNetworkChecks(m, b.launchNetworkChecks.i, b.launchNetworkChecks.u) 110 if err != nil { 111 return err 112 } 113 } 114 115 if b.userCard != nil { 116 err = b.raw.DisplayUserCard(m, *b.userCard) 117 if err != nil { 118 return err 119 } 120 } 121 122 for _, w := range b.proofChecks { 123 var err error 124 if w.social { 125 err = b.raw.FinishSocialProofCheck(m, w.p, w.l) 126 } else { 127 err = b.raw.FinishWebProofCheck(m, w.p, w.l) 128 } 129 if err != nil { 130 return err 131 } 132 } 133 134 for _, c := range b.cryptocurrency { 135 err = b.raw.DisplayCryptocurrency(m, c) 136 if err != nil { 137 return err 138 } 139 } 140 141 if b.stellar != nil { 142 err = b.raw.DisplayStellarAccount(m, *b.stellar) 143 if err != nil { 144 return err 145 } 146 } 147 148 return nil 149 } 150 151 func (b *bufferedIdentifyUI) flushCleanup() { 152 b.start = nil 153 b.proofChecks = nil 154 b.cryptocurrency = nil 155 b.stellar = nil 156 b.bufferedMode = false 157 b.launchNetworkChecks = nil 158 b.keys = nil 159 b.lastTrack = nil 160 b.userCard = nil 161 } 162 163 func (b *bufferedIdentifyUI) FinishWebProofCheck(m libkb.MetaContext, p keybase1.RemoteProof, l keybase1.LinkCheckResult) error { 164 b.Lock() 165 defer b.Unlock() 166 b.proofChecks = append(b.proofChecks, proofCheck{false, p, l}) 167 return b.flush(m, l.BreaksTracking) 168 } 169 170 func (b *bufferedIdentifyUI) FinishSocialProofCheck(m libkb.MetaContext, p keybase1.RemoteProof, l keybase1.LinkCheckResult) error { 171 b.Lock() 172 defer b.Unlock() 173 b.proofChecks = append(b.proofChecks, proofCheck{true, p, l}) 174 return b.flush(m, l.BreaksTracking) 175 } 176 177 func (b *bufferedIdentifyUI) Confirm(m libkb.MetaContext, o *keybase1.IdentifyOutcome) (keybase1.ConfirmResult, error) { 178 b.Lock() 179 defer b.Unlock() 180 if b.bufferedMode { 181 m.Debug("| bufferedIdentifyUI#Confirm: suppressing output") 182 b.suppressed = true 183 return b.confirmIfSuppressed, nil 184 } 185 m.Debug("| bufferedIdentifyUI#Confirm: enabling output") 186 b.flush(m, true) 187 return b.raw.Confirm(m, o) 188 } 189 190 func (b *bufferedIdentifyUI) DisplayCryptocurrency(m libkb.MetaContext, c keybase1.Cryptocurrency) error { 191 b.Lock() 192 defer b.Unlock() 193 b.cryptocurrency = append(b.cryptocurrency, c) 194 return b.flush(m, false) 195 } 196 197 func (b *bufferedIdentifyUI) DisplayStellarAccount(m libkb.MetaContext, c keybase1.StellarAccount) error { 198 b.Lock() 199 defer b.Unlock() 200 b.stellar = &c 201 return b.flush(m, false) 202 } 203 204 func (b *bufferedIdentifyUI) DisplayKey(m libkb.MetaContext, k keybase1.IdentifyKey) error { 205 b.Lock() 206 defer b.Unlock() 207 b.keys = append(b.keys, k) 208 return b.flush(m, k.BreaksTracking) 209 } 210 211 func (b *bufferedIdentifyUI) ReportLastTrack(m libkb.MetaContext, s *keybase1.TrackSummary) error { 212 b.Lock() 213 defer b.Unlock() 214 b.lastTrack = &s 215 return b.flush(m, false) 216 } 217 218 func (b *bufferedIdentifyUI) LaunchNetworkChecks(m libkb.MetaContext, i *keybase1.Identity, u *keybase1.User) error { 219 b.Lock() 220 defer b.Unlock() 221 b.launchNetworkChecks = &launchNetworkChecks{i, u} 222 return b.flush(m, i.BreaksTracking) 223 } 224 225 func (b *bufferedIdentifyUI) DisplayTrackStatement(m libkb.MetaContext, s string) error { 226 return b.raw.DisplayTrackStatement(m, s) 227 } 228 229 func (b *bufferedIdentifyUI) DisplayUserCard(m libkb.MetaContext, c keybase1.UserCard) error { 230 b.Lock() 231 defer b.Unlock() 232 b.userCard = &c 233 return b.flush(m, false) 234 } 235 236 func (b *bufferedIdentifyUI) ReportTrackToken(m libkb.MetaContext, t keybase1.TrackToken) error { 237 b.Lock() 238 defer b.Unlock() 239 if b.suppressed { 240 return nil 241 } 242 return b.raw.ReportTrackToken(m, t) 243 } 244 245 func (b *bufferedIdentifyUI) Cancel(m libkb.MetaContext) error { 246 b.Lock() 247 defer b.Unlock() 248 249 // Cancel should always go through to UI server 250 return b.raw.Cancel(m) 251 } 252 253 func (b *bufferedIdentifyUI) Finish(m libkb.MetaContext) error { 254 b.Lock() 255 defer b.Unlock() 256 if b.suppressed { 257 m.Debug("| bufferedIdentifyUI#Finish: suppressed") 258 return nil 259 } 260 m.Debug("| bufferedIdentifyUI#Finish: went through to UI") 261 262 // This is likely a noop since we already covered this case in the `Confirm` step 263 // above. However, if due a bug we forgot to call `Confirm` from the UI, this 264 // is still useful. 265 b.flush(m, true) 266 267 return b.raw.Finish(m) 268 } 269 270 func (b *bufferedIdentifyUI) DisplayTLFCreateWithInvite(m libkb.MetaContext, d keybase1.DisplayTLFCreateWithInviteArg) error { 271 return b.raw.DisplayTLFCreateWithInvite(m, d) 272 } 273 274 func (b *bufferedIdentifyUI) Dismiss(m libkb.MetaContext, s string, r keybase1.DismissReason) error { 275 return b.raw.Dismiss(m, s, r) 276 }