github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/systests/delegate_ui_test.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 systests 5 6 import ( 7 "fmt" 8 "testing" 9 "time" 10 11 "github.com/keybase/client/go/client" 12 "github.com/keybase/client/go/service" 13 14 keybase1 "github.com/keybase/client/go/protocol/keybase1" 15 "github.com/keybase/go-framed-msgpack-rpc/rpc" 16 context "golang.org/x/net/context" 17 ) 18 19 type delegateUI struct { 20 T *testing.T 21 ch chan error 22 delegated bool 23 started bool 24 finished bool 25 canceled bool 26 27 launchedGithub bool 28 foundGithub bool 29 launchedTwitter bool 30 foundTwitter bool 31 } 32 33 // delegateUI implements the keybase1.IdentifyUiInterface 34 var _ keybase1.IdentifyUiInterface = (*delegateUI)(nil) 35 36 func (d *delegateUI) checkDelegated() error { 37 if !d.delegated { 38 return d.setError(fmt.Errorf("Can't run UI since it wasn't properly delegated")) 39 } 40 return nil 41 } 42 43 func (d *delegateUI) setError(e error) error { 44 d.T.Logf("delegateUI error: %v", e) 45 fmt.Printf("delegateUI error: %v\n", e) 46 go func() { d.ch <- e }() 47 return e 48 } 49 50 func (d *delegateUI) checkStarted() error { 51 if err := d.checkDelegated(); err != nil { 52 return err 53 } 54 if !d.started { 55 return d.setError(fmt.Errorf("Can't run UI since it wasn't properly started")) 56 } 57 if d.canceled { 58 return d.setError(fmt.Errorf("Can't run UI after Cancel() was called")) 59 } 60 return nil 61 } 62 63 func (d *delegateUI) DelegateIdentifyUI(context.Context) (int, error) { 64 d.delegated = true 65 return 1, nil 66 } 67 func (d *delegateUI) Start(context.Context, keybase1.StartArg) error { 68 if err := d.checkDelegated(); err != nil { 69 return err 70 } 71 d.started = true 72 return nil 73 } 74 75 func (d *delegateUI) DisplayKey(context.Context, keybase1.DisplayKeyArg) error { 76 return d.checkStarted() 77 } 78 func (d *delegateUI) ReportLastTrack(context.Context, keybase1.ReportLastTrackArg) error { 79 return d.checkStarted() 80 } 81 func (d *delegateUI) LaunchNetworkChecks(_ context.Context, arg keybase1.LaunchNetworkChecksArg) error { 82 if err := d.checkStarted(); err != nil { 83 return err 84 } 85 for _, proof := range arg.Identity.Proofs { 86 switch proof.Proof.Key { 87 case "twitter": 88 d.launchedTwitter = true 89 case "github": 90 d.launchedGithub = true 91 } 92 } 93 return nil 94 } 95 func (d *delegateUI) DisplayTrackStatement(context.Context, keybase1.DisplayTrackStatementArg) error { 96 return d.checkStarted() 97 } 98 func (d *delegateUI) ReportTrackToken(context.Context, keybase1.ReportTrackTokenArg) error { 99 return d.checkStarted() 100 } 101 func (d *delegateUI) FinishWebProofCheck(context.Context, keybase1.FinishWebProofCheckArg) error { 102 return d.checkStarted() 103 } 104 func (d *delegateUI) FinishSocialProofCheck(_ context.Context, arg keybase1.FinishSocialProofCheckArg) error { 105 if err := d.checkStarted(); err != nil { 106 return err 107 } 108 switch arg.Rp.Key { 109 case "twitter": 110 d.foundTwitter = true 111 case "github": 112 d.foundGithub = true 113 } 114 return nil 115 } 116 func (d *delegateUI) DisplayCryptocurrency(context.Context, keybase1.DisplayCryptocurrencyArg) error { 117 return d.checkStarted() 118 } 119 func (d *delegateUI) DisplayStellarAccount(context.Context, keybase1.DisplayStellarAccountArg) error { 120 return d.checkStarted() 121 } 122 func (d *delegateUI) DisplayUserCard(context.Context, keybase1.DisplayUserCardArg) error { 123 return d.checkStarted() 124 } 125 func (d *delegateUI) Confirm(context.Context, keybase1.ConfirmArg) (res keybase1.ConfirmResult, err error) { 126 if err = d.checkStarted(); err != nil { 127 return res, err 128 } 129 res.IdentityConfirmed = true 130 res.RemoteConfirmed = true 131 return res, nil 132 } 133 func (d *delegateUI) Cancel(context.Context, int) error { 134 close(d.ch) 135 d.canceled = true 136 return nil 137 } 138 func (d *delegateUI) Finish(context.Context, int) error { 139 if err := d.checkStarted(); err != nil { 140 return err 141 } 142 d.finished = true 143 return nil 144 } 145 func (d *delegateUI) Dismiss(context.Context, keybase1.DismissArg) error { 146 return d.checkStarted() 147 } 148 149 func (d *delegateUI) DisplayTLFCreateWithInvite(context.Context, keybase1.DisplayTLFCreateWithInviteArg) error { 150 return nil 151 } 152 153 func (d *delegateUI) checkSuccess() error { 154 if !d.launchedGithub || !d.foundGithub || !d.launchedTwitter || !d.foundTwitter || !d.canceled { 155 return fmt.Errorf("Bad final state for delegate UI: %+v", d) 156 } 157 return nil 158 } 159 160 func newDelegateUI(t *testing.T) *delegateUI { 161 return &delegateUI{ 162 T: t, 163 ch: make(chan error), 164 } 165 } 166 167 func TestDelegateUI(t *testing.T) { 168 tc := setupTest(t, "delegate_ui") 169 defer tc.Cleanup() 170 171 tc1 := cloneContext(tc) 172 defer tc1.Cleanup() 173 tc2 := cloneContext(tc) 174 defer tc2.Cleanup() 175 176 stopCh := make(chan error) 177 svc := service.NewService(tc.G, false) 178 startCh := svc.GetStartChannel() 179 go func() { 180 err := svc.Run() 181 if err != nil { 182 t.Logf("Running the service produced an error: %v", err) 183 } 184 stopCh <- err 185 }() 186 187 // Wait for the server to start up 188 <-startCh 189 dui := newDelegateUI(t) 190 191 launchDelegateUI := func(dui *delegateUI) error { 192 cli, xp, err := client.GetRPCClientWithContext(tc2.G) 193 if err != nil { 194 return err 195 } 196 srv := rpc.NewServer(xp, nil) 197 if err = srv.Register(keybase1.IdentifyUiProtocol(dui)); err != nil { 198 return err 199 } 200 ncli := keybase1.DelegateUiCtlClient{Cli: cli} 201 return ncli.RegisterIdentifyUI(context.TODO()) 202 } 203 204 // Launch the delegate UI 205 if err := launchDelegateUI(dui); err != nil { 206 t.Fatal(err) 207 } 208 209 id := client.NewCmdIDRunner(tc1.G) 210 id.SetUser("t_alice") 211 id.UseDelegateUI() 212 if err := id.Run(); err != nil { 213 t.Fatalf("Error in Run: %v", err) 214 } 215 216 // We should get either a 'done' or an 'error' from the delegateUI. 217 select { 218 case err, ok := <-dui.ch: 219 if err != nil { 220 t.Errorf("Error with delegate UI: %v", err) 221 } else if ok { 222 t.Errorf("Delegate UI didn't close the channel properly") 223 } else if err = dui.checkSuccess(); err != nil { 224 t.Error(err) 225 } 226 case <-time.After(20 * time.Second): 227 t.Fatal("no callback from delegate UI") 228 } 229 230 if err := CtlStop(tc1.G); err != nil { 231 t.Errorf("Error in stopping service: %v", err) 232 } 233 234 // If the server failed, it's also an error 235 if err := <-stopCh; err != nil { 236 t.Fatal(err) 237 } 238 }