github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/track_proof_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 engine
     5  
     6  import (
     7  	"fmt"
     8  	"sort"
     9  	"testing"
    10  
    11  	"github.com/keybase/client/go/libkb"
    12  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  // testing service block
    17  type sb struct {
    18  	social     bool
    19  	id         string
    20  	proofState keybase1.ProofState
    21  }
    22  
    23  func checkTrack(tc libkb.TestContext, fu *FakeUser, username string, blocks []sb, outcome *keybase1.IdentifyOutcome, sigVersion libkb.SigVersion) error {
    24  	ui, them, err := runTrack(tc, fu, username, sigVersion)
    25  	if err != nil {
    26  		return err
    27  	}
    28  	return checkTrackCommon(tc, blocks, outcome, them, ui)
    29  }
    30  
    31  func checkTrackForce(tc libkb.TestContext, fu *FakeUser, username string, blocks []sb, outcome *keybase1.IdentifyOutcome) error {
    32  	ui, them, err := runTrackWithOptions(tc, fu, username, keybase1.TrackOptions{BypassConfirm: true}, fu.NewSecretUI(), true)
    33  	if err != nil {
    34  		return err
    35  	}
    36  	return checkTrackCommon(tc, blocks, outcome, them, ui)
    37  }
    38  
    39  func checkTrackCommon(tc libkb.TestContext, blocks []sb, outcome *keybase1.IdentifyOutcome, them *libkb.User, ui *FakeIdentifyUI) error {
    40  	me, err := libkb.LoadMe(libkb.NewLoadUserArg(tc.G))
    41  	if err != nil {
    42  		return err
    43  	}
    44  	if them == nil {
    45  		tc.T.Fatal("checkTrackCommon called with nil 'them' user")
    46  	}
    47  	m := NewMetaContextForTest(tc)
    48  	s, err := me.TrackChainLinkFor(m, them.GetNormalizedName(), them.GetUID())
    49  	if err != nil {
    50  		return err
    51  	}
    52  
    53  	if s == nil {
    54  		tc.T.Fatal("me.TrackChainLinkFor(...) returned nil, nil")
    55  	} else {
    56  		tc.T.Logf("payload json:\n%s", s.UnmarshalPayloadJSON().MarshalPretty())
    57  	}
    58  
    59  	sbs := s.ToServiceBlocks()
    60  	if len(sbs) != len(blocks) {
    61  		return fmt.Errorf("num service blocks: %d, expected %d", len(sbs), len(blocks))
    62  	}
    63  	sort.Sort(byID(sbs))
    64  	for i, sb := range sbs {
    65  		tsb := blocks[i]
    66  		if sb.IsSocial() != tsb.social {
    67  			return fmt.Errorf("(sb %d): social: %v, expected %v", i, sb.IsSocial(), tsb.social)
    68  		}
    69  		if sb.ToIDString() != tsb.id {
    70  			return fmt.Errorf("(sb %d): id: %s, expected %s", i, sb.ToIDString(), tsb.id)
    71  		}
    72  		if sb.GetProofState() != tsb.proofState {
    73  			return fmt.Errorf("(sb %d): proof state: %d, expected %d", i, sb.GetProofState(), tsb.proofState)
    74  		}
    75  	}
    76  
    77  	if ui.Outcome.TrackStatus != outcome.TrackStatus {
    78  		return fmt.Errorf("track status: %d, expected %d", ui.Outcome.TrackStatus, outcome.TrackStatus)
    79  	}
    80  
    81  	if ui.Outcome.NumTrackFailures != outcome.NumTrackFailures {
    82  		return fmt.Errorf("num track failures: %d, expected %d", ui.Outcome.NumTrackFailures, outcome.NumTrackFailures)
    83  	}
    84  	if ui.Outcome.NumTrackChanges != outcome.NumTrackChanges {
    85  		return fmt.Errorf("num track changes: %d, expected %d", ui.Outcome.NumTrackChanges, outcome.NumTrackChanges)
    86  	}
    87  	if ui.Outcome.NumProofFailures != outcome.NumProofFailures {
    88  		return fmt.Errorf("num proof failures: %d, expected %d", ui.Outcome.NumProofFailures, outcome.NumProofFailures)
    89  	}
    90  	if ui.Outcome.NumProofSuccesses != outcome.NumProofSuccesses {
    91  		return fmt.Errorf("num proof successes: %d, expected %d", ui.Outcome.NumProofSuccesses, outcome.NumProofSuccesses)
    92  	}
    93  	if ui.Outcome.NumRevoked != outcome.NumRevoked {
    94  		return fmt.Errorf("num revoked: %d, expected %d", ui.Outcome.NumRevoked, outcome.NumRevoked)
    95  	}
    96  
    97  	return nil
    98  }
    99  
   100  type byID []*libkb.ServiceBlock
   101  
   102  func (b byID) Len() int           { return len(b) }
   103  func (b byID) Less(x, y int) bool { return b[x].ToIDString() < b[y].ToIDString() }
   104  func (b byID) Swap(x, y int)      { b[x], b[y] = b[y], b[x] }
   105  
   106  type sbtest struct {
   107  	name    string
   108  	blocks  []sb
   109  	outcome keybase1.IdentifyOutcome
   110  }
   111  
   112  // these aren't that interesting since all the proof states are
   113  // the same, but it does some basic testing of the service blocks
   114  // in a TrackChainLink.
   115  var sbtests = []sbtest{
   116  	{
   117  		name: "t_alice",
   118  		blocks: []sb{
   119  			{social: true, id: "kbtester2@github", proofState: keybase1.ProofState_OK},
   120  			{social: true, id: "tacovontaco@twitter", proofState: keybase1.ProofState_OK},
   121  		},
   122  		outcome: keybase1.IdentifyOutcome{
   123  			NumProofSuccesses: 2,
   124  			TrackStatus:       keybase1.TrackStatus_NEW_OK,
   125  		},
   126  	},
   127  	{
   128  		name: "t_bob",
   129  		blocks: []sb{
   130  			{social: true, id: "kbtester1@github", proofState: keybase1.ProofState_OK},
   131  			{social: true, id: "kbtester1@twitter", proofState: keybase1.ProofState_OK},
   132  		},
   133  		outcome: keybase1.IdentifyOutcome{
   134  			NumProofSuccesses: 2,
   135  			TrackStatus:       keybase1.TrackStatus_NEW_OK,
   136  		},
   137  	},
   138  	{
   139  		name: "t_charlie",
   140  		blocks: []sb{
   141  			{social: true, id: "tacoplusplus@github", proofState: keybase1.ProofState_OK},
   142  			{social: true, id: "tacovontaco@twitter", proofState: keybase1.ProofState_OK},
   143  		},
   144  		outcome: keybase1.IdentifyOutcome{
   145  			NumProofSuccesses: 2,
   146  			TrackStatus:       keybase1.TrackStatus_NEW_OK,
   147  		},
   148  	},
   149  	{
   150  		name: "t_doug",
   151  		outcome: keybase1.IdentifyOutcome{
   152  			TrackStatus: keybase1.TrackStatus_NEW_ZERO_PROOFS,
   153  		},
   154  	},
   155  }
   156  
   157  func TestTrackProofServiceBlocks(t *testing.T) {
   158  	tc := SetupEngineTest(t, "track")
   159  	defer tc.Cleanup()
   160  	sigVersion := libkb.GetDefaultSigVersion(tc.G)
   161  	fu := CreateAndSignupFakeUser(tc, "track")
   162  
   163  	for _, test := range sbtests {
   164  		err := checkTrack(tc, fu, test.name, test.blocks, &test.outcome, sigVersion)
   165  		require.NoError(t, err)
   166  		err = runUntrack(tc, fu, test.name, sigVersion)
   167  		require.NoError(t, err)
   168  	}
   169  }
   170  
   171  // track a user that has no proofs
   172  func TestTrackProofZero(t *testing.T) {
   173  	doWithSigChainVersions(func(sigVersion libkb.SigVersion) {
   174  		_testTrackProofZero(t, sigVersion)
   175  	})
   176  }
   177  
   178  func _testTrackProofZero(t *testing.T, sigVersion libkb.SigVersion) {
   179  	tc := SetupEngineTest(t, "track")
   180  	defer tc.Cleanup()
   181  
   182  	// create a user with no proofs
   183  	proofUser := CreateAndSignupFakeUser(tc, "proof")
   184  	Logout(tc)
   185  
   186  	// create a user to track the proofUser
   187  	trackUser := CreateAndSignupFakeUser(tc, "track")
   188  
   189  	outcome := keybase1.IdentifyOutcome{
   190  		TrackStatus: keybase1.TrackStatus_NEW_ZERO_PROOFS,
   191  	}
   192  	err := checkTrack(tc, trackUser, proofUser.Username, nil, &outcome, sigVersion)
   193  	require.NoError(t, err)
   194  }
   195  
   196  // track a user that has a rooter proof, check the tracking
   197  // statement for correctness.
   198  func TestTrackProofRooter(t *testing.T) {
   199  	doWithSigChainVersions(func(sigVersion libkb.SigVersion) {
   200  		_testTrackProofRooter(t, sigVersion)
   201  	})
   202  }
   203  
   204  func _testTrackProofRooter(t *testing.T, sigVersion libkb.SigVersion) {
   205  	tc := SetupEngineTest(t, "track")
   206  	defer tc.Cleanup()
   207  
   208  	// create a user with a rooter proof
   209  	proofUser := CreateAndSignupFakeUser(tc, "proof")
   210  	_, _, err := proveRooter(tc.G, proofUser, sigVersion)
   211  	require.NoError(t, err)
   212  	Logout(tc)
   213  
   214  	// create a user to track the proofUser
   215  	trackUser := CreateAndSignupFakeUser(tc, "track")
   216  
   217  	rbl := sb{
   218  		social:     true,
   219  		id:         proofUser.Username + "@rooter",
   220  		proofState: keybase1.ProofState_OK,
   221  	}
   222  	outcome := keybase1.IdentifyOutcome{
   223  		NumProofSuccesses: 1,
   224  		TrackStatus:       keybase1.TrackStatus_NEW_OK,
   225  	}
   226  	err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   227  	require.NoError(t, err)
   228  
   229  	// retrack, check the track status
   230  	outcome.TrackStatus = keybase1.TrackStatus_UPDATE_OK
   231  	err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   232  	require.NoError(t, err)
   233  }
   234  
   235  func TestTrackProofGubble(t *testing.T) {
   236  	tc := SetupEngineTest(t, "track")
   237  	defer tc.Cleanup()
   238  	sigVersion := libkb.KeybaseSignatureV2
   239  
   240  	// create a user with a rooter proof
   241  	proofUser := CreateAndSignupFakeUser(tc, "proof")
   242  	proveGubbleSocial(tc, proofUser, sigVersion)
   243  	proveGubbleCloud(tc, proofUser, sigVersion)
   244  	Logout(tc)
   245  
   246  	// create a user to track the proofUser
   247  	trackUser := CreateAndSignupFakeUser(tc, "track")
   248  
   249  	rbl := []sb{
   250  		{
   251  			social:     true,
   252  			id:         proofUser.Username + "@gubble.cloud",
   253  			proofState: keybase1.ProofState_OK,
   254  		},
   255  		{
   256  			social:     true,
   257  			id:         proofUser.Username + "@gubble.social",
   258  			proofState: keybase1.ProofState_OK,
   259  		},
   260  	}
   261  	outcome := keybase1.IdentifyOutcome{
   262  		NumProofSuccesses: 2,
   263  		TrackStatus:       keybase1.TrackStatus_NEW_OK,
   264  	}
   265  	err := checkTrack(tc, trackUser, proofUser.Username, rbl, &outcome, sigVersion)
   266  	require.NoError(t, err)
   267  
   268  	// retrack, check the track status
   269  	outcome.TrackStatus = keybase1.TrackStatus_UPDATE_OK
   270  	err = checkTrack(tc, trackUser, proofUser.Username, rbl, &outcome, sigVersion)
   271  	require.NoError(t, err)
   272  }
   273  
   274  // upgrade tracking statement when new proof is added:
   275  // track a user that has no proofs, then track them again after they add a proof
   276  func TestTrackProofUpgrade(t *testing.T) {
   277  	doWithSigChainVersions(func(sigVersion libkb.SigVersion) {
   278  		_testTrackProofUpgrade(t, sigVersion)
   279  	})
   280  }
   281  
   282  func _testTrackProofUpgrade(t *testing.T, sigVersion libkb.SigVersion) {
   283  	tc := SetupEngineTest(t, "track")
   284  	defer tc.Cleanup()
   285  
   286  	// create a user with no proofs
   287  	proofUser := CreateAndSignupFakeUser(tc, "proof")
   288  	Logout(tc)
   289  
   290  	// create a user to track the proofUser
   291  	trackUser := CreateAndSignupFakeUser(tc, "track")
   292  	outcome := keybase1.IdentifyOutcome{
   293  		TrackStatus: keybase1.TrackStatus_NEW_ZERO_PROOFS,
   294  	}
   295  	err := checkTrack(tc, trackUser, proofUser.Username, nil, &outcome, sigVersion)
   296  	require.NoError(t, err)
   297  
   298  	// proofUser adds a rooter proof:
   299  	Logout(tc)
   300  	proofUser.LoginOrBust(tc)
   301  	_, _, err = proveRooter(tc.G, proofUser, sigVersion)
   302  	require.NoError(t, err)
   303  	Logout(tc)
   304  
   305  	// trackUser tracks proofUser again:
   306  	trackUser.LoginOrBust(tc)
   307  
   308  	rbl := sb{
   309  		social:     true,
   310  		id:         proofUser.Username + "@rooter",
   311  		proofState: keybase1.ProofState_OK,
   312  	}
   313  	outcome = keybase1.IdentifyOutcome{
   314  		NumTrackChanges:   1,
   315  		NumProofSuccesses: 1,
   316  		TrackStatus:       keybase1.TrackStatus_UPDATE_NEW_PROOFS,
   317  	}
   318  	err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   319  	require.NoError(t, err)
   320  }
   321  
   322  // test a change to a proof
   323  func TestTrackProofChangeSinceTrack(t *testing.T) {
   324  	doWithSigChainVersions(func(sigVersion libkb.SigVersion) {
   325  		_testTrackProofChangeSinceTrack(t, sigVersion)
   326  	})
   327  }
   328  
   329  func _testTrackProofChangeSinceTrack(t *testing.T, sigVersion libkb.SigVersion) {
   330  	tc := SetupEngineTest(t, "track")
   331  	defer tc.Cleanup()
   332  
   333  	// create a user with a rooter proof
   334  	proofUser := CreateAndSignupFakeUser(tc, "proof")
   335  	_, _, err := proveRooter(tc.G, proofUser, sigVersion)
   336  	require.NoError(t, err)
   337  	Logout(tc)
   338  
   339  	// create a user to track the proofUser
   340  	trackUser := CreateAndSignupFakeUser(tc, "track")
   341  
   342  	rbl := sb{
   343  		social:     true,
   344  		id:         proofUser.Username + "@rooter",
   345  		proofState: keybase1.ProofState_OK,
   346  	}
   347  	outcome := keybase1.IdentifyOutcome{
   348  		NumProofSuccesses: 1,
   349  		TrackStatus:       keybase1.TrackStatus_NEW_OK,
   350  	}
   351  	err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   352  	require.NoError(t, err)
   353  
   354  	Logout(tc)
   355  
   356  	// proof user logs in and does a new rooter proof
   357  	proofUser.LoginOrBust(tc)
   358  	_, _, err = proveRooter(tc.G, proofUser, sigVersion)
   359  	require.NoError(t, err)
   360  	Logout(tc)
   361  
   362  	// track user logs in and tracks proof user again
   363  	trackUser.LoginOrBust(tc)
   364  	outcome.TrackStatus = keybase1.TrackStatus_UPDATE_OK
   365  	err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   366  	require.NoError(t, err)
   367  }
   368  
   369  // track a user that has a failed rooter proof
   370  func TestTrackProofRooterFail(t *testing.T) {
   371  	doWithSigChainVersions(func(sigVersion libkb.SigVersion) {
   372  		_testTrackProofRooterFail(t, sigVersion)
   373  	})
   374  }
   375  
   376  func _testTrackProofRooterFail(t *testing.T, sigVersion libkb.SigVersion) {
   377  	tc := SetupEngineTest(t, "track")
   378  	defer tc.Cleanup()
   379  
   380  	// create a user with a rooter proof
   381  	proofUser := CreateAndSignupFakeUser(tc, "proof")
   382  	_, err := proveRooterFail(tc.G, proofUser, sigVersion)
   383  	require.Error(t, err)
   384  	Logout(tc)
   385  
   386  	// create a user to track the proofUser
   387  	trackUser := CreateAndSignupFakeUser(tc, "track")
   388  
   389  	// proveRooterFail posts a bad sig id, so it won't be found.
   390  	// thus the state is ProofState_SIG_HINT_MISSING
   391  	rbl := sb{
   392  		social:     true,
   393  		id:         proofUser.Username + "@rooter",
   394  		proofState: keybase1.ProofState_SIG_HINT_MISSING,
   395  	}
   396  	outcome := keybase1.IdentifyOutcome{
   397  		NumProofFailures: 1,
   398  		TrackStatus:      keybase1.TrackStatus_NEW_ZERO_PROOFS,
   399  	}
   400  	// and they have no proofs
   401  	err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   402  	require.NoError(t, err)
   403  }
   404  
   405  func TestTrackProofGubbleFail(t *testing.T) {
   406  	tc := SetupEngineTest(t, "track")
   407  	defer tc.Cleanup()
   408  	sigVersion := libkb.KeybaseSignatureV2
   409  
   410  	// create a user with a rooter proof
   411  	proofUser := CreateAndSignupFakeUser(tc, "proof")
   412  	proveGubbleSocialFail(tc, proofUser, sigVersion)
   413  	Logout(tc)
   414  
   415  	// create a user to track the proofUser
   416  	trackUser := CreateAndSignupFakeUser(tc, "track")
   417  
   418  	// proveGubbleSocialFail posts a bad sig id, so it won't be found.
   419  	// thus the state is ProofState_SIG_HINT_MISSING
   420  	rbl := sb{
   421  		social:     true,
   422  		id:         proofUser.Username + "@gubble.social",
   423  		proofState: keybase1.ProofState_SIG_HINT_MISSING,
   424  	}
   425  	outcome := keybase1.IdentifyOutcome{
   426  		NumProofFailures: 1,
   427  		TrackStatus:      keybase1.TrackStatus_NEW_ZERO_PROOFS,
   428  	}
   429  	// and they have no proofs
   430  	err := checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   431  	require.NoError(t, err)
   432  }
   433  
   434  // track a user that has a rooter proof, remove the proof, then
   435  // track again.
   436  // Note that the API server won't notice that the rooter proof has
   437  // been removed as it only checks every 12 hours.  The client will
   438  // notice and should generate an appropriate tracking statement.
   439  func TestTrackProofRooterRemove(t *testing.T) {
   440  	doWithSigChainVersions(func(sigVersion libkb.SigVersion) {
   441  		_testTrackProofRooterRemove(t, sigVersion)
   442  	})
   443  }
   444  
   445  func _testTrackProofRooterRemove(t *testing.T, sigVersion libkb.SigVersion) {
   446  	tc := SetupEngineTest(t, "track")
   447  	defer tc.Cleanup()
   448  
   449  	// create a user with a rooter proof
   450  	proofUser := CreateAndSignupFakeUser(tc, "proof")
   451  	ui, _, err := proveRooter(tc.G, proofUser, sigVersion)
   452  	require.NoError(t, err)
   453  	Logout(tc)
   454  
   455  	// create a user to track the proofUser
   456  	trackUser := CreateAndSignupFakeUser(tc, "track")
   457  
   458  	rbl := sb{
   459  		social:     true,
   460  		id:         proofUser.Username + "@rooter",
   461  		proofState: keybase1.ProofState_OK,
   462  	}
   463  	outcome := keybase1.IdentifyOutcome{
   464  		NumProofSuccesses: 1,
   465  		TrackStatus:       keybase1.TrackStatus_NEW_OK,
   466  	}
   467  	err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   468  	require.NoError(t, err)
   469  
   470  	// remove the rooter proof
   471  	Logout(tc)
   472  	proofUser.LoginOrBust(tc)
   473  	err = proveRooterRemove(tc.G, ui.postID)
   474  	require.NoError(t, err)
   475  
   476  	Logout(tc)
   477  
   478  	// track again
   479  	trackUser.LoginOrBust(tc)
   480  	rbl.proofState = keybase1.ProofState_TEMP_FAILURE
   481  	outcome = keybase1.IdentifyOutcome{
   482  		NumTrackFailures: 1,
   483  		NumTrackChanges:  1,
   484  		NumProofFailures: 1,
   485  		TrackStatus:      keybase1.TrackStatus_UPDATE_BROKEN_FAILED_PROOFS,
   486  	}
   487  	// use checkTrackForce to skip any proof cache results
   488  	err = checkTrackForce(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome)
   489  	require.NoError(t, err)
   490  
   491  	// check that it is "fixed"
   492  	outcome = keybase1.IdentifyOutcome{
   493  		NumProofFailures: 1,
   494  		TrackStatus:      keybase1.TrackStatus_UPDATE_OK,
   495  	}
   496  	err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   497  	require.NoError(t, err)
   498  }
   499  
   500  // test tracking a user who revokes a proof.  Revoking a proof
   501  // removes it from the sig chain, so this tests the
   502  // libkb.IdentifyState.ComputeRevokedProofs() function, and how
   503  // libkb.IdentifyOutcome.TrackStatus() interprets the result.
   504  func TestTrackProofRooterRevoke(t *testing.T) {
   505  	doWithSigChainVersions(func(sigVersion libkb.SigVersion) {
   506  		_testTrackProofRooterRevoke(t, sigVersion)
   507  	})
   508  }
   509  
   510  func _testTrackProofRooterRevoke(t *testing.T, sigVersion libkb.SigVersion) {
   511  	tc := SetupEngineTest(t, "track")
   512  	defer tc.Cleanup()
   513  
   514  	// create a user with a rooter proof
   515  	proofUser := CreateAndSignupFakeUser(tc, "proof")
   516  	_, sigID, err := proveRooter(tc.G, proofUser, sigVersion)
   517  	require.NoError(t, err)
   518  	Logout(tc)
   519  
   520  	// create a user to track the proofUser
   521  	trackUser := CreateAndSignupFakeUser(tc, "track")
   522  
   523  	rbl := sb{
   524  		social:     true,
   525  		id:         proofUser.Username + "@rooter",
   526  		proofState: keybase1.ProofState_OK,
   527  	}
   528  	outcome := keybase1.IdentifyOutcome{
   529  		NumProofSuccesses: 1,
   530  		TrackStatus:       keybase1.TrackStatus_NEW_OK,
   531  	}
   532  	err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   533  	require.NoError(t, err)
   534  
   535  	// revoke the rooter proof
   536  	Logout(tc)
   537  	proofUser.LoginOrBust(tc)
   538  	revEng := NewRevokeSigsEngine(tc.G, []string{sigID.String()})
   539  	uis := libkb.UIs{
   540  		LogUI:    tc.G.UI.GetLogUI(),
   541  		SecretUI: proofUser.NewSecretUI(),
   542  	}
   543  	m := NewMetaContextForTest(tc).WithUIs(uis)
   544  
   545  	err = revEng.Run(m)
   546  	require.NoError(t, err)
   547  	Logout(tc)
   548  
   549  	// track proofUser again and check revoked proof handled correctly
   550  	trackUser.LoginOrBust(tc)
   551  	outcome = keybase1.IdentifyOutcome{
   552  		NumRevoked:  1,
   553  		TrackStatus: keybase1.TrackStatus_UPDATE_BROKEN_REVOKED,
   554  	}
   555  	err = checkTrack(tc, trackUser, proofUser.Username, nil, &outcome, sigVersion)
   556  	require.NoError(t, err)
   557  
   558  	// track again and check for fix
   559  	outcome = keybase1.IdentifyOutcome{
   560  		TrackStatus: keybase1.TrackStatus_UPDATE_OK,
   561  	}
   562  	err = checkTrack(tc, trackUser, proofUser.Username, nil, &outcome, sigVersion)
   563  	require.NoError(t, err)
   564  }
   565  
   566  // proofUser makes a user@rooter proof, then a user2@rooter proof.
   567  // trackUser tracks proofUser.  Verify the tracking statement.
   568  func TestTrackProofRooterOther(t *testing.T) {
   569  	tc := SetupEngineTest(t, "track")
   570  	defer tc.Cleanup()
   571  
   572  	sigVersion := libkb.GetDefaultSigVersion(tc.G)
   573  	// create a user with a rooter proof
   574  	proofUser := CreateAndSignupFakeUser(tc, "proof")
   575  	_, _, err := proveRooter(tc.G, proofUser, sigVersion)
   576  	require.NoError(t, err)
   577  	Logout(tc)
   578  
   579  	// post a rooter proof as a different rooter user
   580  	proofUserOther := CreateAndSignupFakeUser(tc, "proof")
   581  	Logout(tc)
   582  	proofUser.LoginOrBust(tc)
   583  	_, _, err = proveRooterOther(tc.G, proofUser, proofUserOther.Username, sigVersion)
   584  	require.NoError(t, err)
   585  	Logout(tc)
   586  
   587  	// create a user to track the proofUser
   588  	trackUser := CreateAndSignupFakeUser(tc, "track")
   589  
   590  	rbl := sb{
   591  		social:     true,
   592  		id:         proofUserOther.Username + "@rooter",
   593  		proofState: keybase1.ProofState_OK,
   594  	}
   595  	outcome := keybase1.IdentifyOutcome{
   596  		NumProofSuccesses: 1,
   597  		TrackStatus:       keybase1.TrackStatus_NEW_OK,
   598  	}
   599  	err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   600  	require.NoError(t, err)
   601  }
   602  
   603  // proofUser makes a user@rooter proof, trackUser tracks
   604  // proofUser.  proofUser makes a user2@rooter proof, trackUser
   605  // tracks proofUser again.  Test that the change is noticed.
   606  func TestTrackProofRooterChange(t *testing.T) {
   607  	tc := SetupEngineTest(t, "track")
   608  	defer tc.Cleanup()
   609  	sigVersion := libkb.GetDefaultSigVersion(tc.G)
   610  
   611  	// create a user with a rooter proof
   612  	proofUser := CreateAndSignupFakeUser(tc, "proof")
   613  	_, _, err := proveRooter(tc.G, proofUser, sigVersion)
   614  	require.NoError(t, err)
   615  	Logout(tc)
   616  
   617  	// create a user to track the proofUser
   618  	trackUser := CreateAndSignupFakeUser(tc, "track")
   619  
   620  	rbl := sb{
   621  		social:     true,
   622  		id:         proofUser.Username + "@rooter",
   623  		proofState: keybase1.ProofState_OK,
   624  	}
   625  	outcome := keybase1.IdentifyOutcome{
   626  		NumProofSuccesses: 1,
   627  		TrackStatus:       keybase1.TrackStatus_NEW_OK,
   628  	}
   629  	err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   630  	require.NoError(t, err)
   631  
   632  	// post a rooter proof as a different rooter user
   633  	Logout(tc)
   634  	proofUserOther := CreateAndSignupFakeUser(tc, "proof")
   635  	Logout(tc)
   636  
   637  	proofUser.LoginOrBust(tc)
   638  	_, _, err = proveRooterOther(tc.G, proofUser, proofUserOther.Username, sigVersion)
   639  	require.NoError(t, err)
   640  	Logout(tc)
   641  
   642  	// track proofUser again and check new rooter proof with different account handled correctly
   643  	trackUser.LoginOrBust(tc)
   644  	rbl.id = proofUserOther.Username + "@rooter"
   645  	outcome = keybase1.IdentifyOutcome{
   646  		NumTrackChanges:   1,
   647  		NumTrackFailures:  1,
   648  		NumProofSuccesses: 1,
   649  		TrackStatus:       keybase1.TrackStatus_UPDATE_BROKEN_FAILED_PROOFS,
   650  	}
   651  	err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   652  	require.NoError(t, err)
   653  
   654  	// track again and check for fix
   655  	outcome = keybase1.IdentifyOutcome{
   656  		NumProofSuccesses: 1,
   657  		TrackStatus:       keybase1.TrackStatus_UPDATE_OK,
   658  	}
   659  	err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion)
   660  	require.NoError(t, err)
   661  }
   662  
   663  // TODO:
   664  // * get a test that will generate TrackStatus_NEW_FAIL_PROOFS
   665  //   (this requires two services, one with an ok proof, one with a
   666  //   failing proof)
   667  // * test upgrade from http to https, or a secure rooter post vs.
   668  //   regular rooter post to get TrackDiffUpgraded.
   669  // * a test that will generate TrackDiffRemoteChanged