1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package libkb
5
6import (
7	"fmt"
8	"os"
9	"os/user"
10	"path/filepath"
11	"runtime"
12	"strconv"
13	"strings"
14	"sync"
15	"time"
16
17	logger "github.com/keybase/client/go/logger"
18	keybase1 "github.com/keybase/client/go/protocol/keybase1"
19	"github.com/keybase/client/go/systemd"
20	"github.com/syndtr/goleveldb/leveldb/opt"
21)
22
23type NullConfiguration struct{}
24
25func (n NullConfiguration) GetHome() string                                                { return "" }
26func (n NullConfiguration) GetMobileSharedHome() string                                    { return "" }
27func (n NullConfiguration) GetServerURI() (string, error)                                  { return "", nil }
28func (n NullConfiguration) GetConfigFilename() string                                      { return "" }
29func (n NullConfiguration) GetUpdaterConfigFilename() string                               { return "" }
30func (n NullConfiguration) GetGUIConfigFilename() string                                   { return "" }
31func (n NullConfiguration) GetDeviceCloneStateFilename() string                            { return "" }
32func (n NullConfiguration) GetSessionFilename() string                                     { return "" }
33func (n NullConfiguration) GetDbFilename() string                                          { return "" }
34func (n NullConfiguration) GetChatDbFilename() string                                      { return "" }
35func (n NullConfiguration) GetPvlKitFilename() string                                      { return "" }
36func (n NullConfiguration) GetParamProofKitFilename() string                               { return "" }
37func (n NullConfiguration) GetExternalURLKitFilename() string                              { return "" }
38func (n NullConfiguration) GetProveBypass() (bool, bool)                                   { return false, false }
39func (n NullConfiguration) GetUsername() NormalizedUsername                                { return NormalizedUsername("") }
40func (n NullConfiguration) GetEmail() string                                               { return "" }
41func (n NullConfiguration) GetProxy() string                                               { return "" }
42func (n NullConfiguration) GetProxyType() string                                           { return "" }
43func (n NullConfiguration) IsCertPinningEnabled() bool                                     { return true }
44func (n NullConfiguration) GetGpgHome() string                                             { return "" }
45func (n NullConfiguration) GetBundledCA(h string) string                                   { return "" }
46func (n NullConfiguration) GetUserCacheMaxAge() (time.Duration, bool)                      { return 0, false }
47func (n NullConfiguration) GetProofCacheSize() (int, bool)                                 { return 0, false }
48func (n NullConfiguration) GetProofCacheLongDur() (time.Duration, bool)                    { return 0, false }
49func (n NullConfiguration) GetProofCacheMediumDur() (time.Duration, bool)                  { return 0, false }
50func (n NullConfiguration) GetProofCacheShortDur() (time.Duration, bool)                   { return 0, false }
51func (n NullConfiguration) GetLinkCacheSize() (int, bool)                                  { return 0, false }
52func (n NullConfiguration) GetLinkCacheCleanDur() (time.Duration, bool)                    { return 0, false }
53func (n NullConfiguration) GetUPAKCacheSize() (int, bool)                                  { return 0, false }
54func (n NullConfiguration) GetUIDMapFullNameCacheSize() (int, bool)                        { return 0, false }
55func (n NullConfiguration) GetPayloadCacheSize() (int, bool)                               { return 0, false }
56func (n NullConfiguration) GetMerkleKIDs() []string                                        { return nil }
57func (n NullConfiguration) GetCodeSigningKIDs() []string                                   { return nil }
58func (n NullConfiguration) GetPinentry() string                                            { return "" }
59func (n NullConfiguration) GetUID() (ret keybase1.UID)                                     { return }
60func (n NullConfiguration) GetGpg() string                                                 { return "" }
61func (n NullConfiguration) GetGpgOptions() []string                                        { return nil }
62func (n NullConfiguration) GetPGPFingerprint() *PGPFingerprint                             { return nil }
63func (n NullConfiguration) GetSecretKeyringTemplate() string                               { return "" }
64func (n NullConfiguration) GetSalt() []byte                                                { return nil }
65func (n NullConfiguration) GetSocketFile() string                                          { return "" }
66func (n NullConfiguration) GetPidFile() string                                             { return "" }
67func (n NullConfiguration) GetStandalone() (bool, bool)                                    { return false, false }
68func (n NullConfiguration) GetLocalRPCDebug() string                                       { return "" }
69func (n NullConfiguration) GetTimers() string                                              { return "" }
70func (n NullConfiguration) GetDeviceID() keybase1.DeviceID                                 { return "" }
71func (n NullConfiguration) GetDeviceIDForUsername(un NormalizedUsername) keybase1.DeviceID { return "" }
72func (n NullConfiguration) GetDeviceIDForUID(u keybase1.UID) keybase1.DeviceID             { return "" }
73func (n NullConfiguration) GetProxyCACerts() ([]string, error)                             { return nil, nil }
74func (n NullConfiguration) GetUsernameForUID(u keybase1.UID) NormalizedUsername {
75	return NormalizedUsername("")
76}
77func (n NullConfiguration) GetUIDForUsername(u NormalizedUsername) keybase1.UID {
78	return keybase1.UID("")
79}
80func (n NullConfiguration) GetStayLoggedOut() (bool, bool)                  { return false, false }
81func (n NullConfiguration) GetAutoFork() (bool, bool)                       { return false, false }
82func (n NullConfiguration) GetRunMode() (RunMode, error)                    { return NoRunMode, nil }
83func (n NullConfiguration) GetNoAutoFork() (bool, bool)                     { return false, false }
84func (n NullConfiguration) GetLogFile() string                              { return "" }
85func (n NullConfiguration) GetEKLogFile() string                            { return "" }
86func (n NullConfiguration) GetPerfLogFile() string                          { return "" }
87func (n NullConfiguration) GetGUILogFile() string                           { return "" }
88func (n NullConfiguration) GetUseDefaultLogFile() (bool, bool)              { return false, false }
89func (n NullConfiguration) GetUseRootConfigFile() (bool, bool)              { return false, false }
90func (n NullConfiguration) GetLogPrefix() string                            { return "" }
91func (n NullConfiguration) GetScraperTimeout() (time.Duration, bool)        { return 0, false }
92func (n NullConfiguration) GetAPITimeout() (time.Duration, bool)            { return 0, false }
93func (n NullConfiguration) GetTorMode() (TorMode, error)                    { return TorNone, nil }
94func (n NullConfiguration) GetTorHiddenAddress() string                     { return "" }
95func (n NullConfiguration) GetTorProxy() string                             { return "" }
96func (n NullConfiguration) GetUpdatePreferenceAuto() (bool, bool)           { return false, false }
97func (n NullConfiguration) GetUpdatePreferenceSnoozeUntil() keybase1.Time   { return keybase1.Time(0) }
98func (n NullConfiguration) GetUpdateLastChecked() keybase1.Time             { return keybase1.Time(0) }
99func (n NullConfiguration) GetUpdatePreferenceSkip() string                 { return "" }
100func (n NullConfiguration) GetUpdateURL() string                            { return "" }
101func (n NullConfiguration) GetUpdateDisabled() (bool, bool)                 { return false, false }
102func (n NullConfiguration) GetVDebugSetting() string                        { return "" }
103func (n NullConfiguration) GetLocalTrackMaxAge() (time.Duration, bool)      { return 0, false }
104func (n NullConfiguration) GetGregorURI() string                            { return "" }
105func (n NullConfiguration) GetGregorSaveInterval() (time.Duration, bool)    { return 0, false }
106func (n NullConfiguration) GetGregorPingInterval() (time.Duration, bool)    { return 0, false }
107func (n NullConfiguration) GetGregorPingTimeout() (time.Duration, bool)     { return 0, false }
108func (n NullConfiguration) GetChatDelivererInterval() (time.Duration, bool) { return 0, false }
109func (n NullConfiguration) GetGregorDisabled() (bool, bool)                 { return false, false }
110func (n NullConfiguration) GetSecretStorePrimingDisabled() (bool, bool)     { return false, false }
111func (n NullConfiguration) GetMountDir() string                             { return "" }
112func (n NullConfiguration) GetMountDirDefault() string                      { return "" }
113func (n NullConfiguration) GetBGIdentifierDisabled() (bool, bool)           { return false, false }
114func (n NullConfiguration) GetFeatureFlags() (FeatureFlags, error)          { return FeatureFlags{}, nil }
115func (n NullConfiguration) GetAppType() AppType                             { return NoAppType }
116func (n NullConfiguration) IsMobileExtension() (bool, bool)                 { return false, false }
117func (n NullConfiguration) GetSlowGregorConn() (bool, bool)                 { return false, false }
118func (n NullConfiguration) GetReadDeletedSigChain() (bool, bool)            { return false, false }
119func (n NullConfiguration) GetRememberPassphrase(NormalizedUsername) (bool, bool) {
120	return false, false
121}
122func (n NullConfiguration) GetLevelDBNumFiles() (int, bool)                { return 0, false }
123func (n NullConfiguration) GetLevelDBWriteBufferMB() (int, bool)           { return 4, false }
124func (n NullConfiguration) GetChatInboxSourceLocalizeThreads() (int, bool) { return 1, false }
125func (n NullConfiguration) GetAttachmentHTTPStartPort() (int, bool)        { return 0, false }
126func (n NullConfiguration) GetAttachmentDisableMulti() (bool, bool)        { return false, false }
127func (n NullConfiguration) GetDisableTeamAuditor() (bool, bool)            { return false, false }
128func (n NullConfiguration) GetDisableMerkleAuditor() (bool, bool)          { return false, false }
129func (n NullConfiguration) GetDisableSearchIndexer() (bool, bool)          { return false, false }
130func (n NullConfiguration) GetDisableBgConvLoader() (bool, bool)           { return false, false }
131func (n NullConfiguration) GetDisableTeamBoxAuditor() (bool, bool)         { return false, false }
132func (n NullConfiguration) GetDisableEKBackgroundKeygen() (bool, bool)     { return false, false }
133func (n NullConfiguration) GetEnableBotLiteMode() (bool, bool)             { return false, false }
134func (n NullConfiguration) GetExtraNetLogging() (bool, bool)               { return false, false }
135func (n NullConfiguration) GetForceLinuxKeyring() (bool, bool)             { return false, false }
136func (n NullConfiguration) GetForceSecretStoreFile() (bool, bool)          { return false, false }
137func (n NullConfiguration) GetRuntimeStatsEnabled() (bool, bool)           { return false, false }
138func (n NullConfiguration) GetPassphraseState() *keybase1.PassphraseState  { return nil }
139func (n NullConfiguration) GetPassphraseStateForUsername(NormalizedUsername) *keybase1.PassphraseState {
140	return nil
141}
142
143func (n NullConfiguration) GetBug3964RepairTime(NormalizedUsername) (time.Time, error) {
144	return time.Time{}, nil
145}
146func (n NullConfiguration) GetUserConfig() (*UserConfig, error) { return nil, nil }
147func (n NullConfiguration) GetUserConfigForUsername(s NormalizedUsername) (*UserConfig, error) {
148	return nil, nil
149}
150func (n NullConfiguration) GetGString(string) string          { return "" }
151func (n NullConfiguration) GetString(string) string           { return "" }
152func (n NullConfiguration) GetBool(string, bool) (bool, bool) { return false, false }
153
154func (n NullConfiguration) GetAllUsernames() (NormalizedUsername, []NormalizedUsername, error) {
155	return NormalizedUsername(""), nil, nil
156}
157func (n NullConfiguration) GetAllUserConfigs() (*UserConfig, []UserConfig, error) {
158	return nil, nil, nil
159}
160
161func (n NullConfiguration) GetDebug() (bool, bool)            { return false, false }
162func (n NullConfiguration) GetDebugJourneycard() (bool, bool) { return false, false }
163func (n NullConfiguration) GetDisplayRawUntrustedOutput() (bool, bool) {
164	return false, false
165}
166func (n NullConfiguration) GetLogFormat() string {
167	return ""
168}
169func (n NullConfiguration) GetAPIDump() (bool, bool) {
170	return false, false
171}
172func (n NullConfiguration) GetNoPinentry() (bool, bool) {
173	return false, false
174}
175
176func (n NullConfiguration) GetStringAtPath(string) (string, bool) {
177	return "", false
178}
179func (n NullConfiguration) GetInterfaceAtPath(string) (interface{}, error) {
180	return nil, nil
181}
182
183func (n NullConfiguration) GetBoolAtPath(string) (bool, bool) {
184	return false, false
185}
186
187func (n NullConfiguration) GetIntAtPath(string) (int, bool) {
188	return 0, false
189}
190
191func (n NullConfiguration) GetFloatAtPath(string) (float64, bool) {
192	return 0, false
193}
194
195func (n NullConfiguration) GetNullAtPath(string) bool {
196	return false
197}
198
199func (n NullConfiguration) GetSecurityAccessGroupOverride() (bool, bool) {
200	return false, false
201}
202
203func (n NullConfiguration) GetAndroidInstallReferrerChecked() bool { return false }
204
205type TestParameters struct {
206	ConfigFilename   string
207	Home             string
208	MobileSharedHome string
209	GPG              string
210	GPGHome          string
211	GPGOptions       []string
212	Debug            bool
213	// Whether we are in Devel Mode
214	Devel bool
215	// If we're in dev mode, the name for this test, with a random
216	// suffix.
217	DevelName                string
218	DevelPrefix              string // when in test - name for the test without suffix.
219	RuntimeDir               string
220	DisableUpgradePerUserKey bool
221	EnvironmentFeatureFlags  FeatureFlags
222
223	// set to true to use production run mode in tests
224	UseProductionRunMode bool
225
226	// whether LogoutIfRevoked check should be skipped to avoid races
227	// during resets.
228	SkipLogoutIfRevokedCheck bool
229
230	// On if, in test, we want to skip sending system chat messages
231	SkipSendingSystemChatMessages bool
232
233	// If we need to use the real clock for NIST generation (as in really
234	// whacky tests liks TestRekey).
235	UseTimeClockForNISTs bool
236
237	// TeamNoHeadMerkleStore is used for testing to emulate older clients
238	// that didn't store the head merkle sequence to team chain state. We
239	// have an upgrade path in the code that we'd like to test.
240	TeamNoHeadMerkleStore bool
241
242	// TeamSkipAudit is on because some team chains are "canned" and therefore
243	// might point off of the merkle sequence in the database. So it's just
244	// easiest to skip the audit in those cases.
245	TeamSkipAudit bool
246
247	// NoGregor is on if we want to test the service without any gregor conection
248	NoGregor bool
249
250	// TeamAuditParams can be customized if we want to control the behavior
251	// of audits deep in a test
252	TeamAuditParams *TeamAuditParams
253
254	// Toggle if we want to try to 'prime' the secret store before using it.
255	SecretStorePrimingDisabled bool
256
257	// Extra headers for API
258	APIHeaders map[string]string
259}
260
261func (tp TestParameters) GetDebug() (bool, bool) {
262	if tp.Debug {
263		return true, true
264	}
265	return false, false
266}
267
268func (tp TestParameters) GetNoGregor() (bool, bool) {
269	if tp.NoGregor {
270		return true, true
271	}
272	return false, false
273}
274
275func (tp TestParameters) GetSecretStorePrimingDisabled() (bool, bool) {
276	if tp.SecretStorePrimingDisabled {
277		return true, true
278	}
279	return false, false
280}
281
282type Env struct {
283	sync.RWMutex
284	cmd           CommandLine
285	config        ConfigReader
286	HomeFinder    HomeFinder
287	writer        ConfigWriter
288	Test          *TestParameters
289	updaterConfig UpdaterConfigReader
290	guiConfig     *JSONFile
291}
292
293func (e *Env) GetConfig() ConfigReader {
294	e.RLock()
295	defer e.RUnlock()
296	return e.config
297}
298
299func (e *Env) GetConfigWriter() ConfigWriter {
300	e.RLock()
301	defer e.RUnlock()
302	return e.writer
303}
304
305func (e *Env) SetCommandLine(cmd CommandLine) {
306	e.Lock()
307	defer e.Unlock()
308	e.cmd = cmd
309}
310
311func (e *Env) GetCommandLine() CommandLine {
312	e.RLock()
313	defer e.RUnlock()
314	return e.cmd
315}
316
317func (e *Env) SetConfig(r ConfigReader, w ConfigWriter) {
318	e.Lock()
319	defer e.Unlock()
320	e.config = r
321	e.writer = w
322}
323
324func (e *Env) SetGUIConfig(j *JSONFile) {
325	e.Lock()
326	defer e.Unlock()
327	e.guiConfig = j
328}
329
330func (e *Env) GetGUIConfig() *JSONFile {
331	e.RLock()
332	defer e.RUnlock()
333	return e.guiConfig
334}
335
336func (e *Env) SetUpdaterConfig(r UpdaterConfigReader) {
337	e.Lock()
338	defer e.Unlock()
339	e.updaterConfig = r
340}
341
342func (e *Env) GetUpdaterConfig() UpdaterConfigReader {
343	e.RLock()
344	defer e.RUnlock()
345	return e.updaterConfig
346}
347
348func (e *Env) GetOldMountDirDefault() string {
349	switch RuntimeGroup() {
350	case keybase1.RuntimeGroup_LINUXLIKE:
351		return filepath.Join(e.GetDataDir(), "fs")
352	default:
353		return e.GetMountDirDefault()
354	}
355}
356
357func (e *Env) GetMountDirDefault() string {
358	switch RuntimeGroup() {
359	case keybase1.RuntimeGroup_DARWINLIKE:
360		volumes := "/Volumes"
361		user, err := user.Current()
362		var username string
363		if err != nil {
364			// The iOS simulator may not have a proper user set,
365			username = "<unknown>"
366		} else {
367			username = user.Username
368		}
369		var runmodeName string
370		switch e.GetRunMode() {
371		case DevelRunMode:
372			runmodeName = "KeybaseDevel"
373		case StagingRunMode:
374			runmodeName = "KeybaseStaging"
375		case ProductionRunMode:
376			runmodeName = "Keybase"
377		default:
378			panic("Invalid run mode")
379		}
380		return filepath.Join(volumes, fmt.Sprintf(
381			"%s (%s)", runmodeName, username))
382	case keybase1.RuntimeGroup_LINUXLIKE:
383		return filepath.Join(e.GetRuntimeDir(), "kbfs")
384	// kbfsdokan depends on an empty default
385	case keybase1.RuntimeGroup_WINDOWSLIKE:
386		return ""
387	default:
388		return filepath.Join(e.GetRuntimeDir(), "kbfs")
389	}
390}
391
392func (e *Env) GetMountDir() (string, error) {
393	return e.GetString(
394		func() string { return e.cmd.GetMountDir() },
395		func() string { return os.Getenv("KEYBASE_MOUNTDIR") },
396		func() string { return e.GetConfig().GetMountDir() },
397		e.GetMountDirDefault,
398	), nil
399}
400
401func NewEnv(cmd CommandLine, config ConfigReader, getLog LogGetter) *Env {
402	return newEnv(cmd, config, runtime.GOOS, getLog)
403}
404
405func newEnv(cmd CommandLine, config ConfigReader, osname string, getLog LogGetter) *Env {
406	if cmd == nil {
407		cmd = NullConfiguration{}
408	}
409	if config == nil {
410		config = NullConfiguration{}
411	}
412	e := Env{cmd: cmd, config: config, Test: &TestParameters{}}
413
414	e.HomeFinder = NewHomeFinder("keybase",
415		e.getHomeFromTestOrCmd,
416		func() string { return e.GetConfig().GetHome() },
417		e.getMobileSharedHomeFromCmdOrConfig,
418		osname,
419		e.GetRunMode,
420		getLog,
421		os.Getenv)
422	return &e
423}
424
425func (e *Env) getHomeFromTestOrCmd() string {
426	return e.GetString(
427		func() string { return e.Test.Home },
428		func() string {
429			home := e.cmd.GetHome()
430			if home == "" {
431				return ""
432			}
433			absHome, err := filepath.Abs(home)
434			if err != nil {
435				return home
436			}
437			return absHome
438		},
439	)
440}
441
442func (e *Env) getMobileSharedHomeFromCmdOrConfig() string {
443	return e.GetString(
444		func() string { return e.Test.MobileSharedHome },
445		func() string { return e.cmd.GetMobileSharedHome() },
446		func() string { return e.GetConfig().GetMobileSharedHome() },
447	)
448}
449
450func (e *Env) GetDownloadsDir() string     { return e.HomeFinder.DownloadsDir() }
451func (e *Env) GetHome() string             { return e.HomeFinder.Home(false) }
452func (e *Env) GetMobileSharedHome() string { return e.HomeFinder.MobileSharedHome(false) }
453func (e *Env) GetConfigDir() string        { return e.HomeFinder.ConfigDir() }
454func (e *Env) GetCacheDir() string         { return e.HomeFinder.CacheDir() }
455func (e *Env) GetSharedCacheDir() string   { return e.HomeFinder.SharedCacheDir() }
456func (e *Env) GetSandboxCacheDir() string  { return e.HomeFinder.SandboxCacheDir() }
457func (e *Env) GetDataDir() string          { return e.HomeFinder.DataDir() }
458func (e *Env) GetSharedDataDir() string    { return e.HomeFinder.SharedDataDir() }
459func (e *Env) GetLogDir() string           { return e.HomeFinder.LogDir() }
460
461func (e *Env) SendSystemChatMessages() bool {
462	return !e.Test.SkipSendingSystemChatMessages
463}
464
465func (e *Env) UseTimeClockForNISTs() bool {
466	return e.Test.UseTimeClockForNISTs
467}
468
469func (e *Env) GetRuntimeDir() string {
470	return e.GetString(
471		func() string { return e.Test.RuntimeDir },
472		func() string { return e.HomeFinder.RuntimeDir() },
473	)
474}
475
476func (e *Env) GetInfoDir() string {
477	return e.GetString(
478		func() string { return e.Test.RuntimeDir }, // needed for systests
479		func() string { return e.HomeFinder.InfoDir() },
480	)
481}
482
483func (e *Env) GetServiceSpawnDir() (string, error) { return e.HomeFinder.ServiceSpawnDir() }
484
485func (e *Env) getEnvInt(s string) (int, bool) {
486	v := os.Getenv(s)
487	if len(v) > 0 {
488		tmp, err := strconv.ParseInt(v, 0, 64)
489		if err == nil {
490			return int(tmp), true
491		}
492	}
493	return 0, false
494}
495
496func (e *Env) getEnvPath(s string) []string {
497	if tmp := os.Getenv(s); len(tmp) != 0 {
498		return strings.Split(tmp, ":")
499	}
500	return nil
501}
502
503func (e *Env) getEnvBool(s string) (bool, bool) {
504	return getEnvBool(s)
505}
506
507func getEnvBool(s string) (bool, bool) {
508	tmp := os.Getenv(s)
509	if len(tmp) == 0 {
510		return false, false
511	}
512	tmp = strings.ToLower(tmp)
513	if tmp == "0" || tmp[0] == byte('n') {
514		return false, true
515	}
516	return true, true
517}
518
519func (e *Env) getEnvDuration(s string) (time.Duration, bool) {
520	d, err := time.ParseDuration(os.Getenv(s))
521	if err != nil {
522		return 0, false
523	}
524	return d, true
525}
526
527func (e *Env) GetString(flist ...(func() string)) string {
528	var ret string
529	for _, f := range flist {
530		ret = f()
531		if len(ret) > 0 {
532			break
533		}
534	}
535	return ret
536}
537
538func (e *Env) GetBool(def bool, flist ...func() (bool, bool)) bool {
539	for _, f := range flist {
540		if val, isSet := f(); isSet {
541			return val
542		}
543	}
544	return def
545}
546
547type NegBoolFunc struct {
548	neg bool
549	f   func() (bool, bool)
550}
551
552// GetNegBool gets a negatable bool.  You can give it a list of functions,
553// and also possible negations for those functions.
554func (e *Env) GetNegBool(def bool, flist []NegBoolFunc) bool {
555	for _, f := range flist {
556		if val, isSet := f.f(); isSet {
557			return (val != f.neg)
558		}
559	}
560	return def
561}
562
563func (e *Env) GetInt(def int, flist ...func() (int, bool)) int {
564	for _, f := range flist {
565		if val, isSet := f(); isSet {
566			return val
567		}
568	}
569	return def
570}
571
572func (e *Env) GetDuration(def time.Duration, flist ...func() (time.Duration, bool)) time.Duration {
573	for _, f := range flist {
574		if val, isSet := f(); isSet {
575			return val
576		}
577	}
578	return def
579}
580
581func (e *Env) GetServerURI() (string, error) {
582	// appveyor and os x travis CI set server URI, so need to
583	// check for test flag here in order for production api endpoint
584	// tests to pass.
585	if e.Test.UseProductionRunMode {
586		server, e := ServerLookup(e, e.GetRunMode())
587		if e != nil {
588			return "", nil
589		}
590		return server, nil
591	}
592
593	serverURI := e.GetString(
594		func() string {
595			serverURI, err := e.cmd.GetServerURI()
596			if err != nil {
597				return ""
598			}
599			return serverURI
600		},
601		func() string { return os.Getenv("KEYBASE_SERVER_URI") },
602		func() string {
603			serverURI, err := e.GetConfig().GetServerURI()
604			if err != nil {
605				return ""
606			}
607			return serverURI
608		},
609		func() string {
610			serverURI, err := ServerLookup(e, e.GetRunMode())
611			if err != nil {
612				return ""
613			}
614			return serverURI
615		},
616	)
617
618	if serverURI == "" {
619		return "", fmt.Errorf("Env failed to read a server URI from any source!")
620	}
621	return serverURI, nil
622}
623
624func (e *Env) GetUseRootConfigFile() bool {
625	return e.GetBool(false, e.cmd.GetUseRootConfigFile)
626}
627
628func (e *Env) GetRootRedirectorMount() (string, error) {
629	switch RuntimeGroup() {
630	case keybase1.RuntimeGroup_LINUXLIKE, keybase1.RuntimeGroup_DARWINLIKE:
631		return "/keybase", nil
632	default:
633		return "", fmt.Errorf("Root redirector mount unknown on this system.")
634	}
635}
636
637func (e *Env) GetRootConfigDirectory() (string, error) {
638	// NOTE: If this ever changes to more than one level deep, the configure
639	// redirector CLI command needs to be updated to update the permissions
640	// back to 0644 for all the created directories, or other processes won't
641	// be able to read them.
642	// Alternatively, we could package a blank config.json in that directory,
643	// but we can't rely on that for other packages.
644	switch RuntimeGroup() {
645	case keybase1.RuntimeGroup_LINUXLIKE:
646		return "/etc/keybase/", nil
647	default:
648		return "", fmt.Errorf("Root config directory unknown on this system")
649	}
650}
651
652func (e *Env) GetRootConfigFilename() (string, error) {
653	dir, err := e.GetRootConfigDirectory()
654	if err != nil {
655		return "", err
656	}
657	return filepath.Join(dir, "config.json"), nil
658}
659
660func (e *Env) GetEnvFileDir() (string, error) {
661	switch RuntimeGroup() {
662	case keybase1.RuntimeGroup_LINUXLIKE:
663		// Do not respect $XDG_CONFIG_HOME due to debian systemd 229 not supporting %E
664		// see keybase.service systemd unit
665		return filepath.Join(e.GetHome(), ".config", "keybase"), nil
666	default:
667		return "", fmt.Errorf("No envfiledir for %s.", runtime.GOOS)
668	}
669}
670
671func (e *Env) GetEnvfileName() (string, error) {
672	dir, err := e.GetEnvFileDir()
673	if err != nil {
674		return "", err
675	}
676	return filepath.Join(dir, "keybase.autogen.env"), nil
677}
678
679func (e *Env) GetOverrideEnvfileName() (string, error) {
680	dir, err := e.GetEnvFileDir()
681	if err != nil {
682		return "", err
683	}
684	return filepath.Join(dir, "keybase.env"), nil
685}
686
687func (e *Env) GetConfigFilename() string {
688	return e.GetString(
689		func() string {
690			if e.GetUseRootConfigFile() {
691				ret, err := e.GetRootConfigFilename()
692				if err != nil {
693					return ""
694				}
695				return ret
696			}
697			return ""
698		},
699		func() string { return e.Test.ConfigFilename },
700		func() string { return e.cmd.GetConfigFilename() },
701		func() string { return os.Getenv("KEYBASE_CONFIG_FILE") },
702		func() string { return e.GetConfig().GetConfigFilename() },
703		func() string { return filepath.Join(e.GetConfigDir(), ConfigFile) },
704	)
705}
706
707func (e *Env) GetUpdaterConfigFilename() string {
708	return e.GetString(
709		func() string {
710			if e.GetUseRootConfigFile() {
711				dir, err := e.GetRootConfigDirectory()
712				if err != nil {
713					return ""
714				}
715				return filepath.Join(dir, UpdaterConfigFile)
716			}
717			return ""
718		},
719		func() string { return e.cmd.GetUpdaterConfigFilename() },
720		func() string { return os.Getenv("KEYBASE_UPDATER_CONFIG_FILE") },
721		func() string { return e.GetConfig().GetUpdaterConfigFilename() },
722		func() string { return filepath.Join(e.GetConfigDir(), UpdaterConfigFile) },
723	)
724}
725
726func (e *Env) GetGUIConfigFilename() string {
727	return e.GetString(
728		func() string {
729			if e.GetUseRootConfigFile() {
730				dir, err := e.GetRootConfigDirectory()
731				if err != nil {
732					return ""
733				}
734				return filepath.Join(dir, GUIConfigFile)
735			}
736			return ""
737		},
738		func() string { return e.cmd.GetGUIConfigFilename() },
739		func() string { return os.Getenv("KEYBASE_GUI_CONFIG_FILE") },
740		func() string { return e.GetConfig().GetGUIConfigFilename() },
741		func() string { return filepath.Join(e.GetConfigDir(), GUIConfigFile) },
742	)
743}
744
745func (e *Env) GetDeviceCloneStateFilename() string {
746	return e.GetString(
747		func() string { return e.cmd.GetDeviceCloneStateFilename() },
748		func() string { return os.Getenv("KEYBASE_DEVICE_CLONE_STATE_FILE") },
749		func() string { return e.GetConfig().GetDeviceCloneStateFilename() },
750		func() string { return filepath.Join(e.GetConfigDir(), DeviceCloneStateFile) },
751	)
752}
753
754func (e *Env) GetSessionFilename() string {
755	return e.GetString(
756		func() string { return e.cmd.GetSessionFilename() },
757		func() string { return os.Getenv("KEYBASE_SESSION_FILE") },
758		func() string { return e.GetConfig().GetSessionFilename() },
759		func() string { return filepath.Join(e.GetCacheDir(), SessionFile) },
760	)
761}
762
763func (e *Env) GetDbFilename() string {
764	return e.GetString(
765		func() string { return e.cmd.GetDbFilename() },
766		func() string { return os.Getenv("KEYBASE_DB_FILE") },
767		func() string { return e.GetConfig().GetDbFilename() },
768		func() string { return filepath.Join(e.GetDataDir(), DBFile) },
769	)
770}
771
772func (e *Env) GetChatDbFilename() string {
773	return e.GetString(
774		func() string { return e.cmd.GetChatDbFilename() },
775		func() string { return os.Getenv("KEYBASE_CHAT_DB_FILE") },
776		func() string { return e.GetConfig().GetChatDbFilename() },
777		func() string { return filepath.Join(e.GetDataDir(), ChatDBFile) },
778	)
779}
780
781// GetPvlKitFilename gets the path to pvl kit file.
782// Its value is usually "" which means to use the server.
783func (e *Env) GetPvlKitFilename() string {
784	return e.GetString(
785		func() string { return e.cmd.GetPvlKitFilename() },
786		func() string { return os.Getenv("KEYBASE_PVL_KIT_FILE") },
787		func() string { return e.GetConfig().GetPvlKitFilename() },
788	)
789}
790
791// GetParamProofKitFilename gets the path to param proof kit file.  Its value
792// is usually "" which means to use the server.
793func (e *Env) GetParamProofKitFilename() string {
794	return e.GetString(
795		func() string { return e.cmd.GetParamProofKitFilename() },
796		func() string { return os.Getenv("KEYBASE_PARAM_PROOF_KIT_FILE") },
797		func() string { return e.GetConfig().GetParamProofKitFilename() },
798	)
799}
800
801// GetExternalURLKitFilename gets the path to param proof kit file. Its value
802// is usually "" which means to use the server.
803func (e *Env) GetExternalURLKitFilename() string {
804	return e.GetString(
805		func() string { return e.cmd.GetExternalURLKitFilename() },
806		func() string { return os.Getenv("KEYBASE_EXTERNAL_URL_KIT_FILE") },
807		func() string { return e.GetConfig().GetExternalURLKitFilename() },
808	)
809}
810
811// GetProveBypass ignores creation_disabled so that the client will let the user
812// try to make a proof for any known service.
813func (e *Env) GetProveBypass() bool {
814	return e.GetBool(false,
815		func() (bool, bool) { return e.cmd.GetProveBypass() },
816		func() (bool, bool) { return e.getEnvBool("KEYBASE_PROVE_BYPASS") },
817		func() (bool, bool) { return e.GetConfig().GetProveBypass() })
818}
819
820// GetDebugJourneycard enables experimental chat journey cards.
821func (e *Env) GetDebugJourneycard() bool {
822	return e.GetBool(false,
823		func() (bool, bool) { return e.cmd.GetDebugJourneycard() },
824		func() (bool, bool) { return e.getEnvBool("KEYBASE_DEBUG_JOURNEYCARD") },
825		func() (bool, bool) { return e.GetConfig().GetDebugJourneycard() })
826}
827
828func (e *Env) GetDebug() bool {
829	return e.GetBool(false,
830		func() (bool, bool) { return e.Test.GetDebug() },
831		func() (bool, bool) { return e.cmd.GetDebug() },
832		func() (bool, bool) { return e.getEnvBool("KEYBASE_DEBUG") },
833		func() (bool, bool) { return e.GetConfig().GetDebug() },
834	)
835}
836
837func (e *Env) GetDisplayRawUntrustedOutput() bool {
838	return e.GetBool(false,
839		func() (bool, bool) { return e.cmd.GetDisplayRawUntrustedOutput() },
840		func() (bool, bool) { return e.getEnvBool("KEYBASE_DISPLAY_RAW_UNTRUSTED_OUTPUT") },
841		func() (bool, bool) { return e.GetConfig().GetDisplayRawUntrustedOutput() },
842	)
843}
844
845func (e *Env) GetAutoFork() bool {
846	// On !Darwin, we auto-fork by default
847	def := (runtime.GOOS != "darwin")
848	return e.GetNegBool(def,
849		[]NegBoolFunc{
850			{
851				neg: false,
852				f:   func() (bool, bool) { return e.cmd.GetAutoFork() },
853			},
854			{
855				neg: true,
856				f:   func() (bool, bool) { return e.cmd.GetNoAutoFork() },
857			},
858			{
859				neg: false,
860				f:   func() (bool, bool) { return e.getEnvBool("KEYBASE_AUTO_FORK") },
861			},
862			{
863				neg: true,
864				f:   func() (bool, bool) { return e.getEnvBool("KEYBASE_NO_AUTO_FORK") },
865			},
866			{
867				neg: false,
868				f:   func() (bool, bool) { return e.GetConfig().GetAutoFork() },
869			},
870		},
871	)
872}
873
874func (e *Env) GetStandalone() bool {
875	return e.GetBool(false,
876		func() (bool, bool) { return e.cmd.GetStandalone() },
877		func() (bool, bool) { return e.getEnvBool("KEYBASE_STANDALONE") },
878		func() (bool, bool) { return e.GetConfig().GetStandalone() },
879	)
880}
881
882func (e *Env) GetLogFormat() string {
883	return e.GetString(
884		func() string { return e.cmd.GetLogFormat() },
885		func() string { return os.Getenv("KEYBASE_LOG_FORMAT") },
886		func() string { return e.GetConfig().GetLogFormat() },
887	)
888}
889
890func (e *Env) GetLabel() string {
891	return e.GetString(
892		func() string { return e.cmd.GetString("label") },
893		func() string { return os.Getenv("KEYBASE_LABEL") },
894	)
895}
896
897func (e *Env) GetServiceType() string {
898	return e.GetString(
899		func() string { return os.Getenv("KEYBASE_SERVICE_TYPE") },
900	)
901}
902
903func (e *Env) GetAPIDump() bool {
904	return e.GetBool(false,
905		func() (bool, bool) { return e.cmd.GetAPIDump() },
906		func() (bool, bool) { return e.getEnvBool("KEYBASE_API_DUMP") },
907	)
908}
909
910func (e *Env) GetAllowRoot() bool {
911	return e.GetBool(false,
912		func() (bool, bool) { return e.getEnvBool("KEYBASE_ALLOW_ROOT") },
913	)
914}
915
916func (e *Env) GetUsername() NormalizedUsername {
917	return e.GetConfig().GetUsername()
918}
919
920func (e *Env) GetSocketBindFile() (string, error) {
921	return e.GetString(
922		e.sandboxSocketFile,
923		e.defaultSocketFile,
924	), nil
925}
926
927func (e *Env) defaultSocketFile() string {
928	socketFile := e.GetString(
929		func() string { return e.cmd.GetSocketFile() },
930		func() string { return os.Getenv("KEYBASE_SOCKET_FILE") },
931		func() string { return e.GetConfig().GetSocketFile() },
932	)
933	if socketFile == "" {
934		socketFile = filepath.Join(e.GetRuntimeDir(), SocketFile)
935	}
936	return socketFile
937}
938
939// sandboxSocketFile is socket file location for sandbox (macOS only)
940// Note: this was added for KBFS finder integration, which was never
941// activated.
942func (e *Env) sandboxSocketFile() string {
943	sandboxCacheDir := e.HomeFinder.SandboxCacheDir()
944	if sandboxCacheDir == "" {
945		return ""
946	}
947	return filepath.Join(sandboxCacheDir, SocketFile)
948}
949
950func (e *Env) GetSocketDialFiles() ([]string, error) {
951	dialFiles := []string{}
952	sandboxSocketFile := e.sandboxSocketFile()
953	if sandboxSocketFile != "" {
954		dialFiles = append(dialFiles, sandboxSocketFile)
955	}
956	dialFiles = append(dialFiles, e.defaultSocketFile())
957	return dialFiles, nil
958}
959
960func (e *Env) GetGregorURI() string {
961	return e.GetString(
962		func() string { return os.Getenv("KEYBASE_PUSH_SERVER_URI") },
963		func() string { return e.GetConfig().GetGregorURI() },
964		func() string { return e.cmd.GetGregorURI() },
965		func() string { return GregorServerLookup[e.GetRunMode()] },
966	)
967}
968
969func (e *Env) GetGregorSaveInterval() time.Duration {
970	return e.GetDuration(time.Minute,
971		func() (time.Duration, bool) { return e.getEnvDuration("KEYBASE_PUSH_SAVE_INTERVAL") },
972		func() (time.Duration, bool) { return e.GetConfig().GetGregorSaveInterval() },
973		func() (time.Duration, bool) { return e.cmd.GetGregorSaveInterval() },
974	)
975}
976
977func (e *Env) GetGregorDisabled() bool {
978	return e.GetBool(false,
979		func() (bool, bool) { return e.Test.GetNoGregor() },
980		func() (bool, bool) { return e.cmd.GetGregorDisabled() },
981		func() (bool, bool) { return getEnvBool("KEYBASE_PUSH_DISABLED") },
982		func() (bool, bool) { return e.GetConfig().GetGregorDisabled() },
983	)
984}
985
986func (e *Env) GetSecretStorePrimingDisabled() bool {
987	return e.GetBool(false,
988		func() (bool, bool) { return e.Test.GetSecretStorePrimingDisabled() },
989	)
990}
991
992func (e *Env) GetBGIdentifierDisabled() bool {
993	return e.GetBool(true,
994		func() (bool, bool) { return e.cmd.GetBGIdentifierDisabled() },
995		func() (bool, bool) { return getEnvBool("KEYBASE_BG_IDENTIFIER_DISABLED") },
996		func() (bool, bool) { return e.GetConfig().GetBGIdentifierDisabled() },
997	)
998}
999
1000func (e *Env) GetGregorPingInterval() time.Duration {
1001	return e.GetDuration(10*time.Second,
1002		func() (time.Duration, bool) { return e.getEnvDuration("KEYBASE_PUSH_PING_INTERVAL") },
1003		func() (time.Duration, bool) { return e.GetConfig().GetGregorPingInterval() },
1004		func() (time.Duration, bool) { return e.cmd.GetGregorPingInterval() },
1005	)
1006}
1007
1008func (e *Env) GetGregorPingTimeout() time.Duration {
1009	return e.GetDuration(5*time.Second,
1010		func() (time.Duration, bool) { return e.getEnvDuration("KEYBASE_PUSH_PING_TIMEOUT") },
1011		func() (time.Duration, bool) { return e.GetConfig().GetGregorPingTimeout() },
1012		func() (time.Duration, bool) { return e.cmd.GetGregorPingTimeout() },
1013	)
1014}
1015
1016func (e *Env) GetChatDelivererInterval() time.Duration {
1017	return e.GetDuration(5*time.Second,
1018		func() (time.Duration, bool) { return e.getEnvDuration("KEYBASE_CHAT_DELIVERER_INTERVAL") },
1019		func() (time.Duration, bool) { return e.GetConfig().GetChatDelivererInterval() },
1020		func() (time.Duration, bool) { return e.cmd.GetChatDelivererInterval() },
1021	)
1022}
1023
1024func (e *Env) GetAttachmentHTTPStartPort() int {
1025	return e.GetInt(16423,
1026		e.cmd.GetAttachmentHTTPStartPort,
1027		func() (int, bool) { return e.getEnvInt("KEYBASE_ATTACHMENT_HTTP_START") },
1028		e.GetConfig().GetAttachmentHTTPStartPort,
1029	)
1030}
1031
1032func (e *Env) GetAttachmentDisableMulti() bool {
1033	return e.GetBool(false,
1034		e.cmd.GetAttachmentDisableMulti,
1035		func() (bool, bool) { return e.getEnvBool("KEYBASE_ATTACHMENT_DISABLE_MULTI") },
1036		e.GetConfig().GetAttachmentDisableMulti,
1037	)
1038}
1039
1040func (e *Env) GetDisableTeamAuditor() bool {
1041	return e.GetBool(false,
1042		e.cmd.GetDisableTeamAuditor,
1043		func() (bool, bool) { return e.getEnvBool("KEYBASE_DISABLE_TEAM_AUDITOR") },
1044		e.GetConfig().GetDisableTeamAuditor,
1045		// If unset, use the BotLite setting
1046		func() (bool, bool) { return e.GetEnableBotLiteMode(), true },
1047	)
1048}
1049
1050func (e *Env) GetDisableTeamBoxAuditor() bool {
1051	return e.GetBool(false,
1052		e.cmd.GetDisableTeamBoxAuditor,
1053		func() (bool, bool) { return e.getEnvBool("KEYBASE_DISABLE_TEAM_BOX_AUDITOR") },
1054		e.GetConfig().GetDisableTeamBoxAuditor,
1055		// If unset, use the BotLite setting
1056		func() (bool, bool) { return e.GetEnableBotLiteMode(), true },
1057	)
1058}
1059
1060func (e *Env) GetDisableEKBackgroundKeygen() bool {
1061	return e.GetBool(false,
1062		e.cmd.GetDisableEKBackgroundKeygen,
1063		func() (bool, bool) { return e.getEnvBool("KEYBASE_DISABLE_EK_BACKGROUND_KEYGEN") },
1064		e.GetConfig().GetDisableEKBackgroundKeygen,
1065	)
1066}
1067
1068func (e *Env) GetDisableMerkleAuditor() bool {
1069	return e.GetBool(false,
1070		e.cmd.GetDisableMerkleAuditor,
1071		func() (bool, bool) { return e.getEnvBool("KEYBASE_DISABLE_MERKLE_AUDITOR") },
1072		e.GetConfig().GetDisableMerkleAuditor,
1073		// If unset, use the BotLite setting
1074		func() (bool, bool) { return e.GetEnableBotLiteMode(), true },
1075	)
1076}
1077
1078func (e *Env) GetDisableSearchIndexer() bool {
1079	return e.GetBool(false,
1080		e.cmd.GetDisableSearchIndexer,
1081		func() (bool, bool) { return e.getEnvBool("KEYBASE_DISABLE_SEARCH_INDEXER") },
1082		e.GetConfig().GetDisableSearchIndexer,
1083		// If unset, use the BotLite setting
1084		func() (bool, bool) { return e.GetEnableBotLiteMode(), true },
1085	)
1086}
1087
1088func (e *Env) GetDisableBgConvLoader() bool {
1089	return e.GetBool(false,
1090		e.cmd.GetDisableBgConvLoader,
1091		func() (bool, bool) { return e.getEnvBool("KEYBASE_DISABLE_BG_CONV_LOADER") },
1092		e.GetConfig().GetDisableBgConvLoader,
1093		// If unset, use the BotLite setting
1094		func() (bool, bool) { return e.GetEnableBotLiteMode(), true },
1095	)
1096}
1097
1098func (e *Env) GetEnableBotLiteMode() bool {
1099	return e.GetBool(false,
1100		e.cmd.GetEnableBotLiteMode,
1101		func() (bool, bool) { return e.getEnvBool("KEYBASE_ENABLE_BOT_LITE_MODE") },
1102		e.GetConfig().GetEnableBotLiteMode,
1103	)
1104}
1105
1106func (e *Env) GetExtraNetLogging() bool {
1107	return e.GetBool(false,
1108		e.cmd.GetExtraNetLogging,
1109		func() (bool, bool) { return e.getEnvBool("KEYBASE_EXTRA_NET_LOGGING") },
1110		e.GetConfig().GetExtraNetLogging,
1111	)
1112}
1113
1114func (e *Env) GetPidFile() (ret string, err error) {
1115	ret = e.GetString(
1116		func() string { return e.cmd.GetPidFile() },
1117		func() string { return os.Getenv("KEYBASE_PID_FILE") },
1118		func() string { return e.GetConfig().GetPidFile() },
1119	)
1120	if len(ret) == 0 {
1121		ret = filepath.Join(e.GetInfoDir(), PIDFile)
1122	}
1123	return
1124}
1125
1126func (e *Env) GetEmail() string {
1127	return e.GetString(
1128		func() string { return os.Getenv("KEYBASE_EMAIL") },
1129	)
1130}
1131
1132func (e *Env) GetStayLoggedOut() bool {
1133	return e.GetBool(false,
1134		func() (bool, bool) { return e.GetConfig().GetStayLoggedOut() },
1135	)
1136}
1137
1138// Upgrade sigchains to contain per-user-keys.
1139func (e *Env) GetUpgradePerUserKey() bool {
1140	return !e.Test.DisableUpgradePerUserKey
1141}
1142
1143// If true, do not logout after user.key_change notification handler
1144// decides that current device has been revoked.
1145func (e *Env) GetSkipLogoutIfRevokedCheck() bool {
1146	return e.Test.SkipLogoutIfRevokedCheck
1147}
1148
1149// Get the ProxyType based off of the configured proxy and tor settings
1150func (e *Env) GetProxyType() ProxyType {
1151	if e.GetTorMode() != TorNone {
1152		// Tor mode is enabled. Tor mode is implemented via a socks proxy
1153		return Socks
1154	}
1155	var proxyTypeStr = e.GetString(
1156		func() string { return e.cmd.GetProxyType() },
1157		func() string { return os.Getenv("PROXY_TYPE") },
1158		func() string { return e.GetConfig().GetProxyType() },
1159	)
1160	return ProxyTypeStrToEnumFunc(proxyTypeStr)
1161}
1162
1163func ProxyTypeStrToEnumFunc(proxyTypeStr string) ProxyType {
1164	proxyType, ok := ProxyTypeStrToEnum[strings.ToLower(proxyTypeStr)]
1165	if ok {
1166		return proxyType
1167	}
1168	// If they give us a bogus proxy type we just don't enable a proxy
1169	return NoProxy
1170}
1171
1172// Get the address (optionally including a port) of the currently configured proxy. Returns an empty string if no proxy
1173// is configured.
1174func (e *Env) GetProxy() string {
1175	return e.GetString(
1176		func() string {
1177			// Only return the tor proxy address if tor mode is enabled to ensure we fall through to the other options
1178			if e.GetTorMode() != TorNone {
1179				return e.GetTorProxy()
1180			}
1181			return ""
1182		},
1183		// Prioritze tor mode over configured proxies
1184		func() string { return e.cmd.GetProxy() },
1185		func() string { return e.GetConfig().GetProxy() },
1186		func() string { return os.Getenv("PROXY") },
1187		// Prioritize the keybase specific methods of configuring a proxy above the standard unix env variables
1188		func() string { return os.Getenv("HTTPS_PROXY") },
1189		func() string { return os.Getenv("HTTP_PROXY") },
1190	)
1191}
1192
1193func (e *Env) IsCertPinningEnabled() bool {
1194	// SSL Pinning is enabled if none of the config options say it is disabled
1195	if !e.cmd.IsCertPinningEnabled() {
1196		return false
1197	}
1198	res, isSet := e.getEnvBool("DISABLE_SSL_PINNING")
1199	if isSet && res {
1200		return false
1201	}
1202	if !e.GetConfig().IsCertPinningEnabled() {
1203		return false
1204	}
1205	return true
1206}
1207
1208func (e *Env) GetGpgHome() string {
1209	return e.GetString(
1210		func() string { return e.Test.GPGHome },
1211		func() string { return e.cmd.GetGpgHome() },
1212		func() string { return os.Getenv("GNUPGHOME") },
1213		func() string { return e.GetConfig().GetGpgHome() },
1214		func() string { return filepath.Join(e.GetHome(), ".gnupg") },
1215	)
1216}
1217
1218func (e *Env) GetPinentry() string {
1219	return e.GetString(
1220		func() string { return e.cmd.GetPinentry() },
1221		func() string { return os.Getenv("KEYBASE_PINENTRY") },
1222		func() string { return e.GetConfig().GetPinentry() },
1223	)
1224}
1225
1226func (e *Env) GetNoPinentry() bool {
1227
1228	isno := func(s string) (bool, bool) {
1229		s = strings.ToLower(s)
1230		if s == "0" || s == "no" || s == "n" || s == "none" {
1231			return true, true
1232		}
1233		return false, false
1234	}
1235
1236	return e.GetBool(false,
1237		func() (bool, bool) { return isno(e.cmd.GetPinentry()) },
1238		func() (bool, bool) { return isno(os.Getenv("KEYBASE_PINENTRY")) },
1239		func() (bool, bool) { return e.GetConfig().GetNoPinentry() },
1240	)
1241}
1242
1243func (e *Env) GetBundledCA(host string) string {
1244	return e.GetString(
1245		func() string { return e.GetConfig().GetBundledCA(host) },
1246		func() string {
1247			ret, ok := GetBundledCAsFromHost(host)
1248			if !ok {
1249				return ""
1250			}
1251			return string(ret)
1252		},
1253	)
1254}
1255
1256func (e *Env) GetUserCacheMaxAge() time.Duration {
1257	return e.GetDuration(UserCacheMaxAge,
1258		func() (time.Duration, bool) { return e.cmd.GetUserCacheMaxAge() },
1259		func() (time.Duration, bool) { return e.getEnvDuration("KEYBASE_USER_CACHE_MAX_AGE") },
1260		func() (time.Duration, bool) { return e.GetConfig().GetUserCacheMaxAge() },
1261	)
1262}
1263
1264func (e *Env) GetAPITimeout() time.Duration {
1265	return e.GetDuration(HTTPDefaultTimeout,
1266		func() (time.Duration, bool) { return e.cmd.GetAPITimeout() },
1267		func() (time.Duration, bool) { return e.getEnvDuration("KEYBASE_API_TIMEOUT") },
1268		func() (time.Duration, bool) { return e.GetConfig().GetAPITimeout() },
1269	)
1270}
1271
1272func (e *Env) GetScraperTimeout() time.Duration {
1273	return e.GetDuration(HTTPDefaultScraperTimeout,
1274		func() (time.Duration, bool) { return e.cmd.GetScraperTimeout() },
1275		func() (time.Duration, bool) { return e.getEnvDuration("KEYBASE_SCRAPER_TIMEOUT") },
1276		func() (time.Duration, bool) { return e.GetConfig().GetScraperTimeout() },
1277	)
1278}
1279
1280func (e *Env) GetLocalTrackMaxAge() time.Duration {
1281	return e.GetDuration(LocalTrackMaxAge,
1282		func() (time.Duration, bool) { return e.cmd.GetLocalTrackMaxAge() },
1283		func() (time.Duration, bool) { return e.getEnvDuration("KEYBASE_LOCAL_TRACK_MAX_AGE") },
1284		func() (time.Duration, bool) { return e.GetConfig().GetLocalTrackMaxAge() },
1285	)
1286}
1287func (e *Env) GetProofCacheSize() int {
1288	return e.GetInt(ProofCacheSize,
1289		e.cmd.GetProofCacheSize,
1290		func() (int, bool) { return e.getEnvInt("KEYBASE_PROOF_CACHE_SIZE") },
1291		e.GetConfig().GetProofCacheSize,
1292	)
1293}
1294
1295func (e *Env) GetProofCacheLongDur() time.Duration {
1296	return e.GetDuration(ProofCacheLongDur,
1297		func() (time.Duration, bool) { return e.getEnvDuration("KEYBASE_PROOF_CACHE_LONG_DUR") },
1298		e.GetConfig().GetProofCacheLongDur,
1299	)
1300}
1301
1302func (e *Env) GetProofCacheMediumDur() time.Duration {
1303	return e.GetDuration(ProofCacheMediumDur,
1304		func() (time.Duration, bool) { return e.getEnvDuration("KEYBASE_PROOF_CACHE_MEDIUM_DUR") },
1305		e.GetConfig().GetProofCacheMediumDur,
1306	)
1307}
1308
1309func (e *Env) GetProofCacheShortDur() time.Duration {
1310	return e.GetDuration(ProofCacheShortDur,
1311		func() (time.Duration, bool) { return e.getEnvDuration("KEYBASE_PROOF_CACHE_SHORT_DUR") },
1312		e.GetConfig().GetProofCacheShortDur,
1313	)
1314}
1315
1316func (e *Env) GetLinkCacheSize() int {
1317	return e.GetInt(LinkCacheSize,
1318		e.cmd.GetLinkCacheSize,
1319		func() (int, bool) { return e.getEnvInt("KEYBASE_LINK_CACHE_SIZE") },
1320		e.GetConfig().GetLinkCacheSize,
1321	)
1322}
1323
1324func (e *Env) GetUPAKCacheSize() int {
1325	return e.GetInt(UPAKCacheSize,
1326		e.cmd.GetUPAKCacheSize,
1327		func() (int, bool) { return e.getEnvInt("KEYBASE_UPAK_CACHE_SIZE") },
1328		e.GetConfig().GetUPAKCacheSize,
1329	)
1330}
1331
1332func (e *Env) GetUIDMapFullNameCacheSize() int {
1333	return e.GetInt(UIDMapFullNameCacheSize,
1334		e.cmd.GetUIDMapFullNameCacheSize,
1335		func() (int, bool) { return e.getEnvInt("KEYBASE_UID_MAP_FULL_NAME_CACHE_SIZE") },
1336		e.GetConfig().GetUIDMapFullNameCacheSize,
1337	)
1338}
1339
1340func (e *Env) GetLevelDBNumFiles() int {
1341	return e.GetInt(LevelDBNumFiles,
1342		e.cmd.GetLevelDBNumFiles,
1343		func() (int, bool) { return e.getEnvInt("KEYBASE_LEVELDB_NUM_FILES") },
1344		e.GetConfig().GetLevelDBNumFiles,
1345	)
1346}
1347
1348func (e *Env) GetLevelDBWriteBufferMB() int {
1349	return e.GetInt(LevelDBWriteBufferMB,
1350		e.cmd.GetLevelDBWriteBufferMB,
1351		func() (int, bool) { return e.getEnvInt("KEYBASE_LEVELDB_WRITE_BUFFER_MB") },
1352		e.GetConfig().GetLevelDBWriteBufferMB,
1353	)
1354}
1355
1356func (e *Env) GetLinkCacheCleanDur() time.Duration {
1357	return e.GetDuration(LinkCacheCleanDur,
1358		func() (time.Duration, bool) { return e.getEnvDuration("KEYBASE_LINK_CACHE_CLEAN_DUR") },
1359		e.GetConfig().GetLinkCacheCleanDur,
1360	)
1361}
1362
1363func (e *Env) GetPayloadCacheSize() int {
1364	return e.GetInt(PayloadCacheSize,
1365		e.cmd.GetPayloadCacheSize,
1366		func() (int, bool) { return e.getEnvInt("KEYBASE_PAYLOAD_CACHE_SIZE") },
1367		e.GetConfig().GetPayloadCacheSize,
1368	)
1369}
1370
1371func (e *Env) GetEmailOrUsername() string {
1372	un := e.GetUsername().String()
1373	if len(un) > 0 {
1374		return un
1375	}
1376	em := e.GetEmail()
1377	return em
1378}
1379
1380func (e *Env) GetRunMode() RunMode {
1381	// If testing production run mode, then use it:
1382	if e.Test.UseProductionRunMode {
1383		return ProductionRunMode
1384	}
1385
1386	var ret RunMode
1387
1388	pick := func(m RunMode, err error) {
1389		if ret == NoRunMode && err == nil {
1390			ret = m
1391		}
1392	}
1393
1394	pick(e.cmd.GetRunMode())
1395	pick(StringToRunMode(os.Getenv("KEYBASE_RUN_MODE")))
1396	pick(e.GetConfig().GetRunMode())
1397	pick(DefaultRunMode, nil)
1398
1399	// If we aren't running in devel or staging and we're testing. Let's run in devel.
1400	if e.Test.Devel && ret != DevelRunMode && ret != StagingRunMode {
1401		return DevelRunMode
1402	}
1403
1404	return ret
1405}
1406
1407func (e *Env) GetAppType() AppType {
1408	switch {
1409	case e.cmd.GetAppType() != NoAppType:
1410		return e.cmd.GetAppType()
1411	case StringToAppType(os.Getenv("KEYBASE_APP_TYPE")) != NoAppType:
1412		return StringToAppType(os.Getenv("KEYBASE_APP_TYPE"))
1413	case e.GetConfig().GetAppType() != NoAppType:
1414		return e.GetConfig().GetAppType()
1415	default:
1416		return NoAppType
1417	}
1418}
1419
1420func (e *Env) IsMobileExtension() bool {
1421	return e.GetBool(false,
1422		func() (bool, bool) { return e.cmd.IsMobileExtension() },
1423		func() (bool, bool) { return e.getEnvBool("KEYBASE_MOBILE_EXTENSION") },
1424		func() (bool, bool) { return e.GetConfig().IsMobileExtension() },
1425	)
1426}
1427
1428func (e *Env) GetSlowGregorConn() bool {
1429	return e.GetBool(false,
1430		func() (bool, bool) { return e.cmd.GetSlowGregorConn() },
1431		func() (bool, bool) { return e.getEnvBool("KEYBASE_SLOW_GREGOR_CONN") },
1432		func() (bool, bool) { return e.GetConfig().GetSlowGregorConn() },
1433	)
1434}
1435
1436func (e *Env) GetReadDeletedSigChain() bool {
1437	return e.GetBool(false,
1438		func() (bool, bool) { return e.cmd.GetReadDeletedSigChain() },
1439		func() (bool, bool) { return e.getEnvBool("KEYBASE_READ_DELETED_SIGCHAIN") },
1440		func() (bool, bool) { return e.GetConfig().GetReadDeletedSigChain() },
1441	)
1442}
1443
1444func (e *Env) GetFeatureFlags() FeatureFlags {
1445	var ret FeatureFlags
1446	pick := func(f FeatureFlags, err error) {
1447		if ret.Empty() && err == nil {
1448			ret = f
1449		}
1450	}
1451	if e.Test.EnvironmentFeatureFlags != nil {
1452		pick(e.Test.EnvironmentFeatureFlags, nil)
1453	}
1454	pick(e.cmd.GetFeatureFlags())
1455	pick(StringToFeatureFlags(os.Getenv("KEYBASE_FEATURES")), nil)
1456	pick(e.GetConfig().GetFeatureFlags())
1457	return ret
1458}
1459
1460func (e *Env) GetUID() keybase1.UID { return e.GetConfig().GetUID() }
1461
1462func (e *Env) GetStringList(list ...(func() []string)) []string {
1463	for _, f := range list {
1464		if res := f(); res != nil {
1465			return res
1466		}
1467	}
1468	return []string{}
1469}
1470
1471func (e *Env) GetMerkleKIDs() []keybase1.KID {
1472	slist := e.GetStringList(
1473		func() []string { return e.cmd.GetMerkleKIDs() },
1474		func() []string { return e.getEnvPath("KEYBASE_MERKLE_KIDS") },
1475		func() []string { return e.GetConfig().GetMerkleKIDs() },
1476		func() []string {
1477			ret := MerkleProdKIDs
1478			if e.GetRunMode() == DevelRunMode || e.GetRunMode() == StagingRunMode {
1479				ret = append(ret, MerkleTestKIDs...)
1480				ret = append(ret, MerkleStagingKIDs...)
1481			}
1482			return ret
1483		},
1484	)
1485
1486	if slist == nil {
1487		return nil
1488	}
1489	var ret []keybase1.KID
1490	for _, s := range slist {
1491		ret = append(ret, keybase1.KIDFromString(s))
1492	}
1493
1494	return ret
1495}
1496
1497func (e *Env) GetCodeSigningKIDs() []keybase1.KID {
1498	slist := e.GetStringList(
1499		func() []string { return e.cmd.GetCodeSigningKIDs() },
1500		func() []string { return e.getEnvPath("KEYBASE_CODE_SIGNING_KIDS") },
1501		func() []string { return e.GetConfig().GetCodeSigningKIDs() },
1502		func() []string {
1503			ret := CodeSigningProdKIDs
1504			if e.GetRunMode() == DevelRunMode || e.GetRunMode() == StagingRunMode {
1505				ret = append(ret, CodeSigningTestKIDs...)
1506				ret = append(ret, CodeSigningStagingKIDs...)
1507			}
1508			return ret
1509		},
1510	)
1511
1512	if slist == nil {
1513		return nil
1514	}
1515	var ret []keybase1.KID
1516	for _, s := range slist {
1517		ret = append(ret, keybase1.KIDFromString(s))
1518	}
1519
1520	return ret
1521}
1522
1523func (e *Env) GetGpg() string {
1524	return e.GetString(
1525		func() string { return e.Test.GPG },
1526		func() string { return e.cmd.GetGpg() },
1527		func() string { return os.Getenv("GPG") },
1528		func() string { return e.GetConfig().GetGpg() },
1529	)
1530}
1531
1532func (e *Env) GetGpgOptions() []string {
1533	return e.GetStringList(
1534		func() []string { return e.Test.GPGOptions },
1535		func() []string { return e.cmd.GetGpgOptions() },
1536		func() []string { return e.GetConfig().GetGpgOptions() },
1537	)
1538}
1539
1540func (e *Env) GetSecretKeyringTemplate() string {
1541	return e.GetString(
1542		func() string { return e.cmd.GetSecretKeyringTemplate() },
1543		func() string { return os.Getenv("KEYBASE_SECRET_KEYRING_TEMPLATE") },
1544		func() string { return e.GetConfig().GetSecretKeyringTemplate() },
1545		func() string { return filepath.Join(e.GetConfigDir(), SecretKeyringTemplate) },
1546	)
1547}
1548
1549func (e *Env) GetLocalRPCDebug() string {
1550	return e.GetString(
1551		func() string { return e.cmd.GetLocalRPCDebug() },
1552		func() string { return os.Getenv("KEYBASE_LOCAL_RPC_DEBUG") },
1553		func() string { return e.GetConfig().GetLocalRPCDebug() },
1554	)
1555}
1556
1557func (e *Env) GetDoLogForward() bool {
1558	return e.GetLocalRPCDebug() == ""
1559}
1560
1561func (e *Env) GetTimers() string {
1562	return e.GetString(
1563		func() string { return e.cmd.GetTimers() },
1564		func() string { return os.Getenv("KEYBASE_TIMERS") },
1565		func() string { return e.GetConfig().GetTimers() },
1566	)
1567}
1568
1569func (e *Env) GetConvSourceType() string {
1570	return e.GetString(
1571		func() string { return os.Getenv("KEYBASE_CONV_SOURCE_TYPE") },
1572		func() string { return "hybrid" },
1573	)
1574}
1575
1576func (e *Env) GetInboxSourceType() string {
1577	return e.GetString(
1578		func() string { return os.Getenv("KEYBASE_INBOX_SOURCE_TYPE") },
1579		func() string { return "hybrid" },
1580	)
1581}
1582
1583func (e *Env) GetChatInboxSourceLocalizeThreads() int {
1584	return e.GetInt(
1585		10,
1586		e.cmd.GetChatInboxSourceLocalizeThreads,
1587		func() (int, bool) { return e.getEnvInt("KEYBASE_INBOX_SOURCE_LOCALIZE_THREADS") },
1588		e.GetConfig().GetChatInboxSourceLocalizeThreads,
1589	)
1590}
1591
1592// GetChatMemberType returns the default member type for new conversations.
1593func (e *Env) GetChatMemberType() string {
1594	return e.GetString(
1595		func() string { return os.Getenv("KEYBASE_CHAT_MEMBER_TYPE") },
1596		func() string { return "impteam" },
1597	)
1598}
1599
1600func (e *Env) GetAvatarSource() string {
1601	return e.GetString(
1602		func() string { return os.Getenv("KEYBASE_AVATAR_SOURCE") },
1603		func() string { return "full" },
1604	)
1605}
1606
1607func (e *Env) GetDeviceID() keybase1.DeviceID {
1608	return e.GetConfig().GetDeviceID()
1609}
1610
1611func (e *Env) GetDeviceIDForUsername(u NormalizedUsername) keybase1.DeviceID {
1612	return e.GetConfig().GetDeviceIDForUsername(u)
1613}
1614
1615func (e *Env) GetDeviceIDForUID(u keybase1.UID) keybase1.DeviceID {
1616	return e.GetConfig().GetDeviceIDForUID(u)
1617}
1618
1619func (e *Env) GetUsernameForUID(u keybase1.UID) NormalizedUsername {
1620	return e.GetConfig().GetUsernameForUID(u)
1621}
1622
1623func (e *Env) GetInstallID() (ret InstallID) {
1624	if rdr := e.GetUpdaterConfig(); rdr != nil {
1625		ret = rdr.GetInstallID()
1626	}
1627	return ret
1628}
1629
1630func (e *Env) GetEffectiveLogFile() (filename string, ok bool) {
1631	logFile := e.GetLogFile()
1632	if logFile != "" {
1633		return logFile, true
1634	}
1635
1636	filePrefix := e.GetLogPrefix()
1637	if filePrefix != "" {
1638		filePrefix += time.Now().Format("20060102T150405.999999999Z0700")
1639		logFile = filePrefix + ".log"
1640		return logFile, true
1641	}
1642
1643	return e.GetDefaultLogFile(), e.GetUseDefaultLogFile()
1644}
1645
1646func (e *Env) GetLogFile() string {
1647	return e.GetString(
1648		func() string { return e.cmd.GetLogFile() },
1649		func() string { return os.Getenv("KEYBASE_LOG_FILE") },
1650	)
1651}
1652
1653func (e *Env) GetEKLogFile() string {
1654	return e.GetString(
1655		func() string { return e.cmd.GetEKLogFile() },
1656		func() string { return os.Getenv("KEYBASE_EK_LOG_FILE") },
1657		func() string { return filepath.Join(e.GetLogDir(), EKLogFileName) },
1658	)
1659}
1660
1661func (e *Env) GetPerfLogFile() string {
1662	return e.GetString(
1663		func() string { return e.cmd.GetPerfLogFile() },
1664		func() string { return os.Getenv("KEYBASE_PERF_LOG_FILE") },
1665		func() string { return filepath.Join(e.GetLogDir(), PerfLogFileName) },
1666	)
1667}
1668
1669func (e *Env) GetGUILogFile() string {
1670	return e.GetString(
1671		func() string { return e.cmd.GetGUILogFile() },
1672		func() string { return os.Getenv("KEYBASE_GUI_LOG_FILE") },
1673		func() string { return filepath.Join(e.GetLogDir(), GUILogFileName) },
1674	)
1675}
1676
1677func (e *Env) GetUseDefaultLogFile() bool {
1678	return e.GetBool(false,
1679		e.cmd.GetUseDefaultLogFile,
1680		func() (bool, bool) { return e.getEnvBool("KEYBASE_USE_DEFAULT_LOG_FILE") },
1681	)
1682}
1683
1684func (e *Env) GetLogPrefix() string {
1685	return e.cmd.GetLogPrefix()
1686}
1687
1688func (e *Env) GetDefaultLogFile() string {
1689	return filepath.Join(e.GetLogDir(), ServiceLogFileName)
1690}
1691
1692func (e *Env) GetTorMode() TorMode {
1693	var ret TorMode
1694
1695	pick := func(m TorMode, err error) {
1696		if ret == TorNone && err == nil {
1697			ret = m
1698		}
1699	}
1700
1701	pick(e.cmd.GetTorMode())
1702	pick(StringToTorMode(os.Getenv("KEYBASE_TOR_MODE")))
1703	pick(e.GetConfig().GetTorMode())
1704
1705	return ret
1706}
1707
1708func (e *Env) GetTorHiddenAddress() string {
1709	return e.GetString(
1710		func() string { return e.cmd.GetTorHiddenAddress() },
1711		func() string { return os.Getenv("KEYBASE_TOR_HIDDEN_ADDRESS") },
1712		func() string { return e.GetConfig().GetTorHiddenAddress() },
1713		func() string { return TorServerURI },
1714	)
1715}
1716
1717func (e *Env) GetTorProxy() string {
1718	return e.GetString(
1719		func() string { return e.cmd.GetTorProxy() },
1720		func() string { return os.Getenv("KEYBASE_TOR_PROXY") },
1721		func() string { return e.GetConfig().GetTorProxy() },
1722		func() string { return TorProxy },
1723	)
1724}
1725
1726func (e *Env) GetStoredSecretAccessGroup() string {
1727	var override = e.GetBool(
1728		false,
1729		func() (bool, bool) { return e.GetConfig().GetSecurityAccessGroupOverride() },
1730	)
1731
1732	if override {
1733		return ""
1734	}
1735	return "99229SGT5K.group.keybase"
1736}
1737
1738func (e *Env) GetStoredSecretServiceBaseName() string {
1739	var serviceName string
1740	switch e.GetRunMode() {
1741	case DevelRunMode:
1742		serviceName = "keybase-devel"
1743	case StagingRunMode:
1744		serviceName = "keybase-staging"
1745	case ProductionRunMode:
1746		serviceName = "keybase"
1747	default:
1748		panic("Invalid run mode")
1749	}
1750	if e.Test.Devel {
1751		// Append DevelName so that tests won't clobber each
1752		// other's keychain entries on shutdown.
1753		serviceName += "-test"
1754	}
1755	return serviceName
1756}
1757
1758func (e *Env) GetStoredSecretServiceName() string {
1759	serviceName := e.GetStoredSecretServiceBaseName()
1760	if e.Test.Devel {
1761		// Append DevelName so that tests won't clobber each
1762		// other's keychain entries on shutdown.
1763		serviceName += fmt.Sprintf("(%s)", e.Test.DevelName)
1764	}
1765	return serviceName
1766}
1767
1768type AppConfig struct {
1769	NullConfiguration
1770	DownloadsDir                   string
1771	HomeDir                        string
1772	MobileSharedHomeDir            string
1773	LogFile                        string
1774	EKLogFile                      string
1775	PerfLogFile                    string
1776	GUILogFile                     string
1777	UseDefaultLogFile              bool
1778	RunMode                        RunMode
1779	Debug                          bool
1780	LocalRPCDebug                  string
1781	ServerURI                      string
1782	VDebugSetting                  string
1783	SecurityAccessGroupOverride    bool
1784	ChatInboxSourceLocalizeThreads int
1785	MobileExtension                bool
1786	AttachmentHTTPStartPort        int
1787	AttachmentDisableMulti         bool
1788	LinkCacheSize                  int
1789	UPAKCacheSize                  int
1790	PayloadCacheSize               int
1791	ProofCacheSize                 int
1792	DisableTeamAuditor             bool
1793	DisableMerkleAuditor           bool
1794	DisableTeamBoxAuditor          bool
1795	DisableEKBackgroundKeygen      bool
1796	LevelDBWriteBufferMB           int
1797	LevelDBNumFiles                int
1798}
1799
1800var _ CommandLine = AppConfig{}
1801
1802func (c AppConfig) GetLogFile() string {
1803	return c.LogFile
1804}
1805
1806func (c AppConfig) GetEKLogFile() string {
1807	return c.EKLogFile
1808}
1809
1810func (c AppConfig) GetPerfLogFile() string {
1811	return c.PerfLogFile
1812}
1813
1814func (c AppConfig) GetGUILogFile() string {
1815	return c.GUILogFile
1816}
1817
1818func (c AppConfig) GetUseDefaultLogFile() (bool, bool) {
1819	return c.UseDefaultLogFile, true
1820}
1821
1822func (c AppConfig) GetDebug() (bool, bool) {
1823	return c.Debug, c.Debug
1824}
1825
1826func (c AppConfig) GetLocalRPCDebug() string {
1827	return c.LocalRPCDebug
1828}
1829
1830func (c AppConfig) GetRunMode() (RunMode, error) {
1831	return c.RunMode, nil
1832}
1833
1834func (c AppConfig) GetDownloadsDir() string {
1835	return c.DownloadsDir
1836}
1837
1838func (c AppConfig) GetHome() string {
1839	return c.HomeDir
1840}
1841
1842func (c AppConfig) GetMobileSharedHome() string {
1843	return c.MobileSharedHomeDir
1844}
1845
1846func (c AppConfig) GetServerURI() (string, error) {
1847	return c.ServerURI, nil
1848}
1849
1850func (c AppConfig) GetSecurityAccessGroupOverride() (bool, bool) {
1851	return c.SecurityAccessGroupOverride, c.SecurityAccessGroupOverride
1852}
1853
1854func (c AppConfig) GetAppType() AppType {
1855	return MobileAppType
1856}
1857
1858func (c AppConfig) IsMobileExtension() (bool, bool) {
1859	return c.MobileExtension, true
1860}
1861
1862func (c AppConfig) GetSlowGregorConn() (bool, bool) {
1863	return false, false
1864}
1865
1866func (c AppConfig) GetReadDeletedSigChain() (bool, bool) {
1867	return false, false
1868}
1869
1870func (c AppConfig) GetVDebugSetting() string {
1871	return c.VDebugSetting
1872}
1873
1874func (c AppConfig) GetChatInboxSourceLocalizeThreads() (int, bool) {
1875	return c.ChatInboxSourceLocalizeThreads, true
1876}
1877
1878func (c AppConfig) GetLevelDBWriteBufferMB() (int, bool) {
1879	if c.LevelDBWriteBufferMB > 0 {
1880		return c.LevelDBWriteBufferMB, true
1881	}
1882	return LevelDBWriteBufferMBMobile, true
1883}
1884
1885func (c AppConfig) GetLevelDBNumFiles() (int, bool) {
1886	if c.LevelDBNumFiles > 0 {
1887		return c.LevelDBNumFiles, true
1888	}
1889	return LevelDBNumFiles, true
1890}
1891
1892func (c AppConfig) GetAttachmentHTTPStartPort() (int, bool) {
1893	if c.AttachmentHTTPStartPort != 0 {
1894		return c.AttachmentHTTPStartPort, true
1895	}
1896	return 0, false
1897}
1898
1899func (c AppConfig) GetLinkCacheSize() (int, bool) {
1900	if c.LinkCacheSize != 0 {
1901		return c.LinkCacheSize, true
1902	}
1903	return 0, false
1904}
1905
1906func (c AppConfig) GetUPAKCacheSize() (int, bool) {
1907	if c.UPAKCacheSize != 0 {
1908		return c.UPAKCacheSize, true
1909	}
1910	return 0, false
1911}
1912
1913func (c AppConfig) GetPayloadCacheSize() (int, bool) {
1914	if c.PayloadCacheSize != 0 {
1915		return c.PayloadCacheSize, true
1916	}
1917	return 0, false
1918}
1919
1920func (c AppConfig) GetProofCacheSize() (int, bool) {
1921	if c.ProofCacheSize != 0 {
1922		return c.ProofCacheSize, true
1923	}
1924	return 0, false
1925}
1926
1927func (c AppConfig) GetDisableTeamAuditor() (bool, bool) {
1928	return c.DisableTeamAuditor, true
1929}
1930
1931func (c AppConfig) GetDisableMerkleAuditor() (bool, bool) {
1932	return c.DisableMerkleAuditor, true
1933}
1934
1935func (c AppConfig) GetDisableTeamBoxAuditor() (bool, bool) {
1936	return c.DisableTeamBoxAuditor, true
1937}
1938
1939func (c AppConfig) GetDisableEKBackgroundKeygen() (bool, bool) {
1940	return c.DisableEKBackgroundKeygen, true
1941}
1942
1943func (c AppConfig) GetAttachmentDisableMulti() (bool, bool) {
1944	return c.AttachmentDisableMulti, true
1945}
1946
1947func (e *Env) GetUpdatePreferenceAuto() (bool, bool) {
1948	return e.GetConfig().GetUpdatePreferenceAuto()
1949}
1950
1951func (e *Env) GetUpdatePreferenceSkip() string {
1952	return e.GetConfig().GetUpdatePreferenceSkip()
1953}
1954
1955func (e *Env) GetUpdatePreferenceSnoozeUntil() keybase1.Time {
1956	return e.GetConfig().GetUpdatePreferenceSnoozeUntil()
1957}
1958
1959func (e *Env) GetUpdateLastChecked() keybase1.Time {
1960	return e.GetConfig().GetUpdateLastChecked()
1961}
1962
1963func (e *Env) SetUpdatePreferenceAuto(b bool) error {
1964	return e.GetConfigWriter().SetUpdatePreferenceAuto(b)
1965}
1966
1967func (e *Env) SetUpdatePreferenceSkip(v string) error {
1968	return e.GetConfigWriter().SetUpdatePreferenceSkip(v)
1969}
1970
1971func (e *Env) SetUpdatePreferenceSnoozeUntil(t keybase1.Time) error {
1972	return e.GetConfigWriter().SetUpdatePreferenceSnoozeUntil(t)
1973}
1974
1975func (e *Env) SetUpdateLastChecked(t keybase1.Time) error {
1976	return e.GetConfigWriter().SetUpdateLastChecked(t)
1977}
1978
1979func (e *Env) GetUpdateURL() string {
1980	return e.GetConfig().GetUpdateURL()
1981}
1982
1983func (e *Env) GetUpdateDisabled() (bool, bool) {
1984	return e.GetConfig().GetUpdateDisabled()
1985}
1986
1987func (e *Env) GetVDebugSetting() string {
1988	return e.GetString(
1989		func() string { return e.cmd.GetVDebugSetting() },
1990		func() string { return os.Getenv("KEYBASE_VDEBUG") },
1991		func() string { return e.GetConfig().GetVDebugSetting() },
1992		func() string { return "" },
1993	)
1994}
1995
1996func (e *Env) GetRunModeAsString() string {
1997	return string(e.GetRunMode())
1998}
1999
2000// GetServiceInfoPath returns path to info file written by the Keybase service after startup
2001func (e *Env) GetServiceInfoPath() string {
2002	return filepath.Join(e.GetRuntimeDir(), "keybased.info")
2003}
2004
2005// GetKBFSInfoPath returns path to info file written by the KBFS service after startup
2006func (e *Env) GetKBFSInfoPath() string {
2007	return filepath.Join(e.GetRuntimeDir(), "kbfs.info")
2008}
2009
2010func (e *Env) GetUpdateDefaultInstructions() (string, error) {
2011	return PlatformSpecificUpgradeInstructionsString()
2012}
2013
2014func (e *Env) RunningInCI() bool {
2015	return e.GetBool(false,
2016		func() (bool, bool) { return e.getEnvBool("KEYBASE_RUN_CI") },
2017	)
2018}
2019
2020func (e *Env) WantsSystemd() bool {
2021	isNonstandard, isNonstandardErr := e.HomeFinder.IsNonstandardHome()
2022	return (e.GetRunMode() == ProductionRunMode && e.ModelessWantsSystemd() && (isNonstandardErr != nil || !isNonstandard))
2023}
2024
2025func (e *Env) ModelessWantsSystemd() bool {
2026	return (systemd.IsRunningSystemd() &&
2027		os.Getenv("KEYBASE_SYSTEMD") != "0")
2028}
2029
2030func (e *Env) ForceSecretStoreFile() bool {
2031	// By default use system-provided secret store (like MacOS Keychain), but
2032	// allow users to fall back to file-based store for testing and debugging.
2033	return e.GetBool(false,
2034		func() (bool, bool) { return e.getEnvBool("KEYBASE_SECRET_STORE_FILE") },
2035		func() (bool, bool) { return e.GetConfig().GetForceSecretStoreFile() },
2036	)
2037}
2038
2039func (e *Env) GetRuntimeStatsEnabled() bool {
2040	return e.GetBool(false,
2041		func() (bool, bool) { return e.getEnvBool("KEYBASE_RUNTIME_STATS_ENABLED") },
2042		func() (bool, bool) { return e.GetConfig().GetRuntimeStatsEnabled() },
2043	)
2044}
2045
2046func (e *Env) GetRememberPassphrase(username NormalizedUsername) bool {
2047	return e.GetBool(true,
2048		func() (bool, bool) { return e.cmd.GetRememberPassphrase(username) },
2049		func() (bool, bool) { return e.GetConfig().GetRememberPassphrase(username) },
2050	)
2051}
2052
2053func GetPlatformString() string {
2054	if IsIPad {
2055		return "ipad"
2056	}
2057	if isIOS {
2058		return "ios"
2059	}
2060	return runtime.GOOS
2061}
2062
2063func IsMobilePlatform() bool {
2064	s := GetPlatformString()
2065	return (s == "ios" || s == "android" || s == "ipad")
2066}
2067
2068func IsAndroid() bool {
2069	return GetPlatformString() == "android"
2070}
2071
2072func (e *Env) AllowPTrace() bool {
2073	return e.GetBool(false,
2074		func() (bool, bool) { return e.getEnvBool("KEYBASE_ALLOW_PTRACE") },
2075	)
2076}
2077
2078func (e *Env) GetLogFileConfig(filename string) *logger.LogFileConfig {
2079	var maxKeepFiles int
2080	var maxSize int64
2081
2082	if e.GetAppType() == MobileAppType && !e.GetFeatureFlags().Admin(e.GetUID()) {
2083		maxKeepFiles = 2
2084		maxSize = 16 * opt.MiB
2085	} else {
2086		maxKeepFiles = 3
2087		maxSize = 128 * opt.MiB
2088	}
2089
2090	return &logger.LogFileConfig{
2091		Path:         filename,
2092		MaxAge:       30 * 24 * time.Hour, // 30 days
2093		MaxSize:      maxSize,
2094		MaxKeepFiles: maxKeepFiles,
2095	}
2096}
2097func (e *Env) GetForceLinuxKeyring() bool {
2098	return e.GetBool(false,
2099		func() (bool, bool) { return e.cmd.GetForceLinuxKeyring() },
2100		func() (bool, bool) { return e.getEnvBool("KEYBASE_FORCE_LINUX_KEYRING") },
2101		func() (bool, bool) { return e.GetConfig().GetForceLinuxKeyring() })
2102}
2103