1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package libkb
5
6import (
7	"fmt"
8	"runtime/debug"
9	"time"
10
11	"golang.org/x/net/context"
12
13	"github.com/keybase/client/go/jsonhelpers"
14	keybase1 "github.com/keybase/client/go/protocol/keybase1"
15	jsonw "github.com/keybase/go-jsonw"
16)
17
18type UIDer interface {
19	GetUID() keybase1.UID
20}
21
22type StubMode int
23
24const (
25	StubModeStubbed   StubMode = 0
26	StubModeUnstubbed StubMode = 1
27)
28
29func StubModeFromUnstubbedBool(unstubbed bool) StubMode {
30	if unstubbed {
31		return StubModeUnstubbed
32	}
33	return StubModeStubbed
34}
35
36func (s StubMode) String() string {
37	if s == StubModeUnstubbed {
38		return "unstubbed"
39	}
40	return "stubbed"
41}
42
43type LoadUserArg struct {
44	uid                      keybase1.UID
45	name                     string // Can also be an assertion like foo@twitter
46	publicKeyOptional        bool
47	noCacheResult            bool // currently ignore
48	self                     bool
49	forceReload              bool // ignore the cache entirely, don't even bother polling if it is out of date; just fetch new data.
50	forcePoll                bool // for cached user load, force a repoll. If this and StaleOK are both set, we try a network call and if it fails return the cached data.
51	staleOK                  bool // if stale cached versions are OK (for immutable fields)
52	cachedOnly               bool // only return cached data (staleOK should be true and forcePoll must be false)
53	uider                    UIDer
54	abortIfSigchainUnchanged bool
55	resolveBody              *jsonw.Wrapper // some load paths plumb this through
56	upakLite                 bool
57	stubMode                 StubMode // by default, this is StubModeStubbed, meaning, stubbed links are OK
58	forceMerkleServerPolling bool     // can be used to force or suppress server merkle polling, if set
59
60	// NOTE: We used to have these feature flags, but we got rid of them, to
61	// avoid problems where a yes-features load doesn't accidentally get served
62	// the result of an earlier no-features load from cache. We shouldn't add
63	// any more flags like this unless we also add machinery to avoid that
64	// mistake.
65	// AllKeys      bool
66	// AllSubchains bool
67
68	// We might have already loaded these if we're falling back from a
69	// failed LoadUserPlusKeys load
70	merkleLeaf *MerkleUserLeaf
71	sigHints   *SigHints
72	m          MetaContext
73}
74
75func (arg LoadUserArg) String() string {
76	leaf := "nil"
77	if arg.merkleLeaf != nil {
78		leaf = fmt.Sprintf("%v", arg.merkleLeaf.idVersion)
79	}
80	return fmt.Sprintf("{UID:%s Name:%q PublicKeyOptional:%v NoCacheResult:%v Self:%v ForceReload:%v ForcePoll:%v StaleOK:%v AbortIfSigchainUnchanged:%v CachedOnly:%v Leaf:%v %v}",
81		arg.uid, arg.name, arg.publicKeyOptional, arg.noCacheResult, arg.self, arg.forceReload,
82		arg.forcePoll, arg.staleOK, arg.abortIfSigchainUnchanged, arg.cachedOnly, leaf, arg.stubMode)
83}
84
85func (arg LoadUserArg) MetaContext() MetaContext {
86	return arg.m
87}
88
89func NewLoadUserArg(g *GlobalContext) LoadUserArg {
90	return LoadUserArg{m: NewMetaContextBackground(g)}
91}
92
93func NewLoadUserArgWithMetaContext(m MetaContext) LoadUserArg {
94	return LoadUserArg{
95		m:     m,
96		uider: m.LoginContext(),
97	}
98}
99
100func NewLoadUserArgWithContext(ctx context.Context, g *GlobalContext) LoadUserArg {
101	return LoadUserArg{
102		m: NewMetaContext(ctx, g),
103	}
104}
105
106func NewLoadUserSelfArg(g *GlobalContext) LoadUserArg {
107	ret := NewLoadUserArg(g)
108	ret.self = true
109	return ret
110}
111
112func NewLoadUserSelfAndUIDArg(g *GlobalContext) LoadUserArg {
113	ret := NewLoadUserArg(g)
114	ret.self = true
115	ret.uid = g.GetMyUID()
116	return ret
117}
118
119func NewLoadUserForceArg(g *GlobalContext) LoadUserArg {
120	arg := NewLoadUserPubOptionalArg(g)
121	arg.forceReload = true
122	return arg
123}
124
125func NewLoadUserByNameArg(g *GlobalContext, name string) LoadUserArg {
126	arg := NewLoadUserArg(g)
127	arg.name = name
128	return arg
129}
130
131func NewLoadUserByUIDArg(ctx context.Context, g *GlobalContext, uid keybase1.UID) LoadUserArg {
132	arg := NewLoadUserArgWithMetaContext(NewMetaContext(ctx, g))
133	arg.uid = uid
134	return arg
135}
136
137func NewLoadUserByUIDForceArg(g *GlobalContext, uid keybase1.UID) LoadUserArg {
138	arg := NewLoadUserArg(g)
139	arg.uid = uid
140	arg.forceReload = true
141	return arg
142}
143
144func NewLoadUserPubOptionalArg(g *GlobalContext) LoadUserArg {
145	arg := NewLoadUserArg(g)
146	arg.publicKeyOptional = true
147	return arg
148}
149
150func (arg LoadUserArg) WithSelf(self bool) LoadUserArg {
151	arg.self = self
152	return arg
153}
154
155func (arg LoadUserArg) EnsureCtxAndLogTag() LoadUserArg {
156	arg.m = arg.m.EnsureCtx().WithLogTag("LU")
157	return arg
158}
159
160func (arg LoadUserArg) WithCachedOnly(b bool) LoadUserArg {
161	arg.cachedOnly = b
162	return arg
163}
164
165func (arg LoadUserArg) WithResolveBody(r *jsonw.Wrapper) LoadUserArg {
166	arg.resolveBody = r
167	return arg
168}
169
170func (arg LoadUserArg) WithName(n string) LoadUserArg {
171	arg.name = n
172	return arg
173}
174
175func (arg LoadUserArg) WithForceMerkleServerPolling(b bool) LoadUserArg {
176	arg.forceMerkleServerPolling = b
177	return arg
178}
179
180func (arg LoadUserArg) WithNetContext(ctx context.Context) LoadUserArg {
181	arg.m = arg.m.WithCtx(ctx)
182	return arg
183}
184
185func (arg LoadUserArg) WithUID(uid keybase1.UID) LoadUserArg {
186	arg.uid = uid
187	return arg
188}
189
190func (arg LoadUserArg) WithPublicKeyOptional() LoadUserArg {
191	arg.publicKeyOptional = true
192	return arg
193}
194
195func (arg LoadUserArg) ForUPAKLite() LoadUserArg {
196	arg.upakLite = true
197	return arg
198}
199
200func (arg LoadUserArg) WithForcePoll(fp bool) LoadUserArg {
201	arg.forcePoll = fp
202	return arg
203}
204
205func (arg LoadUserArg) WithStaleOK(b bool) LoadUserArg {
206	arg.staleOK = b
207	return arg
208}
209
210func (arg LoadUserArg) GetNetContext() context.Context {
211	if ctx := arg.m.Ctx(); ctx != nil {
212		return ctx
213	}
214	return context.Background()
215}
216
217func (arg LoadUserArg) WithLoginContext(l LoginContext) LoadUserArg {
218	arg.uider = l
219	return arg
220}
221
222func (arg LoadUserArg) WithAbortIfSigchainUnchanged() LoadUserArg {
223	arg.abortIfSigchainUnchanged = true
224	return arg
225}
226
227func (arg LoadUserArg) WithForceReload() LoadUserArg {
228	arg.forceReload = true
229	return arg
230}
231
232func (arg LoadUserArg) WithStubMode(sm StubMode) LoadUserArg {
233	arg.stubMode = sm
234	return arg
235}
236
237func (arg LoadUserArg) ToMerkleOpts() MerkleOpts {
238	ret := MerkleOpts{}
239	if !arg.forceReload && !arg.forcePoll && !arg.forceMerkleServerPolling {
240		ret.NoServerPolling = true
241	}
242	return ret
243}
244
245func (arg *LoadUserArg) checkUIDName() error {
246	if arg.uid.Exists() {
247		return nil
248	}
249
250	if len(arg.name) == 0 && !arg.self {
251		return fmt.Errorf("no username given to LoadUser")
252	}
253
254	if len(arg.name) > 0 && arg.self {
255		return fmt.Errorf("If loading self, can't provide a username")
256	}
257
258	if !arg.self {
259		return nil
260	}
261
262	if arg.uid = myUID(arg.m.G(), arg.uider); arg.uid.IsNil() {
263		arg.name = arg.m.G().Env.GetUsername().String()
264		if len(arg.name) == 0 {
265			return SelfNotFoundError{msg: "could not find UID or username for self"}
266		}
267	}
268	return nil
269}
270
271func (arg *LoadUserArg) resolveUID() (ResolveResult, error) {
272	var rres ResolveResult
273	if arg.uid.Exists() {
274		return rres, nil
275	}
276	if len(arg.name) == 0 {
277		// this won't happen anymore because check moved to
278		// checkUIDName() func, but just in case
279		return rres, fmt.Errorf("resolveUID: no uid or name")
280	}
281
282	if rres = arg.m.G().Resolver.ResolveWithBody(arg.m, arg.name).FailOnDeleted(); rres.err != nil {
283		return rres, rres.err
284	}
285
286	if rres.uid.IsNil() {
287		return rres, fmt.Errorf("No resolution for name=%s", arg.name)
288	}
289
290	arg.uid = rres.uid
291	return rres, nil
292}
293
294// after resolution, check if this is a self load
295func (arg *LoadUserArg) checkSelf() {
296	if arg.self {
297		return
298	}
299
300	myuid := myUID(arg.m.G(), arg.uider)
301	if myuid.Exists() && arg.uid.Exists() && myuid.Equal(arg.uid) {
302		arg.self = true
303	}
304}
305
306func LoadMe(arg LoadUserArg) (*User, error) {
307	arg.self = true
308	return LoadUser(arg)
309}
310
311func LoadMeByUID(ctx context.Context, g *GlobalContext, uid keybase1.UID) (*User, error) {
312	return LoadMe(NewLoadUserByUIDArg(ctx, g, uid))
313}
314func LoadMeByMetaContextAndUID(m MetaContext, uid keybase1.UID) (*User, error) {
315	return LoadMe(NewLoadUserArgWithMetaContext(m).WithUID(uid))
316}
317
318func LoadUser(arg LoadUserArg) (ret *User, err error) {
319	m := arg.MetaContext().WithLogTag("LU")
320	defer m.Trace(fmt.Sprintf("LoadUser(%s)", arg), &err)()
321
322	var refresh bool
323
324	if m.G().VDL.DumpSiteLoadUser() {
325		debug.PrintStack()
326	}
327
328	// Whatever the reply is, pass along our desired global context
329	var refreshReason string
330	defer func() {
331		if ret != nil {
332			ret.SetGlobalContext(m.G())
333			if refresh {
334				m.G().NotifyRouter.HandleUserChanged(m, ret.GetUID(), fmt.Sprintf("libkb.LoadUser refresh '%v'", refreshReason))
335			}
336		}
337	}()
338
339	// make sure we have a uid or a name to load
340	if err = arg.checkUIDName(); err != nil {
341		return nil, err
342	}
343
344	m.Debug("LoadUser(uid=%v, name=%v)", arg.uid, arg.name)
345
346	// resolve the uid from the name, if necessary
347	rres, err := arg.resolveUID()
348	if err != nil {
349		return nil, err
350	}
351
352	// check to see if this is a self load
353	arg.checkSelf()
354
355	m.Debug("| resolved to %s", arg.uid)
356
357	if arg.uid.Exists() {
358		lock, err := m.G().loadUserLockTab.AcquireOnNameWithContextAndTimeout(m.Ctx(), m.G(), arg.uid.String(), 30*time.Second)
359		if err != nil {
360			m.Debug("| error acquiring singleflight lock for %s: %v", arg.uid, err)
361			return nil, err
362		}
363		defer lock.Release(m.Ctx())
364	}
365
366	// We can get the user object's body from either the resolution result or
367	// if it was plumbed through as a parameter.
368	resolveBody := rres.body
369	if resolveBody == nil {
370		resolveBody = arg.resolveBody
371	}
372
373	// get sig hints from local db in order to populate during merkle leaf lookup
374	// They might have already been loaded in.
375	var sigHints *SigHints
376	if sigHints = arg.sigHints; sigHints == nil {
377		sigHints, err = LoadSigHints(m, arg.uid)
378		if err != nil {
379			return nil, err
380		}
381	}
382
383	// load user from local, remote
384	ret, refresh, refreshReason, err = loadUser(m, arg.uid, resolveBody, sigHints, arg.forceReload, arg.merkleLeaf, arg.WithForceMerkleServerPolling(true).ToMerkleOpts())
385	if err != nil {
386		return nil, err
387	}
388
389	ret.sigHints = sigHints
390
391	// Match the returned User object to the Merkle tree. Also make sure
392	// that the username queried for matches the User returned (if it
393	// was indeed queried for)
394	if err = ret.leaf.MatchUser(ret, arg.uid, rres.GetNormalizedQueriedUsername()); err != nil {
395		return ret, err
396	}
397
398	if err = ret.LoadSigChains(m, &ret.leaf, arg.self, arg.stubMode); err != nil {
399		return ret, err
400	}
401
402	if arg.abortIfSigchainUnchanged && ret.sigChain().wasFullyCached {
403		return nil, nil
404	}
405
406	if ret.sigHints != nil && ret.sigHints.dirty {
407		refresh = true
408	}
409
410	// Proactively cache fetches from remote server to local storage
411	if e2 := ret.Store(m); e2 != nil {
412		m.Warning("Problem storing user %s: %s", ret.GetName(), e2)
413	}
414
415	if ret.HasActiveKey() {
416		if err = ret.MakeIDTable(m); err != nil {
417			return ret, err
418		}
419
420		// Check that the user has self-signed only after we
421		// consider revocations. See: https://github.com/keybase/go/issues/43
422		if err = ret.VerifySelfSig(); err != nil {
423			return ret, err
424		}
425
426		cacheUserServiceSummary(m, ret)
427	} else if !arg.publicKeyOptional {
428		m.Debug("No active key for user: %s", ret.GetUID())
429		return ret, NoKeyError{}
430	}
431
432	return ret, err
433}
434
435func loadUser(m MetaContext, uid keybase1.UID, resolveBody *jsonw.Wrapper, sigHints *SigHints, force bool, leaf *MerkleUserLeaf, merkleOpts MerkleOpts) (*User, bool, string, error) {
436	local, err := LoadUserFromLocalStorage(m, uid)
437	var refresh bool
438	var refreshReason string
439	if err != nil {
440		m.Warning("Failed to load %s from storage: %s", uid, err)
441	}
442
443	if leaf == nil {
444		leaf, err = lookupMerkleLeaf(m, uid, (local != nil), sigHints, merkleOpts)
445		if err != nil {
446			return nil, refresh, refreshReason, err
447		}
448	}
449
450	var f1, loadRemote bool
451
452	if local == nil {
453		m.Debug("| No local user stored for %s", uid)
454		loadRemote = true
455	} else if f1, refreshReason, err = local.CheckBasicsFreshness(leaf.idVersion); err != nil {
456		return nil, refresh, refreshReason, err
457	} else {
458		loadRemote = !f1
459		refresh = loadRemote
460	}
461
462	m.Debug("| Freshness: basics=%v; for %s", f1, uid)
463
464	var ret *User
465	if !loadRemote && !force {
466		ret = local
467	} else if ret, err = LoadUserFromServer(m, uid, resolveBody); err != nil {
468		return nil, refresh, refreshReason, err
469	}
470
471	if ret == nil {
472		return nil, refresh, refreshReason, nil
473	}
474
475	if leaf != nil {
476		ret.leaf = *leaf
477	}
478	return ret, refresh, refreshReason, nil
479}
480
481func LoadUserFromLocalStorage(m MetaContext, uid keybase1.UID) (u *User, err error) {
482	m.Debug("+ LoadUserFromLocalStorage(%s)", uid)
483	jw, err := m.G().LocalDb.Get(DbKeyUID(DBUser, uid))
484	if err != nil {
485		return nil, err
486	}
487
488	if jw == nil {
489		m.Debug("- loadUserFromLocalStorage(%s): Not found", uid)
490		return nil, nil
491	}
492
493	m.Debug("| Loaded successfully")
494
495	if u, err = NewUserFromLocalStorage(m.G(), jw); err != nil {
496		return nil, err
497	}
498
499	if u.id.NotEqual(uid) {
500		err = fmt.Errorf("Bad lookup; uid mismatch: %s != %s", uid, u.id)
501	}
502
503	m.Debug("| Loaded username %s (uid=%s)", u.name, uid)
504	m.Debug("- LoadUserFromLocalStorage(%s,%s)", u.name, uid)
505
506	return
507}
508
509// LoadUserEmails returns emails for logged in user
510func LoadUserEmails(m MetaContext) (emails []keybase1.Email, err error) {
511	uid := m.G().GetMyUID()
512	res, err := m.G().API.Get(m, APIArg{
513		Endpoint:    "user/private",
514		SessionType: APISessionTypeREQUIRED,
515		Args: HTTPArgs{
516			"uid": UIDArg(uid),
517		},
518	})
519	if err != nil {
520		return
521	}
522
523	emailPayloads, err := jsonhelpers.JSONGetChildren(res.Body.AtKey("them").AtKey("emails").AtKey("emails"))
524	if err != nil {
525		return nil, err
526	}
527	for _, emailPayload := range emailPayloads {
528		email, err := emailPayload.AtKey("email").GetString()
529		if err != nil {
530			return nil, err
531		}
532		isPrimary, err := emailPayload.AtKey("is_primary").GetInt()
533		if err != nil {
534			return nil, err
535		}
536		isVerified, err := emailPayload.AtKey("is_verified").GetInt()
537		if err != nil {
538			return nil, err
539		}
540		visibilityCode, err := emailPayload.AtKey("visibility").GetInt()
541		if err != nil {
542			return nil, err
543		}
544
545		var lastVerifyEmailDate int64
546		lastVerifyEmailDateNode := emailPayload.AtKey("last_verify_email_date")
547		if lastVerifyEmailDateNode.IsOk() && !lastVerifyEmailDateNode.IsNil() {
548			lastVerifyEmailDate, err = lastVerifyEmailDateNode.GetInt64()
549			if err != nil {
550				return nil, err
551			}
552		}
553
554		emails = append(emails, keybase1.Email{
555			Email:               keybase1.EmailAddress(email),
556			IsVerified:          isVerified == 1,
557			IsPrimary:           isPrimary == 1,
558			Visibility:          keybase1.IdentityVisibility(visibilityCode),
559			LastVerifyEmailDate: keybase1.UnixTime(lastVerifyEmailDate),
560		})
561	}
562
563	return
564}
565
566func LoadUserFromServer(m MetaContext, uid keybase1.UID, body *jsonw.Wrapper) (u *User, err error) {
567	m.Debug("Load User from server: %s", uid)
568
569	// Res.body might already have been preloaded as a result of a Resolve call earlier.
570	if body == nil {
571		res, err := m.G().API.Get(m, APIArg{
572			Endpoint:    "user/lookup",
573			SessionType: APISessionTypeNONE,
574			Args: HTTPArgs{
575				"uid":          UIDArg(uid),
576				"load_deleted": B{true},
577			},
578		})
579
580		if err != nil {
581			return nil, err
582		}
583		body = res.Body.AtKey("them")
584	} else {
585		m.Debug("| Skipped load; got user object previously")
586	}
587
588	if u, err = NewUserFromServer(m.G(), body); err != nil {
589		return u, err
590	}
591	m.Debug("- Load user from server: %s -> %s", uid, ErrToOk(err))
592
593	return u, err
594}
595
596func myUID(g *GlobalContext, uider UIDer) keybase1.UID {
597	if uider != nil {
598		return uider.GetUID()
599	}
600	return g.GetMyUID()
601}
602
603func lookupMerkleLeaf(m MetaContext, uid keybase1.UID, localExists bool, sigHints *SigHints, merkleOpts MerkleOpts) (f *MerkleUserLeaf, err error) {
604	if uid.IsNil() {
605		err = fmt.Errorf("uid parameter for lookupMerkleLeaf empty")
606		return
607	}
608
609	q := NewHTTPArgs()
610	q.Add("uid", UIDArg(uid))
611
612	f, err = m.G().MerkleClient.LookupUser(m, q, sigHints, merkleOpts)
613	if err == nil && f == nil && localExists {
614		err = fmt.Errorf("User not found in server Merkle tree")
615	}
616
617	return
618}
619
620func lookupSigHintsAndMerkleLeaf(m MetaContext, uid keybase1.UID, localExists bool, merkleOpts MerkleOpts) (sigHints *SigHints, leaf *MerkleUserLeaf, err error) {
621	defer m.Trace("lookupSigHintsAndMerkleLeaf", &err)()
622	sigHints, err = LoadSigHints(m, uid)
623	if err != nil {
624		return nil, nil, err
625	}
626
627	leaf, err = lookupMerkleLeaf(m, uid, true, sigHints, merkleOpts)
628	if err != nil {
629		return nil, nil, err
630	}
631
632	return sigHints, leaf, nil
633}
634
635// LoadUserPlusKeys loads user and keys for the given UID.  If `pollForKID` is provided, we'll request
636// this user potentially twice: the first time can hit the cache for the UID, but will force a repoll
637// unless the pollForKID is found for the user.  If pollForKID is empty, then just access the cache as
638// normal.
639func LoadUserPlusKeys(ctx context.Context, g *GlobalContext, uid keybase1.UID, pollForKID keybase1.KID) (keybase1.UserPlusKeys, error) {
640	return g.GetUPAKLoader().LoadUserPlusKeys(ctx, uid, pollForKID)
641}
642
643// IsUserByUsernameOffline checks to see if the given username is a legit Keybase username,
644// using only our offline cache and materials. Useful if you don't mean to share info
645// with the server, as in chat @-mentions. Will return true if it's known to be a legit
646// user, and false if it can't say for sure. "Legit" users in this context might
647// be deleted or reset; they just once existing as a user.
648func IsUserByUsernameOffline(m MetaContext, un NormalizedUsername) bool {
649	if m.G().UIDMapper.MapHardcodedUsernameToUID(un).Exists() {
650		return true
651	}
652
653	// We already took care of the bad username casing in the harcoded exception list above,
654	// so it's ok to treat the NormalizedUsername as a cased string.
655	uid := usernameToUIDPreserveCase(un.String())
656
657	// use the UPAKLoader with StaleOK, CachedOnly in order to get cached upak
658	arg := NewLoadUserArgWithMetaContext(m).WithUID(uid).WithPublicKeyOptional().WithStaleOK(true).WithCachedOnly(true)
659	_, _, err := m.G().GetUPAKLoader().LoadV2(arg)
660
661	if err == nil {
662		return true
663	}
664
665	if _, ok := err.(UserNotFoundError); !ok {
666		m.Debug("IsUserByUsernameOffline(%s) squashing error: %s", un.String(), err)
667	}
668
669	return false
670}
671
672func cacheUserServiceSummary(mctx MetaContext, user *User) {
673	serviceMapper := mctx.G().ServiceMapper
674	if serviceMapper == nil {
675		// no service summary mapper in current context - e.g. in tests.
676		return
677	}
678
679	remoteProofs := user.idTable.remoteProofLinks
680	if remoteProofs != nil {
681		summary := remoteProofs.toServiceSummary()
682		err := serviceMapper.InformOfServiceSummary(mctx.Ctx(), mctx.G(), user.id, summary)
683		if err != nil {
684			mctx.Debug("cacheUserServiceSummary for %q uid: %q: error: %s", user.name, user.id, err)
685		}
686	}
687}
688