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

     1  package systests
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/keybase/client/go/engine"
     8  	"github.com/keybase/client/go/ephemeral"
     9  	"github.com/keybase/client/go/libkb"
    10  	"github.com/keybase/client/go/protocol/gregor1"
    11  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    12  	"github.com/keybase/client/go/teambot"
    13  	"github.com/keybase/clockwork"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func initEphemeralForTests(t *testing.T, mctx libkb.MetaContext) {
    18  	ephemeral.ServiceInit(mctx)
    19  	err := mctx.G().GetEKLib().KeygenIfNeeded(mctx)
    20  	require.NoError(t, err)
    21  }
    22  
    23  func TestEphemeralNewTeamEKNotif(t *testing.T) {
    24  	tt := newTeamTester(t)
    25  	defer tt.cleanup()
    26  
    27  	user1 := tt.addUser("one")
    28  	user2 := tt.addUser("wtr")
    29  	mctx := user1.MetaContext()
    30  	ekLib := user1.tc.G.GetEKLib()
    31  	err := ekLib.KeygenIfNeeded(mctx)
    32  	require.NoError(t, err)
    33  
    34  	mctx2 := user2.MetaContext()
    35  	err = mctx2.G().GetEKLib().KeygenIfNeeded(mctx2)
    36  	require.NoError(t, err)
    37  
    38  	teamID, teamName := user1.createTeam2()
    39  	user1.addTeamMember(teamName.String(), user2.username, keybase1.TeamRole_WRITER)
    40  
    41  	teamEK, created, err := ekLib.GetOrCreateLatestTeamEK(mctx, teamID)
    42  	require.NoError(t, err)
    43  	require.True(t, created)
    44  
    45  	expectedArg := keybase1.NewTeamEkArg{
    46  		Id:         teamID,
    47  		Generation: teamEK.Generation(),
    48  	}
    49  
    50  	checkNewTeamEKNotifications(user1.tc, user1.notifications, expectedArg)
    51  	checkNewTeamEKNotifications(user2.tc, user2.notifications, expectedArg)
    52  }
    53  
    54  func checkNewTeamEKNotifications(tc *libkb.TestContext, notifications *teamNotifyHandler, expectedArg keybase1.NewTeamEkArg) {
    55  	select {
    56  	case arg := <-notifications.newTeamEKCh:
    57  		require.Equal(tc.T, expectedArg, arg)
    58  		return
    59  	case <-time.After(time.Second * libkb.CITimeMultiplier(tc.G)):
    60  		require.Fail(tc.T, "no notification on newTeamEK")
    61  	}
    62  }
    63  
    64  func TestEphemeralNewTeambotEKNotif(t *testing.T) {
    65  	tt := newTeamTester(t)
    66  	defer tt.cleanup()
    67  
    68  	user1 := tt.addUser("one")
    69  	botua := tt.addUser("botua")
    70  	botuaUID := gregor1.UID(botua.uid.ToBytes())
    71  	mctx := user1.MetaContext()
    72  	ekLib := user1.tc.G.GetEKLib()
    73  	err := ekLib.KeygenIfNeeded(mctx)
    74  	require.NoError(t, err)
    75  
    76  	botuaMctx := botua.MetaContext()
    77  	err = botuaMctx.G().GetEKLib().KeygenIfNeeded(botuaMctx)
    78  	require.NoError(t, err)
    79  
    80  	teamID, teamName := user1.createTeam2()
    81  	user1.addRestrictedBotTeamMember(teamName.String(), botua.username, keybase1.TeamBotSettings{})
    82  
    83  	teambotEK, created, err := ekLib.GetOrCreateLatestTeambotEK(mctx, teamID, botuaUID)
    84  	require.NoError(t, err)
    85  	require.True(t, created)
    86  
    87  	expectedArg := keybase1.NewTeambotEkArg{
    88  		Id:         teamID,
    89  		Generation: teambotEK.Generation(),
    90  	}
    91  
    92  	checkNewTeambotEKNotifications(botua.tc, botua.notifications, expectedArg)
    93  }
    94  
    95  func checkNewTeambotEKNotifications(tc *libkb.TestContext, notifications *teamNotifyHandler, expectedArg keybase1.NewTeambotEkArg) {
    96  	select {
    97  	case arg := <-notifications.newTeambotEKCh:
    98  		require.Equal(tc.T, expectedArg, arg)
    99  		return
   100  	case <-time.After(time.Second * libkb.CITimeMultiplier(tc.G)):
   101  		require.Fail(tc.T, "no notification on newTeambotEK")
   102  	}
   103  }
   104  
   105  func checkTeambotEKNeededNotifications(tc *libkb.TestContext, notifications *teamNotifyHandler, expectedArg keybase1.TeambotEkNeededArg) {
   106  	select {
   107  	case arg := <-notifications.teambotEKNeededCh:
   108  		require.Equal(tc.T, expectedArg, arg)
   109  		return
   110  	case <-time.After(time.Second * libkb.CITimeMultiplier(tc.G)):
   111  		require.Fail(tc.T, "no notification on teambotEKNeeded")
   112  	}
   113  }
   114  
   115  func noNewTeambotEKNotification(tc *libkb.TestContext, notifications *teamNotifyHandler) {
   116  	select {
   117  	case arg := <-notifications.newTeambotEKCh:
   118  		require.Fail(tc.T, "unexpected newTeambotEK notification", arg)
   119  	default:
   120  	}
   121  }
   122  
   123  func noTeambotEKNeeded(tc *libkb.TestContext, notifications *teamNotifyHandler) {
   124  	select {
   125  	case arg := <-notifications.teambotEKNeededCh:
   126  		require.Fail(tc.T, "unexpected teambotEKNeeded notification", arg)
   127  	default:
   128  	}
   129  }
   130  
   131  func TestEphemeralTeambotEK(t *testing.T) {
   132  	tt := newTeamTester(t)
   133  	defer tt.cleanup()
   134  
   135  	fc := clockwork.NewFakeClockAt(time.Now())
   136  
   137  	user1 := tt.addUser("one")
   138  	user2 := tt.addUserWithPaper("two")
   139  	botua := tt.addUser("botua")
   140  	botuaUID := gregor1.UID(botua.uid.ToBytes())
   141  	mctx1 := user1.MetaContext()
   142  	mctx2 := user2.MetaContext()
   143  	mctx3 := botua.MetaContext()
   144  	ekLib1 := mctx1.G().GetEKLib()
   145  	ekLib2 := mctx2.G().GetEKLib()
   146  	ekLib3 := mctx3.G().GetEKLib().(*ephemeral.EKLib)
   147  	ekLib3.SetClock(fc)
   148  	err := ekLib1.KeygenIfNeeded(mctx1)
   149  	require.NoError(t, err)
   150  	err = ekLib2.KeygenIfNeeded(mctx2)
   151  	require.NoError(t, err)
   152  	err = ekLib3.KeygenIfNeeded(mctx3)
   153  	require.NoError(t, err)
   154  
   155  	teamID, teamName := user1.createTeam2()
   156  	user1.addTeamMember(teamName.String(), user2.username, keybase1.TeamRole_WRITER)
   157  	user1.addRestrictedBotTeamMember(teamName.String(), botua.username, keybase1.TeamBotSettings{})
   158  
   159  	// bot gets a key on addition to the team
   160  	newEkArg := keybase1.NewTeambotEkArg{
   161  		Id:         teamID,
   162  		Generation: 1,
   163  	}
   164  	checkNewTeambotEKNotifications(botua.tc, botua.notifications, newEkArg)
   165  
   166  	// grab the latest teamEK and make sure the generation lines up with the teambotEK
   167  	teamEK, _, err := ekLib1.GetOrCreateLatestTeamEK(mctx1, teamID)
   168  	require.NoError(t, err)
   169  
   170  	// now created = false since we published on member addition
   171  	teambotEK, created, err := ekLib1.GetOrCreateLatestTeambotEK(mctx1, teamID, botuaUID)
   172  	require.NoError(t, err)
   173  	require.False(t, created)
   174  	require.Equal(t, teamEK.Generation(), teambotEK.Generation())
   175  
   176  	teambotEK2, _, err := ekLib3.GetOrCreateLatestTeambotEK(mctx3, teamID, botuaUID)
   177  	require.NoError(t, err)
   178  	require.Equal(t, teambotEK2.Generation(), teambotEK.Generation())
   179  	require.Equal(t, teambotEK2.Material(), teambotEK.Material())
   180  	noTeambotEKNeeded(user1.tc, user1.notifications)
   181  	noTeambotEKNeeded(user2.tc, user2.notifications)
   182  	noNewTeambotEKNotification(botua.tc, botua.notifications)
   183  
   184  	// simulate a bot restarting in one shot mode and losing it's deviceEKs
   185  	botDeviceEKStore := mctx3.G().GetDeviceEKStorage()
   186  	err = botDeviceEKStore.ForceDeleteAll(mctx3, libkb.NormalizedUsername(botua.username))
   187  	require.NoError(t, err)
   188  	ekLib3.ClearCaches(mctx3)
   189  
   190  	_, created, err = ekLib3.GetOrCreateLatestTeambotEK(mctx3, teamID, botuaUID)
   191  	require.Error(t, err)
   192  	require.IsType(t, ephemeral.EphemeralKeyError{}, err)
   193  	require.False(t, created)
   194  
   195  	// cry for help has been issued.
   196  	forceCreateGen := teambotEK.Generation()
   197  	ekNeededArg := keybase1.TeambotEkNeededArg{
   198  		Id:                    teamID,
   199  		Uid:                   botua.uid,
   200  		Generation:            0,
   201  		ForceCreateGeneration: &forceCreateGen,
   202  	}
   203  	checkTeambotEKNeededNotifications(user1.tc, user1.notifications, ekNeededArg)
   204  	checkTeambotEKNeededNotifications(user2.tc, user2.notifications, ekNeededArg)
   205  
   206  	// and answered.
   207  	newEkArg = keybase1.NewTeambotEkArg{
   208  		Id:         teamID,
   209  		Generation: 2,
   210  	}
   211  	checkNewTeambotEKNotifications(botua.tc, botua.notifications, newEkArg)
   212  
   213  	// bot can access the key
   214  	teambotEK2, created, err = ekLib3.GetOrCreateLatestTeambotEK(mctx3, teamID, botuaUID)
   215  	require.NoError(t, err)
   216  	require.False(t, created)
   217  
   218  	teambotEK, _, err = ekLib1.GetOrCreateLatestTeambotEK(mctx1, teamID, botuaUID)
   219  	require.NoError(t, err)
   220  
   221  	require.Equal(t, teambotEK.Generation(), teambotEK2.Generation())
   222  	require.Equal(t, teambotEK.Material(), teambotEK2.Material())
   223  	noTeambotEKNeeded(user1.tc, user1.notifications)
   224  	noTeambotEKNeeded(user2.tc, user2.notifications)
   225  	noNewTeambotEKNotification(botua.tc, botua.notifications)
   226  
   227  	// force a PTK rotation
   228  	user2.revokePaperKey()
   229  	user1.waitForRotateByID(teamID, keybase1.Seqno(4))
   230  
   231  	// bot gets a new EK on rotation
   232  	newEkArg = keybase1.NewTeambotEkArg{
   233  		Id:         teamID,
   234  		Generation: 3,
   235  	}
   236  	checkNewTeambotEKNotifications(botua.tc, botua.notifications, newEkArg)
   237  
   238  	// simulate a bot restarting in one shot mode and losing it's deviceEKs
   239  	botDeviceEKStore = mctx3.G().GetDeviceEKStorage()
   240  	err = botDeviceEKStore.ForceDeleteAll(mctx3, libkb.NormalizedUsername(botua.username))
   241  	require.NoError(t, err)
   242  	ekLib3.ClearCaches(mctx3)
   243  
   244  	// Force a wrongKID error on the bot user by expiring the wrongKID cache
   245  	key := teambot.TeambotEKWrongKIDCacheKey(teamID, botua.uid, teambotEK2.Generation())
   246  	expired := keybase1.ToTime(fc.Now())
   247  	err = mctx3.G().GetKVStore().PutObj(key, nil, expired)
   248  	require.NoError(t, err)
   249  	permitted, ctime, err := teambot.TeambotEKWrongKIDPermitted(mctx3, teamID, botua.uid,
   250  		teambotEK2.Generation(), keybase1.ToTime(fc.Now()))
   251  	require.NoError(t, err)
   252  	require.True(t, permitted)
   253  	require.Equal(t, expired, ctime)
   254  
   255  	fc.Advance(teambot.MaxTeambotKeyWrongKIDPermitted) // expire wrong KID cache
   256  	permitted, ctime, err = teambot.TeambotEKWrongKIDPermitted(mctx3, teamID, botua.uid,
   257  		teambotEK2.Generation(), keybase1.ToTime(fc.Now()))
   258  	require.NoError(t, err)
   259  	require.False(t, permitted)
   260  	require.Equal(t, expired, ctime)
   261  
   262  	fc.Advance(ephemeral.LibCacheEntryLifetime) // expire lib ek caches
   263  	_, created, err = ekLib3.GetOrCreateLatestTeambotEK(mctx3, teamID, botuaUID)
   264  	require.Error(t, err)
   265  	require.IsType(t, ephemeral.EphemeralKeyError{}, err)
   266  	require.False(t, created)
   267  	forceCreateGen = keybase1.EkGeneration(3)
   268  	ekNeededArg = keybase1.TeambotEkNeededArg{
   269  		Id:                    teamID,
   270  		Uid:                   botua.uid,
   271  		Generation:            0,
   272  		ForceCreateGeneration: &forceCreateGen,
   273  	}
   274  	checkTeambotEKNeededNotifications(user1.tc, user1.notifications, ekNeededArg)
   275  	checkTeambotEKNeededNotifications(user2.tc, user2.notifications, ekNeededArg)
   276  	newEkArg = keybase1.NewTeambotEkArg{
   277  		Id:         teamID,
   278  		Generation: forceCreateGen + 1,
   279  	}
   280  	checkNewTeambotEKNotifications(botua.tc, botua.notifications, newEkArg)
   281  
   282  	teambotEK3, created, err := ekLib3.GetOrCreateLatestTeambotEK(mctx3, teamID, botuaUID)
   283  	require.NoError(t, err)
   284  	require.False(t, created)
   285  	noTeambotEKNeeded(user1.tc, user1.notifications)
   286  	noTeambotEKNeeded(user2.tc, user2.notifications)
   287  	noNewTeambotEKNotification(botua.tc, botua.notifications)
   288  
   289  	// another PTK rotation happens, this time the bot proceeded with a key
   290  	// signed by the old PTK since the wrongKID cache did not expire
   291  	user1.removeTeamMember(teamName.String(), user2.username)
   292  	user1.addTeamMember(teamName.String(), user2.username, keybase1.TeamRole_WRITER)
   293  	user2.waitForNewlyAddedToTeamByID(teamID)
   294  	botua.waitForNewlyAddedToTeamByID(teamID)
   295  
   296  	// bot gets a new EK on rotation
   297  	newEkArg = keybase1.NewTeambotEkArg{
   298  		Id:         teamID,
   299  		Generation: 5,
   300  	}
   301  	checkNewTeambotEKNotifications(botua.tc, botua.notifications, newEkArg)
   302  
   303  	// delete to check regeneration flow
   304  	err = teambot.DeleteTeambotEKForTest(mctx3, teamID, 5)
   305  	require.NoError(t, err)
   306  
   307  	// bot can access the old teambotEK, but asks for a new one to
   308  	// be created since it was signed by the old PTK
   309  	fc.Advance(ephemeral.LibCacheEntryLifetime) // expire lib ek caches
   310  	teambotEK4, created, err := ekLib3.GetOrCreateLatestTeambotEK(mctx3, teamID, botuaUID)
   311  	require.NoError(t, err)
   312  	require.False(t, created)
   313  	require.Equal(t, teambotEK3.Generation(), teambotEK4.Generation())
   314  	require.Equal(t, teambotEK3.Material(), teambotEK4.Material())
   315  	forceCreateGen = keybase1.EkGeneration(5)
   316  	ekNeededArg = keybase1.TeambotEkNeededArg{
   317  		Id:                    teamID,
   318  		Uid:                   botua.uid,
   319  		Generation:            0,
   320  		ForceCreateGeneration: &forceCreateGen,
   321  	}
   322  	checkTeambotEKNeededNotifications(user1.tc, user1.notifications, ekNeededArg)
   323  	checkTeambotEKNeededNotifications(user2.tc, user2.notifications, ekNeededArg)
   324  
   325  	newEkArg = keybase1.NewTeambotEkArg{
   326  		Id:         teamID,
   327  		Generation: forceCreateGen + 1,
   328  	}
   329  	checkNewTeambotEKNotifications(botua.tc, botua.notifications, newEkArg)
   330  
   331  	teambotEK, created, err = ekLib1.GetOrCreateLatestTeambotEK(mctx1, teamID, botuaUID)
   332  	require.NoError(t, err)
   333  	require.False(t, created)
   334  	require.Equal(t, forceCreateGen+1, teambotEK.Generation())
   335  
   336  	teambotEK2, created, err = ekLib3.GetOrCreateLatestTeambotEK(mctx3, teamID, botuaUID)
   337  	require.NoError(t, err)
   338  	require.False(t, created)
   339  	require.Equal(t, teambotEK.Generation(), teambotEK2.Generation())
   340  	require.Equal(t, teambotEK.Material(), teambotEK2.Material())
   341  	noTeambotEKNeeded(user1.tc, user1.notifications)
   342  	noTeambotEKNeeded(user2.tc, user2.notifications)
   343  	noNewTeambotEKNotification(botua.tc, botua.notifications)
   344  
   345  	// kill the ek cache and make sure we don't republish
   346  	ekLib1.ClearCaches(mctx1)
   347  	teambotEKNoCache, created, err := ekLib1.GetOrCreateLatestTeambotEK(mctx1, teamID, botuaUID)
   348  	require.NoError(t, err)
   349  	// created is True since we attempt to publish but the generation remains
   350  	require.True(t, created)
   351  	require.Equal(t, teambotEK.Generation(), teambotEKNoCache.Generation())
   352  
   353  	// Make sure we can access the teambotEK at various generations
   354  	for i := keybase1.EkGeneration(1); i < teambotEK.Generation(); i++ {
   355  		teambotEKNonBot1, err := ekLib1.GetTeambotEK(mctx1, teamID, botuaUID, i, nil)
   356  		require.NoError(t, err)
   357  
   358  		teambotEKNonBot2, err := ekLib2.GetTeambotEK(mctx2, teamID, botuaUID, i, nil)
   359  		require.NoError(t, err)
   360  
   361  		teambotEKBot, err := ekLib3.GetTeambotEK(mctx3, teamID, botuaUID, i, nil)
   362  		switch i {
   363  		case 1, 2, 3:
   364  			require.Error(t, err)
   365  		default:
   366  			require.NoError(t, err)
   367  			require.Equal(t, teambotEKBot.Generation(), teambotEKNonBot1.Generation())
   368  			require.Equal(t, teambotEKBot.Material(), teambotEKNonBot1.Material())
   369  			require.Equal(t, teambotEKBot.Generation(), teambotEKNonBot2.Generation())
   370  			require.Equal(t, teambotEKBot.Material(), teambotEKNonBot2.Material())
   371  		}
   372  		if i == 5 {
   373  			newEkArg = keybase1.NewTeambotEkArg{
   374  				Id:         teamID,
   375  				Generation: 5,
   376  			}
   377  			checkNewTeambotEKNotifications(botua.tc, botua.notifications, newEkArg)
   378  		}
   379  		noNewTeambotEKNotification(botua.tc, botua.notifications)
   380  		noTeambotEKNeeded(user1.tc, user1.notifications)
   381  		noTeambotEKNeeded(user2.tc, user2.notifications)
   382  	}
   383  
   384  	// bot asks for a non-existent generation, no new key is created.
   385  	badGen := teambotEK.Generation() + 50
   386  	_, err = ekLib3.GetTeambotEK(mctx3, teamID, botuaUID, badGen, nil)
   387  	require.Error(t, err)
   388  	require.IsType(t, ephemeral.EphemeralKeyError{}, err)
   389  	ekNeededArg = keybase1.TeambotEkNeededArg{
   390  		Id:         teamID,
   391  		Uid:        botua.uid,
   392  		Generation: 0,
   393  	}
   394  	checkTeambotEKNeededNotifications(user1.tc, user1.notifications, ekNeededArg)
   395  	checkTeambotEKNeededNotifications(user2.tc, user2.notifications, ekNeededArg)
   396  	noNewTeambotEKNotification(botua.tc, botua.notifications)
   397  }
   398  
   399  func TestEphemeralAddMemberWithTeamEK(t *testing.T) {
   400  	runAddMember(t, true /* createTeamEK*/)
   401  }
   402  
   403  func TestEphemeralAddMemberNoTeamEK(t *testing.T) {
   404  	runAddMember(t, false /* createTeamEK*/)
   405  }
   406  
   407  func getTeamEK(mctx libkb.MetaContext, teamID keybase1.TeamID, generation keybase1.EkGeneration) (keybase1.TeamEk, error) {
   408  	ek, err := mctx.G().GetTeamEKBoxStorage().Get(mctx, teamID, generation, nil)
   409  	if err != nil {
   410  		return keybase1.TeamEk{}, err
   411  	}
   412  
   413  	typ, err := ek.KeyType()
   414  	if err != nil {
   415  		return keybase1.TeamEk{}, err
   416  	}
   417  	if !typ.IsTeam() {
   418  		return keybase1.TeamEk{}, ephemeral.NewIncorrectTeamEphemeralKeyTypeError(typ, keybase1.TeamEphemeralKeyType_TEAM)
   419  	}
   420  	return ek.Team(), nil
   421  }
   422  
   423  func runAddMember(t *testing.T, createTeamEK bool) {
   424  	ctx := newSMUContext(t)
   425  	defer ctx.cleanup()
   426  
   427  	ann := ctx.installKeybaseForUser("ann", 10)
   428  	ann.signup()
   429  	bob := ctx.installKeybaseForUser("bob", 10)
   430  	bob.signup()
   431  
   432  	annMctx := ann.MetaContext()
   433  	initEphemeralForTests(t, annMctx)
   434  	bobMctx := bob.MetaContext()
   435  	initEphemeralForTests(t, bobMctx)
   436  
   437  	team := ann.createTeam([]*smuUser{})
   438  	teamName, err := keybase1.TeamNameFromString(team.name)
   439  	require.NoError(t, err)
   440  	teamID := teamName.ToPrivateTeamID()
   441  
   442  	var expectedMetadata keybase1.TeamEkMetadata
   443  	var expectedGeneration keybase1.EkGeneration
   444  	if createTeamEK {
   445  		ekLib := annMctx.G().GetEKLib()
   446  		ek, created, err := ekLib.GetOrCreateLatestTeamEK(annMctx, teamID)
   447  		require.NoError(t, err)
   448  		require.True(t, created)
   449  		typ, err := ek.KeyType()
   450  		require.NoError(t, err)
   451  		require.True(t, typ.IsTeam())
   452  		teamEK := ek.Team()
   453  
   454  		expectedMetadata = teamEK.Metadata
   455  		expectedGeneration = expectedMetadata.Generation
   456  	} else {
   457  		expectedMetadata = keybase1.TeamEkMetadata{}
   458  		expectedGeneration = 1
   459  	}
   460  
   461  	ann.addWriter(team, bob)
   462  
   463  	annTeamEK, annErr := getTeamEK(annMctx, teamID, expectedGeneration)
   464  	bobTeamEK, bobErr := getTeamEK(bobMctx, teamID, expectedGeneration)
   465  	if createTeamEK {
   466  		require.NoError(t, annErr)
   467  		require.NoError(t, bobErr)
   468  	} else {
   469  		require.Error(t, annErr)
   470  		require.IsType(t, ephemeral.EphemeralKeyError{}, annErr)
   471  		ekErr := annErr.(ephemeral.EphemeralKeyError)
   472  		require.Equal(t, ephemeral.DefaultHumanErrMsg, ekErr.HumanError())
   473  
   474  		require.Error(t, bobErr)
   475  		require.IsType(t, ephemeral.EphemeralKeyError{}, bobErr)
   476  		ekErr = bobErr.(ephemeral.EphemeralKeyError)
   477  		require.Equal(t, ephemeral.DefaultHumanErrMsg, ekErr.HumanError())
   478  	}
   479  	require.Equal(t, bobTeamEK.Metadata, expectedMetadata)
   480  	require.Equal(t, annTeamEK.Metadata, expectedMetadata)
   481  }
   482  
   483  func TestEphemeralResetMember(t *testing.T) {
   484  	t.Skip()
   485  	ctx := newSMUContext(t)
   486  	defer ctx.cleanup()
   487  
   488  	ann := ctx.installKeybaseForUser("ann", 10)
   489  	ann.signup()
   490  	ann.registerForNotifications()
   491  	bob := ctx.installKeybaseForUser("bob", 10)
   492  	bob.signup()
   493  	joe := ctx.installKeybaseForUser("joe", 10)
   494  	joe.signup()
   495  
   496  	annMctx := ann.MetaContext()
   497  	initEphemeralForTests(t, annMctx)
   498  	bobMctx := bob.MetaContext()
   499  	initEphemeralForTests(t, bobMctx)
   500  	joeMctx := joe.MetaContext()
   501  	initEphemeralForTests(t, joeMctx)
   502  
   503  	team := ann.createTeam([]*smuUser{bob})
   504  	teamName, err := keybase1.TeamNameFromString(team.name)
   505  	require.NoError(t, err)
   506  	teamID := teamName.ToPrivateTeamID()
   507  
   508  	// Reset bob, invaliding any userEK he has.
   509  	bob.reset()
   510  
   511  	annEkLib := annMctx.G().GetEKLib()
   512  	ek, created, err := annEkLib.GetOrCreateLatestTeamEK(annMctx, teamID)
   513  	require.NoError(t, err)
   514  	require.True(t, created)
   515  
   516  	typ, err := ek.KeyType()
   517  	require.NoError(t, err)
   518  	require.True(t, typ.IsTeam())
   519  	teamEK := ek.Team()
   520  
   521  	expectedMetadata := teamEK.Metadata
   522  	expectedGeneration := expectedMetadata.Generation
   523  
   524  	annTeamEK, annErr := getTeamEK(annMctx, teamID, expectedGeneration)
   525  	require.NoError(t, annErr)
   526  	require.Equal(t, annTeamEK.Metadata, expectedMetadata)
   527  
   528  	// Bob should not have access to this teamEK since he's no longer in the
   529  	// team after resetting.
   530  	bob.loginAfterReset(10)
   531  	bobMctx = bob.MetaContext()
   532  	// make sure bob has new EKs
   533  	err = bobMctx.G().GetEKLib().KeygenIfNeeded(bobMctx)
   534  	require.NoError(t, err)
   535  
   536  	_, bobErr := getTeamEK(bobMctx, teamID, expectedGeneration)
   537  	require.Error(t, bobErr)
   538  	require.IsType(t, libkb.AppStatusError{}, bobErr)
   539  	appStatusErr := bobErr.(libkb.AppStatusError)
   540  	require.Equal(t, appStatusErr.Code, libkb.SCNotFound)
   541  
   542  	// Also add joe who has a valid userEK
   543  	ann.addWriter(team, bob)
   544  	ann.addWriter(team, joe)
   545  	ann.waitForNewlyAddedToTeamByID(teamID)
   546  
   547  	// ann gets the new teamEk which joe can access but bob cannot after he reset.
   548  	ek2, created, err := annEkLib.GetOrCreateLatestTeamEK(annMctx, teamID)
   549  	require.NoError(t, err)
   550  	require.False(t, created)
   551  	typ, err = ek.KeyType()
   552  	require.NoError(t, err)
   553  	require.True(t, typ.IsTeam())
   554  	teamEK2 := ek2.Team()
   555  
   556  	expectedMetadata2 := teamEK2.Metadata
   557  	expectedGeneration2 := expectedMetadata2.Generation
   558  	// We can't require that the next generation is exactly 1 greater than the
   559  	// previous, because there's a race where a CLKR sneaks in here.
   560  	require.True(t, expectedGeneration < expectedGeneration2)
   561  
   562  	annTeamEK, annErr = getTeamEK(annMctx, teamID, expectedGeneration2)
   563  	require.NoError(t, annErr)
   564  	require.Equal(t, annTeamEK.Metadata, expectedMetadata2)
   565  
   566  	bobTeamEK, bobErr := getTeamEK(bobMctx, teamID, expectedGeneration2)
   567  	require.NoError(t, bobErr)
   568  	require.Equal(t, bobTeamEK.Metadata, expectedMetadata2)
   569  
   570  	joeTeamEk, joeErr := getTeamEK(joeMctx, teamID, expectedGeneration2)
   571  	require.NoError(t, joeErr)
   572  	require.Equal(t, joeTeamEk.Metadata, expectedMetadata2)
   573  }
   574  
   575  func TestEphemeralRotateWithTeamEK(t *testing.T) {
   576  	runRotate(t, true /* createTeamEK*/)
   577  }
   578  
   579  func TestEphemeralRotateNoTeamEK(t *testing.T) {
   580  	runRotate(t, false /* createTeamEK*/)
   581  }
   582  
   583  func runRotate(t *testing.T, createTeamEK bool) {
   584  	tt := newTeamTester(t)
   585  	defer tt.cleanup()
   586  
   587  	ann := tt.addUser("ann")
   588  	bob := tt.addUserWithPaper("bob")
   589  
   590  	annMctx := ann.MetaContext()
   591  	err := annMctx.G().GetEKLib().KeygenIfNeeded(annMctx)
   592  	require.NoError(t, err)
   593  	bobMctx := bob.MetaContext()
   594  	err = bobMctx.G().GetEKLib().KeygenIfNeeded(bobMctx)
   595  	require.NoError(t, err)
   596  
   597  	teamID, teamName := ann.createTeam2()
   598  
   599  	// After rotate, we should have rolled the teamEK if one existed.
   600  	var expectedGeneration keybase1.EkGeneration
   601  	if createTeamEK {
   602  		ekLib := annMctx.G().GetEKLib()
   603  		teamEK, created, err := ekLib.GetOrCreateLatestTeamEK(annMctx, teamID)
   604  		require.NoError(t, err)
   605  		require.True(t, created)
   606  		expectedGeneration = teamEK.Generation() + 1
   607  	} else {
   608  		expectedGeneration = 1
   609  	}
   610  
   611  	ann.addTeamMember(teamName.String(), bob.username, keybase1.TeamRole_WRITER)
   612  
   613  	bob.revokePaperKey()
   614  	ann.waitForAnyRotateByID(teamID, keybase1.Seqno(2) /* toSeqno */, keybase1.Seqno(1) /* toHiddenSeqno */)
   615  
   616  	storage := annMctx.G().GetTeamEKBoxStorage()
   617  	teamEK, err := storage.Get(annMctx, teamID, expectedGeneration, nil)
   618  	if createTeamEK {
   619  		require.NoError(t, err)
   620  	} else {
   621  		require.Error(t, err)
   622  		require.IsType(t, ephemeral.EphemeralKeyError{}, err)
   623  		ekErr := err.(ephemeral.EphemeralKeyError)
   624  		require.Equal(t, ephemeral.DefaultHumanErrMsg, ekErr.HumanError())
   625  		require.Equal(t, keybase1.TeamEphemeralKey{}, teamEK)
   626  	}
   627  }
   628  
   629  func TestEphemeralRotateSkipTeamEKRoll(t *testing.T) {
   630  	tt := newTeamTester(t)
   631  	defer tt.cleanup()
   632  
   633  	ann := tt.addUser("ann")
   634  	bob := tt.addUserWithPaper("bob")
   635  
   636  	annMctx := ann.MetaContext()
   637  	err := annMctx.G().GetEKLib().KeygenIfNeeded(annMctx)
   638  	require.NoError(t, err)
   639  	bobMctx := bob.MetaContext()
   640  	err = bobMctx.G().GetEKLib().KeygenIfNeeded(bobMctx)
   641  	require.NoError(t, err)
   642  
   643  	teamID, teamName := ann.createTeam2()
   644  
   645  	// Get our ephemeral keys before the revoke and ensure we can still access
   646  	// them after.
   647  	ekLib := annMctx.G().GetEKLib()
   648  	teamEKPreRoll, created, err := ekLib.GetOrCreateLatestTeamEK(annMctx, teamID)
   649  	require.NoError(t, err)
   650  	require.True(t, created)
   651  
   652  	// This is a hack to skip the teamEK generation during the PTK roll.
   653  	// We want to validate that we can create a new teamEK after this roll even
   654  	// though our existing teamEK is signed by a (now) invalid PTK
   655  	annMctx.G().SetEKLib(nil)
   656  
   657  	ann.addTeamMember(teamName.String(), bob.username, keybase1.TeamRole_WRITER)
   658  
   659  	bob.revokePaperKey()
   660  	ann.waitForAnyRotateByID(teamID, keybase1.Seqno(2) /* toSeqno */, keybase1.Seqno(1) /* toHiddenSeqno */)
   661  	annMctx.G().SetEKLib(ekLib)
   662  
   663  	// Ensure that we access the old teamEK even though it was signed by a
   664  	// non-latest PTK
   665  	teamEKBoxStorage := annMctx.G().GetTeamEKBoxStorage()
   666  	teamEKBoxStorage.ClearCache()
   667  	_, err = annMctx.G().LocalDb.Nuke() // Force us to refetch and verify the key from the server
   668  	require.NoError(t, err)
   669  	teamEKPostRoll, err := teamEKBoxStorage.Get(annMctx, teamID, teamEKPreRoll.Generation(), nil)
   670  	require.NoError(t, err)
   671  	require.Equal(t, teamEKPreRoll, teamEKPostRoll)
   672  
   673  	// After rotating, ensure we can create a new TeamEK without issue.
   674  	needed, err := ekLib.NewTeamEKNeeded(annMctx, teamID)
   675  	require.NoError(t, err)
   676  	require.True(t, needed)
   677  
   678  	merkleRoot, err := annMctx.G().GetMerkleClient().FetchRootFromServer(ann.MetaContext(), libkb.EphemeralKeyMerkleFreshness)
   679  	require.NoError(t, err)
   680  	metadata, err := ephemeral.ForcePublishNewTeamEKForTesting(annMctx, teamID, *merkleRoot)
   681  	require.NoError(t, err)
   682  	require.Equal(t, teamEKPreRoll.Generation()+1, metadata.Generation)
   683  }
   684  
   685  func TestEphemeralNewUserEKAndTeamEKAfterRevokes(t *testing.T) {
   686  	tt := newTeamTester(t)
   687  	defer tt.cleanup()
   688  
   689  	ann := tt.addUserWithPaper("ann")
   690  
   691  	teamID, _ := ann.createTeam2()
   692  
   693  	annMctx := ann.MetaContext()
   694  	ekLib := annMctx.G().GetEKLib()
   695  	err := ekLib.KeygenIfNeeded(annMctx)
   696  	require.NoError(t, err)
   697  
   698  	_, created, err := ekLib.GetOrCreateLatestTeamEK(annMctx, teamID)
   699  	require.NoError(t, err)
   700  	require.True(t, created)
   701  	userEKBoxStorage := annMctx.G().GetUserEKBoxStorage()
   702  	gen, err := userEKBoxStorage.MaxGeneration(annMctx, false)
   703  	require.NoError(t, err)
   704  	userEKPreRevoke, err := userEKBoxStorage.Get(annMctx, gen, nil)
   705  	require.NoError(t, err)
   706  
   707  	// Provision a new device that we can revoke.
   708  	newDevice, cleanup := ann.provisionNewDevice()
   709  	defer cleanup()
   710  
   711  	// Revoke it.
   712  	revokeEngine := engine.NewRevokeDeviceEngine(annMctx.G(), engine.RevokeDeviceEngineArgs{
   713  		ID:        newDevice.deviceKey.DeviceID,
   714  		ForceSelf: true,
   715  		ForceLast: false,
   716  		// We don't need a UserEK here since we force generate it below
   717  		SkipUserEKForTesting: true,
   718  	})
   719  	uis := libkb.UIs{
   720  		LogUI:    annMctx.G().Log,
   721  		SecretUI: ann.newSecretUI(),
   722  	}
   723  	m := ann.MetaContext().WithUIs(uis)
   724  	err = engine.RunEngine2(m, revokeEngine)
   725  	require.NoError(t, err)
   726  
   727  	// Ensure that we access the old userEKs even though it was signed by a
   728  	// non-latest PUK
   729  	userEKBoxStorage.ClearCache()
   730  	_, err = annMctx.G().LocalDb.Nuke() // Force us to refetch and verify the key from the server
   731  	require.NoError(t, err)
   732  	userEKPostRevoke, err := userEKBoxStorage.Get(annMctx, userEKPreRevoke.Metadata.Generation, nil)
   733  	require.NoError(t, err)
   734  	require.Equal(t, userEKPreRevoke, userEKPostRevoke)
   735  
   736  	// Now provision a new userEK. This makes sure that we don't get confused
   737  	// by the revoked device's deviceEKs.
   738  	merkleRoot, err := annMctx.G().GetMerkleClient().FetchRootFromServer(annMctx, libkb.EphemeralKeyMerkleFreshness)
   739  	require.NoError(t, err)
   740  	_, err = ephemeral.ForcePublishNewUserEKForTesting(annMctx, *merkleRoot)
   741  	require.NoError(t, err)
   742  
   743  	// And do the same for the teamEK, just to be sure.
   744  	_, err = ephemeral.ForcePublishNewTeamEKForTesting(annMctx, teamID, *merkleRoot)
   745  	require.NoError(t, err)
   746  }
   747  
   748  func readdToTeamWithEKs(t *testing.T, leave bool) {
   749  	tt := newTeamTester(t)
   750  	defer tt.cleanup()
   751  
   752  	// Make standalone user that will not run gregor. This is
   753  	// important in the *leave* case, where we want to observe
   754  	// effects of team key and EK not being rotated.
   755  	user1 := makeUserStandalone(t, tt, "user1", standaloneUserArgs{
   756  		disableGregor:            true,
   757  		suppressTeamChatAnnounce: true,
   758  	})
   759  	user2 := tt.addUser("wtr")
   760  
   761  	teamID, teamName := user1.createTeam2()
   762  	user1.addTeamMember(teamName.String(), user2.username, keybase1.TeamRole_WRITER)
   763  	user2.waitForNewlyAddedToTeamByID(teamID)
   764  
   765  	mctx1 := user1.MetaContext()
   766  	ekLib := mctx1.G().GetEKLib()
   767  	err := ekLib.KeygenIfNeeded(mctx1)
   768  	require.NoError(t, err)
   769  
   770  	mctx2 := user2.MetaContext()
   771  	err = mctx2.G().GetEKLib().KeygenIfNeeded(mctx2)
   772  	require.NoError(t, err)
   773  
   774  	teamEK, created, err := ekLib.GetOrCreateLatestTeamEK(mctx1, teamID)
   775  	require.NoError(t, err)
   776  	require.True(t, created)
   777  
   778  	currentGen := teamEK.Generation()
   779  	var expectedGen keybase1.EkGeneration
   780  	if leave {
   781  		user2.leave(teamName.String())
   782  		expectedGen = currentGen // user left, no one to rotate keys.
   783  	} else {
   784  		user1.removeTeamMember(teamName.String(), user2.username)
   785  		expectedGen = currentGen + 1 // admin removes user, rotates TK and EK
   786  	}
   787  
   788  	// After leaving user2 won't have access to the current teamEK
   789  	_, err = user2.tc.G.GetTeamEKBoxStorage().Get(user2.MetaContext(), teamID, currentGen, nil)
   790  	require.Error(t, err)
   791  	require.IsType(t, libkb.AppStatusError{}, err)
   792  	appStatusErr := err.(libkb.AppStatusError)
   793  	require.Equal(t, appStatusErr.Code, libkb.SCNotFound)
   794  
   795  	user1.addTeamMember(teamName.String(), user2.username, keybase1.TeamRole_WRITER)
   796  	user2.waitForNewlyAddedToTeamByID(teamID)
   797  
   798  	// Test that user1 and user2 both have access to the currentTeamEK
   799  	// (whether we recreated or reboxed)
   800  	teamEK2U1, err := user1.tc.G.GetTeamEKBoxStorage().Get(mctx1, teamID, expectedGen, nil)
   801  	require.NoError(t, err)
   802  
   803  	teamEK2U2, err := user2.tc.G.GetTeamEKBoxStorage().Get(user2.MetaContext(), teamID, expectedGen, nil)
   804  	require.NoError(t, err)
   805  
   806  	require.Equal(t, teamEK2U1, teamEK2U2)
   807  }
   808  
   809  func TestEphemeralTeamMemberLeaveAndReadd(t *testing.T) {
   810  	readdToTeamWithEKs(t, true /* leave */)
   811  }
   812  
   813  func TestEphemeralTeamMemberRemoveAndReadd(t *testing.T) {
   814  	readdToTeamWithEKs(t, false /* leave */)
   815  }
   816  
   817  func TestEphemeralAfterEKError(t *testing.T) {
   818  	tt := newTeamTester(t)
   819  	defer tt.cleanup()
   820  
   821  	user1 := makeUserStandalone(t, tt, "user1", standaloneUserArgs{
   822  		disableGregor:            true,
   823  		suppressTeamChatAnnounce: true,
   824  	})
   825  	teamID, teamName := user1.createTeam2()
   826  	g1 := user1.tc.G
   827  	mctx1 := user1.MetaContext()
   828  	err := mctx1.G().GetEKLib().KeygenIfNeeded(mctx1)
   829  	require.NoError(t, err)
   830  	merkleRoot, err := g1.GetMerkleClient().FetchRootFromServer(mctx1, libkb.EphemeralKeyMerkleFreshness)
   831  	require.NoError(t, err)
   832  	// Force two team EKs to be created and then create/add u2 to the team.
   833  	// They should not be able to access the first key since they were added
   834  	// after (they are reboxed for the second as part of the add
   835  	teamEKMetadata1, err := ephemeral.ForcePublishNewTeamEKForTesting(mctx1, teamID, *merkleRoot)
   836  	require.NoError(t, err)
   837  	teamEKMetadata2, err := ephemeral.ForcePublishNewTeamEKForTesting(mctx1, teamID, *merkleRoot)
   838  	require.NoError(t, err)
   839  
   840  	user2 := tt.addUserWithPaper("u2")
   841  	mctx2 := user2.MetaContext()
   842  	err = mctx2.G().GetEKLib().KeygenIfNeeded(mctx2)
   843  	require.NoError(t, err)
   844  	user1.addTeamMember(teamName.String(), user2.username, keybase1.TeamRole_WRITER)
   845  	user2.waitForNewlyAddedToTeamByID(teamID)
   846  
   847  	_, err = mctx2.G().GetTeamEKBoxStorage().Get(mctx2, teamID, teamEKMetadata1.Generation, nil)
   848  	require.Error(t, err)
   849  	require.IsType(t, ephemeral.EphemeralKeyError{}, err)
   850  	ekErr := err.(ephemeral.EphemeralKeyError)
   851  	require.Equal(t, libkb.SCEphemeralMemberAfterEK, ekErr.StatusCode)
   852  
   853  	ek2, err := mctx2.G().GetTeamEKBoxStorage().Get(mctx2, teamID, teamEKMetadata2.Generation, nil)
   854  	require.NoError(t, err)
   855  	typ, err := ek2.KeyType()
   856  	require.NoError(t, err)
   857  	require.True(t, typ.IsTeam())
   858  	teamEK2 := ek2.Team()
   859  	require.Equal(t, teamEKMetadata2, teamEK2.Metadata)
   860  
   861  	// Force a second userEK so when the new device is provisioned it is only
   862  	// reboxed for the second userEK. Try to access the first userEK and fail.
   863  	userEKMetdata, err := ephemeral.ForcePublishNewUserEKForTesting(mctx2, *merkleRoot)
   864  	require.NoError(t, err)
   865  	newDevice, cleanup := user2.provisionNewDevice()
   866  	defer cleanup()
   867  	mctx2 = libkb.NewMetaContextForTest(*newDevice.tctx)
   868  
   869  	_, err = mctx2.G().GetUserEKBoxStorage().Get(mctx2, userEKMetdata.Generation-1, nil)
   870  	require.Error(t, err)
   871  	require.IsType(t, ephemeral.EphemeralKeyError{}, err)
   872  	ekErr = err.(ephemeral.EphemeralKeyError)
   873  	require.Equal(t, libkb.SCEphemeralDeviceAfterEK, ekErr.StatusCode)
   874  }