github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/libkb/globals.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  //
     5  // globals
     6  //
     7  //   All of the global objects in the libkb namespace that are shared
     8  //   and mutated across various source files are here.  They are
     9  //   accessed like `G.Log` or `G.Env`.  They're kept
    10  //   under the `G` namespace to better keep track of them all.
    11  //
    12  //   The globals are built up gradually as the process comes up.
    13  //   At first, we only have a logger, but eventually we add
    14  //   command-line flags, configuration and environment, and accordingly,
    15  //   might actually go back and change the Logger.
    16  
    17  package libkb
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"io"
    23  	"log"
    24  	"os"
    25  	"runtime"
    26  	"sync"
    27  	"time"
    28  
    29  	logger "github.com/keybase/client/go/logger"
    30  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    31  	clockwork "github.com/keybase/clockwork"
    32  	context "golang.org/x/net/context"
    33  )
    34  
    35  var IsIPad bool // Set by bind's Init.
    36  
    37  type ShutdownHook func(mctx MetaContext) error
    38  
    39  type LoginHook interface {
    40  	OnLogin(mctx MetaContext) error
    41  }
    42  
    43  type LogoutHook interface {
    44  	OnLogout(mctx MetaContext) error
    45  }
    46  
    47  type DbNukeHook interface {
    48  	OnDbNuke(mctx MetaContext) error
    49  }
    50  
    51  type GlobalContext struct {
    52  	Log                              logger.Logger         // Handles all logging
    53  	PerfLog                          logger.Logger         // Handles all performance event logging
    54  	VDL                              *VDebugLog            // verbose debug log
    55  	GUILogFile                       *logger.LogFileWriter // GUI logs
    56  	Env                              *Env                  // Env variables, cmdline args & config
    57  	SKBKeyringMu                     *sync.Mutex           // Protects all attempts to mutate the SKBKeyringFile
    58  	Keyrings                         *Keyrings             // Gpg Keychains holding keys
    59  	perUserKeyringMu                 *sync.Mutex
    60  	perUserKeyring                   *PerUserKeyring             // Keyring holding per user keys
    61  	API                              API                         // How to make a REST call to the server
    62  	Resolver                         Resolver                    // cache of resolve results
    63  	LocalNetworkInstrumenterStorage  *DiskInstrumentationStorage // Instrument Local RPC calls
    64  	RemoteNetworkInstrumenterStorage *DiskInstrumentationStorage // Instrument Remote API/RPC calls
    65  	LocalDb                          *JSONLocalDb                // Local DB for cache
    66  	LocalChatDb                      *JSONLocalDb                // Local DB for cache
    67  	MerkleClient                     MerkleClientInterface       // client for querying server's merkle sig tree
    68  	XAPI                             ExternalAPI                 // for contacting Twitter, Github, etc.
    69  	DNSNSFetcher                     DNSNameServerFetcher        // The mobile apps potentially pass an implementor of this interface which is used to grab currently configured DNS name servers
    70  	MobileNetState                   *MobileNetState             // The kind of network connection for the currently running instance of the app
    71  	MobileAppState                   *MobileAppState             // The state of focus for the currently running instance of the app
    72  	DesktopAppState                  *DesktopAppState            // The state of focus for the currently running instance of the app
    73  	ChatHelper                       ChatHelper                  // conveniently send chat messages
    74  	RPCCanceler                      *RPCCanceler                // register live RPCs so they can be cancelleed en masse
    75  	IdentifyDispatch                 *IdentifyDispatch           // get notified of identify successes
    76  	Identify3State                   *Identify3State             // keep track of Identify3 sessions
    77  	vidMu                            *sync.Mutex                 // protect VID
    78  	RuntimeStats                     RuntimeStats                // performance runtime stats
    79  
    80  	cacheMu                *sync.RWMutex   // protects all caches
    81  	ProofCache             *ProofCache     // where to cache proof results
    82  	trackCache             *TrackCache     // cache of IdentifyOutcomes for tracking purposes
    83  	identify2Cache         Identify2Cacher // cache of Identify2 results for fast-pathing identify2 RPCS
    84  	linkCache              *LinkCache      // cache of ChainLinks
    85  	upakLoader             UPAKLoader      // Load flat users with the ability to hit the cache
    86  	teamLoader             TeamLoader      // Play back teams for id/name properties
    87  	fastTeamLoader         FastTeamLoader  // Play back team in "fast" mode for keys and names only
    88  	hiddenTeamChainManager HiddenTeamChainManager
    89  	TeamRoleMapManager     TeamRoleMapManager
    90  	IDLocktab              *LockTable
    91  	loadUserLockTab        *LockTable
    92  	teamAuditor            TeamAuditor
    93  	teamBoxAuditor         TeamBoxAuditor
    94  	stellar                Stellar            // Stellar related ops
    95  	deviceEKStorage        DeviceEKStorage    // Store device ephemeral keys
    96  	userEKBoxStorage       UserEKBoxStorage   // Store user ephemeral key boxes
    97  	teamEKBoxStorage       TeamEKBoxStorage   // Store team ephemeral key boxes
    98  	teambotEKBoxStorage    TeamEKBoxStorage   // Store team bot ephemeral key boxes
    99  	ekLib                  EKLib              // Wrapper to call ephemeral key methods
   100  	teambotBotKeyer        TeambotBotKeyer    // TeambotKeyer for bot members
   101  	teambotMemberKeyer     TeambotMemberKeyer // TeambotKeyer for non-bot members
   102  	itciCacher             LRUer              // Cacher for implicit team conflict info
   103  	iteamCacher            MemLRUer           // In memory cacher for implicit teams
   104  	cardCache              *UserCardCache     // cache of keybase1.UserCard objects
   105  	fullSelfer             FullSelfer         // a loader that gets the full self object
   106  	pvlSource              MerkleStore        // a cache and fetcher for pvl
   107  	paramProofStore        MerkleStore        // a cache and fetcher for param proofs
   108  	externalURLStore       MerkleStore        // a cache and fetcher for external urls
   109  	PayloadCache           *PayloadCache      // cache of ChainLink payload json wrappers
   110  	kvRevisionCache        KVRevisionCacher   // cache of revisions for verifying key-value store results
   111  	Pegboard               *Pegboard
   112  
   113  	GpgClient        *GpgCLI        // A standard GPG-client (optional)
   114  	ShutdownHooks    []ShutdownHook // on shutdown, fire these...
   115  	SocketInfo       Socket         // which socket to bind/connect to
   116  	socketWrapperMu  *sync.RWMutex
   117  	SocketWrapper    *SocketWrapper    // only need one connection per
   118  	LoopbackListener *LoopbackListener // If we're in loopback mode, we'll connect through here
   119  	XStreams         *ExportedStreams  // a table of streams we've exported to the daemon (or vice-versa)
   120  	Timers           *TimerSet         // Which timers are currently configured on
   121  	UI               UI                // Interact with the UI
   122  	Service          bool              // whether we're in server mode
   123  	Standalone       bool              // whether we're launched as standalone command
   124  
   125  	shutdownOnce      *sync.Once         // whether we've shut down or not
   126  	ConnectionManager *ConnectionManager // keep tabs on all active client connections
   127  	NotifyRouter      *NotifyRouter      // How to route notifications
   128  	// How to route UIs. Nil if we're in standalone mode or in
   129  	// tests, and non-nil in service mode.
   130  	UIRouter           UIRouter                  // How to route UIs
   131  	proofServices      ExternalServicesCollector // All known external services
   132  	UIDMapper          UIDMapper                 // maps from UID to Usernames
   133  	ServiceMapper      ServiceSummaryMapper      // handles and caches batch requests for service summaries
   134  	ExitCode           keybase1.ExitCode         // Value to return to OS on Exit()
   135  	RateLimits         *RateLimits               // tracks the last time certain actions were taken
   136  	clockMu            *sync.Mutex               // protects Clock
   137  	clock              clockwork.Clock           // RealClock unless we're testing
   138  	secretStoreMu      *sync.Mutex               // protects secretStore
   139  	secretStore        *SecretStoreLocked        // SecretStore
   140  	hookMu             *sync.RWMutex             // protects loginHooks, logoutHooks
   141  	loginHooks         []LoginHook               // call these on login
   142  	logoutHooks        []NamedLogoutHook         // call these on logout
   143  	dbNukeHooks        []NamedDbNukeHook         // call these on dbnuke
   144  	GregorState        GregorState               // for dismissing gregor items that we've handled
   145  	GregorListener     GregorListener            // for alerting about clients connecting and registering UI protocols
   146  	oodiMu             *sync.RWMutex             // For manipulating the OutOfDateInfo
   147  	outOfDateInfo      *keybase1.OutOfDateInfo   // Stores out of date messages we got from API server headers.
   148  	lastUpgradeWarning *time.Time                // When the last upgrade was warned for (to reate-limit nagging)
   149  
   150  	uchMu               *sync.Mutex          // protects the UserChangedHandler array
   151  	UserChangedHandlers []UserChangedHandler // a list of handlers that deal generically with userchanged events
   152  	ConnectivityMonitor ConnectivityMonitor  // Detect whether we're connected or not.
   153  	localSigchainGuard  *LocalSigchainGuard  // Non-strict guard for shoeing away bg tasks when the user is doing sigchain actions
   154  	FeatureFlags        *FeatureFlagSet      // user's feature flag set
   155  
   156  	StandaloneChatConnector StandaloneChatConnector
   157  
   158  	// Can be overloaded by tests to get an improvement in performance
   159  	NewTriplesec func(pw []byte, salt []byte) (Triplesec, error)
   160  
   161  	// Options specified for testing only
   162  	TestOptions GlobalTestOptions
   163  
   164  	// Interface to get (cryptographically secure) randomness. Makes it easier
   165  	// to test randomized behaviors.
   166  	random Random
   167  
   168  	// It is threadsafe to call methods on ActiveDevice which will always be non-nil.
   169  	// But don't access its members directly. If you're going to be changing out the
   170  	// user (and resetting the ActiveDevice), then you should hold the switchUserMu
   171  	switchUserMu  *VerboseLock
   172  	ActiveDevice  *ActiveDevice
   173  	switchedUsers map[NormalizedUsername]bool // bookkeep users who have been switched over (and are still in secret store)
   174  
   175  	// OS Version passed from mobile native code. iOS and Android only.
   176  	// See go/bind/keybase.go
   177  	MobileOsVersion string
   178  	IsIPad          bool
   179  
   180  	SyncedContactList SyncedContactListProvider
   181  
   182  	GUIConfig *JSONFile
   183  
   184  	avatarLoader AvatarLoaderSource
   185  
   186  	TeamMemberCountCache *TeamMemberCountCache
   187  }
   188  
   189  type GlobalTestOptions struct {
   190  	NoBug3964Repair             bool
   191  	NoAutorotateOnBoxAuditRetry bool
   192  }
   193  
   194  func (g *GlobalContext) GetLog() logger.Logger                         { return g.Log }
   195  func (g *GlobalContext) GetPerfLog() logger.Logger                     { return g.PerfLog }
   196  func (g *GlobalContext) GetGUILogWriter() io.Writer                    { return g.GUILogFile }
   197  func (g *GlobalContext) GetVDebugLog() *VDebugLog                      { return g.VDL }
   198  func (g *GlobalContext) GetAPI() API                                   { return g.API }
   199  func (g *GlobalContext) GetExternalAPI() ExternalAPI                   { return g.XAPI }
   200  func (g *GlobalContext) GetServerURI() (string, error)                 { return g.Env.GetServerURI() }
   201  func (g *GlobalContext) GetEnv() *Env                                  { return g.Env }
   202  func (g *GlobalContext) GetDNSNameServerFetcher() DNSNameServerFetcher { return g.DNSNSFetcher }
   203  func (g *GlobalContext) GetKVStore() KVStorer                          { return g.LocalDb }
   204  func (g *GlobalContext) GetClock() clockwork.Clock                     { return g.Clock() }
   205  func (g *GlobalContext) GetEKLib() EKLib                               { return g.ekLib }
   206  func (g *GlobalContext) GetTeambotBotKeyer() TeambotBotKeyer           { return g.teambotBotKeyer }
   207  func (g *GlobalContext) GetTeambotMemberKeyer() TeambotMemberKeyer     { return g.teambotMemberKeyer }
   208  func (g *GlobalContext) GetProofServices() ExternalServicesCollector   { return g.proofServices }
   209  func (g *GlobalContext) GetAvatarLoader() AvatarLoaderSource           { return g.avatarLoader }
   210  
   211  func (g *GlobalContext) GetRandom() Random { return g.random }
   212  func (g *GlobalContext) SetRandom(r Random) {
   213  	if g.GetRunMode() != DevelRunMode {
   214  		panic("Random can only be altered in devel")
   215  	}
   216  	g.random = r
   217  }
   218  
   219  type LogGetter func() logger.Logger
   220  
   221  // Note: all these sync.Mutex fields are pointers so that the Clone funcs work.
   222  func NewGlobalContext() *GlobalContext {
   223  	log := logger.New("keybase")
   224  	ret := &GlobalContext{
   225  		Log:                log,
   226  		PerfLog:            log,
   227  		VDL:                NewVDebugLog(log),
   228  		SKBKeyringMu:       new(sync.Mutex),
   229  		perUserKeyringMu:   new(sync.Mutex),
   230  		vidMu:              new(sync.Mutex),
   231  		cacheMu:            new(sync.RWMutex),
   232  		socketWrapperMu:    new(sync.RWMutex),
   233  		shutdownOnce:       new(sync.Once),
   234  		clockMu:            new(sync.Mutex),
   235  		clock:              clockwork.NewRealClock(),
   236  		hookMu:             new(sync.RWMutex),
   237  		oodiMu:             new(sync.RWMutex),
   238  		outOfDateInfo:      &keybase1.OutOfDateInfo{},
   239  		lastUpgradeWarning: new(time.Time),
   240  		uchMu:              new(sync.Mutex),
   241  		secretStoreMu:      new(sync.Mutex),
   242  		NewTriplesec:       NewSecureTriplesec,
   243  		ActiveDevice:       NewActiveDevice(),
   244  		switchUserMu:       NewVerboseLock(VLog0, "switchUserMu"),
   245  		FeatureFlags:       NewFeatureFlagSet(),
   246  		switchedUsers:      make(map[NormalizedUsername]bool),
   247  		Pegboard:           NewPegboard(),
   248  		random:             &SecureRandom{},
   249  		RuntimeStats:       NewDummyRuntimeStats(),
   250  	}
   251  	ret.TeamMemberCountCache = newTeamMemberCountCache(ret)
   252  	return ret
   253  }
   254  
   255  func init() {
   256  }
   257  
   258  func (g *GlobalContext) SetCommandLine(cmd CommandLine) { g.Env.SetCommandLine(cmd) }
   259  
   260  func (g *GlobalContext) SetUI(u UI) { g.UI = u }
   261  
   262  func (g *GlobalContext) SetEKLib(ekLib EKLib) { g.ekLib = ekLib }
   263  
   264  func (g *GlobalContext) SetTeambotBotKeyer(keyer TeambotBotKeyer) { g.teambotBotKeyer = keyer }
   265  
   266  func (g *GlobalContext) SetTeambotMemberKeyer(keyer TeambotMemberKeyer) { g.teambotMemberKeyer = keyer }
   267  
   268  func (g *GlobalContext) initPerfLogFile() {
   269  	lfc := g.Env.GetLogFileConfig(g.Env.GetPerfLogFile())
   270  	lfc.SkipRedirectStdErr = true
   271  	lfw := logger.NewLogFileWriter(*lfc)
   272  	if err := lfw.Open(g.GetClock().Now()); err != nil {
   273  		g.Log.Debug("Unable to getLogger %v", err)
   274  		return
   275  	}
   276  	g.PerfLog = logger.NewInternalLogger(log.New(lfw, "", log.LstdFlags|log.Lmicroseconds|log.Lshortfile))
   277  }
   278  
   279  func (g *GlobalContext) initGUILogFile() {
   280  	config := g.Env.GetLogFileConfig(g.Env.GetGUILogFile())
   281  	config.SkipRedirectStdErr = true
   282  	fileWriter := logger.NewLogFileWriter(*config)
   283  	if err := fileWriter.Open(g.GetClock().Now()); err != nil {
   284  		g.GetLog().Debug("Unable to init GUI log file %v", err)
   285  		return
   286  	}
   287  	g.GUILogFile = fileWriter
   288  }
   289  
   290  func (g *GlobalContext) Init() *GlobalContext {
   291  	g.Env = NewEnv(nil, nil, g.GetLog)
   292  	g.Service = false
   293  	g.Resolver = NewResolverImpl()
   294  	g.RateLimits = NewRateLimits(g)
   295  	g.upakLoader = NewUncachedUPAKLoader(g)
   296  	g.teamLoader = newNullTeamLoader(g)
   297  	g.fastTeamLoader = newNullFastTeamLoader()
   298  	g.hiddenTeamChainManager = newNullHiddenTeamChainManager()
   299  	g.TeamRoleMapManager = newNullTeamRoleMapManager()
   300  	g.teamAuditor = newNullTeamAuditor()
   301  	g.teamBoxAuditor = newNullTeamBoxAuditor()
   302  	g.stellar = newNullStellar(g)
   303  	g.fullSelfer = NewUncachedFullSelf(g)
   304  	g.ConnectivityMonitor = NullConnectivityMonitor{}
   305  	g.localSigchainGuard = NewLocalSigchainGuard(g)
   306  	g.MobileNetState = NewMobileNetState(g)
   307  	g.MobileAppState = NewMobileAppState(g)
   308  	g.DesktopAppState = NewDesktopAppState(g)
   309  	g.RPCCanceler = NewRPCCanceler()
   310  	g.IdentifyDispatch = NewIdentifyDispatch()
   311  	g.Identify3State = NewIdentify3State(g)
   312  	g.GregorState = newNullGregorState()
   313  	g.LocalNetworkInstrumenterStorage = NewDiskInstrumentationStorage(g, keybase1.NetworkSource_LOCAL)
   314  	g.RemoteNetworkInstrumenterStorage = NewDiskInstrumentationStorage(g, keybase1.NetworkSource_REMOTE)
   315  
   316  	g.Log.Debug("GlobalContext#Init(%p)\n", g)
   317  
   318  	return g
   319  }
   320  
   321  func NewGlobalContextInit() *GlobalContext {
   322  	return NewGlobalContext().Init()
   323  }
   324  
   325  func (g *GlobalContext) SetService() {
   326  	g.Service = true
   327  	g.ConnectionManager = NewConnectionManager()
   328  	g.NotifyRouter = NewNotifyRouter(g)
   329  }
   330  
   331  func (g *GlobalContext) SetUIDMapper(u UIDMapper) {
   332  	g.UIDMapper = u
   333  }
   334  
   335  func (g *GlobalContext) SetServiceSummaryMapper(u ServiceSummaryMapper) {
   336  	g.ServiceMapper = u
   337  }
   338  
   339  func (g *GlobalContext) SetUIRouter(u UIRouter) {
   340  	g.UIRouter = u
   341  }
   342  
   343  func (g *GlobalContext) SetDNSNameServerFetcher(d DNSNameServerFetcher) {
   344  	g.DNSNSFetcher = d
   345  }
   346  
   347  func (g *GlobalContext) SetUPAKLoader(u UPAKLoader) {
   348  	g.upakLoader = u
   349  }
   350  
   351  func (g *GlobalContext) SetAvatarLoader(a AvatarLoaderSource) {
   352  	g.avatarLoader = a
   353  }
   354  
   355  // simulateServiceRestart simulates what happens when a service restarts for the
   356  // purposes of testing.
   357  func (g *GlobalContext) simulateServiceRestart() {
   358  	defer g.switchUserMu.Acquire(NewMetaContext(context.TODO(), g), "simulateServiceRestart")()
   359  	_ = g.ActiveDevice.Clear()
   360  }
   361  
   362  // ConfigureLogging should be given non-nil Usage if called by the main
   363  // service.
   364  func (g *GlobalContext) ConfigureLogging(usage *Usage) error {
   365  	style := g.Env.GetLogFormat()
   366  	debug := g.Env.GetDebug()
   367  
   368  	logFile, ok := g.Env.GetEffectiveLogFile()
   369  	// Configure regardless if the logFile should be used or not
   370  	g.Log.Configure(style, debug, logFile)
   371  
   372  	// Start redirecting logs if the logFile should be used
   373  	// If this is not called, prints logs to stdout.
   374  	if ok {
   375  		err := logger.SetLogFileConfig(g.Env.GetLogFileConfig(logFile), &logger.BufferedLoggerConfig{
   376  			Frequency: 200 * time.Millisecond,
   377  			Size:      1000000,
   378  		})
   379  		if err != nil {
   380  			return err
   381  		}
   382  	}
   383  	g.VDL.Configure(g.Env.GetVDebugSetting())
   384  
   385  	// On Linux, the post-install script calls `keybase --use-root-config-file
   386  	// config get --direct` to figure out if the redirector should be enabled or not.
   387  	// That command, like all other commands, goes through all these initial steps
   388  	// like ConfigureLogging before executing the command. On Ubuntu, '$HOME' is *not*
   389  	// changed to the root's user's HOME when using sudo, which basically means
   390  	// that `sudo bash -c 'mkdir $HOME/.cache'`, e.g., creates it within the *user's*
   391  	// home directory with root permissions (unlike Debian, Fedora, Arch, etc.).
   392  	// So, in this case, we do not configure the log files so as not to mess up
   393  	// permissions in the user's home directory.
   394  	shouldInitLogs := true
   395  	if usage != nil && usage.AllowRoot {
   396  		isAdmin, _, err := IsSystemAdminUser()
   397  		if err == nil && isAdmin {
   398  			shouldInitLogs = false
   399  		}
   400  	}
   401  
   402  	if shouldInitLogs {
   403  		g.initGUILogFile()
   404  		g.initPerfLogFile()
   405  	}
   406  
   407  	return nil
   408  }
   409  
   410  func (g *GlobalContext) PushShutdownHook(sh ShutdownHook) {
   411  	g.ShutdownHooks = append(g.ShutdownHooks, sh)
   412  }
   413  
   414  func (g *GlobalContext) ConfigureConfig() error {
   415  	c := NewJSONConfigFile(g, g.Env.GetConfigFilename())
   416  	err := c.Load(false)
   417  	if err != nil {
   418  		return err
   419  	}
   420  	if err = c.Check(); err != nil {
   421  		return err
   422  	}
   423  	g.Env.SetConfig(c, c)
   424  	return nil
   425  }
   426  
   427  func (g *GlobalContext) ConfigReload() error {
   428  	err := g.ConfigureConfig()
   429  	if err != nil {
   430  		return err
   431  	}
   432  	guiConfigErr := g.ConfigureGUIConfig()
   433  	if guiConfigErr != nil {
   434  		g.Log.Debug("Failed to open gui config: %s", guiConfigErr)
   435  	}
   436  	return g.ConfigureUpdaterConfig()
   437  }
   438  
   439  // migrateGUIConfig does not delete old values from service's config.
   440  func migrateGUIConfig(serviceConfig ConfigReader, guiConfig *JSONFile) error {
   441  	var errs []error
   442  
   443  	p := "ui.routeState2"
   444  	if uiRouteState2, isSet := serviceConfig.GetStringAtPath(p); isSet {
   445  		if err := guiConfig.SetStringAtPath(p, uiRouteState2); err != nil {
   446  			errs = append(errs, err)
   447  		}
   448  	}
   449  
   450  	p = "ui.shownMonsterPushPrompt"
   451  	if uiMonsterStorage, isSet := serviceConfig.GetBoolAtPath(p); isSet {
   452  		if err := guiConfig.SetBoolAtPath(p, uiMonsterStorage); err != nil {
   453  			errs = append(errs, err)
   454  		}
   455  	}
   456  
   457  	p = "stellar.lastSentXLM"
   458  	if stellarLastSentXLM, isSet := serviceConfig.GetBoolAtPath(p); isSet {
   459  		if err := guiConfig.SetBoolAtPath(p, stellarLastSentXLM); err != nil {
   460  			errs = append(errs, err)
   461  		}
   462  	}
   463  
   464  	p = "ui.importContacts"
   465  	syncSettings, err := serviceConfig.GetInterfaceAtPath(p)
   466  	if err != nil {
   467  		if !isJSONNoSuchKeyError(err) {
   468  			errs = append(errs, err)
   469  		}
   470  	} else {
   471  		syncSettings, ok := syncSettings.(map[string]interface{})
   472  		if !ok {
   473  			errs = append(errs, fmt.Errorf("Failed to coerce ui.importContacts in migration"))
   474  		} else {
   475  			for username, syncEnabled := range syncSettings {
   476  				syncEnabled, ok := syncEnabled.(bool)
   477  				if !ok {
   478  					errs = append(errs, fmt.Errorf("Failed to coerce syncEnabled in migration for %s", username))
   479  				}
   480  				err := guiConfig.SetBoolAtPath(fmt.Sprintf("%s.%s", p, username), syncEnabled)
   481  				if err != nil {
   482  					errs = append(errs, err)
   483  				}
   484  			}
   485  		}
   486  	}
   487  	return CombineErrors(errs...)
   488  }
   489  
   490  func (g *GlobalContext) ConfigureGUIConfig() error {
   491  	guiConfig := NewJSONFile(g, g.Env.GetGUIConfigFilename(), "gui config")
   492  	found, err := guiConfig.LoadCheckFound()
   493  	if err == nil {
   494  		if !found {
   495  			err := guiConfig.SetBoolAtPath("gui", true)
   496  			if err != nil {
   497  				return err
   498  			}
   499  			// If this is the first time creating this file, manually migrate
   500  			// old GUI config values from the main config file best-effort.
   501  			serviceConfig := g.Env.GetConfig()
   502  			if migrateErr := migrateGUIConfig(serviceConfig, guiConfig); migrateErr != nil {
   503  				g.Log.Debug("Failed to migrate config to new GUI config file: %s", migrateErr)
   504  			}
   505  
   506  		}
   507  		g.Env.SetGUIConfig(guiConfig)
   508  	}
   509  	return err
   510  }
   511  
   512  func (g *GlobalContext) ConfigureUpdaterConfig() error {
   513  	c := NewJSONUpdaterConfigFile(g)
   514  	err := c.Load(false)
   515  	if err == nil {
   516  		g.Env.SetUpdaterConfig(c)
   517  	} else {
   518  		g.Log.Debug("Failed to open update config: %s\n", err)
   519  	}
   520  	return err
   521  }
   522  
   523  func (g *GlobalContext) ConfigureTimers() error {
   524  	g.Timers = NewTimerSet(g)
   525  	return nil
   526  }
   527  
   528  func (g *GlobalContext) ConfigureKeyring() error {
   529  	g.Keyrings = NewKeyrings(g)
   530  	return nil
   531  }
   532  
   533  func VersionMessage(linefn func(string)) {
   534  	linefn(fmt.Sprintf("Keybase CLI %s", VersionString()))
   535  	linefn(fmt.Sprintf("- Built with %s", runtime.Version()))
   536  	linefn("- Visit https://keybase.io for more details")
   537  }
   538  
   539  func (g *GlobalContext) StartupMessage() {
   540  	VersionMessage(func(s string) { g.Log.Debug(s) })
   541  }
   542  
   543  func (g *GlobalContext) ConfigureAPI() error {
   544  	iapi, xapi, err := NewAPIEngines(g)
   545  	if err != nil {
   546  		return fmt.Errorf("Failed to configure API access: %s", err)
   547  	}
   548  	g.API = iapi
   549  	g.XAPI = xapi
   550  	return nil
   551  }
   552  
   553  // shutdownCachesLocked shutdown any non-nil caches that have running goroutines
   554  // in them. It can be called from either configureMemCachesLocked (via logout or flush),
   555  // or via Shutdown. In either case, callers must hold g.cacheMu.
   556  func (g *GlobalContext) shutdownCachesLocked() {
   557  
   558  	// shutdown and nil out any existing caches.
   559  	if g.trackCache != nil {
   560  		g.trackCache.Shutdown()
   561  	}
   562  	if g.identify2Cache != nil {
   563  		g.identify2Cache.Shutdown()
   564  	}
   565  	if g.linkCache != nil {
   566  		g.linkCache.Shutdown()
   567  	}
   568  	if g.cardCache != nil {
   569  		g.cardCache.Shutdown()
   570  	}
   571  }
   572  
   573  func (g *GlobalContext) TrackCache() *TrackCache {
   574  	g.cacheMu.Lock()
   575  	defer g.cacheMu.Unlock()
   576  	return g.trackCache
   577  }
   578  
   579  func (g *GlobalContext) Identify2Cache() Identify2Cacher {
   580  	g.cacheMu.Lock()
   581  	defer g.cacheMu.Unlock()
   582  	return g.identify2Cache
   583  }
   584  
   585  func (g *GlobalContext) CardCache() *UserCardCache {
   586  	g.cacheMu.Lock()
   587  	defer g.cacheMu.Unlock()
   588  	return g.cardCache
   589  }
   590  
   591  func (g *GlobalContext) LinkCache() *LinkCache {
   592  	g.cacheMu.Lock()
   593  	defer g.cacheMu.Unlock()
   594  	return g.linkCache
   595  }
   596  
   597  func (g *GlobalContext) configureMemCachesLocked(isFlush bool) {
   598  
   599  	g.shutdownCachesLocked()
   600  
   601  	g.IDLocktab = NewLockTable()
   602  	g.loadUserLockTab = NewLockTable()
   603  	g.Resolver.EnableCaching(NewMetaContextBackground(g))
   604  	g.trackCache = NewTrackCache()
   605  	g.identify2Cache = NewIdentify2Cache(g.Env.GetUserCacheMaxAge())
   606  	g.Log.Debug("Created Identify2Cache, max age: %s", g.Env.GetUserCacheMaxAge())
   607  
   608  	g.linkCache = NewLinkCache(g.Env.GetLinkCacheSize(), g.Env.GetLinkCacheCleanDur())
   609  	g.Log.Debug("Created LinkCache, max size: %d, clean dur: %s", g.Env.GetLinkCacheSize(), g.Env.GetLinkCacheCleanDur())
   610  	g.cardCache = NewUserCardCache(g.Env.GetUserCacheMaxAge())
   611  	g.Log.Debug("Created CardCache, max age: %s", g.Env.GetUserCacheMaxAge())
   612  
   613  	// If we're just flushing the caches, and already have a Proof cache, then the right idea
   614  	// is just to reset what's in the ProofCache. Otherwise, we make a new one.
   615  	if isFlush && g.ProofCache != nil {
   616  		_ = g.ProofCache.Reset()
   617  	} else {
   618  		g.ProofCache = NewProofCache(g, g.Env.GetProofCacheSize())
   619  	}
   620  
   621  	// If it's startup (and not a "flush"), then install a new full selfer
   622  	// cache. Otherwise, just make a new instance of the kind that's already there.
   623  	if isFlush {
   624  		g.fullSelfer = g.fullSelfer.New()
   625  	} else {
   626  		g.fullSelfer = NewCachedFullSelf(g)
   627  	}
   628  
   629  	g.Log.Debug("made a new full self cache")
   630  	g.upakLoader = NewCachedUPAKLoader(g, CachedUserTimeout)
   631  	g.Log.Debug("made a new cached UPAK loader (timeout=%v)", CachedUserTimeout)
   632  	g.PayloadCache = NewPayloadCache(g, g.Env.GetPayloadCacheSize())
   633  }
   634  
   635  func (g *GlobalContext) ConfigureCaches() error {
   636  	g.cacheMu.Lock()
   637  	defer g.cacheMu.Unlock()
   638  	g.configureMemCachesLocked(false)
   639  	return g.configureDiskCachesLocked()
   640  }
   641  
   642  func (g *GlobalContext) FlushCaches() {
   643  	g.cacheMu.Lock()
   644  	defer g.cacheMu.Unlock()
   645  	g.configureMemCachesLocked(true)
   646  	g.TeamRoleMapManager.FlushCache()
   647  }
   648  
   649  func (g *GlobalContext) configureDiskCachesLocked() error {
   650  	// We consider the local DBs as caches; they're caching our
   651  	// fetches from the server after all (and also our cryptographic
   652  	// checking).
   653  	g.LocalDb = NewJSONLocalDb(NewLevelDb(g, g.Env.GetDbFilename))
   654  	g.LocalChatDb = NewJSONLocalDb(NewLevelDb(g, g.Env.GetChatDbFilename))
   655  
   656  	epick := FirstErrorPicker{}
   657  	epick.Push(g.LocalDb.Open())
   658  	epick.Push(g.LocalChatDb.Open())
   659  	return epick.Error()
   660  }
   661  
   662  func (g *GlobalContext) ConfigureMerkleClient() error {
   663  	g.MerkleClient = NewMerkleClient(g)
   664  	return nil
   665  }
   666  
   667  func (g *GlobalContext) GetUPAKLoader() UPAKLoader {
   668  	g.cacheMu.RLock()
   669  	defer g.cacheMu.RUnlock()
   670  	return g.upakLoader
   671  }
   672  
   673  func (g *GlobalContext) GetTeamLoader() TeamLoader {
   674  	g.cacheMu.RLock()
   675  	defer g.cacheMu.RUnlock()
   676  	return g.teamLoader
   677  }
   678  
   679  func (g *GlobalContext) GetFastTeamLoader() FastTeamLoader {
   680  	g.cacheMu.RLock()
   681  	defer g.cacheMu.RUnlock()
   682  	return g.fastTeamLoader
   683  }
   684  
   685  func (g *GlobalContext) GetHiddenTeamChainManager() HiddenTeamChainManager {
   686  	g.cacheMu.RLock()
   687  	defer g.cacheMu.RUnlock()
   688  	return g.hiddenTeamChainManager
   689  }
   690  
   691  func (g *GlobalContext) GetTeamRoleMapManager() TeamRoleMapManager {
   692  	g.cacheMu.RLock()
   693  	defer g.cacheMu.RUnlock()
   694  	return g.TeamRoleMapManager
   695  }
   696  
   697  func (g *GlobalContext) SetTeamRoleMapManager(r TeamRoleMapManager) {
   698  	g.cacheMu.Lock()
   699  	defer g.cacheMu.Unlock()
   700  	g.TeamRoleMapManager = r
   701  }
   702  
   703  func (g *GlobalContext) SetHiddenTeamChainManager(h HiddenTeamChainManager) {
   704  	g.cacheMu.Lock()
   705  	defer g.cacheMu.Unlock()
   706  	g.hiddenTeamChainManager = h
   707  }
   708  
   709  func (g *GlobalContext) GetTeamAuditor() TeamAuditor {
   710  	g.cacheMu.RLock()
   711  	defer g.cacheMu.RUnlock()
   712  	return g.teamAuditor
   713  }
   714  
   715  func (g *GlobalContext) GetTeamBoxAuditor() TeamBoxAuditor {
   716  	g.cacheMu.RLock()
   717  	defer g.cacheMu.RUnlock()
   718  	return g.teamBoxAuditor
   719  }
   720  
   721  func (g *GlobalContext) GetStellar() Stellar {
   722  	g.cacheMu.RLock()
   723  	defer g.cacheMu.RUnlock()
   724  	return g.stellar
   725  }
   726  
   727  func (g *GlobalContext) GetDeviceEKStorage() DeviceEKStorage {
   728  	g.cacheMu.RLock()
   729  	defer g.cacheMu.RUnlock()
   730  	return g.deviceEKStorage
   731  }
   732  
   733  func (g *GlobalContext) GetUserEKBoxStorage() UserEKBoxStorage {
   734  	g.cacheMu.RLock()
   735  	defer g.cacheMu.RUnlock()
   736  	return g.userEKBoxStorage
   737  }
   738  
   739  func (g *GlobalContext) GetTeamEKBoxStorage() TeamEKBoxStorage {
   740  	g.cacheMu.RLock()
   741  	defer g.cacheMu.RUnlock()
   742  	return g.teamEKBoxStorage
   743  }
   744  
   745  func (g *GlobalContext) GetTeambotEKBoxStorage() TeamEKBoxStorage {
   746  	g.cacheMu.RLock()
   747  	defer g.cacheMu.RUnlock()
   748  	return g.teambotEKBoxStorage
   749  }
   750  
   751  func (g *GlobalContext) GetImplicitTeamConflictInfoCacher() LRUer {
   752  	g.cacheMu.RLock()
   753  	defer g.cacheMu.RUnlock()
   754  	return g.itciCacher
   755  }
   756  
   757  func (g *GlobalContext) SetImplicitTeamConflictInfoCacher(l LRUer) {
   758  	g.cacheMu.RLock()
   759  	defer g.cacheMu.RUnlock()
   760  	g.itciCacher = l
   761  }
   762  
   763  func (g *GlobalContext) GetImplicitTeamCacher() MemLRUer {
   764  	g.cacheMu.RLock()
   765  	defer g.cacheMu.RUnlock()
   766  	return g.iteamCacher
   767  }
   768  
   769  func (g *GlobalContext) SetImplicitTeamCacher(l MemLRUer) {
   770  	g.cacheMu.RLock()
   771  	defer g.cacheMu.RUnlock()
   772  	g.iteamCacher = l
   773  }
   774  
   775  func (g *GlobalContext) GetKVRevisionCache() KVRevisionCacher {
   776  	g.cacheMu.RLock()
   777  	defer g.cacheMu.RUnlock()
   778  	return g.kvRevisionCache
   779  }
   780  
   781  func (g *GlobalContext) SetKVRevisionCache(kvr KVRevisionCacher) {
   782  	g.cacheMu.RLock()
   783  	defer g.cacheMu.RUnlock()
   784  	g.kvRevisionCache = kvr
   785  }
   786  
   787  func (g *GlobalContext) GetFullSelfer() FullSelfer {
   788  	g.cacheMu.RLock()
   789  	defer g.cacheMu.RUnlock()
   790  	return g.fullSelfer
   791  }
   792  
   793  func (g *GlobalContext) GetParamProofStore() MerkleStore {
   794  	return g.paramProofStore
   795  }
   796  
   797  func (g *GlobalContext) GetExternalURLStore() MerkleStore {
   798  	return g.externalURLStore
   799  }
   800  
   801  // to implement ProofContext
   802  func (g *GlobalContext) GetPvlSource() MerkleStore {
   803  	return g.pvlSource
   804  }
   805  
   806  // to implement ProofContext
   807  func (g *GlobalContext) GetAppType() AppType {
   808  	return g.Env.GetAppType()
   809  }
   810  
   811  func (g *GlobalContext) IsMobileAppType() bool {
   812  	return g.Env.GetAppType() == MobileAppType
   813  }
   814  
   815  func (g *GlobalContext) ConfigureExportedStreams() error {
   816  	g.XStreams = NewExportedStreams()
   817  	return nil
   818  }
   819  
   820  // Shutdown is called exactly once per-process and does whatever
   821  // cleanup is necessary to shut down the server.
   822  func (g *GlobalContext) Shutdown(mctx MetaContext) error {
   823  	var err error
   824  	didShutdown := false
   825  
   826  	// Wrap in a Once.Do so that we don't inadvertedly
   827  	// run this code twice.
   828  	g.shutdownOnce.Do(func() {
   829  		g.Log.Debug("GlobalContext#Shutdown(%p)\n", g)
   830  		if g.PerfLog != nil {
   831  			g.PerfLog.Debug("GlobalContext#Shutdown(%p)\n", g)
   832  		}
   833  		didShutdown = true
   834  
   835  		epick := FirstErrorPicker{}
   836  
   837  		if g.hiddenTeamChainManager != nil {
   838  			g.hiddenTeamChainManager.Shutdown(mctx)
   839  		}
   840  
   841  		if g.NotifyRouter != nil {
   842  			g.NotifyRouter.Shutdown()
   843  		}
   844  
   845  		if g.UIRouter != nil {
   846  			g.UIRouter.Shutdown()
   847  		}
   848  
   849  		if g.ConnectionManager != nil {
   850  			g.ConnectionManager.Shutdown()
   851  		}
   852  
   853  		if g.UI != nil {
   854  			epick.Push(g.UI.Shutdown())
   855  		}
   856  
   857  		// Shutdown can still race with Logout, so make sure that we hold onto
   858  		// the cacheMu before shutting down the caches. See comments in
   859  		// shutdownCachesLocked
   860  		g.cacheMu.Lock()
   861  		g.shutdownCachesLocked()
   862  		g.cacheMu.Unlock()
   863  
   864  		if g.proofServices != nil {
   865  			g.proofServices.Shutdown()
   866  		}
   867  
   868  		if g.Resolver != nil {
   869  			g.Resolver.Shutdown(NewMetaContextBackground(g))
   870  		}
   871  
   872  		g.Log.Debug("executing %d shutdown hooks; errCount=%d", len(g.ShutdownHooks), epick.Count())
   873  		for _, hook := range g.ShutdownHooks {
   874  			epick.Push(hook(mctx))
   875  		}
   876  		g.Log.Debug("executed shutdown hooks; errCount=%d", epick.Count())
   877  
   878  		if g.LocalNetworkInstrumenterStorage != nil {
   879  			<-g.LocalNetworkInstrumenterStorage.Stop(mctx.Ctx())
   880  		}
   881  
   882  		if g.RemoteNetworkInstrumenterStorage != nil {
   883  			<-g.RemoteNetworkInstrumenterStorage.Stop(mctx.Ctx())
   884  		}
   885  
   886  		// shutdown the databases after the shutdown hooks run, we may want to
   887  		// flush memory caches to disk during shutdown.
   888  		if g.LocalDb != nil {
   889  			epick.Push(g.LocalDb.Close())
   890  		}
   891  		if g.LocalChatDb != nil {
   892  			epick.Push(g.LocalChatDb.Close())
   893  		}
   894  		if g.GUILogFile != nil {
   895  			epick.Push(g.GUILogFile.Close())
   896  		}
   897  		<-g.Identify3State.Shutdown()
   898  
   899  		err = epick.Error()
   900  
   901  		g.Log.Debug("exiting shutdown code=%d; errCount=%d; firstErr=%v", g.ExitCode, epick.Count(), err)
   902  	})
   903  
   904  	// Make a little bit of a statement if we wind up here a second time
   905  	// (which is a bug).
   906  	if !didShutdown {
   907  		g.Log.Debug("Skipped shutdown on second call")
   908  	}
   909  
   910  	return err
   911  }
   912  
   913  func (u Usage) UseKeyring() bool {
   914  	return u.KbKeyring || u.GpgKeyring
   915  }
   916  
   917  // If changed, make sure to correct standalone usage in g.Configure below
   918  var ServiceUsage = Usage{
   919  	Config:     true,
   920  	KbKeyring:  true,
   921  	GpgKeyring: true,
   922  	API:        true,
   923  	Socket:     true,
   924  }
   925  
   926  func (g *GlobalContext) ConfigureCommand(line CommandLine, cmd Command) error {
   927  	usage := cmd.GetUsage()
   928  	return g.Configure(line, usage)
   929  }
   930  
   931  func (g *GlobalContext) Configure(line CommandLine, usage Usage) error {
   932  	g.SetCommandLine(line)
   933  
   934  	if err := g.ConfigureLogging(&usage); err != nil {
   935  		return err
   936  	}
   937  	if g.Env.GetStandalone() {
   938  		// If standalone, override the usage to be the same as in a service
   939  		// If changed, make sure to correct ServiceUsage above.
   940  		usage.Config = ServiceUsage.Config
   941  		usage.KbKeyring = ServiceUsage.KbKeyring
   942  		usage.GpgKeyring = ServiceUsage.GpgKeyring
   943  		usage.API = ServiceUsage.API
   944  		usage.Socket = ServiceUsage.Socket
   945  	}
   946  
   947  	if err := g.ConfigureUsage(usage); err != nil {
   948  		return err
   949  	}
   950  
   951  	// secretStore must be created after SetCommandLine and ConfigureUsage in
   952  	// order to correctly use -H,-home flag and config vars for
   953  	// remember_passphrase.
   954  	g.secretStoreMu.Lock()
   955  	g.secretStore = NewSecretStoreLocked(NewMetaContextBackground(g))
   956  	g.secretStoreMu.Unlock()
   957  
   958  	return nil
   959  }
   960  
   961  func (g *GlobalContext) ConfigureUsage(usage Usage) error {
   962  	var err error
   963  
   964  	if usage.Config {
   965  		if err = g.ConfigReload(); err != nil {
   966  			return err
   967  		}
   968  	}
   969  	if usage.UseKeyring() {
   970  		if err = g.ConfigureKeyring(); err != nil {
   971  			return err
   972  		}
   973  	}
   974  	if usage.API {
   975  		if err = g.ConfigureAPI(); err != nil {
   976  			return err
   977  		}
   978  	}
   979  	if usage.Socket || !g.Env.GetStandalone() {
   980  		if err = g.ConfigureSocketInfo(); err != nil {
   981  			return err
   982  		}
   983  	}
   984  	if err = g.ConfigureExportedStreams(); err != nil {
   985  		return err
   986  	}
   987  
   988  	if err = g.ConfigureCaches(); err != nil {
   989  		return err
   990  	}
   991  	g.LocalNetworkInstrumenterStorage.Start(context.TODO())
   992  	g.RemoteNetworkInstrumenterStorage.Start(context.TODO())
   993  
   994  	if err = g.ConfigureMerkleClient(); err != nil {
   995  		return err
   996  	}
   997  
   998  	if g.UI != nil {
   999  		if err = g.UI.Configure(); err != nil {
  1000  			return err
  1001  		}
  1002  	}
  1003  
  1004  	return g.ConfigureTimers()
  1005  }
  1006  
  1007  func (g *GlobalContext) GetGpgClient() *GpgCLI {
  1008  	if g.GpgClient == nil {
  1009  		g.GpgClient = NewGpgCLI(g, nil)
  1010  	}
  1011  	return g.GpgClient
  1012  }
  1013  
  1014  func (g *GlobalContext) GetMyUID() keybase1.UID {
  1015  	// Prefer ActiveDevice, that's the prefered way
  1016  	// to figure out what the current user's UID is.
  1017  	uid := g.ActiveDevice.UID()
  1018  	if uid.Exists() {
  1019  		return uid
  1020  	}
  1021  	return g.Env.GetUID()
  1022  }
  1023  
  1024  func (g *GlobalContext) ConfigureSocketInfo() (err error) {
  1025  	g.SocketInfo, err = NewSocket(g)
  1026  	return err
  1027  }
  1028  
  1029  // Contextified objects have explicit references to the GlobalContext,
  1030  // so that G can be swapped out for something else.  We're going to incrementally
  1031  // start moving objects over to this system.
  1032  type Contextified struct {
  1033  	g *GlobalContext
  1034  }
  1035  
  1036  func (c Contextified) G() *GlobalContext {
  1037  	return c.g
  1038  }
  1039  
  1040  func (c Contextified) MetaContext(ctx context.Context) MetaContext {
  1041  	return NewMetaContext(ctx, c.g)
  1042  }
  1043  
  1044  func (c Contextified) GStrict() *GlobalContext {
  1045  	return c.g
  1046  }
  1047  
  1048  func (c *Contextified) SetGlobalContext(g *GlobalContext) { c.g = g }
  1049  
  1050  func NewContextified(gc *GlobalContext) Contextified {
  1051  	return Contextified{g: gc}
  1052  }
  1053  
  1054  type Contextifier interface {
  1055  	G() *GlobalContext
  1056  }
  1057  
  1058  func (g *GlobalContext) GetConfiguredAccounts(ctx context.Context) ([]keybase1.ConfiguredAccount, error) {
  1059  	m := NewMetaContext(ctx, g)
  1060  	g.secretStoreMu.Lock()
  1061  	defer g.secretStoreMu.Unlock()
  1062  	return GetConfiguredAccounts(m, g.secretStore)
  1063  }
  1064  
  1065  func (g *GlobalContext) GetAllUserNames() (NormalizedUsername, []NormalizedUsername, error) {
  1066  	return g.Env.GetConfig().GetAllUsernames()
  1067  }
  1068  
  1069  func (g *GlobalContext) GetStoredSecretServiceName() string {
  1070  	return g.Env.GetStoredSecretServiceName()
  1071  }
  1072  
  1073  func (g *GlobalContext) GetStoredSecretAccessGroup() string {
  1074  	return g.Env.GetStoredSecretAccessGroup()
  1075  }
  1076  
  1077  func (g *GlobalContext) GetUsersWithStoredSecrets(ctx context.Context) ([]string, error) {
  1078  	g.secretStoreMu.Lock()
  1079  	defer g.secretStoreMu.Unlock()
  1080  	if g.secretStore != nil {
  1081  		return g.secretStore.GetUsersWithStoredSecrets(NewMetaContext(ctx, g))
  1082  	}
  1083  	return []string{}, nil
  1084  }
  1085  
  1086  func (g *GlobalContext) GetCacheDir() string {
  1087  	return g.Env.GetCacheDir()
  1088  }
  1089  
  1090  func (g *GlobalContext) GetSharedCacheDir() string {
  1091  	return g.Env.GetSharedCacheDir()
  1092  }
  1093  
  1094  func (g *GlobalContext) GetRuntimeDir() string {
  1095  	return g.Env.GetRuntimeDir()
  1096  }
  1097  
  1098  func (g *GlobalContext) GetRunMode() RunMode {
  1099  	return g.Env.GetRunMode()
  1100  }
  1101  
  1102  func (g *GlobalContext) Clock() clockwork.Clock {
  1103  	g.clockMu.Lock()
  1104  	defer g.clockMu.Unlock()
  1105  	if g.clock == nil {
  1106  		g.clock = clockwork.NewRealClock()
  1107  	}
  1108  	return g.clock
  1109  }
  1110  
  1111  func (g *GlobalContext) SetClock(c clockwork.Clock) {
  1112  	g.clockMu.Lock()
  1113  	defer g.clockMu.Unlock()
  1114  	g.clock = c
  1115  }
  1116  
  1117  func (g *GlobalContext) GetMyClientDetails() keybase1.ClientDetails {
  1118  	return keybase1.ClientDetails{
  1119  		ClientType: keybase1.ClientType_CLI,
  1120  		Pid:        os.Getpid(),
  1121  		Argv:       os.Args,
  1122  		Version:    VersionString(),
  1123  	}
  1124  }
  1125  
  1126  type UnforwardedLoggerWithLegacyInterface interface {
  1127  	Debug(s string, args ...interface{})
  1128  	Error(s string, args ...interface{})
  1129  	Errorf(s string, args ...interface{})
  1130  	Warning(s string, args ...interface{})
  1131  	Info(s string, args ...interface{})
  1132  	Profile(s string, args ...interface{})
  1133  }
  1134  
  1135  func (g *GlobalContext) GetUnforwardedLogger() (log UnforwardedLoggerWithLegacyInterface) {
  1136  	defer func() {
  1137  		if log == nil {
  1138  			// Hopefully this won't happen before we get to refactor the logger
  1139  			// interfaces. If this happens, we really shouldn't return nil, but
  1140  			// rather fix whatever caused it.
  1141  			panic("can't make unforwarded logger")
  1142  		}
  1143  	}()
  1144  	if g.Log == nil {
  1145  		return nil
  1146  	}
  1147  	if log, ok := g.Log.(*logger.Standard); ok {
  1148  		return (*logger.UnforwardedLogger)(log)
  1149  	}
  1150  	if log, ok := g.Log.(*logger.TestLogger); ok {
  1151  		return log
  1152  	}
  1153  	return nil
  1154  }
  1155  
  1156  // GetLogf returns a logger with a minimal formatter style interface
  1157  func (g *GlobalContext) GetLogf() logger.Loggerf {
  1158  	return logger.NewLoggerf(g.Log)
  1159  }
  1160  
  1161  func (g *GlobalContext) AddLoginHook(hook LoginHook) {
  1162  	g.hookMu.Lock()
  1163  	defer g.hookMu.Unlock()
  1164  	g.Log.Debug("AddLoginHook: %T", hook)
  1165  	g.loginHooks = append(g.loginHooks, hook)
  1166  }
  1167  
  1168  func (g *GlobalContext) CallLoginHooks(mctx MetaContext) {
  1169  	mctx.Debug("G#CallLoginHooks")
  1170  
  1171  	// Trigger the creation of a per-user-keyring
  1172  	_, _ = g.GetPerUserKeyring(mctx.Ctx())
  1173  
  1174  	mctx.Debug("CallLoginHooks: running UPAK#LoginAs")
  1175  	err := g.GetUPAKLoader().LoginAs(mctx.CurrentUID())
  1176  	if err != nil {
  1177  		mctx.Warning("LoginAs error: %+v", err)
  1178  	}
  1179  
  1180  	// Do so outside the lock below
  1181  	mctx.Debug("CallLoginHooks: running FullSelfer#OnLogin")
  1182  	err = g.GetFullSelfer().OnLogin(mctx)
  1183  	if err != nil {
  1184  		mctx.Warning("OnLogin full self error: %+v", err)
  1185  	}
  1186  
  1187  	mctx.Debug("CallLoginHooks: recording login in secretstore")
  1188  	err = RecordLoginTime(mctx, g.Env.GetUsername())
  1189  	if err != nil {
  1190  		mctx.Warning("OnLogin RecordLogin error: %+v", err)
  1191  	}
  1192  
  1193  	mctx.Debug("CallLoginHooks: running registered login hooks")
  1194  	g.hookMu.RLock()
  1195  	defer g.hookMu.RUnlock()
  1196  	for _, h := range g.loginHooks {
  1197  		mctx.Debug("CallLoginHooks: will call login hook for %T", h)
  1198  	}
  1199  	for _, h := range g.loginHooks {
  1200  		mctx.Debug("CallLoginHooks: calling login hook for %T", h)
  1201  		if err := h.OnLogin(mctx); err != nil {
  1202  			mctx.Warning("OnLogin hook error: %s", err)
  1203  		}
  1204  	}
  1205  }
  1206  
  1207  type NamedLogoutHook struct {
  1208  	LogoutHook
  1209  	name string
  1210  }
  1211  
  1212  func (g *GlobalContext) AddLogoutHook(hook LogoutHook, name string) {
  1213  	g.hookMu.Lock()
  1214  	defer g.hookMu.Unlock()
  1215  	g.logoutHooks = append(g.logoutHooks, NamedLogoutHook{
  1216  		LogoutHook: hook,
  1217  		name:       name,
  1218  	})
  1219  }
  1220  
  1221  func (g *GlobalContext) CallLogoutHooks(mctx MetaContext) {
  1222  	defer mctx.Trace("GlobalContext.CallLogoutHooks", nil)()
  1223  	g.hookMu.RLock()
  1224  	defer g.hookMu.RUnlock()
  1225  	for _, h := range g.logoutHooks {
  1226  		mctx.Debug("+ Logout hook [%v]", h.name)
  1227  		if err := h.OnLogout(mctx); err != nil {
  1228  			mctx.Warning("| Logout hook [%v] : %s", h.name, err)
  1229  		}
  1230  		mctx.Debug("- Logout hook [%v]", h.name)
  1231  	}
  1232  }
  1233  
  1234  type NamedDbNukeHook struct {
  1235  	DbNukeHook
  1236  	name string
  1237  }
  1238  
  1239  func (g *GlobalContext) AddDbNukeHook(hook DbNukeHook, name string) {
  1240  	g.hookMu.Lock()
  1241  	defer g.hookMu.Unlock()
  1242  	g.dbNukeHooks = append(g.dbNukeHooks, NamedDbNukeHook{
  1243  		DbNukeHook: hook,
  1244  		name:       name,
  1245  	})
  1246  }
  1247  
  1248  func (g *GlobalContext) CallDbNukeHooks(mctx MetaContext) {
  1249  	defer mctx.Trace("GlobalContext.CallDbNukeHook", nil)()
  1250  	g.hookMu.RLock()
  1251  	defer g.hookMu.RUnlock()
  1252  	for _, h := range g.dbNukeHooks {
  1253  		mctx.Debug("+ DbNukeHook hook [%v]", h.name)
  1254  		if err := h.OnDbNuke(mctx); err != nil {
  1255  			mctx.Warning("| DbNukeHook hook [%v] : %s", h.name, err)
  1256  		}
  1257  		mctx.Debug("- DbNukeHook hook [%v]", h.name)
  1258  	}
  1259  }
  1260  
  1261  func (g *GlobalContext) GetConfigDir() string {
  1262  	return g.Env.GetConfigDir()
  1263  }
  1264  
  1265  func (g *GlobalContext) GetMountDir() (string, error) {
  1266  	return g.Env.GetMountDir()
  1267  }
  1268  
  1269  // GetServiceInfoPath returns path to info file written by the Keybase service after startup
  1270  func (g *GlobalContext) GetServiceInfoPath() string {
  1271  	return g.Env.GetServiceInfoPath()
  1272  }
  1273  
  1274  // GetKBFSInfoPath returns path to info file written by the KBFS service after startup
  1275  func (g *GlobalContext) GetKBFSInfoPath() string {
  1276  	return g.Env.GetKBFSInfoPath()
  1277  }
  1278  
  1279  func (g *GlobalContext) GetLogDir() string {
  1280  	return g.Env.GetLogDir()
  1281  }
  1282  
  1283  func (g *GlobalContext) GetDataDir() string {
  1284  	return g.Env.GetDataDir()
  1285  }
  1286  
  1287  func (g *GlobalContext) NewRPCLogFactory() *RPCLogFactory {
  1288  	return &RPCLogFactory{Contextified: NewContextified(g)}
  1289  }
  1290  
  1291  func (g *GlobalContext) MakeAssertionContext(mctx MetaContext) AssertionContext {
  1292  	g.cacheMu.Lock()
  1293  	defer g.cacheMu.Unlock()
  1294  	if g.proofServices == nil {
  1295  		return nil
  1296  	}
  1297  	return MakeAssertionContext(mctx, g.proofServices)
  1298  }
  1299  
  1300  func (g *GlobalContext) SetProofServices(s ExternalServicesCollector) {
  1301  	g.cacheMu.Lock()
  1302  	defer g.cacheMu.Unlock()
  1303  	g.proofServices = s
  1304  }
  1305  
  1306  func (g *GlobalContext) SetParamProofStore(s MerkleStore) {
  1307  	g.cacheMu.Lock()
  1308  	defer g.cacheMu.Unlock()
  1309  	g.paramProofStore = s
  1310  }
  1311  
  1312  func (g *GlobalContext) SetExternalURLStore(s MerkleStore) {
  1313  	g.cacheMu.Lock()
  1314  	defer g.cacheMu.Unlock()
  1315  	g.externalURLStore = s
  1316  }
  1317  
  1318  func (g *GlobalContext) SetPvlSource(s MerkleStore) {
  1319  	g.cacheMu.Lock()
  1320  	defer g.cacheMu.Unlock()
  1321  	g.pvlSource = s
  1322  }
  1323  
  1324  func (g *GlobalContext) SetTeamLoader(l TeamLoader) {
  1325  	g.cacheMu.Lock()
  1326  	defer g.cacheMu.Unlock()
  1327  	g.teamLoader = l
  1328  }
  1329  
  1330  func (g *GlobalContext) SetMerkleClient(m MerkleClientInterface) {
  1331  	g.cacheMu.Lock()
  1332  	defer g.cacheMu.Unlock()
  1333  	g.MerkleClient = m
  1334  }
  1335  
  1336  func (g *GlobalContext) GetMerkleClient() MerkleClientInterface {
  1337  	g.cacheMu.Lock()
  1338  	defer g.cacheMu.Unlock()
  1339  	return g.MerkleClient
  1340  }
  1341  
  1342  func (g *GlobalContext) SetFastTeamLoader(l FastTeamLoader) {
  1343  	g.cacheMu.Lock()
  1344  	defer g.cacheMu.Unlock()
  1345  	g.fastTeamLoader = l
  1346  }
  1347  
  1348  func (g *GlobalContext) SetTeamAuditor(a TeamAuditor) {
  1349  	g.cacheMu.Lock()
  1350  	defer g.cacheMu.Unlock()
  1351  	g.teamAuditor = a
  1352  }
  1353  
  1354  func (g *GlobalContext) SetTeamBoxAuditor(a TeamBoxAuditor) {
  1355  	g.cacheMu.Lock()
  1356  	defer g.cacheMu.Unlock()
  1357  	g.teamBoxAuditor = a
  1358  }
  1359  
  1360  func (g *GlobalContext) SetStellar(s Stellar) {
  1361  	g.cacheMu.Lock()
  1362  	defer g.cacheMu.Unlock()
  1363  	g.stellar = s
  1364  }
  1365  
  1366  func (g *GlobalContext) SetDeviceEKStorage(s DeviceEKStorage) {
  1367  	g.cacheMu.Lock()
  1368  	defer g.cacheMu.Unlock()
  1369  	g.deviceEKStorage = s
  1370  }
  1371  
  1372  func (g *GlobalContext) SetUserEKBoxStorage(s UserEKBoxStorage) {
  1373  	g.cacheMu.Lock()
  1374  	defer g.cacheMu.Unlock()
  1375  	g.userEKBoxStorage = s
  1376  }
  1377  
  1378  func (g *GlobalContext) SetTeamEKBoxStorage(s TeamEKBoxStorage) {
  1379  	g.cacheMu.Lock()
  1380  	defer g.cacheMu.Unlock()
  1381  	g.teamEKBoxStorage = s
  1382  }
  1383  
  1384  func (g *GlobalContext) SetTeambotEKBoxStorage(s TeamEKBoxStorage) {
  1385  	g.cacheMu.Lock()
  1386  	defer g.cacheMu.Unlock()
  1387  	g.teambotEKBoxStorage = s
  1388  }
  1389  
  1390  func (g *GlobalContext) LoadUserByUID(uid keybase1.UID) (*User, error) {
  1391  	arg := NewLoadUserArgWithMetaContext(NewMetaContextBackground(g)).WithUID(uid).WithPublicKeyOptional()
  1392  	return LoadUser(arg)
  1393  }
  1394  
  1395  func (g *GlobalContext) BustLocalUserCache(ctx context.Context, u keybase1.UID) {
  1396  	g.GetUPAKLoader().Invalidate(ctx, u)
  1397  	_ = g.CardCache().Delete(u)
  1398  	_ = g.GetFullSelfer().HandleUserChanged(u)
  1399  }
  1400  
  1401  func (g *GlobalContext) OverrideUPAKLoader(upak UPAKLoader) {
  1402  	g.upakLoader = upak
  1403  }
  1404  
  1405  func (g *GlobalContext) AddUserChangedHandler(h UserChangedHandler) {
  1406  	g.uchMu.Lock()
  1407  	g.UserChangedHandlers = append(g.UserChangedHandlers, h)
  1408  	g.uchMu.Unlock()
  1409  }
  1410  
  1411  func (g *GlobalContext) GetOutOfDateInfo() keybase1.OutOfDateInfo {
  1412  	g.oodiMu.RLock()
  1413  	ret := *g.outOfDateInfo
  1414  	g.oodiMu.RUnlock()
  1415  	return ret
  1416  }
  1417  
  1418  func (g *GlobalContext) KeyfamilyChanged(ctx context.Context, u keybase1.UID) {
  1419  	g.Log.CDebugf(ctx, "+ KeyfamilyChanged(%s)", u)
  1420  	defer g.Log.CDebugf(ctx, "- KeyfamilyChanged(%s)", u)
  1421  
  1422  	// Make sure we kill the UPAK and full self cache for this user
  1423  	g.BustLocalUserCache(ctx, u)
  1424  
  1425  	if g.NotifyRouter != nil {
  1426  		g.NotifyRouter.HandleKeyfamilyChanged(u)
  1427  		// TODO: remove this when KBFS handles KeyfamilyChanged
  1428  		g.NotifyRouter.HandleUserChanged(NewMetaContext(ctx, g), u, "KeyfamilyChanged")
  1429  	}
  1430  }
  1431  
  1432  func (g *GlobalContext) UserChanged(ctx context.Context, u keybase1.UID) {
  1433  	g.Log.CDebugf(ctx, "+ UserChanged(%s)", u)
  1434  	defer g.Log.CDebugf(ctx, "- UserChanged(%s)", u)
  1435  
  1436  	_, _ = g.GetPerUserKeyring(context.TODO())
  1437  
  1438  	g.BustLocalUserCache(ctx, u)
  1439  	if g.NotifyRouter != nil {
  1440  		g.NotifyRouter.HandleUserChanged(NewMetaContext(ctx, g), u, "G.UserChanged")
  1441  	}
  1442  
  1443  	g.uchMu.Lock()
  1444  	list := g.UserChangedHandlers
  1445  	var newList []UserChangedHandler
  1446  	for _, cc := range list {
  1447  		if err := cc.HandleUserChanged(u); err == nil {
  1448  			newList = append(newList, cc)
  1449  		}
  1450  	}
  1451  	g.UserChangedHandlers = newList
  1452  	g.uchMu.Unlock()
  1453  }
  1454  
  1455  // GetPerUserKeyring recreates PerUserKeyring if the uid changes or this is none installed.
  1456  func (g *GlobalContext) GetPerUserKeyring(ctx context.Context) (ret *PerUserKeyring, err error) {
  1457  	defer g.Trace("G#GetPerUserKeyring", &err)()
  1458  
  1459  	myUID := g.ActiveDevice.UID()
  1460  	if myUID.IsNil() {
  1461  		return nil, errors.New("PerUserKeyring unavailable with no UID")
  1462  	}
  1463  
  1464  	// Don't do any operations under these locks that could come back and hit them again.
  1465  	// That's why GetMyUID up above is not under this lock.
  1466  	g.perUserKeyringMu.Lock()
  1467  	defer g.perUserKeyringMu.Unlock()
  1468  
  1469  	makeNew := func() (*PerUserKeyring, error) {
  1470  		pukring, err := NewPerUserKeyring(g, myUID)
  1471  		if err != nil {
  1472  			g.Log.CWarningf(ctx, "G#GetPerUserKeyring -> failed: %s", err)
  1473  			g.perUserKeyring = nil
  1474  			return nil, err
  1475  		}
  1476  		g.Log.CDebugf(ctx, "G#GetPerUserKeyring -> new")
  1477  		g.perUserKeyring = pukring
  1478  		return g.perUserKeyring, nil
  1479  	}
  1480  
  1481  	if g.perUserKeyring == nil {
  1482  		return makeNew()
  1483  	}
  1484  	pukUID := g.perUserKeyring.GetUID()
  1485  	if pukUID.Equal(myUID) {
  1486  		return g.perUserKeyring, nil
  1487  	}
  1488  	return makeNew()
  1489  }
  1490  
  1491  func (g *GlobalContext) ClearPerUserKeyring() {
  1492  	defer g.Trace("G#ClearPerUserKeyring", nil)()
  1493  
  1494  	g.perUserKeyringMu.Lock()
  1495  	defer g.perUserKeyringMu.Unlock()
  1496  	g.perUserKeyring = nil
  1497  }
  1498  
  1499  func (g *GlobalContext) LocalSigchainGuard() *LocalSigchainGuard {
  1500  	return g.localSigchainGuard
  1501  }
  1502  
  1503  func (g *GlobalContext) StartStandaloneChat() {
  1504  	if !g.Standalone {
  1505  		return
  1506  	}
  1507  
  1508  	if g.StandaloneChatConnector == nil {
  1509  		g.Log.Warning("G#StartStandaloneChat - not starting chat, StandaloneChatConnector is nil.")
  1510  		return
  1511  	}
  1512  
  1513  	_ = g.StandaloneChatConnector.StartStandaloneChat(g)
  1514  }
  1515  
  1516  func (g *GlobalContext) SecretStore() *SecretStoreLocked {
  1517  	g.secretStoreMu.Lock()
  1518  	defer g.secretStoreMu.Unlock()
  1519  
  1520  	return g.secretStore
  1521  }
  1522  
  1523  // ReplaceSecretStore gets the existing secret out of the existing
  1524  // secret store, creates a new secret store (could be a new type
  1525  // of SecretStore based on a config change), and inserts the secret
  1526  // into the new secret store.
  1527  func (g *GlobalContext) ReplaceSecretStore(ctx context.Context) error {
  1528  	g.secretStoreMu.Lock()
  1529  	defer g.secretStoreMu.Unlock()
  1530  
  1531  	username := g.Env.GetUsername()
  1532  	m := NewMetaContext(ctx, g)
  1533  
  1534  	// get the current secret
  1535  	secret, err := g.secretStore.RetrieveSecret(m, username)
  1536  	if err != nil {
  1537  		m.Debug("error retrieving existing secret for ReplaceSecretStore: %s", err)
  1538  		return err
  1539  	}
  1540  
  1541  	// clear the existing secret from the existing secret store
  1542  	if err := g.secretStore.ClearSecret(m, username); err != nil {
  1543  		m.Debug("error clearing existing secret for ReplaceSecretStore: %s", err)
  1544  		return err
  1545  	}
  1546  
  1547  	// make a new secret store
  1548  	g.secretStore = NewSecretStoreLocked(m)
  1549  
  1550  	// store the secret in the secret store
  1551  	if err := g.secretStore.StoreSecret(m, username, secret); err != nil {
  1552  		m.Debug("error storing existing secret for ReplaceSecretStore: %s", err)
  1553  		return err
  1554  	}
  1555  
  1556  	m.Debug("ReplaceSecretStore success")
  1557  
  1558  	return nil
  1559  }
  1560  
  1561  func (g *GlobalContext) IsOneshot(ctx context.Context) (bool, error) {
  1562  	uc, err := g.Env.GetConfig().GetUserConfig()
  1563  	if err != nil {
  1564  		g.Log.CDebugf(ctx, "IsOneshot: Error getting a user config: %s", err)
  1565  		return false, err
  1566  	}
  1567  	if uc == nil {
  1568  		g.Log.CDebugf(ctx, "IsOneshot: nil user config")
  1569  		return false, nil
  1570  	}
  1571  	return uc.IsOneshot(), nil
  1572  }
  1573  
  1574  func (g *GlobalContext) GetMeUV(ctx context.Context) (res keybase1.UserVersion, err error) {
  1575  	res = g.ActiveDevice.UserVersion()
  1576  	if res.IsNil() {
  1577  		return keybase1.UserVersion{}, LoginRequiredError{}
  1578  	}
  1579  	return res, nil
  1580  }