github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/track_token_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  	"testing"
     8  	"time"
     9  
    10  	"github.com/keybase/client/go/gregor"
    11  	"github.com/keybase/client/go/libkb"
    12  	gregor1 "github.com/keybase/client/go/protocol/gregor1"
    13  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    14  	"github.com/keybase/clockwork"
    15  	context "golang.org/x/net/context"
    16  )
    17  
    18  func doWithSigChainVersions(f func(libkb.SigVersion)) {
    19  	f(libkb.KeybaseSignatureV1)
    20  	f(libkb.KeybaseSignatureV2)
    21  }
    22  
    23  func TestTrackTokenIdentify2(t *testing.T) {
    24  	doWithSigChainVersions(func(sigVersion libkb.SigVersion) {
    25  		_testTrackTokenIdentify2(t, sigVersion)
    26  	})
    27  }
    28  
    29  func _testTrackTokenIdentify2(t *testing.T, sigVersion libkb.SigVersion) {
    30  	tc := SetupEngineTest(t, "track")
    31  	defer tc.Cleanup()
    32  	fu := CreateAndSignupFakeUser(tc, "track")
    33  
    34  	idUI := &FakeIdentifyUI{}
    35  	username := "t_tracy"
    36  	arg := &keybase1.Identify2Arg{
    37  		UserAssertion:    username,
    38  		NeedProofSet:     true,
    39  		IdentifyBehavior: keybase1.TLFIdentifyBehavior_CLI,
    40  	}
    41  	uis := libkb.UIs{
    42  		LogUI:      tc.G.UI.GetLogUI(),
    43  		IdentifyUI: idUI,
    44  		SecretUI:   fu.NewSecretUI(),
    45  	}
    46  	eng := NewResolveThenIdentify2(tc.G, arg)
    47  	m := NewMetaContextForTest(tc).WithUIs(uis)
    48  	if err := RunEngine2(m, eng); err != nil {
    49  		tc.T.Fatal(err)
    50  	}
    51  	sv := keybase1.SigVersion(sigVersion)
    52  	targ := TrackTokenArg{
    53  		Token:   idUI.Token,
    54  		Options: keybase1.TrackOptions{BypassConfirm: true, SigVersion: &sv},
    55  	}
    56  	teng := NewTrackToken(tc.G, &targ)
    57  	if err := RunEngine2(m, teng); err != nil {
    58  		tc.T.Fatal(err)
    59  	}
    60  
    61  	defer func() { _ = runUntrack(tc, fu, username, sigVersion) }()
    62  	assertTracking(tc, username)
    63  }
    64  
    65  func TestTrackLocalThenLocalTemp(t *testing.T) {
    66  	tc := SetupEngineTest(t, "track")
    67  	defer tc.Cleanup()
    68  	sigVersion := libkb.GetDefaultSigVersion(tc.G)
    69  
    70  	fakeClock := clockwork.NewFakeClockAt(time.Now())
    71  	tc.G.SetClock(fakeClock)
    72  	fu := CreateAndSignupFakeUser(tc, "track")
    73  
    74  	flakeyAPI := flakeyRooterAPI{orig: tc.G.XAPI, flakeOut: false, G: tc.G}
    75  	tc.G.XAPI = &flakeyAPI
    76  
    77  	idUI := &FakeIdentifyUI{}
    78  	username := "t_tracy"
    79  
    80  	arg := &keybase1.Identify2Arg{
    81  		UserAssertion:    username,
    82  		NeedProofSet:     true,
    83  		IdentifyBehavior: keybase1.TLFIdentifyBehavior_CLI,
    84  	}
    85  	uis := libkb.UIs{
    86  		LogUI:      tc.G.UI.GetLogUI(),
    87  		IdentifyUI: idUI,
    88  		SecretUI:   fu.NewSecretUI(),
    89  	}
    90  
    91  	// Identify tracy; all proofs should work
    92  	eng := NewResolveThenIdentify2(tc.G, arg)
    93  	m := NewMetaContextForTest(tc).WithUIs(uis)
    94  	if err := RunEngine2(m, eng); err != nil {
    95  		t.Fatal(err)
    96  	}
    97  	sv := keybase1.SigVersion(sigVersion)
    98  	targ := TrackTokenArg{
    99  		Token:   idUI.Token,
   100  		Options: keybase1.TrackOptions{BypassConfirm: true, LocalOnly: true, SigVersion: &sv},
   101  	}
   102  
   103  	// Track tracy
   104  	teng := NewTrackToken(tc.G, &targ)
   105  	if err := RunEngine2(m, teng); err != nil {
   106  		t.Fatal(err)
   107  	}
   108  
   109  	defer func() { _ = runUntrack(tc, fu, username, sigVersion) }()
   110  
   111  	// Now make her Rooter proof fail with a 429
   112  	flakeyAPI.flakeOut = true
   113  	idUI = &FakeIdentifyUI{}
   114  	m = m.WithIdentifyUI(idUI)
   115  
   116  	// Advance so that our previous cached success is out of
   117  	// cache
   118  	fakeClock.Advance(tc.G.Env.GetProofCacheLongDur() + time.Minute)
   119  
   120  	eng = NewResolveThenIdentify2(tc.G, arg)
   121  	eng.testArgs = &Identify2WithUIDTestArgs{noCache: true}
   122  
   123  	// Should  get an error
   124  	if err := RunEngine2(m, eng); err == nil {
   125  		t.Fatal("Expected identify error")
   126  	}
   127  
   128  	result, found := idUI.ProofResults["rooter"]
   129  	if !found {
   130  		t.Fatal("Failed to find a rooter proof")
   131  	}
   132  	if pe := libkb.ImportProofError(result.ProofResult); pe == nil {
   133  		t.Fatal("expected a Rooter error result")
   134  	}
   135  
   136  	// This is like the UI saying to store the local track
   137  	targ.Options.ExpiringLocal = true
   138  	targ.Token = idUI.Token
   139  	// Track tracy
   140  	teng = NewTrackToken(tc.G, &targ)
   141  	if err := RunEngine2(m, teng); err != nil {
   142  		t.Fatal(err)
   143  	}
   144  
   145  	// Identify should work once more because we signed with failures
   146  	eng = NewResolveThenIdentify2(tc.G, arg)
   147  	eng.testArgs = &Identify2WithUIDTestArgs{noCache: true}
   148  	var err error
   149  	// Should not get an error
   150  	if err = RunEngine2(m, eng); err != nil {
   151  		t.Logf("Identify failure: %v", err)
   152  		t.Fatal("Expected to pass identify")
   153  	}
   154  
   155  	result, found = idUI.ProofResults["rooter"]
   156  	if !found {
   157  		t.Fatal("Failed to find a rooter proof")
   158  	}
   159  	if result.Diff == nil {
   160  		t.Fatal("Failed to find a rooter proof result diff")
   161  	}
   162  	if result.Diff.Type != keybase1.TrackDiffType_NONE_VIA_TEMPORARY {
   163  		t.Fatal("Failed to find a rooter proof result diff of type TrackDiffType_NONE_VIA_TEMPORARY")
   164  	}
   165  	if pe := libkb.ImportProofError(result.ProofResult); pe == nil {
   166  		t.Fatal("expected a Rooter error result")
   167  	}
   168  
   169  	// Advance so that our temporary track is discarded
   170  	fakeClock.Advance(tc.G.Env.GetLocalTrackMaxAge() + time.Minute)
   171  
   172  	// Identify should fail once more
   173  	eng = NewResolveThenIdentify2(tc.G, arg)
   174  	eng.testArgs = &Identify2WithUIDTestArgs{noCache: true}
   175  	// Should get an error
   176  	if err = RunEngine2(m, eng); err == nil {
   177  		t.Fatal("Expected rooter to fail")
   178  	}
   179  	t.Logf("Identify failure: %v", err)
   180  
   181  	result, found = idUI.ProofResults["rooter"]
   182  	if !found {
   183  		t.Fatal("Failed to find a rooter proof")
   184  	}
   185  	if pe := libkb.ImportProofError(result.ProofResult); pe == nil {
   186  		t.Fatal("expected a Rooter error result")
   187  	}
   188  
   189  	assertTracking(tc, username)
   190  }
   191  
   192  func TestTrackRemoteThenLocalTemp(t *testing.T) {
   193  	doWithSigChainVersions(func(sigVersion libkb.SigVersion) {
   194  		_testTrackRemoteThenLocalTemp(t, sigVersion)
   195  	})
   196  }
   197  
   198  func _testTrackRemoteThenLocalTemp(t *testing.T, sigVersion libkb.SigVersion) {
   199  	tc := SetupEngineTest(t, "track")
   200  	defer tc.Cleanup()
   201  
   202  	// Tracking remote means we have to agree what time it is
   203  	fakeClock := clockwork.NewFakeClockAt(time.Now())
   204  	tc.G.SetClock(fakeClock)
   205  	fu := CreateAndSignupFakeUser(tc, "track")
   206  
   207  	flakeyAPI := flakeyRooterAPI{orig: tc.G.XAPI, flakeOut: false, G: tc.G}
   208  	tc.G.XAPI = &flakeyAPI
   209  
   210  	idUI := &FakeIdentifyUI{}
   211  	username := "t_tracy"
   212  
   213  	arg := &keybase1.Identify2Arg{
   214  		UserAssertion:    username,
   215  		NeedProofSet:     true,
   216  		IdentifyBehavior: keybase1.TLFIdentifyBehavior_CLI,
   217  	}
   218  	uis := libkb.UIs{
   219  		LogUI:      tc.G.UI.GetLogUI(),
   220  		IdentifyUI: idUI,
   221  		SecretUI:   fu.NewSecretUI(),
   222  	}
   223  
   224  	// Identify tracy; all proofs should work
   225  	eng := NewResolveThenIdentify2(tc.G, arg)
   226  	m := NewMetaContextForTest(tc).WithUIs(uis)
   227  	if err := RunEngine2(m, eng); err != nil {
   228  		t.Fatal(err)
   229  	}
   230  	// Leaving LocalOnly off here will result in remote tracking
   231  	sv := keybase1.SigVersion(sigVersion)
   232  	targ := TrackTokenArg{
   233  		Token:   idUI.Token,
   234  		Options: keybase1.TrackOptions{BypassConfirm: true, SigVersion: &sv},
   235  	}
   236  
   237  	// Track tracy
   238  	teng := NewTrackToken(tc.G, &targ)
   239  	if err := RunEngine2(m, teng); err != nil {
   240  		t.Fatal(err)
   241  	}
   242  
   243  	defer func() { _ = runUntrack(tc, fu, username, sigVersion) }()
   244  
   245  	// Now make her Rooter proof fail with a 429
   246  	flakeyAPI.flakeOut = true
   247  	idUI = &FakeIdentifyUI{}
   248  	m = m.WithIdentifyUI(idUI)
   249  
   250  	// Advance so that our previous cached success is out of
   251  	// cache
   252  	fakeClock.Advance(tc.G.Env.GetProofCacheLongDur() + time.Minute)
   253  
   254  	eng = NewResolveThenIdentify2(tc.G, arg)
   255  	eng.testArgs = &Identify2WithUIDTestArgs{noCache: true}
   256  
   257  	// Should  get an error
   258  	if err := RunEngine2(m, eng); err == nil {
   259  		t.Fatal("Expected identify error")
   260  	}
   261  
   262  	result, found := idUI.ProofResults["rooter"]
   263  	if !found {
   264  		t.Fatal("Failed to find a rooter proof")
   265  	}
   266  	if pe := libkb.ImportProofError(result.ProofResult); pe == nil {
   267  		t.Fatal("expected a Rooter error result")
   268  	}
   269  
   270  	// This is like the UI saying to store the local track
   271  	targ.Options.ExpiringLocal = true
   272  	targ.Token = idUI.Token
   273  	// Track tracy
   274  	teng = NewTrackToken(tc.G, &targ)
   275  	if err := RunEngine2(m, teng); err != nil {
   276  		t.Fatal(err)
   277  	}
   278  
   279  	// Identify should work once more because we signed with failures
   280  	eng = NewResolveThenIdentify2(tc.G, arg)
   281  	eng.testArgs = &Identify2WithUIDTestArgs{noCache: true}
   282  	var err error
   283  	// Should not get an error
   284  	if err = RunEngine2(m, eng); err != nil {
   285  		t.Logf("Identify failure: %v", err)
   286  		t.Fatal("Expected to pass identify")
   287  	}
   288  
   289  	result, found = idUI.ProofResults["rooter"]
   290  	if !found {
   291  		t.Fatal("Failed to find a rooter proof")
   292  	}
   293  	if pe := libkb.ImportProofError(result.ProofResult); pe == nil {
   294  		t.Fatal("expected a Rooter error result")
   295  	}
   296  
   297  	// Advance so that our temporary track is discarded
   298  	// cache
   299  	fakeClock.Advance(tc.G.Env.GetLocalTrackMaxAge() + time.Minute)
   300  
   301  	// Identify should fail once more
   302  	eng = NewResolveThenIdentify2(tc.G, arg)
   303  	eng.testArgs = &Identify2WithUIDTestArgs{noCache: true}
   304  	// Should get an error
   305  	if err = RunEngine2(m, eng); err == nil {
   306  		t.Fatal("Expected rooter to fail")
   307  	}
   308  	t.Logf("Identify failure: %v", err)
   309  
   310  	result, found = idUI.ProofResults["rooter"]
   311  	if !found {
   312  		t.Fatal("Failed to find a rooter proof")
   313  	}
   314  	if pe := libkb.ImportProofError(result.ProofResult); pe == nil {
   315  		t.Fatal("expected a Rooter error result")
   316  	}
   317  
   318  	assertTracking(tc, username)
   319  }
   320  
   321  func TestTrackFailTempRecover(t *testing.T) {
   322  	tc := SetupEngineTest(t, "track")
   323  	defer tc.Cleanup()
   324  	sigVersion := libkb.GetDefaultSigVersion(tc.G)
   325  
   326  	fakeClock := clockwork.NewFakeClockAt(time.Now())
   327  	tc.G.SetClock(fakeClock)
   328  	fu := CreateAndSignupFakeUser(tc, "track")
   329  
   330  	flakeyAPI := flakeyRooterAPI{orig: tc.G.XAPI, flakeOut: false, G: tc.G}
   331  	tc.G.XAPI = &flakeyAPI
   332  
   333  	idUI := &FakeIdentifyUI{}
   334  	username := "t_tracy"
   335  
   336  	arg := &keybase1.Identify2Arg{
   337  		UserAssertion:    username,
   338  		NeedProofSet:     true,
   339  		IdentifyBehavior: keybase1.TLFIdentifyBehavior_CLI,
   340  	}
   341  	uis := libkb.UIs{
   342  		LogUI:      tc.G.UI.GetLogUI(),
   343  		IdentifyUI: idUI,
   344  		SecretUI:   fu.NewSecretUI(),
   345  	}
   346  
   347  	// Identify tracy; all proofs should work
   348  	eng := NewResolveThenIdentify2(tc.G, arg)
   349  	m := NewMetaContextForTest(tc).WithUIs(uis)
   350  	if err := RunEngine2(m, eng); err != nil {
   351  		t.Fatal(err)
   352  	}
   353  	sv := keybase1.SigVersion(sigVersion)
   354  	targ := TrackTokenArg{
   355  		Token:   idUI.Token,
   356  		Options: keybase1.TrackOptions{BypassConfirm: true, LocalOnly: true, SigVersion: &sv},
   357  	}
   358  
   359  	// Track tracy
   360  	teng := NewTrackToken(tc.G, &targ)
   361  	if err := RunEngine2(m, teng); err != nil {
   362  		t.Fatal(err)
   363  	}
   364  
   365  	defer func() { _ = runUntrack(tc, fu, username, sigVersion) }()
   366  
   367  	// Now make her Rooter proof fail with a 429
   368  	flakeyAPI.flakeOut = true
   369  	idUI = &FakeIdentifyUI{}
   370  	m = m.WithIdentifyUI(idUI)
   371  
   372  	// Advance so that our previous cached success is out of
   373  	// cache
   374  	fakeClock.Advance(tc.G.Env.GetProofCacheLongDur() + time.Minute)
   375  
   376  	eng = NewResolveThenIdentify2(tc.G, arg)
   377  	eng.testArgs = &Identify2WithUIDTestArgs{noCache: true}
   378  
   379  	// Should  get an error
   380  	if err := RunEngine2(m, eng); err == nil {
   381  		t.Fatal("Expected identify error")
   382  	}
   383  
   384  	result, found := idUI.ProofResults["rooter"]
   385  	if !found {
   386  		t.Fatal("Failed to find a rooter proof")
   387  	}
   388  	pe := libkb.ImportProofError(result.ProofResult)
   389  	if pe == nil {
   390  		t.Fatal("expected a Rooter error result")
   391  	}
   392  
   393  	t.Logf("Rooter proof result, error: %v, -- %v", result, pe)
   394  	if result.Diff != nil {
   395  		t.Logf("Rooter proof result diff: %v", result.Diff)
   396  	}
   397  	// This is like the UI saying to store the local track
   398  	targ.Options.ExpiringLocal = true
   399  
   400  	targ.Token = idUI.Token
   401  	// Track tracy
   402  	teng = NewTrackToken(tc.G, &targ)
   403  	if err := RunEngine2(m, teng); err != nil {
   404  		t.Fatal(err)
   405  	}
   406  
   407  	// Now make her Rooter proof work again
   408  	flakeyAPI.flakeOut = false
   409  
   410  	// Identify should work because of the original, permanent track
   411  	eng = NewResolveThenIdentify2(tc.G, arg)
   412  	eng.testArgs = &Identify2WithUIDTestArgs{noCache: true}
   413  	var err error
   414  	// Should not get an error
   415  	if err = RunEngine2(m, eng); err != nil {
   416  		t.Logf("Identify failure: %v", err)
   417  		t.Fatal("Expected to pass identify")
   418  	}
   419  
   420  	// There shouldn't be a Diff in the result, but if there is, make sure
   421  	// it isn't due to temporary tracking
   422  	result, found = idUI.ProofResults["rooter"]
   423  	if !found || result.Diff.Type != keybase1.TrackDiffType_NONE {
   424  		t.Fatalf("Expected a TrackDiffType_NONE")
   425  	}
   426  
   427  	// Advance the clock to make sure local temp track goes away
   428  	fakeClock.Advance(tc.G.Env.GetLocalTrackMaxAge() + time.Minute)
   429  
   430  	if err := eng.i2eng.createIdentifyState(m); err != nil {
   431  		t.Fatal(err)
   432  	}
   433  	if eng.i2eng.state.TrackLookup() == nil {
   434  		t.Fatalf("Expected permanent LocalTrackChainLinkFor %s", username)
   435  	}
   436  	if eng.i2eng.state.TmpTrackLookup() != nil {
   437  		t.Fatalf("Expected no temporary LocalTrackChainLinkFor %s", username)
   438  	}
   439  	assertTracking(tc, username)
   440  }
   441  
   442  type FakeGregorState struct {
   443  	dismissedMsgID gregor.MsgID
   444  }
   445  
   446  var _ libkb.GregorState = (*FakeGregorState)(nil)
   447  
   448  func (d *FakeGregorState) State(ctx context.Context) (gregor.State, error) {
   449  	return nil, nil
   450  }
   451  
   452  func (d *FakeGregorState) UpdateCategory(ctx context.Context, cat string, body []byte,
   453  	dtime gregor1.TimeOrOffset) (res gregor1.MsgID, err error) {
   454  	return gregor1.MsgID{}, nil
   455  }
   456  
   457  func (d *FakeGregorState) InjectItem(ctx context.Context, cat string, body []byte, dtime gregor1.TimeOrOffset) (gregor1.MsgID, error) {
   458  	return nil, nil
   459  }
   460  
   461  func (d *FakeGregorState) DismissItem(ctx context.Context, cli gregor1.IncomingInterface, id gregor.MsgID) error {
   462  	d.dismissedMsgID = id
   463  	return nil
   464  }
   465  
   466  func (d *FakeGregorState) DismissCategory(ct context.Context, cat gregor1.Category) error {
   467  	return nil
   468  }
   469  
   470  func (d *FakeGregorState) LocalDismissItem(ctx context.Context, id gregor.MsgID) error {
   471  	return nil
   472  }
   473  
   474  func TestTrackWithTokenDismissesGregor(t *testing.T) {
   475  	tc := SetupEngineTest(t, "track")
   476  	defer tc.Cleanup()
   477  	sigVersion := libkb.GetDefaultSigVersion(tc.G)
   478  	fu := CreateAndSignupFakeUser(tc, "track")
   479  
   480  	dismisser := &FakeGregorState{}
   481  	tc.G.GregorState = dismisser
   482  
   483  	msgID := gregor1.MsgID("my_random_id")
   484  	responsibleGregorItem := gregor1.ItemAndMetadata{
   485  		// All we need for this test is the msgID, to check for dismissal.
   486  		Md_: &gregor1.Metadata{
   487  			MsgID_: msgID,
   488  		},
   489  	}
   490  
   491  	idUI := &FakeIdentifyUI{}
   492  	username := "t_tracy"
   493  	arg := &keybase1.Identify2Arg{
   494  		UserAssertion:    username,
   495  		NeedProofSet:     true,
   496  		IdentifyBehavior: keybase1.TLFIdentifyBehavior_CLI,
   497  	}
   498  	uis := libkb.UIs{
   499  		LogUI:      tc.G.UI.GetLogUI(),
   500  		IdentifyUI: idUI,
   501  		SecretUI:   fu.NewSecretUI(),
   502  	}
   503  	eng := NewResolveThenIdentify2(tc.G, arg)
   504  	m := NewMetaContextForTest(tc).WithUIs(uis)
   505  	eng.SetResponsibleGregorItem(&responsibleGregorItem)
   506  	if err := RunEngine2(m, eng); err != nil {
   507  		tc.T.Fatal(err)
   508  	}
   509  	sv := keybase1.SigVersion(sigVersion)
   510  	targ := TrackTokenArg{
   511  		Token:   idUI.Token,
   512  		Options: keybase1.TrackOptions{BypassConfirm: true, SigVersion: &sv},
   513  	}
   514  	teng := NewTrackToken(tc.G, &targ)
   515  	if err := RunEngine2(m, teng); err != nil {
   516  		tc.T.Fatal(err)
   517  	}
   518  
   519  	// Check that the dismissed ID matches what we defined above.
   520  	if msgID.String() != dismisser.dismissedMsgID.String() {
   521  		tc.T.Fatalf("Dismissed msgID (%s) != responsible msgID (%s)", msgID.String(), dismisser.dismissedMsgID.String())
   522  	}
   523  }