/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/kbtest/kbtest.go
542 строки
16 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. package kbtest import ( "context" "crypto/rand" "encoding/hex" "fmt" "os" "sync" "testing" "time" "github.com/stretchr/testify/require" "github.com/keybase/client/go/engine" "github.com/keybase/client/go/kex2" "github.com/keybase/client/go/libkb" "github.com/keybase/client/go/protocol/keybase1" ) const testInviteCode = "202020202020202020202020" const DefaultDeviceName = "my device" type FakeUser struct { Username string Email string Passphrase string User *libkb.User EldestSeqno keybase1.Seqno } func NewFakeUser(prefix string) (*FakeUser, error) { buf := make([]byte, 5) if _, err := rand.Read(buf); err != nil { return nil, err } username := fmt.Sprintf("%s_%s", prefix, hex.EncodeToString(buf)) email := fmt.Sprintf("%s@noemail.keybase.io", username) buf = make([]byte, 12) if _, err := rand.Read(buf); err != nil { return nil, err } passphrase := hex.EncodeToString(buf) return &FakeUser{username, email, passphrase, nil, keybase1.Seqno(1)}, nil } func (fu *FakeUser) NewSecretUI() *libkb.TestSecretUI { return &libkb.TestSecretUI{Passphrase: fu.Passphrase} } func (fu *FakeUser) GetUID() keybase1.UID { return libkb.UsernameToUID(fu.Username) } func (fu FakeUser) NormalizedUsername() libkb.NormalizedUsername { return libkb.NewNormalizedUsername(fu.Username) } func (fu *FakeUser) GetUserVersion() keybase1.UserVersion { return keybase1.UserVersion{ Uid: fu.GetUID(), EldestSeqno: fu.EldestSeqno, } } func (fu *FakeUser) Login(g *libkb.GlobalContext) error { uis := libkb.UIs{ ProvisionUI: &TestProvisionUI{}, LogUI: g.UI.GetLogUI(), GPGUI: &GPGTestUI{}, SecretUI: fu.NewSecretUI(), LoginUI: &libkb.TestLoginUI{Username: fu.Username}, } li := engine.NewLogin(g, keybase1.DeviceTypeV2_DESKTOP, fu.Username, keybase1.ClientType_CLI) m := libkb.NewMetaContextTODO(g).WithUIs(uis) return engine.RunEngine2(m, li) } func LogoutAndLoginAs(tc libkb.TestContext, fu *FakeUser) { Logout(tc) err := fu.Login(tc.G) require.NoError(tc.T, err) } func CreateAndSignupFakeUser(prefix string, g *libkb.GlobalContext) (*FakeUser, error) { return createAndSignupFakeUser(prefix, g, true /* skipPaper */, keybase1.DeviceType_DESKTOP, false /* randomPW */) } func CreateAndSignupFakeUserPaper(prefix string, g *libkb.GlobalContext) (*FakeUser, error) { return createAndSignupFakeUser(prefix, g, false /* skipPaper */, keybase1.DeviceType_DESKTOP, false /* randomPW */) } func CreateAndSignupFakeUserMobile(prefix string, g *libkb.GlobalContext) (*FakeUser, error) { return createAndSignupFakeUser(prefix, g, true /* skipPaper */, keybase1.DeviceType_MOBILE, false /* randomPW */) } func CreateAndSignupFakeUserRandomPW(prefix string, g *libkb.GlobalContext) (*FakeUser, error) { return createAndSignupFakeUser(prefix, g, true /* skipPaper */, keybase1.DeviceType_DESKTOP, true /* randomPW */) } func createAndSignupFakeUser(prefix string, g *libkb.GlobalContext, skipPaper bool, deviceType keybase1.DeviceType, randomPW bool) (*FakeUser, error) { fu, err := NewFakeUser(prefix) if err != nil { return nil, err } if randomPW { fu.Passphrase = "" } arg := engine.SignupEngineRunArg{ Username: fu.Username, Email: fu.Email, InviteCode: testInviteCode, Passphrase: fu.Passphrase, DeviceName: DefaultDeviceName, DeviceType: deviceType, SkipGPG: true, SkipMail: true, SkipPaper: skipPaper, GenerateRandomPassphrase: randomPW, StoreSecret: true, } uis := libkb.UIs{ LogUI: g.UI.GetLogUI(), GPGUI: &GPGTestUI{}, SecretUI: fu.NewSecretUI(), LoginUI: &libkb.TestLoginUI{Username: fu.Username}, } s := engine.NewSignupEngine(g, &arg) m := libkb.NewMetaContextTODO(g).WithUIs(uis) if err := engine.RunEngine2(m, s); err != nil { return nil, err } fu.User, err = libkb.LoadUser(libkb.NewLoadUserByNameArg(g, fu.Username)) if err != nil { return nil, err } return fu, nil } func TCreateFakeUser(tc libkb.TestContext) *FakeUser { Logout(tc) // Not randomPW because these user's can't logout without setting a PW, // and we do a lot of "switching" (logout-login) between users in tests. user, err := createAndSignupFakeUser(tc.Tp.DevelPrefix, tc.G, true /* skipPaper */, keybase1.DeviceType_DESKTOP, false /* randomPW */) require.NoError(tc.T, err) return user } func GetContactSettings(tc libkb.TestContext, u *FakeUser) (ret keybase1.ContactSettings) { m := libkb.NewMetaContextForTest(tc) ret, err := libkb.GetContactSettings(m) require.NoError(tc.T, err) tc.T.Logf("Got contact settings for user %s", u.Username) return ret } func SetContactSettings(tc libkb.TestContext, u *FakeUser, arg keybase1.ContactSettings) { m := libkb.NewMetaContextForTest(tc) err := libkb.SetContactSettings(m, arg) require.NoError(tc.T, err) tc.T.Logf("Set contact settings for user %s", u.Username) } // copied from engine/common_test.go func ResetAccount(tc libkb.TestContext, u *FakeUser) { m := libkb.NewMetaContextForTest(tc) err := libkb.ResetAccount(m, u.NormalizedUsername(), u.Passphrase) require.NoError(tc.T, err) tc.T.Logf("Account reset for user %s", u.Username) Logout(tc) } func DeleteAccount(tc libkb.TestContext, u *FakeUser) { m := libkb.NewMetaContextForTest(tc) err := libkb.DeleteAccount(m, u.NormalizedUsername(), &u.Passphrase) require.NoError(tc.T, err) tc.T.Logf("Account deleted for user %s", u.Username) Logout(tc) } // copied from engine/common_test.go func Logout(tc libkb.TestContext) { mctx := libkb.NewMetaContextForTest(tc) if err := mctx.LogoutKillSecrets(); err != nil { tc.T.Fatalf("logout error: %s", err) } } // summarized from engine/revoke_test.go func RotatePaper(tc libkb.TestContext, u *FakeUser) { uis := libkb.UIs{ LogUI: tc.G.UI.GetLogUI(), LoginUI: &libkb.TestLoginUI{}, SecretUI: &libkb.TestSecretUI{}, } eng := engine.NewPaperKey(tc.G) m := libkb.NewMetaContextForTest(tc).WithUIs(uis) err := engine.RunEngine2(m, eng) require.NoError(tc.T, err) arg := libkb.NewLoadUserByNameArg(tc.G, u.Username).WithPublicKeyOptional() user, err := libkb.LoadUser(arg) require.NoError(tc.T, err) activeDevices := make([]*libkb.Device, 0) for _, device := range user.GetComputedKeyFamily().GetAllDevices() { if device.Status != nil && *device.Status == libkb.DeviceStatusActive { activeDevices = append(activeDevices, device.Device) } } var revokeDevice *libkb.Device for _, device := range activeDevices { if device.Type == keybase1.DeviceTypeV2_PAPER { revokeDevice = device } } require.NotNil(tc.T, revokeDevice, "no paper key found to revoke") revokeEngine := engine.NewRevokeDeviceEngine(tc.G, engine.RevokeDeviceEngineArgs{ID: revokeDevice.ID}) uis = libkb.UIs{ LogUI: tc.G.UI.GetLogUI(), SecretUI: u.NewSecretUI(), } m = libkb.NewMetaContextForTest(tc).WithUIs(uis) err = engine.RunEngine2(m, revokeEngine) require.NoError(tc.T, err) } func AssertProvisioned(tc libkb.TestContext) error { if !tc.G.ActiveDevice.Valid() { return libkb.LoginRequiredError{} } return nil } func FakeSalt() []byte { return []byte("fakeSALTfakeSALT") } // Provision a new device (in context tcY) from the active (and logged in) device in test context tcX. // This was adapted from engine/kex2_test.go // Note that it uses Errorf in goroutines, so if it fails // the test will not fail until later. // `tcX` is a TestContext where device X (the provisioner) is already provisioned and logged in. // this function will provision a new device Y inside `tcY` // `newDeviceType` is keybase1.DeviceTypeV2_MOBILE or keybase1.DeviceTypeV2_DESKTOP. func ProvisionNewDeviceKex(tcX *libkb.TestContext, tcY *libkb.TestContext, userX *FakeUser, newDeviceType keybase1.DeviceTypeV2) { // tcX is the device X (provisioner) context: // tcX should already have been logged in. t := tcX.T var secretX kex2.Secret if _, err := rand.Read(secretX[:]); err != nil { t.Fatal(err) } var secretY kex2.Secret if _, err := rand.Read(secretY[:]); err != nil { t.Fatal(err) } var wg sync.WaitGroup // start provisionee wg.Add(1) go func() { defer wg.Done() err := (func() error { uis := libkb.UIs{ ProvisionUI: &TestProvisionUI{SecretCh: make(chan kex2.Secret, 1)}, } m := libkb.NewMetaContextForTest(*tcY).WithUIs(uis).WithNewProvisionalLoginContext() deviceID, err := libkb.NewDeviceID() if err != nil { return err } suffix, err := libkb.RandBytes(5) if err != nil { return err } dname := fmt.Sprintf("device_%x", suffix) device := &libkb.Device{ ID: deviceID, Description: &dname, Type: newDeviceType, } provisionee := engine.NewKex2Provisionee(tcY.G, device, secretY, userX.GetUID(), FakeSalt()) return engine.RunEngine2(m, provisionee) })() require.NoError(t, err, "kex2 provisionee") }() // start provisioner wg.Add(1) go func() { defer wg.Done() uis := libkb.UIs{ SecretUI: userX.NewSecretUI(), ProvisionUI: &TestProvisionUI{}, } provisioner := engine.NewKex2Provisioner(tcX.G, secretX, nil) go provisioner.AddSecret(secretY) m := libkb.NewMetaContextForTest(*tcX).WithUIs(uis) if err := engine.RunEngine2(m, provisioner); err != nil { require.NoErrorf(t, err, "provisioner error") return } }() wg.Wait() } type TestProvisionUI struct { SecretCh chan kex2.Secret DeviceType keybase1.DeviceTypeV2 } func (u *TestProvisionUI) ChooseProvisioningMethod(_ context.Context, _ keybase1.ChooseProvisioningMethodArg) (keybase1.ProvisionMethod, error) { panic("ChooseProvisioningMethod deprecated") } func (u *TestProvisionUI) ChooseGPGMethod(_ context.Context, _ keybase1.ChooseGPGMethodArg) (keybase1.GPGMethod, error) { return keybase1.GPGMethod_GPG_NONE, nil } func (u *TestProvisionUI) SwitchToGPGSignOK(ctx context.Context, arg keybase1.SwitchToGPGSignOKArg) (bool, error) { return true, nil } func (u *TestProvisionUI) ChooseDevice(_ context.Context, arg keybase1.ChooseDeviceArg) (keybase1.DeviceID, error) { for _, d := range arg.Devices { if d.Type == u.DeviceType { return d.DeviceID, nil } } return "", nil } func (u *TestProvisionUI) ChooseDeviceType(_ context.Context, _ keybase1.ChooseDeviceTypeArg) (keybase1.DeviceType, error) { return keybase1.DeviceType_DESKTOP, nil } func (u *TestProvisionUI) DisplayAndPromptSecret(_ context.Context, arg keybase1.DisplayAndPromptSecretArg) (keybase1.SecretResponse, error) { var ks kex2.Secret copy(ks[:], arg.Secret) u.SecretCh <- ks var sr keybase1.SecretResponse return sr, nil } func (u *TestProvisionUI) PromptNewDeviceName(_ context.Context, arg keybase1.PromptNewDeviceNameArg) (string, error) { return libkb.RandString("device", 5) } func (u *TestProvisionUI) DisplaySecretExchanged(_ context.Context, _ int) error { return nil } func (u *TestProvisionUI) ProvisioneeSuccess(_ context.Context, _ keybase1.ProvisioneeSuccessArg) error { return nil } func (u *TestProvisionUI) ProvisionerSuccess(_ context.Context, _ keybase1.ProvisionerSuccessArg) error { return nil } type TeamNotifyListener struct { libkb.NoopNotifyListener changeByIDCh chan keybase1.TeamChangedByIDArg changeByNameCh chan keybase1.TeamChangedByNameArg } var _ libkb.NotifyListener = (*TeamNotifyListener)(nil) func (n *TeamNotifyListener) TeamChangedByID(teamID keybase1.TeamID, latestSeqno keybase1.Seqno, implicitTeam bool, changes keybase1.TeamChangeSet, latestHiddenSeqno keybase1.Seqno, source keybase1.TeamChangedSource) { n.changeByIDCh <- keybase1.TeamChangedByIDArg{ TeamID: teamID, LatestSeqno: latestSeqno, ImplicitTeam: implicitTeam, Changes: changes, LatestHiddenSeqno: latestHiddenSeqno, } } func (n *TeamNotifyListener) TeamChangedByName(teamName string, latestSeqno keybase1.Seqno, implicitTeam bool, changes keybase1.TeamChangeSet, latestHiddenSeqno keybase1.Seqno, source keybase1.TeamChangedSource) { n.changeByNameCh <- keybase1.TeamChangedByNameArg{ TeamName: teamName, LatestSeqno: latestSeqno, ImplicitTeam: implicitTeam, Changes: changes, LatestHiddenSeqno: latestHiddenSeqno, } } func NewTeamNotifyListener() *TeamNotifyListener { return &TeamNotifyListener{ changeByIDCh: make(chan keybase1.TeamChangedByIDArg, 10), changeByNameCh: make(chan keybase1.TeamChangedByNameArg, 10), } } func CheckTeamMiscNotifications(tc libkb.TestContext, notifications *TeamNotifyListener) { changeByID := false changeByName := false for { select { case arg := <-notifications.changeByIDCh: changeByID = arg.Changes.Misc case arg := <-notifications.changeByNameCh: changeByName = arg.Changes.Misc case <-time.After(500 * time.Millisecond * libkb.CITimeMultiplier(tc.G)): tc.T.Fatal("no notification on teamSetSettings") } if changeByID && changeByName { return } } } type fakeIdentifyUI struct { *engine.LoopbackIdentifyUI } func (l *fakeIdentifyUI) Confirm(_ libkb.MetaContext, o *keybase1.IdentifyOutcome) (keybase1.ConfirmResult, error) { return keybase1.ConfirmResult{IdentityConfirmed: true, RemoteConfirmed: true}, nil } func newFakeIdentifyUI(g *libkb.GlobalContext) *fakeIdentifyUI { var tb *keybase1.IdentifyTrackBreaks return &fakeIdentifyUI{ engine.NewLoopbackIdentifyUI(g, &tb), } } func RunTrack(tc libkb.TestContext, fu *FakeUser, username string) (them *libkb.User, err error) { sv := keybase1.SigVersion(2) return RunTrackWithOptions(tc, fu, username, keybase1.TrackOptions{BypassConfirm: true, SigVersion: &sv}, fu.NewSecretUI(), false) } func RunTrackWithOptions(tc libkb.TestContext, fu *FakeUser, username string, options keybase1.TrackOptions, secretUI libkb.SecretUI, forceRemoteCheck bool) (them *libkb.User, err error) { idUI := newFakeIdentifyUI(tc.G) arg := &engine.TrackEngineArg{ UserAssertion: username, Options: options, ForceRemoteCheck: forceRemoteCheck, } uis := libkb.UIs{ LogUI: tc.G.UI.GetLogUI(), IdentifyUI: idUI, SecretUI: secretUI, } eng := engine.NewTrackEngine(tc.G, arg) m := libkb.NewMetaContextForTest(tc).WithUIs(uis) err = engine.RunEngine2(m, eng) them = eng.User() return them, err } // GenerateTestPhoneNumber generates a random phone number in US with 555 area // code. It passes serverside "strict phone number" checker test, and it's // considered `possible`, but not `valid` by libphonenumber. func GenerateTestPhoneNumber() string { ret := make([]byte, 7) _, err := rand.Read(ret) if err != nil { panic(err) } for i := range ret { ret[i] = "0123456789"[int(ret[i])%10] } return fmt.Sprintf("1555%s", string(ret)) } func GenerateRandomEmailAddress() keybase1.EmailAddress { buf := make([]byte, 5) _, err := rand.Read(buf) if err != nil { panic(err) } email := fmt.Sprintf("%s@example.org", hex.EncodeToString(buf)) return keybase1.EmailAddress(email) } type getCodeResponse struct { libkb.AppStatusEmbed VerificationCode string `json:"verification_code"` } func GetPhoneVerificationCode(mctx libkb.MetaContext, phoneNumber keybase1.PhoneNumber) (code string, err error) { arg := libkb.APIArg{ Endpoint: "test/phone_number_code", SessionType: libkb.APISessionTypeREQUIRED, Args: libkb.HTTPArgs{ "phone_number": libkb.S{Val: phoneNumber.String()}, }, } var resp getCodeResponse err = mctx.G().API.GetDecode(mctx, arg, &resp) if err != nil { return "", err } return resp.VerificationCode, nil } func VerifyEmailAuto(mctx libkb.MetaContext, email keybase1.EmailAddress) error { arg := libkb.APIArg{ Endpoint: "test/verify_email_auto", SessionType: libkb.APISessionTypeREQUIRED, Args: libkb.HTTPArgs{ "email": libkb.S{Val: string(email)}, }, } _, err := mctx.G().API.Post(mctx, arg) return err } func EditProfile(mctx libkb.MetaContext, arg keybase1.ProfileEditArg) error { eng := engine.NewProfileEdit(mctx.G(), arg) return engine.RunEngine2(mctx, eng) } func RunningInCI() bool { x := os.Getenv("KEYBASE_RUN_CI") return len(x) > 0 && x != "0" && x[0] != byte('n') } func SkipTestOnNonMasterCI(t *testing.T, reason string) { if RunningInCI() && os.Getenv("BRANCH_NAME") != "master" { t.Skipf("skip test on non-master CI run: %v", reason) } } // CORE-10146 func SkipIconRemoteTest() bool { return RunningInCI() }