github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/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  }