1// Copyright 2016 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4// There are two test files by this name. One in libkb, one in engine.
5
6package libkb
7
8import (
9	"testing"
10	"time"
11
12	context "golang.org/x/net/context"
13
14	keybase1 "github.com/keybase/client/go/protocol/keybase1"
15	"github.com/keybase/clockwork"
16	"github.com/stretchr/testify/require"
17)
18
19func TestCachedUserLoad(t *testing.T) {
20	tc := SetupTest(t, "GetUPAKLoader()", 1)
21	defer tc.Cleanup()
22
23	fakeClock := clockwork.NewFakeClock()
24	tc.G.SetClock(fakeClock)
25
26	// Load t_alice a few different ways
27	arg := NewLoadUserArg(tc.G).WithUID(keybase1.UID("295a7eea607af32040647123732bc819"))
28	var info CachedUserLoadInfo
29	_, _, err := tc.G.GetUPAKLoader().(*CachedUPAKLoader).loadWithInfo(arg, &info, nil, true)
30	if err != nil {
31		t.Fatal(err)
32	}
33
34	checkLoad := func(upk *keybase1.UserPlusKeysV2AllIncarnations, err error) {
35		if err != nil {
36			t.Fatal(err)
37		}
38		if upk == nil {
39			t.Fatal("expected a UPK back")
40		}
41		if upk.Current.Username != "t_alice" {
42			t.Fatalf("expected %s but got %s", "t_alice", upk.Current.Username)
43		}
44	}
45	if info.InCache || info.TimedOut || info.StaleVersion || info.LoadedLeaf || !info.LoadedUser {
46		t.Fatalf("wrong info: %+v", info)
47	}
48
49	fakeClock.Advance(CachedUserTimeout / 100)
50	info = CachedUserLoadInfo{}
51	upk, user, err := tc.G.GetUPAKLoader().(*CachedUPAKLoader).loadWithInfo(arg, &info, nil, true)
52	checkLoad(upk, err)
53	if user != nil {
54		t.Fatal("expected no full user load")
55	}
56
57	if !info.InCache || info.TimedOut || info.StaleVersion || info.LoadedLeaf || info.LoadedUser {
58		t.Fatalf("wrong info: %+v", info)
59	}
60
61	fakeClock.Advance(2 * CachedUserTimeout)
62	info = CachedUserLoadInfo{}
63	upk, user, err = tc.G.GetUPAKLoader().(*CachedUPAKLoader).loadWithInfo(arg, &info, nil, true)
64	checkLoad(upk, err)
65	if user != nil {
66		t.Fatal("expected no full user load")
67	}
68	if !info.InCache || !info.TimedOut || info.StaleVersion || !info.LoadedLeaf || info.LoadedUser {
69		t.Fatalf("wrong info: %+v", info)
70	}
71
72	require.True(t, IsUserByUsernameOffline(NewMetaContextForTest(tc), "t_alice"))
73	require.False(t, IsUserByUsernameOffline(NewMetaContextForTest(tc), "t_alice_xxx"))
74	// This hardcoded user was put into the TestUIDMapper, so it should return a result
75	require.True(t, IsUserByUsernameOffline(NewMetaContextForTest(tc), "max"))
76}
77
78func TestCheckKIDForUID(t *testing.T) {
79	tc := SetupTest(t, "CheckKIDForUID", 1)
80	defer tc.Cleanup()
81
82	fakeClock := clockwork.NewFakeClock()
83	tc.G.SetClock(fakeClock)
84
85	georgeUID := keybase1.UID("9f9611a4b7920637b1c2a839b2a0e119")
86	georgeKIDSibkey := keybase1.KID("01206f31b54690a95a1a60a0d8861c8ec27c322b49a93b475a631ee6a676018bfd140a")
87	georgeKIDSubkey := keybase1.KID("0121d6543b431d9d3b7485cf23fd6d9fa719bbc2429141dcc44b94ebf4093c37aa5b0a")
88
89	// The 't_kb' user's Sibkey for device named 'Computer'
90	kbKIDSibkey := keybase1.KID("0120d2156264b9023ca1828a57e6e925cbb48f80e8e701fe036b1dfd50337d10d6db0a")
91
92	rebeccaUID := keybase1.UID("99337e411d1004050e9e7ee2cf1a6219")
93	rebeccaKIDRevoked := keybase1.KID("0120e177772304cd9ec833ceb88eeb6e32a667151d9e4fb09df433a846d05e6c40350a")
94
95	found, revokedAt, deleted, err := tc.G.GetUPAKLoader().CheckKIDForUID(context.Background(), georgeUID, georgeKIDSibkey)
96	if !found || (revokedAt != nil) || deleted || (err != nil) {
97		t.Fatalf("bad CheckKIDForUID response")
98	}
99	found, revokedAt, deleted, err = tc.G.GetUPAKLoader().CheckKIDForUID(context.Background(), georgeUID, georgeKIDSubkey)
100	if !found || (revokedAt != nil) || deleted || (err != nil) {
101		t.Fatalf("bad CheckKIDForUID response")
102	}
103	found, revokedAt, deleted, err = tc.G.GetUPAKLoader().CheckKIDForUID(context.Background(), georgeUID, kbKIDSibkey)
104	if found || (revokedAt != nil) || deleted || (err != nil) {
105		t.Fatalf("bad CheckKIDForUID response")
106	}
107
108	found, revokedAt, deleted, err = tc.G.GetUPAKLoader().CheckKIDForUID(context.Background(), rebeccaUID, rebeccaKIDRevoked)
109	if !found || (revokedAt == nil) || deleted || (err != nil) {
110		t.Fatalf("bad CheckKIDForUID response")
111	}
112}
113
114func TestCacheFallbacks(t *testing.T) {
115	tc := SetupTest(t, "LookupUsernameAndDevice", 1)
116	defer tc.Cleanup()
117
118	fakeClock := clockwork.NewFakeClock()
119	tc.G.SetClock(fakeClock)
120
121	test := func() *CachedUserLoadInfo {
122		var ret CachedUserLoadInfo
123		uid := keybase1.UID("eb72f49f2dde6429e5d78003dae0c919")
124		arg := NewLoadUserArg(tc.G).WithUID(uid)
125		upk, _, err := tc.G.GetUPAKLoader().(*CachedUPAKLoader).loadWithInfo(arg, &ret, nil, false)
126		require.NoError(t, err)
127		require.Equal(t, upk.Current.Username, "t_tracy", "tracy was right")
128		return &ret
129	}
130	i := test()
131	require.True(t, (!i.InCache && !i.InDiskCache && !i.TimedOut && !i.StaleVersion && !i.LoadedLeaf && i.LoadedUser))
132	i = test()
133	require.True(t, (i.InCache && !i.InDiskCache && !i.TimedOut && !i.StaleVersion && !i.LoadedLeaf && !i.LoadedUser))
134	tc.G.GetUPAKLoader().ClearMemory()
135	i = test()
136	require.True(t, (!i.InCache && i.InDiskCache && !i.TimedOut && !i.StaleVersion && !i.LoadedLeaf && !i.LoadedUser))
137	i = test()
138	require.True(t, (i.InCache && !i.InDiskCache && !i.TimedOut && !i.StaleVersion && !i.LoadedLeaf && !i.LoadedUser))
139	fakeClock.Advance(10 * time.Hour)
140	i = test()
141	require.True(t, (i.InCache && !i.InDiskCache && i.TimedOut && !i.StaleVersion && i.LoadedLeaf && !i.LoadedUser))
142	tc.G.GetUPAKLoader().ClearMemory()
143	i = test()
144	require.True(t, (!i.InCache && i.InDiskCache && !i.TimedOut && !i.StaleVersion && !i.LoadedLeaf && !i.LoadedUser))
145}
146
147func TestLookupUsernameAndDevice(t *testing.T) {
148	tc := SetupTest(t, "LookupUsernameAndDevice", 1)
149	defer tc.Cleanup()
150
151	fakeClock := clockwork.NewFakeClock()
152	tc.G.SetClock(fakeClock)
153
154	test := func() {
155		uid := keybase1.UID("eb72f49f2dde6429e5d78003dae0c919")
156		did := keybase1.DeviceID("e5f7f7ca6b6277de4d2c45f57b767f18")
157		un, name, typ, err := tc.G.GetUPAKLoader().LookupUsernameAndDevice(context.Background(), uid, did)
158		require.NoError(t, err)
159		require.Equal(t, un.String(), "t_tracy", "tracy was right")
160		require.Equal(t, name, "work", "right device name")
161		require.Equal(t, typ, keybase1.DeviceTypeV2_DESKTOP, "right type")
162	}
163
164	for i := 0; i < 2; i++ {
165		test()
166		test()
167		fakeClock.Advance(10 * time.Hour)
168		test()
169		test()
170		tc.G.GetUPAKLoader().ClearMemory()
171	}
172}
173
174func TestLookupUID(t *testing.T) {
175	tc := SetupTest(t, "LookupUsernameAndDevice", 1)
176	defer tc.Cleanup()
177
178	fakeClock := clockwork.NewFakeClock()
179	tc.G.SetClock(fakeClock)
180
181	test := func() {
182		uid := keybase1.UID("eb72f49f2dde6429e5d78003dae0c919")
183		un := NewNormalizedUsername("t_tracy")
184		uid2, err := tc.G.GetUPAKLoader().LookupUID(context.Background(), un)
185		require.NoError(t, err)
186		require.Equal(t, uid, uid2)
187	}
188
189	for i := 0; i < 2; i++ {
190		test()
191		test()
192		fakeClock.Advance(10 * time.Hour)
193		test()
194		test()
195		tc.G.GetUPAKLoader().ClearMemory()
196	}
197}
198
199func TestLookupUsername(t *testing.T) {
200	tc := SetupTest(t, "LookupUsernameAndDevice", 1)
201	defer tc.Cleanup()
202
203	uid := keybase1.UID("eb72f49f2dde6429e5d78003dae0c919")
204	un, err := tc.G.GetUPAKLoader().LookupUsername(context.Background(), uid)
205	require.NoError(t, err)
206	require.Equal(t, un, NewNormalizedUsername("t_tracy"), "tracy came back")
207	badUID := keybase1.UID("eb72f49f2dde6429e5d78003dae0b919")
208	_, err = tc.G.GetUPAKLoader().LookupUsername(context.Background(), badUID)
209	require.Error(t, err)
210}
211
212func TestLoadUPAK2(t *testing.T) {
213	tc := SetupTest(t, "LookupUsernameAndDevice", 1)
214	defer tc.Cleanup()
215
216	load := func() {
217		uid := keybase1.UID("eb72f49f2dde6429e5d78003dae0c919")
218		upak, _, err := tc.G.GetUPAKLoader().LoadV2(NewLoadUserByUIDArg(context.TODO(), tc.G, uid))
219		require.NoError(t, err)
220		key, ok := upak.Current.DeviceKeys[keybase1.KID("01204fbb0a8ee105c2732155bffd927a6f612b6a36c63c484e6290f6a7ac560a1a780a")]
221		require.True(t, ok)
222		require.Equal(t, key.Base.Provisioning.SigChainLocation.Seqno, keybase1.Seqno(3))
223		require.Equal(t, key.Base.Provisioning.SigChainLocation.SeqType, keybase1.SeqType_PUBLIC)
224		require.Nil(t, key.Base.Revocation)
225	}
226
227	load()
228	load()
229}
230