1package engine
2
3import (
4	"os"
5	"testing"
6	"time"
7
8	"golang.org/x/net/context"
9
10	"github.com/keybase/client/go/libkb"
11	"github.com/keybase/clockwork"
12	"github.com/stretchr/testify/require"
13)
14
15func TestLoginOffline(t *testing.T) {
16	tc := SetupEngineTest(t, "login")
17	defer tc.Cleanup()
18
19	u1 := CreateAndSignupFakeUser(tc, "login")
20	Logout(tc)
21	u1.LoginOrBust(tc)
22
23	// do a upak load to make sure it is cached
24	arg := libkb.NewLoadUserByUIDArg(context.TODO(), tc.G, u1.UID())
25	_, _, err := tc.G.GetUPAKLoader().Load(arg)
26	require.NoError(t, err)
27
28	// Simulate restarting the service by wiping out the
29	// passphrase stream cache and cached secret keys
30	clearCaches(tc.G)
31	tc.G.GetUPAKLoader().ClearMemory()
32
33	// set server uri to nonexistent ip so api calls will fail
34	prev := os.Getenv("KEYBASE_SERVER_URI")
35	os.Setenv("KEYBASE_SERVER_URI", "http://127.0.0.127:3333")
36	defer os.Setenv("KEYBASE_SERVER_URI", prev)
37	err = tc.G.ConfigureAPI()
38	require.NoError(t, err)
39
40	eng := NewLoginOffline(tc.G)
41	m := NewMetaContextForTest(tc)
42	if err := RunEngine2(m, eng); err != nil {
43		t.Fatal(err)
44	}
45	uv, deviceID, deviceName, skey, ekey := tc.G.ActiveDevice.AllFields()
46	if uv.IsNil() {
47		t.Errorf("uid is nil, expected it to exist")
48	}
49	if !uv.Uid.Equal(u1.UID()) {
50		t.Errorf("uid: %v, expected %v", uv, u1)
51	}
52
53	if deviceID.IsNil() {
54		t.Errorf("deviceID is nil, expected it to exist")
55	}
56
57	if deviceName != defaultDeviceName {
58		t.Errorf("device name: %q, expected %q", deviceName, defaultDeviceName)
59	}
60
61	if skey == nil {
62		t.Errorf("signing key is nil, expected it to exist")
63	}
64
65	if ekey == nil {
66		t.Errorf("encryption key is nil, expected it to exist")
67	}
68
69	if tc.G.ActiveDevice.Name() != defaultDeviceName {
70		t.Errorf("device name: %q, expected %q", tc.G.ActiveDevice.Name(), defaultDeviceName)
71	}
72}
73
74// Use fake clock to test login offline after significant delay
75// (make sure upak loader won't use network)
76func TestLoginOfflineDelay(t *testing.T) {
77	tc := SetupEngineTest(t, "login")
78	defer tc.Cleanup()
79
80	fakeClock := clockwork.NewFakeClockAt(time.Now())
81	tc.G.SetClock(fakeClock)
82
83	u1 := CreateAndSignupFakeUser(tc, "login")
84	Logout(tc)
85	u1.LoginOrBust(tc)
86
87	// do a upak load to make sure it is cached
88	arg := libkb.NewLoadUserByUIDArg(context.TODO(), tc.G, u1.UID())
89	_, _, err := tc.G.GetUPAKLoader().Load(arg)
90	require.NoError(t, err)
91
92	// Simulate restarting the service by wiping out the
93	// passphrase stream cache and cached secret keys
94	clearCaches(tc.G)
95	tc.G.GetUPAKLoader().ClearMemory()
96
97	// set server uri to nonexistent ip so api calls will fail
98	prev := os.Getenv("KEYBASE_SERVER_URI")
99	os.Setenv("KEYBASE_SERVER_URI", "http://127.0.0.127:3333")
100	defer os.Setenv("KEYBASE_SERVER_URI", prev)
101	err = tc.G.ConfigureAPI()
102	require.NoError(t, err)
103
104	// advance the clock past the cache timeout
105	fakeClock.Advance(libkb.CachedUserTimeout * 10)
106
107	eng := NewLoginOffline(tc.G)
108	m := NewMetaContextForTest(tc)
109	if err := RunEngine2(m, eng); err != nil {
110		t.Fatal(err)
111	}
112	uv, deviceID, deviceName, skey, ekey := tc.G.ActiveDevice.AllFields()
113	if uv.IsNil() {
114		t.Errorf("uid is nil, expected it to exist")
115	}
116	if !uv.Uid.Equal(u1.UID()) {
117		t.Errorf("uid: %v, expected %v", uv, u1.UID())
118	}
119
120	if deviceID.IsNil() {
121		t.Errorf("deviceID is nil, expected it to exist")
122	}
123
124	if deviceName != defaultDeviceName {
125		t.Errorf("device name: %q, expected %q", deviceName, defaultDeviceName)
126	}
127
128	if skey == nil {
129		t.Errorf("signing key is nil, expected it to exist")
130	}
131
132	if ekey == nil {
133		t.Errorf("encryption key is nil, expected it to exist")
134	}
135}
136
137// Login offline with nothing in upak cache for self user.
138func TestLoginOfflineNoUpak(t *testing.T) {
139	tc := SetupEngineTest(t, "login")
140	defer tc.Cleanup()
141
142	u1 := CreateAndSignupFakeUser(tc, "login")
143	Logout(tc)
144	u1.LoginOrBust(tc)
145
146	// Simulate restarting the service by wiping out the
147	// passphrase stream cache and cached secret keys
148	tc.SimulateServiceRestart()
149	tc.G.GetUPAKLoader().ClearMemory()
150
151	// invalidate the cache for uid
152	tc.G.GetUPAKLoader().Invalidate(context.Background(), u1.UID())
153
154	// set server uri to nonexistent ip so api calls will fail
155	prev := os.Getenv("KEYBASE_SERVER_URI")
156	os.Setenv("KEYBASE_SERVER_URI", "http://127.0.0.127:3333")
157	defer os.Setenv("KEYBASE_SERVER_URI", prev)
158	err := tc.G.ConfigureAPI()
159	require.NoError(t, err)
160
161	eng := NewLoginOffline(tc.G)
162	m := NewMetaContextForTest(tc)
163	err = RunEngine2(m, eng)
164	if err != nil {
165		t.Fatalf("LoginOffline should still work after upak cache invalidation; got %s", err)
166	}
167}
168