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 }