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 "bytes" 8 "crypto/rand" 9 "errors" 10 "fmt" 11 "io/ioutil" 12 "os" 13 "path/filepath" 14 "strings" 15 "sync" 16 "testing" 17 "time" 18 19 "github.com/keybase/clockwork" 20 "github.com/stretchr/testify/require" 21 "golang.org/x/net/context" 22 23 "github.com/keybase/client/go/kex2" 24 "github.com/keybase/client/go/libkb" 25 gregor1 "github.com/keybase/client/go/protocol/gregor1" 26 keybase1 "github.com/keybase/client/go/protocol/keybase1" 27) 28 29func TestLoginLogoutLogin(t *testing.T) { 30 tc := SetupEngineTest(t, "login") 31 defer tc.Cleanup() 32 33 u1 := CreateAndSignupFakeUser(tc, "login") 34 Logout(tc) 35 u1.LoginOrBust(tc) 36} 37 38// Test login switching between two different users. 39func TestLoginAndSwitchWithLogout(t *testing.T) { 40 tc := SetupEngineTest(t, "login") 41 defer tc.Cleanup() 42 43 u1 := CreateAndSignupFakeUser(tc, "first") 44 Logout(tc) 45 u2 := CreateAndSignupFakeUser(tc, "secon") 46 Logout(tc) 47 t.Logf("first logging back in") 48 u1.LoginOrBust(tc) 49 Logout(tc) 50 t.Logf("second logging back in") 51 u2.LoginOrBust(tc) 52} 53 54func TestLoginTwiceLogoutOnce(t *testing.T) { 55 tc := SetupEngineTest(t, "login") 56 defer tc.Cleanup() 57 u1 := CreateAndSignupFakeUser(tc, "first") 58 Logout(tc) 59 t.Logf("Logout first, and signup u2") 60 u2 := CreateAndSignupFakeUser(tc, "secon") 61 t.Logf("Login u1") 62 err := u1.SwitchTo(tc.G, true) 63 require.NoError(t, err) 64 t.Logf("Logged in u1") 65 err = u2.SwitchTo(tc.G, true) 66 require.NoError(t, err) 67 eng := NewLogout(libkb.LogoutOptions{}) 68 mctx := NewMetaContextForTest(tc).WithUIs(libkb.UIs{ 69 LoginUI: &libkb.TestLoginUI{}, 70 SecretUI: &nullSecretUI{}, 71 }) 72 err = RunEngine2(mctx, eng) 73 require.NoError(t, err) 74 // Log back into the first user, but shouldn't need a password 75 err = u1.SwitchTo(tc.G, true) 76 require.NoError(t, err) 77 require.True(t, tc.G.ActiveDevice.Valid()) 78 require.Equal(t, tc.G.ActiveDevice.UID(), u1.UID()) 79} 80 81// Test login switching between two different users. 82func TestLoginAndSwitchWithoutLogout(t *testing.T) { 83 tc := SetupEngineTest(t, "login") 84 defer tc.Cleanup() 85 u1 := CreateAndSignupFakeUser(tc, "first") 86 Logout(tc) 87 t.Logf("Logout first, and signup u2") 88 u2 := CreateAndSignupFakeUser(tc, "secon") 89 t.Logf("Login u1") 90 err := u1.SwitchTo(tc.G, true) 91 require.NoError(t, err) 92 t.Logf("Logged in u1") 93 err = u2.SwitchTo(tc.G, true) 94 require.NoError(t, err) 95 t.Logf("Logged in u2") 96 97 swtch := func(u *FakeUser) { 98 err := u.SwitchTo(tc.G, false) 99 require.NoError(t, err) 100 } 101 for i := 0; i < 3; i++ { 102 swtch(u1) 103 swtch(u2) 104 } 105} 106 107func TestLoginUsernameWhitespace(t *testing.T) { 108 tc := SetupEngineTest(t, "login") 109 defer tc.Cleanup() 110 111 u1 := CreateAndSignupFakeUser(tc, "lg") 112 Logout(tc) 113 u1.Username = " " + u1.Username 114 u1.LoginOrBust(tc) 115} 116 117// Login should now unlock device keys at the end, no matter what. 118func TestLoginUnlocksDeviceKeys(t *testing.T) { 119 tc := SetupEngineTest(t, "login") 120 defer tc.Cleanup() 121 122 u1 := CreateAndSignupFakeUser(tc, "login") 123 Logout(tc) 124 u1.LoginOrBust(tc) 125 126 assertPassphraseStreamCache(tc) 127 assertDeviceKeysCached(tc) 128 assertSecretStored(tc, u1.Username) 129} 130 131func TestLoginActiveDevice(t *testing.T) { 132 tc := SetupEngineTest(t, "login") 133 defer tc.Cleanup() 134 135 u1 := CreateAndSignupFakeUser(tc, "login") 136 Logout(tc) 137 u1.LoginOrBust(tc) 138 139 assertDeviceKeysCached(tc) 140 require.Equal(t, tc.G.ActiveDevice.Name(), defaultDeviceName) 141 142 simulateServiceRestart(t, tc, u1) 143 144 assertDeviceKeysCached(tc) 145 require.Equal(t, tc.G.ActiveDevice.Name(), defaultDeviceName) 146} 147 148func TestCreateFakeUserNoKeys(t *testing.T) { 149 tc := SetupEngineTest(t, "login") 150 defer tc.Cleanup() 151 152 createFakeUserWithNoKeys(tc) 153 154 me, err := libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(tc.G)) 155 if err != nil { 156 t.Fatal(err) 157 } 158 159 kf := me.GetKeyFamily() 160 if kf == nil { 161 t.Fatal("user has a nil key family") 162 } 163 if me.GetEldestKID().Exists() { 164 t.Fatalf("user has an eldest key, they should have no keys: %s", me.GetEldestKID()) 165 } 166 167 ckf := me.GetComputedKeyFamily() 168 if ckf.HasActiveKey() { 169 t.Errorf("user has an active key, but they should have no keys") 170 } 171} 172 173func testUserHasDeviceKey(tc libkb.TestContext) { 174 me, err := libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(tc.G)) 175 require.NoError(tc.T, err) 176 177 kf := me.GetKeyFamily() 178 require.NotNil(tc.T, kf) 179 require.False(tc.T, me.GetEldestKID().IsNil()) 180 181 ckf := me.GetComputedKeyFamily() 182 require.NotNil(tc.T, ckf) 183 184 active := ckf.HasActiveKey() 185 require.True(tc.T, active) 186 187 subkey, err := me.GetDeviceSubkey() 188 require.NoError(tc.T, err) 189 require.NotNil(tc.T, subkey) 190} 191 192func TestUserEmails(t *testing.T) { 193 tc := SetupEngineTest(t, "login") 194 defer tc.Cleanup() 195 196 CreateAndSignupFakeUser(tc, "login") 197 emails, err := libkb.LoadUserEmails(NewMetaContextForTest(tc)) 198 if err != nil { 199 t.Fatal(err) 200 } 201 if len(emails) == 0 { 202 t.Errorf("No emails for user") 203 } 204} 205 206func TestProvisionDesktopAfterSwitch(t *testing.T) { 207 testProvisionAfterSwitch(t, true) 208} 209 210func TestProvisionAfterSwitchWithWrongUser(t *testing.T) { 211 testProvisionAfterSwitch(t, false) 212} 213 214func testProvisionAfterSwitch(t *testing.T, shouldItWork bool) { 215 // device X (provisioner) context: 216 t.Logf("setup X") 217 tcX := SetupEngineTest(t, "kex2provision") 218 defer tcX.Cleanup() 219 220 // device Y (provisionee) context: 221 t.Logf("setup Y") 222 tcY := SetupEngineTest(t, "template") 223 defer tcY.Cleanup() 224 225 // provisioner needs to be logged in 226 t.Logf("provisioner login") 227 userX := CreateAndSignupFakeUserPaper(tcX, "login") 228 Logout(tcX) 229 230 var secretX kex2.Secret 231 _, err := rand.Read(secretX[:]) 232 require.NoError(t, err) 233 234 // Now make a user Pam 235 userPam := CreateAndSignupFakeUserPaper(tcX, "login") 236 237 userProvisionAs := userX 238 if !shouldItWork { 239 userProvisionAs = userPam 240 } 241 242 // Now switch back to userX, which may or may not be userProvisionAs (above) 243 err = userX.SwitchTo(tcX.G, true) 244 require.NoError(t, err) 245 246 secretCh := make(chan kex2.Secret) 247 248 // provisionee calls login: 249 t.Logf("provisionee login") 250 uis := libkb.UIs{ 251 ProvisionUI: newTestProvisionUISecretCh(secretCh), 252 LoginUI: &libkb.TestLoginUI{Username: userProvisionAs.Username}, 253 LogUI: tcY.G.UI.GetLogUI(), 254 SecretUI: &libkb.TestSecretUI{}, 255 GPGUI: &gpgtestui{}, 256 } 257 258 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 259 260 var wg sync.WaitGroup 261 262 assertError := func(err error) { 263 if shouldItWork { 264 require.NoError(t, err) 265 } else { 266 require.Error(t, err) 267 require.True(t, strings.Contains(err.Error(), "is a different user than we wanted")) 268 } 269 } 270 271 // start provisionee 272 t.Logf("start provisionee") 273 wg.Add(1) 274 go func() { 275 defer wg.Done() 276 m := NewMetaContextForTest(tcY).WithUIs(uis) 277 err := RunEngine2(m, eng) 278 assertError(err) 279 }() 280 281 // start provisioner 282 t.Logf("start provisioner") 283 provisioner := NewKex2Provisioner(tcX.G, secretX, nil) 284 wg.Add(1) 285 go func() { 286 defer wg.Done() 287 uis := libkb.UIs{ 288 SecretUI: userProvisionAs.NewSecretUI(), 289 ProvisionUI: newTestProvisionUI(), 290 } 291 m := NewMetaContextForTest(tcX).WithUIs(uis) 292 err := RunEngine2(m, provisioner) 293 assertError(err) 294 }() 295 296 secretFromY := <-secretCh 297 298 provisioner.AddSecret(secretFromY) 299 300 t.Logf("wait") 301 wg.Wait() 302 303 require.False(t, t.Failed(), "prior failure in a goroutine") 304 305 if !shouldItWork { 306 return 307 } 308 309 t.Logf("asserts") 310 if err := AssertProvisioned(tcY); err != nil { 311 t.Fatal(err) 312 } 313 314 // after provisioning, the passphrase stream should be cached 315 // (note that this just checks the passphrase stream, not 3sec) 316 assertPassphraseStreamCache(tcY) 317 318 // after provisioning, the device keys should be cached 319 assertDeviceKeysCached(tcY) 320 321 // after provisioning, the secret should be stored 322 assertSecretStored(tcY, userX.Username) 323 324} 325 326func TestProvisionDesktop(t *testing.T) { 327 doWithSigChainVersions(func(sigVersion libkb.SigVersion) { 328 testProvisionDesktop(t, false, sigVersion) 329 }) 330} 331 332func TestProvisionDesktopPUK(t *testing.T) { 333 testProvisionDesktop(t, true, libkb.KeybaseNullSigVersion) 334} 335 336func testProvisionDesktop(t *testing.T, upgradePerUserKey bool, sigVersion libkb.SigVersion) { 337 // device X (provisioner) context: 338 t.Logf("setup X") 339 tcX := SetupEngineTest(t, "kex2provision") 340 defer tcX.Cleanup() 341 tcX.Tp.DisableUpgradePerUserKey = !upgradePerUserKey 342 343 // device Y (provisionee) context: 344 t.Logf("setup Y") 345 tcY := SetupEngineTest(t, "template") 346 defer tcY.Cleanup() 347 tcY.Tp.DisableUpgradePerUserKey = !upgradePerUserKey 348 349 // provisioner needs to be logged in 350 t.Logf("provisioner login") 351 userX := CreateAndSignupFakeUserPaper(tcX, "login") 352 var secretX kex2.Secret 353 if _, err := rand.Read(secretX[:]); err != nil { 354 t.Fatal(err) 355 } 356 357 secretCh := make(chan kex2.Secret) 358 359 // provisionee calls login: 360 t.Logf("provisionee login") 361 uis := libkb.UIs{ 362 ProvisionUI: newTestProvisionUISecretCh(secretCh), 363 LoginUI: &libkb.TestLoginUI{Username: userX.Username}, 364 LogUI: tcY.G.UI.GetLogUI(), 365 SecretUI: &libkb.TestSecretUI{}, 366 GPGUI: &gpgtestui{}, 367 } 368 369 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 370 371 var wg sync.WaitGroup 372 373 // start provisionee 374 t.Logf("start provisionee") 375 wg.Add(1) 376 go func() { 377 defer wg.Done() 378 m := NewMetaContextForTest(tcY).WithUIs(uis) 379 if err := RunEngine2(m, eng); err != nil { 380 t.Errorf("login error: %s", err) 381 return 382 } 383 }() 384 385 // start provisioner 386 t.Logf("start provisioner") 387 provisioner := NewKex2Provisioner(tcX.G, secretX, nil) 388 wg.Add(1) 389 go func() { 390 defer wg.Done() 391 392 uis := libkb.UIs{ 393 SecretUI: userX.NewSecretUI(), 394 ProvisionUI: newTestProvisionUI(), 395 } 396 m := NewMetaContextForTest(tcX).WithUIs(uis) 397 if err := RunEngine2(m, provisioner); err != nil { 398 t.Errorf("provisioner error: %s", err) 399 return 400 } 401 }() 402 403 secretFromY := <-secretCh 404 405 provisioner.AddSecret(secretFromY) 406 407 t.Logf("wait") 408 wg.Wait() 409 410 require.False(t, t.Failed(), "prior failure in a goroutine") 411 412 t.Logf("asserts") 413 if err := AssertProvisioned(tcY); err != nil { 414 t.Fatal(err) 415 } 416 417 // after provisioning, the passphrase stream should be cached 418 // (note that this just checks the passphrase stream, not 3sec) 419 assertPassphraseStreamCache(tcY) 420 421 // after provisioning, the device keys should be cached 422 assertDeviceKeysCached(tcY) 423 424 // after provisioning, the secret should be stored 425 assertSecretStored(tcY, userX.Username) 426 427 t.Logf("test tracks") 428 testTrack(t, tcY, sigVersion, "t_alice") 429 430 // Make sure that we can still track without a passphrase 431 // after a simulated service restart. In other words, that 432 // the full LKSec secret was written to the secret store. 433 simulateServiceRestart(t, tcY, userX) 434 testTrack(t, tcY, sigVersion, "t_bob") 435} 436 437func TestProvisionMobile(t *testing.T) { 438 // device X (provisioner) context: 439 tcX := SetupEngineTest(t, "kex2provision") 440 defer tcX.Cleanup() 441 442 // device Y (provisionee) context: 443 tcY := SetupEngineTest(t, "template") 444 defer tcY.Cleanup() 445 446 // provisioner needs to be logged in 447 userX := CreateAndSignupFakeUserPaper(tcX, "login") 448 var secretX kex2.Secret 449 if _, err := rand.Read(secretX[:]); err != nil { 450 t.Fatal(err) 451 } 452 453 secretCh := make(chan kex2.Secret) 454 455 // provisionee calls login: 456 uis := libkb.UIs{ 457 ProvisionUI: newTestProvisionUISecretCh(secretCh), 458 LoginUI: &libkb.TestLoginUI{Username: userX.Username}, 459 LogUI: tcY.G.UI.GetLogUI(), 460 SecretUI: &libkb.TestSecretUI{}, 461 GPGUI: &gpgtestui{}, 462 } 463 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_MOBILE, "", keybase1.ClientType_CLI) 464 465 var wg sync.WaitGroup 466 467 // start provisionee 468 wg.Add(1) 469 go func() { 470 defer wg.Done() 471 m := NewMetaContextForTest(tcY).WithUIs(uis) 472 if err := RunEngine2(m, eng); err != nil { 473 t.Errorf("login error: %s", err) 474 return 475 } 476 }() 477 478 // start provisioner 479 provisioner := NewKex2Provisioner(tcX.G, secretX, nil) 480 wg.Add(1) 481 go func() { 482 defer wg.Done() 483 484 uis := libkb.UIs{ 485 SecretUI: userX.NewSecretUI(), 486 ProvisionUI: newTestProvisionUI(), 487 } 488 m := NewMetaContextForTest(tcX).WithUIs(uis) 489 if err := RunEngine2(m, provisioner); err != nil { 490 t.Errorf("provisioner error: %s", err) 491 return 492 } 493 }() 494 495 secretFromY := <-secretCh 496 497 provisioner.AddSecret(secretFromY) 498 499 wg.Wait() 500 501 if err := AssertProvisioned(tcY); err != nil { 502 t.Fatal(err) 503 } 504} 505 506func TestProvisionWithRevoke(t *testing.T) { 507 // device X (provisioner) context: 508 tcX := SetupEngineTest(t, "kex2provision") 509 defer tcX.Cleanup() 510 511 // device Y (provisionee) context: 512 tcY := SetupEngineTest(t, "template") 513 defer tcY.Cleanup() 514 515 // provisioner needs to be logged in 516 userX := CreateAndSignupFakeUserPaper(tcX, "login") 517 var secretX kex2.Secret 518 if _, err := rand.Read(secretX[:]); err != nil { 519 t.Fatal(err) 520 } 521 522 secretCh := make(chan kex2.Secret) 523 524 // provisionee calls login: 525 uis := libkb.UIs{ 526 ProvisionUI: newTestProvisionUISecretCh(secretCh), 527 LoginUI: &libkb.TestLoginUI{Username: userX.Username}, 528 LogUI: tcY.G.UI.GetLogUI(), 529 SecretUI: &libkb.TestSecretUI{}, 530 GPGUI: &gpgtestui{}, 531 } 532 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_MOBILE, "", keybase1.ClientType_CLI) 533 534 var wg sync.WaitGroup 535 536 // start provisionee 537 wg.Add(1) 538 go func() { 539 defer wg.Done() 540 m := NewMetaContextForTest(tcY).WithUIs(uis) 541 if err := RunEngine2(m, eng); err != nil { 542 t.Errorf("login error: %s", err) 543 return 544 } 545 }() 546 547 // start provisioner 548 provisioner := NewKex2Provisioner(tcX.G, secretX, nil) 549 wg.Add(1) 550 go func() { 551 defer wg.Done() 552 553 uis := libkb.UIs{ 554 SecretUI: userX.NewSecretUI(), 555 ProvisionUI: newTestProvisionUI(), 556 } 557 m := NewMetaContextForTest(tcX).WithUIs(uis) 558 if err := RunEngine2(m, provisioner); err != nil { 559 t.Errorf("provisioner error: %s", err) 560 return 561 } 562 }() 563 564 secretFromY := <-secretCh 565 566 // x is going to revoke a device here to change the sigchain 567 revoked := revokeAnyPaperKey(tcX, userX) 568 if revoked == nil { 569 t.Fatal("revokeAnyPaperKey for user x did not revoke anything") 570 } 571 572 provisioner.AddSecret(secretFromY) 573 574 wg.Wait() 575 576 if err := AssertProvisioned(tcY); err != nil { 577 t.Fatal(err) 578 } 579} 580 581// If a user has device keys and no pgp keys, not selecting a device 582// should trigger the autoreset flow. 583func TestProvisionAutoreset(t *testing.T) { 584 // device X (provisioner) context: 585 tcX := SetupEngineTest(t, "provision_x") 586 defer tcX.Cleanup() 587 588 // create user (and device X) 589 userX := CreateAndSignupFakeUser(tcX, "login") 590 require.NoError(t, AssertLoggedIn(tcX), "should be logged in on device x") 591 require.NoError(t, AssertProvisioned(tcX), "should be provisioned on device x") 592 593 // device Y (provisionee) context: 594 tcY := SetupEngineTest(t, "provision_y") 595 defer tcY.Cleanup() 596 597 uis := libkb.UIs{ 598 ProvisionUI: newTestProvisionUIChooseNoDevice(), 599 LoginUI: &libkb.TestLoginUI{ 600 Username: userX.Username, 601 ResetAccount: keybase1.ResetPromptResponse_CONFIRM_RESET, 602 }, 603 LogUI: tcY.G.UI.GetLogUI(), 604 SecretUI: &libkb.TestSecretUI{Passphrase: userX.Passphrase}, 605 GPGUI: &gpgtestui{}, 606 } 607 m := NewMetaContextForTest(tcY).WithUIs(uis) 608 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 609 require.NoError(t, RunEngine2(m, eng), "expected login engine to succeed") 610 require.NotNil(t, AssertLoggedIn(tcY), "should not be logged in") 611 612 // Travel 5 days into future + 1h to make sure that it all runs 613 require.NoError(t, timeTravelReset(tcX, time.Hour*121)) 614 require.NoError(t, processReset(tcX)) 615 616 // Rather than sleeping we'll wait for autoreset by analyzing its state 617 var lastErr error 618 for i := 0; i < 60; i++ { 619 // up to 60 iters * 100ms = 6s 620 lastErr = assertAutoreset(tcX, userX.UID(), libkb.AutoresetEventReady) 621 if lastErr == nil { 622 break 623 } 624 time.Sleep(100 * time.Millisecond) 625 } 626 require.NoError(t, lastErr) 627 628 // Second iteration on device Y should result in a reset + provision 629 uis = libkb.UIs{ 630 ProvisionUI: newTestProvisionUIChooseNoDevice(), 631 LoginUI: &libkb.TestLoginUI{ 632 Username: userX.Username, 633 ResetAccount: keybase1.ResetPromptResponse_CONFIRM_RESET, 634 }, 635 LogUI: tcY.G.UI.GetLogUI(), 636 SecretUI: &libkb.TestSecretUI{Passphrase: userX.Passphrase}, 637 GPGUI: &gpgtestui{}, 638 } 639 m = NewMetaContextForTest(tcY).WithUIs(uis) 640 eng = NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 641 require.NoError(t, RunEngine2(m, eng), "expected 2nd login engine to succeed") 642 require.NoError(t, AssertLoggedIn(tcY), "should be logged in") 643 require.NoError(t, AssertProvisioned(tcY), "should be provisioned on device y") 644} 645 646func timeTravelReset(tc libkb.TestContext, duration time.Duration) error { 647 mctx := libkb.NewMetaContextForTest(tc) 648 _, err := tc.G.API.Post(mctx, libkb.APIArg{ 649 Endpoint: "autoreset/timetravel", 650 SessionType: libkb.APISessionTypeREQUIRED, 651 Args: libkb.HTTPArgs{ 652 "duration_sec": libkb.I{Val: int(gregor1.ToDurationSec(duration))}, 653 }, 654 }) 655 return err 656} 657 658func processReset(tc libkb.TestContext) error { 659 mctx := libkb.NewMetaContextForTest(tc) 660 _, err := tc.G.API.Post(mctx, libkb.APIArg{ 661 Endpoint: "autoreset/process_dev", 662 SessionType: libkb.APISessionTypeNONE, 663 RetryCount: 5, 664 }) 665 return err 666} 667 668func TestProvisionPassphraseNoKeysSolo(t *testing.T) { 669 testProvisionPassphraseNoKeysSolo(t, false) 670} 671 672func TestProvisionPassphraseNoKeysSoloPUK(t *testing.T) { 673 testProvisionPassphraseNoKeysSolo(t, true) 674} 675 676// If a user has no keys, provision via passphrase should work. 677func testProvisionPassphraseNoKeysSolo(t *testing.T, upgradePerUserKey bool) { 678 tcWeb := SetupEngineTest(t, "web") 679 defer tcWeb.Cleanup() 680 tcWeb.Tp.DisableUpgradePerUserKey = !upgradePerUserKey 681 682 username, passphrase := createFakeUserWithNoKeys(tcWeb) 683 684 Logout(tcWeb) 685 686 hasZeroPaperDev(tcWeb, &FakeUser{Username: username, Passphrase: passphrase}) 687 688 tc := SetupEngineTest(t, "login") 689 defer tc.Cleanup() 690 tc.Tp.DisableUpgradePerUserKey = !upgradePerUserKey 691 692 uis := libkb.UIs{ 693 ProvisionUI: newTestProvisionUIPassphrase(), 694 LoginUI: &libkb.TestLoginUI{Username: username}, 695 LogUI: tc.G.UI.GetLogUI(), 696 SecretUI: &libkb.TestSecretUI{Passphrase: passphrase}, 697 GPGUI: &gpgtestui{}, 698 } 699 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 700 m := NewMetaContextForTest(tc).WithUIs(uis) 701 if err := RunEngine2(m, eng); err != nil { 702 t.Fatal(err) 703 } 704 705 // since this user didn't have any keys, login should have fixed that: 706 testUserHasDeviceKey(tc) 707 708 // and they should not have a paper backup key 709 hasZeroPaperDev(tc, &FakeUser{Username: username, Passphrase: passphrase}) 710 711 if err := AssertProvisioned(tc); err != nil { 712 t.Fatal(err) 713 } 714 715 // secret should be stored 716 assertSecretStored(tc, username) 717} 718 719// Test bad name input (not valid username or email address). 720func TestProvisionPassphraseBadName(t *testing.T) { 721 tcWeb := SetupEngineTest(t, "web") 722 defer tcWeb.Cleanup() 723 724 _, passphrase := createFakeUserWithNoKeys(tcWeb) 725 726 Logout(tcWeb) 727 728 tc := SetupEngineTest(t, "login") 729 defer tc.Cleanup() 730 731 uis := libkb.UIs{ 732 ProvisionUI: newTestProvisionUIPassphrase(), 733 LoginUI: &libkb.TestLoginUI{Username: strings.Repeat("X", 20)}, 734 LogUI: tc.G.UI.GetLogUI(), 735 SecretUI: &libkb.TestSecretUI{Passphrase: passphrase}, 736 GPGUI: &gpgtestui{}, 737 } 738 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 739 m := NewMetaContextForTest(tc).WithUIs(uis) 740 err := RunEngine2(m, eng) 741 require.Error(t, err) 742 require.IsType(t, libkb.BadUsernameError{}, err) 743} 744 745// If a user has (only) a synced pgp key, provision via passphrase 746// should work. 747func TestProvisionPassphraseSyncedPGP(t *testing.T) { 748 tc := SetupEngineTest(t, "login") 749 u1 := createFakeUserWithPGPOnly(t, tc) 750 t.Log("Created fake user") 751 Logout(tc) 752 tc.Cleanup() 753 754 // redo SetupEngineTest to get a new home directory...should look like a new device. 755 tc = SetupEngineTest(t, "login") 756 defer tc.Cleanup() 757 758 uis := libkb.UIs{ 759 ProvisionUI: newTestProvisionUIPassphrase(), 760 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 761 LogUI: tc.G.UI.GetLogUI(), 762 SecretUI: u1.NewSecretUI(), 763 GPGUI: &gpgtestui{}, 764 } 765 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 766 m := NewMetaContextForTest(tc).WithUIs(uis) 767 if err := RunEngine2(m, eng); err != nil { 768 t.Fatal(err) 769 } 770 771 // since this user didn't have any device keys, login should have fixed that: 772 testUserHasDeviceKey(tc) 773 774 // and they should not have a paper backup key 775 hasZeroPaperDev(tc, u1) 776 777 if err := AssertProvisioned(tc); err != nil { 778 t.Fatal(err) 779 } 780 781 // after provisioning, the secret should be stored 782 assertSecretStored(tc, u1.Username) 783 784 // should be able to sign and to track someone (no passphrase prompt) 785 testSign(t, tc) 786 simulateServiceRestart(t, tc, u1) 787 testSign(t, tc) 788} 789 790// If a user has (only) a synced pgp key, provision via passphrase 791// should work, if they specify email address as username. 792func TestProvisionPassphraseSyncedPGPEmail(t *testing.T) { 793 tc := SetupEngineTest(t, "login") 794 u1 := createFakeUserWithPGPOnly(t, tc) 795 Logout(tc) 796 tc.Cleanup() 797 798 // redo SetupEngineTest to get a new home directory...should look like a new device. 799 tc = SetupEngineTest(t, "login") 800 defer tc.Cleanup() 801 802 uis := libkb.UIs{ 803 ProvisionUI: newTestProvisionUIPassphrase(), 804 LoginUI: &libkb.TestLoginUI{Username: u1.Email}, 805 LogUI: tc.G.UI.GetLogUI(), 806 SecretUI: u1.NewSecretUI(), 807 GPGUI: &gpgtestui{}, 808 } 809 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 810 m := NewMetaContextForTest(tc).WithUIs(uis) 811 err := RunEngine2(m, eng) 812 require.Error(t, err) 813 require.IsType(t, libkb.BadUsernameError{}, err) 814 require.Contains(t, err.Error(), "not supported") 815} 816 817// Check that a bad passphrase fails to unlock a synced pgp key 818func TestProvisionSyncedPGPBadPassphrase(t *testing.T) { 819 tc := SetupEngineTest(t, "login") 820 u1 := createFakeUserWithPGPOnly(t, tc) 821 t.Log("Created fake user") 822 Logout(tc) 823 tc.Cleanup() 824 825 // redo SetupEngineTest to get a new home directory...should look like a new device. 826 tc = SetupEngineTest(t, "login") 827 defer tc.Cleanup() 828 829 uis := libkb.UIs{ 830 ProvisionUI: newTestProvisionUIPassphrase(), 831 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 832 LogUI: tc.G.UI.GetLogUI(), 833 SecretUI: &libkb.TestSecretUI{Passphrase: u1.Passphrase + u1.Passphrase}, 834 GPGUI: &gpgtestui{}, 835 } 836 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 837 m := NewMetaContextForTest(tc).WithUIs(uis) 838 if err := RunEngine2(m, eng); err == nil { 839 t.Fatal("sync pgp provision worked with bad passphrase") 840 } else if _, ok := err.(libkb.PassphraseError); !ok { 841 t.Errorf("error: %T, expected libkb.PassphraseError", err) 842 } 843} 844 845// If a user is logged in as alice, then logs in as bob (who has 846// no keys), provision via passphrase should work. 847// Bug https://keybase.atlassian.net/browse/CORE-2605 848func TestProvisionPassphraseNoKeysSwitchUser(t *testing.T) { 849 // this is the web user 850 tcWeb := SetupEngineTest(t, "web") 851 username, passphrase := createFakeUserWithNoKeys(tcWeb) 852 Logout(tcWeb) 853 tcWeb.Cleanup() 854 855 tc := SetupEngineTest(t, "login") 856 defer tc.Cleanup() 857 858 // this is a provisioned user. stay logged in as this user 859 // and start login process for web user. 860 CreateAndSignupFakeUser(tc, "alice") 861 862 Logout(tc) 863 864 uis := libkb.UIs{ 865 ProvisionUI: newTestProvisionUIPassphrase(), 866 LoginUI: &libkb.TestLoginUI{Username: username}, 867 LogUI: tc.G.UI.GetLogUI(), 868 SecretUI: &libkb.TestSecretUI{Passphrase: passphrase}, 869 GPGUI: &gpgtestui{}, 870 } 871 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, username, keybase1.ClientType_CLI) 872 m := NewMetaContextForTest(tc).WithUIs(uis) 873 if err := RunEngine2(m, eng); err != nil { 874 t.Fatal(err) 875 } 876 877 // since this user didn't have any keys, login should have fixed that: 878 testUserHasDeviceKey(tc) 879 880 t.Logf("user has device key") 881 882 // and they should not have a paper backup key 883 hasZeroPaperDev(tc, &FakeUser{Username: username, Passphrase: passphrase}) 884 885 t.Logf("user has paper device") 886 887 if err := AssertProvisioned(tc); err != nil { 888 t.Fatal(err) 889 } 890 891 // after provisioning, the secret should be stored 892 assertSecretStored(tc, username) 893} 894 895// If a user has a synced pgp key, they can use it to provision their first device. 896// After that, if they have a PUK, then they should not be able to provision with 897// the synced pgp key again. 898func TestProvisionSyncedPGPWithPUK(t *testing.T) { 899 tc := SetupEngineTest(t, "login") 900 u1 := createFakeUserWithPGPOnly(t, tc) 901 Logout(tc) 902 tc.Cleanup() 903 904 // redo SetupEngineTest to get a new home directory...should look like a new device. 905 // (PUK is on) 906 tc = SetupEngineTest(t, "login") 907 defer tc.Cleanup() 908 909 uis := libkb.UIs{ 910 ProvisionUI: newTestProvisionUIPassphrase(), 911 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 912 LogUI: tc.G.UI.GetLogUI(), 913 SecretUI: u1.NewSecretUI(), 914 GPGUI: &gpgtestui{}, 915 } 916 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 917 m := NewMetaContextForTest(tc).WithUIs(uis) 918 if err := RunEngine2(m, eng); err != nil { 919 t.Fatal(err) 920 } 921 922 // since this user didn't have any device keys, login should have fixed that: 923 testUserHasDeviceKey(tc) 924 if err := AssertProvisioned(tc); err != nil { 925 t.Fatal(err) 926 } 927 928 // force them to have a puk 929 ForcePUK(tc) 930 931 // redo SetupEngineTest to get a new home directory...should look like a new device. 932 // (PUK is on) 933 tc2 := SetupEngineTest(t, "login") 934 defer tc2.Cleanup() 935 936 uis2 := libkb.UIs{ 937 ProvisionUI: newTestProvisionUIPassphrase(), 938 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 939 LogUI: tc2.G.UI.GetLogUI(), 940 SecretUI: u1.NewSecretUI(), 941 GPGUI: &gpgtestui{}, 942 } 943 944 // this should fail, the user should not be allowed to use synced pgp key to provision 945 // second device when PUK is on: 946 eng2 := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 947 m2 := NewMetaContextForTest(tc2).WithUIs(uis2) 948 err := RunEngine2(m2, eng2) 949 require.Error(t, err, "Provision w/ synced pgp key on device 2 w/ PUK enabled should fail") 950 require.IsType(t, err, libkb.ProvisionViaDeviceRequiredError{}) 951} 952 953// Provision device using a private GPG key (not synced to keybase 954// server), import private key to lksec. With PUK, shouldn't be allowed on 955// device 2. 956func TestProvisionGPGWithPUK(t *testing.T) { 957 tc := SetupEngineTest(t, "login") 958 defer tc.Cleanup() 959 960 u1 := createFakeUserWithPGPPubOnly(t, tc) 961 Logout(tc) 962 963 // redo SetupEngineTest to get a new home directory...should look like a new device. 964 tc2 := SetupEngineTest(t, "login") 965 defer tc2.Cleanup() 966 967 // we need the gpg keyring that's in the first homedir 968 if err := tc.MoveGpgKeyringTo(tc2); err != nil { 969 t.Fatal(err) 970 } 971 972 // run login on new device 973 uis2 := libkb.UIs{ 974 ProvisionUI: newTestProvisionUIGPGImport(), 975 LogUI: tc2.G.UI.GetLogUI(), 976 SecretUI: u1.NewSecretUI(), 977 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 978 GPGUI: &gpgtestui{}, 979 } 980 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 981 m2 := NewMetaContextForTest(tc2).WithUIs(uis2) 982 if err := RunEngine2(m2, eng); err != nil { 983 t.Fatal(err) 984 } 985 986 testUserHasDeviceKey(tc2) 987 if err := AssertProvisioned(tc2); err != nil { 988 t.Fatal(err) 989 } 990 991 // force them to have a puk 992 ForcePUK(tc2) 993 994 // redo SetupEngineTest to get a new home directory...should look like a new device. 995 tc3 := SetupEngineTest(t, "login") 996 defer tc3.Cleanup() 997 998 // we need the gpg keyring 999 if err := tc2.MoveGpgKeyringTo(tc3); err != nil { 1000 t.Fatal(err) 1001 } 1002 1003 // run login on new device 1004 uis3 := libkb.UIs{ 1005 ProvisionUI: newTestProvisionUIGPGImport(), 1006 LogUI: tc3.G.UI.GetLogUI(), 1007 SecretUI: u1.NewSecretUI(), 1008 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 1009 GPGUI: &gpgtestui{}, 1010 } 1011 eng3 := NewLogin(tc3.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 1012 m3 := NewMetaContextForTest(tc3).WithUIs(uis3) 1013 err := RunEngine2(m3, eng3) 1014 require.Error(t, err, "Provision w/ gpg key on device 2 w/ PUK enabled should fail") 1015 require.IsType(t, err, libkb.ProvisionViaDeviceRequiredError{}) 1016} 1017 1018// Test provisioning where we use one username, but suddenly we are 1019// key-exchanging with someone else. 1020func TestProvisionWithUnexpectedX(t *testing.T) { 1021 t.Logf("Setting contexts and users") 1022 1023 // We want to provision as this user: 1024 tcV := SetupEngineTest(t, "kex2provision") 1025 defer tcV.Cleanup() 1026 wantedUser := CreateAndSignupFakeUserPaper(tcV, "usr1") 1027 1028 // But actually this one will respond: 1029 tcF := SetupEngineTest(t, "unexpected") 1030 defer tcF.Cleanup() 1031 actualUser := CreateAndSignupFakeUserPaper(tcF, "usr2") 1032 var secretX kex2.Secret 1033 _, err := rand.Read(secretX[:]) 1034 require.NoError(t, err) 1035 1036 // device Y (provisionee) context: 1037 tcY := SetupEngineTest(t, "template") 1038 defer tcY.Cleanup() 1039 1040 secretCh := make(chan kex2.Secret) 1041 1042 // provisionee calls login: 1043 t.Logf("provisionee login") 1044 uis := libkb.UIs{ 1045 ProvisionUI: newTestProvisionUISecretCh(secretCh), 1046 LoginUI: &libkb.TestLoginUI{Username: wantedUser.Username}, 1047 LogUI: tcY.G.UI.GetLogUI(), 1048 SecretUI: &libkb.TestSecretUI{}, 1049 GPGUI: &gpgtestui{}, 1050 } 1051 1052 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 1053 1054 var wg sync.WaitGroup 1055 1056 // start provisionee 1057 t.Logf("start provisionee") 1058 wg.Add(1) 1059 go func() { 1060 defer wg.Done() 1061 m := NewMetaContextForTest(tcY).WithUIs(uis) 1062 err := RunEngine2(m, eng) 1063 require.Error(t, err) 1064 require.Contains(t, err.Error(), "different user") 1065 }() 1066 1067 // start provisioner 1068 t.Logf("start provisioner") 1069 provisioner := NewKex2Provisioner(tcF.G, secretX, nil) 1070 wg.Add(1) 1071 go func() { 1072 defer wg.Done() 1073 1074 uis := libkb.UIs{ 1075 SecretUI: actualUser.NewSecretUI(), 1076 ProvisionUI: newTestProvisionUI(), 1077 } 1078 m := NewMetaContextForTest(tcF).WithUIs(uis) 1079 err := RunEngine2(m, provisioner) 1080 require.Error(t, err) 1081 require.Contains(t, err.Error(), "different user") 1082 }() 1083 1084 secretFromY := <-secretCh 1085 provisioner.AddSecret(secretFromY) 1086 1087 t.Logf("wait") 1088 wg.Wait() 1089} 1090 1091func testSign(t *testing.T, tc libkb.TestContext) { 1092 // should be able to sign something with new device keys without 1093 // entering a passphrase 1094 var sink bytes.Buffer 1095 1096 sarg := &SaltpackSignArg{ 1097 Sink: libkb.NopWriteCloser{W: &sink}, 1098 Source: ioutil.NopCloser(bytes.NewBufferString("hello")), 1099 } 1100 1101 signEng := NewSaltpackSign(tc.G, sarg) 1102 uis := libkb.UIs{ 1103 IdentifyUI: &FakeIdentifyUI{}, 1104 SecretUI: &libkb.TestSecretUI{}, // empty 1105 } 1106 1107 m := NewMetaContextForTest(tc).WithUIs(uis) 1108 if err := RunEngine2(m, signEng); err != nil { 1109 t.Fatal(err) 1110 } 1111} 1112 1113func testTrack(t *testing.T, tc libkb.TestContext, sigVersion libkb.SigVersion, whom string) { 1114 1115 if sigVersion == libkb.KeybaseNullSigVersion { 1116 sigVersion = libkb.GetDefaultSigVersion(tc.G) 1117 } 1118 // should be able to track someone (no passphrase prompt) 1119 targ := &TrackEngineArg{ 1120 UserAssertion: whom, 1121 Options: keybase1.TrackOptions{BypassConfirm: true}, 1122 SigVersion: sigVersion, 1123 } 1124 uis := libkb.UIs{ 1125 LogUI: tc.G.UI.GetLogUI(), 1126 IdentifyUI: &FakeIdentifyUI{}, 1127 SecretUI: &libkb.TestSecretUI{}, 1128 } 1129 1130 teng := NewTrackEngine(tc.G, targ) 1131 m := NewMetaContextForTest(tc).WithUIs(uis) 1132 err := RunEngine2(m, teng) 1133 require.NoError(t, err) 1134} 1135 1136func testProvisionPaperOnly(t *testing.T, changePaperkey func(s string) string) { 1137 tc := SetupEngineTest(t, "login") 1138 defer tc.Cleanup() 1139 1140 fu := NewFakeUserOrBust(t, "paper") 1141 arg := MakeTestSignupEngineRunArg(fu) 1142 arg.SkipPaper = false 1143 loginUI := &paperLoginUI{Username: fu.Username} 1144 uis := libkb.UIs{ 1145 LogUI: tc.G.UI.GetLogUI(), 1146 GPGUI: &gpgtestui{}, 1147 SecretUI: fu.NewSecretUI(), 1148 LoginUI: loginUI, 1149 } 1150 s := NewSignupEngine(tc.G, &arg) 1151 err := RunEngine2(NewMetaContextForTest(tc).WithUIs(uis), s) 1152 if err != nil { 1153 tc.T.Fatal(err) 1154 } 1155 1156 assertNumDevicesAndKeys(tc, fu, 2, 4) 1157 1158 Logout(tc) 1159 1160 if len(loginUI.PaperPhrase) == 0 { 1161 t.Fatal("login ui has no paper key phrase") 1162 } 1163 1164 // redo SetupEngineTest to get a new home directory...should look like a new device. 1165 tc2 := SetupEngineTest(t, "login") 1166 fakeClock := clockwork.NewFakeClockAt(time.Now()) 1167 tc2.G.SetClock(fakeClock) 1168 // to pick up the new clock... 1169 defer tc2.Cleanup() 1170 1171 secUI := fu.NewSecretUI() 1172 secUI.Passphrase = changePaperkey(loginUI.PaperPhrase) 1173 provUI := newTestProvisionUIPaper() 1174 provLoginUI := &libkb.TestLoginUI{Username: fu.Username} 1175 uis2 := libkb.UIs{ 1176 ProvisionUI: provUI, 1177 LogUI: tc2.G.UI.GetLogUI(), 1178 SecretUI: secUI, 1179 LoginUI: provLoginUI, 1180 GPGUI: &gpgtestui{}, 1181 } 1182 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 1183 m2 := NewMetaContextForTest(tc2).WithUIs(uis2) 1184 if err := RunEngine2(m2, eng); err != nil { 1185 t.Fatal(err) 1186 } 1187 1188 testUserHasDeviceKey(tc2) 1189 1190 assertNumDevicesAndKeys(tc, fu, 3, 6) 1191 1192 if err := AssertProvisioned(tc2); err != nil { 1193 t.Fatal(err) 1194 } 1195 1196 if provUI.calledChooseDeviceType != 0 { 1197 t.Errorf("expected 0 calls to ChooseDeviceType, got %d", provUI.calledChooseDeviceType) 1198 } 1199 if provLoginUI.CalledGetEmailOrUsername != 1 { 1200 t.Errorf("expected 1 call to GetEmailOrUsername, got %d", provLoginUI.CalledGetEmailOrUsername) 1201 } 1202 var device *libkb.DeviceWithKeys 1203 1204 ch := make(chan struct{}) 1205 pch := func() { 1206 ch <- struct{}{} 1207 } 1208 1209 wrapper := m2.ActiveDevice().ProvisioningKeyWrapper(m2) 1210 if wrapper != nil { 1211 device = wrapper.DeviceWithKeys() 1212 wrapper.SetTestPostCleanHook(pch) 1213 } 1214 1215 if device == nil || device.EncryptionKey() == nil { 1216 t.Errorf("Got a null paper encryption key") 1217 } 1218 1219 fakeClock.Advance(libkb.ProvisioningKeyMemoryTimeout + 1*time.Minute) 1220 <-ch 1221 1222 device = m2.ActiveDevice().ProvisioningKey(m2) 1223 if device != nil { 1224 t.Errorf("Got a non-null paper encryption key after timeout") 1225 } 1226 1227 testSign(t, tc2) 1228 1229 testTrack(t, tc2, libkb.KeybaseNullSigVersion, "t_alice") 1230 1231 simulateServiceRestart(t, tc2, fu) 1232 1233 // should be able to sign and to track someone (no passphrase prompt) 1234 testSign(t, tc2) 1235 testTrack(t, tc2, libkb.KeybaseNullSigVersion, "t_bob") 1236} 1237 1238func removePaperkeyPrefix(paperkey string) string { 1239 return strings.Join(strings.Split(paperkey, " ")[2:], " ") 1240} 1241 1242func TestProvisionPaperOnlyNoPrefix(t *testing.T) { 1243 testProvisionPaperOnly(t, removePaperkeyPrefix) 1244} 1245 1246func TestProvisionPaperOnly(t *testing.T) { 1247 testProvisionPaperOnly(t, func(s string) string { return s }) 1248} 1249 1250func simulateServiceRestart(t *testing.T, tc libkb.TestContext, fu *FakeUser) { 1251 1252 // Simulate restarting the service by wiping out the 1253 // passphrase stream cache and cached secret keys 1254 tc.SimulateServiceRestart() 1255 1256 // now assert we can login without a passphrase 1257 uis := libkb.UIs{ 1258 LoginUI: &libkb.TestLoginUI{Username: fu.Username}, 1259 LogUI: tc.G.UI.GetLogUI(), 1260 SecretUI: &libkb.TestSecretUI{}, 1261 GPGUI: &gpgtestui{}, 1262 ProvisionUI: newTestProvisionUI(), 1263 } 1264 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 1265 m := NewMetaContextForTest(tc).WithUIs(uis) 1266 err := RunEngine2(m, eng) 1267 require.NoError(t, err) 1268} 1269 1270func TestProvisionPaperCommandLine(t *testing.T) { 1271 tc := SetupEngineTest(t, "login") 1272 defer tc.Cleanup() 1273 fu := NewFakeUserOrBust(t, "paper") 1274 arg := MakeTestSignupEngineRunArg(fu) 1275 arg.SkipPaper = false 1276 loginUI := &paperLoginUI{Username: fu.Username} 1277 uis := libkb.UIs{ 1278 LogUI: tc.G.UI.GetLogUI(), 1279 GPGUI: &gpgtestui{}, 1280 SecretUI: fu.NewSecretUI(), 1281 LoginUI: loginUI, 1282 } 1283 s := NewSignupEngine(tc.G, &arg) 1284 err := RunEngine2(NewMetaContextForTest(tc).WithUIs(uis), s) 1285 require.NoError(t, err) 1286 1287 assertNumDevicesAndKeys(tc, fu, 2, 4) 1288 1289 Logout(tc) 1290 1291 require.True(t, len(loginUI.PaperPhrase) > 0) 1292 1293 // redo SetupEngineTest to get a new home directory...should look like a 1294 // new device. 1295 tc2 := SetupEngineTest(t, "login") 1296 defer tc2.Cleanup() 1297 1298 secUI := fu.NewSecretUI() 1299 provUI := newTestProvisionUIPaper() 1300 provLoginUI := &libkb.TestLoginUI{Username: fu.Username} 1301 uis = libkb.UIs{ 1302 ProvisionUI: provUI, 1303 LogUI: tc2.G.UI.GetLogUI(), 1304 SecretUI: secUI, 1305 LoginUI: provLoginUI, 1306 GPGUI: &gpgtestui{}, 1307 } 1308 1309 m := NewMetaContextForTest(tc2).WithUIs(uis) 1310 eng := NewPaperProvisionEngine(tc2.G, fu.Username, "fakedevice", loginUI.PaperPhrase) 1311 err = RunEngine2(m, eng) 1312 require.NoError(t, err) 1313 1314 testUserHasDeviceKey(tc2) 1315 1316 assertNumDevicesAndKeys(tc, fu, 3, 6) 1317 err = AssertProvisioned(tc2) 1318 require.NoError(t, err) 1319 1320 require.Equal(t, provUI.calledChooseDeviceType, 0) 1321 require.Equal(t, provLoginUI.CalledGetEmailOrUsername, 0) 1322} 1323 1324func TestSelfProvision(t *testing.T) { 1325 tc := SetupEngineTest(t, "login") 1326 defer tc.Cleanup() 1327 1328 user := CreateAndSignupFakeUser(tc, "clone") 1329 secUI := user.NewSecretUI() 1330 provUI := newTestProvisionUIPaper() 1331 provLoginUI := &libkb.TestLoginUI{Username: user.Username} 1332 uis := libkb.UIs{ 1333 ProvisionUI: provUI, 1334 LogUI: tc.G.UI.GetLogUI(), 1335 SecretUI: secUI, 1336 LoginUI: provLoginUI, 1337 GPGUI: &gpgtestui{}, 1338 } 1339 1340 m := NewMetaContextForTest(tc).WithUIs(uis) 1341 // Test the happy case of successfully self provisioning. 1342 assertValidSelfProvision(t, tc, m, user) 1343} 1344 1345func assertValidSelfProvision(t *testing.T, tc libkb.TestContext, m libkb.MetaContext, user *FakeUser) { 1346 libkb.CreateClonedDevice(tc, m) 1347 newName := tc.G.ActiveDevice.Name() + "uncloneme" 1348 eng := NewSelfProvisionEngine(tc.G, newName) 1349 err := RunEngine2(m, eng) 1350 require.NoError(t, err) 1351 1352 testUserHasDeviceKey(tc) 1353 assertNumDevicesAndKeys(tc, user, 2, 4) 1354 err = AssertProvisioned(tc) 1355 require.NoError(t, err) 1356 require.Equal(t, tc.G.ActiveDevice.Name(), newName) 1357 1358 assertDeviceKeysCached(tc) 1359 assertPassphraseStreamCache(tc) 1360 assertSecretStored(tc, user.Username) 1361 1362 // GetBootstrapStatus should return without error and with LoggedIn set to 1363 // true. 1364 beng := NewBootstrap(tc.G) 1365 err = RunEngine2(m, beng) 1366 require.NoError(t, err) 1367 status := beng.Status() 1368 require.True(t, status.LoggedIn) 1369 require.True(t, status.Registered) 1370 1371 t.Logf("test tracks") 1372 testTrack(t, tc, libkb.KeybaseNullSigVersion, "t_alice") 1373 testSign(t, tc) 1374 1375 // Make sure that we can still track without a passphrase 1376 // after a simulated service restart. In other words, that 1377 // the full LKSec secret was written to the secret store. 1378 simulateServiceRestart(t, tc, user) 1379 testSign(t, tc) 1380 testTrack(t, tc, libkb.KeybaseNullSigVersion, "t_bob") 1381 assertDeviceKeysCached(tc) 1382 require.Equal(t, tc.G.ActiveDevice.Name(), newName) 1383 1384 Logout(tc) 1385 user.LoginOrBust(tc) 1386} 1387 1388func TestSelfProvisionFailNoClone(t *testing.T) { 1389 // If we don't have a clone, we can't run this engine 1390 testFailSelfProvision(t, func(tc libkb.TestContext, m libkb.MetaContext) string { 1391 return "new" 1392 }) 1393} 1394 1395func TestSelfProvisionFailDuplicateName(t *testing.T) { 1396 testFailSelfProvision(t, func(tc libkb.TestContext, m libkb.MetaContext) string { 1397 libkb.CreateClonedDevice(tc, m) 1398 // Use the default name so we get an error when provisioning. 1399 return "" 1400 }) 1401} 1402 1403func testFailSelfProvision(t *testing.T, fn func(tc libkb.TestContext, m libkb.MetaContext) string) { 1404 1405 tc := SetupEngineTest(t, "login") 1406 defer tc.Cleanup() 1407 1408 user := CreateAndSignupFakeUser(tc, "clone") 1409 1410 secUI := user.NewSecretUI() 1411 provUI := newTestProvisionUIPaper() 1412 provLoginUI := &libkb.TestLoginUI{Username: user.Username} 1413 uis := libkb.UIs{ 1414 ProvisionUI: provUI, 1415 LogUI: tc.G.UI.GetLogUI(), 1416 SecretUI: secUI, 1417 LoginUI: provLoginUI, 1418 GPGUI: &gpgtestui{}, 1419 } 1420 m := NewMetaContextForTest(tc).WithUIs(uis) 1421 1422 suffix := fn(tc, m) 1423 oldName := tc.G.ActiveDevice.Name() 1424 newName := oldName + suffix 1425 1426 t.Logf("self provision running %v %v", oldName, newName) 1427 eng := NewSelfProvisionEngine(tc.G, newName) 1428 err := RunEngine2(m, eng) 1429 require.Error(t, err) 1430 t.Logf("self provision failed successfully %v %v", oldName, newName) 1431 1432 testUserHasDeviceKey(tc) 1433 // Since provisioning failed, we still just have a single device. 1434 assertNumDevicesAndKeys(tc, user, 1, 2) 1435 require.Equal(t, tc.G.ActiveDevice.Name(), oldName) 1436 1437 // GetBootstrapStatus should return without error and with LoggedIn set 1438 // to true. 1439 beng := NewBootstrap(tc.G) 1440 err = RunEngine2(m, beng) 1441 require.NoError(t, err) 1442 status := beng.Status() 1443 require.True(t, status.LoggedIn) 1444 require.True(t, status.Registered) 1445 1446 Logout(tc) 1447 user.LoginOrBust(tc) 1448 1449 // Make sure we can successfully self provision after we've failed. 1450 assertValidSelfProvision(t, tc, m, user) 1451} 1452 1453// Provision device using a private GPG key (not synced to keybase 1454// server), import private key to lksec. 1455func TestProvisionGPGImportOK(t *testing.T) { 1456 tc := SetupEngineTest(t, "login") 1457 defer tc.Cleanup() 1458 1459 u1 := createFakeUserWithPGPPubOnly(t, tc) 1460 Logout(tc) 1461 1462 // redo SetupEngineTest to get a new home directory...should look like a new device. 1463 tc2 := SetupEngineTest(t, "login") 1464 defer tc2.Cleanup() 1465 1466 // we need the gpg keyring that's in the first homedir 1467 if err := tc.MoveGpgKeyringTo(tc2); err != nil { 1468 t.Fatal(err) 1469 } 1470 1471 // run login on new device 1472 uis2 := libkb.UIs{ 1473 ProvisionUI: newTestProvisionUIGPGImport(), 1474 LogUI: tc2.G.UI.GetLogUI(), 1475 SecretUI: u1.NewSecretUI(), 1476 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 1477 GPGUI: &gpgtestui{}, 1478 } 1479 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 1480 m2 := NewMetaContextForTest(tc2).WithUIs(uis2) 1481 if err := RunEngine2(m2, eng); err != nil { 1482 t.Fatal(err) 1483 } 1484 1485 testUserHasDeviceKey(tc2) 1486 1487 // highly possible they didn't have a paper key, so make sure they still don't have one: 1488 hasZeroPaperDev(tc2, u1) 1489 1490 if err := AssertProvisioned(tc2); err != nil { 1491 t.Fatal(err) 1492 } 1493 1494 // since they imported their pgp key, they should be able to pgp sign something: 1495 if err := signString(tc2, "sign me", u1.NewSecretUI()); err != nil { 1496 t.Error("pgp sign failed after gpg provision w/ import") 1497 t.Fatal(err) 1498 } 1499 1500 // after provisioning, the secret should be stored 1501 assertSecretStored(tc2, u1.Username) 1502} 1503 1504// Provision device using a private GPG key (not synced to keybase 1505// server), import private key to lksec. User selects key from 1506// several matching keys. 1507func TestProvisionGPGImportMultiple(t *testing.T) { 1508 tc := SetupEngineTest(t, "login") 1509 defer tc.Cleanup() 1510 1511 u1 := createFakeUserWithPGPMult(t, tc) 1512 Logout(tc) 1513 1514 // redo SetupEngineTest to get a new home directory...should look like a new device. 1515 tc2 := SetupEngineTest(t, "login") 1516 defer tc2.Cleanup() 1517 1518 // we need the gpg keyring that's in the first homedir 1519 if err := tc.MoveGpgKeyringTo(tc2); err != nil { 1520 t.Fatal(err) 1521 } 1522 1523 // run login on new device 1524 uis2 := libkb.UIs{ 1525 ProvisionUI: newTestProvisionUIGPGImport(), 1526 LogUI: tc2.G.UI.GetLogUI(), 1527 SecretUI: u1.NewSecretUI(), 1528 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 1529 GPGUI: &gpgtestui{}, 1530 } 1531 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 1532 m2 := NewMetaContextForTest(tc2).WithUIs(uis2) 1533 if err := RunEngine2(m2, eng); err != nil { 1534 t.Fatal(err) 1535 } 1536 1537 testUserHasDeviceKey(tc2) 1538 1539 // highly possible they didn't have a paper key, so make sure they still don't have one: 1540 hasZeroPaperDev(tc2, u1) 1541 1542 if err := AssertProvisioned(tc2); err != nil { 1543 t.Fatal(err) 1544 } 1545 1546 // since they imported their pgp key, they should be able to pgp sign something: 1547 if err := signString(tc2, "sign me", u1.NewSecretUI()); err != nil { 1548 t.Error("pgp sign failed after gpg provision w/ import") 1549 t.Fatal(err) 1550 } 1551 1552 // after provisioning, the secret should be stored 1553 assertSecretStored(tc2, u1.Username) 1554} 1555 1556// Provision device using a private GPG key (not synced to keybase 1557// server), use gpg to sign (no private key import). 1558func TestProvisionGPGSign(t *testing.T) { 1559 // use tcCheck just to check gpg version 1560 tcCheck := SetupEngineTest(t, "check") 1561 defer tcCheck.Cleanup() 1562 skipOldGPG(tcCheck) 1563 1564 // this test sometimes fails at the GPG level with a "Bad signature" error, 1565 // so we're going to retry it several times to hopefully get past it. 1566 attempts := 10 1567 for i := 0; i < attempts; i++ { 1568 tc := SetupEngineTest(t, "login") 1569 defer tc.Cleanup() 1570 1571 u1 := createFakeUserWithPGPPubOnly(t, tc) 1572 Logout(tc) 1573 1574 // redo SetupEngineTest to get a new home directory...should look like a new device. 1575 tc2 := SetupEngineTest(t, "login") 1576 defer tc2.Cleanup() 1577 1578 // we need the gpg keyring that's in the first homedir 1579 if err := tc.MoveGpgKeyringTo(tc2); err != nil { 1580 t.Fatal(err) 1581 } 1582 1583 // run login on new device 1584 uis2 := libkb.UIs{ 1585 ProvisionUI: newTestProvisionUIGPGSign(), 1586 LogUI: tc2.G.UI.GetLogUI(), 1587 SecretUI: u1.NewSecretUI(), 1588 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 1589 GPGUI: &gpgtestui{Contextified: libkb.NewContextified(tc2.G)}, 1590 } 1591 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 1592 m2 := NewMetaContextForTest(tc2).WithUIs(uis2) 1593 if err := RunEngine2(m2, eng); err != nil { 1594 t.Logf("test run %d: RunEngine(Login) error: %s", i+1, err) 1595 continue 1596 } 1597 1598 t.Logf("test run %d: RunEngine(Login) succeeded", i+1) 1599 1600 testUserHasDeviceKey(tc2) 1601 1602 // highly possible they didn't have a paper key, so make sure they still don't have one: 1603 hasZeroPaperDev(tc2, u1) 1604 1605 if err := AssertProvisioned(tc2); err != nil { 1606 t.Fatal(err) 1607 } 1608 1609 // after provisioning, the secret should be stored 1610 assertSecretStored(tc2, u1.Username) 1611 1612 checkPerUserKeyCount(&tc2, 1) 1613 1614 // since they *did not* import a pgp key, they should *not* be able to pgp sign something: 1615 if err := signString(tc2, "sign me", u1.NewSecretUI()); err == nil { 1616 t.Error("pgp sign worked after gpg provision w/o import") 1617 t.Fatal(err) 1618 } 1619 1620 t.Logf("test run %d: all checks passed, returning", i+1) 1621 return 1622 } 1623 1624 t.Fatalf("TestProvisionGPGSign failed %d times", attempts) 1625} 1626 1627func TestProvisionGPGSignFailedSign(t *testing.T) { 1628 tc := SetupEngineTest(t, "login") 1629 defer tc.Cleanup() 1630 1631 u1 := createFakeUserWithPGPPubOnly(t, tc) 1632 Logout(tc) 1633 1634 // redo SetupEngineTest to get a new home directory...should look like a new device. 1635 tc2 := SetupEngineTest(t, "login") 1636 defer tc2.Cleanup() 1637 1638 // we need the gpg keyring that's in the first homedir 1639 if err := tc.MoveGpgKeyringTo(tc2); err != nil { 1640 t.Fatal(err) 1641 } 1642 1643 // run login on new device 1644 uis2 := libkb.UIs{ 1645 ProvisionUI: newTestProvisionUIGPGSign(), 1646 LogUI: tc2.G.UI.GetLogUI(), 1647 SecretUI: u1.NewSecretUI(), 1648 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 1649 GPGUI: &gpgTestUIBadSign{}, 1650 } 1651 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 1652 m2 := NewMetaContextForTest(tc2).WithUIs(uis2) 1653 if err := RunEngine2(m2, eng); err == nil { 1654 t.Fatal("expected a failure in login") 1655 } 1656 1657 cf := tc2.G.Env.GetConfigFilename() 1658 jf := libkb.NewJSONConfigFile(tc2.G, cf) 1659 if err := jf.Load(true); err != nil { 1660 t.Fatal(err) 1661 } 1662 devid := jf.GetDeviceID() 1663 if !devid.IsNil() { 1664 t.Fatalf("got a non-nil Device ID after failed GPG provision (%v)", devid) 1665 } 1666} 1667 1668// Provision device using a private GPG key (not synced to keybase 1669// server), use gpg to sign (no private key import). 1670// Enable secret storage. keybase-issues#1822 1671func TestProvisionGPGSignSecretStore(t *testing.T) { 1672 tcCheck := SetupEngineTest(t, "check") 1673 defer tcCheck.Cleanup() 1674 skipOldGPG(tcCheck) 1675 1676 // this test sometimes fails at the GPG level with a "Bad signature" error, 1677 // so we're going to retry it several times to hopefully get past it. 1678 attempts := 10 1679 for i := 0; i < attempts; i++ { 1680 tc := SetupEngineTest(t, "login") 1681 defer tc.Cleanup() 1682 1683 u1 := createFakeUserWithPGPPubOnly(t, tc) 1684 Logout(tc) 1685 1686 // redo SetupEngineTest to get a new home directory...should look like a new device. 1687 tc2 := SetupEngineTest(t, "login") 1688 defer tc2.Cleanup() 1689 1690 // we need the gpg keyring that's in the first homedir 1691 if err := tc.MoveGpgKeyringTo(tc2); err != nil { 1692 t.Fatal(err) 1693 } 1694 1695 // create a secret UI that stores the secret 1696 secUI := u1.NewSecretUI() 1697 secUI.StoreSecret = true 1698 1699 // run login on new device 1700 uis2 := libkb.UIs{ 1701 ProvisionUI: newTestProvisionUIGPGSign(), 1702 LogUI: tc2.G.UI.GetLogUI(), 1703 SecretUI: secUI, 1704 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 1705 GPGUI: &gpgtestui{Contextified: libkb.NewContextified(tc2.G)}, 1706 } 1707 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 1708 m2 := NewMetaContextForTest(tc2).WithUIs(uis2) 1709 if err := RunEngine2(m2, eng); err != nil { 1710 t.Logf("test run %d: RunEngine(Login) error: %s", i+1, err) 1711 continue 1712 } 1713 1714 t.Logf("test run %d: RunEngine(Login) succeeded", i+1) 1715 1716 testUserHasDeviceKey(tc2) 1717 1718 // highly possible they didn't have a paper key, so make sure they still don't have one: 1719 hasZeroPaperDev(tc2, u1) 1720 1721 if err := AssertProvisioned(tc2); err != nil { 1722 t.Fatal(err) 1723 } 1724 1725 // after provisioning, the secret should be stored 1726 assertSecretStored(tc2, u1.Username) 1727 1728 t.Logf("test run %d: all checks passed, returning", i+1) 1729 return 1730 } 1731 1732 t.Fatalf("TestProvisionGPGSignSecretStore failed %d times", attempts) 1733} 1734 1735// Provision device using a private GPG key (not synced to keybase 1736// server). Import private key to lksec fails, switches to gpg 1737// sign, which works. 1738func TestProvisionGPGSwitchToSign(t *testing.T) { 1739 tcCheck := SetupEngineTest(t, "check") 1740 defer tcCheck.Cleanup() 1741 skipOldGPG(tcCheck) 1742 1743 // this test sometimes fails at the GPG level with a "Bad signature" error, 1744 // so we're going to retry it several times to hopefully get past it. 1745 attempts := 10 1746 for i := 0; i < attempts; i++ { 1747 tc := SetupEngineTest(t, "login") 1748 defer tc.Cleanup() 1749 1750 u1 := createFakeUserWithPGPPubOnly(t, tc) 1751 Logout(tc) 1752 1753 // redo SetupEngineTest to get a new home directory...should look like a new device. 1754 tc2 := SetupEngineTest(t, "login") 1755 defer tc2.Cleanup() 1756 1757 // we need the gpg keyring that's in the first homedir 1758 if err := tc.MoveGpgKeyringTo(tc2); err != nil { 1759 t.Fatal(err) 1760 } 1761 1762 // load the user (bypassing LoginUsername for this test...) 1763 user, err := libkb.LoadUser(libkb.NewLoadUserByNameArg(tc2.G, u1.Username)) 1764 if err != nil { 1765 t.Fatal(err) 1766 } 1767 1768 // run login on new device 1769 uis := libkb.UIs{ 1770 ProvisionUI: newTestProvisionUIGPGImport(), 1771 LogUI: tc2.G.UI.GetLogUI(), 1772 SecretUI: u1.NewSecretUI(), 1773 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 1774 GPGUI: &gpgtestui{Contextified: libkb.NewContextified(tc2.G)}, 1775 } 1776 1777 arg := loginProvisionArg{ 1778 DeviceType: keybase1.DeviceTypeV2_DESKTOP, 1779 ClientType: keybase1.ClientType_CLI, 1780 User: user, 1781 } 1782 1783 eng := newLoginProvision(tc2.G, &arg) 1784 // use a gpg client that will fail to import any gpg key 1785 eng.gpgCli = newGPGImportFailer(tc2.G) 1786 m := NewMetaContextForTest(tc2).WithUIs(uis).WithNewProvisionalLoginContext() 1787 1788 if err := RunEngine2(m, eng); err != nil { 1789 t.Logf("test run %d: RunEngine(Login) error: %s", i+1, err) 1790 continue 1791 } 1792 1793 t.Logf("test run %d: RunEngine(Login) succeeded", i+1) 1794 1795 testUserHasDeviceKey(tc2) 1796 1797 // highly possible they didn't have a paper key, so make sure they still don't have one: 1798 hasZeroPaperDev(tc2, u1) 1799 1800 if err := AssertProvisioned(tc2); err != nil { 1801 t.Fatal(err) 1802 } 1803 1804 // after provisioning, the secret should be stored 1805 assertSecretStored(tc2, u1.Username) 1806 1807 // since they did not import their pgp key, they should not be able 1808 // to pgp sign something: 1809 if err := signString(tc2, "sign me", u1.NewSecretUI()); err == nil { 1810 t.Fatal("pgp sign worked after gpg sign provisioning") 1811 } 1812 t.Logf("test run %d: all checks passed, returning", i+1) 1813 return 1814 } 1815 1816 t.Fatalf("TestProvisionGPGSwitchToSign failed %d times", attempts) 1817} 1818 1819// Try provision device using a private GPG key (not synced to keybase 1820// server). Import private key to lksec fails, user does not want 1821// to switch to gpg sign, so provisioning fails. 1822func TestProvisionGPGNoSwitchToSign(t *testing.T) { 1823 tc := SetupEngineTest(t, "login") 1824 defer tc.Cleanup() 1825 1826 u1 := createFakeUserWithPGPPubOnly(t, tc) 1827 Logout(tc) 1828 1829 // redo SetupEngineTest to get a new home directory...should look like a new device. 1830 tc2 := SetupEngineTest(t, "login") 1831 defer tc2.Cleanup() 1832 1833 // we need the gpg keyring that's in the first homedir 1834 if err := tc.MoveGpgKeyringTo(tc2); err != nil { 1835 t.Fatal(err) 1836 } 1837 1838 // load the user (bypassing LoginUsername for this test...) 1839 user, err := libkb.LoadUser(libkb.NewLoadUserByNameArg(tc2.G, u1.Username)) 1840 if err != nil { 1841 t.Fatal(err) 1842 } 1843 1844 // instruct provisioning ui to not allow the switch to gpg sign: 1845 provUI := newTestProvisionUIGPGImport() 1846 provUI.abortSwitchToGPGSign = true 1847 1848 // run login on new device 1849 uis := libkb.UIs{ 1850 ProvisionUI: provUI, 1851 LogUI: tc2.G.UI.GetLogUI(), 1852 SecretUI: u1.NewSecretUI(), 1853 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 1854 GPGUI: &gpgtestui{Contextified: libkb.NewContextified(tc2.G)}, 1855 } 1856 1857 arg := loginProvisionArg{ 1858 DeviceType: keybase1.DeviceTypeV2_DESKTOP, 1859 ClientType: keybase1.ClientType_CLI, 1860 User: user, 1861 } 1862 1863 eng := newLoginProvision(tc2.G, &arg) 1864 // use a gpg client that will fail to import any gpg key 1865 eng.gpgCli = newGPGImportFailer(tc2.G) 1866 1867 m := NewMetaContextForTest(tc2).WithUIs(uis) 1868 1869 if err := RunEngine2(m, eng); err == nil { 1870 t.Fatal("provisioning worked despite not allowing switch to gpg sign") 1871 } 1872} 1873 1874// User with pgp keys, but on a device without any gpg keyring. 1875func TestProvisionGPGNoKeyring(t *testing.T) { 1876 tc := SetupEngineTest(t, "login") 1877 u1 := createFakeUserWithPGPPubOnly(t, tc) 1878 Logout(tc) 1879 tc.Cleanup() 1880 1881 // redo SetupEngineTest to get a new home directory...should look like a new device. 1882 tc2 := SetupEngineTest(t, "login") 1883 defer tc2.Cleanup() 1884 1885 // run login on new device 1886 uis2 := libkb.UIs{ 1887 ProvisionUI: newTestProvisionUIGPGImport(), 1888 LogUI: tc2.G.UI.GetLogUI(), 1889 SecretUI: u1.NewSecretUI(), 1890 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 1891 GPGUI: &gpgtestui{Contextified: libkb.NewContextified(tc.G)}, 1892 } 1893 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 1894 m2 := NewMetaContextForTest(tc2).WithUIs(uis2) 1895 if err := RunEngine2(m2, eng); err == nil { 1896 t.Fatal("provision worked without gpg keyring") 1897 } else if _, ok := err.(libkb.NoMatchingGPGKeysError); !ok { 1898 t.Errorf("error %T, expected libkb.NoMatchingGPGKeysError", err) 1899 } 1900} 1901 1902// User with pgp keys, but on a device with gpg keys that don't 1903// match. 1904func TestProvisionGPGNoMatch(t *testing.T) { 1905 tc := SetupEngineTest(t, "login") 1906 u1 := createFakeUserWithPGPPubOnly(t, tc) 1907 Logout(tc) 1908 tc.Cleanup() 1909 1910 // redo SetupEngineTest to get a new home directory...should look like a new device. 1911 tc2 := SetupEngineTest(t, "login") 1912 defer tc2.Cleanup() 1913 1914 // make a new keyring, not associated with keybase 1915 if err := tc2.GenerateGPGKeyring(u1.Email); err != nil { 1916 t.Fatal(err) 1917 } 1918 1919 // run login on new device 1920 uis2 := libkb.UIs{ 1921 ProvisionUI: newTestProvisionUIGPGImport(), 1922 LogUI: tc2.G.UI.GetLogUI(), 1923 SecretUI: u1.NewSecretUI(), 1924 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 1925 GPGUI: &gpgtestui{Contextified: libkb.NewContextified(tc2.G)}, 1926 } 1927 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 1928 m2 := NewMetaContextForTest(tc2).WithUIs(uis2) 1929 if err := RunEngine2(m2, eng); err == nil { 1930 t.Fatal("provision worked without matching gpg key") 1931 } else if _, ok := err.(libkb.NoMatchingGPGKeysError); !ok { 1932 t.Errorf("error %T, expected libkb.NoMatchingGPGKeysError", err) 1933 } 1934} 1935 1936// User with pgp keys, but on a device without gpg. 1937func TestProvisionGPGNoGPGExecutable(t *testing.T) { 1938 tc := SetupEngineTest(t, "login") 1939 u1 := createFakeUserWithPGPPubOnly(t, tc) 1940 Logout(tc) 1941 tc.Cleanup() 1942 1943 // redo SetupEngineTest to get a new home directory...should look like a new device. 1944 tc2 := SetupEngineTest(t, "login") 1945 defer tc2.Cleanup() 1946 1947 // this should make it unable to find gpg 1948 tc2.G.Env.Test.GPG = filepath.Join(string(filepath.Separator), "dev", "null") 1949 1950 // run login on new device 1951 uis2 := libkb.UIs{ 1952 ProvisionUI: newTestProvisionUIGPGImport(), 1953 LogUI: tc2.G.UI.GetLogUI(), 1954 SecretUI: u1.NewSecretUI(), 1955 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 1956 GPGUI: &gpgtestui{Contextified: libkb.NewContextified(tc2.G)}, 1957 } 1958 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 1959 m2 := NewMetaContextForTest(tc2).WithUIs(uis2) 1960 err := RunEngine2(m2, eng) 1961 if err == nil { 1962 t.Fatal("provision worked without gpg") 1963 } 1964 if _, ok := err.(libkb.GPGUnavailableError); !ok { 1965 t.Errorf("login run err type: %T, expected libkb.GPGUnavailableError", err) 1966 } 1967} 1968 1969// User with pgp keys, but on a device where gpg executable 1970// specified is not found. 1971func TestProvisionGPGNoGPGFound(t *testing.T) { 1972 tc := SetupEngineTest(t, "login") 1973 u1 := createFakeUserWithPGPPubOnly(t, tc) 1974 Logout(tc) 1975 tc.Cleanup() 1976 1977 // redo SetupEngineTest to get a new home directory...should look like a new device. 1978 tc2 := SetupEngineTest(t, "login") 1979 defer tc2.Cleanup() 1980 1981 // this should make it unable to find gpg 1982 tc2.G.Env.Test.GPG = filepath.Join(string(filepath.Separator), "not", "a", "directory", "that", "ever", "exists", "bin", "gpg") 1983 1984 // run login on new device 1985 uis2 := libkb.UIs{ 1986 ProvisionUI: newTestProvisionUIGPGImport(), 1987 LogUI: tc2.G.UI.GetLogUI(), 1988 SecretUI: u1.NewSecretUI(), 1989 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 1990 GPGUI: &gpgtestui{Contextified: libkb.NewContextified(tc2.G)}, 1991 } 1992 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 1993 m2 := NewMetaContextForTest(tc2).WithUIs(uis2) 1994 err := RunEngine2(m2, eng) 1995 if err == nil { 1996 t.Fatal("provision worked without gpg") 1997 } 1998 if _, ok := err.(libkb.GPGUnavailableError); !ok { 1999 t.Errorf("login run err type: %T, expected libkb.GPGUnavailableError", err) 2000 } 2001} 2002 2003func TestProvisionDupDevice(t *testing.T) { 2004 // device X (provisioner) context: 2005 tcX := SetupEngineTest(t, "kex2provision") 2006 defer tcX.Cleanup() 2007 2008 // device Y (provisionee) context: 2009 tcY := SetupEngineTest(t, "template") 2010 defer tcY.Cleanup() 2011 2012 // provisioner needs to be logged in 2013 userX := CreateAndSignupFakeUser(tcX, "login") 2014 2015 secretCh := make(chan kex2.Secret) 2016 2017 provui := &testProvisionDupDeviceUI{newTestProvisionUISecretCh(secretCh)} 2018 2019 // provisionee calls login: 2020 uis := libkb.UIs{ 2021 ProvisionUI: provui, 2022 LoginUI: &libkb.TestLoginUI{Username: userX.Username}, 2023 LogUI: tcY.G.UI.GetLogUI(), 2024 SecretUI: &libkb.TestSecretUI{}, 2025 GPGUI: &gpgtestui{}, 2026 } 2027 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2028 m := NewMetaContextForTest(tcY).WithUIs(uis) 2029 2030 // start provisionee 2031 if err := RunEngine2(m, eng); err == nil { 2032 t.Errorf("login ran without error") 2033 return 2034 } 2035 2036 // Note: there is no need to start the provisioner as the provisionee will 2037 // fail because of the duplicate device name before the provisioner 2038 // is needed. 2039 2040 // double-check that provisioning failed 2041 if err := AssertProvisioned(tcY); err == nil { 2042 t.Fatal("device provisioned using existing name") 2043 } 2044} 2045 2046// If a user has no keys, provision via passphrase should work. 2047// This tests when they have another account on the same machine. 2048func TestProvisionPassphraseNoKeysMultipleAccounts(t *testing.T) { 2049 tcWeb := SetupEngineTest(t, "login") 2050 2051 // create a "web" user with no keys 2052 username, passphrase := createFakeUserWithNoKeys(tcWeb) 2053 Logout(tcWeb) 2054 tcWeb.Cleanup() 2055 2056 // create a new test context 2057 tc := SetupEngineTest(t, "fake") 2058 defer tc.Cleanup() 2059 2060 // create a user to fill up config with something 2061 CreateAndSignupFakeUser(tc, "fake") 2062 Logout(tc) 2063 2064 // now try to log in as the web user 2065 uis := libkb.UIs{ 2066 ProvisionUI: newTestProvisionUIPassphrase(), 2067 LoginUI: &libkb.TestLoginUI{Username: username}, 2068 LogUI: tc.G.UI.GetLogUI(), 2069 SecretUI: &libkb.TestSecretUI{Passphrase: passphrase}, 2070 GPGUI: &gpgtestui{}, 2071 } 2072 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, username, keybase1.ClientType_CLI) 2073 m := NewMetaContextForTest(tc).WithUIs(uis) 2074 if err := RunEngine2(m, eng); err != nil { 2075 t.Fatal(err) 2076 } 2077 2078 // since this user didn't have any keys, login should have fixed that: 2079 testUserHasDeviceKey(tc) 2080 2081 // and they should not have a paper backup key by default 2082 hasZeroPaperDev(tc, &FakeUser{Username: username, Passphrase: passphrase}) 2083 2084 if err := AssertProvisioned(tc); err != nil { 2085 t.Fatal(err) 2086 } 2087 2088 // after provisioning, the secret should be stored 2089 assertSecretStored(tc, username) 2090} 2091 2092// We have obviated the unlock command by combining it with login. 2093func TestLoginStreamCache(t *testing.T) { 2094 tc := SetupEngineTest(t, "login") 2095 defer tc.Cleanup() 2096 2097 u1 := SignupFakeUserStoreSecret(tc, "login") 2098 assertSecretStored(tc, u1.Username) 2099 2100 if !assertStreamCache(tc, true) { 2101 t.Fatal("expected valid stream cache after signup") 2102 } 2103 2104 clearCaches(tc.G) 2105 2106 if !assertStreamCache(tc, false) { 2107 t.Fatal("expected invalid stream cache after clear") 2108 } 2109 2110 // This should not unlock the stream cache 2111 u1.LoginOrBust(tc) 2112 2113 if !assertStreamCache(tc, false) { 2114 t.Fatal("expected no valid stream cache after login") 2115 } 2116 assertDeviceKeysCached(tc) 2117 assertSecretStored(tc, u1.Username) 2118} 2119 2120// Check the device type 2121func TestLoginInvalidDeviceType(t *testing.T) { 2122 tcWeb := SetupEngineTest(t, "web") 2123 defer tcWeb.Cleanup() 2124 2125 username, passphrase := createFakeUserWithNoKeys(tcWeb) 2126 2127 Logout(tcWeb) 2128 2129 tc := SetupEngineTest(t, "login") 2130 defer tc.Cleanup() 2131 2132 uis := libkb.UIs{ 2133 ProvisionUI: newTestProvisionUIPassphrase(), 2134 LoginUI: &libkb.TestLoginUI{Username: username}, 2135 LogUI: tc.G.UI.GetLogUI(), 2136 SecretUI: &libkb.TestSecretUI{Passphrase: passphrase}, 2137 GPGUI: &gpgtestui{}, 2138 } 2139 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_PAPER, "", keybase1.ClientType_CLI) 2140 m := NewMetaContextForTest(tc).WithUIs(uis) 2141 if err := RunEngine2(m, eng); err == nil { 2142 t.Fatal("login with paper device type worked") 2143 } else if _, ok := err.(libkb.InvalidArgumentError); !ok { 2144 t.Errorf("err type: %T, expected libkb.InvalidArgumentError", err) 2145 } 2146} 2147 2148// Test that login provision checks for nil user in argument. 2149func TestProvisionNilUser(t *testing.T) { 2150 tc := SetupEngineTest(t, "login") 2151 defer tc.Cleanup() 2152 2153 arg := loginProvisionArg{ 2154 DeviceType: keybase1.DeviceTypeV2_DESKTOP, 2155 ClientType: keybase1.ClientType_CLI, 2156 User: nil, 2157 } 2158 eng := newLoginProvision(tc.G, &arg) 2159 uis := libkb.UIs{ 2160 ProvisionUI: newTestProvisionUIPassphrase(), 2161 LoginUI: &libkb.TestLoginUI{}, 2162 LogUI: tc.G.UI.GetLogUI(), 2163 SecretUI: &libkb.TestSecretUI{}, 2164 GPGUI: &gpgtestui{}, 2165 } 2166 m := NewMetaContextForTest(tc).WithUIs(uis) 2167 if err := RunEngine2(m, eng); err == nil { 2168 t.Fatal("loginprovision with nil user worked") 2169 } else if _, ok := err.(libkb.InvalidArgumentError); !ok { 2170 t.Errorf("err type: %T, expected libkb.InvalidArgumentError", err) 2171 } 2172} 2173 2174func userPlusPaper(t *testing.T) (*FakeUser, string) { 2175 tc := SetupEngineTest(t, "fake") 2176 defer tc.Cleanup() 2177 fu := NewFakeUserOrBust(t, "fake") 2178 arg := MakeTestSignupEngineRunArg(fu) 2179 arg.SkipPaper = false 2180 loginUI := &paperLoginUI{Username: fu.Username} 2181 uis := libkb.UIs{ 2182 LogUI: tc.G.UI.GetLogUI(), 2183 GPGUI: &gpgtestui{}, 2184 SecretUI: fu.NewSecretUI(), 2185 LoginUI: loginUI, 2186 } 2187 s := NewSignupEngine(tc.G, &arg) 2188 if err := RunEngine2(NewMetaContextForTest(tc).WithUIs(uis), s); err != nil { 2189 t.Fatal(err) 2190 } 2191 Logout(tc) 2192 return fu, loginUI.PaperPhrase 2193} 2194 2195func TestProvisionPaperFailures(t *testing.T) { 2196 // create two users 2197 ux, uxPaper := userPlusPaper(t) 2198 _, uyPaper := userPlusPaper(t) 2199 2200 // try provision as ux on a new device with uy's paper key 2201 tc := SetupEngineTest(t, "login") 2202 defer tc.Cleanup() 2203 2204 secUI := ux.NewSecretUI() 2205 secUI.Passphrase = uyPaper 2206 provUI := newTestProvisionUIPaper() 2207 provLoginUI := &libkb.TestLoginUI{Username: ux.Username} 2208 uis := libkb.UIs{ 2209 ProvisionUI: provUI, 2210 LogUI: tc.G.UI.GetLogUI(), 2211 SecretUI: secUI, 2212 LoginUI: provLoginUI, 2213 GPGUI: &gpgtestui{}, 2214 } 2215 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2216 m := NewMetaContextForTest(tc).WithUIs(uis) 2217 if err := RunEngine2(m, eng); err == nil { 2218 t.Fatal("provision with another user's paper key worked") 2219 } 2220 2221 // try provision as ux on a new device with swapped word paper key 2222 tcSwap := SetupEngineTest(t, "login") 2223 defer tcSwap.Cleanup() 2224 2225 words := strings.Fields(uxPaper) 2226 didSwap := false 2227 for i := 2; i < len(words)-1; i++ { 2228 if words[i] != words[i+1] { 2229 tc.G.Log.Debug("swapped word %d (%s) and %d (%s)", i, words[i], i+1, words[i+1]) 2230 didSwap = true 2231 words[i], words[i+1] = words[i+1], words[i] 2232 break 2233 } 2234 } 2235 if !didSwap { 2236 t.Fatalf("paper key words were all the same; could not swap: %s", uxPaper) 2237 } 2238 swapped := strings.Join(words, " ") 2239 secUI = ux.NewSecretUI() 2240 secUI.Passphrase = swapped 2241 provUI = newTestProvisionUIPaper() 2242 provLoginUI = &libkb.TestLoginUI{Username: ux.Username} 2243 uis = libkb.UIs{ 2244 ProvisionUI: provUI, 2245 LogUI: tcSwap.G.UI.GetLogUI(), 2246 SecretUI: secUI, 2247 LoginUI: provLoginUI, 2248 GPGUI: &gpgtestui{}, 2249 } 2250 eng = NewLogin(tcSwap.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2251 m = NewMetaContextForTest(tcSwap).WithUIs(uis) 2252 err := RunEngine2(m, eng) 2253 if err == nil { 2254 t.Fatal("provision with swapped word paper key worked") 2255 } 2256 if _, ok := err.(libkb.NotFoundError); !ok { 2257 t.Fatalf("error type: %T, expected libkb.NotFoundError", err) 2258 } 2259 2260 // try provision as ux on a new device first with fu's paper key 2261 // then with ux's paper key (testing retry works) 2262 tc2 := SetupEngineTest(t, "login") 2263 defer tc2.Cleanup() 2264 2265 retrySecUI := &testRetrySecretUI{ 2266 Passphrases: []string{uyPaper, uxPaper}, 2267 } 2268 provUI = newTestProvisionUIPaper() 2269 provLoginUI = &libkb.TestLoginUI{Username: ux.Username} 2270 uis = libkb.UIs{ 2271 ProvisionUI: provUI, 2272 LogUI: tc2.G.UI.GetLogUI(), 2273 SecretUI: retrySecUI, 2274 LoginUI: provLoginUI, 2275 GPGUI: &gpgtestui{}, 2276 } 2277 eng = NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2278 m = NewMetaContextForTest(tc2).WithUIs(uis) 2279 if err := RunEngine2(m, eng); err != nil { 2280 t.Fatal(err) 2281 } 2282 if retrySecUI.index != len(retrySecUI.Passphrases) { 2283 t.Errorf("retry sec ui index: %d, expected %d", retrySecUI.index, len(retrySecUI.Passphrases)) 2284 } 2285 2286 // try provision as ux on a new device first with garbage paper key 2287 // then with ux's paper key (testing retry works) 2288 tc3 := SetupEngineTest(t, "login") 2289 defer tc3.Cleanup() 2290 2291 retrySecUI = &testRetrySecretUI{ 2292 Passphrases: []string{"garbage garbage garbage", uxPaper}, 2293 } 2294 provUI = newTestProvisionUIPaper() 2295 provLoginUI = &libkb.TestLoginUI{Username: ux.Username} 2296 uis = libkb.UIs{ 2297 ProvisionUI: provUI, 2298 LogUI: tc3.G.UI.GetLogUI(), 2299 SecretUI: retrySecUI, 2300 LoginUI: provLoginUI, 2301 GPGUI: &gpgtestui{}, 2302 } 2303 eng = NewLogin(tc3.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2304 m = NewMetaContextForTest(tc3).WithUIs(uis) 2305 if err := RunEngine2(m, eng); err != nil { 2306 t.Fatal(err) 2307 } 2308 if retrySecUI.index != len(retrySecUI.Passphrases) { 2309 t.Errorf("retry sec ui index: %d, expected %d", retrySecUI.index, len(retrySecUI.Passphrases)) 2310 } 2311 2312 // try provision as ux on a new device first with invalid version paper key 2313 // then with ux's paper key (testing retry works) 2314 tc4 := SetupEngineTest(t, "login") 2315 defer tc4.Cleanup() 2316 2317 paperNextVer, err := libkb.MakePaperKeyPhrase(libkb.PaperKeyVersion + 1) 2318 if err != nil { 2319 t.Fatal(err) 2320 } 2321 retrySecUI = &testRetrySecretUI{ 2322 Passphrases: []string{paperNextVer.String(), uxPaper}, 2323 } 2324 provUI = newTestProvisionUIPaper() 2325 provLoginUI = &libkb.TestLoginUI{Username: ux.Username} 2326 uis = libkb.UIs{ 2327 ProvisionUI: provUI, 2328 LogUI: tc4.G.UI.GetLogUI(), 2329 SecretUI: retrySecUI, 2330 LoginUI: provLoginUI, 2331 GPGUI: &gpgtestui{}, 2332 } 2333 eng = NewLogin(tc4.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2334 m = NewMetaContextForTest(tc4).WithUIs(uis) 2335 if err := RunEngine2(m, eng); err != nil { 2336 t.Fatal(err) 2337 } 2338 if retrySecUI.index != len(retrySecUI.Passphrases) { 2339 t.Errorf("retry sec ui index: %d, expected %d", retrySecUI.index, len(retrySecUI.Passphrases)) 2340 } 2341 2342} 2343 2344// After kex provisioning, try using a synced pgp key to sign 2345// something. 2346func TestProvisionKexUseSyncPGP(t *testing.T) { 2347 // device X (provisioner) context: 2348 tcX := SetupEngineTestRealTriplesec(t, "kex2provision") 2349 defer tcX.Cleanup() 2350 2351 // device Y (provisionee) context: 2352 tcY := SetupEngineTestRealTriplesec(t, "template") 2353 defer tcY.Cleanup() 2354 2355 // create provisioner with synced pgp key 2356 userX := createFakeUserWithPGPSibkeyPushedPaper(tcX) 2357 var secretX kex2.Secret 2358 if _, err := rand.Read(secretX[:]); err != nil { 2359 t.Fatal(err) 2360 } 2361 2362 secretCh := make(chan kex2.Secret) 2363 2364 // provisionee calls login: 2365 uis := libkb.UIs{ 2366 ProvisionUI: newTestProvisionUISecretCh(secretCh), 2367 LoginUI: &libkb.TestLoginUI{Username: userX.Username}, 2368 LogUI: tcY.G.UI.GetLogUI(), 2369 SecretUI: &libkb.TestSecretUI{}, 2370 GPGUI: &gpgtestui{}, 2371 } 2372 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2373 2374 var wg sync.WaitGroup 2375 2376 // start provisionee 2377 wg.Add(1) 2378 go func() { 2379 defer wg.Done() 2380 m := NewMetaContextForTest(tcY).WithUIs(uis) 2381 if err := RunEngine2(m, eng); err != nil { 2382 t.Errorf("login error: %s", err) 2383 return 2384 } 2385 }() 2386 2387 // start provisioner 2388 provisioner := NewKex2Provisioner(tcX.G, secretX, nil) 2389 wg.Add(1) 2390 go func() { 2391 defer wg.Done() 2392 2393 uis := libkb.UIs{ 2394 SecretUI: userX.NewSecretUI(), 2395 ProvisionUI: newTestProvisionUI(), 2396 } 2397 m := NewMetaContextForTest(tcX).WithUIs(uis) 2398 if err := RunEngine2(m, provisioner); err != nil { 2399 t.Errorf("provisioner error: %s", err) 2400 return 2401 } 2402 }() 2403 secretFromY := <-secretCh 2404 provisioner.AddSecret(secretFromY) 2405 2406 wg.Wait() 2407 2408 if err := AssertProvisioned(tcY); err != nil { 2409 t.Fatal(err) 2410 } 2411 2412 t.Logf(strings.Repeat("*", 100)) 2413 t.Logf("provisioned") 2414 t.Logf(strings.Repeat("*", 100)) 2415 2416 testTrack(t, tcY, libkb.KeybaseNullSigVersion, "t_alice") 2417 2418 // tsec isn't cached on device Y, so this should fail since the 2419 // secret ui doesn't know the passphrase: 2420 if err := signString(tcY, "sign me", &libkb.TestSecretUI{}); err == nil { 2421 t.Fatal("sign worked on device Y after provisioning without knowing passphrase") 2422 } 2423 2424 // but if we know the passphrase, it should prompt for it 2425 // and use it 2426 if err := signString(tcY, "sign me", userX.NewSecretUI()); err != nil { 2427 t.Fatalf("sign failed on device Y with passphrase in secret ui: %s", err) 2428 } 2429} 2430 2431// Provision one (physical) device with multiple users. 2432func TestProvisionMultipleUsers(t *testing.T) { 2433 // make some users with synced pgp keys 2434 users := make([]*FakeUser, 3) 2435 for i := 0; i < len(users); i++ { 2436 tc := SetupEngineTest(t, "login") 2437 users[i] = createFakeUserWithPGPOnly(t, tc) 2438 Logout(tc) 2439 tc.Cleanup() 2440 } 2441 2442 // provision user[0] on a new device 2443 tc := SetupEngineTest(t, "login") 2444 defer tc.Cleanup() 2445 2446 uis := libkb.UIs{ 2447 ProvisionUI: newTestProvisionUIPassphrase(), 2448 LoginUI: &libkb.TestLoginUI{Username: users[0].Username}, 2449 LogUI: tc.G.UI.GetLogUI(), 2450 SecretUI: users[0].NewSecretUI(), 2451 GPGUI: &gpgtestui{}, 2452 } 2453 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2454 m := NewMetaContextForTest(tc).WithUIs(uis) 2455 if err := RunEngine2(m, eng); err != nil { 2456 t.Fatal(err) 2457 } 2458 2459 testUserHasDeviceKey(tc) 2460 hasZeroPaperDev(tc, users[0]) 2461 if err := AssertProvisioned(tc); err != nil { 2462 t.Fatal(err) 2463 } 2464 2465 Logout(tc) 2466 2467 // provision user[1] on the same device, specifying username 2468 uis = libkb.UIs{ 2469 ProvisionUI: newTestProvisionUIPassphrase(), 2470 LoginUI: &libkb.TestLoginUI{}, 2471 LogUI: tc.G.UI.GetLogUI(), 2472 SecretUI: users[1].NewSecretUI(), 2473 GPGUI: &gpgtestui{}, 2474 } 2475 eng = NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, users[1].Username, keybase1.ClientType_CLI) 2476 m = NewMetaContextForTest(tc).WithUIs(uis) 2477 if err := RunEngine2(m, eng); err != nil { 2478 t.Fatal(err) 2479 } 2480 2481 testUserHasDeviceKey(tc) 2482 hasZeroPaperDev(tc, users[1]) 2483 if err := AssertProvisioned(tc); err != nil { 2484 t.Fatal(err) 2485 } 2486 2487 Logout(tc) 2488 2489 // provision user[2] on the same device, specifying email 2490 uis = libkb.UIs{ 2491 ProvisionUI: newTestProvisionUIPassphrase(), 2492 LoginUI: &libkb.TestLoginUI{}, 2493 LogUI: tc.G.UI.GetLogUI(), 2494 SecretUI: users[2].NewSecretUI(), 2495 GPGUI: &gpgtestui{}, 2496 } 2497 eng = NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, users[2].Username, keybase1.ClientType_CLI) 2498 m = NewMetaContextForTest(tc).WithUIs(uis) 2499 if err := RunEngine2(m, eng); err != nil { 2500 t.Fatal(err) 2501 } 2502 2503 testUserHasDeviceKey(tc) 2504 hasZeroPaperDev(tc, users[2]) 2505 if err := AssertProvisioned(tc); err != nil { 2506 t.Fatal(err) 2507 } 2508 2509 Logout(tc) 2510 2511 // login via email does not work anymore (CORE-10470) 2512 uis = libkb.UIs{ 2513 ProvisionUI: newTestProvisionUIPassphrase(), 2514 LoginUI: &libkb.TestLoginUI{}, 2515 LogUI: tc.G.UI.GetLogUI(), 2516 SecretUI: users[2].NewSecretUI(), 2517 GPGUI: &gpgtestui{}, 2518 } 2519 eng = NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, users[2].Email, keybase1.ClientType_CLI) 2520 m = NewMetaContextForTest(tc).WithUIs(uis) 2521 err := RunEngine2(m, eng) 2522 require.Error(t, err) 2523 require.IsType(t, libkb.BadUsernameError{}, err) 2524 require.Contains(t, err.Error(), "not supported") 2525} 2526 2527// create a standard user with device keys, reset account, login. 2528func TestResetAccount(t *testing.T) { 2529 tc := SetupEngineTest(t, "login") 2530 defer tc.Cleanup() 2531 2532 u := CreateAndSignupFakeUser(tc, "login") 2533 originalDevice := tc.G.Env.GetDeviceID() 2534 ResetAccount(tc, u) 2535 2536 // this will reprovision as an eldest device: 2537 u.LoginOrBust(tc) 2538 if err := AssertProvisioned(tc); err != nil { 2539 t.Fatal(err) 2540 } 2541 2542 newDevice := tc.G.Env.GetDeviceID() 2543 2544 if newDevice == originalDevice { 2545 t.Errorf("device id did not change: %s", newDevice) 2546 } 2547 2548 testUserHasDeviceKey(tc) 2549} 2550 2551// create a standard user with device keys, reset account (but don't logout), login. 2552func TestResetAccountNoLogout(t *testing.T) { 2553 tc := SetupEngineTest(t, "login") 2554 defer tc.Cleanup() 2555 2556 u := CreateAndSignupFakeUser(tc, "login") 2557 originalDevice := tc.G.Env.GetDeviceID() 2558 ResetAccountNoLogout(tc, u) 2559 2560 // this will reprovision as an eldest device: 2561 u.LoginOrBust(tc) 2562 if err := AssertProvisioned(tc); err != nil { 2563 t.Fatal(err) 2564 } 2565 2566 newDevice := tc.G.Env.GetDeviceID() 2567 2568 if newDevice == originalDevice { 2569 t.Errorf("device id did not change: %s", newDevice) 2570 } 2571 2572 testUserHasDeviceKey(tc) 2573} 2574 2575// create a standard user with device keys, reset account (but don't logout), login. 2576// Prime the FullSelfer cache before reset. 2577func TestResetAccountNoLogoutSelfCache(t *testing.T) { 2578 tc := SetupEngineTest(t, "login") 2579 defer tc.Cleanup() 2580 2581 u := CreateAndSignupFakeUser(tc, "login") 2582 originalDevice := tc.G.Env.GetDeviceID() 2583 2584 // make sure FullSelf is cached 2585 err := tc.G.GetFullSelfer().WithSelf(context.TODO(), func(u *libkb.User) error { 2586 t.Logf("full self user: %s", u.GetName()) 2587 return nil 2588 }) 2589 require.NoError(t, err) 2590 2591 ResetAccountNoLogout(tc, u) 2592 2593 // this will reprovision as an eldest device: 2594 u.LoginOrBust(tc) 2595 if err := AssertProvisioned(tc); err != nil { 2596 t.Fatal(err) 2597 } 2598 2599 newDevice := tc.G.Env.GetDeviceID() 2600 2601 if newDevice == originalDevice { 2602 t.Errorf("device id did not change: %s", newDevice) 2603 } 2604 2605 testUserHasDeviceKey(tc) 2606} 2607 2608// After resetting account, try provisioning in a clean home dir. 2609func TestResetAccountNewHome(t *testing.T) { 2610 tc := SetupEngineTest(t, "login") 2611 defer tc.Cleanup() 2612 2613 u := CreateAndSignupFakeUser(tc, "login") 2614 originalDevice := tc.G.Env.GetDeviceID() 2615 ResetAccount(tc, u) 2616 2617 tcp := SetupEngineTest(t, "login") 2618 // this will reprovision as an eldest device: 2619 u.LoginOrBust(tcp) 2620 if err := AssertProvisioned(tcp); err != nil { 2621 t.Fatal(err) 2622 } 2623 2624 newDevice := tcp.G.Env.GetDeviceID() 2625 2626 if newDevice == originalDevice { 2627 t.Errorf("device id did not change: %s", newDevice) 2628 } 2629 2630 testUserHasDeviceKey(tcp) 2631} 2632 2633// After account reset, establish new eldest keys, paper key. 2634// Provision another device with paper key. 2635func TestResetAccountPaper(t *testing.T) { 2636 tc := SetupEngineTest(t, "login") 2637 defer tc.Cleanup() 2638 2639 u := CreateAndSignupFakeUser(tc, "login") 2640 ResetAccount(tc, u) 2641 2642 // login, creating new eldest key, new paper keys 2643 loginUI := &paperLoginUI{Username: u.Username} 2644 uis := libkb.UIs{ 2645 ProvisionUI: newTestProvisionUI(), 2646 LogUI: tc.G.UI.GetLogUI(), 2647 GPGUI: &gpgtestui{}, 2648 SecretUI: u.NewSecretUI(), 2649 LoginUI: loginUI, 2650 } 2651 li := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, u.Username, keybase1.ClientType_CLI) 2652 m := NewMetaContextForTest(tc).WithUIs(uis) 2653 if err := RunEngine2(m, li); err != nil { 2654 t.Fatal(err) 2655 } 2656 paper := loginUI.PaperPhrase 2657 if len(paper) != 0 { 2658 t.Fatal("paper phrase exists in login ui") 2659 } 2660 testUserHasDeviceKey(tc) 2661 2662 uis = libkb.UIs{ 2663 LogUI: tc.G.UI.GetLogUI(), 2664 LoginUI: &libkb.TestLoginUI{}, 2665 SecretUI: &libkb.TestSecretUI{}, 2666 } 2667 peng := NewPaperKey(tc.G) 2668 m = NewMetaContextForTest(tc).WithUIs(uis) 2669 if err := RunEngine2(m, peng); err != nil { 2670 t.Fatal(err) 2671 } 2672 if len(peng.Passphrase()) == 0 { 2673 t.Fatal("empty paper phrase") 2674 } 2675 paper = peng.Passphrase() 2676 2677 // provision on new device with paper key 2678 tcp := SetupEngineTest(t, "login") 2679 defer tcp.Cleanup() 2680 2681 secUI := u.NewSecretUI() 2682 secUI.Passphrase = paper 2683 provUI := newTestProvisionUIPaper() 2684 provLoginUI := &libkb.TestLoginUI{Username: u.Username} 2685 uis = libkb.UIs{ 2686 ProvisionUI: provUI, 2687 LogUI: tcp.G.UI.GetLogUI(), 2688 SecretUI: secUI, 2689 LoginUI: provLoginUI, 2690 GPGUI: &gpgtestui{}, 2691 } 2692 eng := NewLogin(tcp.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2693 m = NewMetaContextForTest(tcp).WithUIs(uis) 2694 if err := RunEngine2(m, eng); err != nil { 2695 t.Fatal(err) 2696 } 2697 2698 testUserHasDeviceKey(tcp) 2699} 2700 2701// After resetting account, try kex2 provisioning. 2702func TestResetAccountKexProvision(t *testing.T) { 2703 tc := SetupEngineTest(t, "login") 2704 defer tc.Cleanup() 2705 2706 u := CreateAndSignupFakeUser(tc, "login") 2707 2708 ResetAccount(tc, u) 2709 2710 // create provisioner device 2711 tcX := SetupEngineTest(t, "login") 2712 defer tcX.Cleanup() 2713 // this will reprovision as an eldest device: 2714 u.LoginOrBust(tcX) 2715 if err := AssertProvisioned(tcX); err != nil { 2716 t.Fatal(err) 2717 } 2718 testUserHasDeviceKey(tcX) 2719 var secretX kex2.Secret 2720 if _, err := rand.Read(secretX[:]); err != nil { 2721 t.Fatal(err) 2722 } 2723 secretCh := make(chan kex2.Secret) 2724 2725 // provisionee context: 2726 tcY := SetupEngineTest(t, "template") 2727 defer tcY.Cleanup() 2728 2729 // provisionee calls login: 2730 uis := libkb.UIs{ 2731 ProvisionUI: newTestProvisionUISecretCh(secretCh), 2732 LoginUI: &libkb.TestLoginUI{Username: u.Username}, 2733 LogUI: tcY.G.UI.GetLogUI(), 2734 SecretUI: &libkb.TestSecretUI{}, 2735 GPGUI: &gpgtestui{}, 2736 } 2737 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2738 2739 var wg sync.WaitGroup 2740 2741 // start provisionee 2742 wg.Add(1) 2743 go func() { 2744 defer wg.Done() 2745 m := NewMetaContextForTest(tcY).WithUIs(uis) 2746 if err := RunEngine2(m, eng); err != nil { 2747 t.Errorf("login error: %s", err) 2748 return 2749 } 2750 }() 2751 2752 // start provisioner 2753 provisioner := NewKex2Provisioner(tcX.G, secretX, nil) 2754 wg.Add(1) 2755 go func() { 2756 defer wg.Done() 2757 2758 uis := libkb.UIs{ 2759 SecretUI: u.NewSecretUI(), 2760 ProvisionUI: newTestProvisionUI(), 2761 } 2762 m := NewMetaContextForTest(tcX).WithUIs(uis) 2763 if err := RunEngine2(m, provisioner); err != nil { 2764 t.Errorf("provisioner error: %s", err) 2765 return 2766 } 2767 }() 2768 secretFromY := <-secretCh 2769 provisioner.AddSecret(secretFromY) 2770 2771 wg.Wait() 2772 2773 err := AssertProvisioned(tcY) 2774 require.NoError(t, err) 2775 testTrack(t, tcY, libkb.KeybaseNullSigVersion, "t_alice") 2776} 2777 2778// Try to replicate @nistur sigchain. 2779// github issue: https://github.com/keybase/client/issues/2356 2780func TestResetThenPGPOnlyThenProvision(t *testing.T) { 2781 tc0 := SetupEngineTest(t, "login") 2782 defer tc0.Cleanup() 2783 2784 // user with synced pgp key 2785 u := createFakeUserWithPGPOnly(t, tc0) 2786 Logout(tc0) 2787 2788 // provision a device with that key 2789 tc := SetupEngineTest(t, "login") 2790 defer tc.Cleanup() 2791 2792 uis := libkb.UIs{ 2793 ProvisionUI: newTestProvisionUIPassphrase(), 2794 LoginUI: &libkb.TestLoginUI{Username: u.Username}, 2795 LogUI: tc.G.UI.GetLogUI(), 2796 SecretUI: u.NewSecretUI(), 2797 GPGUI: &gpgtestui{}, 2798 } 2799 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2800 m := NewMetaContextForTest(tc).WithUIs(uis) 2801 if err := RunEngine2(m, eng); err != nil { 2802 t.Fatal(err) 2803 } 2804 2805 // since this user didn't have any device keys, login should have fixed that: 2806 testUserHasDeviceKey(tc) 2807 2808 // now reset account 2809 ResetAccount(tc, u) 2810 2811 // Now login again so we can post a PGP key 2812 m = m.WithNewProvisionalLoginContext() 2813 err := libkb.PassphraseLoginNoPrompt(m, u.Username, u.Passphrase) 2814 require.NoError(t, err, "passphrase login no prompt worked") 2815 2816 // Generate a new test PGP key for the user, and specify the PushSecret 2817 // flag so that their triplesec'ed key is pushed to the server. 2818 gen := libkb.PGPGenArg{ 2819 PrimaryBits: 768, 2820 SubkeyBits: 768, 2821 } 2822 gen.AddDefaultUID(tc.G) 2823 peng := NewPGPKeyImportEngine(tc.G, PGPKeyImportEngineArg{ 2824 Gen: &gen, 2825 PushSecret: true, 2826 NoSave: true, 2827 }) 2828 2829 if err := RunEngine2(m, peng); err != nil { 2830 tc.T.Fatal(err) 2831 } 2832 2833 m = m.CommitProvisionalLogin() 2834 Logout(tc) 2835 2836 // Now finally try a login 2837 eng = NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2838 if err := RunEngine2(m, eng); err != nil { 2839 t.Fatal(err) 2840 } 2841 2842 // since this user didn't have any device keys, login should have fixed that: 2843 testUserHasDeviceKey(tc) 2844} 2845 2846// Try to replicate @nistur sigchain. 2847// github issue: https://github.com/keybase/client/issues/2356 2848func TestResetAccountLikeNistur(t *testing.T) { 2849 tc0 := SetupEngineTest(t, "login") 2850 defer tc0.Cleanup() 2851 2852 // user with synced pgp key 2853 u := createFakeUserWithPGPOnly(t, tc0) 2854 Logout(tc0) 2855 2856 // provision a device with that key 2857 tc := SetupEngineTest(t, "login") 2858 defer tc.Cleanup() 2859 2860 uis := libkb.UIs{ 2861 ProvisionUI: newTestProvisionUIPassphrase(), 2862 LoginUI: &libkb.TestLoginUI{Username: u.Username}, 2863 LogUI: tc.G.UI.GetLogUI(), 2864 SecretUI: u.NewSecretUI(), 2865 GPGUI: &gpgtestui{}, 2866 } 2867 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2868 m := NewMetaContextForTest(tc).WithUIs(uis) 2869 if err := RunEngine2(m, eng); err != nil { 2870 t.Fatal(err) 2871 } 2872 2873 // since this user didn't have any device keys, login should have fixed that: 2874 testUserHasDeviceKey(tc) 2875 2876 // now reset account 2877 ResetAccount(tc, u) 2878 2879 // create provisioner device 2880 tcX := SetupEngineTest(t, "login") 2881 defer tcX.Cleanup() 2882 2883 // this will reprovision as an eldest device: 2884 u.LoginOrBust(tcX) 2885 if err := AssertProvisioned(tcX); err != nil { 2886 t.Fatal(err) 2887 } 2888 testUserHasDeviceKey(tcX) 2889 var secretX kex2.Secret 2890 if _, err := rand.Read(secretX[:]); err != nil { 2891 t.Fatal(err) 2892 } 2893 secretCh := make(chan kex2.Secret) 2894 2895 // provisionee context: 2896 tcY := SetupEngineTest(t, "template") 2897 defer tcY.Cleanup() 2898 2899 // provisionee calls login: 2900 uis = libkb.UIs{ 2901 ProvisionUI: newTestProvisionUISecretCh(secretCh), 2902 LoginUI: &libkb.TestLoginUI{Username: u.Username}, 2903 LogUI: tcY.G.UI.GetLogUI(), 2904 SecretUI: &libkb.TestSecretUI{}, 2905 GPGUI: &gpgtestui{}, 2906 } 2907 eng = NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2908 2909 var wg sync.WaitGroup 2910 2911 // start provisionee 2912 wg.Add(1) 2913 go func() { 2914 defer wg.Done() 2915 m := NewMetaContextForTest(tcY).WithUIs(uis) 2916 if err := RunEngine2(m, eng); err != nil { 2917 t.Errorf("login error: %s", err) 2918 return 2919 } 2920 }() 2921 2922 // start provisioner 2923 provisioner := NewKex2Provisioner(tcX.G, secretX, nil) 2924 wg.Add(1) 2925 go func() { 2926 defer wg.Done() 2927 2928 uis := libkb.UIs{ 2929 SecretUI: u.NewSecretUI(), 2930 ProvisionUI: newTestProvisionUI(), 2931 } 2932 m := NewMetaContextForTest(tcX).WithUIs(uis) 2933 if err := RunEngine2(m, provisioner); err != nil { 2934 t.Errorf("provisioner error: %s", err) 2935 return 2936 } 2937 }() 2938 secretFromY := <-secretCh 2939 provisioner.AddSecret(secretFromY) 2940 2941 wg.Wait() 2942 2943 err := AssertProvisioned(tcY) 2944 require.NoError(t, err) 2945 testTrack(t, tcY, libkb.KeybaseNullSigVersion, "t_alice") 2946} 2947 2948// Establish two devices. Reset on one of them, login on the other. 2949func TestResetMultipleDevices(t *testing.T) { 2950 tcX := SetupEngineTest(t, "login") 2951 defer tcX.Cleanup() 2952 2953 // create provisioner device 2954 u := CreateAndSignupFakeUser(tcX, "login") 2955 if err := AssertProvisioned(tcX); err != nil { 2956 t.Fatal(err) 2957 } 2958 testUserHasDeviceKey(tcX) 2959 var secretX kex2.Secret 2960 if _, err := rand.Read(secretX[:]); err != nil { 2961 t.Fatal(err) 2962 } 2963 secretCh := make(chan kex2.Secret) 2964 2965 // provisionee context: 2966 tcY := SetupEngineTest(t, "template") 2967 defer tcY.Cleanup() 2968 2969 // provisionee calls login: 2970 uis := libkb.UIs{ 2971 ProvisionUI: newTestProvisionUISecretCh(secretCh), 2972 LoginUI: &libkb.TestLoginUI{Username: u.Username}, 2973 LogUI: tcY.G.UI.GetLogUI(), 2974 SecretUI: &libkb.TestSecretUI{}, 2975 GPGUI: &gpgtestui{}, 2976 } 2977 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 2978 2979 var wg sync.WaitGroup 2980 2981 // start provisionee 2982 wg.Add(1) 2983 go func() { 2984 defer wg.Done() 2985 m := NewMetaContextForTest(tcY).WithUIs(uis) 2986 if err := RunEngine2(m, eng); err != nil { 2987 t.Errorf("login error: %s", err) 2988 return 2989 } 2990 }() 2991 2992 // start provisioner 2993 provisioner := NewKex2Provisioner(tcX.G, secretX, nil) 2994 wg.Add(1) 2995 go func() { 2996 defer wg.Done() 2997 2998 uis := libkb.UIs{ 2999 SecretUI: u.NewSecretUI(), 3000 ProvisionUI: newTestProvisionUI(), 3001 } 3002 m := NewMetaContextForTest(tcX).WithUIs(uis) 3003 if err := RunEngine2(m, provisioner); err != nil { 3004 t.Errorf("provisioner error: %s", err) 3005 return 3006 } 3007 }() 3008 secretFromY := <-secretCh 3009 provisioner.AddSecret(secretFromY) 3010 3011 wg.Wait() 3012 3013 if err := AssertProvisioned(tcY); err != nil { 3014 t.Fatal(err) 3015 } 3016 3017 // have two devices in contexts tcX and tcY 3018 deviceX := tcX.G.Env.GetDeviceID() 3019 3020 // logout on tcX 3021 Logout(tcX) 3022 3023 // reset on tcY 3024 ResetAccount(tcY, u) 3025 3026 // login on tcX 3027 u.LoginOrBust(tcX) 3028 3029 if err := AssertProvisioned(tcX); err != nil { 3030 t.Fatal(err) 3031 } 3032 3033 if tcX.G.Env.GetDeviceID() == deviceX { 3034 t.Error("device id did not change") 3035 } 3036} 3037 3038// If there is a bad device id in the config file, provisioning 3039// appears to succeed and provision the new device, but the config 3040// file retains the bad device id and further attempts to 3041// do anything fail (they say login required, and running login 3042// results in provisioning again...) 3043// Seems to only happen w/ kex2. 3044func TestProvisionWithBadConfig(t *testing.T) { 3045 // device X (provisioner) context: 3046 tcX := SetupEngineTest(t, "kex2provision") 3047 defer tcX.Cleanup() 3048 3049 // device Y (provisionee) context: 3050 tcY := SetupEngineTest(t, "template") 3051 defer tcY.Cleanup() 3052 3053 // provisioner needs to be logged in 3054 userX := CreateAndSignupFakeUserPaper(tcX, "login") 3055 var secretX kex2.Secret 3056 if _, err := rand.Read(secretX[:]); err != nil { 3057 t.Fatal(err) 3058 } 3059 3060 // copy the config info from device X to device Y 3061 uc, err := tcX.G.Env.GetConfig().GetUserConfig() 3062 if err != nil { 3063 t.Fatal(err) 3064 } 3065 if err := tcY.G.Env.GetConfigWriter().SetUserConfig(uc, true); err != nil { 3066 t.Fatal(err) 3067 } 3068 // but give device Y a new random device ID that doesn't exist: 3069 newID, err := libkb.NewDeviceID() 3070 if err != nil { 3071 t.Fatal(err) 3072 } 3073 if err := tcY.G.Env.GetConfigWriter().SetDeviceID(newID); err != nil { 3074 t.Fatal(err) 3075 } 3076 3077 secretCh := make(chan kex2.Secret) 3078 3079 // provisionee calls login: 3080 uis := libkb.UIs{ 3081 ProvisionUI: newTestProvisionUISecretCh(secretCh), 3082 LoginUI: &libkb.TestLoginUI{Username: userX.Username}, 3083 LogUI: tcY.G.UI.GetLogUI(), 3084 SecretUI: &libkb.TestSecretUI{}, 3085 GPGUI: &gpgtestui{}, 3086 } 3087 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 3088 3089 var wg sync.WaitGroup 3090 3091 // start provisionee 3092 wg.Add(1) 3093 go func() { 3094 defer wg.Done() 3095 m := NewMetaContextForTest(tcY).WithUIs(uis) 3096 if err := RunEngine2(m, eng); err != nil { 3097 t.Errorf("login error: %s", err) 3098 return 3099 } 3100 }() 3101 3102 // start provisioner 3103 provisioner := NewKex2Provisioner(tcX.G, secretX, nil) 3104 wg.Add(1) 3105 go func() { 3106 defer wg.Done() 3107 3108 uis := libkb.UIs{ 3109 SecretUI: userX.NewSecretUI(), 3110 ProvisionUI: newTestProvisionUI(), 3111 } 3112 m := NewMetaContextForTest(tcX).WithUIs(uis) 3113 if err := RunEngine2(m, provisioner); err != nil { 3114 t.Errorf("provisioner error: %s", err) 3115 return 3116 } 3117 }() 3118 secretFromY := <-secretCh 3119 provisioner.AddSecret(secretFromY) 3120 3121 wg.Wait() 3122 3123 if tcY.G.Env.GetDeviceID() == newID { 3124 t.Errorf("y device id: %s, same as %s. expected it to change.", tcY.G.Env.GetDeviceID(), newID) 3125 } 3126 if tcY.G.Env.GetDeviceID() == tcX.G.Env.GetDeviceID() { 3127 t.Error("y device id matches x device id, they should be different") 3128 } 3129 3130 err = AssertProvisioned(tcY) 3131 require.NoError(t, err) 3132 testTrack(t, tcY, libkb.KeybaseNullSigVersion, "t_alice") 3133} 3134 3135// If the provisioner has their secret stored, they should not be 3136// prompted to enter a passphrase when they provision a device. 3137func TestProvisionerSecretStore(t *testing.T) { 3138 // device X (provisioner) context: 3139 tcX := SetupEngineTest(t, "kex2provision") 3140 defer tcX.Cleanup() 3141 3142 // device Y (provisionee) context: 3143 tcY := SetupEngineTest(t, "template") 3144 defer tcY.Cleanup() 3145 3146 // create provisioner w/ stored secret 3147 userX := SignupFakeUserStoreSecret(tcX, "login") 3148 // userX := CreateAndSignupFakeUser(tcX, "login") 3149 var secretX kex2.Secret 3150 if _, err := rand.Read(secretX[:]); err != nil { 3151 t.Fatal(err) 3152 } 3153 clearCaches(tcX.G) 3154 3155 secretCh := make(chan kex2.Secret) 3156 3157 // provisionee calls login: 3158 uis := libkb.UIs{ 3159 ProvisionUI: newTestProvisionUISecretCh(secretCh), 3160 LoginUI: &libkb.TestLoginUI{Username: userX.Username}, 3161 LogUI: tcY.G.UI.GetLogUI(), 3162 SecretUI: &libkb.TestSecretUI{}, 3163 GPGUI: &gpgtestui{}, 3164 } 3165 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 3166 m := NewMetaContextForTest(tcY).WithUIs(uis) 3167 3168 // start provisionee 3169 errY := make(chan error, 1) 3170 go func() { 3171 errY <- RunEngine2(m, eng) 3172 }() 3173 3174 // start provisioner 3175 provisioner := NewKex2Provisioner(tcX.G, secretX, nil) 3176 errX := make(chan error, 1) 3177 go func() { 3178 uis := libkb.UIs{ 3179 SecretUI: &testNoPromptSecretUI{}, 3180 ProvisionUI: newTestProvisionUI(), 3181 } 3182 m := NewMetaContextForTest(tcX).WithUIs(uis) 3183 errX <- RunEngine2(m, provisioner) 3184 }() 3185 secretFromY := <-secretCh 3186 go provisioner.AddSecret(secretFromY) 3187 3188 var xDone, yDone bool 3189 for { 3190 select { 3191 case e := <-errY: 3192 if e != nil { 3193 t.Fatalf("provisionee error: %s", e) 3194 } 3195 yDone = true 3196 case e := <-errX: 3197 if e != nil { 3198 t.Fatalf("provisioner error: %s", e) 3199 } 3200 xDone = true 3201 } 3202 if xDone && yDone { 3203 break 3204 } 3205 } 3206 3207 if err := AssertProvisioned(tcY); err != nil { 3208 t.Fatal(err) 3209 } 3210 3211 // On device Y, logout and login. This should tickle Bug3964 3212 Logout(tcY) 3213 uis = libkb.UIs{ 3214 ProvisionUI: newTestProvisionUIPassphrase(), 3215 LoginUI: &libkb.TestLoginUI{}, 3216 LogUI: tcY.G.UI.GetLogUI(), 3217 SecretUI: userX.NewSecretUI(), 3218 GPGUI: &gpgtestui{}, 3219 } 3220 eng = NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, userX.Username, keybase1.ClientType_CLI) 3221 m = NewMetaContextForTest(tcY).WithUIs(uis) 3222 if err := RunEngine2(m, eng); err != nil { 3223 t.Fatal(err) 3224 } 3225} 3226 3227// GPG key required for provisioning, but user on a mobile device. 3228func TestProvisionGPGMobile(t *testing.T) { 3229 tc := SetupEngineTest(t, "login") 3230 defer tc.Cleanup() 3231 3232 u1 := createFakeUserWithPGPPubOnly(t, tc) 3233 Logout(tc) 3234 3235 // redo SetupEngineTest to get a new home directory...should look like a new device. 3236 tc2 := SetupEngineTest(t, "login") 3237 defer tc2.Cleanup() 3238 3239 // we need the gpg keyring that's in the first homedir 3240 if err := tc.MoveGpgKeyringTo(tc2); err != nil { 3241 t.Fatal(err) 3242 } 3243 3244 // run login on new device 3245 uis := libkb.UIs{ 3246 ProvisionUI: newTestProvisionUIGPGImport(), 3247 LogUI: tc2.G.UI.GetLogUI(), 3248 SecretUI: u1.NewSecretUI(), 3249 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 3250 GPGUI: &gpgtestui{}, 3251 } 3252 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_MOBILE, "", keybase1.ClientType_CLI) 3253 m := NewMetaContextForTest(tc2).WithUIs(uis) 3254 err := RunEngine2(m, eng) 3255 if err == nil { 3256 t.Fatal("no error provisioning with gpg on mobile") 3257 } 3258 if _, ok := err.(libkb.GPGUnavailableError); !ok { 3259 t.Errorf("error type: %T, expected libkb.GPGUnavailableError", err) 3260 } 3261} 3262 3263func TestProvisionEnsureNoPaperKey(t *testing.T) { 3264 testProvisionEnsureNoPaperKey(t, false) 3265} 3266 3267func TestProvisionEnsureNoPaperKeyPUK(t *testing.T) { 3268 testProvisionEnsureNoPaperKey(t, true) 3269} 3270 3271// Provisioning a new device when the user has no paper keys should work 3272// and not generate a paper key. 3273func testProvisionEnsureNoPaperKey(t *testing.T, upgradePerUserKey bool) { 3274 // This test is based on TestProvisionDesktop. 3275 3276 t.Logf("create 2 contexts") 3277 3278 // device X (provisioner) context: 3279 tcX := SetupEngineTest(t, "kex2provision") 3280 defer tcX.Cleanup() 3281 tcX.Tp.DisableUpgradePerUserKey = !upgradePerUserKey 3282 3283 // device Y (provisionee) context: 3284 tcY := SetupEngineTest(t, "template") 3285 defer tcY.Cleanup() 3286 tcY.Tp.DisableUpgradePerUserKey = !upgradePerUserKey 3287 3288 // provisioner needs to be logged in 3289 userX := CreateAndSignupFakeUserPaper(tcX, "login") 3290 var secretX kex2.Secret 3291 if _, err := rand.Read(secretX[:]); err != nil { 3292 t.Fatal(err) 3293 } 3294 3295 t.Logf("check for initial paper key") 3296 originalPaperKey := hasOnePaperDev(tcY, userX) 3297 3298 t.Logf("revoke paper keys from X") 3299 { 3300 uis := libkb.UIs{ 3301 LoginUI: &libkb.TestLoginUI{Username: userX.Username}, 3302 LogUI: tcX.G.UI.GetLogUI(), 3303 SecretUI: &libkb.TestSecretUI{}, 3304 } 3305 eng := NewRevokeDeviceEngine(tcX.G, RevokeDeviceEngineArgs{ 3306 ID: originalPaperKey, 3307 ForceSelf: false, 3308 }) 3309 m := libkb.NewMetaContextTODO(tcX.G).WithUIs(uis) 3310 err := RunEngine2(m, eng) 3311 require.NoError(t, err, "revoke original paper key") 3312 } 3313 3314 t.Logf("check for no paper key") 3315 hasZeroPaperDev(tcX, userX) 3316 3317 t.Logf("do kex provision") 3318 3319 secretCh := make(chan kex2.Secret) 3320 3321 // provisionee calls login: 3322 uis := libkb.UIs{ 3323 ProvisionUI: newTestProvisionUISecretCh(secretCh), 3324 LoginUI: &libkb.TestLoginUI{Username: userX.Username}, 3325 LogUI: tcY.G.UI.GetLogUI(), 3326 SecretUI: &libkb.TestSecretUI{}, 3327 GPGUI: &gpgtestui{}, 3328 } 3329 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 3330 3331 var wg sync.WaitGroup 3332 3333 // start provisionee 3334 wg.Add(1) 3335 go func() { 3336 defer wg.Done() 3337 m := NewMetaContextForTest(tcY).WithUIs(uis) 3338 if err := RunEngine2(m, eng); err != nil { 3339 t.Errorf("provisionee login error: %s", err) 3340 return 3341 } 3342 }() 3343 3344 // start provisioner 3345 provisioner := NewKex2Provisioner(tcX.G, secretX, nil) 3346 wg.Add(1) 3347 go func() { 3348 defer wg.Done() 3349 3350 uis := libkb.UIs{ 3351 SecretUI: userX.NewSecretUI(), 3352 ProvisionUI: newTestProvisionUI(), 3353 } 3354 m := NewMetaContextForTest(tcX).WithUIs(uis) 3355 if err := RunEngine2(m, provisioner); err != nil { 3356 t.Errorf("provisioner error: %s", err) 3357 return 3358 } 3359 }() 3360 secretFromY := <-secretCh 3361 provisioner.AddSecret(secretFromY) 3362 3363 wg.Wait() 3364 3365 require.False(t, t.Failed(), "prior failure in a goroutine") 3366 3367 if err := AssertProvisioned(tcY); err != nil { 3368 t.Fatal(err) 3369 } 3370 3371 t.Logf("kex finished") 3372 3373 // after provisioning, the passphrase stream should be cached 3374 // (note that this just checks the passphrase stream, not 3sec) 3375 assertPassphraseStreamCache(tcY) 3376 3377 // after provisioning, the device keys should be cached 3378 assertDeviceKeysCached(tcY) 3379 3380 // Make sure that we can still track without a passphrase 3381 // after a simulated service restart. In other words, that 3382 // the full LKSec secret was written to the secret store. 3383 simulateServiceRestart(t, tcY, userX) 3384 testTrack(t, tcY, libkb.KeybaseNullSigVersion, "t_bob") 3385 3386 t.Logf("check for no paper key") 3387 hasZeroPaperDev(tcY, userX) 3388 hasZeroPaperDev(tcX, userX) 3389} 3390 3391// Device X provisions device Y, then device Y revokes X. 3392func TestProvisionAndRevoke(t *testing.T) { 3393 // This test is based on TestProvisionDesktop. 3394 3395 t.Logf("create 2 contexts") 3396 3397 // device X (provisioner) context: 3398 tcX := SetupEngineTest(t, "kex2provision") 3399 defer tcX.Cleanup() 3400 3401 // device Y (provisionee) context: 3402 tcY := SetupEngineTest(t, "template") 3403 defer tcY.Cleanup() 3404 3405 // provisioner needs to be logged in 3406 userX := CreateAndSignupFakeUserPaper(tcX, "login") 3407 var secretX kex2.Secret 3408 if _, err := rand.Read(secretX[:]); err != nil { 3409 t.Fatal(err) 3410 } 3411 3412 t.Logf("check for initial paper key") 3413 _ = hasOnePaperDev(tcY, userX) 3414 3415 t.Logf("do kex provision") 3416 3417 secretCh := make(chan kex2.Secret) 3418 3419 // provisionee calls login: 3420 uis := libkb.UIs{ 3421 ProvisionUI: newTestProvisionUISecretCh(secretCh), 3422 LoginUI: &libkb.TestLoginUI{Username: userX.Username}, 3423 LogUI: tcY.G.UI.GetLogUI(), 3424 SecretUI: &libkb.TestSecretUI{}, 3425 GPGUI: &gpgtestui{}, 3426 } 3427 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 3428 3429 var wg sync.WaitGroup 3430 3431 // start provisionee 3432 wg.Add(1) 3433 go func() { 3434 defer wg.Done() 3435 m := NewMetaContextForTest(tcY).WithUIs(uis) 3436 if err := RunEngine2(m, eng); err != nil { 3437 t.Errorf("provisionee login error: %s", err) 3438 return 3439 } 3440 }() 3441 3442 // start provisioner 3443 provisioner := NewKex2Provisioner(tcX.G, secretX, nil) 3444 wg.Add(1) 3445 go func() { 3446 defer wg.Done() 3447 3448 uis := libkb.UIs{ 3449 SecretUI: userX.NewSecretUI(), 3450 ProvisionUI: newTestProvisionUI(), 3451 } 3452 m := NewMetaContextForTest(tcX).WithUIs(uis) 3453 if err := RunEngine2(m, provisioner); err != nil { 3454 t.Errorf("provisioner error: %s", err) 3455 return 3456 } 3457 }() 3458 secretFromY := <-secretCh 3459 provisioner.AddSecret(secretFromY) 3460 3461 wg.Wait() 3462 3463 require.False(t, t.Failed(), "prior failure in a goroutine") 3464 3465 if err := AssertProvisioned(tcY); err != nil { 3466 t.Fatal(err) 3467 } 3468 3469 t.Logf("kex finished") 3470 3471 // after provisioning, the passphrase stream should be cached 3472 // (note that this just checks the passphrase stream, not 3sec) 3473 assertPassphraseStreamCache(tcY) 3474 3475 // after provisioning, the device keys should be cached 3476 assertDeviceKeysCached(tcY) 3477 3478 t.Logf("revoke device X from Y") 3479 3480 // require.NoError(t, doRevokeDevice(tcY, userX, tcX.G.ActiveDevice.DeviceID(), false)) 3481 { 3482 uis := libkb.UIs{ 3483 LoginUI: &libkb.TestLoginUI{Username: userX.Username}, 3484 LogUI: tcY.G.UI.GetLogUI(), 3485 SecretUI: &libkb.TestSecretUI{}, 3486 } 3487 eng := NewRevokeDeviceEngine(tcY.G, RevokeDeviceEngineArgs{ 3488 ID: tcX.G.ActiveDevice.DeviceID(), 3489 ForceSelf: false, 3490 }) 3491 m := libkb.NewMetaContextTODO(tcY.G).WithUIs(uis) 3492 err := RunEngine2(m, eng) 3493 require.NoError(t, err, "revoke original paper key") 3494 } 3495 3496 t.Logf("revoke finished") 3497 3498 // Make sure that we can still track without a passphrase 3499 // after a simulated service restart. In other words, that 3500 // the full LKSec secret was written to the secret store. 3501 simulateServiceRestart(t, tcY, userX) 3502 testTrack(t, tcY, libkb.KeybaseNullSigVersion, "t_bob") 3503 3504 t.Logf("check for paper key") 3505 hasOnePaperDev(tcY, userX) 3506 hasOnePaperDev(tcX, userX) 3507} 3508 3509// Test bootstrap, login offline after service restart when provisioned via 3510// GPG sign. 3511func TestBootstrapAfterGPGSign(t *testing.T) { 3512 // use tcCheck just to check gpg version 3513 tcCheck := SetupEngineTest(t, "check") 3514 defer tcCheck.Cleanup() 3515 skipOldGPG(tcCheck) 3516 3517 // this test sometimes fails at the GPG level with a "Bad signature" error, 3518 // so we're going to retry it several times to hopefully get past it. 3519 attempts := 10 3520 for i := 0; i < attempts; i++ { 3521 tc := SetupEngineTest(t, "login") 3522 defer tc.Cleanup() 3523 3524 u1 := createFakeUserWithPGPPubOnly(t, tc) 3525 Logout(tc) 3526 3527 // redo SetupEngineTest to get a new home directory...should look like a new device. 3528 tc2 := SetupEngineTest(t, "login") 3529 defer tc2.Cleanup() 3530 3531 // we need the gpg keyring that's in the first homedir 3532 if err := tc.MoveGpgKeyringTo(tc2); err != nil { 3533 t.Fatal(err) 3534 } 3535 3536 // run login on new device 3537 uis := libkb.UIs{ 3538 ProvisionUI: newTestProvisionUIGPGSign(), 3539 LogUI: tc2.G.UI.GetLogUI(), 3540 SecretUI: u1.NewSecretUI(), 3541 LoginUI: &libkb.TestLoginUI{Username: u1.Username}, 3542 GPGUI: &gpgtestui{Contextified: libkb.NewContextified(tc2.G)}, 3543 } 3544 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 3545 m := NewMetaContextForTest(tc2).WithUIs(uis) 3546 if err := RunEngine2(m, eng); err != nil { 3547 t.Logf("test run %d: RunEngine(Login) error: %s", i+1, err) 3548 continue 3549 } 3550 3551 t.Logf("test run %d: RunEngine(Login) succeeded", i+1) 3552 3553 testUserHasDeviceKey(tc2) 3554 3555 // highly possible they didn't have a paper key, so make sure they still don't have one: 3556 hasZeroPaperDev(tc2, u1) 3557 3558 if err := AssertProvisioned(tc2); err != nil { 3559 t.Fatal(err) 3560 } 3561 3562 // do a upak load to make sure it is cached 3563 arg := libkb.NewLoadUserByUIDArg(context.TODO(), tc2.G, u1.UID()) 3564 _, _, err := tc2.G.GetUPAKLoader().Load(arg) 3565 require.NoError(t, err) 3566 3567 // Simulate restarting the service by wiping out the 3568 // passphrase stream cache and cached secret keys 3569 tc2.SimulateServiceRestart() 3570 tc2.G.GetUPAKLoader().ClearMemory() 3571 3572 // LoginOffline will run when service restarts. 3573 // Since this was GPG sign, there will be no secret stored. 3574 oeng := NewLoginOffline(tc2.G) 3575 oerr := RunEngine2(m, oeng) 3576 if oerr != nil { 3577 t.Fatalf("LoginOffline failed after gpg sign + svc restart: %s", oerr) 3578 } 3579 3580 // GetBootstrapStatus should return without error and with LoggedIn set 3581 // to true. 3582 beng := NewBootstrap(tc2.G) 3583 m = NewMetaContextForTest(tc2) 3584 if err := RunEngine2(m, beng); err != nil { 3585 t.Fatal(err) 3586 } 3587 status := beng.Status() 3588 if status.LoggedIn != true { 3589 t.Error("bootstrap status -> logged out, expected logged in") 3590 } 3591 if !status.Registered { 3592 t.Error("registered false") 3593 } 3594 3595 t.Logf("test run %d: all checks passed, returning", i+1) 3596 return 3597 } 3598 3599 t.Fatalf("TestBootstrapAfterGPGSign failed %d times", attempts) 3600} 3601 3602func TestLoginAlready(t *testing.T) { 3603 tc := SetupEngineTest(t, "login") 3604 defer tc.Cleanup() 3605 3606 u1 := CreateAndSignupFakeUser(tc, "login") 3607 Logout(tc) 3608 u1.LoginOrBust(tc) 3609 3610 // Logging in again with same username should not return an error 3611 if err := u1.Login(tc.G); err != nil { 3612 t.Fatal(err) 3613 } 3614 3615 // Logging in with a different username should returh LoggedInError 3616 u1.Username = "x" + u1.Username 3617 err := u1.Login(tc.G) 3618 if err == nil { 3619 t.Fatal("login with different username should return an error") 3620 } 3621 if _, ok := err.(libkb.LoggedInError); !ok { 3622 t.Fatalf("err type: %T (%s), expected libkb.LoggedInError", err, err) 3623 } 3624} 3625 3626func TestLoginUsernameOnProvisionedDevice(t *testing.T) { 3627 tc := SetupEngineTest(t, "login") 3628 defer tc.Cleanup() 3629 3630 u1 := CreateAndSignupFakeUser(tc, "login") 3631 Logout(tc) 3632 3633 secui := u1.NewCountSecretUI() 3634 uis := libkb.UIs{ 3635 ProvisionUI: newTestProvisionUIPassphrase(), 3636 LoginUI: &libkb.TestLoginUI{}, 3637 LogUI: tc.G.UI.GetLogUI(), 3638 SecretUI: secui, 3639 GPGUI: &gpgtestui{}, 3640 } 3641 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, u1.Username, keybase1.ClientType_CLI) 3642 m := NewMetaContextForTest(tc).WithUIs(uis) 3643 if err := RunEngine2(m, eng); err != nil { 3644 t.Fatalf("login with email should work now, got error: %s (%T)", err, err) 3645 } 3646 3647 assertPassphraseStreamCache(tc) 3648 assertDeviceKeysCached(tc) 3649 assertSecretStored(tc, u1.Username) 3650 3651 require.Equal(t, 1, secui.CallCount, "expecting a passphrase prompt when logging in with username") 3652} 3653 3654func TestLoginEmailOnProvisionedDevice(t *testing.T) { 3655 tc := SetupEngineTest(t, "login") 3656 defer tc.Cleanup() 3657 3658 u1 := CreateAndSignupFakeUser(tc, "login") 3659 Logout(tc) 3660 3661 secui := u1.NewCountSecretUI() 3662 uis := libkb.UIs{ 3663 ProvisionUI: newTestProvisionUIPassphrase(), 3664 LoginUI: &libkb.TestLoginUI{}, 3665 LogUI: tc.G.UI.GetLogUI(), 3666 SecretUI: secui, 3667 GPGUI: &gpgtestui{}, 3668 } 3669 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, u1.Email, keybase1.ClientType_CLI) 3670 m := NewMetaContextForTest(tc).WithUIs(uis) 3671 err := RunEngine2(m, eng) 3672 require.Error(t, err) 3673 require.IsType(t, libkb.BadUsernameError{}, err) 3674 require.Contains(t, err.Error(), "not supported") 3675} 3676func TestBeforeResetDeviceName(t *testing.T) { 3677 tc := SetupEngineTest(t, "login") 3678 defer tc.Cleanup() 3679 3680 u := CreateAndSignupFakeUser(tc, "login") 3681 originalDeviceName := u.DeviceName 3682 t.Logf("original device name: %s", originalDeviceName) 3683 ResetAccount(tc, u) 3684 3685 provui := &testProvisionSetNameUI{ 3686 testProvisionUI: newTestProvisionUI(), 3687 DeviceName: originalDeviceName, 3688 } 3689 uis := libkb.UIs{ 3690 ProvisionUI: provui, 3691 LoginUI: &libkb.TestLoginUI{Username: u.Username}, 3692 LogUI: tc.G.UI.GetLogUI(), 3693 SecretUI: u.NewSecretUI(), 3694 GPGUI: &gpgtestui{}, 3695 } 3696 eng := NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 3697 m := NewMetaContextForTest(tc).WithUIs(uis) 3698 err := RunEngine2(m, eng) 3699 if err == nil { 3700 t.Errorf("Login worked with pre-reset device name") 3701 } 3702 if len(provui.ExistingDevicesFromArg) == 0 { 3703 t.Fatalf("no existing devices provided to provision ui, expected 1 (pre reset)") 3704 } 3705 if provui.ExistingDevicesFromArg[0] != originalDeviceName { 3706 t.Errorf("existing device name 0: %q, expected %q", provui.ExistingDevicesFromArg[0], originalDeviceName) 3707 } 3708} 3709 3710func TestProvisioningWithSmartPunctuationDeviceName(t *testing.T) { 3711 tc := SetupEngineTest(t, "login") 3712 defer tc.Cleanup() 3713 3714 fu := NewFakeUserOrBust(tc.T, "login") 3715 tc.G.Log.Debug("New test user: %s / %s", fu.Username, fu.Email) 3716 3717 arg := MakeTestSignupEngineRunArg(fu) 3718 desiredName := arg.DeviceName + "'s test's cool-thing-device" 3719 arg.DeviceName += "’s test‘s cool—thing–device" 3720 SignupFakeUserWithArg(tc, fu, arg) 3721 fu.LoginOrBust(tc) 3722 if err := fu.LoadUser(tc); err != nil { 3723 t.Errorf("unable to load user: %q", err) 3724 } 3725 deviceNames, err := fu.User.DeviceNames() 3726 if err != nil { 3727 t.Errorf("unable to list device names: %q", err) 3728 } 3729 if len(deviceNames) < 1 { 3730 t.Error("no devices returned") 3731 } 3732 if deviceNames[0] != desiredName { 3733 t.Errorf("device name 0: %q, should be %q", deviceNames[0], desiredName) 3734 } 3735} 3736 3737func TestProvisionAutomatedPaperKey(t *testing.T) { 3738 tc := SetupEngineTest(t, "login") 3739 defer tc.Cleanup() 3740 3741 fu := NewFakeUserOrBust(t, "paper") 3742 arg := MakeTestSignupEngineRunArg(fu) 3743 arg.SkipPaper = false 3744 loginUI := &paperLoginUI{Username: fu.Username} 3745 uis := libkb.UIs{ 3746 LogUI: tc.G.UI.GetLogUI(), 3747 GPGUI: &gpgtestui{}, 3748 SecretUI: fu.NewSecretUI(), 3749 LoginUI: loginUI, 3750 } 3751 s := NewSignupEngine(tc.G, &arg) 3752 err := RunEngine2(NewMetaContextForTest(tc).WithUIs(uis), s) 3753 if err != nil { 3754 tc.T.Fatal(err) 3755 } 3756 3757 assertNumDevicesAndKeys(tc, fu, 2, 4) 3758 3759 Logout(tc) 3760 3761 if len(loginUI.PaperPhrase) == 0 { 3762 t.Fatal("login ui has no paper key phrase") 3763 } 3764 3765 // redo SetupEngineTest to get a new home directory 3766 tc2 := SetupEngineTest(t, "login") 3767 defer tc2.Cleanup() 3768 3769 provUI := newTestProvisionUIPaper() 3770 provLoginUI := &libkb.TestLoginUI{} 3771 uis2 := libkb.UIs{ 3772 ProvisionUI: provUI, 3773 LogUI: tc2.G.UI.GetLogUI(), 3774 SecretUI: fu.NewSecretUI(), 3775 LoginUI: provLoginUI, 3776 GPGUI: &gpgtestui{}, 3777 } 3778 eng := NewLogin(tc2.G, keybase1.DeviceTypeV2_DESKTOP, fu.Username, keybase1.ClientType_CLI) 3779 eng.PaperKey = loginUI.PaperPhrase 3780 eng.DeviceName = "a different device name" 3781 m2 := NewMetaContextForTest(tc2).WithUIs(uis2) 3782 require.NoError(t, RunEngine2(m2, eng), "run login engine") 3783 3784 assertNumDevicesAndKeys(tc, fu, 3, 6) 3785 require.NoError(t, AssertProvisioned(tc2), "provisioned") 3786 3787 require.Equal(t, provLoginUI.CalledGetEmailOrUsername, 0, "expected no calls to GetEmailOrUsername") 3788 require.Equal(t, provUI.calledChooseDevice, 0, "expected no calls to ChooseDevice") 3789} 3790 3791// Device X provisions device Y (which has a cached passphrase stream), device X changes the password, 3792// device Y provisions device Z (which could break because of the outdated passphrase stream) 3793func TestProvisionAfterPasswordChange(t *testing.T) { 3794 t.Logf("create 3 contexts") 3795 3796 // device X (initial provisioner and passphrase changer) context: 3797 tcX := SetupEngineTest(t, "kex2race1") 3798 defer tcX.Cleanup() 3799 3800 // device Y (second provisioner and race condition culprit) context: 3801 tcY := SetupEngineTest(t, "kex2race2") 3802 defer tcY.Cleanup() 3803 3804 // device Z (provisionee) context: 3805 tcZ := SetupEngineTest(t, "kex2race3") 3806 defer tcZ.Cleanup() 3807 3808 // the initial needs to sign up and log in 3809 userX := CreateAndSignupFakeUserPaper(tcX, "login") 3810 var secretX kex2.Secret 3811 if _, err := rand.Read(secretX[:]); err != nil { 3812 t.Fatal(err) 3813 } 3814 3815 t.Logf("kex#1 starting") 3816 3817 secretCh := make(chan kex2.Secret) 3818 3819 // provisionee calls login: 3820 uis := libkb.UIs{ 3821 ProvisionUI: newTestProvisionUISecretCh(secretCh), 3822 LoginUI: &libkb.TestLoginUI{Username: userX.Username}, 3823 LogUI: tcX.G.UI.GetLogUI(), 3824 SecretUI: &libkb.TestSecretUI{}, 3825 GPGUI: &gpgtestui{}, 3826 } 3827 3828 var wg sync.WaitGroup 3829 3830 // start provisionee for step #1 3831 wg.Add(1) 3832 go func() { 3833 defer wg.Done() 3834 m := NewMetaContextForTest(tcY).WithUIs(uis) 3835 eng := NewLogin(tcY.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 3836 if err := RunEngine2(m, eng); err != nil { 3837 t.Errorf("provisionee login error: %s", err) 3838 return 3839 } 3840 }() 3841 3842 // start provisioner for step #1 3843 provisioner := NewKex2Provisioner(tcX.G, secretX, nil) 3844 wg.Add(1) 3845 go func() { 3846 defer wg.Done() 3847 3848 // We're reusing the m from the PGP key generation 3849 m := NewMetaContextForTest(tcX).WithUIs(uis) 3850 if err := RunEngine2(m, provisioner); err != nil { 3851 t.Errorf("provisioner error: %s", err) 3852 return 3853 } 3854 }() 3855 secretFromY := <-secretCh 3856 provisioner.AddSecret(secretFromY) 3857 3858 wg.Wait() 3859 3860 require.False(t, t.Failed(), "prior failure in a goroutine") 3861 3862 // 2nd device should be provisioned 3863 if err := AssertProvisioned(tcY); err != nil { 3864 t.Fatal(err) 3865 } 3866 3867 t.Logf("kex#1 finished") 3868 3869 // after provisioning, the passphrase stream in device Y should be cached 3870 assertPassphraseStreamCache(tcY) 3871 assertDeviceKeysCached(tcY) 3872 3873 // now we have the following: 3874 // 1) the initial provisioner 3875 // 2) an already provisioned device with a cached passphrase stream 3876 // 3) a totally clean device 3877 // in order to trigger the race we have to make the cached ppstream in (2) outdated 3878 3879 // Change the password on device 1 to modify ppgen 3880 newPassphrase := "password1234" 3881 require.NoError(t, RunEngine2( 3882 NewMetaContextForTest(tcX).WithUIs(libkb.UIs{ 3883 SecretUI: &libkb.TestSecretUI{}, 3884 }), 3885 NewPassphraseChange(tcX.G, &keybase1.PassphraseChangeArg{ 3886 OldPassphrase: userX.Passphrase, 3887 Passphrase: newPassphrase, 3888 }), 3889 )) 3890 3891 // Now provision Z from Y 3892 t.Logf("kex#2 starting") 3893 3894 // start provisionee for step #2 3895 wg.Add(1) 3896 go func() { 3897 defer wg.Done() 3898 m := NewMetaContextForTest(tcZ).WithUIs(uis) 3899 eng := NewLogin(tcZ.G, keybase1.DeviceTypeV2_DESKTOP, "", keybase1.ClientType_CLI) 3900 if err := RunEngine2(m, eng); err != nil { 3901 t.Errorf("provisionee login error: %s", err) 3902 return 3903 } 3904 }() 3905 3906 // start provisioner for step #2 3907 var secretY kex2.Secret 3908 if _, err := rand.Read(secretY[:]); err != nil { 3909 t.Fatal(err) 3910 } 3911 provisioner = NewKex2Provisioner(tcY.G, secretY, nil) 3912 wg.Add(1) 3913 go func() { 3914 defer wg.Done() 3915 3916 // We're reusing the m from the PGP key generation 3917 m := NewMetaContextForTest(tcY).WithUIs(uis) 3918 // m.ActiveDevice().ClearPassphraseStreamCache() 3919 if err := RunEngine2(m, provisioner); err != nil { 3920 t.Errorf("provisioner error: %s", err) 3921 return 3922 } 3923 }() 3924 secretFromZ := <-secretCh 3925 provisioner.AddSecret(secretFromZ) 3926 3927 wg.Wait() 3928 3929 require.False(t, t.Failed(), "prior failure in a goroutine") 3930 3931 // 3rd device should be provisioned 3932 if err := AssertProvisioned(tcZ); err != nil { 3933 t.Fatal(err) 3934 } 3935 3936 t.Logf("kex#2 finished") 3937} 3938 3939type testProvisionUI struct { 3940 secretCh chan kex2.Secret 3941 method keybase1.ProvisionMethod 3942 gpgMethod keybase1.GPGMethod 3943 chooseDevice keybase1.DeviceTypeV2 3944 calledChooseDevice int 3945 verbose bool 3946 calledChooseDeviceType int 3947 abortSwitchToGPGSign bool 3948 lastDevices []keybase1.Device 3949} 3950 3951func newTestProvisionUI() *testProvisionUI { 3952 ui := &testProvisionUI{method: keybase1.ProvisionMethod_DEVICE} 3953 if len(os.Getenv("KB_TEST_VERBOSE")) > 0 { 3954 ui.verbose = true 3955 } 3956 ui.gpgMethod = keybase1.GPGMethod_GPG_IMPORT 3957 return ui 3958} 3959 3960func newTestProvisionUISecretCh(ch chan kex2.Secret) *testProvisionUI { 3961 ui := newTestProvisionUI() 3962 ui.secretCh = ch 3963 ui.chooseDevice = keybase1.DeviceTypeV2_DESKTOP 3964 return ui 3965} 3966 3967func newTestProvisionUINoSecret() *testProvisionUI { 3968 ui := newTestProvisionUI() 3969 ui.chooseDevice = keybase1.DeviceTypeV2_DESKTOP 3970 return ui 3971} 3972 3973func newTestProvisionUIPassphrase() *testProvisionUI { 3974 ui := newTestProvisionUI() 3975 ui.method = keybase1.ProvisionMethod_PASSPHRASE 3976 return ui 3977} 3978 3979func newTestProvisionUIChooseNoDevice() *testProvisionUI { 3980 ui := newTestProvisionUI() 3981 ui.chooseDevice = keybase1.DeviceTypeV2_NONE 3982 return ui 3983} 3984 3985func newTestProvisionUIPaper() *testProvisionUI { 3986 ui := newTestProvisionUI() 3987 ui.method = keybase1.ProvisionMethod_PAPER_KEY 3988 ui.chooseDevice = keybase1.DeviceTypeV2_PAPER 3989 return ui 3990} 3991 3992func newTestProvisionUIGPGImport() *testProvisionUI { 3993 ui := newTestProvisionUI() 3994 ui.method = keybase1.ProvisionMethod_GPG_IMPORT 3995 ui.gpgMethod = keybase1.GPGMethod_GPG_IMPORT 3996 return ui 3997} 3998 3999func newTestProvisionUIGPGSign() *testProvisionUI { 4000 ui := newTestProvisionUI() 4001 ui.method = keybase1.ProvisionMethod_GPG_SIGN 4002 ui.gpgMethod = keybase1.GPGMethod_GPG_SIGN 4003 return ui 4004} 4005 4006func (u *testProvisionUI) printf(format string, a ...interface{}) { 4007 if !u.verbose { 4008 return 4009 } 4010 fmt.Printf("testProvisionUI: "+format+"\n", a...) 4011} 4012 4013func (u *testProvisionUI) ChooseProvisioningMethod(_ context.Context, _ keybase1.ChooseProvisioningMethodArg) (keybase1.ProvisionMethod, error) { 4014 panic("ChooseProvisioningMethod deprecated") 4015} 4016 4017func (u *testProvisionUI) ChooseGPGMethod(_ context.Context, _ keybase1.ChooseGPGMethodArg) (keybase1.GPGMethod, error) { 4018 u.printf("ChooseGPGMethod") 4019 return u.gpgMethod, nil 4020} 4021 4022func (u *testProvisionUI) SwitchToGPGSignOK(ctx context.Context, arg keybase1.SwitchToGPGSignOKArg) (bool, error) { 4023 if u.abortSwitchToGPGSign { 4024 return false, nil 4025 } 4026 return true, nil 4027} 4028 4029func (u *testProvisionUI) ChooseDevice(_ context.Context, arg keybase1.ChooseDeviceArg) (keybase1.DeviceID, error) { 4030 u.printf("ChooseDevice") 4031 u.calledChooseDevice++ 4032 4033 u.lastDevices = arg.Devices 4034 4035 if len(arg.Devices) == 0 { 4036 return "", nil 4037 } 4038 4039 if u.chooseDevice == keybase1.DeviceTypeV2_NONE { 4040 return "", nil 4041 } 4042 4043 for _, d := range arg.Devices { 4044 if d.Type == u.chooseDevice { 4045 return d.DeviceID, nil 4046 } 4047 } 4048 return "", nil 4049} 4050 4051func (u *testProvisionUI) ChooseDeviceType(_ context.Context, _ keybase1.ChooseDeviceTypeArg) (keybase1.DeviceType, error) { 4052 u.printf("ChooseDeviceType") 4053 u.calledChooseDeviceType++ 4054 return keybase1.DeviceType_DESKTOP, nil 4055} 4056 4057func (u *testProvisionUI) DisplayAndPromptSecret(_ context.Context, arg keybase1.DisplayAndPromptSecretArg) (keybase1.SecretResponse, error) { 4058 u.printf("DisplayAndPromptSecret") 4059 var ks kex2.Secret 4060 copy(ks[:], arg.Secret) 4061 u.secretCh <- ks 4062 var sr keybase1.SecretResponse 4063 return sr, nil 4064} 4065 4066func (u *testProvisionUI) PromptNewDeviceName(_ context.Context, arg keybase1.PromptNewDeviceNameArg) (string, error) { 4067 u.printf("PromptNewDeviceName") 4068 return libkb.RandString("device", 5) 4069} 4070 4071func (u *testProvisionUI) DisplaySecretExchanged(_ context.Context, _ int) error { 4072 u.printf("DisplaySecretExchanged") 4073 return nil 4074} 4075 4076func (u *testProvisionUI) ProvisioneeSuccess(_ context.Context, _ keybase1.ProvisioneeSuccessArg) error { 4077 u.printf("ProvisioneeSuccess") 4078 return nil 4079} 4080 4081func (u *testProvisionUI) ProvisionerSuccess(_ context.Context, _ keybase1.ProvisionerSuccessArg) error { 4082 u.printf("ProvisionerSuccess") 4083 return nil 4084} 4085 4086type testProvisionDupDeviceUI struct { 4087 *testProvisionUI 4088} 4089 4090// return an existing device name 4091func (u *testProvisionDupDeviceUI) PromptNewDeviceName(_ context.Context, arg keybase1.PromptNewDeviceNameArg) (string, error) { 4092 return arg.ExistingDevices[0], nil 4093} 4094 4095type testProvisionSetNameUI struct { 4096 *testProvisionUI 4097 DeviceName string 4098 ExistingDevicesFromArg []string 4099} 4100 4101// return an existing device name 4102func (u *testProvisionSetNameUI) PromptNewDeviceName(_ context.Context, arg keybase1.PromptNewDeviceNameArg) (string, error) { 4103 u.ExistingDevicesFromArg = arg.ExistingDevices 4104 return u.DeviceName, nil 4105} 4106 4107type paperLoginUI struct { 4108 Username string 4109 PaperPhrase string 4110} 4111 4112var _ libkb.LoginUI = (*paperLoginUI)(nil) 4113 4114func (p *paperLoginUI) GetEmailOrUsername(_ context.Context, _ int) (string, error) { 4115 return p.Username, nil 4116} 4117 4118func (p *paperLoginUI) PromptRevokePaperKeys(_ context.Context, arg keybase1.PromptRevokePaperKeysArg) (bool, error) { 4119 return false, nil 4120} 4121 4122func (p *paperLoginUI) DisplayPaperKeyPhrase(_ context.Context, arg keybase1.DisplayPaperKeyPhraseArg) error { 4123 return nil 4124} 4125 4126func (p *paperLoginUI) DisplayPrimaryPaperKey(_ context.Context, arg keybase1.DisplayPrimaryPaperKeyArg) error { 4127 p.PaperPhrase = arg.Phrase 4128 return nil 4129} 4130 4131func (p *paperLoginUI) PromptResetAccount(_ context.Context, arg keybase1.PromptResetAccountArg) (keybase1.ResetPromptResponse, error) { 4132 return keybase1.ResetPromptResponse_NOTHING, nil 4133} 4134 4135func (p *paperLoginUI) DisplayResetProgress(_ context.Context, arg keybase1.DisplayResetProgressArg) error { 4136 return nil 4137} 4138 4139func (p *paperLoginUI) ExplainDeviceRecovery(_ context.Context, arg keybase1.ExplainDeviceRecoveryArg) error { 4140 return nil 4141} 4142 4143func (p *paperLoginUI) PromptPassphraseRecovery(_ context.Context, arg keybase1.PromptPassphraseRecoveryArg) (bool, error) { 4144 return false, nil 4145} 4146 4147func (p *paperLoginUI) ChooseDeviceToRecoverWith(_ context.Context, arg keybase1.ChooseDeviceToRecoverWithArg) (keybase1.DeviceID, error) { 4148 return "", nil 4149} 4150 4151func (p *paperLoginUI) DisplayResetMessage(_ context.Context, arg keybase1.DisplayResetMessageArg) error { 4152 return nil 4153} 4154 4155func signString(tc libkb.TestContext, input string, secUI libkb.SecretUI) error { 4156 var sink bytes.Buffer 4157 4158 earg := PGPSignArg{ 4159 Sink: libkb.NopWriteCloser{W: &sink}, 4160 Source: ioutil.NopCloser(bytes.NewBufferString(input)), 4161 Opts: keybase1.PGPSignOptions{ 4162 Mode: keybase1.SignMode_ATTACHED, 4163 }, 4164 } 4165 4166 eng := NewPGPSignEngine(tc.G, &earg) 4167 m := NewMetaContextForTest(tc).WithUIs(libkb.UIs{ 4168 PgpUI: &TestPgpUI{}, 4169 SecretUI: secUI, 4170 }) 4171 return RunEngine2(m, eng) 4172} 4173 4174type testRetrySecretUI struct { 4175 Passphrases []string 4176 StoreSecret bool 4177 index int 4178} 4179 4180func (t *testRetrySecretUI) GetPassphrase(p keybase1.GUIEntryArg, terminal *keybase1.SecretEntryArg) (keybase1.GetPassphraseRes, error) { 4181 n := t.index 4182 if n >= len(t.Passphrases) { 4183 n = len(t.Passphrases) - 1 4184 } 4185 t.index++ 4186 return keybase1.GetPassphraseRes{ 4187 Passphrase: t.Passphrases[n], 4188 StoreSecret: t.StoreSecret, 4189 }, nil 4190} 4191 4192type testNoPromptSecretUI struct { 4193} 4194 4195func (t *testNoPromptSecretUI) GetPassphrase(p keybase1.GUIEntryArg, terminal *keybase1.SecretEntryArg) (res keybase1.GetPassphraseRes, err error) { 4196 err = errors.New("GetPassphrase called on testNoPromptSecretUI") 4197 return res, err 4198} 4199 4200type gpgImportFailer struct { 4201 g *libkb.GlobalContext 4202} 4203 4204func newGPGImportFailer(g *libkb.GlobalContext) *gpgImportFailer { 4205 return &gpgImportFailer{g: g} 4206} 4207 4208func (g *gpgImportFailer) ImportKey(_ libkb.MetaContext, secret bool, fp libkb.PGPFingerprint, tty string) (*libkb.PGPKeyBundle, error) { 4209 return nil, errors.New("failed to import key") 4210} 4211 4212func (g *gpgImportFailer) Index(mctx libkb.MetaContext, secret bool, query string) (ki *libkb.GpgKeyIndex, w libkb.Warnings, err error) { 4213 // use real gpg for this part 4214 gpg := g.g.GetGpgClient() 4215 if err := gpg.Configure(mctx); err != nil { 4216 return nil, w, err 4217 } 4218 return gpg.Index(mctx, secret, query) 4219} 4220 4221func skipOldGPG(tc libkb.TestContext) { 4222 gpg := tc.G.GetGpgClient() 4223 if err := gpg.Configure(tc.MetaContext()); err != nil { 4224 tc.T.Skip(fmt.Sprintf("skipping test due to gpg configure error: %s", err)) 4225 } 4226 ok, err := gpg.VersionAtLeast("2.0.29") 4227 if err != nil { 4228 tc.T.Fatal(err) 4229 } 4230 if ok { 4231 return 4232 } 4233 4234 v, err := gpg.SemanticVersion() 4235 if err != nil { 4236 tc.T.Fatal(err) 4237 } 4238 tc.T.Skip(fmt.Sprintf("skipping test due to gpg version < 2.0.29 (%v)", v)) 4239} 4240 4241func assertDeviceKeysCached(tc libkb.TestContext) { 4242 _, _, _, sk, ek := tc.G.ActiveDevice.AllFields() 4243 if sk == nil { 4244 tc.T.Error("cached signing key nil") 4245 } 4246 if ek == nil { 4247 tc.T.Error("cached encryption key nil") 4248 } 4249} 4250 4251func assertPassphraseStreamCache(tc libkb.TestContext) { 4252 var ppsValid bool 4253 if ppsc := tc.G.ActiveDevice.PassphraseStreamCache(); ppsc != nil { 4254 ppsValid = ppsc.ValidPassphraseStream() 4255 } 4256 if !ppsValid { 4257 tc.T.Fatal("passphrase stream not cached") 4258 } 4259} 4260 4261func assertSecretStored(tc libkb.TestContext, username string) { 4262 secret, err := tc.G.SecretStore().RetrieveSecret(NewMetaContextForTest(tc), libkb.NewNormalizedUsername(username)) 4263 require.NoError(tc.T, err, "no error fetching secret") 4264 require.False(tc.T, secret.IsNil(), "secret was non-nil") 4265} 4266 4267func assertSecretNotStored(tc libkb.TestContext, username string) { 4268 nun := libkb.NewNormalizedUsername(username) 4269 _, err := tc.G.SecretStore().RetrieveSecret(NewMetaContextForTest(tc), nun) 4270 require.Error(tc.T, err, "no secret found") 4271 require.Equal(tc.T, err, libkb.NewErrSecretForUserNotFound(nun)) 4272} 4273 4274func assertAutoreset(tc libkb.TestContext, uid keybase1.UID, expectedStatus int) error { 4275 mctx := libkb.NewMetaContextForTest(tc) 4276 resp, err := tc.G.API.Get(mctx, libkb.APIArg{ 4277 Endpoint: "autoreset/status_dev", 4278 SessionType: libkb.APISessionTypeOPTIONAL, 4279 Args: libkb.HTTPArgs{ 4280 "uid": libkb.S{Val: uid.String()}, 4281 }, 4282 }) 4283 if err != nil { 4284 return err 4285 } 4286 4287 status, ok := resp.Body.AtPathGetInt("autoreset.type") 4288 if expectedStatus == -1 { 4289 if ok { 4290 return fmt.Errorf("expected account %s to not be in reset pipeline", uid.String()) 4291 } 4292 return nil 4293 } 4294 if !ok { 4295 return fmt.Errorf("expected account %s to be in %d state (got null)", uid.String(), expectedStatus) 4296 } 4297 if status != expectedStatus { 4298 return fmt.Errorf("expected account %s to be in %d state (got %d)", uid.String(), expectedStatus, status) 4299 } 4300 return nil 4301} 4302