<commit_before>package engine

import (
	"errors"
	"fmt"

	"github.com/keybase/go/libkb"
	keybase_1 "github.com/keybase/protocol/go"
)

type Doctor struct {
	user       *libkb.User
	docUI      libkb.DoctorUI
	secretUI   libkb.SecretUI
	logUI      libkb.LogUI
	identifyUI libkb.IdentifyUI

	signingKey libkb.GenericKey
}

func NewDoctor(docUI libkb.DoctorUI, secUI libkb.SecretUI, logUI libkb.LogUI, identifyUI libkb.IdentifyUI) *Doctor {
	return &Doctor{docUI: docUI, secretUI: secUI, logUI: logUI, identifyUI: identifyUI}
}

func (d *Doctor) LoginCheckup(u *libkb.User) error {
	d.user = u

	// This can fail, but we'll warn if it does.
	d.syncSecrets()

	if err := d.checkUID(); err != nil {
		return err
	}

	if err := d.checkKeys(); err != nil {
		return err
	}
	return nil
}

// checkUID makes sure that we've verified our own UID.  This might result in a
// self-tracking operation.
func (d *Doctor) checkUID() (err error) {
	uid := d.user.GetUid()

	if !d.user.HasActiveKey() {
		d.logUI.Debug("Skipping checkUID due to no active key")
	} else if u2 := G.Env.GetVerifiedUID(); u2 != nil && !u2.Eq(uid) {
		err = libkb.UidMismatchError{Msg: fmt.Sprintf("Got wrong uid; wanted %s but got %s", uid, u2)}
	} else if u2 == nil && d.identifyUI != nil {
		d.logUI.Warning("Verifying your UID...")
		err = d.user.IdentifySelf(d.identifyUI)
		if err == nil {
			d.logUI.Warning("Setting UID to %s", uid)
		}
	}
	return err
}

func (d *Doctor) syncSecrets() (err error) {
	if err = G.SecretSyncer.Load(d.user.GetUid()); err != nil {
		G.Log.Warning("Problem syncing secrets from server: %s", err.Error())
	}
	return err
}

func (d *Doctor) checkKeys() error {
	kf := d.user.GetKeyFamily()
	if kf == nil {
		return d.addBasicKeys()
	}
	if kf.GetEldest() == nil {
		return d.addBasicKeys()
	}

	// they have at least one key

	if d.user.HasDeviceInCurrentInstall() {
		// they have a device sibkey for this device
		return nil
	}

	// make sure secretsyncer loaded
	if err := G.SecretSyncer.Load(d.user.GetUid()); err != nil {
		return err
	}

	if G.SecretSyncer.HasActiveDevice() {
		// they have at least one device, just not this device...
		return d.deviceSign()
	}

	// they don't have any devices.  use their detkey to sign a new device.
	dk, err := d.detkey()
	if err != nil {
		return err
	}<commit_msg>found unimplemented scenario:  web user with pgp keys, no detkey.<commit_after>package engine

import (
	"errors"
	"fmt"

	"github.com/keybase/go/libkb"
	keybase_1 "github.com/keybase/protocol/go"
)

type Doctor struct {
	user       *libkb.User
	docUI      libkb.DoctorUI
	secretUI   libkb.SecretUI
	logUI      libkb.LogUI
	identifyUI libkb.IdentifyUI

	signingKey libkb.GenericKey
}

func NewDoctor(docUI libkb.DoctorUI, secUI libkb.SecretUI, logUI libkb.LogUI, identifyUI libkb.IdentifyUI) *Doctor {
	return &Doctor{docUI: docUI, secretUI: secUI, logUI: logUI, identifyUI: identifyUI}
}

func (d *Doctor) LoginCheckup(u *libkb.User) error {
	d.user = u

	// This can fail, but we'll warn if it does.
	d.syncSecrets()

	if err := d.checkUID(); err != nil {
		return err
	}

	if err := d.checkKeys(); err != nil {
		return err
	}
	return nil
}

// checkUID makes sure that we've verified our own UID.  This might result in a
// self-tracking operation.
func (d *Doctor) checkUID() (err error) {
	uid := d.user.GetUid()

	if !d.user.HasActiveKey() {
		d.logUI.Debug("Skipping checkUID due to no active key")
	} else if u2 := G.Env.GetVerifiedUID(); u2 != nil && !u2.Eq(uid) {
		err = libkb.UidMismatchError{Msg: fmt.Sprintf("Got wrong uid; wanted %s but got %s", uid, u2)}
	} else if u2 == nil && d.identifyUI != nil {
		d.logUI.Warning("Verifying your UID...")
		err = d.user.IdentifySelf(d.identifyUI)
		if err == nil {
			d.logUI.Warning("Setting UID to %s", uid)
		}
	}
	return err
}

func (d *Doctor) syncSecrets() (err error) {
	if err = G.SecretSyncer.Load(d.user.GetUid()); err != nil {
		G.Log.Warning("Problem syncing secrets from server: %s", err.Error())
	}
	return err
}

func (d *Doctor) checkKeys() error {
	kf := d.user.GetKeyFamily()
	if kf == nil {
		return d.addBasicKeys()
	}
	if kf.GetEldest() == nil {
		return d.addBasicKeys()
	}

	// they have at least one key

	if d.user.HasDeviceInCurrentInstall() {
		// they have a device sibkey for this device
		return nil
	}

	// make sure secretsyncer loaded
	if err := G.SecretSyncer.Load(d.user.GetUid()); err != nil {
		return err
	}

	if G.SecretSyncer.HasActiveDevice() {
		// they have at least one device, just not this device...
		return d.deviceSign()
	}

	// they don't have any devices.

	dk, err := d.detkey()
	if err != nil {
		if _, ok := err.(libkb.NotFoundError); ok {
			// they don't have a detkey, so add basic keys.
			// they can get to this point if they sign up on the web,
			// add a pgp key.  With that situation, they have keys
			// so the check above for a nil key family doesn't apply.
			//	return d.addBasicKeys()

			// XXX this scenario isn't currently implemented.  PC working on it.
			return fmt.Errorf("This scenario isn't implemented yet.  Presumably you are logging in with a user that has pgp keys and no detkey on a new device.  PC currently implementing this...")
		}
		return err
	}

	// use their detkey to sign this device
{'fraction_non_alphanumeric': 0.1303683909142966, 'fraction_numerical': 0.0022905134567665587, 'mean_word_length': 3.2497972424979724, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5965928', 'n_tokens_mistral': 2007, 'n_tokens_neox': 1892, 'n_words': 596}