1// Copyright 2017 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4// PerUserKeyUpgrade creates a per-user-key for the active user
5// if they do not already have one.
6// It adds a per-user-key link to the sigchain and adds the key to the local keyring.
7package engine
8
9import (
10	"fmt"
11
12	"github.com/keybase/client/go/libkb"
13)
14
15// PerUserKeyUpgrade is an engine.
16type PerUserKeyUpgrade struct {
17	libkb.Contextified
18	args      *PerUserKeyUpgradeArgs
19	DidNewKey bool
20}
21
22type PerUserKeyUpgradeArgs struct{}
23
24// NewPerUserKeyUpgrade creates a PerUserKeyUpgrade engine.
25func NewPerUserKeyUpgrade(g *libkb.GlobalContext, args *PerUserKeyUpgradeArgs) *PerUserKeyUpgrade {
26	return &PerUserKeyUpgrade{
27		args:         args,
28		Contextified: libkb.NewContextified(g),
29	}
30}
31
32// Name is the unique engine name.
33func (e *PerUserKeyUpgrade) Name() string {
34	return "PerUserKeyUpgrade"
35}
36
37// GetPrereqs returns the engine prereqs.
38func (e *PerUserKeyUpgrade) Prereqs() Prereqs {
39	return Prereqs{
40		Device: true,
41	}
42}
43
44// RequiredUIs returns the required UIs.
45func (e *PerUserKeyUpgrade) RequiredUIs() []libkb.UIKind {
46	return []libkb.UIKind{}
47}
48
49// SubConsumers returns the other UI consumers for this engine.
50func (e *PerUserKeyUpgrade) SubConsumers() []libkb.UIConsumer {
51	return []libkb.UIConsumer{&PerUserKeyRoll{}}
52}
53
54// Run starts the engine.
55func (e *PerUserKeyUpgrade) Run(m libkb.MetaContext) (err error) {
56	defer m.Trace("PerUserKeyUpgrade", &err)()
57	return e.inner(m)
58}
59
60func (e *PerUserKeyUpgrade) inner(m libkb.MetaContext) error {
61	if !m.G().Env.GetUpgradePerUserKey() {
62		return fmt.Errorf("per-user-key upgrade is disabled")
63	}
64
65	m.Debug("PerUserKeyUpgrade load self")
66
67	uid := m.G().GetMyUID()
68	if uid.IsNil() {
69		return libkb.NoUIDError{}
70	}
71
72	m.Debug("PerUserKeyUpgrade upgrading: %d", uid)
73
74	loadArg := libkb.NewLoadUserArgWithMetaContext(m).
75		WithUID(uid).
76		WithSelf(true).
77		WithPublicKeyOptional()
78	upak, me, err := m.G().GetUPAKLoader().LoadV2(loadArg)
79	if err != nil {
80		return err
81	}
82	// `me` could be nil. Use the upak for quick checks and then pass maybe-nil `me` to the next engine.
83
84	m.Debug("PerUserKeyUpgrade check for key")
85	if len(upak.Current.PerUserKeys) > 0 {
86		m.Debug("PerUserKeyUpgrade already has per-user-key")
87		e.DidNewKey = false
88		return nil
89	}
90	m.Debug("PerUserKeyUpgrade has no per-user-key")
91
92	// Make the key
93	arg := &PerUserKeyRollArgs{
94		Me: me,
95	}
96	eng := NewPerUserKeyRoll(m.G(), arg)
97	err = RunEngine2(m, eng)
98	e.DidNewKey = eng.DidNewKey
99
100	return err
101}
102