github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/libkb/context.go (about)

     1  package libkb
     2  
     3  import (
     4  	"fmt"
     5  	"runtime/debug"
     6  	"time"
     7  
     8  	logger "github.com/keybase/client/go/logger"
     9  	"github.com/keybase/client/go/profiling"
    10  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    11  	context "golang.org/x/net/context"
    12  )
    13  
    14  type APITokener interface {
    15  	Tokens() (session, csrf string)
    16  }
    17  
    18  type MetaContext struct {
    19  	ctx          context.Context
    20  	g            *GlobalContext
    21  	loginContext LoginContext
    22  	activeDevice *ActiveDevice
    23  	apiTokener   APITokener
    24  	uis          UIs
    25  }
    26  
    27  func (m MetaContext) Dump() {
    28  	m.Debug("MetaContext#Dump:")
    29  	if m.activeDevice != nil {
    30  		m.Debug("- Local ActiveDevice:")
    31  		m.activeDevice.Dump(m, "-- ")
    32  	}
    33  	m.Debug("- Global ActiveDevice:")
    34  	m.g.ActiveDevice.Dump(m, "-- ")
    35  	if m.loginContext != nil {
    36  		m.Debug("- Login Context:")
    37  		m.loginContext.Dump(m, "-- ")
    38  	}
    39  }
    40  
    41  func NewMetaContext(ctx context.Context, g *GlobalContext) MetaContext {
    42  	return MetaContext{ctx: ctx, g: g}
    43  }
    44  
    45  func (m MetaContext) WithLoginContext(l LoginContext) MetaContext {
    46  	m.loginContext = l
    47  	return m
    48  }
    49  
    50  func (m MetaContext) WithAPITokener(t APITokener) MetaContext {
    51  	m.apiTokener = t
    52  	return m
    53  }
    54  
    55  func (m MetaContext) WithCtx(c context.Context) MetaContext {
    56  	m.ctx = c
    57  	return m
    58  }
    59  
    60  func (m MetaContext) G() *GlobalContext {
    61  	return m.g
    62  }
    63  
    64  func (m MetaContext) Ctx() context.Context {
    65  	return m.ctx
    66  }
    67  
    68  func (m MetaContext) LoginContext() LoginContext {
    69  	return m.loginContext
    70  }
    71  
    72  func (m MetaContext) VLogf(lev VDebugLevel, msg string, args ...interface{}) {
    73  	m.g.VDL.CLogfWithAddedDepth(m.ctx, lev, 1, msg, args...)
    74  }
    75  
    76  func (m MetaContext) Trace(msg string, err *error) func() {
    77  	return CTrace(m.ctx, m.g.Log.CloneWithAddedDepth(1), msg, err, m.G().Clock())
    78  }
    79  func (m MetaContext) VTrace(lev VDebugLevel, msg string, err *error) func() {
    80  	return m.g.CVTrace(m.ctx, lev, msg, err)
    81  }
    82  func (m MetaContext) PerfTrace(msg string, err *error) func() {
    83  	return CTrace(m.ctx, m.g.PerfLog.CloneWithAddedDepth(1), msg, err, m.G().Clock())
    84  }
    85  func (m MetaContext) TimeBuckets() (MetaContext, *profiling.TimeBuckets) {
    86  	var ret *profiling.TimeBuckets
    87  	m.ctx, ret = m.G().CTimeBuckets(m.ctx)
    88  	return m, ret
    89  }
    90  func (m MetaContext) TimeTracer(label string, enabled bool) profiling.TimeTracer {
    91  	return m.G().CTimeTracer(m.Ctx(), label, enabled)
    92  }
    93  
    94  func (m MetaContext) Debug(f string, args ...interface{}) {
    95  	m.g.Log.CloneWithAddedDepth(1).CDebugf(m.ctx, f, args...)
    96  }
    97  func (m MetaContext) PerfDebug(f string, args ...interface{}) {
    98  	m.g.PerfLog.CloneWithAddedDepth(1).CDebugf(m.ctx, f, args...)
    99  }
   100  func (m MetaContext) Warning(f string, args ...interface{}) {
   101  	m.g.Log.CloneWithAddedDepth(1).CWarningf(m.ctx, f, args...)
   102  }
   103  func (m MetaContext) Error(f string, args ...interface{}) {
   104  	m.g.Log.CloneWithAddedDepth(1).CErrorf(m.ctx, f, args...)
   105  }
   106  func (m MetaContext) Info(f string, args ...interface{}) {
   107  	m.g.Log.CloneWithAddedDepth(1).CInfof(m.ctx, f, args...)
   108  }
   109  
   110  func (m MetaContext) ActiveDevice() *ActiveDevice {
   111  	if m.activeDevice != nil {
   112  		m.Debug("MetaContext#ActiveDevice: thread local")
   113  		return m.activeDevice
   114  	}
   115  	m.Debug("MetaContext#ActiveDevice: global")
   116  	return m.G().ActiveDevice
   117  }
   118  
   119  func (m MetaContext) NIST() (*NIST, error) {
   120  	nist, uid, _, err := m.ActiveDevice().NISTAndUIDDeviceID(m.Ctx())
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  	if !uid.Equal(m.CurrentUID()) {
   125  		m.Debug("MetaContext#NIST: Not returning nist, since for wrong UID: %s != %s", uid, m.CurrentUID())
   126  		return nil, nil
   127  	}
   128  	return nist, nil
   129  }
   130  
   131  func NewMetaContextTODO(g *GlobalContext) MetaContext {
   132  	return MetaContext{ctx: context.TODO(), g: g}
   133  }
   134  func NewMetaContextBackground(g *GlobalContext) MetaContext {
   135  	return MetaContext{ctx: context.Background(), g: g}
   136  }
   137  
   138  func (m MetaContext) WithDelegatedIdentifyUI(u IdentifyUI) MetaContext {
   139  	m.uis.IdentifyUI = u
   140  	return m
   141  }
   142  
   143  func (m MetaContext) WithContext(ctx context.Context) MetaContext {
   144  	m.ctx = ctx
   145  	return m
   146  }
   147  
   148  func (m MetaContext) WithContextCancel() (MetaContext, func()) {
   149  	var f func()
   150  	m.ctx, f = context.WithCancel(m.ctx)
   151  	return m, f
   152  }
   153  
   154  func (m MetaContext) BackgroundWithCancel() (MetaContext, func()) {
   155  	var f func()
   156  	m.ctx, f = context.WithCancel(context.Background())
   157  	return m, f
   158  }
   159  
   160  func (m MetaContext) BackgroundWithLogTags() MetaContext {
   161  	m.ctx = CopyTagsToBackground(m.ctx)
   162  	return m
   163  }
   164  
   165  func (m MetaContext) WithTimeout(timeout time.Duration) (MetaContext, func()) {
   166  	var f func()
   167  	m.ctx, f = context.WithTimeout(m.ctx, timeout)
   168  	return m, f
   169  }
   170  
   171  func (m MetaContext) WithLogTag(k string) MetaContext {
   172  	m.ctx = WithLogTag(m.ctx, k)
   173  	return m
   174  }
   175  
   176  func (m MetaContext) WithLogTags(tags map[string]string) MetaContext {
   177  	for k, v := range tags {
   178  		m.ctx = WithLogTagWithValue(m.ctx, k, v)
   179  	}
   180  	return m
   181  }
   182  
   183  func (m MetaContext) WithTimeBuckets() (MetaContext, *profiling.TimeBuckets) {
   184  	ctx, tbs := m.G().CTimeBuckets(m.ctx)
   185  	m.ctx = ctx
   186  	return m, tbs
   187  }
   188  
   189  func (m MetaContext) EnsureCtx() MetaContext {
   190  	if m.ctx == nil {
   191  		m.ctx = context.Background()
   192  		m.Debug("installing background context.Context")
   193  	}
   194  	return m
   195  }
   196  
   197  func (m MetaContext) WithSecretUI(u SecretUI) MetaContext {
   198  	m.uis.SecretUI = u
   199  	return m
   200  }
   201  
   202  func (m MetaContext) WithLogUI(u LogUI) MetaContext {
   203  	m.uis.LogUI = u
   204  	return m
   205  }
   206  
   207  func (m MetaContext) WithPgpUI(u PgpUI) MetaContext {
   208  	m.uis.PgpUI = u
   209  	return m
   210  }
   211  
   212  func (m MetaContext) WithIdentifyUI(u IdentifyUI) MetaContext {
   213  	m.uis.IdentifyUI = u
   214  	return m
   215  }
   216  
   217  func (m MetaContext) WithGPGUI(u GPGUI) MetaContext {
   218  	m.uis.GPGUI = u
   219  	return m
   220  }
   221  
   222  func (m MetaContext) WithSaltpackUI(s SaltpackUI) MetaContext {
   223  	m.uis.SaltpackUI = s
   224  	return m
   225  }
   226  
   227  func (m MetaContext) UIs() UIs {
   228  	return m.uis
   229  }
   230  
   231  func (m MetaContext) WithUIs(u UIs) MetaContext {
   232  	m.uis = u
   233  	return m
   234  }
   235  
   236  func (m MetaContext) WithActiveDevice(a *ActiveDevice) MetaContext {
   237  	m.activeDevice = a
   238  	return m
   239  }
   240  
   241  func (m MetaContext) WithProvisioningKeyActiveDevice(d *DeviceWithKeys, uv keybase1.UserVersion) MetaContext {
   242  	return m.WithActiveDevice(d.ToProvisioningKeyActiveDevice(m, uv))
   243  }
   244  
   245  func (m MetaContext) WithGlobalActiveDevice() MetaContext {
   246  	m.activeDevice = nil
   247  	return m
   248  }
   249  
   250  func (m MetaContext) SecretKeyPromptArg(ska SecretKeyArg, reason string) SecretKeyPromptArg {
   251  	return SecretKeyPromptArg{
   252  		SecretUI: m.uis.SecretUI,
   253  		Ska:      ska,
   254  		Reason:   reason,
   255  	}
   256  }
   257  
   258  func (m MetaContext) WithNewProvisionalLoginContext() MetaContext {
   259  	return m.WithLoginContext(newProvisionalLoginContext(m))
   260  }
   261  
   262  func (m MetaContext) WithNewProvisionalLoginContextForUser(u *User) MetaContext {
   263  	return m.WithNewProvisionalLoginContextForUserVersionAndUsername(u.ToUserVersion(), u.GetNormalizedName())
   264  }
   265  
   266  func (m MetaContext) WithNewProvisionalLoginContextForUserVersionAndUsername(uv keybase1.UserVersion, un NormalizedUsername) MetaContext {
   267  	plc := newProvisionalLoginContextWithUserVersionAndUsername(m, uv, un)
   268  	err := m.ActiveDevice().CopyCacheToLoginContextIfForUserVersion(m, plc, uv)
   269  	if err != nil {
   270  		m.Debug("WithNewProvisionalLoginContextForUserVersionAndUsername: error %+v", err)
   271  	}
   272  	return m.WithLoginContext(plc)
   273  }
   274  
   275  func (m MetaContext) CommitProvisionalLogin() MetaContext {
   276  	m.Debug("MetaContext#CommitProvisionalLogin")
   277  	lctx := m.loginContext
   278  	m.loginContext = nil
   279  	if lctx != nil {
   280  		if ppsc := lctx.PassphraseStreamCache(); ppsc != nil {
   281  			m.ActiveDevice().CachePassphraseStream(ppsc)
   282  		}
   283  	}
   284  	return m
   285  }
   286  
   287  type UIs struct {
   288  	GPGUI       GPGUI
   289  	LogUI       LogUI
   290  	LoginUI     LoginUI
   291  	SecretUI    SecretUI
   292  	IdentifyUI  IdentifyUI
   293  	PgpUI       PgpUI
   294  	ProveUI     ProveUI
   295  	ProvisionUI ProvisionUI
   296  	SaltpackUI  SaltpackUI
   297  
   298  	// Usually set to `NONE`, meaning none specified.
   299  	// But if we know it, specify the end client type here
   300  	// since some things like GPG shell-out work differently
   301  	// depending.
   302  	ClientType keybase1.ClientType
   303  
   304  	SessionID int
   305  }
   306  
   307  func (e UIs) HasUI(kind UIKind) bool {
   308  	switch kind {
   309  	case GPGUIKind:
   310  		return e.GPGUI != nil
   311  	case LogUIKind:
   312  		return e.LogUI != nil
   313  	case LoginUIKind:
   314  		return e.LoginUI != nil
   315  	case SecretUIKind:
   316  		return e.SecretUI != nil
   317  	case IdentifyUIKind:
   318  		return e.IdentifyUI != nil
   319  	case PgpUIKind:
   320  		return e.PgpUI != nil
   321  	case ProveUIKind:
   322  		return e.ProveUI != nil
   323  	case ProvisionUIKind:
   324  		return e.ProvisionUI != nil
   325  	case SaltpackUIKind:
   326  		return e.SaltpackUI != nil
   327  	}
   328  	panic(fmt.Sprintf("unhandled kind: %d", kind))
   329  }
   330  
   331  type MetaContextified struct {
   332  	m MetaContext
   333  }
   334  
   335  func (m MetaContextified) M() MetaContext {
   336  	return m.m
   337  }
   338  
   339  func (m MetaContextified) G() *GlobalContext {
   340  	return m.m.g
   341  }
   342  
   343  func NewMetaContextified(m MetaContext) MetaContextified {
   344  	return MetaContextified{m: m}
   345  }
   346  
   347  // SwitchUserNewConfig switches the global active "user" as far as the global
   348  // config file is concerned.  It switches the user to a new user, and therefore
   349  // you should specify the username, salt, and device ID for this user on this
   350  // device. It will take out the global `switchUserMu` and also clear out the
   351  // global ActiveDevice at the same time. We follow the same pattern here and
   352  // elsewhere: atomically mutate the `current_user` of the config file as we set
   353  // the global ActiveDevice.
   354  func (m MetaContext) SwitchUserNewConfig(u keybase1.UID, n NormalizedUsername, salt []byte, d keybase1.DeviceID) error {
   355  	return m.switchUserNewConfig(u, n, salt, d, nil)
   356  }
   357  
   358  func (m MetaContext) switchUserNewConfig(u keybase1.UID, n NormalizedUsername, salt []byte, d keybase1.DeviceID, ad *ActiveDevice) error {
   359  	g := m.G()
   360  	defer g.switchUserMu.Acquire(m, "switchUserNewConfig")()
   361  	cw := g.Env.GetConfigWriter()
   362  	if cw == nil {
   363  		return NoConfigWriterError{}
   364  	}
   365  	// Note that `true` here means that an existing user config entry will
   366  	// be overwritten.
   367  	if err := cw.SetUserConfig(NewUserConfig(u, n, salt, d), true /* overwrite */); err != nil {
   368  		return err
   369  	}
   370  	// Clear stayLoggedOut, so that if the service restarts for any reason
   371  	// we will know that we are logged in.
   372  	if g.Env.GetStayLoggedOut() {
   373  		if err := cw.SetStayLoggedOut(false); err != nil {
   374  			return err
   375  		}
   376  	}
   377  	return g.ActiveDevice.SetOrClear(m, ad)
   378  }
   379  
   380  // SwitchUserNewConfigActiveDevice creates a new config file stanza and an
   381  // active device for the given user, all while holding the switchUserMu lock.
   382  func (m MetaContext) SwitchUserNewConfigActiveDevice(uv keybase1.UserVersion, n NormalizedUsername, salt []byte, d keybase1.DeviceID, sigKey GenericKey, encKey GenericKey, deviceName string, keychainMode KeychainMode) error {
   383  	ad := NewProvisionalActiveDevice(m, uv, d, sigKey, encKey, deviceName, keychainMode)
   384  	return m.switchUserNewConfig(uv.Uid, n, salt, d, ad)
   385  }
   386  
   387  // SwitchUserNukeConfig removes the given username from the config file, and
   388  // then switches to not having a current user (by clearing the ActiveDevice,
   389  // etc). It does this in a critical section, holding switchUserMu.
   390  func (m MetaContext) SwitchUserNukeConfig(n NormalizedUsername) error {
   391  	g := m.G()
   392  	defer g.switchUserMu.Acquire(m, "SwitchUserNukeConfig")()
   393  	cw := g.Env.GetConfigWriter()
   394  	cr := g.Env.GetConfig()
   395  	if cw == nil {
   396  		return NoConfigWriterError{}
   397  	}
   398  	if cr == nil {
   399  		return NoConfigFileError{}
   400  	}
   401  	uid := cr.GetUIDForUsername(n)
   402  	err := cw.NukeUser(n)
   403  	if err != nil {
   404  		return err
   405  	}
   406  	if g.ActiveDevice.UID().Equal(uid) {
   407  		err := g.ActiveDevice.Clear()
   408  		if err != nil {
   409  			return err
   410  		}
   411  	}
   412  	return nil
   413  }
   414  
   415  func (m MetaContext) SwitchUser(n NormalizedUsername) error {
   416  	return m.SwitchUserToActiveDevice(n, nil)
   417  }
   418  
   419  func (m MetaContext) SwitchUserToActiveDevice(n NormalizedUsername, ad *ActiveDevice) (err error) {
   420  
   421  	defer m.Trace(fmt.Sprintf("MetaContext#SwitchUserToActiveDevice(%s,ActiveDevice:%v)", n.String(), (ad != nil)), &err)()
   422  
   423  	g := m.G()
   424  	if n.IsNil() {
   425  		return nil
   426  	}
   427  	if !n.IsValid() {
   428  		return NewBadUsernameError(n.String())
   429  	}
   430  	defer g.switchUserMu.Acquire(m, "SwitchUserToActiveDevice %v", n)()
   431  	cw := g.Env.GetConfigWriter()
   432  	if cw == nil {
   433  		return NoConfigWriterError{}
   434  	}
   435  	err = cw.SwitchUser(n)
   436  	if _, ok := err.(UserNotFoundError); ok {
   437  		m.Debug("| No user %s found; clearing out config", n)
   438  		err = nil
   439  	}
   440  	if err != nil {
   441  		return err
   442  	}
   443  	err = g.ActiveDevice.SetOrClear(m, ad)
   444  	if err != nil {
   445  		return err
   446  	}
   447  	m.CommitProvisionalLogin()
   448  
   449  	return nil
   450  }
   451  
   452  func (m MetaContext) SwitchUserDeprovisionNukeConfig(username NormalizedUsername) error {
   453  	g := m.G()
   454  	defer g.switchUserMu.Acquire(m, "SwitchUserDeprovisionNukeConfig %v", username)()
   455  
   456  	cw := g.Env.GetConfigWriter()
   457  	if cw == nil {
   458  		return NoConfigWriterError{}
   459  	}
   460  	if err := cw.NukeUser(username); err != nil {
   461  		return err
   462  	}
   463  
   464  	// The config entries we just nuked could still be in memory. Clear them.
   465  	return cw.SetUserConfig(nil, true /* overwrite; ignored */)
   466  }
   467  
   468  // SetActiveOneshotDevice acquires the switchUserMu mutex, setting the active
   469  // device to one that corresponds to the given UID and DeviceWithKeys, and also
   470  // sets the config file to a temporary in-memory config (not writing to disk)
   471  // to satisfy local requests for g.Env.*
   472  func (m MetaContext) SwitchUserToActiveOneshotDevice(uv keybase1.UserVersion, nun NormalizedUsername, d *DeviceWithKeys) (err error) {
   473  	defer m.Trace("MetaContext#SwitchUserToActiveOneshotDevice", &err)()
   474  
   475  	g := m.G()
   476  	defer g.switchUserMu.Acquire(m, "SwitchUserToActiveOneshotDevice")()
   477  	cw := g.Env.GetConfigWriter()
   478  	if cw == nil {
   479  		return NoConfigWriterError{}
   480  	}
   481  	ad := d.ToProvisioningKeyActiveDevice(m, uv)
   482  	err = g.ActiveDevice.Copy(m, ad)
   483  	if err != nil {
   484  		return err
   485  	}
   486  	uc := NewOneshotUserConfig(uv.Uid, nun, nil, d.DeviceID())
   487  	err = cw.SetUserConfig(uc, false)
   488  	if err != nil {
   489  		return err
   490  	}
   491  	return nil
   492  }
   493  
   494  // SwitchUserLoggedOut clears the active device and the current_user stanza of
   495  // the config file, all while holding the switchUserMu
   496  func (m MetaContext) SwitchUserLoggedOut() (err error) {
   497  	defer m.Trace("MetaContext#SwitchUserLoggedOut", &err)()
   498  	g := m.G()
   499  	defer g.switchUserMu.Acquire(m, "SwitchUserLoggedOut")()
   500  	cw := g.Env.GetConfigWriter()
   501  	if cw == nil {
   502  		return NoConfigWriterError{}
   503  	}
   504  	err = g.ActiveDevice.Clear()
   505  	if err != nil {
   506  		return err
   507  	}
   508  	err = cw.SetUserConfig(nil, false)
   509  	if err != nil {
   510  		return err
   511  	}
   512  	return nil
   513  }
   514  
   515  // SetActiveDevice sets the active device to have the UserVersion, deviceID,
   516  // sigKey, encKey and deviceName as specified, and does so while grabbing the
   517  // global switchUser lock, since it should be sycnhronized with attempts to
   518  // switch the global logged in user. It does not, however, change the
   519  // `current_user` in the config file, or edit the global config file in any
   520  // way.
   521  func (m MetaContext) SetActiveDevice(uv keybase1.UserVersion, deviceID keybase1.DeviceID,
   522  	sigKey, encKey GenericKey, deviceName string, keychainMode KeychainMode) error {
   523  	g := m.G()
   524  	defer g.switchUserMu.Acquire(m, "SetActiveDevice")()
   525  	if !g.Env.GetUID().Equal(uv.Uid) {
   526  		return NewUIDMismatchError("UID switched out from underneath provisioning process")
   527  	}
   528  	return g.ActiveDevice.Set(m, uv, deviceID, sigKey, encKey, deviceName, 0, keychainMode)
   529  }
   530  
   531  func (m MetaContext) SetSigningKey(uv keybase1.UserVersion, deviceID keybase1.DeviceID, sigKey GenericKey, deviceName string) error {
   532  	g := m.G()
   533  	defer g.switchUserMu.Acquire(m, "SetSigningKey")()
   534  	return g.ActiveDevice.setSigningKey(g, uv, deviceID, sigKey, deviceName)
   535  }
   536  
   537  func (m MetaContext) SetEncryptionKey(uv keybase1.UserVersion, deviceID keybase1.DeviceID, encKey GenericKey) error {
   538  	g := m.G()
   539  	defer g.switchUserMu.Acquire(m, "SetEncryptionKey")()
   540  	return g.ActiveDevice.setEncryptionKey(uv, deviceID, encKey)
   541  }
   542  
   543  // LogoutAndDeprovisionIfRevoked loads the user and checks if the current
   544  // device keys have been revoked. If so, it calls Logout and then runs the
   545  // ClearSecretsOnDeprovision
   546  func (m MetaContext) LogoutAndDeprovisionIfRevoked() (err error) {
   547  	m = m.WithLogTag("LOIR")
   548  
   549  	defer m.Trace("GlobalContext#LogoutAndDeprovisionIfRevoked", &err)()
   550  
   551  	if !m.ActiveDevice().Valid() {
   552  		m.Debug("LogoutAndDeprovisionIfRevoked: skipping check (not logged in)")
   553  		return nil
   554  	}
   555  
   556  	if m.G().Env.GetSkipLogoutIfRevokedCheck() {
   557  		m.Debug("LogoutAndDeprovisionIfRevoked: skipping check (SkipLogoutIfRevokedCheck)")
   558  		return nil
   559  	}
   560  
   561  	doLogout := false
   562  	err = CheckCurrentUIDDeviceID(m)
   563  	switch err.(type) {
   564  	case nil:
   565  		m.Debug("LogoutAndDeprovisionIfRevoked: current device ok")
   566  	case DeviceNotFoundError:
   567  		m.Debug("LogoutAndDeprovisionIfRevoked: device not found error; user was likely reset; calling logout (%s)", err)
   568  		doLogout = true
   569  	case KeyRevokedError:
   570  		m.Debug("LogoutAndDeprovisionIfRevoked: key revoked error error; device was revoked; calling logout (%s)", err)
   571  		doLogout = true
   572  	default:
   573  		m.Debug("LogoutAndDeprovisionIfRevoked: non-actionable error: %s", err)
   574  	}
   575  
   576  	if doLogout {
   577  		username := m.G().Env.GetUsername()
   578  		if err := m.LogoutWithOptions(LogoutOptions{KeepSecrets: false, Force: true}); err != nil {
   579  			return err
   580  		}
   581  		return ClearSecretsOnDeprovision(m, username)
   582  	}
   583  
   584  	return nil
   585  }
   586  
   587  func (m MetaContext) PassphraseStream() *PassphraseStream {
   588  	if m.LoginContext() != nil {
   589  		if m.LoginContext().PassphraseStreamCache() == nil {
   590  			return nil
   591  		}
   592  		return m.LoginContext().PassphraseStreamCache().PassphraseStream()
   593  	}
   594  	return m.ActiveDevice().PassphraseStream()
   595  }
   596  
   597  func (m MetaContext) PassphraseStreamAndTriplesec() (*PassphraseStream, Triplesec) {
   598  	var ppsc *PassphraseStreamCache
   599  	if m.LoginContext() != nil {
   600  		ppsc = m.LoginContext().PassphraseStreamCache()
   601  	} else {
   602  		ppsc = m.ActiveDevice().PassphraseStreamCache()
   603  	}
   604  	if ppsc == nil {
   605  		return nil, nil
   606  	}
   607  	return ppsc.PassphraseStreamAndTriplesec()
   608  }
   609  
   610  func (m MetaContext) TriplesecAndGeneration() (ret Triplesec, ppgen PassphraseGeneration) {
   611  	var pps *PassphraseStream
   612  	pps, ret = m.PassphraseStreamAndTriplesec()
   613  	if pps == nil {
   614  		return nil, ppgen
   615  	}
   616  	ppgen = pps.Generation()
   617  	if ppgen.IsNil() {
   618  		return nil, ppgen
   619  	}
   620  	return ret, ppgen
   621  }
   622  
   623  func (m MetaContext) CurrentUsername() NormalizedUsername {
   624  	if m.LoginContext() != nil {
   625  		return m.LoginContext().GetUsername()
   626  	}
   627  	return m.ActiveDevice().Username(m)
   628  }
   629  
   630  func (m MetaContext) CurrentUID() keybase1.UID {
   631  	if m.LoginContext() != nil {
   632  		return m.LoginContext().GetUID()
   633  	}
   634  	return m.ActiveDevice().UID()
   635  }
   636  
   637  func (m MetaContext) CurrentUserVersion() keybase1.UserVersion {
   638  	if m.LoginContext() != nil {
   639  		return m.LoginContext().GetUserVersion()
   640  	}
   641  	return m.ActiveDevice().UserVersion()
   642  }
   643  
   644  func (m MetaContext) HasAnySession() (ret bool) {
   645  	defer m.Trace("MetaContext#HasAnySession", nil)()
   646  	if m.LoginContext() != nil {
   647  		ok, _ := m.LoginContext().LoggedInLoad()
   648  		if ok {
   649  			m.Debug("| has temporary login session")
   650  			return true
   651  		}
   652  	}
   653  
   654  	if m.ActiveDevice().Valid() {
   655  		m.Debug("| has valid device")
   656  		return true
   657  	}
   658  
   659  	return false
   660  }
   661  
   662  func (m MetaContext) SyncSecrets() (ss *SecretSyncer, err error) {
   663  	defer m.Trace("MetaContext#SyncSecrets", &err)()
   664  	if m.LoginContext() != nil {
   665  		err = m.LoginContext().RunSecretSyncer(m, keybase1.UID(""))
   666  		if err != nil {
   667  			return nil, err
   668  		}
   669  		return m.LoginContext().SecretSyncer(), nil
   670  	}
   671  	return m.ActiveDevice().SyncSecrets(m)
   672  }
   673  
   674  func (m MetaContext) SyncSecretsForUID(u keybase1.UID) (ss *SecretSyncer, err error) {
   675  	defer m.Trace("MetaContext#SyncSecrets", &err)()
   676  	return m.ActiveDevice().SyncSecretsForUID(m, u, false /* force */)
   677  }
   678  
   679  func (m MetaContext) ProvisionalSessionArgs() (token string, csrf string) {
   680  	if m.LoginContext() == nil {
   681  		return "", ""
   682  	}
   683  	sess := m.LoginContext().LocalSession()
   684  	if sess == nil || !sess.IsValid() {
   685  		return "", ""
   686  	}
   687  	return sess.token, sess.csrf
   688  }
   689  
   690  func (m MetaContext) Keyring() (ret *SKBKeyringFile, err error) {
   691  	defer m.Trace("MetaContext#Keyring", &err)()
   692  	if m.LoginContext() != nil {
   693  		return m.LoginContext().Keyring(m)
   694  	}
   695  	return m.ActiveDevice().Keyring(m)
   696  }
   697  
   698  var _ logger.ContextInterface = MetaContext{}
   699  
   700  func (m MetaContext) UpdateContextToLoggerContext(c context.Context) logger.ContextInterface {
   701  	return m.WithContext(c)
   702  }
   703  
   704  func (m MetaContext) DebugStack() {
   705  	m.Debug("stack trace:\n%s", string(debug.Stack()))
   706  }