1// Copyright 2017 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package engine
5
6import (
7	"time"
8
9	"github.com/keybase/client/go/libkb"
10	"github.com/keybase/client/go/protocol/keybase1"
11)
12
13// Bootstrap is an engine.
14type Bootstrap struct {
15	libkb.Contextified
16	status keybase1.BootstrapStatus
17}
18
19// NewBootstrap creates a Bootstrap engine.
20func NewBootstrap(g *libkb.GlobalContext) *Bootstrap {
21	return &Bootstrap{
22		Contextified: libkb.NewContextified(g),
23	}
24}
25
26// Name is the unique engine name.
27func (e *Bootstrap) Name() string {
28	return "Bootstrap"
29}
30
31// GetPrereqs returns the engine prereqs.
32func (e *Bootstrap) Prereqs() Prereqs {
33	return Prereqs{}
34}
35
36// RequiredUIs returns the required UIs.
37func (e *Bootstrap) RequiredUIs() []libkb.UIKind {
38	return []libkb.UIKind{}
39}
40
41// SubConsumers returns the other UI consumers for this engine.
42func (e *Bootstrap) SubConsumers() []libkb.UIConsumer {
43	return nil
44}
45
46func (e *Bootstrap) lookupFullname(m libkb.MetaContext, uv keybase1.UserVersion) {
47	pkgs, err := m.G().UIDMapper.MapUIDsToUsernamePackagesOffline(m.Ctx(), m.G(), []keybase1.UID{uv.Uid}, time.Duration(0))
48	if err != nil {
49		m.Warning("UID -> Username failed lookup: %s", err)
50		return
51	}
52	pkg := pkgs[0]
53	if pkg.NormalizedUsername.IsNil() || pkg.FullName == nil {
54		m.Debug("Empty username for UID=%s", uv.Uid)
55		return
56	}
57	if !uv.EldestSeqno.Eq(pkg.FullName.EldestSeqno) {
58		m.Debug("Wrong eldest for username package; got %d but wanted %d", pkg.FullName.EldestSeqno, uv.EldestSeqno)
59		return
60	}
61	e.status.Fullname = pkg.FullName.FullName
62}
63
64// Run starts the engine.
65func (e *Bootstrap) Run(m libkb.MetaContext) error {
66	e.status.Registered = e.signedUp(m)
67
68	// if any Login engine worked previously, then ActiveDevice will
69	// be valid:
70	validActiveDevice := m.G().ActiveDevice.Valid()
71
72	// the only way for ActiveDevice to be valid is to be logged in
73	// (and provisioned)
74	e.status.LoggedIn = validActiveDevice
75	if !e.status.LoggedIn {
76		m.Debug("Bootstrap: not logged in")
77		return nil
78	}
79	m.Debug("Bootstrap: logged in (valid active device)")
80
81	var uv keybase1.UserVersion
82	uv, e.status.DeviceID, e.status.DeviceName, _, _ = e.G().ActiveDevice.AllFields()
83	e.status.Uid = uv.Uid
84	e.status.Username = e.G().ActiveDevice.Username(m).String()
85	m.Debug("Bootstrap status: uid=%s, username=%s, deviceID=%s, deviceName=%s", e.status.Uid, e.status.Username, e.status.DeviceID, e.status.DeviceName)
86
87	if chatHelper := e.G().ChatHelper; chatHelper != nil {
88		e.status.UserReacjis = chatHelper.UserReacjis(m.Ctx(), e.status.Uid.ToBytes())
89	}
90
91	e.lookupFullname(m, uv)
92
93	return nil
94}
95
96// signedUp is true if there's a uid in config.json.
97func (e *Bootstrap) signedUp(m libkb.MetaContext) bool {
98	cr := m.G().Env.GetConfig()
99	if cr == nil {
100		return false
101	}
102	if uid := cr.GetUID(); uid.Exists() {
103		return true
104	}
105	return false
106}
107
108func (e *Bootstrap) Status() keybase1.BootstrapStatus {
109	return e.status
110}
111