github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/login_with_paperkey_test.go (about)

     1  // Copyright 2017 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  
     9  	"github.com/keybase/client/go/libkb"
    10  	"github.com/keybase/client/go/protocol/keybase1"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  // Test logging in with paper key when
    15  // loggedin: true
    16  // unlocked: true
    17  // Does not ask for anything.
    18  func TestLoginWithPaperKeyAlreadyIn(t *testing.T) {
    19  	tc := SetupEngineTest(t, "loginwithpaperkey")
    20  	defer tc.Cleanup()
    21  	_, paperkey := CreateAndSignupLPK(tc, "login")
    22  
    23  	t.Logf("checking logged in status [before]")
    24  	AssertLoggedInLPK(&tc, true)
    25  	t.Logf("checking unlocked status [before]")
    26  	AssertDeviceKeysLock(&tc, true)
    27  
    28  	t.Logf("running LoginWithPaperKey")
    29  	uis := libkb.UIs{
    30  		LogUI: tc.G.UI.GetLogUI(),
    31  		SecretUI: &TestSecretUIPaperKey{
    32  			T:                         t,
    33  			Paperkey:                  paperkey,
    34  			AllowedGetPassphraseCalls: 0,
    35  		},
    36  	}
    37  	eng := NewLoginWithPaperKey(tc.G, "")
    38  	m := NewMetaContextForTest(tc).WithUIs(uis)
    39  	err := RunEngine2(m, eng)
    40  	require.NoError(t, err)
    41  
    42  	t.Logf("checking logged in status [after]")
    43  	AssertLoggedInLPK(&tc, true)
    44  	t.Logf("checking unlocked status [after]")
    45  	AssertDeviceKeysLock(&tc, true)
    46  }
    47  
    48  // Test logging in with paper key when
    49  // loggedin: false
    50  // unlocked: false
    51  // Asks for a paperky.
    52  func TestLoginWithPaperKeyFromScratch(t *testing.T) {
    53  	tc := SetupEngineTest(t, "loginwithpaperkey")
    54  	defer tc.Cleanup()
    55  	_, paperkey := CreateAndSignupLPK(tc, "login")
    56  
    57  	t.Logf("logging out")
    58  	Logout(tc)
    59  
    60  	t.Logf("checking logged in status [before]")
    61  	AssertLoggedInLPK(&tc, false)
    62  	t.Logf("checking unlocked status [before]")
    63  	AssertDeviceKeysLock(&tc, false)
    64  
    65  	t.Logf("running LoginWithPaperKey")
    66  	uis := libkb.UIs{
    67  		LogUI: tc.G.UI.GetLogUI(),
    68  		SecretUI: &TestSecretUIPaperKey{
    69  			T:                         t,
    70  			Paperkey:                  paperkey,
    71  			AllowedGetPassphraseCalls: 1,
    72  		},
    73  	}
    74  	eng := NewLoginWithPaperKey(tc.G, "")
    75  	m := NewMetaContextForTest(tc).WithUIs(uis)
    76  	err := RunEngine2(m, eng)
    77  	require.NoError(t, err)
    78  
    79  	t.Logf("checking logged in status [after]")
    80  	AssertLoggedInLPK(&tc, true)
    81  	t.Logf("checking unlocked status [after]")
    82  	AssertDeviceKeysLock(&tc, true)
    83  }
    84  
    85  // Test logging in with paper key when
    86  // loggedin: true
    87  // unlocked: false
    88  // Asks for a paperkey.
    89  func TestLoginWithPaperKeyLoggedInAndLocked(t *testing.T) {
    90  	tc := SetupEngineTest(t, "loginwithpaperkey")
    91  	defer tc.Cleanup()
    92  	u, paperkey := CreateAndSignupLPK(tc, "login")
    93  
    94  	t.Logf("locking keys")
    95  	tc.SimulateServiceRestart()
    96  	err := tc.G.SecretStore().ClearSecret(NewMetaContextForTest(tc), libkb.NormalizedUsername(u.Username))
    97  	require.NoError(t, err)
    98  
    99  	t.Logf("checking logged in status [before]")
   100  	AssertLoggedInLPK(&tc, false)
   101  	t.Logf("checking unlocked status [before]")
   102  	AssertDeviceKeysLock(&tc, false)
   103  
   104  	t.Logf("running LoginWithPaperKey")
   105  	uis := libkb.UIs{
   106  		LogUI: tc.G.UI.GetLogUI(),
   107  		SecretUI: &TestSecretUIPaperKey{
   108  			T:                         t,
   109  			Paperkey:                  paperkey,
   110  			AllowedGetPassphraseCalls: 1,
   111  		},
   112  	}
   113  	eng := NewLoginWithPaperKey(tc.G, "")
   114  	m := NewMetaContextForTest(tc).WithUIs(uis)
   115  	err = RunEngine2(m, eng)
   116  	require.NoError(t, err)
   117  
   118  	t.Logf("checking logged in status [after]")
   119  	AssertLoggedInLPK(&tc, true)
   120  	t.Logf("checking unlocked status [after]")
   121  	AssertDeviceKeysLock(&tc, true)
   122  }
   123  
   124  // full flow, login with username
   125  func TestLoginWithPaperKeyByUsername(t *testing.T) {
   126  	tc := SetupEngineTest(t, "loginwithpaperkey")
   127  	defer tc.Cleanup()
   128  	fu, paperkey := CreateAndSignupLPK(tc, "login")
   129  
   130  	t.Logf("logging out")
   131  	Logout(tc)
   132  
   133  	t.Logf("checking logged in status [before]")
   134  	AssertLoggedInLPK(&tc, false)
   135  	t.Logf("checking unlocked status [before]")
   136  	AssertDeviceKeysLock(&tc, false)
   137  
   138  	t.Logf("running LoginWithPaperKey")
   139  	uis := libkb.UIs{
   140  		LogUI: tc.G.UI.GetLogUI(),
   141  		SecretUI: &TestSecretUIPaperKey{
   142  			T:                         t,
   143  			Paperkey:                  paperkey,
   144  			AllowedGetPassphraseCalls: 1,
   145  		},
   146  	}
   147  	eng := NewLoginWithPaperKey(tc.G, fu.NormalizedUsername().String())
   148  	m := NewMetaContextForTest(tc).WithUIs(uis)
   149  	err := RunEngine2(m, eng)
   150  	require.NoError(t, err)
   151  
   152  	t.Logf("checking logged in status [after]")
   153  	AssertLoggedInLPK(&tc, true)
   154  	t.Logf("checking unlocked status [after]")
   155  	AssertDeviceKeysLock(&tc, true)
   156  }
   157  
   158  // full flow, fail to login due to an invalid username
   159  func TestLoginWithInvalidUsername(t *testing.T) {
   160  	tc := SetupEngineTest(t, "loginwithpaperkey")
   161  	defer tc.Cleanup()
   162  
   163  	// We're creating the user to make sure that we have _some_ keys
   164  	// and differentiate from the no-username-passed flow
   165  	_, paperkey := CreateAndSignupLPK(tc, "login")
   166  
   167  	t.Logf("logging out")
   168  	Logout(tc)
   169  
   170  	t.Logf("checking logged in status [before]")
   171  	AssertLoggedInLPK(&tc, false)
   172  	t.Logf("checking unlocked status [before]")
   173  	AssertDeviceKeysLock(&tc, false)
   174  
   175  	t.Logf("running LoginWithPaperKey")
   176  	uis := libkb.UIs{
   177  		LogUI: tc.G.UI.GetLogUI(),
   178  		SecretUI: &TestSecretUIPaperKey{
   179  			T:                         t,
   180  			Paperkey:                  paperkey,
   181  			AllowedGetPassphraseCalls: 1,
   182  		},
   183  	}
   184  	eng := NewLoginWithPaperKey(tc.G, "doesnotexist")
   185  	m := NewMetaContextForTest(tc).WithUIs(uis)
   186  	err := RunEngine2(m, eng)
   187  	require.Equal(t, libkb.NotFoundError{}, err)
   188  
   189  	t.Logf("checking logged in status [after]")
   190  	AssertLoggedInLPK(&tc, false)
   191  	t.Logf("checking unlocked status [after]")
   192  	AssertDeviceKeysLock(&tc, false)
   193  }
   194  
   195  // Returns the user and paper key.
   196  func CreateAndSignupLPK(tc libkb.TestContext, prefix string) (*FakeUser, string) {
   197  	u := CreateAndSignupFakeUser(tc, prefix)
   198  
   199  	uis := libkb.UIs{
   200  		LogUI:    tc.G.UI.GetLogUI(),
   201  		LoginUI:  &libkb.TestLoginUI{},
   202  		SecretUI: &libkb.TestSecretUI{},
   203  	}
   204  	beng := NewPaperKey(tc.G)
   205  	m := NewMetaContextForTest(tc).WithUIs(uis)
   206  	if err := RunEngine2(m, beng); err != nil {
   207  		tc.T.Fatal(err)
   208  	}
   209  
   210  	backupPassphrase := beng.Passphrase()
   211  
   212  	return u, backupPassphrase
   213  }
   214  
   215  func AssertLoggedInLPK(tc *libkb.TestContext, shouldBeLoggedIn bool) {
   216  	activeDeviceIsValid := tc.G.ActiveDevice.Valid()
   217  	t := tc.T
   218  	if shouldBeLoggedIn {
   219  		require.Equal(t, true, activeDeviceIsValid, "user should be logged in")
   220  	} else {
   221  		require.Equal(t, false, activeDeviceIsValid, "user should not be logged in")
   222  	}
   223  }
   224  
   225  func AssertDeviceKeysLock(tc *libkb.TestContext, shouldBeUnlocked bool) {
   226  	_, _, _, sk, ek := tc.G.ActiveDevice.AllFields()
   227  
   228  	if shouldBeUnlocked {
   229  		require.NotNil(tc.T, sk, "device signing key should be available")
   230  		require.NotNil(tc.T, ek, "device encryption key should be available")
   231  	} else {
   232  		require.Nil(tc.T, sk, "device signing key should be unavailable")
   233  		require.Nil(tc.T, ek, "device encryption key should be unavailable")
   234  	}
   235  }
   236  
   237  type TestSecretUIPaperKey struct {
   238  	T                         *testing.T
   239  	Paperkey                  string
   240  	AllowedGetPassphraseCalls int
   241  	nGetPassphraseCalls       int
   242  }
   243  
   244  func (t *TestSecretUIPaperKey) GetPassphrase(p keybase1.GUIEntryArg, terminal *keybase1.SecretEntryArg) (keybase1.GetPassphraseRes, error) {
   245  	require.Equal(t.T, keybase1.PassphraseType_PAPER_KEY, p.Type, "TestSecretUIPaperKey prompted for non-paperkey")
   246  	t.nGetPassphraseCalls++
   247  	require.True(t.T, t.nGetPassphraseCalls <= t.AllowedGetPassphraseCalls, "GetPassphrase called too many times on paperkey")
   248  	return keybase1.GetPassphraseRes{
   249  		Passphrase: t.Paperkey,
   250  		// What's this?
   251  		StoreSecret: false,
   252  	}, nil
   253  }