1// Copyright 2017 Keybase, Inc. All rights reserved. Use of 2// this source code is governed by the included BSD license. 3 4package engine 5 6import ( 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. 18func 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. 52func 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. 89func 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 125func 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 159func 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. 196func 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 215func 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 225func 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 237type TestSecretUIPaperKey struct { 238 T *testing.T 239 Paperkey string 240 AllowedGetPassphraseCalls int 241 nGetPassphraseCalls int 242} 243 244func (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} 254