github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/device_add_test.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package engine 5 6 import ( 7 "crypto/rand" 8 "fmt" 9 "sync" 10 "testing" 11 12 "golang.org/x/net/context" 13 14 "github.com/keybase/client/go/kex2" 15 "github.com/keybase/client/go/libkb" 16 keybase1 "github.com/keybase/client/go/protocol/keybase1" 17 "github.com/stretchr/testify/require" 18 ) 19 20 func TestDeviceAdd(t *testing.T) { 21 testDeviceAdd(t, false) 22 } 23 24 func TestDeviceAddPUK(t *testing.T) { 25 testDeviceAdd(t, true) 26 } 27 28 func runDeviceAddTest(t *testing.T, wg *sync.WaitGroup, tcY *libkb.TestContext, secretY kex2.Secret, 29 uid keybase1.UID) { 30 defer wg.Done() 31 err := (func() error { 32 uis := libkb.UIs{ 33 ProvisionUI: &testProvisionUI{secretCh: make(chan kex2.Secret, 1)}, 34 } 35 m := NewMetaContextForTest(*tcY).WithUIs(uis).WithNewProvisionalLoginContext() 36 deviceID, err := libkb.NewDeviceID() 37 if err != nil { 38 return err 39 } 40 suffix, err := libkb.RandBytes(5) 41 if err != nil { 42 return err 43 } 44 dname := fmt.Sprintf("device_%x", suffix) 45 device := &libkb.Device{ 46 ID: deviceID, 47 Description: &dname, 48 Type: keybase1.DeviceTypeV2_DESKTOP, 49 } 50 provisionee := NewKex2Provisionee(tcY.G, device, secretY, uid, fakeSalt()) 51 return RunEngine2(m, provisionee) 52 })() 53 require.NoError(t, err, "kex2 provisionee") 54 } 55 56 func testDeviceAdd(t *testing.T, upgradePerUserKey bool) { 57 // device X (provisioner) context: 58 tcX := SetupEngineTest(t, "kex2provision") 59 defer tcX.Cleanup() 60 tcX.Tp.DisableUpgradePerUserKey = !upgradePerUserKey 61 62 // device Y (provisionee) context: 63 tcY := SetupEngineTest(t, "template") 64 defer tcY.Cleanup() 65 tcY.Tp.DisableUpgradePerUserKey = !upgradePerUserKey 66 67 // provisioner needs to be logged in 68 userX := CreateAndSignupFakeUser(tcX, "login") 69 70 var secretY kex2.Secret 71 if _, err := rand.Read(secretY[:]); err != nil { 72 t.Fatal(err) 73 } 74 75 var wg sync.WaitGroup 76 77 // start provisionee 78 wg.Add(1) 79 go runDeviceAddTest(t, &wg, &tcY, secretY, userX.UID()) 80 81 // run DeviceAdd engine on device X 82 uis := libkb.UIs{ 83 SecretUI: userX.NewSecretUI(), 84 ProvisionUI: &testXProvisionUI{secret: secretY}, 85 } 86 eng := NewDeviceAdd(tcX.G) 87 m := NewMetaContextForTest(tcX).WithUIs(uis) 88 if err := RunEngine2(m, eng); err != nil { 89 t.Errorf("device add error: %s", err) 90 } 91 92 wg.Wait() 93 } 94 95 func TestDeviceAddPhraseLegacyDesktop(t *testing.T) { 96 testDeviceAddPhrase(t, libkb.Kex2SecretTypeV1Desktop) 97 } 98 99 func TestDeviceAddPhraseLegacyMobile(t *testing.T) { 100 testDeviceAddPhrase(t, libkb.Kex2SecretTypeV1Mobile) 101 } 102 103 func TestDeviceAddPhraseV2(t *testing.T) { 104 testDeviceAddPhrase(t, libkb.Kex2SecretTypeV2) 105 } 106 107 func testDeviceAddPhrase(t *testing.T, typ libkb.Kex2SecretType) { 108 109 // device X (provisioner) context: 110 tcX := SetupEngineTest(t, "kex2provision") 111 defer tcX.Cleanup() 112 113 // device Y (provisionee) context: 114 tcY := SetupEngineTest(t, "template") 115 defer tcY.Cleanup() 116 117 // provisioner needs to be logged in 118 userX := CreateAndSignupFakeUser(tcX, "login") 119 120 secretY, err := libkb.NewKex2SecretFromTypeAndUID(typ, userX.UID()) 121 if err != nil { 122 t.Fatal(err) 123 } 124 125 var wg sync.WaitGroup 126 127 // start provisionee 128 wg.Add(1) 129 go runDeviceAddTest(t, &wg, &tcY, secretY.Secret(), userX.UID()) 130 131 // run DeviceAdd engine on device X 132 uis := libkb.UIs{ 133 SecretUI: userX.NewSecretUI(), 134 ProvisionUI: &testPhraseProvisionUI{phrase: secretY.Phrase()}, 135 } 136 eng := NewDeviceAdd(tcX.G) 137 m := NewMetaContextForTest(tcX).WithUIs(uis) 138 if err := RunEngine2(m, eng); err != nil { 139 t.Errorf("device add error: %s", err) 140 } 141 142 wg.Wait() 143 } 144 145 func TestDeviceAddStoredSecret(t *testing.T) { 146 // device X (provisioner) context: 147 tcX := SetupEngineTest(t, "kex2provision") 148 defer tcX.Cleanup() 149 150 // device Y (provisionee) context: 151 tcY := SetupEngineTest(t, "template") 152 defer tcY.Cleanup() 153 154 // provisioner needs to be logged in 155 userX := SignupFakeUserStoreSecret(tcX, "login") 156 157 var secretY kex2.Secret 158 if _, err := rand.Read(secretY[:]); err != nil { 159 t.Fatal(err) 160 } 161 162 var wg sync.WaitGroup 163 164 // start provisionee 165 wg.Add(1) 166 go runDeviceAddTest(t, &wg, &tcY, secretY, userX.UID()) 167 168 testSecretUI := userX.NewSecretUI() 169 170 // run DeviceAdd engine on device X 171 uis := libkb.UIs{ 172 SecretUI: testSecretUI, 173 ProvisionUI: &testXProvisionUI{secret: secretY}, 174 } 175 eng := NewDeviceAdd(tcX.G) 176 m := NewMetaContextForTest(tcX).WithUIs(uis) 177 if err := RunEngine2(m, eng); err != nil { 178 t.Errorf("device add error: %s", err) 179 } 180 181 wg.Wait() 182 183 if testSecretUI.CalledGetPassphrase { 184 t.Fatal("GetPassphrase() unexpectedly called") 185 } 186 } 187 188 type testXProvisionUI struct { 189 secret kex2.Secret 190 testProvisionUI 191 } 192 193 func (u *testXProvisionUI) DisplayAndPromptSecret(_ context.Context, arg keybase1.DisplayAndPromptSecretArg) (keybase1.SecretResponse, error) { 194 return keybase1.SecretResponse{Secret: u.secret[:]}, nil 195 } 196 197 type testPhraseProvisionUI struct { 198 phrase string 199 testProvisionUI 200 } 201 202 func (u *testPhraseProvisionUI) DisplayAndPromptSecret(_ context.Context, arg keybase1.DisplayAndPromptSecretArg) (keybase1.SecretResponse, error) { 203 return keybase1.SecretResponse{Phrase: u.phrase}, nil 204 }