1// Copyright 2017 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4// PerUserKeyUpgradeBackground runs PerUserKeyUpgrade in the background once in a while.
5// It brings users without per-user-keys up to having them.
6// Note that this engine is long-lived and potentially has to deal with being
7// logged out and logged in as a different user, etc.
8
9package engine
10
11import (
12	"sync"
13	"time"
14
15	"github.com/keybase/client/go/libkb"
16)
17
18var PerUserKeyUpgradeBackgroundSettings = BackgroundTaskSettings{
19	Start:        30 * time.Second, // Wait after starting the app
20	StartStagger: 10 * time.Second, // Wait an additional random amount.
21	WakeUp:       10 * time.Second, // Additional delay after waking from sleep.
22	Interval:     1 * time.Hour,    // Wait between checks
23	Limit:        5 * time.Minute,  // Time limit on each round
24}
25
26// PerUserKeyUpgradeBackground is an engine.
27type PerUserKeyUpgradeBackground struct {
28	libkb.Contextified
29	sync.Mutex
30
31	args *PerUserKeyUpgradeBackgroundArgs
32	task *BackgroundTask
33}
34
35type PerUserKeyUpgradeBackgroundArgs struct {
36	// Channels used for testing. Normally nil.
37	testingMetaCh     chan<- string
38	testingRoundResCh chan<- error
39}
40
41// NewPerUserKeyUpgradeBackground creates a PerUserKeyUpgradeBackground engine.
42func NewPerUserKeyUpgradeBackground(g *libkb.GlobalContext, args *PerUserKeyUpgradeBackgroundArgs) *PerUserKeyUpgradeBackground {
43	task := NewBackgroundTask(g, &BackgroundTaskArgs{
44		Name:     "PerUserKeyUpgradeBackground",
45		F:        PerUserKeyUpgradeBackgroundRound,
46		Settings: PerUserKeyUpgradeBackgroundSettings,
47
48		testingMetaCh:     args.testingMetaCh,
49		testingRoundResCh: args.testingRoundResCh,
50	})
51	return &PerUserKeyUpgradeBackground{
52		Contextified: libkb.NewContextified(g),
53		args:         args,
54		// Install the task early so that Shutdown can be called before RunEngine.
55		task: task,
56	}
57}
58
59// Name is the unique engine name.
60func (e *PerUserKeyUpgradeBackground) Name() string {
61	return "PerUserKeyUpgradeBackground"
62}
63
64// GetPrereqs returns the engine prereqs.
65func (e *PerUserKeyUpgradeBackground) Prereqs() Prereqs {
66	return Prereqs{}
67}
68
69// RequiredUIs returns the required UIs.
70func (e *PerUserKeyUpgradeBackground) RequiredUIs() []libkb.UIKind {
71	return []libkb.UIKind{}
72}
73
74// SubConsumers returns the other UI consumers for this engine.
75func (e *PerUserKeyUpgradeBackground) SubConsumers() []libkb.UIConsumer {
76	return []libkb.UIConsumer{&PerUserKeyUpgrade{}}
77}
78
79// Run starts the engine.
80// Returns immediately, kicks off a background goroutine.
81func (e *PerUserKeyUpgradeBackground) Run(m libkb.MetaContext) (err error) {
82	return RunEngine2(m, e.task)
83}
84
85func (e *PerUserKeyUpgradeBackground) Shutdown() {
86	e.task.Shutdown()
87}
88
89func PerUserKeyUpgradeBackgroundRound(m libkb.MetaContext) error {
90	if !m.G().Env.GetUpgradePerUserKey() {
91		m.Debug("PerUserKeyUpgradeBackground disabled")
92		return nil
93	}
94
95	if !m.G().LocalSigchainGuard().IsAvailable(m.Ctx(), "PerUserKeyUpgradeBackgroundRound") {
96		m.Debug("PerUserKeyUpgradeBackground yielding to guard")
97		return nil
98	}
99
100	if m.G().ConnectivityMonitor.IsConnected(m.Ctx()) == libkb.ConnectivityMonitorNo {
101		m.Debug("PerUserKeyUpgradeBackground giving up offline")
102		return nil
103	}
104
105	// Do a fast local check to see if our work is done.
106	pukring, err := m.G().GetPerUserKeyring(m.Ctx())
107	if err != nil {
108		m.Debug("PerUserKeyUpgradeBackground error getting keyring: %v", err)
109		// ignore error
110	}
111	if err == nil {
112		if pukring.HasAnyKeys() {
113			m.Debug("PerUserKeyUpgradeBackground already has keys")
114			return nil
115		}
116	}
117
118	arg := &PerUserKeyUpgradeArgs{}
119	eng := NewPerUserKeyUpgrade(m.G(), arg)
120	err = RunEngine2(m, eng)
121	return err
122}
123