github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/config.go (about)

     1  // Copyright 2015 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package libkb
     5  
     6  import (
     7  	"fmt"
     8  	"strconv"
     9  	"strings"
    10  	"sync"
    11  	"time"
    12  
    13  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    14  	jsonw "github.com/keybase/go-jsonw"
    15  )
    16  
    17  type UserConfigWrapper struct {
    18  	userConfig *UserConfig
    19  	sync.Mutex
    20  }
    21  
    22  type JSONConfigFile struct {
    23  	*JSONFile
    24  	userConfigWrapper *UserConfigWrapper
    25  }
    26  
    27  var _ (ConfigReader) = (*JSONConfigFile)(nil)
    28  
    29  func NewJSONConfigFile(g *GlobalContext, s string) *JSONConfigFile {
    30  	return &JSONConfigFile{NewJSONFile(g, s, "config"), &UserConfigWrapper{}}
    31  }
    32  
    33  // Check looks inside the JSON file to see if any fields are poorly specified
    34  func (f *JSONConfigFile) Check() error {
    35  	return PickFirstError(
    36  		// Feel free to add others here..
    37  		func() error {
    38  			_, err := f.GetRunMode()
    39  			return err
    40  		}(),
    41  	)
    42  }
    43  
    44  func (f *JSONConfigFile) GetDurationAtPath(p string) (time.Duration, bool) {
    45  	s, ok := f.GetStringAtPath(p)
    46  	if !ok {
    47  		return 0, false
    48  	}
    49  	d, err := time.ParseDuration(s)
    50  	if err != nil {
    51  		f.G().Log.Warning("invalid time duration in config file: %s => %s", p, s)
    52  		return 0, false
    53  	}
    54  	return d, true
    55  }
    56  
    57  func (f *JSONConfigFile) GetTopLevelString(s string) (ret string) {
    58  	var e error
    59  	f.setMutex.RLock()
    60  	defer f.setMutex.RUnlock()
    61  	f.jw.AtKey(s).GetStringVoid(&ret, &e)
    62  	f.G().VDL.Log(VLog1, "Config: mapping %q -> %q", s, ret)
    63  	return
    64  }
    65  
    66  func (f *JSONConfigFile) GetTopLevelBool(s string) (res, isSet bool) {
    67  	f.setMutex.RLock()
    68  	defer f.setMutex.RUnlock()
    69  	if w := f.jw.AtKey(s); !w.IsNil() {
    70  		isSet = true
    71  		var e error
    72  		w.GetBoolVoid(&res, &e)
    73  	}
    74  	return
    75  }
    76  
    77  func (f *JSONConfigFile) GetUserConfig() (*UserConfig, error) {
    78  	f.userConfigWrapper.Lock()
    79  	defer f.userConfigWrapper.Unlock()
    80  	f.setMutex.RLock()
    81  	defer f.setMutex.RUnlock()
    82  	return f.getUserConfigWithLock()
    83  }
    84  
    85  // GetUserConfig looks for the `current_user` field to see if there's
    86  // a corresponding user object in the `users` table. There really should be.
    87  func (f *JSONConfigFile) getUserConfigWithLock() (ret *UserConfig, err error) {
    88  	var s string
    89  	if ret = f.userConfigWrapper.userConfig; ret != nil {
    90  		return
    91  	}
    92  	if s, err = f.jw.AtKey("current_user").GetString(); err != nil {
    93  		return
    94  	}
    95  	nu := NewNormalizedUsername(s)
    96  	if ret, err = f.getUserConfigForUsernameLocked(nu); err != nil {
    97  		return
    98  	} else if ret != nil {
    99  		f.userConfigWrapper.userConfig = ret
   100  	} else {
   101  		err = ConfigError{f.filename,
   102  			fmt.Sprintf("Didn't find a UserConfig for %s", s)}
   103  	}
   104  	return
   105  }
   106  
   107  func (f *JSONConfigFile) GetDeviceIDForUsername(nu NormalizedUsername) keybase1.DeviceID {
   108  	ret, err := f.GetUserConfigForUsername(nu)
   109  	var empty keybase1.DeviceID
   110  	if err != nil {
   111  		return empty
   112  	}
   113  	return ret.GetDeviceID()
   114  }
   115  
   116  func (f *JSONConfigFile) GetPassphraseStateForUsername(nu NormalizedUsername) (ret *keybase1.PassphraseState) {
   117  	userConfig, err := f.GetUserConfigForUsername(nu)
   118  	if err != nil || userConfig == nil {
   119  		return nil
   120  	}
   121  	return userConfig.GetPassphraseState()
   122  }
   123  
   124  func (f *JSONConfigFile) GetDeviceIDForUID(u keybase1.UID) keybase1.DeviceID {
   125  	ret, err := f.GetUserConfigForUID(u)
   126  	var empty keybase1.DeviceID
   127  	if err != nil || ret == nil {
   128  		return empty
   129  	}
   130  	return ret.GetDeviceID()
   131  }
   132  
   133  func (f *JSONConfigFile) GetUsernameForUID(u keybase1.UID) NormalizedUsername {
   134  	ret, err := f.GetUserConfigForUID(u)
   135  	var empty NormalizedUsername
   136  	if err != nil || ret == nil {
   137  		return empty
   138  	}
   139  	return ret.GetUsername()
   140  }
   141  
   142  func (f *JSONConfigFile) GetUIDForUsername(n NormalizedUsername) keybase1.UID {
   143  	ret, err := f.GetUserConfigForUsername(n)
   144  	var empty keybase1.UID
   145  	if err != nil || ret == nil {
   146  		return empty
   147  	}
   148  	return ret.GetUID()
   149  }
   150  
   151  func (f *JSONConfigFile) SwitchUser(nu NormalizedUsername) error {
   152  	f.userConfigWrapper.Lock()
   153  	defer f.userConfigWrapper.Unlock()
   154  	f.setMutex.Lock()
   155  	defer f.setMutex.Unlock()
   156  
   157  	if cu := f.getCurrentUser(); cu.Eq(nu) {
   158  		f.G().Log.Debug("| Already configured as user=%s", nu)
   159  		return nil
   160  	}
   161  
   162  	var err error
   163  	var val *jsonw.Wrapper
   164  	if f.jw.AtKey("users").AtKey(nu.String()).IsNil() {
   165  		val = jsonw.NewNil()
   166  		err = UserNotFoundError{Msg: nu.String()}
   167  	} else {
   168  		val = jsonw.NewString(nu.String())
   169  	}
   170  
   171  	setKeyErr := f.jw.SetKey("current_user", val)
   172  	if err == nil {
   173  		err = setKeyErr
   174  	}
   175  	f.userConfigWrapper.userConfig = nil
   176  	saveErr := f.Save()
   177  	if err == nil {
   178  		err = saveErr
   179  	}
   180  	return err
   181  }
   182  
   183  // NukeUser deletes the given user from the config file, or if
   184  // the given user is empty, deletes the current user from the
   185  // config file.
   186  func (f *JSONConfigFile) NukeUser(nu NormalizedUsername) error {
   187  	f.userConfigWrapper.Lock()
   188  	defer f.userConfigWrapper.Unlock()
   189  	f.setMutex.Lock()
   190  	defer f.setMutex.Unlock()
   191  
   192  	if cu := f.getCurrentUser(); nu.IsNil() || cu.Eq(nu) {
   193  		err := f.jw.DeleteValueAtPath("current_user")
   194  		f.userConfigWrapper.userConfig = nil
   195  		if err != nil {
   196  			return err
   197  		}
   198  		if nu.IsNil() {
   199  			nu = cu
   200  		}
   201  	}
   202  
   203  	if !f.jw.AtKey("users").AtKey(nu.String()).IsNil() {
   204  		err := f.jw.DeleteValueAtPath("users." + nu.String())
   205  		if err != nil {
   206  			return err
   207  		}
   208  	}
   209  
   210  	return f.Save()
   211  }
   212  
   213  // GetUserConfigForUsername sees if there's a UserConfig object for the given
   214  // username previously stored.
   215  func (f *JSONConfigFile) GetUserConfigForUsername(nu NormalizedUsername) (*UserConfig, error) {
   216  	f.userConfigWrapper.Lock()
   217  	defer f.userConfigWrapper.Unlock()
   218  	f.setMutex.Lock()
   219  	defer f.setMutex.Unlock()
   220  	return f.getUserConfigForUsernameLocked(nu)
   221  }
   222  
   223  func (f *JSONConfigFile) getUserConfigForUsernameLocked(nu NormalizedUsername) (*UserConfig, error) {
   224  	if uc := f.copyUserConfigIfForUsername(nu); uc != nil {
   225  		return uc, nil
   226  	}
   227  	return ImportUserConfigFromJSONWrapper(f.jw.AtKey("users").AtKey(nu.String()))
   228  }
   229  
   230  func (f *JSONConfigFile) copyUserConfigIfForUsername(u NormalizedUsername) *UserConfig {
   231  	if f.userConfigWrapper == nil || f.userConfigWrapper.userConfig == nil {
   232  		return nil
   233  	}
   234  	if f.userConfigWrapper.userConfig.GetUsername().IsNil() {
   235  		return nil
   236  	}
   237  	if f.userConfigWrapper.userConfig.GetUsername().Eq(u) {
   238  		tmp := *f.userConfigWrapper.userConfig
   239  		return &tmp
   240  	}
   241  	return nil
   242  }
   243  
   244  func (f *JSONConfigFile) copyUserConfigIfForUID(u keybase1.UID) *UserConfig {
   245  	if f.userConfigWrapper == nil || f.userConfigWrapper.userConfig == nil {
   246  		return nil
   247  	}
   248  	if f.userConfigWrapper.userConfig.GetUID().IsNil() {
   249  		return nil
   250  	}
   251  	if f.userConfigWrapper.userConfig.GetUID().Equal(u) {
   252  		tmp := *f.userConfigWrapper.userConfig
   253  		return &tmp
   254  	}
   255  	return nil
   256  }
   257  
   258  // GetUserConfigForUID sees if there's a UserConfig object for the given UIDs previously stored.
   259  func (f *JSONConfigFile) GetUserConfigForUID(u keybase1.UID) (*UserConfig, error) {
   260  	f.userConfigWrapper.Lock()
   261  	defer f.userConfigWrapper.Unlock()
   262  	f.setMutex.RLock()
   263  	defer f.setMutex.RUnlock()
   264  
   265  	if uc := f.copyUserConfigIfForUID(u); uc != nil {
   266  		return uc, nil
   267  	}
   268  
   269  	d := f.jw.AtKey("users")
   270  	keys, _ := d.Keys()
   271  	for _, key := range keys {
   272  		uc, err := f.getUserConfigForUsernameLocked(NewNormalizedUsername(key))
   273  		if err == nil && uc != nil && uc.GetUID().Equal(u) {
   274  			return uc, nil
   275  		}
   276  	}
   277  	return nil, nil
   278  }
   279  
   280  func (f *JSONConfigFile) GetAllUserConfigs() (current *UserConfig, others []UserConfig, err error) {
   281  	f.userConfigWrapper.Lock()
   282  	defer f.userConfigWrapper.Unlock()
   283  	f.setMutex.RLock()
   284  	defer f.setMutex.RUnlock()
   285  
   286  	currentUsername, allUsernames, err := f.getAllUsernamesLocked()
   287  	if err != nil {
   288  		return nil, nil, err
   289  	}
   290  
   291  	if !currentUsername.IsNil() {
   292  		current, _ = f.getUserConfigForUsernameLocked(currentUsername)
   293  	}
   294  
   295  	for _, u := range allUsernames {
   296  		tmp, err := f.getUserConfigForUsernameLocked(u)
   297  		if err == nil && tmp != nil {
   298  			others = append(others, *tmp)
   299  		}
   300  	}
   301  
   302  	return current, others, nil
   303  }
   304  
   305  func (f *JSONConfigFile) GetAllUsernames() (current NormalizedUsername, others []NormalizedUsername, err error) {
   306  	f.setMutex.RLock()
   307  	defer f.setMutex.RUnlock()
   308  	return f.getAllUsernamesLocked()
   309  }
   310  
   311  func (f *JSONConfigFile) getAllUsernamesLocked() (current NormalizedUsername, others []NormalizedUsername, err error) {
   312  	current = f.getCurrentUser()
   313  	uw := f.jw.AtKey("users")
   314  	if uw.IsNil() {
   315  		return
   316  	}
   317  	keys, e := uw.Keys()
   318  	if e != nil {
   319  		err = e
   320  		return
   321  	}
   322  	for _, k := range keys {
   323  		u := uw.AtKey(k)
   324  		if u == nil {
   325  			continue
   326  		}
   327  		name, e := u.AtKey("name").GetString()
   328  		if e != nil {
   329  			err = e
   330  			return
   331  		}
   332  		nu := NewNormalizedUsername(name)
   333  		if !nu.Eq(current) {
   334  			others = append(others, nu)
   335  		}
   336  	}
   337  	return
   338  }
   339  
   340  // SetDeviceID sets the device field of the UserConfig object
   341  func (f *JSONConfigFile) SetDeviceID(did keybase1.DeviceID) (err error) {
   342  	f.userConfigWrapper.Lock()
   343  	defer f.userConfigWrapper.Unlock()
   344  	f.setMutex.Lock()
   345  	defer f.setMutex.Unlock()
   346  
   347  	f.G().Log.Debug("| Setting DeviceID to %v\n", did)
   348  	var u *UserConfig
   349  	if u, err = f.getUserConfigWithLock(); err != nil {
   350  	} else if u == nil {
   351  		err = NoUserConfigError{}
   352  	} else {
   353  		u.SetDevice(did)
   354  		err = f.setUserConfigWithLock(u, true)
   355  	}
   356  	return
   357  }
   358  
   359  func (f *JSONConfigFile) getCurrentUser() NormalizedUsername {
   360  	s, _ := f.jw.AtKey("current_user").GetString()
   361  	return NormalizedUsername(s)
   362  }
   363  
   364  // SetUserConfig writes this UserConfig to the config file and updates the
   365  // currently active UserConfig in memory.  If the given UserConfig is nil, then
   366  // just empty everything out and clear the `current_user` field.  Note that
   367  // we never actually overwrite users.<username>, we just write it if it
   368  // doesn't already exist, and we update the `current_user` pointer.
   369  func (f *JSONConfigFile) SetUserConfig(u *UserConfig, overwrite bool) error {
   370  	f.userConfigWrapper.Lock()
   371  	defer f.userConfigWrapper.Unlock()
   372  	f.setMutex.Lock()
   373  	defer f.setMutex.Unlock()
   374  	return f.setUserConfigWithLock(u, overwrite)
   375  }
   376  
   377  func (f *JSONConfigFile) setUserConfigWithLock(u *UserConfig, overwrite bool) error {
   378  
   379  	if u == nil {
   380  		f.G().Log.Debug("| SetUserConfig(nil)")
   381  		err := f.jw.DeleteKey("current_user")
   382  		if err != nil {
   383  			return err
   384  		}
   385  		f.userConfigWrapper.userConfig = nil
   386  		return f.Save()
   387  	}
   388  
   389  	if u.IsOneshot() {
   390  		f.userConfigWrapper.userConfig = u
   391  		return nil
   392  	}
   393  
   394  	parent := f.jw.AtKey("users")
   395  	un := u.GetUsername()
   396  	f.G().Log.Debug("| SetUserConfig(%s)", un)
   397  	if parent.IsNil() {
   398  		parent = jsonw.NewDictionary()
   399  		err := f.jw.SetKey("users", parent)
   400  		if err != nil {
   401  			return err
   402  		}
   403  	}
   404  	if parent.AtKey(un.String()).IsNil() || overwrite {
   405  		uWrapper, err := jsonw.NewObjectWrapper(*u)
   406  		if err != nil {
   407  			return err
   408  		}
   409  		err = parent.SetKey(un.String(), uWrapper)
   410  		if err != nil {
   411  			return err
   412  		}
   413  		f.userConfigWrapper.userConfig = u
   414  	}
   415  
   416  	if !f.getCurrentUser().Eq(un) {
   417  		err := f.jw.SetKey("current_user", jsonw.NewString(un.String()))
   418  		if err != nil {
   419  			return err
   420  		}
   421  		f.userConfigWrapper.userConfig = nil
   422  	}
   423  
   424  	return f.Save()
   425  }
   426  
   427  func (f *JSONConfigFile) Reset() {
   428  	f.setMutex.Lock()
   429  	defer f.setMutex.Unlock()
   430  	f.jw = jsonw.NewDictionary()
   431  	_ = f.Save()
   432  }
   433  
   434  func (f *JSONConfigFile) GetHome() string {
   435  	return f.GetTopLevelString("home")
   436  }
   437  
   438  func (f *JSONConfigFile) GetMobileSharedHome() string {
   439  	return f.GetTopLevelString("mobile_shared_home")
   440  }
   441  
   442  func (f *JSONConfigFile) GetServerURI() (string, error) {
   443  	return f.GetTopLevelString("server"), nil
   444  }
   445  
   446  func (f *JSONConfigFile) GetConfigFilename() string {
   447  	return f.GetTopLevelString("config_file")
   448  }
   449  
   450  func (f *JSONConfigFile) GetUpdaterConfigFilename() string {
   451  	return f.GetTopLevelString("updater_config_file")
   452  }
   453  
   454  func (f *JSONConfigFile) GetGUIConfigFilename() string {
   455  	return f.GetTopLevelString("gui_config_file")
   456  }
   457  
   458  func (f *JSONConfigFile) GetDeviceCloneStateFilename() string {
   459  	return f.GetTopLevelString("device_clone_state_file")
   460  }
   461  
   462  func (f *JSONConfigFile) GetSecretKeyringTemplate() string {
   463  	return f.GetTopLevelString("secret_keyring")
   464  }
   465  
   466  func (f *JSONConfigFile) GetSessionFilename() string {
   467  	return f.GetTopLevelString("session_file")
   468  }
   469  
   470  func (f *JSONConfigFile) GetDbFilename() string {
   471  	return f.GetTopLevelString("db")
   472  }
   473  
   474  func (f *JSONConfigFile) GetChatDbFilename() string {
   475  	return f.GetTopLevelString("chat_db")
   476  }
   477  
   478  func (f *JSONConfigFile) GetPvlKitFilename() string {
   479  	return f.GetTopLevelString("pvl_kit")
   480  }
   481  
   482  func (f *JSONConfigFile) GetParamProofKitFilename() string {
   483  	return f.GetTopLevelString("paramproof_kit")
   484  }
   485  
   486  func (f *JSONConfigFile) GetExternalURLKitFilename() string {
   487  	return f.GetTopLevelString("externalurl_kit")
   488  }
   489  
   490  func (f *JSONConfigFile) GetProveBypass() (bool, bool) {
   491  	return f.GetBoolAtPath("prove_bypass")
   492  }
   493  
   494  func (f *JSONConfigFile) GetPinentry() string {
   495  	res, _ := f.GetStringAtPath("pinentry.path")
   496  	return res
   497  }
   498  
   499  func (f *JSONConfigFile) GetGpg() string {
   500  	res, _ := f.GetStringAtPath("gpg.command")
   501  	return res
   502  }
   503  
   504  func (f *JSONConfigFile) GetLocalRPCDebug() string {
   505  	return f.GetTopLevelString("local_rpc_debug")
   506  }
   507  
   508  func (f *JSONConfigFile) GetTimers() string {
   509  	return f.GetTopLevelString("timers")
   510  }
   511  
   512  func (f *JSONConfigFile) GetGpgOptions() []string {
   513  	var ret []string
   514  	if f.jw == nil {
   515  		// noop
   516  	} else if v := f.jw.AtPath("gpg.options"); v == nil {
   517  		// noop
   518  	} else if l, e := v.Len(); e != nil || l == 0 {
   519  		// noop
   520  	} else {
   521  		ret = make([]string, 0, l)
   522  		for i := 0; i < l; i++ {
   523  			if s, e := v.AtIndex(i).GetString(); e == nil {
   524  				ret = append(ret, s)
   525  			}
   526  		}
   527  	}
   528  	return ret
   529  }
   530  
   531  func (f *JSONConfigFile) GetRunMode() (ret RunMode, err error) {
   532  	ret = NoRunMode
   533  	if s, isSet := f.GetStringAtPath("run_mode"); isSet {
   534  		ret, err = StringToRunMode(s)
   535  	}
   536  	return ret, err
   537  }
   538  
   539  func (f *JSONConfigFile) GetFeatureFlags() (ret FeatureFlags, err error) {
   540  	if s, isSet := f.GetStringAtPath("features"); isSet {
   541  		ret = StringToFeatureFlags(s)
   542  	}
   543  	return ret, err
   544  }
   545  
   546  func (f *JSONConfigFile) GetNoPinentry() (bool, bool) {
   547  	return f.GetBoolAtPath("pinentry.disabled")
   548  }
   549  
   550  func (f *JSONConfigFile) GetUsername() (ret NormalizedUsername) {
   551  	if uc, _ := f.GetUserConfig(); uc != nil {
   552  		ret = uc.GetUsername()
   553  	}
   554  	return ret
   555  }
   556  
   557  func (f *JSONConfigFile) GetUID() (ret keybase1.UID) {
   558  	if uc, _ := f.GetUserConfig(); uc != nil {
   559  		ret = uc.GetUID()
   560  	}
   561  	return ret
   562  }
   563  
   564  func (f *JSONConfigFile) GetDeviceID() (ret keybase1.DeviceID) {
   565  	if uc, _ := f.GetUserConfig(); uc != nil {
   566  		ret = uc.GetDeviceID()
   567  	}
   568  	return ret
   569  }
   570  
   571  func (f *JSONConfigFile) GetPassphraseState() (ret *keybase1.PassphraseState) {
   572  	if uc, _ := f.GetUserConfig(); uc != nil {
   573  		ret = uc.GetPassphraseState()
   574  	}
   575  	return ret
   576  }
   577  
   578  func (f *JSONConfigFile) SetPassphraseState(passphraseState keybase1.PassphraseState) (err error) {
   579  	f.userConfigWrapper.Lock()
   580  	defer f.userConfigWrapper.Unlock()
   581  	f.setMutex.Lock()
   582  	defer f.setMutex.Unlock()
   583  
   584  	f.G().Log.Debug("| Setting PassphraseState to %v\n", passphraseState)
   585  	var u *UserConfig
   586  	if u, err = f.getUserConfigWithLock(); err != nil {
   587  	} else if u == nil {
   588  		err = NoUserConfigError{}
   589  	} else {
   590  		u.SetPassphraseState(passphraseState)
   591  		err = f.setUserConfigWithLock(u, true)
   592  	}
   593  	return
   594  }
   595  
   596  func (f *JSONConfigFile) GetTorMode() (ret TorMode, err error) {
   597  	if s, isSet := f.GetStringAtPath("tor.mode"); isSet {
   598  		ret, err = StringToTorMode(s)
   599  	}
   600  	return ret, err
   601  }
   602  
   603  func (f *JSONConfigFile) GetTorHiddenAddress() string {
   604  	s, _ := f.GetStringAtPath("tor.hidden_address")
   605  	return s
   606  }
   607  
   608  func (f *JSONConfigFile) GetTorProxy() string {
   609  	s, _ := f.GetStringAtPath("tor.proxy")
   610  	return s
   611  }
   612  
   613  func (f *JSONConfigFile) GetProxy() string {
   614  	return f.GetTopLevelString("proxy")
   615  }
   616  
   617  func (f *JSONConfigFile) GetProxyType() string {
   618  	return f.GetTopLevelString("proxy-type")
   619  }
   620  
   621  func (f *JSONConfigFile) IsCertPinningEnabled() bool {
   622  	res, isSet := f.GetTopLevelBool("disable-cert-pinning")
   623  	if !isSet {
   624  		// Enable SSL pinning if the flag is not set
   625  		return true
   626  	}
   627  	return !res
   628  }
   629  
   630  func (f *JSONConfigFile) GetDebug() (bool, bool) {
   631  	return f.GetTopLevelBool("debug")
   632  }
   633  
   634  func (f *JSONConfigFile) GetDebugJourneycard() (bool, bool) {
   635  	return f.GetTopLevelBool("debug_journeycard")
   636  }
   637  
   638  func (f *JSONConfigFile) GetDisplayRawUntrustedOutput() (bool, bool) {
   639  	return f.GetTopLevelBool("display_raw_untrusted_output")
   640  }
   641  
   642  func (f *JSONConfigFile) GetVDebugSetting() string {
   643  	return f.GetTopLevelString("vdebug")
   644  }
   645  
   646  func (f *JSONConfigFile) GetAutoFork() (bool, bool) {
   647  	return f.GetTopLevelBool("auto_fork")
   648  }
   649  
   650  func (f *JSONConfigFile) GetRememberPassphrase(username NormalizedUsername) (bool, bool) {
   651  	const legacyRememberPassphraseKey = "remember_passphrase"
   652  
   653  	if username.IsNil() {
   654  		return f.GetTopLevelBool(legacyRememberPassphraseKey)
   655  	}
   656  	if m, ok := f.jw.AtKey("remember_passphrase_map").GetDataOrNil().(map[string]interface{}); ok {
   657  		if ret, mOk := m[username.String()]; mOk {
   658  			if boolRet, boolOk := ret.(bool); boolOk {
   659  				return boolRet, true
   660  			}
   661  		}
   662  	}
   663  	return f.GetTopLevelBool(legacyRememberPassphraseKey)
   664  }
   665  
   666  func (f *JSONConfigFile) GetStayLoggedOut() (bool, bool) {
   667  	return f.GetBoolAtPath("stay_logged_out")
   668  }
   669  
   670  func (f *JSONConfigFile) SetStayLoggedOut(stayLoggedOut bool) error {
   671  	return f.SetBoolAtPath("stay_logged_out", stayLoggedOut)
   672  }
   673  
   674  func (f *JSONConfigFile) GetLogFormat() string {
   675  	return f.GetTopLevelString("log_format")
   676  }
   677  
   678  func (f *JSONConfigFile) GetStandalone() (bool, bool) {
   679  	return f.GetTopLevelBool("standalone")
   680  }
   681  
   682  func (f *JSONConfigFile) GetGregorURI() string {
   683  	s, _ := f.GetStringAtPath("push.server_uri")
   684  	return s
   685  }
   686  
   687  func (f *JSONConfigFile) GetGregorDisabled() (bool, bool) {
   688  	return f.GetBoolAtPath("push.disabled")
   689  }
   690  
   691  func (f *JSONConfigFile) GetSecretStorePrimingDisabled() (bool, bool) {
   692  	// SecretStorePrimingDisabled is only for tests
   693  	return false, false
   694  }
   695  
   696  func (f *JSONConfigFile) GetBGIdentifierDisabled() (bool, bool) {
   697  	return f.GetBoolAtPath("bg_identifier.disabled")
   698  }
   699  
   700  func (f *JSONConfigFile) GetGregorSaveInterval() (time.Duration, bool) {
   701  	return f.GetDurationAtPath("push.save_interval")
   702  }
   703  
   704  func (f *JSONConfigFile) GetGregorPingInterval() (time.Duration, bool) {
   705  	return f.GetDurationAtPath("push.ping_interval")
   706  }
   707  
   708  func (f *JSONConfigFile) GetGregorPingTimeout() (time.Duration, bool) {
   709  	return f.GetDurationAtPath("push.ping_timeout")
   710  }
   711  
   712  func (f *JSONConfigFile) GetChatDelivererInterval() (time.Duration, bool) {
   713  	return f.GetDurationAtPath("chat.deliverer_interval")
   714  }
   715  
   716  func (f *JSONConfigFile) getCacheSize(w string) (int, bool) {
   717  	return f.jw.AtPathGetInt(w)
   718  }
   719  
   720  func (f *JSONConfigFile) GetUserCacheMaxAge() (time.Duration, bool) {
   721  	return f.GetDurationAtPath("cache.maxage.users")
   722  }
   723  
   724  func (f *JSONConfigFile) GetAPITimeout() (time.Duration, bool) {
   725  	return f.GetDurationAtPath("timeouts.api")
   726  }
   727  
   728  func (f *JSONConfigFile) GetScraperTimeout() (time.Duration, bool) {
   729  	return f.GetDurationAtPath("timeouts.scraper")
   730  }
   731  
   732  func (f *JSONConfigFile) GetProofCacheSize() (int, bool) {
   733  	return f.getCacheSize("cache.limits.proofs")
   734  }
   735  
   736  func (f *JSONConfigFile) GetProofCacheLongDur() (time.Duration, bool) {
   737  	return f.GetDurationAtPath("cache.long_duration.proofs")
   738  }
   739  
   740  func (f *JSONConfigFile) GetProofCacheMediumDur() (time.Duration, bool) {
   741  	return f.GetDurationAtPath("cache.medium_duration.proofs")
   742  }
   743  
   744  func (f *JSONConfigFile) GetProofCacheShortDur() (time.Duration, bool) {
   745  	return f.GetDurationAtPath("cache.short_duration.proofs")
   746  }
   747  
   748  func (f *JSONConfigFile) GetLinkCacheSize() (int, bool) {
   749  	return f.getCacheSize("cache.limits.links")
   750  }
   751  
   752  func (f *JSONConfigFile) GetLinkCacheCleanDur() (time.Duration, bool) {
   753  	return f.GetDurationAtPath("cache.clean_duration.links")
   754  }
   755  
   756  func (f *JSONConfigFile) GetUPAKCacheSize() (int, bool) {
   757  	return f.getCacheSize("cache.limits.upak")
   758  }
   759  
   760  func (f *JSONConfigFile) GetUIDMapFullNameCacheSize() (int, bool) {
   761  	return f.getCacheSize("cache.limits.uid_map_full_name")
   762  }
   763  
   764  func (f *JSONConfigFile) GetPayloadCacheSize() (int, bool) {
   765  	return f.getCacheSize("cache.limits.payloads")
   766  }
   767  
   768  func (f *JSONConfigFile) GetLevelDBNumFiles() (int, bool) {
   769  	return f.GetIntAtPath("leveldb.num_files")
   770  }
   771  
   772  func (f *JSONConfigFile) GetLevelDBWriteBufferMB() (int, bool) {
   773  	return f.GetIntAtPath("leveldb.write_buffer_mb")
   774  }
   775  
   776  func (f *JSONConfigFile) GetChatInboxSourceLocalizeThreads() (int, bool) {
   777  	return f.GetIntAtPath("chat.inboxsource.localizethreads")
   778  }
   779  
   780  func (f *JSONConfigFile) getStringArray(v *jsonw.Wrapper) []string {
   781  	n, err := v.Len()
   782  	if err != nil {
   783  		return nil
   784  	}
   785  
   786  	if n == 0 {
   787  		return nil
   788  	}
   789  
   790  	ret := make([]string, n)
   791  	for i := 0; i < n; i++ {
   792  		s, err := v.AtIndex(i).GetString()
   793  		if err != nil {
   794  			return nil
   795  		}
   796  		ret[i] = s
   797  	}
   798  	return ret
   799  }
   800  
   801  func (f *JSONConfigFile) GetMerkleKIDs() []string {
   802  	if f.jw == nil {
   803  		return nil
   804  	}
   805  
   806  	v, err := f.jw.AtKey("keys").AtKey("merkle").ToArray()
   807  	if err != nil || v == nil {
   808  		return nil
   809  	}
   810  
   811  	return f.getStringArray(v)
   812  }
   813  
   814  func (f *JSONConfigFile) GetCodeSigningKIDs() []string {
   815  	if f.jw == nil {
   816  		return nil
   817  	}
   818  
   819  	v, err := f.jw.AtKey("keys").AtKey("codesigning").ToArray()
   820  	if err != nil || v == nil {
   821  		return nil
   822  	}
   823  	return f.getStringArray(v)
   824  }
   825  
   826  func (f *JSONConfigFile) GetGpgHome() (ret string) {
   827  	ret, _ = f.GetStringAtPath("gpg.home")
   828  	return ret
   829  }
   830  
   831  func (f *JSONConfigFile) GetBundledCA(host string) (ret string) {
   832  	f.setMutex.RLock()
   833  	defer f.setMutex.RUnlock()
   834  	var err error
   835  	f.jw.AtKey("bundled_ca").AtKey(host).GetStringVoid(&ret, &err)
   836  	if err == nil {
   837  		f.G().Log.Debug("Read bundled CA for %s", host)
   838  	}
   839  	return ret
   840  }
   841  
   842  func (f *JSONConfigFile) GetSocketFile() string {
   843  	return f.GetTopLevelString("socket_file")
   844  }
   845  
   846  func (f *JSONConfigFile) GetPidFile() string {
   847  	return f.GetTopLevelString("pid_file")
   848  }
   849  
   850  func (f *JSONConfigFile) GetProxyCACerts() (ret []string, err error) {
   851  	f.setMutex.RLock()
   852  	defer f.setMutex.RUnlock()
   853  	jw := f.jw.AtKey("proxy_ca_certs")
   854  	if l, e := jw.Len(); e == nil {
   855  		for i := 0; i < l; i++ {
   856  			s, e2 := jw.AtIndex(i).GetString()
   857  			if e2 != nil {
   858  				err = ConfigError{f.filename,
   859  					fmt.Sprintf("Error reading proxy CA file @ index %d: %s", i, e2)}
   860  				return
   861  			}
   862  
   863  			ret = append(ret, s)
   864  		}
   865  	} else if s, e := jw.GetString(); e == nil {
   866  		ret = strings.Split(s, ":")
   867  	} else if !jw.IsNil() {
   868  		err = ConfigError{f.filename, fmt.Sprintf("Can't read Proxy CA certs: %s", e)}
   869  	}
   870  	return
   871  }
   872  
   873  func (f *JSONConfigFile) GetLogFile() string {
   874  	return f.GetTopLevelString("log_file")
   875  }
   876  
   877  func (f *JSONConfigFile) GetEKLogFile() string {
   878  	return f.GetTopLevelString("ek_log_file")
   879  }
   880  
   881  func (f *JSONConfigFile) GetPerfLogFile() string {
   882  	return f.GetTopLevelString("perf_log_file")
   883  }
   884  
   885  func (f *JSONConfigFile) GetGUILogFile() string {
   886  	return f.GetTopLevelString("gui_log_file")
   887  }
   888  
   889  func (f *JSONConfigFile) GetUseDefaultLogFile() (bool, bool) {
   890  	return f.GetTopLevelBool("use_default_log_file")
   891  }
   892  
   893  func (f *JSONConfigFile) GetUseRootConfigFile() (bool, bool) {
   894  	return false, false
   895  }
   896  
   897  func (f *JSONConfigFile) GetLogPrefix() string {
   898  	return f.GetTopLevelString("log_prefix")
   899  }
   900  
   901  func (f *JSONConfigFile) GetSecurityAccessGroupOverride() (bool, bool) {
   902  	return false, false
   903  }
   904  
   905  func (f *JSONConfigFile) GetUpdatePreferenceAuto() (bool, bool) {
   906  	return f.GetBoolAtPath("updates.auto")
   907  }
   908  
   909  func (f *JSONConfigFile) GetUpdatePreferenceSnoozeUntil() keybase1.Time {
   910  	return f.GetTimeAtPath("updates.snooze")
   911  }
   912  
   913  func (f *JSONConfigFile) GetUpdateLastChecked() keybase1.Time {
   914  	return f.GetTimeAtPath("updates.last_checked")
   915  }
   916  
   917  func (f *JSONConfigFile) GetUpdatePreferenceSkip() string {
   918  	s, _ := f.GetStringAtPath("updates.skip")
   919  	return s
   920  }
   921  
   922  func (f *JSONConfigFile) SetUpdatePreferenceAuto(b bool) error {
   923  	return f.SetBoolAtPath("updates.auto", b)
   924  }
   925  
   926  func (f *JSONConfigFile) SetUpdatePreferenceSkip(v string) error {
   927  	return f.SetStringAtPath("updates.skip", v)
   928  }
   929  
   930  func (f *JSONConfigFile) SetUpdatePreferenceSnoozeUntil(t keybase1.Time) error {
   931  	return f.SetTimeAtPath("updates.snooze", t)
   932  }
   933  
   934  func (f *JSONConfigFile) SetUpdateLastChecked(t keybase1.Time) error {
   935  	return f.SetTimeAtPath("updates.last_checked", t)
   936  }
   937  
   938  func (f *JSONConfigFile) GetUpdateURL() string {
   939  	s, _ := f.GetStringAtPath("updates.url")
   940  	return s
   941  }
   942  
   943  func (f *JSONConfigFile) GetUpdateDisabled() (bool, bool) {
   944  	return f.GetBoolAtPath("updates.disabled")
   945  }
   946  
   947  func (f *JSONConfigFile) GetTimeAtPath(path string) keybase1.Time {
   948  	var ret keybase1.Time
   949  	s, _ := f.GetStringAtPath(path)
   950  	if len(s) == 0 {
   951  		return ret
   952  	}
   953  	u, err := strconv.ParseUint(s, 10, 64)
   954  	if err != nil {
   955  		return ret
   956  	}
   957  	ret = keybase1.Time(u)
   958  	return ret
   959  }
   960  
   961  func (f *JSONConfigFile) SetTimeAtPath(path string, t keybase1.Time) error {
   962  	if t == keybase1.Time(0) {
   963  		return f.SetNullAtPath(path)
   964  	}
   965  	return f.SetStringAtPath(path, fmt.Sprintf("%d", t))
   966  }
   967  
   968  func (f *JSONConfigFile) GetLocalTrackMaxAge() (time.Duration, bool) {
   969  	return f.GetDurationAtPath("local_track_max_age")
   970  }
   971  
   972  func (f *JSONConfigFile) GetMountDir() string {
   973  	return f.GetTopLevelString("mountdir")
   974  }
   975  
   976  func (f *JSONConfigFile) GetMountDirDefault() string {
   977  	return f.GetTopLevelString("mountdirdefault")
   978  }
   979  
   980  func bug3964path(un NormalizedUsername) string {
   981  	return fmt.Sprintf("maintenance.%s.bug_3964_repair_time", un)
   982  }
   983  
   984  func (f *JSONConfigFile) GetBug3964RepairTime(un NormalizedUsername) (time.Time, error) {
   985  	if un == "" {
   986  		return time.Time{}, NoUserConfigError{}
   987  	}
   988  	s, _ := f.GetStringAtPath(bug3964path(un))
   989  	if s == "" {
   990  		return time.Time{}, nil
   991  	}
   992  	i, err := strconv.ParseUint(s, 10, 64)
   993  	if err != nil {
   994  		return time.Time{}, err
   995  	}
   996  	return keybase1.FromTime(keybase1.Time(i)), nil
   997  }
   998  
   999  func (f *JSONConfigFile) SetBug3964RepairTime(un NormalizedUsername, t time.Time) (err error) {
  1000  	return f.SetStringAtPath(bug3964path(un), fmt.Sprintf("%d", int64(keybase1.ToTime(t))))
  1001  }
  1002  
  1003  func (f *JSONConfigFile) GetAppType() AppType {
  1004  	return AppType(f.GetTopLevelString("app_type"))
  1005  }
  1006  
  1007  func (f *JSONConfigFile) IsMobileExtension() (bool, bool) {
  1008  	return f.GetBoolAtPath("mobile_extension")
  1009  }
  1010  
  1011  func (f *JSONConfigFile) GetSlowGregorConn() (bool, bool) {
  1012  	return f.GetBoolAtPath("slow_gregor_conn")
  1013  }
  1014  
  1015  func (f *JSONConfigFile) GetReadDeletedSigChain() (bool, bool) {
  1016  	return f.GetBoolAtPath("read_deleted_sigchain")
  1017  }
  1018  
  1019  func (f *JSONConfigFile) SetRememberPassphrase(username NormalizedUsername, remember bool) error {
  1020  	if username.IsNil() {
  1021  		return f.SetBoolAtPath("remember_passphrase", remember)
  1022  	}
  1023  	return f.SetBoolAtPath(fmt.Sprintf("remember_passphrase_map.%s", username.String()), remember)
  1024  }
  1025  
  1026  func (f *JSONConfigFile) GetAttachmentHTTPStartPort() (int, bool) {
  1027  	return f.GetIntAtPath("attachment_httpsrv_port")
  1028  }
  1029  
  1030  func (f *JSONConfigFile) GetAttachmentDisableMulti() (bool, bool) {
  1031  	return f.GetBoolAtPath("attachment_disable_multi")
  1032  }
  1033  
  1034  func (f *JSONConfigFile) GetDisableTeamAuditor() (bool, bool) {
  1035  	return f.GetBoolAtPath("disable_team_auditor")
  1036  }
  1037  
  1038  func (f *JSONConfigFile) GetDisableTeamBoxAuditor() (bool, bool) {
  1039  	return f.GetBoolAtPath("disable_team_box_auditor")
  1040  }
  1041  
  1042  func (f *JSONConfigFile) GetDisableEKBackgroundKeygen() (bool, bool) {
  1043  	return f.GetBoolAtPath("disable_ek_background_keygen")
  1044  }
  1045  
  1046  func (f *JSONConfigFile) GetDisableMerkleAuditor() (bool, bool) {
  1047  	return f.GetBoolAtPath("disable_merkle_auditor")
  1048  }
  1049  
  1050  func (f *JSONConfigFile) GetDisableSearchIndexer() (bool, bool) {
  1051  	return f.GetBoolAtPath("disable_search_indexer")
  1052  }
  1053  
  1054  func (f *JSONConfigFile) GetDisableBgConvLoader() (bool, bool) {
  1055  	return f.GetBoolAtPath("disable_bg_conv_loader")
  1056  }
  1057  
  1058  func (f *JSONConfigFile) GetEnableBotLiteMode() (bool, bool) {
  1059  	return f.GetBoolAtPath("enable_bot_lite_mode")
  1060  }
  1061  
  1062  func (f *JSONConfigFile) GetExtraNetLogging() (bool, bool) {
  1063  	return f.GetBoolAtPath("extra_net_logging")
  1064  }
  1065  
  1066  func (f *JSONConfigFile) GetForceLinuxKeyring() (bool, bool) {
  1067  	return f.GetBoolAtPath("force_linux_keyring")
  1068  }
  1069  
  1070  func (f *JSONConfigFile) GetForceSecretStoreFile() (bool, bool) {
  1071  	return f.GetBoolAtPath("force_less_safe_secret_store_file")
  1072  }
  1073  
  1074  func (f *JSONConfigFile) GetRuntimeStatsEnabled() (bool, bool) {
  1075  	return f.GetBoolAtPath("runtime_stats_enabled")
  1076  }
  1077  
  1078  func (f *JSONConfigFile) GetAndroidInstallReferrerChecked() bool {
  1079  	val, isSet := f.GetBoolAtPath("android_install_referrer_checked")
  1080  	// default to false when value is not set
  1081  	return isSet && val
  1082  }
  1083  
  1084  func (f *JSONConfigFile) SetAndroidInstallReferrerChecked(b bool) error {
  1085  	return f.SetBoolAtPath("android_install_referrer_checked", b)
  1086  }