1// Copyright 2016 Keybase Inc. All rights reserved.
2// Use of this source code is governed by a BSD
3// license that can be found in the LICENSE file.
4
5package libkbfs
6
7import (
8	"bytes"
9	"fmt"
10	"reflect"
11	"runtime"
12	"strings"
13	"testing"
14	"time"
15
16	"github.com/keybase/client/go/kbfs/data"
17	"github.com/keybase/client/go/kbfs/kbfsblock"
18	"github.com/keybase/client/go/kbfs/kbfscodec"
19	"github.com/keybase/client/go/kbfs/kbfscrypto"
20	"github.com/keybase/client/go/kbfs/kbfsmd"
21	"github.com/keybase/client/go/kbfs/tlf"
22	"github.com/keybase/client/go/kbfs/tlfhandle"
23	kbname "github.com/keybase/client/go/kbun"
24	"github.com/keybase/client/go/protocol/keybase1"
25	"github.com/keybase/go-codec/codec"
26	"github.com/pkg/errors"
27	"github.com/stretchr/testify/require"
28	"golang.org/x/net/context"
29)
30
31var testMetadataVers = []kbfsmd.MetadataVer{
32	kbfsmd.InitialExtraMetadataVer, kbfsmd.ImplicitTeamsVer,
33}
34
35// runTestOverMetadataVers runs the given test function over all
36// metadata versions to test. The test is assumed to be parallelizable
37// with other instances of itself. Example use:
38//
39// func TestFoo(t *testing.T) {
40//	runTestOverMetadataVers(t, testFoo)
41// }
42//
43// func testFoo(t *testing.T, ver MetadataVer) {
44//	...
45// 	brmd, err := MakeInitialRootMetadata(ver, ...)
46//	...
47// }
48func runTestOverMetadataVers(
49	t *testing.T, f func(t *testing.T, ver kbfsmd.MetadataVer)) {
50	for _, ver := range testMetadataVers {
51		ver := ver // capture range variable.
52		t.Run(ver.String(), func(t *testing.T) {
53			f(t, ver)
54		})
55	}
56}
57
58// runTestsOverMetadataVers runs the given list of test functions over
59// all metadata versions to test. prefix should be the common prefix
60// for all the test function names, and the names of the subtest will
61// be taken to be the strings after that prefix. Example use:
62//
63// func TestFoo(t *testing.T) {
64// 	tests := []func(*testing.T, kbfsmd.MetadataVer){
65//		testFooBar1,
66//		testFooBar2,
67//		testFooBar3,
68//		...
69//	}
70//	runTestsOverMetadataVers(t, "testFoo", tests)
71// }
72func runTestsOverMetadataVers(t *testing.T, prefix string,
73	fs []func(t *testing.T, ver kbfsmd.MetadataVer)) {
74	for _, f := range fs {
75		f := f // capture range variable.
76		name := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
77		i := strings.LastIndex(name, prefix)
78		if i >= 0 {
79			i += len(prefix)
80		} else {
81			i = 0
82		}
83		name = name[i:]
84		t.Run(name, func(t *testing.T) {
85			runTestOverMetadataVers(t, f)
86		})
87	}
88}
89
90// runBenchmarkOverMetadataVers runs the given benchmark function over
91// all metadata versions to test. Example use:
92//
93// func BenchmarkFoo(b *testing.B) {
94//	runBenchmarkOverMetadataVers(b, testFoo)
95// }
96//
97// func benchmarkFoo(b *testing.B, ver kbfsmd.MetadataVer) {
98//	...
99// 	brmd, err := MakeInitialRootMetadata(ver, ...)
100//	...
101// }
102func runBenchmarkOverMetadataVers(
103	b *testing.B, f func(b *testing.B, ver kbfsmd.MetadataVer)) {
104	for _, ver := range testMetadataVers {
105		ver := ver // capture range variable.
106		b.Run(ver.String(), func(b *testing.B) {
107			f(b, ver)
108		})
109	}
110}
111
112// TODO: Add way to test with all possible (ver, maxVer) combos,
113// e.g. for upconversion tests.
114
115type privateMetadataFuture struct {
116	PrivateMetadata
117	kbfscodec.Extra
118}
119
120func (pmf privateMetadataFuture) toCurrent() PrivateMetadata {
121	pm := pmf.PrivateMetadata
122	pm.Dir = pmf.Dir
123	pm.Changes.Ops = make(opsList, len(pmf.Changes.Ops))
124	for i, opFuture := range pmf.Changes.Ops {
125		currentOp := opFuture.(kbfscodec.FutureStruct).ToCurrentStruct()
126		// A generic version of "v := currentOp; ...Ops[i] = &v".
127		v := reflect.New(reflect.TypeOf(currentOp))
128		v.Elem().Set(reflect.ValueOf(currentOp))
129		pm.Changes.Ops[i] = v.Interface().(op)
130	}
131	return pm
132}
133
134func (pmf privateMetadataFuture) ToCurrentStruct() kbfscodec.CurrentStruct {
135	return pmf.toCurrent()
136}
137
138func makeFakePrivateMetadataFuture(t *testing.T) privateMetadataFuture {
139	createOp := makeFakeCreateOpFuture(t)
140	rmOp := makeFakeRmOpFuture(t)
141	renameOp := makeFakeRenameOpFuture(t)
142	syncOp := makeFakeSyncOpFuture(t)
143	setAttrOp := makeFakeSetAttrOpFuture(t)
144	resolutionOp := makeFakeResolutionOpFuture(t)
145	rekeyOp := makeFakeRekeyOpFuture(t)
146	gcOp := makeFakeGcOpFuture(t)
147
148	pmf := privateMetadataFuture{
149		PrivateMetadata{
150			data.DirEntry{},
151			kbfscrypto.MakeTLFPrivateKey([32]byte{0xb}),
152			BlockChanges{
153				makeFakeBlockInfo(t),
154				opsList{
155					&createOp,
156					&rmOp,
157					&renameOp,
158					&syncOp,
159					&setAttrOp,
160					&resolutionOp,
161					&rekeyOp,
162					&gcOp,
163				},
164				0,
165			},
166			0,
167			codec.UnknownFieldSetHandler{},
168			BlockChanges{},
169		},
170		kbfscodec.MakeExtraOrBust("PrivateMetadata", t),
171	}
172	return pmf
173}
174
175func TestPrivateMetadataUnknownFields(t *testing.T) {
176	testStructUnknownFields(t, makeFakePrivateMetadataFuture(t))
177}
178
179// makeFakeTlfHandle should only be used in this file.
180func makeFakeTlfHandle(
181	t *testing.T, x uint32, ty tlf.Type,
182	unresolvedWriters, unresolvedReaders []keybase1.SocialAssertion) *tlfhandle.Handle {
183	id := keybase1.MakeTestUID(x).AsUserOrTeam()
184	return tlfhandle.NewHandle(
185		ty, map[keybase1.UserOrTeamID]kbname.NormalizedUsername{
186			id: "test_user",
187		}, unresolvedWriters, unresolvedReaders, "", tlf.NullID)
188}
189
190// Test that GetTlfHandle() and MakeBareTlfHandle() work properly for
191// public TLFs.
192func testRootMetadataGetTlfHandlePublic(t *testing.T, ver kbfsmd.MetadataVer) {
193	uw := []keybase1.SocialAssertion{
194		{
195			User:    "user2",
196			Service: "service3",
197		},
198		{
199			User:    "user1",
200			Service: "service1",
201		},
202	}
203	h := makeFakeTlfHandle(t, 14, tlf.Public, uw, nil)
204	tlfID := tlf.FakeID(0, tlf.Public)
205	rmd, err := makeInitialRootMetadata(ver, tlfID, h)
206	require.NoError(t, err)
207
208	dirHandle := rmd.GetTlfHandle()
209	require.Equal(t, h, dirHandle)
210
211	rmd.tlfHandle = nil
212	bh, err := rmd.MakeBareTlfHandle()
213	require.NoError(t, err)
214	require.Equal(t, h.ToBareHandleOrBust(), bh)
215}
216
217// Test that GetTlfHandle() and MakeBareTlfHandle() work properly for
218// non-public TLFs.
219func testRootMetadataGetTlfHandlePrivate(t *testing.T, ver kbfsmd.MetadataVer) {
220	uw := []keybase1.SocialAssertion{
221		{
222			User:    "user2",
223			Service: "service3",
224		},
225		{
226			User:    "user1",
227			Service: "service1",
228		},
229	}
230	ur := []keybase1.SocialAssertion{
231		{
232			User:    "user5",
233			Service: "service3",
234		},
235		{
236			User:    "user1",
237			Service: "service2",
238		},
239	}
240	h := makeFakeTlfHandle(t, 14, tlf.Private, uw, ur)
241	tlfID := tlf.FakeID(0, tlf.Private)
242	rmd, err := makeInitialRootMetadata(ver, tlfID, h)
243	require.NoError(t, err)
244
245	rmd.fakeInitialRekey()
246
247	dirHandle := rmd.GetTlfHandle()
248	require.Equal(t, h, dirHandle)
249
250	rmd.tlfHandle = nil
251	bh, err := rmd.MakeBareTlfHandle()
252	require.NoError(t, err)
253	require.Equal(t, h.ToBareHandleOrBust(), bh)
254}
255
256// Test that key generations work as expected for private TLFs.
257func testRootMetadataLatestKeyGenerationPrivate(t *testing.T, ver kbfsmd.MetadataVer) {
258	tlfID := tlf.FakeID(0, tlf.Private)
259	h := makeFakeTlfHandle(t, 14, tlf.Private, nil, nil)
260	rmd, err := makeInitialRootMetadata(ver, tlfID, h)
261	require.NoError(t, err)
262
263	if rmd.LatestKeyGeneration() != 0 {
264		t.Errorf("Expected key generation to be invalid (0)")
265	}
266	rmd.fakeInitialRekey()
267	if rmd.LatestKeyGeneration() != kbfsmd.FirstValidKeyGen {
268		t.Errorf("Expected key generation to be valid(%d)", kbfsmd.FirstValidKeyGen)
269	}
270}
271
272// Test that key generations work as expected for public TLFs.
273func testRootMetadataLatestKeyGenerationPublic(t *testing.T, ver kbfsmd.MetadataVer) {
274	tlfID := tlf.FakeID(0, tlf.Public)
275	h := makeFakeTlfHandle(t, 14, tlf.Public, nil, nil)
276	rmd, err := makeInitialRootMetadata(ver, tlfID, h)
277	require.NoError(t, err)
278
279	if rmd.LatestKeyGeneration() != kbfsmd.PublicKeyGen {
280		t.Errorf("Expected key generation to be public (%d)", kbfsmd.PublicKeyGen)
281	}
282}
283
284func testMakeRekeyReadError(t *testing.T, ver kbfsmd.MetadataVer) {
285	ctx := context.Background()
286	config := MakeTestConfigOrBust(t, "alice", "bob")
287	config.SetMetadataVersion(ver)
288	defer CheckConfigAndShutdown(ctx, t, config)
289
290	tlfID := tlf.FakeID(1, tlf.Private)
291	h := parseTlfHandleOrBust(t, config, "alice", tlf.Private, tlfID)
292	rmd, err := makeInitialRootMetadata(config.MetadataVersion(), tlfID, h)
293	require.NoError(t, err)
294
295	rmd.fakeInitialRekey()
296
297	u, id, err := config.KBPKI().Resolve(
298		ctx, "bob", keybase1.OfflineAvailability_NONE)
299	require.NoError(t, err)
300	uid, err := id.AsUser()
301	require.NoError(t, err)
302
303	dummyErr := errors.New("dummy")
304	err = makeRekeyReadErrorHelper(dummyErr, rmd.ReadOnly(), h, uid, u)
305	require.Equal(
306		t, tlfhandle.NewReadAccessError(h, u, "/keybase/private/alice"), err)
307
308	err = makeRekeyReadErrorHelper(dummyErr,
309		rmd.ReadOnly(), h, h.FirstResolvedWriter().AsUserOrBust(), "alice")
310	require.Equal(t, NeedSelfRekeyError{"alice", dummyErr}, err)
311}
312
313func testMakeRekeyReadErrorResolvedHandle(t *testing.T, ver kbfsmd.MetadataVer) {
314	ctx := context.Background()
315	config := MakeTestConfigOrBust(t, "alice", "bob")
316	defer CheckConfigAndShutdown(ctx, t, config)
317
318	tlfID := tlf.FakeID(1, tlf.Private)
319	h, err := tlfhandle.ParseHandle(
320		ctx, config.KBPKI(), config.MDOps(), nil,
321		"alice,bob@twitter", tlf.Private)
322	require.NoError(t, err)
323	rmd, err := makeInitialRootMetadata(config.MetadataVersion(), tlfID, h)
324	require.NoError(t, err)
325
326	rmd.fakeInitialRekey()
327
328	u, id, err := config.KBPKI().Resolve(
329		ctx, "bob", keybase1.OfflineAvailability_NONE)
330	require.NoError(t, err)
331	uid, err := id.AsUser()
332	require.NoError(t, err)
333
334	err = makeRekeyReadErrorHelper(errors.New("dummy"),
335		rmd.ReadOnly(), h, uid, u)
336	require.Equal(t, tlfhandle.NewReadAccessError(
337		h, u, "/keybase/private/alice,bob@twitter"), err)
338
339	config.KeybaseService().(*KeybaseDaemonLocal).AddNewAssertionForTestOrBust(
340		"bob", "bob@twitter")
341
342	resolvedHandle, err := h.ResolveAgain(ctx, config.KBPKI(), nil, nil)
343	require.NoError(t, err)
344
345	dummyErr := errors.New("dummy")
346	err = makeRekeyReadErrorHelper(dummyErr,
347		rmd.ReadOnly(), resolvedHandle, uid, u)
348	require.Equal(t, NeedOtherRekeyError{"alice,bob", dummyErr}, err)
349}
350
351// Test that MakeSuccessor fails when the final bit is set.
352
353func testRootMetadataFinalIsFinal(t *testing.T, ver kbfsmd.MetadataVer) {
354	tlfID := tlf.FakeID(0, tlf.Public)
355	h := makeFakeTlfHandle(t, 14, tlf.Public, nil, nil)
356	rmd, err := makeInitialRootMetadata(ver, tlfID, h)
357	require.NoError(t, err)
358
359	rmd.SetFinalBit()
360	_, err = rmd.MakeSuccessor(context.Background(), -1, nil, nil, nil,
361		nil, nil, kbfsmd.FakeID(1), true)
362	_, isFinalError := err.(kbfsmd.MetadataIsFinalError)
363	require.Equal(t, isFinalError, true)
364}
365
366func getAllUsersKeysForTest(
367	t *testing.T, config Config, rmd *RootMetadata, un string) []kbfscrypto.TLFCryptKey {
368	var keys []kbfscrypto.TLFCryptKey
369	for keyGen := kbfsmd.FirstValidKeyGen; keyGen <= rmd.LatestKeyGeneration(); keyGen++ {
370		key, err := config.KeyManager().(*KeyManagerStandard).getTLFCryptKeyUsingCurrentDevice(
371			context.Background(), rmd, keyGen, true)
372		require.NoError(t, err)
373		keys = append(keys, key)
374	}
375	return keys
376}
377
378// We always want misses for the tests below.
379type dummyNoKeyCache struct {
380}
381
382func (kc *dummyNoKeyCache) GetTLFCryptKey(_ tlf.ID, _ kbfsmd.KeyGen) (kbfscrypto.TLFCryptKey, error) {
383	return kbfscrypto.TLFCryptKey{}, KeyCacheMissError{}
384}
385
386func (kc *dummyNoKeyCache) PutTLFCryptKey(_ tlf.ID, _ kbfsmd.KeyGen, _ kbfscrypto.TLFCryptKey) error {
387	return nil
388}
389
390// Test upconversion from MDv2 to MDv3 for a private folder.
391func TestRootMetadataUpconversionPrivate(t *testing.T) {
392	config := MakeTestConfigOrBust(t, "alice", "bob", "charlie")
393	config.SetKeyCache(&dummyNoKeyCache{})
394	ctx := context.Background()
395	defer CheckConfigAndShutdown(ctx, t, config)
396
397	tlfID := tlf.FakeID(1, tlf.Private)
398	h := parseTlfHandleOrBust(t, config, "alice,alice@twitter#bob,charlie@twitter,eve@reddit", tlf.Private, tlfID)
399	rmd, err := makeInitialRootMetadata(kbfsmd.InitialExtraMetadataVer, tlfID, h)
400	require.NoError(t, err)
401	require.Equal(t, kbfsmd.KeyGen(0), rmd.LatestKeyGeneration())
402	require.Equal(t, kbfsmd.Revision(1), rmd.Revision())
403	require.Equal(t, kbfsmd.InitialExtraMetadataVer, rmd.Version())
404
405	// set some dummy numbers
406	diskUsage, refBytes, unrefBytes := uint64(12345), uint64(4321), uint64(1234)
407	rmd.SetDiskUsage(diskUsage)
408	rmd.SetRefBytes(refBytes)
409	rmd.SetUnrefBytes(unrefBytes)
410	// Make sure the MD looks readable.
411	rmd.data.Dir.BlockPointer = data.BlockPointer{ID: kbfsblock.FakeID(1)}
412
413	// key it once
414	done, _, err := config.KeyManager().Rekey(context.Background(), rmd, false)
415	require.NoError(t, err)
416	require.True(t, done)
417	require.Equal(t, kbfsmd.KeyGen(1), rmd.LatestKeyGeneration())
418	require.Equal(t, kbfsmd.Revision(1), rmd.Revision())
419	require.Equal(t, kbfsmd.InitialExtraMetadataVer, rmd.Version())
420	require.Equal(t, 0, len(rmd.bareMd.(*kbfsmd.RootMetadataV2).RKeys[0].TLFReaderEphemeralPublicKeys))
421	require.Equal(t, 1, len(rmd.bareMd.(*kbfsmd.RootMetadataV2).WKeys[0].TLFEphemeralPublicKeys))
422
423	// revoke bob's device
424	_, bobID, err := config.KBPKI().Resolve(
425		context.Background(), "bob", keybase1.OfflineAvailability_NONE)
426	require.NoError(t, err)
427	bobUID, err := bobID.AsUser()
428	require.NoError(t, err)
429
430	RevokeDeviceForLocalUserOrBust(t, config, bobUID, 0)
431
432	// rekey it
433	done, _, err = config.KeyManager().Rekey(context.Background(), rmd, false)
434	require.NoError(t, err)
435	require.True(t, done)
436	require.Equal(t, kbfsmd.KeyGen(2), rmd.LatestKeyGeneration())
437	require.Equal(t, kbfsmd.Revision(1), rmd.Revision())
438	require.Equal(t, kbfsmd.InitialExtraMetadataVer, rmd.Version())
439	require.Equal(t, 1, len(rmd.bareMd.(*kbfsmd.RootMetadataV2).WKeys[0].TLFEphemeralPublicKeys))
440	require.Equal(t, 0, len(rmd.bareMd.(*kbfsmd.RootMetadataV2).RKeys[0].TLFReaderEphemeralPublicKeys))
441
442	// prove charlie
443	config.KeybaseService().(*KeybaseDaemonLocal).AddNewAssertionForTestOrBust(
444		"charlie", "charlie@twitter")
445
446	// rekey it
447	done, _, err = config.KeyManager().Rekey(context.Background(), rmd, false)
448	require.NoError(t, err)
449	require.True(t, done)
450	require.Equal(t, kbfsmd.KeyGen(2), rmd.LatestKeyGeneration())
451	require.Equal(t, kbfsmd.Revision(1), rmd.Revision())
452	require.Equal(t, kbfsmd.InitialExtraMetadataVer, rmd.Version())
453	require.Equal(t, 2, len(rmd.bareMd.(*kbfsmd.RootMetadataV2).WKeys[0].TLFEphemeralPublicKeys))
454	require.Equal(t, 0, len(rmd.bareMd.(*kbfsmd.RootMetadataV2).RKeys[0].TLFReaderEphemeralPublicKeys))
455
456	// add a device for charlie and rekey as charlie
457	_, charlieID, err := config.KBPKI().Resolve(
458		context.Background(), "charlie", keybase1.OfflineAvailability_NONE)
459	require.NoError(t, err)
460	charlieUID, err := charlieID.AsUser()
461	require.NoError(t, err)
462
463	config2 := ConfigAsUser(config, "charlie")
464	config2.SetKeyCache(&dummyNoKeyCache{})
465	defer CheckConfigAndShutdown(ctx, t, config2)
466	AddDeviceForLocalUserOrBust(t, config, charlieUID)
467	AddDeviceForLocalUserOrBust(t, config2, charlieUID)
468
469	// rekey it
470	done, _, err = config2.KeyManager().Rekey(context.Background(), rmd, false)
471	require.NoError(t, err)
472	require.True(t, done)
473	require.Equal(t, kbfsmd.KeyGen(2), rmd.LatestKeyGeneration())
474	require.Equal(t, kbfsmd.Revision(1), rmd.Revision())
475	require.Equal(t, kbfsmd.InitialExtraMetadataVer, rmd.Version())
476	require.Equal(t, 2, len(rmd.bareMd.(*kbfsmd.RootMetadataV2).WKeys[0].TLFEphemeralPublicKeys))
477	require.Equal(t, 1, len(rmd.bareMd.(*kbfsmd.RootMetadataV2).RKeys[0].TLFReaderEphemeralPublicKeys))
478
479	// override the metadata version
480	config.metadataVersion = kbfsmd.SegregatedKeyBundlesVer
481
482	// create an MDv3 successor
483	rmd2, err := rmd.MakeSuccessor(context.Background(),
484		config.MetadataVersion(), config.Codec(),
485		config.KeyManager(), config.KBPKI(), config.KBPKI(), nil,
486		kbfsmd.FakeID(1), true)
487	require.NoError(t, err)
488	require.Equal(t, kbfsmd.KeyGen(2), rmd2.LatestKeyGeneration())
489	require.Equal(t, kbfsmd.Revision(2), rmd2.Revision())
490	require.Equal(t, kbfsmd.SegregatedKeyBundlesVer, rmd2.Version())
491	extra, ok := rmd2.extra.(*kbfsmd.ExtraMetadataV3)
492	require.True(t, ok)
493	require.True(t, extra.IsWriterKeyBundleNew())
494	require.True(t, extra.IsReaderKeyBundleNew())
495
496	// compare numbers
497	require.Equal(t, diskUsage, rmd2.DiskUsage())
498	require.Equal(t, rmd.data.Dir, rmd2.data.Dir)
499
500	// These should be 0 since they are reset for successors.
501	require.Equal(t, uint64(0), rmd2.RefBytes())
502	require.Equal(t, uint64(0), rmd2.UnrefBytes())
503
504	// create and compare bare tlf handles (this verifies unresolved+resolved writer/reader sets are identical)
505	rmd.tlfHandle, rmd2.tlfHandle = nil, nil // avoid a panic due to the handle already existing
506	handle, err := rmd.MakeBareTlfHandle()
507	require.NoError(t, err)
508	handle2, err := rmd2.MakeBareTlfHandle()
509	require.NoError(t, err)
510	require.Equal(t, handle, handle2)
511
512	// compare tlf crypt keys
513	keys, err := config.KeyManager().GetTLFCryptKeyOfAllGenerations(context.Background(), rmd)
514	require.NoError(t, err)
515	require.Equal(t, 2, len(keys))
516
517	keys2, err := config.KeyManager().GetTLFCryptKeyOfAllGenerations(context.Background(), rmd2)
518	require.NoError(t, err)
519	require.Equal(t, 2, len(keys2))
520	require.Equal(t, keys, keys2)
521
522	// get each key generation for alice from each version of metadata
523	aliceKeys := getAllUsersKeysForTest(t, config, rmd, "alice")
524	aliceKeys2 := getAllUsersKeysForTest(t, config, rmd2, "alice")
525
526	// compare alice's keys
527	require.Equal(t, 2, len(aliceKeys))
528	require.Equal(t, aliceKeys, aliceKeys2)
529
530	// get each key generation for charlie from each version of metadata
531	charlieKeys := getAllUsersKeysForTest(t, config2, rmd, "charlie")
532	charlieKeys2 := getAllUsersKeysForTest(t, config2, rmd2, "charlie")
533
534	// compare charlie's keys
535	require.Equal(t, 2, len(charlieKeys))
536	require.Equal(t, charlieKeys, charlieKeys2)
537
538	// compare alice and charlie's keys
539	require.Equal(t, aliceKeys, charlieKeys)
540
541	// Rekeying again shouldn't change wkbNew/rkbNew.
542	err = rmd2.finalizeRekey(config.Codec())
543	require.NoError(t, err)
544	extra, ok = rmd2.extra.(*kbfsmd.ExtraMetadataV3)
545	require.True(t, ok)
546	require.True(t, extra.IsWriterKeyBundleNew())
547	require.True(t, extra.IsReaderKeyBundleNew())
548}
549
550// Test upconversion from MDv2 to MDv3 for a public folder.
551func TestRootMetadataUpconversionPublic(t *testing.T) {
552	ctx := context.Background()
553	config := MakeTestConfigOrBust(t, "alice", "bob")
554	defer CheckConfigAndShutdown(ctx, t, config)
555
556	tlfID := tlf.FakeID(1, tlf.Public)
557	h := parseTlfHandleOrBust(
558		t, config, "alice,bob,charlie@twitter", tlf.Public, tlfID)
559	rmd, err := makeInitialRootMetadata(kbfsmd.InitialExtraMetadataVer, tlfID, h)
560	require.NoError(t, err)
561	require.Equal(t, kbfsmd.PublicKeyGen, rmd.LatestKeyGeneration())
562	require.Equal(t, kbfsmd.Revision(1), rmd.Revision())
563	require.Equal(t, kbfsmd.InitialExtraMetadataVer, rmd.Version())
564
565	// set some dummy numbers
566	diskUsage, refBytes, unrefBytes := uint64(12345), uint64(4321), uint64(1234)
567	rmd.SetDiskUsage(diskUsage)
568	rmd.SetRefBytes(refBytes)
569	rmd.SetUnrefBytes(unrefBytes)
570
571	// override the metadata version
572	config.metadataVersion = kbfsmd.SegregatedKeyBundlesVer
573
574	// create an MDv3 successor
575	rmd2, err := rmd.MakeSuccessor(context.Background(),
576		config.MetadataVersion(), config.Codec(),
577		config.KeyManager(), config.KBPKI(), config.KBPKI(), config,
578		kbfsmd.FakeID(1), true)
579	require.NoError(t, err)
580	require.Equal(t, kbfsmd.PublicKeyGen, rmd2.LatestKeyGeneration())
581	require.Equal(t, kbfsmd.Revision(2), rmd2.Revision())
582	require.Equal(t, kbfsmd.SegregatedKeyBundlesVer, rmd2.Version())
583	// Do this instead of require.Nil because we want to assert
584	// that it's untyped nil.
585	require.True(t, rmd2.extra == nil)
586
587	// compare numbers
588	require.Equal(t, diskUsage, rmd2.DiskUsage())
589	// we expect this and the below to be zero this time because the folder is public.
590	// they aren't reset in the private version because the private metadata isn't
591	// initialized therefor it's considered unreadable.
592	require.Equal(t, uint64(0), rmd2.RefBytes())
593	require.Equal(t, uint64(0), rmd2.UnrefBytes())
594
595	// create and compare bare tlf handles (this verifies unresolved+resolved writer sets are identical)
596	rmd.tlfHandle, rmd2.tlfHandle = nil, nil // avoid a panic due to the handle already existing
597	handle, err := rmd.MakeBareTlfHandle()
598	require.NoError(t, err)
599	handle2, err := rmd2.MakeBareTlfHandle()
600	require.NoError(t, err)
601	require.Equal(t, handle, handle2)
602}
603
604// Test upconversion from MDv2 to MDv3 for a private conflict folder.
605// Regression test for KBFS-2381.
606func TestRootMetadataUpconversionPrivateConflict(t *testing.T) {
607	ctx := context.Background()
608	config := MakeTestConfigOrBust(t, "alice", "bob")
609	defer CheckConfigAndShutdown(ctx, t, config)
610
611	tlfID := tlf.FakeID(1, tlf.Private)
612	h := parseTlfHandleOrBust(
613		t, config, "alice,bob (conflicted copy 2017-08-24)", tlf.Private, tlfID)
614	rmd, err := makeInitialRootMetadata(kbfsmd.InitialExtraMetadataVer, tlfID, h)
615	require.NoError(t, err)
616	require.Equal(t, kbfsmd.KeyGen(0), rmd.LatestKeyGeneration())
617	require.Equal(t, kbfsmd.Revision(1), rmd.Revision())
618	require.Equal(t, kbfsmd.InitialExtraMetadataVer, rmd.Version())
619	require.NotNil(t, h.ConflictInfo())
620
621	// set some dummy numbers
622	diskUsage, refBytes, unrefBytes :=
623		uint64(12345), uint64(4321), uint64(1234)
624	rmd.SetDiskUsage(diskUsage)
625	rmd.SetRefBytes(refBytes)
626	rmd.SetUnrefBytes(unrefBytes)
627	// Make sure the MD looks readable.
628	rmd.data.Dir.BlockPointer = data.BlockPointer{ID: kbfsblock.FakeID(1)}
629
630	// key it once
631	done, _, err := config.KeyManager().Rekey(context.Background(), rmd, false)
632	require.NoError(t, err)
633	require.True(t, done)
634	require.Equal(t, kbfsmd.KeyGen(1), rmd.LatestKeyGeneration())
635	require.Equal(t, kbfsmd.Revision(1), rmd.Revision())
636	require.Equal(t, kbfsmd.InitialExtraMetadataVer, rmd.Version())
637	require.Equal(t, 0, len(rmd.bareMd.(*kbfsmd.RootMetadataV2).RKeys[0].TLFReaderEphemeralPublicKeys))
638	require.Equal(t, 1, len(rmd.bareMd.(*kbfsmd.RootMetadataV2).WKeys[0].TLFEphemeralPublicKeys))
639	require.True(t, rmd.IsReadable())
640
641	// override the metadata version
642	config.metadataVersion = kbfsmd.SegregatedKeyBundlesVer
643
644	// create an MDv3 successor
645	rmd2, err := rmd.MakeSuccessor(context.Background(),
646		config.MetadataVersion(), config.Codec(),
647		config.KeyManager(), config.KBPKI(), config.KBPKI(), config,
648		kbfsmd.FakeID(1), true)
649	require.NoError(t, err)
650	require.Equal(t, kbfsmd.KeyGen(1), rmd2.LatestKeyGeneration())
651	require.Equal(t, kbfsmd.Revision(2), rmd2.Revision())
652	require.Equal(t, kbfsmd.SegregatedKeyBundlesVer, rmd2.Version())
653	extra, ok := rmd2.extra.(*kbfsmd.ExtraMetadataV3)
654	require.True(t, ok)
655	require.True(t, extra.IsWriterKeyBundleNew())
656	require.True(t, extra.IsReaderKeyBundleNew())
657
658	// Check the handle, but the cached handle in the MD is a direct copy...
659	require.Equal(
660		t, h.GetCanonicalPath(), rmd2.GetTlfHandle().GetCanonicalPath())
661	// So also check that the conflict info is set in the MD itself.
662	require.NotNil(t, rmd2.bareMd.(*kbfsmd.RootMetadataV3).ConflictInfo)
663}
664
665// The server will be reusing IsLastModifiedBy and we don't want a client
666// to be able to construct an MD that will crash the server.
667func TestRootMetadataV3NoPanicOnWriterMismatch(t *testing.T) {
668	ctx := context.Background()
669	config := MakeTestConfigOrBust(t, "alice", "bob")
670	defer CheckConfigAndShutdown(ctx, t, config)
671
672	_, id, err := config.KBPKI().Resolve(
673		context.Background(), "alice", keybase1.OfflineAvailability_NONE)
674	require.NoError(t, err)
675	uid, err := id.AsUser()
676	require.NoError(t, err)
677
678	tlfID := tlf.FakeID(0, tlf.Private)
679	h := makeFakeTlfHandle(t, 14, tlf.Private, nil, nil)
680	rmd, err := makeInitialRootMetadata(kbfsmd.SegregatedKeyBundlesVer, tlfID, h)
681	require.NoError(t, err)
682	rmd.fakeInitialRekey()
683	rmd.SetLastModifyingWriter(uid)
684	rmd.SetLastModifyingUser(uid)
685
686	// sign with a mismatched writer
687	config2 := ConfigAsUser(config, "bob")
688	defer CheckConfigAndShutdown(ctx, t, config2)
689	rmds, err := SignBareRootMetadata(
690		context.Background(), config.Codec(), config.Crypto(), config2.Crypto(), rmd.bareMd, time.Now())
691	require.NoError(t, err)
692
693	// verify last modifier
694	session, err := config.KBPKI().GetCurrentSession(context.Background())
695	require.NoError(t, err)
696	session2, err := config2.KBPKI().GetCurrentSession(context.Background())
697	require.NoError(t, err)
698
699	err = rmds.IsLastModifiedBy(uid, session.VerifyingKey)
700	require.EqualError(t, err, fmt.Sprintf("Last writer verifying key %s != %s", session2.VerifyingKey, session.VerifyingKey))
701}
702
703// Test that a reader can't upconvert a private folder from v2 to v3.
704func TestRootMetadataReaderUpconversionPrivate(t *testing.T) {
705	ctx := context.Background()
706	configWriter := MakeTestConfigOrBust(t, "alice", "bob")
707	configWriter.SetKeyCache(&dummyNoKeyCache{})
708	defer CheckConfigAndShutdown(ctx, t, configWriter)
709
710	tlfID := tlf.FakeID(1, tlf.Private)
711	h := parseTlfHandleOrBust(t, configWriter, "alice#bob", tlf.Private, tlfID)
712	rmd, err := makeInitialRootMetadata(kbfsmd.InitialExtraMetadataVer, tlfID, h)
713	require.NoError(t, err)
714	require.Equal(t, kbfsmd.KeyGen(0), rmd.LatestKeyGeneration())
715	require.Equal(t, kbfsmd.Revision(1), rmd.Revision())
716	require.Equal(t, kbfsmd.PreExtraMetadataVer, rmd.Version())
717
718	// set some dummy numbers
719	diskUsage, refBytes, unrefBytes := uint64(12345), uint64(4321), uint64(1234)
720	rmd.SetDiskUsage(diskUsage)
721	rmd.SetRefBytes(refBytes)
722	rmd.SetUnrefBytes(unrefBytes)
723
724	// Have the writer key it first.
725	done, _, err := configWriter.KeyManager().Rekey(
726		context.Background(), rmd, false)
727	require.NoError(t, err)
728	require.True(t, done)
729	require.Equal(t, kbfsmd.KeyGen(1), rmd.LatestKeyGeneration())
730	require.Equal(t, kbfsmd.Revision(1), rmd.Revision())
731	require.Equal(t, kbfsmd.PreExtraMetadataVer, rmd.Version())
732	require.Equal(t, 1, len(rmd.bareMd.(*kbfsmd.RootMetadataV2).WKeys[0].TLFEphemeralPublicKeys))
733	require.Equal(t, 0, len(rmd.bareMd.(*kbfsmd.RootMetadataV2).RKeys[0].TLFReaderEphemeralPublicKeys))
734
735	// Set the private MD, to make sure it gets copied properly during
736	// upconversion.
737	_, aliceID, err := configWriter.KBPKI().Resolve(
738		context.Background(), "alice", keybase1.OfflineAvailability_NONE)
739	require.NoError(t, err)
740	aliceUID, err := aliceID.AsUser()
741	require.NoError(t, err)
742
743	err = encryptMDPrivateData(context.Background(), configWriter.Codec(),
744		configWriter.Crypto(), configWriter.Crypto(),
745		configWriter.KeyManager(), aliceUID, rmd)
746	require.NoError(t, err)
747
748	// add a device for bob and rekey as bob
749	_, bobID, err := configWriter.KBPKI().Resolve(
750		context.Background(), "bob", keybase1.OfflineAvailability_NONE)
751	require.NoError(t, err)
752	bobUID, err := bobID.AsUser()
753	require.NoError(t, err)
754
755	configReader := ConfigAsUser(configWriter, "bob")
756	configReader.SetKeyCache(&dummyNoKeyCache{})
757	defer CheckConfigAndShutdown(ctx, t, configReader)
758	AddDeviceForLocalUserOrBust(t, configWriter, bobUID)
759	AddDeviceForLocalUserOrBust(t, configReader, bobUID)
760
761	// Override the metadata version, make a successor, and rekey as
762	// reader.  This should keep the version the same, since readers
763	// can't upconvert.
764	configReader.metadataVersion = kbfsmd.SegregatedKeyBundlesVer
765	rmd2, err := rmd.MakeSuccessor(context.Background(),
766		configReader.MetadataVersion(), configReader.Codec(),
767		configReader.KeyManager(), configReader.KBPKI(),
768		configReader.KBPKI(), configReader, kbfsmd.FakeID(1), false)
769	require.NoError(t, err)
770	require.Equal(t, kbfsmd.KeyGen(1), rmd2.LatestKeyGeneration())
771	require.Equal(t, kbfsmd.Revision(2), rmd2.Revision())
772	require.Equal(t, kbfsmd.PreExtraMetadataVer, rmd2.Version())
773	// Do this instead of require.Nil because we want to assert
774	// that it's untyped nil.
775	require.True(t, rmd2.extra == nil)
776	done, _, err = configReader.KeyManager().Rekey(
777		context.Background(), rmd2, false)
778	require.NoError(t, err)
779	require.True(t, done)
780	require.Equal(t, kbfsmd.KeyGen(1), rmd2.LatestKeyGeneration())
781	require.Equal(t, kbfsmd.Revision(2), rmd2.Revision())
782	require.Equal(t, kbfsmd.PreExtraMetadataVer, rmd2.Version())
783	require.True(t, rmd2.IsWriterMetadataCopiedSet())
784	require.True(t, bytes.Equal(rmd.GetSerializedPrivateMetadata(),
785		rmd2.GetSerializedPrivateMetadata()))
786
787	rmds, err := SignBareRootMetadata(context.Background(),
788		configReader.Codec(), configReader.Crypto(), configReader.Crypto(),
789		rmd2.bareMd, configReader.Clock().Now())
790	require.NoError(t, err)
791	err = rmds.IsValidAndSigned(
792		ctx, configReader.Codec(), nil, rmd2.extra,
793		keybase1.OfflineAvailability_NONE)
794	require.NoError(t, err)
795}
796
797// Check writer/reader methods with teams
798func TestRootMetadataTeamMembership(t *testing.T) {
799	config := MakeTestConfigOrBust(t, "alice", "bob", "charlie")
800	ctx := context.Background()
801	defer CheckConfigAndShutdown(ctx, t, config)
802
803	teamInfos := AddEmptyTeamsForTestOrBust(t, config, "t1")
804	tid := teamInfos[0].TID
805
806	tlfID := tlf.FakeID(1, tlf.SingleTeam)
807	h := tlfhandle.NewHandle(
808		tlf.SingleTeam,
809		map[keybase1.UserOrTeamID]kbname.NormalizedUsername{
810			tid.AsUserOrTeam(): "t1",
811		}, nil, nil, "t1", tlf.NullID)
812	rmd, err := makeInitialRootMetadata(kbfsmd.InitialExtraMetadataVer, tlfID, h)
813	require.NoError(t, err)
814
815	getUser := func(name string) (keybase1.UID, kbfscrypto.VerifyingKey) {
816		_, id, err := config.KBPKI().Resolve(
817			context.Background(), name, keybase1.OfflineAvailability_NONE)
818		require.NoError(t, err)
819		uid, err := id.AsUser()
820		require.NoError(t, err)
821
822		userInfo, err := config.KeybaseService().LoadUserPlusKeys(
823			context.Background(), uid, keybase1.KID(""),
824			keybase1.OfflineAvailability_NONE)
825		require.NoError(t, err)
826
827		return uid, userInfo.VerifyingKeys[0]
828	}
829	aliceUID, aliceKey := getUser("alice")
830	bobUID, bobKey := getUser("bob")
831	charlieUID, charlieKey := getUser("charlie")
832
833	// No user should be able to read this yet.
834	checkWriter := func(uid keybase1.UID, key kbfscrypto.VerifyingKey,
835		expectedIsWriter bool) {
836		isWriter, err := rmd.IsWriter(ctx, config.KBPKI(), config, uid, key)
837		require.NoError(t, err)
838		require.Equal(t, expectedIsWriter, isWriter)
839	}
840	checkReader := func(uid keybase1.UID, expectedIsReader bool) {
841		isReader, err := rmd.IsReader(ctx, config.KBPKI(), config, uid)
842		require.NoError(t, err)
843		require.Equal(t, expectedIsReader, isReader)
844	}
845	checkWriter(aliceUID, aliceKey, false)
846	checkWriter(bobUID, bobKey, false)
847	checkWriter(charlieUID, charlieKey, false)
848	checkReader(aliceUID, false)
849	checkReader(bobUID, false)
850	checkReader(charlieUID, false)
851
852	// Make bob a writer.
853	AddTeamWriterForTestOrBust(t, config, tid, bobUID)
854	checkWriter(aliceUID, aliceKey, false)
855	checkWriter(bobUID, bobKey, true)
856	checkWriter(charlieUID, charlieKey, false)
857	checkReader(aliceUID, false)
858	checkReader(bobUID, true)
859	checkReader(charlieUID, false)
860
861	// Make alice a writer, and charlie a reader.
862	AddTeamWriterForTestOrBust(t, config, tid, aliceUID)
863	AddTeamReaderForTestOrBust(t, config, tid, charlieUID)
864	checkWriter(aliceUID, aliceKey, true)
865	checkWriter(bobUID, bobKey, true)
866	checkWriter(charlieUID, charlieKey, false)
867	checkReader(aliceUID, true)
868	checkReader(bobUID, true)
869	checkReader(charlieUID, true)
870
871	// Promote charlie to writer.
872	AddTeamWriterForTestOrBust(t, config, tid, charlieUID)
873	checkWriter(aliceUID, aliceKey, true)
874	checkWriter(bobUID, bobKey, true)
875	checkWriter(charlieUID, charlieKey, true)
876	checkReader(aliceUID, true)
877	checkReader(bobUID, true)
878	checkReader(charlieUID, true)
879}
880
881// Check that MakeSuccessor gets the right key gen for teams.
882func TestRootMetadataTeamMakeSuccessor(t *testing.T) {
883	config := MakeTestConfigOrBust(t, "alice")
884	ctx := context.Background()
885	defer CheckConfigAndShutdown(ctx, t, config)
886
887	teamInfos := AddEmptyTeamsForTestOrBust(t, config, "t1")
888	tid := teamInfos[0].TID
889
890	tlfID := tlf.FakeID(1, tlf.SingleTeam)
891	h := tlfhandle.NewHandle(
892		tlf.SingleTeam,
893		map[keybase1.UserOrTeamID]kbname.NormalizedUsername{
894			tid.AsUserOrTeam(): "t1",
895		}, nil, nil, "t1", tlf.NullID)
896	rmd, err := makeInitialRootMetadata(kbfsmd.SegregatedKeyBundlesVer, tlfID, h)
897	require.NoError(t, err)
898	rmd.bareMd.SetLatestKeyGenerationForTeamTLF(teamInfos[0].LatestKeyGen)
899	// Make sure the MD looks readable.
900	rmd.data.Dir.BlockPointer = data.BlockPointer{ID: kbfsblock.FakeID(1)}
901
902	firstKeyGen := rmd.LatestKeyGeneration()
903	require.Equal(t, kbfsmd.FirstValidKeyGen, firstKeyGen)
904
905	rmd2, err := rmd.MakeSuccessor(context.Background(),
906		config.MetadataVersion(), config.Codec(),
907		config.KeyManager(), config.KBPKI(), config.KBPKI(), config,
908		kbfsmd.FakeID(1), true)
909	require.NoError(t, err)
910
911	// No increase yet.
912	kg := rmd2.LatestKeyGeneration()
913	require.Equal(t, firstKeyGen, kg)
914
915	AddTeamKeyForTestOrBust(t, config, tid)
916
917	rmd3, err := rmd2.MakeSuccessor(context.Background(),
918		config.MetadataVersion(), config.Codec(),
919		config.KeyManager(), config.KBPKI(), config.KBPKI(), config,
920		kbfsmd.FakeID(2), true)
921	require.NoError(t, err)
922
923	// Should have been bumped by one.
924	kg = rmd3.LatestKeyGeneration()
925	require.Equal(t, firstKeyGen+1, kg)
926}
927
928func TestRootMetadata(t *testing.T) {
929	tests := []func(*testing.T, kbfsmd.MetadataVer){
930		testRootMetadataGetTlfHandlePublic,
931		testRootMetadataGetTlfHandlePrivate,
932		testRootMetadataLatestKeyGenerationPrivate,
933		testRootMetadataLatestKeyGenerationPublic,
934		testMakeRekeyReadError,
935		testMakeRekeyReadErrorResolvedHandle,
936		testRootMetadataFinalIsFinal,
937	}
938	runTestsOverMetadataVers(t, "testRootMetadata", tests)
939}
940