github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/libkb/loaduser.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package libkb 5 6 import ( 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 18 type UIDer interface { 19 GetUID() keybase1.UID 20 } 21 22 type StubMode int 23 24 const ( 25 StubModeStubbed StubMode = 0 26 StubModeUnstubbed StubMode = 1 27 ) 28 29 func StubModeFromUnstubbedBool(unstubbed bool) StubMode { 30 if unstubbed { 31 return StubModeUnstubbed 32 } 33 return StubModeStubbed 34 } 35 36 func (s StubMode) String() string { 37 if s == StubModeUnstubbed { 38 return "unstubbed" 39 } 40 return "stubbed" 41 } 42 43 type 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 75 func (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 85 func (arg LoadUserArg) MetaContext() MetaContext { 86 return arg.m 87 } 88 89 func NewLoadUserArg(g *GlobalContext) LoadUserArg { 90 return LoadUserArg{m: NewMetaContextBackground(g)} 91 } 92 93 func NewLoadUserArgWithMetaContext(m MetaContext) LoadUserArg { 94 return LoadUserArg{ 95 m: m, 96 uider: m.LoginContext(), 97 } 98 } 99 100 func NewLoadUserArgWithContext(ctx context.Context, g *GlobalContext) LoadUserArg { 101 return LoadUserArg{ 102 m: NewMetaContext(ctx, g), 103 } 104 } 105 106 func NewLoadUserSelfArg(g *GlobalContext) LoadUserArg { 107 ret := NewLoadUserArg(g) 108 ret.self = true 109 return ret 110 } 111 112 func NewLoadUserSelfAndUIDArg(g *GlobalContext) LoadUserArg { 113 ret := NewLoadUserArg(g) 114 ret.self = true 115 ret.uid = g.GetMyUID() 116 return ret 117 } 118 119 func NewLoadUserForceArg(g *GlobalContext) LoadUserArg { 120 arg := NewLoadUserPubOptionalArg(g) 121 arg.forceReload = true 122 return arg 123 } 124 125 func NewLoadUserByNameArg(g *GlobalContext, name string) LoadUserArg { 126 arg := NewLoadUserArg(g) 127 arg.name = name 128 return arg 129 } 130 131 func 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 137 func NewLoadUserByUIDForceArg(g *GlobalContext, uid keybase1.UID) LoadUserArg { 138 arg := NewLoadUserArg(g) 139 arg.uid = uid 140 arg.forceReload = true 141 return arg 142 } 143 144 func NewLoadUserPubOptionalArg(g *GlobalContext) LoadUserArg { 145 arg := NewLoadUserArg(g) 146 arg.publicKeyOptional = true 147 return arg 148 } 149 150 func (arg LoadUserArg) WithSelf(self bool) LoadUserArg { 151 arg.self = self 152 return arg 153 } 154 155 func (arg LoadUserArg) EnsureCtxAndLogTag() LoadUserArg { 156 arg.m = arg.m.EnsureCtx().WithLogTag("LU") 157 return arg 158 } 159 160 func (arg LoadUserArg) WithCachedOnly(b bool) LoadUserArg { 161 arg.cachedOnly = b 162 return arg 163 } 164 165 func (arg LoadUserArg) WithResolveBody(r *jsonw.Wrapper) LoadUserArg { 166 arg.resolveBody = r 167 return arg 168 } 169 170 func (arg LoadUserArg) WithName(n string) LoadUserArg { 171 arg.name = n 172 return arg 173 } 174 175 func (arg LoadUserArg) WithForceMerkleServerPolling(b bool) LoadUserArg { 176 arg.forceMerkleServerPolling = b 177 return arg 178 } 179 180 func (arg LoadUserArg) WithNetContext(ctx context.Context) LoadUserArg { 181 arg.m = arg.m.WithCtx(ctx) 182 return arg 183 } 184 185 func (arg LoadUserArg) WithUID(uid keybase1.UID) LoadUserArg { 186 arg.uid = uid 187 return arg 188 } 189 190 func (arg LoadUserArg) WithPublicKeyOptional() LoadUserArg { 191 arg.publicKeyOptional = true 192 return arg 193 } 194 195 func (arg LoadUserArg) ForUPAKLite() LoadUserArg { 196 arg.upakLite = true 197 return arg 198 } 199 200 func (arg LoadUserArg) WithForcePoll(fp bool) LoadUserArg { 201 arg.forcePoll = fp 202 return arg 203 } 204 205 func (arg LoadUserArg) WithStaleOK(b bool) LoadUserArg { 206 arg.staleOK = b 207 return arg 208 } 209 210 func (arg LoadUserArg) GetNetContext() context.Context { 211 if ctx := arg.m.Ctx(); ctx != nil { 212 return ctx 213 } 214 return context.Background() 215 } 216 217 func (arg LoadUserArg) WithLoginContext(l LoginContext) LoadUserArg { 218 arg.uider = l 219 return arg 220 } 221 222 func (arg LoadUserArg) WithAbortIfSigchainUnchanged() LoadUserArg { 223 arg.abortIfSigchainUnchanged = true 224 return arg 225 } 226 227 func (arg LoadUserArg) WithForceReload() LoadUserArg { 228 arg.forceReload = true 229 return arg 230 } 231 232 func (arg LoadUserArg) WithStubMode(sm StubMode) LoadUserArg { 233 arg.stubMode = sm 234 return arg 235 } 236 237 func (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 245 func (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 271 func (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 295 func (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 306 func LoadMe(arg LoadUserArg) (*User, error) { 307 arg.self = true 308 return LoadUser(arg) 309 } 310 311 func LoadMeByUID(ctx context.Context, g *GlobalContext, uid keybase1.UID) (*User, error) { 312 return LoadMe(NewLoadUserByUIDArg(ctx, g, uid)) 313 } 314 func LoadMeByMetaContextAndUID(m MetaContext, uid keybase1.UID) (*User, error) { 315 return LoadMe(NewLoadUserArgWithMetaContext(m).WithUID(uid)) 316 } 317 318 func 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 435 func 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 481 func 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 510 func 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 566 func 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 596 func myUID(g *GlobalContext, uider UIDer) keybase1.UID { 597 if uider != nil { 598 return uider.GetUID() 599 } 600 return g.GetMyUID() 601 } 602 603 func 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 620 func 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. 639 func 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. 648 func 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 672 func 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 }