1// Copyright 2015 Keybase, Inc. All rights reserved. Use of 2// this source code is governed by the included BSD license. 3 4package engine 5 6import ( 7 "reflect" 8 "sync" 9 "testing" 10 "time" 11 12 "github.com/keybase/client/go/libkb" 13 keybase1 "github.com/keybase/client/go/protocol/keybase1" 14 "github.com/stretchr/testify/require" 15) 16 17func runIdentify(tc *libkb.TestContext, username string) (idUI *FakeIdentifyUI, res *keybase1.Identify2ResUPK2, err error) { 18 idUI = &FakeIdentifyUI{} 19 arg := keybase1.Identify2Arg{ 20 UserAssertion: username, 21 AlwaysBlock: true, 22 IdentifyBehavior: keybase1.TLFIdentifyBehavior_CLI, 23 } 24 25 uis := libkb.UIs{ 26 LogUI: tc.G.UI.GetLogUI(), 27 IdentifyUI: idUI, 28 } 29 30 eng := NewResolveThenIdentify2(tc.G, &arg) 31 m := NewMetaContextForTest(*tc).WithUIs(uis) 32 err = RunEngine2(m, eng) 33 if err != nil { 34 return idUI, nil, err 35 } 36 res, err = eng.Result(m) 37 if err != nil { 38 return idUI, nil, err 39 } 40 return idUI, res, nil 41} 42 43func checkAliceProofs(tb libkb.TestingTB, idUI *FakeIdentifyUI, user *keybase1.UserPlusKeysV2) { 44 checkKeyedProfile(tb, idUI, user, "alice", map[string]string{ 45 "github": "kbtester2", 46 "twitter": "tacovontaco", 47 }) 48} 49 50func checkBobProofs(tb libkb.TestingTB, idUI *FakeIdentifyUI, user *keybase1.UserPlusKeysV2) { 51 checkKeyedProfile(tb, idUI, user, "bob", map[string]string{ 52 "github": "kbtester1", 53 "twitter": "kbtester1", 54 }) 55} 56 57func checkCharlieProofs(tb libkb.TestingTB, idUI *FakeIdentifyUI, user *keybase1.UserPlusKeysV2) { 58 checkKeyedProfile(tb, idUI, user, "charlie", map[string]string{ 59 "github": "tacoplusplus", 60 "twitter": "tacovontaco", 61 }) 62} 63 64func checkDougProofs(tb libkb.TestingTB, idUI *FakeIdentifyUI, user *keybase1.UserPlusKeysV2) { 65 checkKeyedProfile(tb, idUI, user, "doug", nil) 66} 67 68func checkKeyedProfile(tb libkb.TestingTB, idUI *FakeIdentifyUI, them *keybase1.UserPlusKeysV2, name string, expectedProofs map[string]string) { 69 if them == nil { 70 tb.Fatal("nil 'them' user") 71 } 72 exported := &keybase1.User{ 73 Uid: them.GetUID(), 74 Username: them.GetName(), 75 } 76 if !reflect.DeepEqual(idUI.User, exported) { 77 tb.Fatal("LaunchNetworkChecks User not equal to result user.", idUI.User, exported) 78 } 79 80 if !reflect.DeepEqual(expectedProofs, idUI.Proofs) { 81 tb.Fatal("Wrong proofs.", expectedProofs, idUI.Proofs) 82 } 83} 84 85func checkDisplayKeys(t *testing.T, idUI *FakeIdentifyUI, callCount, keyCount int) { 86 if idUI.DisplayKeyCalls != callCount { 87 t.Errorf("DisplayKey calls: %d. expected %d.", idUI.DisplayKeyCalls, callCount) 88 } 89 90 if len(idUI.Keys) != keyCount { 91 t.Errorf("keys: %d, expected %d.", len(idUI.Keys), keyCount) 92 for k, v := range idUI.Keys { 93 t.Logf("key: %+v, %+v", k, v) 94 } 95 } 96} 97 98func TestIdAlice(t *testing.T) { 99 tc := SetupEngineTest(t, "id") 100 defer tc.Cleanup() 101 idUI, result, err := runIdentify(&tc, "t_alice") 102 require.NoError(t, err) 103 checkAliceProofs(t, idUI, &result.Upk.Current) 104 checkDisplayKeys(t, idUI, 1, 1) 105} 106 107func TestIdBob(t *testing.T) { 108 tc := SetupEngineTest(t, "id") 109 defer tc.Cleanup() 110 idUI, result, err := runIdentify(&tc, "t_bob") 111 require.NoError(t, err) 112 checkBobProofs(t, idUI, &result.Upk.Current) 113 checkDisplayKeys(t, idUI, 1, 1) 114} 115 116func TestIdCharlie(t *testing.T) { 117 tc := SetupEngineTest(t, "id") 118 defer tc.Cleanup() 119 idUI, result, err := runIdentify(&tc, "t_charlie") 120 require.NoError(t, err) 121 checkCharlieProofs(t, idUI, &result.Upk.Current) 122 checkDisplayKeys(t, idUI, 1, 1) 123} 124 125func TestIdDoug(t *testing.T) { 126 tc := SetupEngineTest(t, "id") 127 defer tc.Cleanup() 128 idUI, result, err := runIdentify(&tc, "t_doug") 129 require.NoError(t, err) 130 checkDougProofs(t, idUI, &result.Upk.Current) 131 checkDisplayKeys(t, idUI, 1, 1) 132} 133 134func TestIdEllen(t *testing.T) { 135 tc := SetupEngineTest(t, "id") 136 defer tc.Cleanup() 137 idUI, _, err := runIdentify(&tc, "t_ellen") 138 require.NoError(t, err) 139 checkDisplayKeys(t, idUI, 0, 0) 140} 141 142// TestIdPGPNotEldest creates a user with a pgp key that isn't 143// eldest key, then runs identify to make sure the pgp key is 144// still displayed. 145func TestIdPGPNotEldest(t *testing.T) { 146 tc := SetupEngineTest(t, "id") 147 defer tc.Cleanup() 148 149 // create new user, then add pgp key 150 u := CreateAndSignupFakeUser(tc, "login") 151 uis := libkb.UIs{LogUI: tc.G.UI.GetLogUI(), SecretUI: u.NewSecretUI()} 152 _, _, key := genPGPKeyAndArmor(t, tc, u.Email) 153 eng, err := NewPGPKeyImportEngineFromBytes(tc.G, []byte(key), true) 154 require.NoError(t, err) 155 156 m := NewMetaContextForTest(tc).WithUIs(uis) 157 err = RunEngine2(m, eng) 158 require.NoError(t, err) 159 160 Logout(tc) 161 162 idUI, _, err := runIdentify(&tc, u.Username) 163 require.NoError(t, err) 164 165 checkDisplayKeys(t, idUI, 1, 1) 166} 167 168func TestIdGenericSocialProof(t *testing.T) { 169 tc := SetupEngineTest(t, "id") 170 defer tc.Cleanup() 171 172 // create new user and have them prove a gubble.social account 173 fu := CreateAndSignupFakeUser(tc, "login") 174 proveGubbleSocial(tc, fu, libkb.KeybaseSignatureV2) 175 proveGubbleCloud(tc, fu, libkb.KeybaseSignatureV2) 176 Logout(tc) 177 178 fu2 := CreateAndSignupFakeUser(tc, "login") 179 fu2.LoginOrBust(tc) 180 181 idUI, result, err := runIdentify(&tc, fu.Username) 182 require.NoError(t, err) 183 184 expectedResult := keybase1.ProofResult{ 185 State: keybase1.ProofState_OK, 186 Status: keybase1.ProofStatus_OK, 187 Desc: "", 188 } 189 190 require.Equal(t, expectedResult, idUI.ProofResults["gubble.social"].ProofResult) 191 require.Equal(t, expectedResult, idUI.ProofResults["gubble.cloud"].ProofResult) 192 193 checkKeyedProfile(t, idUI, &result.Upk.Current, fu.Username, map[string]string{ 194 "gubble.social": fu.Username, 195 "gubble.cloud": fu.Username, 196 }) 197} 198 199type FakeIdentifyUI struct { 200 Proofs map[string]string 201 ProofResults map[string]keybase1.LinkCheckResult 202 User *keybase1.User 203 Keys map[libkb.PGPFingerprint]*keybase1.TrackDiff 204 DisplayKeyCalls int 205 DisplayKeyDiffs []*keybase1.TrackDiff 206 Outcome *keybase1.IdentifyOutcome 207 StartCount int 208 Token keybase1.TrackToken 209 BrokenTracking bool 210 DisplayTLFArg keybase1.DisplayTLFCreateWithInviteArg 211 DisplayTLFCount int 212 FakeConfirm bool 213 LastTrack *keybase1.TrackSummary 214 sync.Mutex 215} 216 217func (ui *FakeIdentifyUI) FinishWebProofCheck(_ libkb.MetaContext, proof keybase1.RemoteProof, result keybase1.LinkCheckResult) error { 218 ui.Lock() 219 defer ui.Unlock() 220 if ui.Proofs == nil { 221 ui.Proofs = make(map[string]string) 222 } 223 ui.Proofs[proof.Key] = proof.Value 224 225 if ui.ProofResults == nil { 226 ui.ProofResults = make(map[string]keybase1.LinkCheckResult) 227 } 228 ui.ProofResults[proof.Key] = result 229 if result.BreaksTracking { 230 ui.BrokenTracking = true 231 } 232 return nil 233} 234 235func (ui *FakeIdentifyUI) FinishSocialProofCheck(_ libkb.MetaContext, proof keybase1.RemoteProof, result keybase1.LinkCheckResult) error { 236 ui.Lock() 237 defer ui.Unlock() 238 if ui.Proofs == nil { 239 ui.Proofs = make(map[string]string) 240 } 241 ui.Proofs[proof.Key] = proof.Value 242 if ui.ProofResults == nil { 243 ui.ProofResults = make(map[string]keybase1.LinkCheckResult) 244 } 245 ui.ProofResults[proof.Key] = result 246 if result.BreaksTracking { 247 ui.BrokenTracking = true 248 } 249 return nil 250} 251 252func (ui *FakeIdentifyUI) Confirm(_ libkb.MetaContext, outcome *keybase1.IdentifyOutcome) (result keybase1.ConfirmResult, err error) { 253 ui.Lock() 254 defer ui.Unlock() 255 256 // Do a short sleep. This helps trigger bugs when other code is racing 257 // against the UI here. (Note from Jack: In the bug I initially added this 258 // for, 10ms was just enough to trigger it. I'm adding in an extra factor 259 // of 10.) 260 time.Sleep(100 * time.Millisecond) 261 262 ui.Outcome = outcome 263 bypass := ui.FakeConfirm || outcome.TrackOptions.BypassConfirm 264 result.IdentityConfirmed = bypass 265 result.RemoteConfirmed = bypass && !outcome.TrackOptions.ExpiringLocal 266 return 267} 268 269func (ui *FakeIdentifyUI) DisplayCryptocurrency(libkb.MetaContext, keybase1.Cryptocurrency) error { 270 return nil 271} 272 273func (ui *FakeIdentifyUI) DisplayStellarAccount(libkb.MetaContext, keybase1.StellarAccount) error { 274 return nil 275} 276 277func (ui *FakeIdentifyUI) DisplayKey(_ libkb.MetaContext, ik keybase1.IdentifyKey) error { 278 ui.Lock() 279 defer ui.Unlock() 280 if ui.Keys == nil { 281 ui.Keys = make(map[libkb.PGPFingerprint]*keybase1.TrackDiff) 282 } 283 284 fp := libkb.ImportPGPFingerprintSlice(ik.PGPFingerprint) 285 if fp != nil { 286 ui.Keys[*fp] = ik.TrackDiff 287 } 288 289 if ik.TrackDiff != nil { 290 ui.DisplayKeyDiffs = append(ui.DisplayKeyDiffs, ik.TrackDiff) 291 } 292 293 ui.DisplayKeyCalls++ 294 return nil 295} 296func (ui *FakeIdentifyUI) ReportLastTrack(_ libkb.MetaContext, summary *keybase1.TrackSummary) error { 297 ui.LastTrack = summary 298 return nil 299} 300 301func (ui *FakeIdentifyUI) Start(_ libkb.MetaContext, username string, _ keybase1.IdentifyReason, _ bool) error { 302 ui.Lock() 303 defer ui.Unlock() 304 ui.StartCount++ 305 return nil 306} 307 308func (ui *FakeIdentifyUI) Cancel(libkb.MetaContext) error { 309 return nil 310} 311 312func (ui *FakeIdentifyUI) Finish(libkb.MetaContext) error { 313 return nil 314} 315 316func (ui *FakeIdentifyUI) Dismiss(_ libkb.MetaContext, _ string, _ keybase1.DismissReason) error { 317 return nil 318} 319 320func (ui *FakeIdentifyUI) LaunchNetworkChecks(_ libkb.MetaContext, id *keybase1.Identity, user *keybase1.User) error { 321 ui.Lock() 322 defer ui.Unlock() 323 ui.User = user 324 return nil 325} 326 327func (ui *FakeIdentifyUI) DisplayTrackStatement(libkb.MetaContext, string) error { 328 return nil 329} 330 331func (ui *FakeIdentifyUI) DisplayUserCard(libkb.MetaContext, keybase1.UserCard) error { 332 return nil 333} 334 335func (ui *FakeIdentifyUI) ReportTrackToken(_ libkb.MetaContext, tok keybase1.TrackToken) error { 336 ui.Token = tok 337 return nil 338} 339 340func (ui *FakeIdentifyUI) SetStrict(b bool) { 341} 342 343func (ui *FakeIdentifyUI) DisplayTLFCreateWithInvite(_ libkb.MetaContext, arg keybase1.DisplayTLFCreateWithInviteArg) error { 344 ui.DisplayTLFCount++ 345 ui.DisplayTLFArg = arg 346 return nil 347} 348