// Run starts the engine. func (e *DeviceAdd) Run(ctx *Context) (err error) { e.G().Log.Debug("+ DeviceAdd.Run()") defer func() { e.G().Log.Debug("- DeviceAdd.Run() -> %s", libkb.ErrToOk(err)) }() provisioneeType, err := ctx.ProvisionUI.ChooseDeviceType(context.TODO(), 0) if err != nil { return err } e.G().Log.Debug("provisionee device type: %v", provisioneeType) // make a new secret: secret, err := libkb.NewKex2Secret() if err != nil { return err } e.G().Log.Debug("secret phrase: %s", secret.Phrase()) // create provisioner engine provisioner := NewKex2Provisioner(e.G(), secret.Secret()) var canceler func() // display secret and prompt for secret from X in a goroutine: go func() { sb := secret.Secret() arg := keybase1.DisplayAndPromptSecretArg{ Secret: sb[:], Phrase: secret.Phrase(), OtherDeviceType: provisioneeType, } var contxt context.Context contxt, canceler = context.WithCancel(context.Background()) receivedSecret, err := ctx.ProvisionUI.DisplayAndPromptSecret(contxt, arg) if err != nil { // XXX ??? e.G().Log.Warning("DisplayAndPromptSecret error: %s", err) } else if receivedSecret != nil { e.G().Log.Debug("received secret, adding to provisioner") var ks kex2.Secret copy(ks[:], receivedSecret) provisioner.AddSecret(ks) } }() defer func() { if canceler != nil { e.G().Log.Debug("canceling DisplayAndPromptSecret call") canceler() } }() // run provisioner if err = RunEngine(provisioner, ctx); err != nil { return err } return nil }
func TestDeviceAddPhrase(t *testing.T) { // device X (provisioner) context: tcX := SetupEngineTest(t, "kex2provision") defer tcX.Cleanup() // device Y (provisionee) context: tcY := SetupEngineTest(t, "template") defer tcY.Cleanup() // provisioner needs to be logged in userX := CreateAndSignupFakeUser(tcX, "login") var secretX kex2.Secret if _, err := rand.Read(secretX[:]); err != nil { t.Fatal(err) } secretY, err := libkb.NewKex2Secret() if err != nil { t.Fatal(err) } var wg sync.WaitGroup // start provisionee wg.Add(1) go func() { defer wg.Done() f := func(lctx libkb.LoginContext) error { ctx := &Context{ ProvisionUI: &testProvisionUI{secretCh: make(chan kex2.Secret, 1)}, LoginContext: lctx, NetContext: context.TODO(), } deviceID, err := libkb.NewDeviceID() if err != nil { t.Errorf("provisionee device id error: %s", err) return err } suffix, err := libkb.RandBytes(5) if err != nil { t.Errorf("provisionee device suffix error: %s", err) return err } dname := fmt.Sprintf("device_%x", suffix) device := &libkb.Device{ ID: deviceID, Description: &dname, Type: libkb.DeviceTypeDesktop, } provisionee := NewKex2Provisionee(tcY.G, device, secretY.Secret()) if err := RunEngine(provisionee, ctx); err != nil { t.Errorf("provisionee error: %s", err) return err } return nil } if err := tcY.G.LoginState().ExternalFunc(f, "Test - DeviceAdd"); err != nil { t.Errorf("kex2 provisionee error: %s", err) } }() // run DeviceAdd engine on device X ctx := &Context{ SecretUI: userX.NewSecretUI(), ProvisionUI: &testPhraseProvisionUI{phrase: secretY.Phrase()}, NetContext: context.TODO(), } eng := NewDeviceAdd(tcX.G) if err := RunEngine(eng, ctx); err != nil { t.Errorf("device add error: %s", err) } wg.Wait() }
// Run starts the engine. func (e *DeviceAdd) Run(ctx *Context) (err error) { e.G().Log.Debug("+ DeviceAdd.Run()") defer func() { e.G().Log.Debug("- DeviceAdd.Run() -> %s", libkb.ErrToOk(err)) }() arg := keybase1.ChooseDeviceTypeArg{Kind: keybase1.ChooseType_NEW_DEVICE} provisioneeType, err := ctx.ProvisionUI.ChooseDeviceType(context.TODO(), arg) if err != nil { return err } e.G().Log.Debug("provisionee device type: %v", provisioneeType) // make a new secret: secret, err := libkb.NewKex2Secret() if err != nil { return err } e.G().Log.Debug("secret phrase: %s", secret.Phrase()) // provisioner needs ppstream, and UI is confusing when it asks for // it at the same time as asking for the secret, so get it first // before prompting for the kex2 secret: pps, err := e.G().LoginState().GetPassphraseStream(ctx.SecretUI) if err != nil { return err } // create provisioner engine provisioner := NewKex2Provisioner(e.G(), secret.Secret(), pps) var canceler func() // display secret and prompt for secret from X in a goroutine: go func() { sb := secret.Secret() arg := keybase1.DisplayAndPromptSecretArg{ Secret: sb[:], Phrase: secret.Phrase(), OtherDeviceType: provisioneeType, } var contxt context.Context contxt, canceler = context.WithCancel(context.Background()) receivedSecret, err := ctx.ProvisionUI.DisplayAndPromptSecret(contxt, arg) if err != nil { // XXX ??? e.G().Log.Warning("DisplayAndPromptSecret error: %s", err) } else if receivedSecret.Secret != nil && len(receivedSecret.Secret) > 0 { e.G().Log.Debug("received secret, adding to provisioner") var ks kex2.Secret copy(ks[:], receivedSecret.Secret) provisioner.AddSecret(ks) } else if len(receivedSecret.Phrase) > 0 { e.G().Log.Debug("received secret phrase, adding to provisioner") ks, err := libkb.NewKex2SecretFromPhrase(receivedSecret.Phrase) if err != nil { e.G().Log.Warning("DisplayAndPromptSecret error: %s", err) } else { provisioner.AddSecret(ks.Secret()) } } }() defer func() { if canceler != nil { e.G().Log.Debug("canceling DisplayAndPromptSecret call") canceler() } }() // run provisioner if err = RunEngine(provisioner, ctx); err != nil { if err == kex2.ErrHelloTimeout { return libkb.CanceledError{M: "Failed to provision device: are you sure you typed the secret properly?"} } return err } return nil }
// deviceWithType provisions this device with an existing device using the // kex2 protocol. provisionerType is the existing device type. func (e *loginProvision) deviceWithType(ctx *Context, provisionerType keybase1.DeviceType) error { // make a new secret: secret, err := libkb.NewKex2Secret() if err != nil { return err } e.G().Log.Debug("secret phrase received") // make a new device: deviceID, err := libkb.NewDeviceID() if err != nil { return err } device := &libkb.Device{ ID: deviceID, Type: e.arg.DeviceType, } // create provisionee engine provisionee := NewKex2Provisionee(e.G(), device, secret.Secret()) var canceler func() // display secret and prompt for secret from X in a goroutine: go func() { sb := secret.Secret() arg := keybase1.DisplayAndPromptSecretArg{ Secret: sb[:], Phrase: secret.Phrase(), OtherDeviceType: provisionerType, } var contxt context.Context contxt, canceler = context.WithCancel(context.Background()) receivedSecret, err := ctx.ProvisionUI.DisplayAndPromptSecret(contxt, arg) if err != nil { // cancel provisionee run: provisionee.Cancel() e.G().Log.Warning("DisplayAndPromptSecret error: %s", err) } else if receivedSecret.Secret != nil && len(receivedSecret.Secret) > 0 { e.G().Log.Debug("received secret, adding to provisionee") var ks kex2.Secret copy(ks[:], receivedSecret.Secret) provisionee.AddSecret(ks) } else if len(receivedSecret.Phrase) > 0 { e.G().Log.Debug("received secret phrase, adding to provisionee") ks, err := libkb.NewKex2SecretFromPhrase(receivedSecret.Phrase) if err != nil { e.G().Log.Warning("DisplayAndPromptSecret error: %s", err) } else { provisionee.AddSecret(ks.Secret()) } } }() defer func() { if canceler != nil { e.G().Log.Debug("canceling DisplayAndPromptSecret call") canceler() } }() f := func(lctx libkb.LoginContext) error { // run provisionee ctx.LoginContext = lctx return RunEngine(provisionee, ctx) } if err := e.G().LoginState().ExternalFunc(f, "loginProvision.device - Run provisionee"); err != nil { return err } // need username, device name for ProvisionUI.ProvisioneeSuccess() e.username = provisionee.GetName() pdevice := provisionee.Device() if pdevice == nil { e.G().Log.Warning("nil provisionee device") } else if pdevice.Description == nil { e.G().Log.Warning("nil provisionee device description") } else { e.devname = *pdevice.Description } return nil }
// device provisions this device with an existing device using the // kex2 protocol. func (e *XLoginProvision) device(ctx *Context) error { provisionerType, err := ctx.ProvisionUI.ChooseDeviceType(context.TODO(), 0) if err != nil { return err } e.G().Log.Debug("provisioner device type: %v", provisionerType) // make a new secret: secret, err := libkb.NewKex2Secret() if err != nil { return err } e.G().Log.Debug("secret phrase: %s", secret.Phrase()) // make a new device: deviceID, err := libkb.NewDeviceID() if err != nil { return err } device := &libkb.Device{ ID: deviceID, Type: e.deviceType, } // create provisionee engine provisionee := NewKex2Provisionee(e.G(), device, secret.Secret()) var canceler func() // display secret and prompt for secret from X in a goroutine: go func() { sb := secret.Secret() arg := keybase1.DisplayAndPromptSecretArg{ Secret: sb[:], Phrase: secret.Phrase(), OtherDeviceType: provisionerType, } var contxt context.Context contxt, canceler = context.WithCancel(context.Background()) receivedSecret, err := ctx.ProvisionUI.DisplayAndPromptSecret(contxt, arg) if err != nil { // XXX ??? e.G().Log.Warning("DisplayAndPromptSecret error: %s", err) } else if receivedSecret != nil { var ks kex2.Secret copy(ks[:], receivedSecret) provisionee.AddSecret(ks) } }() defer func() { if canceler != nil { e.G().Log.Debug("canceling DisplayAndPromptSecret call") canceler() } }() // run provisionee if err := RunEngine(provisionee, ctx); err != nil { return err } return nil }
// Run starts the engine. func (e *DeviceAdd) Run(ctx *Context) (err error) { e.G().Log.Debug("+ DeviceAdd.Run()") defer func() { e.G().Log.Debug("- DeviceAdd.Run() -> %s", libkb.ErrToOk(err)) }() arg := keybase1.ChooseDeviceTypeArg{Kind: keybase1.ChooseType_NEW_DEVICE} provisioneeType, err := ctx.ProvisionUI.ChooseDeviceType(context.TODO(), arg) if err != nil { return err } e.G().Log.Debug("provisionee device type: %v", provisioneeType) // make a new secret: secret, err := libkb.NewKex2Secret() if err != nil { return err } e.G().Log.Debug("secret phrase received") // provisioner needs ppstream, and UI is confusing when it asks for // it at the same time as asking for the secret, so get it first // before prompting for the kex2 secret: pps, err := e.G().LoginState().GetPassphraseStream(ctx.SecretUI) if err != nil { return err } // create provisioner engine provisioner := NewKex2Provisioner(e.G(), secret.Secret(), pps) var canceler func() ctx.NetContext, canceler = context.WithCancel(ctx.NetContext) // display secret and prompt for secret from X in a goroutine: go func() { sb := secret.Secret() arg := keybase1.DisplayAndPromptSecretArg{ Secret: sb[:], Phrase: secret.Phrase(), OtherDeviceType: provisioneeType, } receivedSecret, err := ctx.ProvisionUI.DisplayAndPromptSecret(ctx.NetContext, arg) if err != nil { e.G().Log.Warning("DisplayAndPromptSecret error: %s", err) canceler() } else if receivedSecret.Secret != nil && len(receivedSecret.Secret) > 0 { e.G().Log.Debug("received secret, adding to provisioner") var ks kex2.Secret copy(ks[:], receivedSecret.Secret) provisioner.AddSecret(ks) } else if len(receivedSecret.Phrase) > 0 { e.G().Log.Debug("received secret phrase, adding to provisioner") ks, err := libkb.NewKex2SecretFromPhrase(receivedSecret.Phrase) if err != nil { e.G().Log.Warning("NewKex2SecretFromPhrase error: %s", err) canceler() } else { provisioner.AddSecret(ks.Secret()) } } }() defer func() { canceler() }() if err := RunEngine(provisioner, ctx); err != nil { if err == kex2.ErrHelloTimeout { err = libkb.CanceledError{M: "Failed to provision device: are you sure you typed the secret properly?"} } return err } // provisioning was successful, so the user has changed: e.G().NotifyRouter.HandleKeyfamilyChanged(e.G().Env.GetUID()) // TODO: Remove this after kbfs notification change complete e.G().NotifyRouter.HandleUserChanged(e.G().Env.GetUID()) return nil }
// device provisions this device with an existing device using the // kex2 protocol. func (e *XLoginProvision) device(ctx *Context) error { provisionerType, err := ctx.ProvisionUI.ChooseDeviceType(context.TODO(), 0) if err != nil { return err } e.G().Log.Debug("provisioner device type: %v", provisionerType) // make a new secret: secret, err := libkb.NewKex2Secret() if err != nil { return err } e.G().Log.Debug("secret phrase: %s", secret.Phrase()) // make a new device: deviceID, err := libkb.NewDeviceID() if err != nil { return err } device := &libkb.Device{ ID: deviceID, Type: e.arg.DeviceType, } // create provisionee engine provisionee := NewKex2Provisionee(e.G(), device, secret.Secret()) var canceler func() // display secret and prompt for secret from X in a goroutine: go func() { sb := secret.Secret() arg := keybase1.DisplayAndPromptSecretArg{ Secret: sb[:], Phrase: secret.Phrase(), OtherDeviceType: provisionerType, } var contxt context.Context contxt, canceler = context.WithCancel(context.Background()) receivedSecret, err := ctx.ProvisionUI.DisplayAndPromptSecret(contxt, arg) if err != nil { // could cancel provisionee run here? e.G().Log.Warning("DisplayAndPromptSecret error: %s", err) } else if receivedSecret != nil && len(receivedSecret) > 0 { var ks kex2.Secret copy(ks[:], receivedSecret) provisionee.AddSecret(ks) } }() defer func() { if canceler != nil { e.G().Log.Debug("canceling DisplayAndPromptSecret call") canceler() } }() // run provisionee if err := RunEngine(provisionee, ctx); err != nil { return err } if err := e.G().LoginState().LocalSession(func(s *libkb.Session) { s.SetDeviceProvisioned(deviceID) }, "XLoginProvision - device"); err != nil { return err } // need username, device name for ProvisionUI.ProvisioneeSuccess() e.username = provisionee.GetName() pdevice := provisionee.Device() if pdevice == nil { e.G().Log.Warning("nil provisionee device") } else if pdevice.Description == nil { e.G().Log.Warning("nil provisionee device description") } else { e.devname = *pdevice.Description } return nil }