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 "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 16func 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 25func 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 34func 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 43func UIDWrapper(uid keybase1.UID) *jsonw.Wrapper { 44 return jsonw.NewString(uid.String()) 45} 46 47func 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. 53func 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. 63func GetUIDByUsername(g *GlobalContext, username string) keybase1.UID { 64 return GetUIDByNormalizedUsername(g, NewNormalizedUsername(username)) 65} 66 67func 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 83func UsernameToUID(s string) keybase1.UID { 84 return usernameToUIDPreserveCase(strings.ToLower(s)) 85} 86 87func 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. 100func 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. 112func 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} 119