1package engine
2
3import (
4	"context"
5	"time"
6
7	"github.com/keybase/client/go/libkb"
8	keybase1 "github.com/keybase/client/go/protocol/keybase1"
9)
10
11type LogoutEngine struct {
12	options libkb.LogoutOptions
13}
14
15func NewLogout(options libkb.LogoutOptions) *LogoutEngine {
16	return &LogoutEngine{options: options}
17}
18func (e *LogoutEngine) Name() string                     { return "Logout" }
19func (e *LogoutEngine) Prereqs() Prereqs                 { return Prereqs{} }
20func (e *LogoutEngine) RequiredUIs() []libkb.UIKind      { return []libkb.UIKind{} }
21func (e *LogoutEngine) SubConsumers() []libkb.UIConsumer { return []libkb.UIConsumer{} }
22
23func (e *LogoutEngine) filterLoggedIn(accounts []keybase1.
24	ConfiguredAccount) (ret []libkb.NormalizedUsername) {
25	for _, acct := range accounts {
26		if acct.HasStoredSecret {
27			ret = append(ret, libkb.NewNormalizedUsername(acct.Username))
28		}
29	}
30	return ret
31}
32
33// Tell the user what accounts they still have secrets stored for,
34// so they don't think they are fully logged out of everything.
35func (e *LogoutEngine) printSwitchInfo(mctx libkb.MetaContext) (err error) {
36	defer mctx.Trace("Logout#printSwitchInfo", &err)()
37	ctx, cancel := context.WithTimeout(mctx.Ctx(), time.Second*3)
38	defer cancel()
39	accounts, err := mctx.G().GetConfiguredAccounts(ctx)
40	if err != nil {
41		return err
42	}
43	loggedInAccounts := e.filterLoggedIn(accounts)
44
45	if len(loggedInAccounts) > 0 {
46		maybePlural := ""
47		if len(loggedInAccounts) > 1 {
48			maybePlural = "s"
49		}
50		accountsList := ""
51		for idx, acct := range loggedInAccounts {
52			accountsList += string(acct)
53			if idx < len(loggedInAccounts)-2 {
54				accountsList += ", "
55			}
56			if idx == len(loggedInAccounts)-2 {
57				accountsList += " and "
58			}
59
60		}
61		mctx.Info(
62			"You can still sign in to keybase account%s %s"+
63				" without a password.", maybePlural, accountsList)
64	}
65	return nil
66}
67
68func (e *LogoutEngine) Run(mctx libkb.MetaContext) (err error) {
69	defer mctx.Trace("Logout#Run", &err)()
70	err = mctx.LogoutWithOptions(e.options)
71	if err != nil {
72		return err
73	}
74
75	if e.options.KeepSecrets {
76		err = mctx.G().Env.GetConfigWriter().SetStayLoggedOut(true)
77		if err != nil {
78			mctx.Warning("Could not save logged out state to config.json: %v", err)
79		}
80	}
81
82	if err := e.printSwitchInfo(mctx); err != nil {
83		// We don't care if this doesn't work here - user is logged
84		// out at this point. LogoutEngine is considered successful.
85		mctx.Info("You may still have secrets stored for one or more accounts"+
86			": %s", err)
87	}
88	return nil
89}
90
91var _ Engine2 = (*LogoutEngine)(nil)
92