github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/uidmap/hardcoded_uids.go (about)

     1  package uidmap
     2  
     3  import (
     4  	"bytes"
     5  	"compress/zlib"
     6  	"fmt"
     7  	"io"
     8  	"sort"
     9  	"sync"
    10  
    11  	"github.com/keybase/client/go/libkb"
    12  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    13  )
    14  
    15  var offsets []uint32
    16  var usernames []byte
    17  var once sync.Once
    18  
    19  // Map of sorted location -> unsorted location, so we can binary search the usernames
    20  var usernameSortOrder []uint16
    21  var usoOnce sync.Once
    22  
    23  func findInit() {
    24  	once.Do(func() {
    25  		initUsernameOffsets()
    26  		initUsernames()
    27  	})
    28  }
    29  
    30  func usernameFindInit() {
    31  	usoOnce.Do(initUsernameSort)
    32  }
    33  
    34  func usernameBytesAtSortedIndex(i int) []byte {
    35  	j := usernameSortOrder[i]
    36  	o := offsets[j]
    37  	return usernames[o : o+uint32(lengths[j])]
    38  }
    39  
    40  func usernameAtSortedIndex(i int) string {
    41  	return string(usernameBytesAtSortedIndex(i))
    42  }
    43  
    44  func initUsernameSort() {
    45  	findInit()
    46  	usernameSortOrder = make([]uint16, len(lengths))
    47  	for i := 0; i < len(lengths); i++ {
    48  		usernameSortOrder[i] = uint16(i)
    49  	}
    50  	sort.SliceStable(usernameSortOrder, func(i, j int) bool {
    51  		return bytes.Compare(usernameBytesAtSortedIndex(i), usernameBytesAtSortedIndex(j)) < 0
    52  	})
    53  }
    54  
    55  type bufWriter struct {
    56  	b []byte
    57  	n int
    58  }
    59  
    60  func (b *bufWriter) Write(p []byte) (int, error) {
    61  	copy(b.b[b.n:], p)
    62  	b.n += len(p)
    63  	return len(p), nil
    64  }
    65  
    66  func initUsernameOffsets() {
    67  	var offset uint32
    68  	offsets = make([]uint32, len(lengths))
    69  	for index, length := range lengths {
    70  		offsets[index] = offset
    71  		offset += uint32(length)
    72  	}
    73  }
    74  
    75  func initUsernames() {
    76  	//
    77  	// The list of usernames is computed as such:
    78  	//  1. Sort all exceptions by UID
    79  	//  2. concatenate all username strings after sorting in 1
    80  	//  3. Tolower the blob
    81  	//  4. run through zlib
    82  	//  5. Also, along with (2), record the length of all of the usernames, and insert into an array
    83  	//  6. Compute running offsets by cumsum'ing the values in 5.
    84  	//
    85  	zip, err := zlib.NewReader(bytes.NewReader(usernamesCompressed[:]))
    86  	if err != nil {
    87  		panic(err)
    88  	}
    89  	usernames = make([]byte, usernamesLen)
    90  	buf := bufWriter{usernames, 0}
    91  	n, err := io.Copy(&buf, zip)
    92  	if err != nil {
    93  		panic(err)
    94  	}
    95  	if n != usernamesLen {
    96  		panic(fmt.Sprintf("bad expansion: wanted %d bytes but got %d", usernamesLen, n))
    97  	}
    98  	zip.Close()
    99  }
   100  
   101  func uidBytesAt(i int) []byte {
   102  	start := i * keybase1.UID_LEN
   103  	return uids[start : start+keybase1.UID_LEN]
   104  }
   105  
   106  func uidAt(i int) keybase1.UID {
   107  	ret, _ := keybase1.UIDFromSlice(uidBytesAt(i))
   108  	return ret
   109  }
   110  
   111  func findHardcodedUsername(u libkb.NormalizedUsername) keybase1.UID {
   112  	usernameFindInit()
   113  	l := len(lengths)
   114  	searchFor := []byte(u.String())
   115  	doCmp := func(i int) int {
   116  		ret := bytes.Compare(searchFor, usernameBytesAtSortedIndex(i))
   117  		return ret
   118  	}
   119  	n := sort.Search(l, func(i int) bool {
   120  		return doCmp(i) <= 0
   121  	})
   122  	if n == l || doCmp(n) != 0 {
   123  		return keybase1.UID("")
   124  	}
   125  	return uidAt(int(usernameSortOrder[n]))
   126  }
   127  
   128  // Returns empty name if not found
   129  func findHardcoded(uid keybase1.UID) libkb.NormalizedUsername {
   130  	findInit()
   131  	searchFor := uid.ToBytes()
   132  	if len(searchFor) != keybase1.UID_LEN {
   133  		// wrong uid size
   134  		return libkb.NormalizedUsername("")
   135  	}
   136  	l := len(uids) / keybase1.UID_LEN
   137  	doCmp := func(i int) int {
   138  		return bytes.Compare(searchFor, uidBytesAt(i))
   139  	}
   140  	n := sort.Search(l, func(i int) bool {
   141  		return doCmp(i) <= 0
   142  	})
   143  	if n == l || doCmp(n) != 0 {
   144  		return libkb.NormalizedUsername("")
   145  	}
   146  	offset := offsets[n]
   147  	s := string(usernames[offset : offset+uint32(lengths[n])])
   148  	return libkb.NewNormalizedUsername(s)
   149  }
   150  
   151  func checkUIDAgainstUsername(uid keybase1.UID, un libkb.NormalizedUsername) bool {
   152  	found := findHardcoded(uid)
   153  	if !found.IsNil() {
   154  		return found.Eq(un)
   155  	}
   156  	computed := libkb.UsernameToUID(un.String())
   157  	return computed.Equal(uid)
   158  }