github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/systests/tracking_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 "testing" 8 9 "github.com/keybase/client/go/client" 10 "github.com/keybase/client/go/libkb" 11 keybase1 "github.com/keybase/client/go/protocol/keybase1" 12 "github.com/keybase/client/go/service" 13 "github.com/keybase/go-framed-msgpack-rpc/rpc" 14 "github.com/stretchr/testify/require" 15 context "golang.org/x/net/context" 16 ) 17 18 type trackingUI struct { 19 signupUI 20 } 21 22 func (n *trackingUI) GetIdentifyTrackUI() libkb.IdentifyUI { 23 return &identifyUI{} 24 } 25 26 type identifyUI struct { 27 } 28 29 func (*identifyUI) Confirm(libkb.MetaContext, *keybase1.IdentifyOutcome) (keybase1.ConfirmResult, error) { 30 return keybase1.ConfirmResult{ 31 IdentityConfirmed: true, 32 RemoteConfirmed: true, 33 }, nil 34 } 35 func (*identifyUI) Start(libkb.MetaContext, string, keybase1.IdentifyReason, bool) error { 36 return nil 37 } 38 func (*identifyUI) FinishWebProofCheck(libkb.MetaContext, keybase1.RemoteProof, keybase1.LinkCheckResult) error { 39 return nil 40 } 41 func (*identifyUI) FinishSocialProofCheck(libkb.MetaContext, keybase1.RemoteProof, keybase1.LinkCheckResult) error { 42 return nil 43 } 44 func (*identifyUI) DisplayCryptocurrency(libkb.MetaContext, keybase1.Cryptocurrency) error { 45 return nil 46 } 47 func (*identifyUI) DisplayStellarAccount(libkb.MetaContext, keybase1.StellarAccount) error { 48 return nil 49 } 50 func (*identifyUI) DisplayKey(libkb.MetaContext, keybase1.IdentifyKey) error { 51 return nil 52 } 53 func (*identifyUI) ReportLastTrack(libkb.MetaContext, *keybase1.TrackSummary) error { 54 return nil 55 } 56 func (*identifyUI) LaunchNetworkChecks(libkb.MetaContext, *keybase1.Identity, *keybase1.User) error { 57 return nil 58 } 59 func (*identifyUI) DisplayTrackStatement(libkb.MetaContext, string) error { 60 return nil 61 } 62 func (*identifyUI) DisplayUserCard(libkb.MetaContext, keybase1.UserCard) error { 63 return nil 64 } 65 func (*identifyUI) ReportTrackToken(libkb.MetaContext, keybase1.TrackToken) error { 66 return nil 67 } 68 func (*identifyUI) SetStrict(b bool) {} 69 func (*identifyUI) Cancel(libkb.MetaContext) error { 70 return nil 71 } 72 func (*identifyUI) Finish(libkb.MetaContext) error { 73 return nil 74 } 75 func (*identifyUI) Dismiss(libkb.MetaContext, string, keybase1.DismissReason) error { 76 return nil 77 } 78 79 func (*identifyUI) DisplayTLFCreateWithInvite(libkb.MetaContext, keybase1.DisplayTLFCreateWithInviteArg) error { 80 return nil 81 } 82 83 type trackingNotifyHandler struct { 84 trackingCh chan keybase1.TrackingChangedArg 85 errCh chan error 86 } 87 88 func newTrackingNotifyHandler() *trackingNotifyHandler { 89 return &trackingNotifyHandler{ 90 trackingCh: make(chan keybase1.TrackingChangedArg), 91 errCh: make(chan error), 92 } 93 } 94 95 func (h *trackingNotifyHandler) TrackingChanged(_ context.Context, arg keybase1.TrackingChangedArg) error { 96 h.trackingCh <- arg 97 return nil 98 } 99 100 func (h *trackingNotifyHandler) TrackingInfo(context.Context, keybase1.TrackingInfoArg) error { 101 return nil 102 } 103 104 func (h *trackingNotifyHandler) NotifyUserBlocked(context.Context, keybase1.UserBlockedSummary) error { 105 return nil 106 } 107 108 func TestTrackingNotifications(t *testing.T) { 109 tc := setupTest(t, "signup") 110 defer tc.Cleanup() 111 tc2 := cloneContext(tc) 112 defer tc2.Cleanup() 113 tc5 := cloneContext(tc) 114 defer tc5.Cleanup() 115 116 // Hack the various portions of the service that aren't 117 // properly contextified. 118 119 stopCh := make(chan error) 120 svc := service.NewService(tc.G, false) 121 startCh := svc.GetStartChannel() 122 go func() { 123 err := svc.Run() 124 if err != nil { 125 t.Logf("Running the service produced an error: %v", err) 126 } 127 stopCh <- err 128 }() 129 130 userInfo := randomUser("sgnup") 131 132 tui := trackingUI{ 133 signupUI: signupUI{ 134 info: userInfo, 135 Contextified: libkb.NewContextified(tc2.G), 136 }, 137 } 138 tc2.G.SetUI(&tui) 139 signup := client.NewCmdSignupRunner(tc2.G) 140 signup.SetTest() 141 142 <-startCh 143 144 if err := signup.Run(); err != nil { 145 t.Fatal(err) 146 } 147 nh := newTrackingNotifyHandler() 148 149 // Launch the server that will listen for tracking notifications. 150 launchServer := func(nh *trackingNotifyHandler) error { 151 cli, xp, err := client.GetRPCClientWithContext(tc5.G) 152 if err != nil { 153 return err 154 } 155 srv := rpc.NewServer(xp, nil) 156 if err = srv.Register(keybase1.NotifyTrackingProtocol(nh)); err != nil { 157 return err 158 } 159 ncli := keybase1.NotifyCtlClient{Cli: cli} 160 return ncli.SetNotifications(context.TODO(), keybase1.NotificationChannels{ 161 Tracking: true, 162 }) 163 } 164 165 // Actually launch it in the background 166 go func() { 167 err := launchServer(nh) 168 if err != nil { 169 nh.errCh <- err 170 } 171 }() 172 173 // Have our test user track t_alice. 174 trackCmd := client.NewCmdTrackRunner(tc2.G) 175 trackCmd.SetUser("t_alice") 176 trackCmd.SetOptions(keybase1.TrackOptions{BypassConfirm: true}) 177 err := trackCmd.Run() 178 if err != nil { 179 t.Fatal(err) 180 } 181 182 // Do a check for new tracking statements that should fire off a 183 // notification. Currently the track command above does not fetch the new 184 // chain link from the server, so this call is required. It's possible that 185 // TrackEngine (or our signature caching code) might change in the future, 186 // making this call unnecessary. 187 checkTrackingCmd := client.NewCmdCheckTrackingRunner(tc2.G) 188 err = checkTrackingCmd.Run() 189 if err != nil { 190 t.Fatal(err) 191 } 192 193 // Wait to get a notification back as we expect. 194 // NOTE: If this test ever starts deadlocking here, it's possible that 195 // we've changed how we cache signatures that we make on the local client, 196 // in such a way that the fetch done by CheckTracking above doesn't find 197 // any "isOwnNewLinkFromServer" links. If so, one way to fix this test 198 // would be to blow away the local db before calling CheckTracking. 199 tc.G.Log.Debug("Waiting for two tracking notifications.") 200 for i := 0; i < 2; i++ { 201 select { 202 case err := <-nh.errCh: 203 t.Fatalf("Error before notify: %v", err) 204 case arg := <-nh.trackingCh: 205 tAliceUID := keybase1.UID("295a7eea607af32040647123732bc819") 206 tc.G.Log.Debug("Got tracking changed notification (%#v)", arg) 207 if "t_alice" == arg.Username { 208 if !tAliceUID.Equal(arg.Uid) { 209 t.Fatalf("Bad UID back: %s != %s", tAliceUID, arg.Uid) 210 } 211 } else if userInfo.username == arg.Username { 212 if !tc.G.Env.GetUID().Equal(arg.Uid) { 213 t.Fatalf("Bad UID back: %s != %s", tc.G.Env.GetUID(), arg.Uid) 214 } 215 } else { 216 t.Fatalf("Bad username back: %s != %s || %s", arg.Username, "t_alice", userInfo.username) 217 } 218 } 219 } 220 221 if err := CtlStop(tc2.G); err != nil { 222 t.Fatal(err) 223 } 224 225 // If the server failed, it's also an error 226 if err := <-stopCh; err != nil { 227 t.Fatal(err) 228 } 229 } 230 231 func TestV2Compressed(t *testing.T) { 232 tt := newTeamTester(t) 233 defer tt.cleanup() 234 235 ctx := context.TODO() 236 237 alice := tt.addUser("alice") 238 aliceG := alice.tc.G 239 240 tt.addUser("wong") 241 wong := tt.users[1] 242 wongG := wong.tc.G 243 upk, err := wongG.GetUPAKLoader().LoadUserPlusKeys(ctx, wong.uid, "") 244 require.NoError(t, err) 245 246 iuiW := newSimpleIdentifyUI() 247 attachIdentifyUI(t, wongG, iuiW) 248 iuiW.confirmRes = keybase1.ConfirmResult{IdentityConfirmed: true, RemoteConfirmed: true, AutoConfirmed: true} 249 250 idAndListFollowers := func(username string) { 251 cli1, err := client.GetIdentifyClient(aliceG) 252 require.NoError(t, err) 253 _, err = cli1.Identify2(ctx, keybase1.Identify2Arg{ 254 UserAssertion: username, 255 IdentifyBehavior: keybase1.TLFIdentifyBehavior_CHAT_GUI, 256 }) 257 require.NoError(t, err) 258 259 cli2, err := client.GetUserClient(aliceG) 260 require.NoError(t, err) 261 _, err = cli2.ListTrackersUnverified(ctx, keybase1.ListTrackersUnverifiedArg{Assertion: username}) 262 require.NoError(t, err) 263 } 264 265 aliceG.ProofCache.DisableDisk() 266 wongG.ProofCache.DisableDisk() 267 // The track/untrack statements will be stubbed links, the proveRooter will 268 // not 269 wong.track(alice.username) 270 // ensure we don't stub a non-stubable 271 wong.proveRooter() 272 idAndListFollowers(wong.username) 273 274 // ensure we don't stub tail since we need to check against the merkle tree 275 wong.untrack(alice.username) 276 idAndListFollowers(wong.username) 277 278 wong.reset() 279 wong.loginAfterReset() 280 tt.addUser("bob") 281 bob := tt.users[2] 282 bobG := bob.tc.G 283 for _, dk := range upk.DeviceKeys { 284 user, upak, _, err := bobG.GetUPAKLoader().LoadKeyV2(ctx, wong.uid, dk.KID) 285 require.NoError(t, err) 286 require.NotNil(t, user) 287 require.NotNil(t, upak) 288 } 289 }