/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/engine/upak_loader_test.go
589 строк
17 KB
zoom-ua
remove golang.org/x/net/context in favor of context (#28708)
17 дек 2025, 18:24
Не верифицирован
17 дек 2025, 18:24
67b0ffe
Код
Авторство
О чём код?
// Copyright 2015 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. // There are two test files by this name. One in libkb, one in engine. package engine import ( "context" "sync" "testing" "time" "github.com/keybase/client/go/libkb" keybase1 "github.com/keybase/client/go/protocol/keybase1" "github.com/keybase/clockwork" "github.com/stretchr/testify/require" ) func TestLoadDeviceKeyNew(t *testing.T) { tc := SetupEngineTest(t, "clu") defer tc.Cleanup() t.Logf("create new user") fu := NewFakeUserOrBust(t, "paper") arg := MakeTestSignupEngineRunArg(fu) arg.SkipPaper = false loginUI := &paperLoginUI{Username: fu.Username} uis := libkb.UIs{ LogUI: tc.G.UI.GetLogUI(), GPGUI: &gpgtestui{}, SecretUI: fu.NewSecretUI(), LoginUI: loginUI, } s := NewSignupEngine(tc.G, &arg) err := RunEngine2(NewMetaContextForTest(tc).WithUIs(uis), s) if err != nil { tc.T.Fatal(err) } t.Logf("using username:%+v", fu.Username) loadArg := libkb.NewLoadUserByNameArg(tc.G, fu.Username).WithPublicKeyOptional() user, err := libkb.LoadUser(loadArg) if err != nil { tc.T.Fatal(err) } t.Logf("using username:%+v uid: %+v", user.GetNormalizedName(), user.GetUID()) assertNumDevicesAndKeys(tc, fu, 2, 4) devices, _ := getActiveDevicesAndKeys(tc, fu) var device1 *libkb.Device for _, device := range devices { if device.Type != keybase1.DeviceTypeV2_PAPER { device1 = device.Device } } require.NotNil(t, device1, "device1 should be non-nil") t.Logf("using device1:%+v", device1.ID) t.Logf("load existing device key") upk, deviceKey, revoked, err := tc.G.GetUPAKLoader().LoadDeviceKey(context.TODO(), user.GetUID(), device1.ID) require.NoError(t, err) require.Equal(t, user.GetNormalizedName().String(), upk.Base.Username, "usernames must match") require.Equal(t, device1.ID, deviceKey.DeviceID, "deviceID must match") require.Equal(t, *device1.Description, deviceKey.DeviceDescription, "device name must match") require.Nil(t, revoked, "device not revoked") err = tc.G.GetFullSelfer().WithSelf(context.TODO(), func(u *libkb.User) error { dev, err := u.GetDevice(device1.ID) require.NoError(t, err) require.NotNil(t, dev) return nil }) require.NoError(t, err) Logout(tc) if len(loginUI.PaperPhrase) == 0 { t.Fatal("login ui has no paper key phrase") } t.Logf("create new device") // redo SetupEngineTest to get a new home directory...should look like a new device. tc2 := SetupEngineTest(t, "login") defer tc2.Cleanup() secUI := fu.NewSecretUI() provUI := newTestProvisionUIPaper() provLoginUI := &libkb.TestLoginUI{Username: fu.Username} uis = libkb.UIs{ ProvisionUI: provUI, LogUI: tc2.G.UI.GetLogUI(), SecretUI: secUI, LoginUI: provLoginUI, GPGUI: &gpgtestui{}, } eng := NewPaperProvisionEngine(tc2.G, fu.Username, "fakedevice", loginUI.PaperPhrase) m := NewMetaContextForTest(tc2).WithUIs(uis) if err := RunEngine2(m, eng); err != nil { t.Fatal(err) } t.Logf("d2 provisioned (1)") testUserHasDeviceKey(tc2) require.NoError(t, AssertProvisioned(tc2)) t.Logf("d2 provisioned (2)") devices, _ = getActiveDevicesAndKeys(tc, fu) var device2 *libkb.Device for _, device := range devices { if device.Type != keybase1.DeviceTypeV2_PAPER && device.ID != device1.ID { device2 = device.Device } } require.NotNil(t, device2, "device2 should be non-nil") t.Logf("using device2:%+v", device2.ID) t.Logf("load brand new device (while old is cached)") upk, deviceKey, revoked, err = tc.G.GetUPAKLoader().LoadDeviceKey(context.TODO(), user.GetUID(), device2.ID) require.NoError(t, err) require.Equal(t, user.GetNormalizedName().String(), upk.Base.Username, "usernames must match") require.Equal(t, device2.ID, deviceKey.DeviceID, "deviceID must match") require.Equal(t, *device2.Description, deviceKey.DeviceDescription, "device name must match") require.Nil(t, revoked, "device not revoked") err = tc.G.GetFullSelfer().WithSelf(context.TODO(), func(u *libkb.User) error { dev, err := u.GetDevice(deviceKey.DeviceID) require.NoError(t, err) require.NotNil(t, dev) return nil }) require.NoError(t, err) } func TestLoadDeviceKeyRevoked(t *testing.T) { tc := SetupEngineTest(t, "clu") defer tc.Cleanup() fu := CreateAndSignupFakeUserPaper(tc, "rev") t.Logf("using username:%+v", fu.Username) loadArg := libkb.NewLoadUserByNameArg(tc.G, fu.Username).WithPublicKeyOptional() user, err := libkb.LoadUser(loadArg) if err != nil { tc.T.Fatal(err) } t.Logf("using username:%+v uid: %+v", user.GetNormalizedName(), user.GetUID()) assertNumDevicesAndKeys(tc, fu, 2, 4) devices, _ := getActiveDevicesAndKeys(tc, fu) var thisDevice *libkb.Device for _, device := range devices { if device.Type != keybase1.DeviceTypeV2_PAPER { thisDevice = device.Device } } // Revoke the current device with --force err = doRevokeDevice(tc, fu, thisDevice.ID, true, false) if err != nil { tc.T.Fatal(err) } assertNumDevicesAndKeys(tc, fu, 1, 2) t.Logf("load revoked device") upk, deviceKey, revoked, err := tc.G.GetUPAKLoader().LoadDeviceKey(context.TODO(), user.GetUID(), thisDevice.ID) require.NoError(t, err) require.Equal(t, user.GetNormalizedName().String(), upk.Base.Username, "usernames must match") require.Equal(t, thisDevice.ID, deviceKey.DeviceID, "deviceID must match") require.Equal(t, *thisDevice.Description, deviceKey.DeviceDescription, "device name must match") require.NotNil(t, revoked, "device should be revoked") err = tc.G.GetFullSelfer().WithSelf(context.TODO(), func(u *libkb.User) error { dev, err := u.GetDevice(deviceKey.DeviceID) require.NoError(t, err) require.NotNil(t, dev) require.False(t, dev.IsActive()) dev, err = u.GetDevice(thisDevice.ID) require.NoError(t, err) require.NotNil(t, dev) return nil }) require.NoError(t, err) } func TestFullSelfCacherFlushSingleMachine(t *testing.T) { tc := SetupEngineTest(t, "fsc") defer tc.Cleanup() sigVersion := libkb.GetDefaultSigVersion(tc.G) fu := CreateAndSignupFakeUser(tc, "fsc") var scv keybase1.Seqno err := tc.G.GetFullSelfer().WithSelf(context.TODO(), func(u *libkb.User) error { require.NotNil(t, u) scv = u.GetSigChainLastKnownSeqno() return nil }) require.NoError(t, err) trackAlice(tc, fu, sigVersion) defer untrackAlice(tc, fu, sigVersion) err = tc.G.GetFullSelfer().WithSelf(context.TODO(), func(u *libkb.User) error { require.NotNil(t, u) require.True(t, u.GetSigChainLastKnownSeqno() > scv) return nil }) require.NoError(t, err) } func TestFullSelfCacherFlushTwoMachines(t *testing.T) { tc := SetupEngineTest(t, "fsc") defer tc.Cleanup() fakeClock := clockwork.NewFakeClockAt(time.Now()) tc.G.SetClock(fakeClock) t.Logf("create new user") fu := NewFakeUserOrBust(t, "paper") arg := MakeTestSignupEngineRunArg(fu) arg.SkipPaper = false loginUI := &paperLoginUI{Username: fu.Username} uis := libkb.UIs{ LogUI: tc.G.UI.GetLogUI(), GPGUI: &gpgtestui{}, SecretUI: fu.NewSecretUI(), LoginUI: loginUI, } s := NewSignupEngine(tc.G, &arg) err := RunEngine2(NewMetaContextForTest(tc).WithUIs(uis), s) if err != nil { tc.T.Fatal(err) } t.Logf("using username:%+v", fu.Username) var scv keybase1.Seqno err = tc.G.GetFullSelfer().WithSelf(context.TODO(), func(u *libkb.User) error { require.NotNil(t, u) scv = u.GetSigChainLastKnownSeqno() return nil }) require.NoError(t, err) if len(loginUI.PaperPhrase) == 0 { t.Fatal("login ui has no paper key phrase") } t.Logf("create new device") // redo SetupEngineTest to get a new home directory...should look like a new device. tc2 := SetupEngineTest(t, "login") defer tc2.Cleanup() secUI := fu.NewSecretUI() provUI := newTestProvisionUIPaper() provLoginUI := &libkb.TestLoginUI{Username: fu.Username} uis = libkb.UIs{ ProvisionUI: provUI, LogUI: tc2.G.UI.GetLogUI(), SecretUI: secUI, LoginUI: provLoginUI, GPGUI: &gpgtestui{}, } eng := NewPaperProvisionEngine(tc2.G, fu.Username, "fakedevice", loginUI.PaperPhrase) m := NewMetaContextForTest(tc2).WithUIs(uis) if err := RunEngine2(m, eng); err != nil { t.Fatal(err) } t.Logf("d2 provisioned (1)") // Without pubsub (not available on engine tests), we don't get any // invalidation of the user on the first machine (tc). So this // user's sigchain should stay the same. err = tc.G.GetFullSelfer().WithSelf(context.TODO(), func(u *libkb.User) error { require.NotNil(t, u) require.True(t, u.GetSigChainLastKnownSeqno() == scv) return nil }) require.NoError(t, err) // After the CachedUserTimeout, the FullSelfer ought to repoll. // Check that the sigchain is updated after the repoll, which reflects // the new device having been added. fakeClock.Advance(libkb.CachedUserTimeout + time.Second) err = tc.G.GetFullSelfer().WithSelf(context.TODO(), func(u *libkb.User) error { require.NotNil(t, u) require.True(t, u.GetSigChainLastKnownSeqno() > scv) return nil }) require.NoError(t, err) } func TestUPAKDeadlock(t *testing.T) { tc := SetupEngineTest(t, "upak") defer tc.Cleanup() fu := CreateAndSignupFakeUserPaper(tc, "upak") // First clear the cache tc.G.KeyfamilyChanged(context.TODO(), fu.UID()) var wg sync.WaitGroup ch := make(chan struct{}) tc.G.GetFullSelfer().(*libkb.CachedFullSelf).TestDeadlocker = func() { <-ch } tc.G.GetUPAKLoader().(*libkb.CachedUPAKLoader).TestDeadlocker = func() { ch <- struct{}{} } wg.Add(1) go func() { _ = tc.G.GetFullSelfer().WithSelf(context.TODO(), func(u *libkb.User) error { require.Equal(t, u.GetUID(), fu.UID(), "right UID") return nil }) wg.Done() }() wg.Add(1) go func() { un, err := tc.G.GetUPAKLoader().LookupUsername(context.TODO(), fu.UID()) require.NoError(t, err) if un.String() != fu.Username { t.Errorf("username mismatch: %s != %s", un, fu.Username) } wg.Done() }() doneCh := make(chan struct{}) go func() { wg.Wait() doneCh <- struct{}{} }() select { case <-doneCh: break case <-time.After(20 * time.Second): t.Fatal("deadlocked!") } } func TestLoadAfterAcctReset1(t *testing.T) { // One context for user that will be doing LoadUser, and another // for user that will sign up and reset itself. tc := SetupEngineTest(t, "clu") defer tc.Cleanup() resetUserTC := SetupEngineTest(t, "clu2") defer resetUserTC.Cleanup() t.Logf("create new user") fu := CreateAndSignupFakeUser(resetUserTC, "res") fakeClock := clockwork.NewFakeClockAt(time.Now()) tc.G.SetClock(fakeClock) loadUpak := func() error { t.Logf("loadUpak: using username:%+v", fu.Username) loadArg := libkb.NewLoadUserArg(tc.G).WithUID(fu.UID()).WithNetContext(context.TODO()).WithStaleOK(false).WithForceMerkleServerPolling(true) upak, _, err := tc.G.GetUPAKLoader().Load(loadArg) if err != nil { return err } t.Logf("loadUpak done: using username:%+v uid: %+v keys: %d", upak.Base.Username, upak.Base.Uid, len(upak.Base.DeviceKeys)) return nil } err := loadUpak() if err != nil { t.Fatalf("Failed to load user: %+v", err) } ResetAccount(resetUserTC, fu) loadUpakExpectFailure := func() { err := loadUpak() if err == nil { t.Fatalf("Expected UPAKLoader.Load to fail on nuked account.") } else if _, ok := err.(libkb.NoKeyError); !ok { t.Fatalf("Expected UPAKLoader.Load to fail with NoKeyError, instead failed with: %+v", err) } } // advance the clock past the cache timeout fakeClock.Advance(libkb.CachedUserTimeout * 10) loadUpakExpectFailure() // Try again, see if still errors out (this time user should not // be in cache at all). fakeClock.Advance(libkb.CachedUserTimeout * 10) loadUpakExpectFailure() } func TestLoadAfterAcctReset2(t *testing.T) { // One context for user that will be doing LoadUser, and another // for user that will sign up and reset itself. tc := SetupEngineTest(t, "clu") defer tc.Cleanup() resetUserTC := SetupEngineTest(t, "clu2") defer resetUserTC.Cleanup() t.Logf("create new user") fu := CreateAndSignupFakeUser(resetUserTC, "res") fakeClock := clockwork.NewFakeClockAt(time.Now()) tc.G.SetClock(fakeClock) loadUpak := func() (*keybase1.UserPlusAllKeys, error) { t.Logf("loadUpak: using username:%+v", fu.Username) loadArg := libkb.NewLoadUserArg(tc.G).WithUID(fu.UID()).WithPublicKeyOptional().WithNetContext(context.TODO()).WithStaleOK(false) upak, _, err := tc.G.GetUPAKLoader().Load(loadArg) if err != nil { return nil, err } t.Logf("loadUpak done: using username:%+v uid: %+v keys: %d", upak.Base.Username, upak.Base.Uid, len(upak.Base.DeviceKeys)) return upak, nil } upak1, err := loadUpak() if err != nil { t.Fatalf("Failed to load user: %+v", err) } // Reset account and then login again to establish new eldest and // add new device keys. ResetAccount(resetUserTC, fu) tcp := SetupEngineTest(t, "login") defer tcp.Cleanup() fu.LoginOrBust(tcp) if err := AssertProvisioned(tcp); err != nil { t.Fatal(err) } fakeClock.Advance(libkb.CachedUserTimeout * 10) upak2, err := loadUpak() if err != nil { t.Fatalf("Failed to load user after reset+login with: %+v", err) } if upak1.Base.DeviceKeys[0].KID == upak2.Base.DeviceKeys[0].KID { t.Fatal("Found old device key after LoadUser.") } } // Test the bug in CORE-6943: after a reset, if we did two // logins in a row, right on top of each other, previous subchains // would be dropped from the self UPAK. func TestLoadAfterAcctResetCORE6943(t *testing.T) { tc := SetupEngineTest(t, "clu") defer tc.Cleanup() sigVersion := libkb.GetDefaultSigVersion(tc.G) t.Logf("create new user") fu := CreateAndSignupFakeUser(tc, "res") trackAlice(tc, fu, sigVersion) loadUpak := func() (*keybase1.UserPlusAllKeys, error) { t.Logf("loadUpak: using username:%+v", fu.Username) loadArg := libkb.NewLoadUserArg(tc.G).WithUID(fu.UID()).WithPublicKeyOptional().WithNetContext(context.TODO()).WithStaleOK(false) upak, _, err := tc.G.GetUPAKLoader().Load(loadArg) if err != nil { return nil, err } t.Logf("loadUpak done: using username:%+v uid: %+v keys: %d", upak.Base.Username, upak.Base.Uid, len(upak.Base.DeviceKeys)) return upak, nil } upak1, err := loadUpak() if err != nil { t.Fatalf("Failed to load user: %+v", err) } // Reset account and then login again to establish new eldest and // add new device keys. ResetAccount(tc, fu) tc.G.GetUPAKLoader().Invalidate(context.TODO(), fu.UID()) fu.LoginOrBust(tc) if err := AssertProvisioned(tc); err != nil { t.Fatal(err) } // login a second time to force the bug. fu.LoginOrBust(tc) // Make sure that we can load the eldest key from the previous subchain _, _, _, err = tc.G.GetUPAKLoader().LoadKeyV2(context.TODO(), fu.UID(), upak1.Base.DeviceKeys[0].KID) if err != nil { t.Fatal("Failed to load a UID/KID combo from first incarnation") } _, err = loadUpak() if err != nil { t.Fatalf("Failed to load user: %+v", err) } } func TestUPAKUnstub(t *testing.T) { tc := SetupEngineTest(t, "login") defer tc.Cleanup() u1 := CreateAndSignupFakeUser(tc, "first") Logout(tc) u2 := CreateAndSignupFakeUser(tc, "secon") testTrack(t, tc, libkb.KeybaseSignatureV2, "t_alice") testTrack(t, tc, libkb.KeybaseSignatureV2, u1.Username) // The last link is always unstubbed, so this is a throw-away so that we have some links that // are stubbed (the two just above). testTrack(t, tc, libkb.KeybaseSignatureV2, "t_bob") Logout(tc) t.Logf("first logging back in") u1.LoginOrBust(tc) upl := tc.G.GetUPAKLoader() mctx := NewMetaContextForTest(tc) // wipe out all the caches _, err := tc.G.LocalDb.Nuke() require.NoError(t, err) upl.Invalidate(mctx.Ctx(), u2.UID()) assertStubbed := func() { arg := libkb.NewLoadUserArgWithMetaContext(mctx).WithUID(u2.UID()) upak, _, err := upl.LoadV2(arg) require.NoError(t, err) require.Equal(t, 1, len(upak.Current.RemoteTracks)) require.Equal(t, "t_bob", upak.Current.RemoteTracks[keybase1.UID("afb5eda3154bc13c1df0189ce93ba119")].Username) require.False(t, upak.Current.Unstubbed) } assertStubbed() Logout(tc) t.Logf("second logging back in") u2.LoginOrBust(tc) assertStubbed() assertAllLinks := func(stubMode libkb.StubMode) { arg := libkb.NewLoadUserArgWithMetaContext(mctx).WithUID(u2.UID()).WithStubMode(stubMode) upak, _, err := upl.LoadV2(arg) require.NoError(t, err) require.Equal(t, 3, len(upak.Current.RemoteTracks)) require.Equal(t, u1.Username, upak.Current.RemoteTracks[u1.UID()].Username) require.True(t, upak.Current.Unstubbed) } assertAllLinks(libkb.StubModeUnstubbed) Logout(tc) t.Logf("first logging back in") u1.LoginOrBust(tc) assertAllLinks(libkb.StubModeUnstubbed) assertAllLinks(libkb.StubModeStubbed) } func TestInvalidation(t *testing.T) { tc := SetupEngineTest(t, "login") defer tc.Cleanup() u := CreateAndSignupFakeUser(tc, "first") upl := tc.G.GetUPAKLoader() mctx := NewMetaContextForTest(tc) arg := libkb.NewLoadUserArgWithMetaContext(mctx).WithUID(u.UID()) upak, _, err := upl.LoadV2(arg) require.NoError(t, err) require.NotNil(t, upak) upl.Invalidate(mctx.Ctx(), u.UID()) arg = libkb.NewLoadUserArgWithMetaContext(mctx).WithUID(u.UID()).WithCachedOnly(true) _, _, err = upl.LoadV2(arg) require.Error(t, err) require.IsType(t, libkb.UserNotFoundError{}, err) require.Contains(t, err.Error(), "cached user found, but it was stale, and cached only") arg = libkb.NewLoadUserArgWithMetaContext(mctx).WithUID(u.UID()).WithCachedOnly(true).WithStaleOK(true) upak, _, err = upl.LoadV2(arg) require.NoError(t, err) require.NotNil(t, upak) }