github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/uid.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 "crypto/sha256" 8 "encoding/hex" 9 "fmt" 10 "strings" 11 12 keybase1 "github.com/keybase/client/go/protocol/keybase1" 13 jsonw "github.com/keybase/go-jsonw" 14 ) 15 16 func UIDFromHex(s string) (keybase1.UID, error) { 17 u, err := keybase1.UIDFromString(s) 18 if err != nil { 19 var nilUID keybase1.UID 20 return nilUID, err 21 } 22 return u, nil 23 } 24 25 func GetUID(w *jsonw.Wrapper) (keybase1.UID, error) { 26 s, err := w.GetString() 27 var nilUID keybase1.UID 28 if err != nil { 29 return nilUID, err 30 } 31 return UIDFromHex(s) 32 } 33 34 func GetUIDVoid(w *jsonw.Wrapper, u *keybase1.UID, e *error) { 35 uid, err := GetUID(w) 36 if err == nil { 37 *u = uid 38 } else if e != nil && *e == nil { 39 *e = err 40 } 41 } 42 43 func UIDWrapper(uid keybase1.UID) *jsonw.Wrapper { 44 return jsonw.NewString(uid.String()) 45 } 46 47 func UIDArg(uid keybase1.UID) HTTPValue { 48 return S{Val: uid.String()} 49 } 50 51 // GetUIDByNormalizedUsername returns UID for normalized username. Works 52 // offline for all usernames. 53 func GetUIDByNormalizedUsername(g *GlobalContext, username NormalizedUsername) keybase1.UID { 54 uid := g.UIDMapper.MapHardcodedUsernameToUID(username) 55 if uid.Exists() { 56 return uid 57 } 58 return usernameToUIDPreserveCase(username.String()) 59 } 60 61 // GetUIDByUsername returns UID for username strings with potentially 62 // mixed letter casing. Works offline for all usernames. 63 func GetUIDByUsername(g *GlobalContext, username string) keybase1.UID { 64 return GetUIDByNormalizedUsername(g, NewNormalizedUsername(username)) 65 } 66 67 func AssertUsernameMatchesUID(g *GlobalContext, uid keybase1.UID, username string) error { 68 u2 := GetUIDByUsername(g, username) 69 if uid.NotEqual(u2) { 70 return UIDMismatchError{fmt.Sprintf("%s != %s (via %s)", uid, u2, username)} 71 } 72 return nil 73 } 74 75 // NOTE: Use the high level API above instead of any of the following. The 76 // hilvl API handles both UIDS for old, potentially incorrectly hashed 77 // usernames, as well as new, correct UIDs. 78 // 79 // tldr: you probably want to use GetUID* functions, instead of UsernameToUID*. 80 81 // UsernameToUID works for users created after "Fri Feb 6 19:33:08 EST 2015", 82 // with some exceptions, since we didn't ToLower() for all UIDs 83 func UsernameToUID(s string) keybase1.UID { 84 return usernameToUIDPreserveCase(strings.ToLower(s)) 85 } 86 87 func CheckUIDAgainstUsername(uid keybase1.UID, username string) (err error) { 88 // Note: does not handle pre-Feb-2015 UIDs. You might want to use 89 // `AssertUsernameMatchesUID` instead. 90 u2 := UsernameToUID(username) 91 if uid.NotEqual(u2) { 92 err = UIDMismatchError{fmt.Sprintf("%s != %s (via %s)", uid, u2, username)} 93 } 94 return 95 } 96 97 // UsernameToUID works for users created after "Fri Feb 6 19:33:08 EST 2015". Some of 98 // them had buggy Username -> UID conversions, in which case we need to hash the 99 // original case to recover their UID. 100 func usernameToUIDPreserveCase(s string) keybase1.UID { 101 h := sha256.Sum256([]byte(s)) 102 var uid [keybase1.UID_LEN]byte 103 copy(uid[:], h[0:keybase1.UID_LEN-1]) 104 uid[keybase1.UID_LEN-1] = keybase1.UID_SUFFIX_2 105 ret, _ := keybase1.UIDFromString(hex.EncodeToString(uid[:])) 106 return ret 107 } 108 109 // checkUIDAgainstCasedUsername takes the input string, does not convert toLower, 110 // and then hashes it to recover a UID. This is a workaround for some 111 // users whose UIDs were computed incorrectly. 112 func checkUIDAgainstCasedUsername(uid keybase1.UID, username string) (err error) { 113 u2 := usernameToUIDPreserveCase(username) 114 if uid.NotEqual(u2) { 115 err = UIDMismatchError{fmt.Sprintf("%s != %s (via %s)", uid, u2, username)} 116 } 117 return 118 }