github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/protocol/keybase1/extras.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 keybase1
     5  
     6  import (
     7  	"bytes"
     8  	"crypto/hmac"
     9  	"crypto/sha256"
    10  	"crypto/sha512"
    11  	"crypto/subtle"
    12  	"encoding/base64"
    13  	"encoding/binary"
    14  	"encoding/hex"
    15  	"encoding/json"
    16  	"errors"
    17  	"fmt"
    18  	"math"
    19  	"reflect"
    20  	"regexp"
    21  	"sort"
    22  	"strconv"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/keybase/client/go/kbtime"
    27  	"github.com/keybase/go-framed-msgpack-rpc/rpc"
    28  	jsonw "github.com/keybase/go-jsonw"
    29  )
    30  
    31  const (
    32  	UID_LEN                       = 16
    33  	UID_SUFFIX                    = 0x00
    34  	UID_SUFFIX_2                  = 0x19
    35  	UID_SUFFIX_HEX                = "00"
    36  	UID_SUFFIX_2_HEX              = "19"
    37  	TEAMID_LEN                    = 16
    38  	TEAMID_PRIVATE_SUFFIX         = 0x24
    39  	TEAMID_PRIVATE_SUFFIX_HEX     = "24"
    40  	TEAMID_PUBLIC_SUFFIX          = 0x2e
    41  	TEAMID_PUBLIC_SUFFIX_HEX      = "2e"
    42  	SUB_TEAMID_PRIVATE_SUFFIX     = 0x25
    43  	SUB_TEAMID_PRIVATE_SUFFIX_HEX = "25"
    44  	SUB_TEAMID_PUBLIC_SUFFIX      = 0x2f
    45  	SUB_TEAMID_PUBLIC_SUFFIX_HEX  = "2f"
    46  	PUBLIC_UID                    = "ffffffffffffffffffffffffffffff00"
    47  )
    48  
    49  // UID for the special "public" user.
    50  var PublicUID = UID(PUBLIC_UID)
    51  
    52  const (
    53  	SIG_ID_LEN         = 32
    54  	SIG_ID_SUFFIX      = 0x0f
    55  	SIG_SHORT_ID_BYTES = 27
    56  	SigIDQueryMin      = 8
    57  )
    58  
    59  const (
    60  	DeviceIDLen       = 16
    61  	DeviceIDSuffix    = 0x18
    62  	DeviceIDSuffixHex = "18"
    63  )
    64  
    65  const (
    66  	KidLen     = 35   // bytes
    67  	KidSuffix  = 0x0a // a byte
    68  	KidVersion = 0x1
    69  )
    70  
    71  const redactedReplacer = "[REDACTED]"
    72  
    73  func Unquote(data []byte) string {
    74  	return strings.Trim(string(data), "\"")
    75  }
    76  
    77  func Quote(s string) []byte {
    78  	return []byte("\"" + s + "\"")
    79  }
    80  
    81  func UnquoteBytes(data []byte) []byte {
    82  	return bytes.Trim(data, "\"")
    83  }
    84  
    85  func KIDFromSlice(b []byte) KID {
    86  	return KID(hex.EncodeToString(b))
    87  }
    88  
    89  func (b BinaryKID) ToKID() KID {
    90  	return KIDFromSlice([]byte(b))
    91  }
    92  
    93  func (k KID) ToBinaryKID() BinaryKID {
    94  	return BinaryKID(k.ToBytes())
    95  }
    96  
    97  func (b BinaryKID) Equal(c BinaryKID) bool {
    98  	return bytes.Equal([]byte(b), []byte(c))
    99  }
   100  
   101  func KIDFromStringChecked(s string) (KID, error) {
   102  
   103  	// It's OK to have a 0-length KID. That means, no such key
   104  	// (or NULL kid).
   105  	if len(s) == 0 {
   106  		return KID(""), nil
   107  	}
   108  
   109  	b, err := hex.DecodeString(s)
   110  	if err != nil {
   111  		return KID(""), err
   112  	}
   113  
   114  	if len(b) != KidLen {
   115  		return KID(""), fmt.Errorf("KID wrong length; wanted %d but got %d bytes",
   116  			KidLen, len(b))
   117  	}
   118  	if b[len(b)-1] != KidSuffix {
   119  		return KID(""), fmt.Errorf("Bad KID suffix: got 0x%02x, wanted 0x%02x",
   120  			b[len(b)-1], KidSuffix)
   121  	}
   122  	if b[0] != KidVersion {
   123  		return KID(""), fmt.Errorf("Bad KID version; got 0x%02x but wanted 0x%02x",
   124  			b[0], KidVersion)
   125  	}
   126  	return KID(s), nil
   127  }
   128  
   129  func HashMetaFromString(s string) (ret HashMeta, err error) {
   130  	// TODO: Should we add similar handling to other types?
   131  	if s == "null" {
   132  		return nil, nil
   133  	}
   134  	b, err := hex.DecodeString(s)
   135  	if err != nil {
   136  		return ret, err
   137  	}
   138  	return HashMeta(b), nil
   139  }
   140  
   141  func cieq(s string, t string) bool {
   142  	return strings.EqualFold(s, t)
   143  }
   144  
   145  func KBFSRootHashFromString(s string) (ret KBFSRootHash, err error) {
   146  	if s == "null" {
   147  		return nil, nil
   148  	}
   149  	b, err := base64.StdEncoding.DecodeString(s)
   150  	if err != nil {
   151  		return ret, err
   152  	}
   153  	return KBFSRootHash(b), nil
   154  }
   155  
   156  func (h KBFSRootHash) String() string {
   157  	return hex.EncodeToString(h)
   158  }
   159  
   160  func (h KBFSRootHash) Eq(h2 KBFSRootHash) bool {
   161  	return hmac.Equal(h[:], h2[:])
   162  }
   163  
   164  func (h HashMeta) String() string {
   165  	return hex.EncodeToString(h)
   166  }
   167  
   168  func (h HashMeta) Eq(h2 HashMeta) bool {
   169  	return hmac.Equal(h[:], h2[:])
   170  }
   171  
   172  func (h *HashMeta) UnmarshalJSON(b []byte) error {
   173  	hm, err := HashMetaFromString(Unquote(b))
   174  	if err != nil {
   175  		return err
   176  	}
   177  	*h = hm
   178  	return nil
   179  }
   180  
   181  func (h *KBFSRootHash) UnmarshalJSON(b []byte) error {
   182  	rh, err := KBFSRootHashFromString(Unquote(b))
   183  	if err != nil {
   184  		return err
   185  	}
   186  	*h = rh
   187  	return nil
   188  }
   189  
   190  func SHA512FromString(s string) (ret SHA512, err error) {
   191  	if s == "null" {
   192  		return nil, nil
   193  	}
   194  	b, err := hex.DecodeString(s)
   195  	if err != nil {
   196  		return ret, err
   197  	}
   198  	if len(b) != 64 {
   199  		return nil, fmt.Errorf("Wanted a 64-byte SHA512, but got %d bytes", len(b))
   200  	}
   201  	return SHA512(b), nil
   202  }
   203  
   204  func (s SHA512) String() string {
   205  	return hex.EncodeToString(s)
   206  }
   207  
   208  func (s SHA512) Eq(s2 SHA512) bool {
   209  	return hmac.Equal(s[:], s2[:])
   210  }
   211  
   212  func (s *SHA512) UnmarshalJSON(b []byte) error {
   213  	tmp, err := SHA512FromString(Unquote(b))
   214  	if err != nil {
   215  		return err
   216  	}
   217  	*s = tmp
   218  	return nil
   219  }
   220  
   221  func (t *ResetType) UnmarshalJSON(b []byte) error {
   222  	var err error
   223  	s := strings.TrimSpace(string(b))
   224  	var ret ResetType
   225  	switch s {
   226  	case "\"reset\"", "1":
   227  		ret = ResetType_RESET
   228  	case "\"delete\"", "2":
   229  		ret = ResetType_DELETE
   230  	default:
   231  		err = fmt.Errorf("Bad reset type: %s", s)
   232  	}
   233  	*t = ret
   234  	return err
   235  }
   236  
   237  func (l *LeaseID) UnmarshalJSON(b []byte) error {
   238  	decoded, err := hex.DecodeString(Unquote(b))
   239  	if err != nil {
   240  		return err
   241  	}
   242  	*l = LeaseID(hex.EncodeToString(decoded))
   243  	return nil
   244  }
   245  
   246  func (h HashMeta) MarshalJSON() ([]byte, error) {
   247  	return Quote(h.String()), nil
   248  }
   249  
   250  func KIDFromString(s string) KID {
   251  	// there are no validations for KIDs (length, suffixes)
   252  	return KID(s)
   253  }
   254  
   255  func (k KID) IsValid() bool {
   256  	return len(k) > 0
   257  }
   258  
   259  func (k KID) String() string {
   260  	return string(k)
   261  }
   262  
   263  func (k KID) IsNil() bool {
   264  	return len(k) == 0
   265  }
   266  
   267  func (k KID) Exists() bool {
   268  	return !k.IsNil()
   269  }
   270  
   271  func (k KID) Equal(v KID) bool {
   272  	return k == v
   273  }
   274  
   275  func (k KID) NotEqual(v KID) bool {
   276  	return !k.Equal(v)
   277  }
   278  
   279  func (k KID) SecureEqual(v KID) bool {
   280  	return hmac.Equal(k.ToBytes(), v.ToBytes())
   281  }
   282  
   283  func (k KID) Match(q string, exact bool) bool {
   284  	if k.IsNil() {
   285  		return false
   286  	}
   287  
   288  	if exact {
   289  		return cieq(k.String(), q)
   290  	}
   291  
   292  	if strings.HasPrefix(k.String(), strings.ToLower(q)) {
   293  		return true
   294  	}
   295  	if strings.HasPrefix(k.ToShortIDString(), q) {
   296  		return true
   297  	}
   298  	return false
   299  }
   300  
   301  func (k KID) ToBytes() []byte {
   302  	b, err := hex.DecodeString(string(k))
   303  	if err != nil {
   304  		return nil
   305  	}
   306  	return b
   307  }
   308  
   309  func (k KID) GetKeyType() byte {
   310  	raw := k.ToBytes()
   311  	if len(raw) < 2 {
   312  		return 0
   313  	}
   314  	return raw[1]
   315  }
   316  
   317  func (k KID) ToShortIDString() string {
   318  	return encode(k.ToBytes()[0:12])
   319  }
   320  
   321  func (k KID) ToJsonw() *jsonw.Wrapper {
   322  	if k.IsNil() {
   323  		return jsonw.NewNil()
   324  	}
   325  	return jsonw.NewString(string(k))
   326  }
   327  
   328  func (k KID) IsIn(list []KID) bool {
   329  	for _, h := range list {
   330  		if h.Equal(k) {
   331  			return true
   332  		}
   333  	}
   334  	return false
   335  }
   336  
   337  func PGPFingerprintFromString(s string) (ret PGPFingerprint, err error) {
   338  	b, err := hex.DecodeString(s)
   339  	if err != nil {
   340  		return
   341  	}
   342  	copy(ret[:], b)
   343  	return
   344  }
   345  
   346  func (p *PGPFingerprint) String() string {
   347  	return hex.EncodeToString(p[:])
   348  }
   349  
   350  func (p PGPFingerprint) MarshalJSON() ([]byte, error) {
   351  	return Quote(p.String()), nil
   352  }
   353  
   354  func (p *PGPFingerprint) UnmarshalJSON(b []byte) error {
   355  	tmp, err := PGPFingerprintFromString(Unquote(b))
   356  	if err != nil {
   357  		return err
   358  	}
   359  	*p = tmp
   360  	return nil
   361  }
   362  
   363  func DeviceIDFromBytes(b [DeviceIDLen]byte) DeviceID {
   364  	return DeviceID(hex.EncodeToString(b[:]))
   365  }
   366  
   367  func (d DeviceID) ToBytes(out []byte) error {
   368  	tmp, err := hex.DecodeString(string(d))
   369  	if err != nil {
   370  		return err
   371  	}
   372  	if len(tmp) != DeviceIDLen {
   373  		return fmt.Errorf("Bad device ID; wanted %d bytes but got %d", DeviceIDLen, len(tmp))
   374  	}
   375  	if len(out) != DeviceIDLen {
   376  		return fmt.Errorf("Need to output to a slice with %d bytes", DeviceIDLen)
   377  	}
   378  	copy(out, tmp)
   379  	return nil
   380  }
   381  
   382  func DeviceIDFromSlice(b []byte) (DeviceID, error) {
   383  	if len(b) != DeviceIDLen {
   384  		return "", fmt.Errorf("invalid byte slice for DeviceID: len == %d, expected %d", len(b), DeviceIDLen)
   385  	}
   386  	var x [DeviceIDLen]byte
   387  	copy(x[:], b)
   388  	return DeviceIDFromBytes(x), nil
   389  }
   390  
   391  func LinkIDFromByte32(b [32]byte) LinkID {
   392  	return LinkID(hex.EncodeToString(b[:]))
   393  }
   394  
   395  func DeviceIDFromString(s string) (DeviceID, error) {
   396  	if len(s) != hex.EncodedLen(DeviceIDLen) {
   397  		return "", fmt.Errorf("Bad Device ID length: %d", len(s))
   398  	}
   399  	suffix := s[len(s)-2:]
   400  	if suffix != DeviceIDSuffixHex {
   401  		return "", fmt.Errorf("Bad suffix byte: %s", suffix)
   402  	}
   403  	return DeviceID(s), nil
   404  }
   405  
   406  func (d DeviceID) String() string {
   407  	return string(d)
   408  }
   409  
   410  func (d DeviceID) IsNil() bool {
   411  	return len(d) == 0
   412  }
   413  
   414  func (d DeviceID) Exists() bool {
   415  	return !d.IsNil()
   416  }
   417  
   418  func (d DeviceID) Eq(d2 DeviceID) bool {
   419  	return d == d2
   420  }
   421  
   422  func (t TeamID) Eq(t2 TeamID) bool {
   423  	return t == t2
   424  }
   425  
   426  func (l LinkID) Eq(l2 LinkID) bool {
   427  	return l == l2
   428  }
   429  
   430  func (l LinkID) IsNil() bool {
   431  	return len(l) == 0
   432  }
   433  
   434  func (l LinkID) String() string {
   435  	return string(l)
   436  }
   437  
   438  func NilTeamID() TeamID { return TeamID("") }
   439  
   440  func (s Seqno) Eq(s2 Seqno) bool {
   441  	return s == s2
   442  }
   443  
   444  func (s Seqno) String() string {
   445  	return fmt.Sprintf("%d", s)
   446  }
   447  
   448  func UIDFromString(s string) (UID, error) {
   449  	if len(s) != hex.EncodedLen(UID_LEN) {
   450  		return "", fmt.Errorf("Bad UID '%s'; must be %d bytes long", s, UID_LEN)
   451  	}
   452  	suffix := s[len(s)-2:]
   453  	if suffix != UID_SUFFIX_HEX && suffix != UID_SUFFIX_2_HEX {
   454  		return "", fmt.Errorf("Bad UID '%s': must end in 0x%x or 0x%x", s, UID_SUFFIX, UID_SUFFIX_2)
   455  	}
   456  	return UID(s), nil
   457  }
   458  
   459  func UIDFromSlice(b []byte) (UID, error) {
   460  	return UIDFromString(hex.EncodeToString(b))
   461  }
   462  
   463  // Used by unit tests.
   464  func MakeTestUID(n uint32) UID {
   465  	b := make([]byte, 8)
   466  	binary.LittleEndian.PutUint32(b, n)
   467  	s := hex.EncodeToString(b)
   468  	c := 2*UID_LEN - len(UID_SUFFIX_HEX) - len(s)
   469  	s += strings.Repeat("0", c) + UID_SUFFIX_HEX
   470  	uid, err := UIDFromString(s)
   471  	if err != nil {
   472  		panic(err)
   473  	}
   474  	return uid
   475  }
   476  
   477  func (u UID) String() string {
   478  	return string(u)
   479  }
   480  
   481  func (u UID) ToBytes() []byte {
   482  	b, err := hex.DecodeString(string(u))
   483  	if err != nil {
   484  		return nil
   485  	}
   486  	return b
   487  }
   488  
   489  func (u UID) IsNil() bool {
   490  	return len(u) == 0
   491  }
   492  
   493  func (u UID) Exists() bool {
   494  	return !u.IsNil()
   495  }
   496  
   497  func (u UID) Equal(v UID) bool {
   498  	return u == v
   499  }
   500  
   501  func (u UID) NotEqual(v UID) bool {
   502  	return !u.Equal(v)
   503  }
   504  
   505  func (u UID) Less(v UID) bool {
   506  	return u < v
   507  }
   508  
   509  func (u UID) AsUserOrTeam() UserOrTeamID {
   510  	return UserOrTeamID(u)
   511  }
   512  
   513  func TeamIDFromString(s string) (TeamID, error) {
   514  	if len(s) != hex.EncodedLen(TEAMID_LEN) {
   515  		return "", fmt.Errorf("Bad TeamID '%s'; must be %d bytes long", s, TEAMID_LEN)
   516  	}
   517  	suffix := s[len(s)-2:]
   518  	switch suffix {
   519  	case TEAMID_PRIVATE_SUFFIX_HEX, TEAMID_PUBLIC_SUFFIX_HEX,
   520  		SUB_TEAMID_PRIVATE_SUFFIX_HEX, SUB_TEAMID_PUBLIC_SUFFIX_HEX:
   521  		return TeamID(s), nil
   522  	}
   523  	return "", fmt.Errorf("Bad TeamID '%s': must end in one of [0x%x, 0x%x, 0x%x, 0x%x]",
   524  		s, TEAMID_PRIVATE_SUFFIX_HEX, TEAMID_PUBLIC_SUFFIX_HEX, SUB_TEAMID_PRIVATE_SUFFIX, SUB_TEAMID_PUBLIC_SUFFIX)
   525  }
   526  
   527  func UserOrTeamIDFromString(s string) (UserOrTeamID, error) {
   528  	UID, errUser := UIDFromString(s)
   529  	if errUser == nil {
   530  		return UID.AsUserOrTeam(), nil
   531  	}
   532  	teamID, errTeam := TeamIDFromString(s)
   533  	if errTeam == nil {
   534  		return teamID.AsUserOrTeam(), nil
   535  	}
   536  	return "", fmt.Errorf("Bad UserOrTeamID: could not parse %s as a UID (err = %v) or team id (err = %v)", s, errUser, errTeam)
   537  }
   538  
   539  // Used by unit tests.
   540  func MakeTestTeamID(n uint32, public bool) TeamID {
   541  	b := make([]byte, 8)
   542  	binary.LittleEndian.PutUint32(b, n)
   543  	s := hex.EncodeToString(b)
   544  	useSuffix := TEAMID_PRIVATE_SUFFIX_HEX
   545  	if public {
   546  		useSuffix = TEAMID_PUBLIC_SUFFIX_HEX
   547  	}
   548  	c := 2*TEAMID_LEN - len(useSuffix) - len(s)
   549  	s += strings.Repeat("0", c) + useSuffix
   550  	tid, err := TeamIDFromString(s)
   551  	if err != nil {
   552  		panic(err)
   553  	}
   554  	return tid
   555  }
   556  
   557  // Used by unit tests.
   558  func MakeTestSubTeamID(n uint32, public bool) TeamID {
   559  	b := make([]byte, 8)
   560  	binary.LittleEndian.PutUint32(b, n)
   561  	s := hex.EncodeToString(b)
   562  	useSuffix := SUB_TEAMID_PRIVATE_SUFFIX_HEX
   563  	if public {
   564  		useSuffix = SUB_TEAMID_PUBLIC_SUFFIX_HEX
   565  	}
   566  	c := 2*TEAMID_LEN - len(useSuffix) - len(s)
   567  	s += strings.Repeat("0", c) + useSuffix
   568  	tid, err := TeamIDFromString(s)
   569  	if err != nil {
   570  		panic(err)
   571  	}
   572  	return tid
   573  }
   574  
   575  // Can panic if invalid
   576  func (t TeamID) IsSubTeam() bool {
   577  	suffix := t[len(t)-2:]
   578  	switch suffix {
   579  	case SUB_TEAMID_PRIVATE_SUFFIX_HEX, SUB_TEAMID_PUBLIC_SUFFIX_HEX:
   580  		return true
   581  	}
   582  	return false
   583  }
   584  
   585  func (t TeamID) IsRootTeam() bool {
   586  	return !t.IsSubTeam()
   587  }
   588  
   589  func (t TeamID) IsPublic() bool {
   590  	suffix := t[len(t)-2:]
   591  	switch suffix {
   592  	case TEAMID_PUBLIC_SUFFIX_HEX, SUB_TEAMID_PUBLIC_SUFFIX_HEX:
   593  		return true
   594  	}
   595  	return false
   596  }
   597  
   598  func (t TeamID) String() string {
   599  	return string(t)
   600  }
   601  
   602  func (t TeamID) ToBytes() []byte {
   603  	b, err := hex.DecodeString(string(t))
   604  	if err != nil {
   605  		return nil
   606  	}
   607  	return b
   608  }
   609  
   610  func (t TeamID) IsNil() bool {
   611  	return len(t) == 0
   612  }
   613  
   614  func (t TeamID) Exists() bool {
   615  	return !t.IsNil()
   616  }
   617  
   618  func (t TeamID) Equal(v TeamID) bool {
   619  	return t == v
   620  }
   621  
   622  func (t TeamID) NotEqual(v TeamID) bool {
   623  	return !t.Equal(v)
   624  }
   625  
   626  func (t TeamID) Less(v TeamID) bool {
   627  	return t < v
   628  }
   629  
   630  func (t TeamID) AsUserOrTeam() UserOrTeamID {
   631  	return UserOrTeamID(t)
   632  }
   633  
   634  const ptrSize = 4 << (^uintptr(0) >> 63) // stolen from runtime/internal/sys
   635  
   636  // Size implements the cache.Measurable interface.
   637  func (t TeamID) Size() int {
   638  	return len(t) + ptrSize
   639  }
   640  
   641  func (s SigID) IsNil() bool {
   642  	return len(s) == 0
   643  }
   644  
   645  func (s SigID) Exists() bool {
   646  	return !s.IsNil()
   647  }
   648  
   649  func (s SigID) String() string { return string(s) }
   650  
   651  func (s SigID) ToDisplayString(verbose bool) string {
   652  	if verbose {
   653  		return string(s)
   654  	}
   655  	return fmt.Sprintf("%s...", s[0:SigIDQueryMin])
   656  }
   657  
   658  func (s SigID) PrefixMatch(q string, exact bool) bool {
   659  	if s.IsNil() {
   660  		return false
   661  	}
   662  
   663  	if exact {
   664  		return cieq(string(s), q)
   665  	}
   666  
   667  	if strings.HasPrefix(strings.ToLower(string(s)), strings.ToLower(q)) {
   668  		return true
   669  	}
   670  
   671  	return false
   672  }
   673  
   674  func SigIDFromString(s string) (SigID, error) {
   675  	// Add 1 extra byte for the suffix
   676  	blen := SIG_ID_LEN + 1
   677  	if len(s) != hex.EncodedLen(blen) {
   678  		return "", fmt.Errorf("Invalid SigID string length: %d, expected %d", len(s), hex.EncodedLen(blen))
   679  	}
   680  	s = strings.ToLower(s)
   681  	// Throw the outcome away, but we're checking that we can decode the value as hex
   682  	_, err := hex.DecodeString(s)
   683  	if err != nil {
   684  		return "", err
   685  	}
   686  	return SigID(s), nil
   687  }
   688  
   689  func (s SigID) ToBytes() []byte {
   690  	b, err := hex.DecodeString(string(s))
   691  	if err != nil {
   692  		return nil
   693  	}
   694  	return b[0:SIG_ID_LEN]
   695  }
   696  
   697  func (s SigID) StripSuffix() SigIDBase {
   698  	l := hex.EncodedLen(SIG_ID_LEN)
   699  	if len(s) == l {
   700  		return SigIDBase(string(s))
   701  	}
   702  	return SigIDBase(string(s[0:l]))
   703  }
   704  
   705  func (s SigID) Eq(t SigID) bool {
   706  	b := s.ToBytes()
   707  	c := t.ToBytes()
   708  	if b == nil || c == nil {
   709  		return false
   710  	}
   711  	return hmac.Equal(b, c)
   712  }
   713  
   714  type SigIDMapKey string
   715  
   716  // ToMapKey returns the string representation (hex-encoded) of a SigID with the hardcoded 0x0f suffix
   717  // (for backward comptability with on-disk storage).
   718  func (s SigID) ToMapKey() SigIDMapKey {
   719  	return SigIDMapKey(s.StripSuffix().ToSigIDLegacy().String())
   720  }
   721  
   722  func (s SigID) ToMediumID() string {
   723  	return encode(s.ToBytes())
   724  }
   725  
   726  func (s SigID) ToShortID() string {
   727  	return encode(s.ToBytes()[0:SIG_SHORT_ID_BYTES])
   728  }
   729  
   730  // SigIDBase is a 64-character long hex encoding of the SHA256 of a signature, without
   731  // any suffix. You get a SigID by adding either a 0f or a 22 suffix.
   732  type SigIDBase string
   733  
   734  func (s SigIDBase) String() string {
   735  	return string(s)
   736  }
   737  
   738  func SigIDBaseFromBytes(b [SIG_ID_LEN]byte) SigIDBase {
   739  	s := hex.EncodeToString(b[:])
   740  	return SigIDBase(s)
   741  }
   742  
   743  // MarshalJSON output the SigIDBase as a full SigID to be compatible
   744  // with legacy versions of the app.
   745  func (s SigIDBase) MarshalJSON() ([]byte, error) {
   746  	return Quote(s.ToSigIDLegacy().String()), nil
   747  }
   748  
   749  // UnmarshalJSON will accept either a SigID or a SigIDBase, and can
   750  // strip off the suffix.
   751  func (s *SigIDBase) UnmarshalJSON(b []byte) error {
   752  	tmp := Unquote(b)
   753  
   754  	l := hex.EncodedLen(SIG_ID_LEN)
   755  	if len(tmp) == l {
   756  		base, err := SigIDBaseFromString(tmp)
   757  		if err != nil {
   758  			return err
   759  		}
   760  		*s = base
   761  		return nil
   762  	}
   763  
   764  	// If we didn't get a sigID the right size, try to strip off the suffix.
   765  	sigID, err := SigIDFromString(tmp)
   766  	if err != nil {
   767  		return err
   768  	}
   769  	*s = sigID.StripSuffix()
   770  	return nil
   771  }
   772  
   773  func SigIDBaseFromSlice(b []byte) (SigIDBase, error) {
   774  	var buf [32]byte
   775  	if len(b) != len(buf) {
   776  		return "", errors.New("need a SHA256 hash, got something the wrong length")
   777  	}
   778  	copy(buf[:], b)
   779  	return SigIDBaseFromBytes(buf), nil
   780  }
   781  
   782  func SigIDBaseFromString(s string) (SigIDBase, error) {
   783  	b, err := hex.DecodeString(s)
   784  	if err != nil {
   785  		return "", err
   786  	}
   787  	return SigIDBaseFromSlice(b)
   788  }
   789  
   790  func (s SigIDBase) EqSigID(t SigID) bool {
   791  	return cieq(s.String(), t.StripSuffix().String())
   792  }
   793  
   794  // SigIDSuffixParameters specify how to turn a 64-character SigIDBase into a 66-character SigID,
   795  // via the two suffixes. In the future, there might be a third, 38, in use.
   796  type SigIDSuffixParameters struct {
   797  	IsUserSig       bool       // true for user, false for team
   798  	IsWalletStellar bool       // exceptional sig type for backwards compatibility
   799  	SigVersion      SigVersion // 1,2 or 3 supported now
   800  }
   801  
   802  func SigIDSuffixParametersFromTypeAndVersion(typ string, vers SigVersion) SigIDSuffixParameters {
   803  	return SigIDSuffixParameters{
   804  		IsUserSig:       !strings.HasPrefix(typ, "teams."),
   805  		IsWalletStellar: (typ == "wallet.stellar"),
   806  		SigVersion:      vers,
   807  	}
   808  }
   809  
   810  func (s SigIDSuffixParameters) String() string {
   811  	if s.IsWalletStellar && s.SigVersion == 2 {
   812  		return "22"
   813  	}
   814  	if s.IsUserSig {
   815  		return "0f"
   816  	}
   817  	switch s.SigVersion {
   818  	case 2:
   819  		return "22"
   820  	case 3:
   821  		return "38"
   822  	default:
   823  		return "0f"
   824  	}
   825  }
   826  
   827  func (s SigIDBase) ToSigID(p SigIDSuffixParameters) SigID {
   828  	return SigID(string(s) + p.String())
   829  }
   830  
   831  // ToSigIDLegacy does what all of Keybase used to do, which is to always assign a 0x0f
   832  // suffix to SigIDBases to get SigIDs.
   833  func (s SigIDBase) ToSigIDLegacy() SigID {
   834  	return s.ToSigID(SigIDSuffixParameters{IsUserSig: true, IsWalletStellar: false, SigVersion: 1})
   835  }
   836  
   837  func (s SigIDBase) Eq(t SigIDBase) bool {
   838  	return cieq(string(s), string(t))
   839  }
   840  
   841  func (s SigIDBase) ToBytes() []byte {
   842  	x, err := hex.DecodeString(string(s))
   843  	if err != nil {
   844  		return nil
   845  	}
   846  	return x
   847  }
   848  
   849  func encode(b []byte) string {
   850  	return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
   851  }
   852  
   853  func FromTime(t Time) time.Time {
   854  	if t == 0 {
   855  		return time.Time{}
   856  	}
   857  	// t is in millisecond.
   858  	tSec := int64(t) / 1000
   859  	tNanoSecOffset := (int64(t) - tSec*1000) * 1000000
   860  	return time.Unix(tSec, tNanoSecOffset)
   861  }
   862  
   863  func (t Time) Time() time.Time {
   864  	return FromTime(t)
   865  }
   866  
   867  func (t Time) UnixSeconds() int64 {
   868  	return t.Time().Unix()
   869  }
   870  
   871  func ToTime(t time.Time) Time {
   872  	if t.IsZero() {
   873  		return 0
   874  	}
   875  
   876  	return Time(t.Unix()*1000 + (int64(t.Nanosecond()) / 1000000))
   877  }
   878  
   879  func ToTimePtr(t *time.Time) *Time {
   880  	if t == nil {
   881  		return nil
   882  	}
   883  	ret := ToTime(*t)
   884  	return &ret
   885  }
   886  
   887  func TimeFromSeconds(seconds int64) Time {
   888  	return Time(seconds * 1000)
   889  }
   890  
   891  func (t Time) IsZero() bool        { return t == 0 }
   892  func (t Time) After(t2 Time) bool  { return t > t2 }
   893  func (t Time) Before(t2 Time) bool { return t < t2 }
   894  
   895  func FormatTime(t Time) string {
   896  	layout := "2006-01-02 15:04:05 MST"
   897  	return FromTime(t).Format(layout)
   898  }
   899  
   900  func FromUnixTime(u UnixTime) time.Time {
   901  	if u == 0 {
   902  		return time.Time{}
   903  	}
   904  	return time.Unix(int64(u), 0)
   905  }
   906  
   907  func (u UnixTime) Time() time.Time {
   908  	return FromUnixTime(u)
   909  }
   910  
   911  func (u UnixTime) UnixSeconds() int64 {
   912  	return int64(u)
   913  }
   914  
   915  func ToUnixTime(t time.Time) UnixTime {
   916  	if t.IsZero() {
   917  		return 0
   918  	}
   919  	return UnixTime(t.Unix())
   920  }
   921  
   922  func UnixTimeFromSeconds(seconds int64) UnixTime {
   923  	return UnixTime(seconds)
   924  }
   925  
   926  func (u UnixTime) IsZero() bool            { return u == UnixTime(0) }
   927  func (u UnixTime) After(u2 UnixTime) bool  { return u > u2 }
   928  func (u UnixTime) Before(u2 UnixTime) bool { return u < u2 }
   929  func FormatUnixTime(u UnixTime) string {
   930  	layout := "2006-01-02 15:04:05 MST"
   931  	return FromUnixTime(u).Format(layout)
   932  }
   933  
   934  func (s Status) Error() string {
   935  	if s.Code == int(StatusCode_SCOk) {
   936  		return ""
   937  	}
   938  	return fmt.Sprintf("%s (%s/%d)", s.Desc, s.Name, s.Code)
   939  }
   940  
   941  func (s Status) GoError() error {
   942  	if s.Code == int(StatusCode_SCOk) {
   943  		return nil
   944  	}
   945  	return fmt.Errorf(s.Error())
   946  }
   947  
   948  func (s InstallStatus) String() string {
   949  	switch s {
   950  	case InstallStatus_UNKNOWN:
   951  		return "Unknown"
   952  	case InstallStatus_ERROR:
   953  		return "Error"
   954  	case InstallStatus_NOT_INSTALLED:
   955  		return "Not Installed"
   956  	case InstallStatus_INSTALLED:
   957  		return "Installed"
   958  	}
   959  	return ""
   960  }
   961  
   962  func (s InstallAction) String() string {
   963  	switch s {
   964  	case InstallAction_UNKNOWN:
   965  		return "Unknown"
   966  	case InstallAction_NONE:
   967  		return "None"
   968  	case InstallAction_UPGRADE:
   969  		return "Upgrade"
   970  	case InstallAction_REINSTALL:
   971  		return "Re-Install"
   972  	case InstallAction_INSTALL:
   973  		return "Install"
   974  	}
   975  	return ""
   976  }
   977  
   978  func (s ServiceStatus) NeedsInstall() bool {
   979  	return s.InstallAction == InstallAction_INSTALL ||
   980  		s.InstallAction == InstallAction_REINSTALL ||
   981  		s.InstallAction == InstallAction_UPGRADE
   982  }
   983  
   984  func (k *KID) UnmarshalJSON(b []byte) error {
   985  	kid, err := KIDFromStringChecked(Unquote(b))
   986  	if err != nil {
   987  		return err
   988  	}
   989  	*k = kid
   990  	return nil
   991  }
   992  
   993  func (u *UID) UnmarshalJSON(b []byte) error {
   994  	uid, err := UIDFromString(Unquote(b))
   995  	if err != nil {
   996  		return err
   997  	}
   998  	*u = uid
   999  	return nil
  1000  }
  1001  
  1002  func (u *UserOrTeamID) UnmarshalJSON(b []byte) error {
  1003  	utid, err := UserOrTeamIDFromString(Unquote(b))
  1004  	if err != nil {
  1005  		return err
  1006  	}
  1007  	*u = utid
  1008  	return nil
  1009  }
  1010  
  1011  // Size implements the cache.Measurable interface.
  1012  func (u UID) Size() int {
  1013  	return len(u) + ptrSize
  1014  }
  1015  
  1016  func (k *KID) MarshalJSON() ([]byte, error) {
  1017  	return Quote(k.String()), nil
  1018  }
  1019  
  1020  func (u *UID) MarshalJSON() ([]byte, error) {
  1021  	return Quote(u.String()), nil
  1022  }
  1023  
  1024  func (u *UserOrTeamID) MarshalJSON() ([]byte, error) {
  1025  	return Quote(u.String()), nil
  1026  }
  1027  
  1028  // Size implements the keybase/kbfs/cache.Measurable interface.
  1029  func (k *KID) Size() int {
  1030  	if k == nil {
  1031  		return 0
  1032  	}
  1033  	return len(*k) + ptrSize
  1034  }
  1035  
  1036  func (s *SigID) UnmarshalJSON(b []byte) error {
  1037  	sigID, err := SigIDFromString(Unquote(b))
  1038  	if err != nil {
  1039  		return err
  1040  	}
  1041  	*s = sigID
  1042  	return nil
  1043  }
  1044  
  1045  func (s *SigID) MarshalJSON() ([]byte, error) {
  1046  	return Quote(s.String()), nil
  1047  }
  1048  
  1049  func (f Folder) ToString() string {
  1050  	prefix := "<unrecognized>"
  1051  	switch f.FolderType {
  1052  	case FolderType_PRIVATE:
  1053  		prefix = "private"
  1054  	case FolderType_PUBLIC:
  1055  		prefix = "public"
  1056  	case FolderType_TEAM:
  1057  		prefix = "team"
  1058  	}
  1059  	return prefix + "/" + f.Name
  1060  }
  1061  
  1062  func (f Folder) String() string {
  1063  	return f.ToString()
  1064  }
  1065  
  1066  func (f FolderHandle) ToString() string {
  1067  	prefix := "<unrecognized>"
  1068  	switch f.FolderType {
  1069  	case FolderType_PRIVATE:
  1070  		prefix = "private"
  1071  	case FolderType_PUBLIC:
  1072  		prefix = "public"
  1073  	case FolderType_TEAM:
  1074  		prefix = "team"
  1075  	}
  1076  	return prefix + "/" + f.Name
  1077  }
  1078  
  1079  func (f FolderHandle) String() string {
  1080  	return f.ToString()
  1081  }
  1082  
  1083  func (t TrackToken) String() string {
  1084  	return string(t)
  1085  }
  1086  
  1087  func KIDFromRawKey(b []byte, keyType byte) KID {
  1088  	tmp := []byte{KidVersion, keyType}
  1089  	tmp = append(tmp, b...)
  1090  	tmp = append(tmp, byte(KidSuffix))
  1091  	return KIDFromSlice(tmp)
  1092  }
  1093  
  1094  type APIStatus interface {
  1095  	Status() Status
  1096  }
  1097  
  1098  type Error struct {
  1099  	code    StatusCode
  1100  	message string
  1101  }
  1102  
  1103  func NewError(code StatusCode, message string) *Error {
  1104  	if code == StatusCode_SCOk {
  1105  		return nil
  1106  	}
  1107  	return &Error{code: code, message: message}
  1108  }
  1109  
  1110  func FromError(err error) *Error {
  1111  	return &Error{code: StatusCode_SCGeneric, message: err.Error()}
  1112  }
  1113  
  1114  func StatusOK(desc string) Status {
  1115  	if desc == "" {
  1116  		desc = "OK"
  1117  	}
  1118  	return Status{Code: int(StatusCode_SCOk), Name: "OK", Desc: desc}
  1119  }
  1120  
  1121  func StatusFromCode(code StatusCode, message string) Status {
  1122  	if code == StatusCode_SCOk {
  1123  		return StatusOK(message)
  1124  	}
  1125  	return NewError(code, message).Status()
  1126  }
  1127  
  1128  func (e *Error) Error() string {
  1129  	return e.message
  1130  }
  1131  
  1132  func (e *Error) Status() Status {
  1133  	return Status{Code: int(e.code), Name: "ERROR", Desc: e.message}
  1134  }
  1135  
  1136  func (t ClientType) String() string {
  1137  	switch t {
  1138  	case ClientType_CLI:
  1139  		return "command-line client"
  1140  	case ClientType_KBFS:
  1141  		return "KBFS"
  1142  	case ClientType_GUI_MAIN:
  1143  		return "desktop"
  1144  	case ClientType_GUI_HELPER:
  1145  		return "desktop helper"
  1146  	default:
  1147  		return "other"
  1148  	}
  1149  }
  1150  
  1151  func (m MerkleTreeID) Number() int {
  1152  	return int(m)
  1153  }
  1154  
  1155  func (m MerkleTreeID) String() string {
  1156  	return strconv.Itoa(int(m))
  1157  }
  1158  
  1159  func (r BlockReference) String() string {
  1160  	return fmt.Sprintf("%s,%s", r.Bid.BlockHash, hex.EncodeToString(r.Nonce[:]))
  1161  }
  1162  
  1163  func (r BlockReferenceCount) String() string {
  1164  	return fmt.Sprintf("%s,%d", r.Ref.String(), r.LiveCount)
  1165  }
  1166  
  1167  func (sa SocialAssertion) String() string {
  1168  	if sa.Service == "email" {
  1169  		return fmt.Sprintf("[%s]@email", sa.User)
  1170  	}
  1171  	return fmt.Sprintf("%s@%s", sa.User, sa.Service)
  1172  }
  1173  
  1174  func (sa SocialAssertion) TeamInviteType() string {
  1175  	return string(sa.Service)
  1176  }
  1177  
  1178  func (sa SocialAssertion) TeamInviteName() TeamInviteName {
  1179  	return TeamInviteName(sa.User)
  1180  }
  1181  
  1182  func (a GetArg) GetEndpoint() string {
  1183  	return a.Endpoint
  1184  }
  1185  
  1186  func (a GetArg) GetHTTPArgs() []StringKVPair {
  1187  	return a.Args
  1188  }
  1189  
  1190  func (a GetArg) GetHttpStatuses() []int {
  1191  	return a.HttpStatus
  1192  }
  1193  
  1194  func (a GetArg) GetAppStatusCodes() []int {
  1195  	return a.AppStatusCode
  1196  }
  1197  
  1198  func (a GetWithSessionArg) GetEndpoint() string {
  1199  	return a.Endpoint
  1200  }
  1201  
  1202  func (a GetWithSessionArg) GetHTTPArgs() []StringKVPair {
  1203  	return a.Args
  1204  }
  1205  
  1206  func (a GetWithSessionArg) GetHttpStatuses() []int {
  1207  	return a.HttpStatus
  1208  }
  1209  
  1210  func (a GetWithSessionArg) GetAppStatusCodes() []int {
  1211  	return a.AppStatusCode
  1212  }
  1213  
  1214  func (a PostArg) GetEndpoint() string {
  1215  	return a.Endpoint
  1216  }
  1217  
  1218  func (a PostArg) GetHTTPArgs() []StringKVPair {
  1219  	return a.Args
  1220  }
  1221  
  1222  func (a PostArg) GetHttpStatuses() []int {
  1223  	return a.HttpStatus
  1224  }
  1225  
  1226  func (a PostArg) GetAppStatusCodes() []int {
  1227  	return a.AppStatusCode
  1228  }
  1229  
  1230  func (a PostJSONArg) GetEndpoint() string {
  1231  	return a.Endpoint
  1232  }
  1233  
  1234  func (a PostJSONArg) GetHTTPArgs() []StringKVPair {
  1235  	return a.Args
  1236  }
  1237  
  1238  func (a PostJSONArg) GetHttpStatuses() []int {
  1239  	return a.HttpStatus
  1240  }
  1241  
  1242  func (a PostJSONArg) GetAppStatusCodes() []int {
  1243  	return a.AppStatusCode
  1244  }
  1245  
  1246  func (a DeleteArg) GetEndpoint() string {
  1247  	return a.Endpoint
  1248  }
  1249  
  1250  func (a DeleteArg) GetHTTPArgs() []StringKVPair {
  1251  	return a.Args
  1252  }
  1253  
  1254  func (a DeleteArg) GetHttpStatuses() []int {
  1255  	return a.HttpStatus
  1256  }
  1257  
  1258  func (a DeleteArg) GetAppStatusCodes() []int {
  1259  	return a.AppStatusCode
  1260  }
  1261  
  1262  // ToStatusAble is something that can be coerced into a status. Some error types
  1263  // in your application might want this.
  1264  type ToStatusAble interface {
  1265  	ToStatus() Status
  1266  }
  1267  
  1268  // WrapError is a generic method that converts a Go Error into a RPC error status object.
  1269  // If the error is itself a Status object to being with, then it will just return that
  1270  // status object. If it is something that can be made into a Status object via the
  1271  // ToStatusAble interface, then we'll try that. Otherwise, we'll just make a generic
  1272  // Error type.
  1273  func WrapError(e error) interface{} {
  1274  
  1275  	if e == nil {
  1276  		return nil
  1277  	}
  1278  
  1279  	if ee, ok := e.(ToStatusAble); ok {
  1280  		tmp := ee.ToStatus()
  1281  		return &tmp
  1282  	}
  1283  
  1284  	if status, ok := e.(*Status); ok {
  1285  		return status
  1286  	}
  1287  
  1288  	if status, ok := e.(Status); ok {
  1289  		return status
  1290  	}
  1291  
  1292  	return Status{
  1293  		Name: "GENERIC",
  1294  		Code: int(StatusCode_SCGeneric),
  1295  		Desc: e.Error(),
  1296  	}
  1297  }
  1298  
  1299  // WrapError should function as a valid WrapErrorFunc as used by the RPC library.
  1300  var _ rpc.WrapErrorFunc = WrapError
  1301  
  1302  // ErrorUnwrapper is converter that take a Status object off the wire and convert it
  1303  // into an Error that Go can understand, and you can discriminate on in your code.
  1304  // Though status object can act as Go errors, you can further convert them into
  1305  // typed errors via the Upcaster function if specified. An Upcaster takes a Status
  1306  // and returns something that obeys the Error interface, but can be anything your
  1307  // program needs.
  1308  type ErrorUnwrapper struct {
  1309  	Upcaster func(status Status) error
  1310  }
  1311  
  1312  // MakeArg just makes a dummy object that we can unmarshal into, as needed by the
  1313  // underlying RPC library.
  1314  func (eu ErrorUnwrapper) MakeArg() interface{} {
  1315  	return &Status{}
  1316  }
  1317  
  1318  // UnwrapError takes an incoming RPC object, attempts to coerce it into a Status
  1319  // object, and then Upcasts via the Upcaster or just returns if not was provided.
  1320  func (eu ErrorUnwrapper) UnwrapError(arg interface{}) (appError, dispatchError error) {
  1321  	targ, ok := arg.(*Status)
  1322  	if !ok {
  1323  		dispatchError = errors.New("Error converting status to keybase1.Status object")
  1324  		return nil, dispatchError
  1325  	}
  1326  	if targ == nil {
  1327  		return nil, nil
  1328  	}
  1329  	if targ.Code == int(StatusCode_SCOk) {
  1330  		return nil, nil
  1331  	}
  1332  
  1333  	if eu.Upcaster != nil {
  1334  		appError = eu.Upcaster(*targ)
  1335  	} else {
  1336  		appError = *targ
  1337  	}
  1338  	return appError, nil
  1339  }
  1340  
  1341  // Assert that Status can function as an error object.
  1342  var _ error = Status{}
  1343  
  1344  // Assert that our ErrorUnwrapper fits the RPC error unwrapper spec.
  1345  var _ rpc.ErrorUnwrapper = ErrorUnwrapper{}
  1346  
  1347  func (t TLFID) String() string {
  1348  	return string(t)
  1349  }
  1350  
  1351  func (t TLFID) IsNil() bool {
  1352  	return len(t) == 0
  1353  }
  1354  
  1355  func (t TLFID) Exists() bool {
  1356  	return !t.IsNil()
  1357  }
  1358  
  1359  func (t TLFID) ToBytes() []byte {
  1360  	b, err := hex.DecodeString(string(t))
  1361  	if err != nil {
  1362  		return nil
  1363  	}
  1364  	return b
  1365  }
  1366  
  1367  func (t TLFID) Eq(u TLFID) bool {
  1368  	return t == u
  1369  }
  1370  
  1371  func (b TLFIdentifyBehavior) UnblockThenForceIDTable() bool {
  1372  	switch b {
  1373  	case TLFIdentifyBehavior_GUI_PROFILE:
  1374  		return true
  1375  	default:
  1376  		return false
  1377  	}
  1378  }
  1379  
  1380  func (b TLFIdentifyBehavior) AlwaysRunIdentify() bool {
  1381  	switch b {
  1382  	case TLFIdentifyBehavior_CHAT_CLI,
  1383  		TLFIdentifyBehavior_CHAT_GUI,
  1384  		TLFIdentifyBehavior_SALTPACK,
  1385  		TLFIdentifyBehavior_KBFS_CHAT,
  1386  		TLFIdentifyBehavior_GUI_PROFILE:
  1387  		return true
  1388  	default:
  1389  		return false
  1390  	}
  1391  }
  1392  
  1393  func (b TLFIdentifyBehavior) CanUseUntrackedFastPath() bool {
  1394  	switch b {
  1395  	case TLFIdentifyBehavior_CHAT_GUI,
  1396  		TLFIdentifyBehavior_FS_GUI,
  1397  		TLFIdentifyBehavior_SALTPACK,
  1398  		TLFIdentifyBehavior_RESOLVE_AND_CHECK:
  1399  		return true
  1400  	default:
  1401  		// TLFIdentifyBehavior_DEFAULT_KBFS, for filesystem activity that
  1402  		// doesn't have any other UI to report errors with.
  1403  		return false
  1404  	}
  1405  }
  1406  
  1407  func (b TLFIdentifyBehavior) WarningInsteadOfErrorOnBrokenTracks() bool {
  1408  	switch b {
  1409  	case TLFIdentifyBehavior_CHAT_GUI,
  1410  		TLFIdentifyBehavior_FS_GUI:
  1411  		// The chat GUI is specifically exempted from broken
  1412  		// track errors, because people need to be able to use it to ask each other
  1413  		// about the fact that proofs are broken.
  1414  		return true
  1415  	default:
  1416  		return false
  1417  	}
  1418  }
  1419  
  1420  func (b TLFIdentifyBehavior) NotifyGUIAboutBreaks() bool {
  1421  	switch b {
  1422  	case TLFIdentifyBehavior_FS_GUI:
  1423  		// Technically chat needs this too but is done in go/chat by itself and
  1424  		// doesn't use this. So we only put FS_GUI here.
  1425  		return true
  1426  	default:
  1427  		return false
  1428  	}
  1429  }
  1430  
  1431  func (b TLFIdentifyBehavior) SkipUserCard() bool {
  1432  	switch b {
  1433  	case TLFIdentifyBehavior_CHAT_GUI,
  1434  		TLFIdentifyBehavior_FS_GUI,
  1435  		TLFIdentifyBehavior_RESOLVE_AND_CHECK:
  1436  		// We don't need to bother loading a user card in these cases.
  1437  		return true
  1438  	default:
  1439  		return false
  1440  	}
  1441  }
  1442  
  1443  func (b TLFIdentifyBehavior) AllowCaching() bool {
  1444  	switch b {
  1445  	case TLFIdentifyBehavior_RESOLVE_AND_CHECK:
  1446  		// We Don't want to use any internal ID2 caching for ResolveAndCheck.
  1447  		return false
  1448  	default:
  1449  		return true
  1450  	}
  1451  }
  1452  
  1453  func (b TLFIdentifyBehavior) AllowDeletedUsers() bool {
  1454  	switch b {
  1455  	case TLFIdentifyBehavior_RESOLVE_AND_CHECK:
  1456  		// ResolveAndCheck is OK with deleted users
  1457  		return true
  1458  	default:
  1459  		return false
  1460  	}
  1461  }
  1462  
  1463  // All of the chat modes want to prevent tracker popups.
  1464  func (b TLFIdentifyBehavior) ShouldSuppressTrackerPopups() bool {
  1465  	switch b {
  1466  	case TLFIdentifyBehavior_CHAT_GUI,
  1467  		TLFIdentifyBehavior_FS_GUI,
  1468  		TLFIdentifyBehavior_CHAT_CLI,
  1469  		TLFIdentifyBehavior_KBFS_REKEY,
  1470  		TLFIdentifyBehavior_KBFS_QR,
  1471  		TLFIdentifyBehavior_SALTPACK,
  1472  		TLFIdentifyBehavior_RESOLVE_AND_CHECK,
  1473  		TLFIdentifyBehavior_KBFS_CHAT,
  1474  		TLFIdentifyBehavior_KBFS_INIT:
  1475  		// These are identifies that either happen without user interaction at
  1476  		// all, or happen while you're staring at some Keybase UI that can
  1477  		// report errors on its own. No popups needed.
  1478  		return true
  1479  	default:
  1480  		// TLFIdentifyBehavior_DEFAULT_KBFS, for filesystem activity that
  1481  		// doesn't have any other UI to report errors with.
  1482  		return false
  1483  	}
  1484  }
  1485  
  1486  // SkipExternalChecks indicates we do not want to run any external proof checkers in
  1487  // identify modes that yield true.
  1488  func (b TLFIdentifyBehavior) SkipExternalChecks() bool {
  1489  	switch b {
  1490  	case TLFIdentifyBehavior_KBFS_QR,
  1491  		TLFIdentifyBehavior_KBFS_REKEY:
  1492  		return true
  1493  	default:
  1494  		return false
  1495  	}
  1496  }
  1497  
  1498  // ShouldRefreshChatView indicates that when the identify is complete, we
  1499  // should update the chat system's view of the computed track breaks (also
  1500  // affects username coloring in the GUI).
  1501  func (b TLFIdentifyBehavior) ShouldRefreshChatView() bool {
  1502  	switch b {
  1503  	case TLFIdentifyBehavior_GUI_PROFILE, TLFIdentifyBehavior_CLI:
  1504  		return true
  1505  	default:
  1506  		return false
  1507  	}
  1508  }
  1509  
  1510  func (c CanonicalTLFNameAndIDWithBreaks) Eq(r CanonicalTLFNameAndIDWithBreaks) bool {
  1511  	if c.CanonicalName != r.CanonicalName {
  1512  		return false
  1513  	}
  1514  	if c.TlfID != r.TlfID {
  1515  		return false
  1516  	}
  1517  	if len(c.Breaks.Breaks) != len(r.Breaks.Breaks) {
  1518  		return false
  1519  	}
  1520  
  1521  	m := make(map[string]bool)
  1522  	for _, b := range c.Breaks.Breaks {
  1523  		m[b.User.Username] = true
  1524  	}
  1525  	for _, b := range r.Breaks.Breaks {
  1526  		if !m[b.User.Username] {
  1527  			return false
  1528  		}
  1529  	}
  1530  
  1531  	return true
  1532  }
  1533  
  1534  func (c CanonicalTlfName) String() string {
  1535  	return string(c)
  1536  }
  1537  
  1538  func (u UserPlusKeys) GetUID() UID {
  1539  	return u.Uid
  1540  }
  1541  
  1542  func (u UserPlusKeys) GetName() string {
  1543  	return u.Username
  1544  }
  1545  
  1546  func (u UserPlusKeys) GetStatus() StatusCode {
  1547  	return u.Status
  1548  }
  1549  
  1550  func (u UserPlusKeysV2AllIncarnations) GetRemoteTrack(uid UID) *RemoteTrack {
  1551  	ret, ok := u.Current.RemoteTracks[uid]
  1552  	if !ok {
  1553  		return nil
  1554  	}
  1555  	return &ret
  1556  }
  1557  
  1558  func (u UserPlusAllKeys) GetUID() UID {
  1559  	return u.Base.GetUID()
  1560  }
  1561  
  1562  func (u UserPlusAllKeys) GetName() string {
  1563  	return u.Base.GetName()
  1564  }
  1565  
  1566  func (u UserPlusAllKeys) GetStatus() StatusCode {
  1567  	return u.Base.GetStatus()
  1568  }
  1569  
  1570  func (u UserPlusAllKeys) GetDeviceID(kid KID) (ret DeviceID, err error) {
  1571  	for _, dk := range u.Base.DeviceKeys {
  1572  		if dk.KID.Equal(kid) {
  1573  			return dk.DeviceID, nil
  1574  		}
  1575  	}
  1576  	return ret, fmt.Errorf("no device key for kid")
  1577  }
  1578  
  1579  func (u UserPlusAllKeys) Export() *User {
  1580  	return &User{Uid: u.GetUID(), Username: u.GetName()}
  1581  }
  1582  
  1583  func (u UserVersionVector) Equal(u2 UserVersionVector) bool {
  1584  	if u2.Id == 0 || u.Id == 0 || u2.Id != u.Id {
  1585  		return false
  1586  	}
  1587  	if u2.SigHints == 0 || u.SigHints == 0 || u2.SigHints != u.SigHints {
  1588  		return false
  1589  	}
  1590  	if u2.SigChain == 0 || u.SigChain == 0 || u2.SigChain != u.SigChain {
  1591  		return false
  1592  	}
  1593  	return true
  1594  }
  1595  
  1596  func ToDurationMsec(d time.Duration) DurationMsec {
  1597  	return DurationMsec(d / time.Millisecond)
  1598  }
  1599  
  1600  func (d DurationMsec) Duration() time.Duration {
  1601  	return time.Duration(d) * time.Millisecond
  1602  }
  1603  
  1604  func ToDurationSec(d time.Duration) DurationSec {
  1605  	return DurationSec(d / time.Second)
  1606  }
  1607  
  1608  func (d DurationSec) Duration() time.Duration {
  1609  	return time.Duration(d) * time.Second
  1610  }
  1611  
  1612  func (u UserPlusAllKeys) FindDevice(d DeviceID) *PublicKey {
  1613  	for _, k := range u.Base.DeviceKeys {
  1614  		if k.DeviceID.Eq(d) {
  1615  			return &k
  1616  		}
  1617  	}
  1618  	return nil
  1619  }
  1620  
  1621  func (u UserPlusKeysV2) GetUID() UID {
  1622  	return u.Uid
  1623  }
  1624  
  1625  func (u UserPlusKeysV2) GetName() string {
  1626  	return u.Username
  1627  }
  1628  
  1629  func (u UserPlusKeysV2) GetStatus() StatusCode {
  1630  	return u.Status
  1631  }
  1632  
  1633  func (u UserPlusKeysV2AllIncarnations) ExportToSimpleUser() User {
  1634  	return User{Uid: u.GetUID(), Username: u.GetName()}
  1635  }
  1636  
  1637  func (u UserPlusKeysV2AllIncarnations) FindDevice(d DeviceID) *PublicKeyV2NaCl {
  1638  	for _, k := range u.Current.DeviceKeys {
  1639  		if k.DeviceID.Eq(d) {
  1640  			return &k
  1641  		}
  1642  	}
  1643  	return nil
  1644  }
  1645  
  1646  func (u UserPlusKeysV2AllIncarnations) GetUID() UID {
  1647  	return u.Current.GetUID()
  1648  }
  1649  
  1650  func (u UserPlusKeysV2AllIncarnations) GetName() string {
  1651  	return u.Current.GetName()
  1652  }
  1653  
  1654  func (u UserPlusKeysV2AllIncarnations) GetStatus() StatusCode {
  1655  	return u.Current.GetStatus()
  1656  }
  1657  
  1658  func (u UserPlusKeysV2AllIncarnations) AllIncarnations() (ret []UserPlusKeysV2) {
  1659  	ret = append(ret, u.Current)
  1660  	ret = append(ret, u.PastIncarnations...)
  1661  	return ret
  1662  }
  1663  
  1664  func (u UserPlusKeys) FindKID(needle KID) *PublicKey {
  1665  	for _, k := range u.DeviceKeys {
  1666  		if k.KID.Equal(needle) {
  1667  			return &k
  1668  		}
  1669  	}
  1670  	return nil
  1671  }
  1672  
  1673  // FindKID finds the Key and user incarnation that most recently used this KID.
  1674  // It is possible for users to use the same KID across incarnations (though definitely
  1675  // not condoned or encouraged). In that case, we'll give the most recent use.
  1676  func (u UserPlusKeysV2AllIncarnations) FindKID(kid KID) (*UserPlusKeysV2, *PublicKeyV2NaCl) {
  1677  	ret, ok := u.Current.DeviceKeys[kid]
  1678  	if ok {
  1679  		return &u.Current, &ret
  1680  	}
  1681  	for i := len(u.PastIncarnations) - 1; i >= 0; i-- {
  1682  		prev := u.PastIncarnations[i]
  1683  		ret, ok = prev.DeviceKeys[kid]
  1684  		if ok {
  1685  			return &prev, &ret
  1686  		}
  1687  	}
  1688  	return nil, nil
  1689  }
  1690  
  1691  // HasKID returns true if u has the given KID in any of its incarnations.
  1692  // Useful for deciding if we should repoll a stale UPAK in the UPAK loader.
  1693  func (u UserPlusKeysV2AllIncarnations) HasKID(kid KID) bool {
  1694  	incarnation, _ := u.FindKID(kid)
  1695  	return (incarnation != nil)
  1696  }
  1697  
  1698  func (u UserPlusKeysV2) FindDeviceKey(needle KID) *PublicKeyV2NaCl {
  1699  	for _, k := range u.DeviceKeys {
  1700  		if k.Base.Kid.Equal(needle) {
  1701  			return &k
  1702  		}
  1703  	}
  1704  	return nil
  1705  }
  1706  
  1707  func (u UserPlusKeysV2) FindSigningDeviceKey(d DeviceID) *PublicKeyV2NaCl {
  1708  	for _, k := range u.DeviceKeys {
  1709  		if k.DeviceID.Eq(d) && k.Base.IsSibkey {
  1710  			return &k
  1711  		}
  1712  	}
  1713  	return nil
  1714  }
  1715  
  1716  func (u UserPlusKeysV2) FindSigningDeviceKID(d DeviceID) (KID, string) {
  1717  	key := u.FindSigningDeviceKey(d)
  1718  	if key == nil {
  1719  		return KID(""), ""
  1720  	}
  1721  	return key.Base.Kid, key.DeviceDescription
  1722  }
  1723  
  1724  func (u UserPlusKeysV2) FindEncryptionDeviceKeyFromSigningKID(parent KID) *PublicKeyV2NaCl {
  1725  	for _, k := range u.DeviceKeys {
  1726  		if !k.Base.IsSibkey && k.Parent != nil && k.Parent.Equal(parent) {
  1727  			return &k
  1728  		}
  1729  	}
  1730  	return nil
  1731  }
  1732  
  1733  func (u UserPlusKeysV2) FindEncryptionKIDFromSigningKID(parent KID) KID {
  1734  	key := u.FindEncryptionDeviceKeyFromSigningKID(parent)
  1735  	if key == nil {
  1736  		return KID("")
  1737  	}
  1738  	return key.Base.Kid
  1739  }
  1740  
  1741  func (u UserPlusKeysV2) FindEncryptionKIDFromDeviceID(deviceID DeviceID) KID {
  1742  	signingKID, _ := u.FindSigningDeviceKID(deviceID)
  1743  	if signingKID.IsNil() {
  1744  		return KID("")
  1745  	}
  1746  	return u.FindEncryptionKIDFromSigningKID(signingKID)
  1747  }
  1748  
  1749  func (s ChatConversationID) String() string {
  1750  	return hex.EncodeToString(s)
  1751  }
  1752  
  1753  func (s ChatConversationID) Bytes() []byte {
  1754  	return s
  1755  }
  1756  
  1757  // IsOlderThan returns true if any of the versions of u are older than v
  1758  func (u UserPlusAllKeys) IsOlderThan(v UserPlusAllKeys) bool {
  1759  	if u.Base.Uvv.SigChain < v.Base.Uvv.SigChain {
  1760  		return true
  1761  	}
  1762  	if u.Base.Uvv.Id < v.Base.Uvv.Id {
  1763  		return true
  1764  	}
  1765  	return false
  1766  }
  1767  
  1768  // IsOlderThan returns true if any of the versions of u are older than v
  1769  func (u UserPlusKeysV2AllIncarnations) IsOlderThan(v UserPlusKeysV2AllIncarnations) bool {
  1770  	if u.Uvv.SigChain < v.Uvv.SigChain {
  1771  		return true
  1772  	}
  1773  	if u.Uvv.Id < v.Uvv.Id {
  1774  		return true
  1775  	}
  1776  	if u.Uvv.CachedAt < v.Uvv.CachedAt {
  1777  		return true
  1778  	}
  1779  	return false
  1780  }
  1781  
  1782  func (u UserPlusKeysV2AllIncarnations) AllDeviceNames() []string {
  1783  	var names []string
  1784  
  1785  	for _, k := range u.Current.DeviceKeys {
  1786  		if k.DeviceDescription != "" {
  1787  			names = append(names, k.DeviceDescription)
  1788  		}
  1789  	}
  1790  	for _, v := range u.PastIncarnations {
  1791  		for _, k := range v.DeviceKeys {
  1792  			if k.DeviceDescription != "" {
  1793  				names = append(names, k.DeviceDescription)
  1794  			}
  1795  		}
  1796  	}
  1797  
  1798  	return names
  1799  }
  1800  
  1801  func (ut UserOrTeamID) String() string {
  1802  	return string(ut)
  1803  }
  1804  
  1805  func (ut UserOrTeamID) ToBytes() []byte {
  1806  	b, err := hex.DecodeString(string(ut))
  1807  	if err != nil {
  1808  		return nil
  1809  	}
  1810  	return b
  1811  }
  1812  
  1813  func (ut UserOrTeamID) IsNil() bool {
  1814  	return len(ut) == 0
  1815  }
  1816  
  1817  func (ut UserOrTeamID) Exists() bool {
  1818  	return !ut.IsNil()
  1819  }
  1820  
  1821  func (ut UserOrTeamID) Equal(v UserOrTeamID) bool {
  1822  	return ut == v
  1823  }
  1824  
  1825  func (ut UserOrTeamID) NotEqual(v UserOrTeamID) bool {
  1826  	return !ut.Equal(v)
  1827  }
  1828  
  1829  func (ut UserOrTeamID) Less(v UserOrTeamID) bool {
  1830  	return ut < v
  1831  }
  1832  
  1833  func (ut UserOrTeamID) AsUser() (UID, error) {
  1834  	if !ut.IsUser() {
  1835  		return UID(""), errors.New("ID is not a UID")
  1836  	}
  1837  	return UID(ut), nil
  1838  }
  1839  
  1840  func (ut UserOrTeamID) AsUserOrBust() UID {
  1841  	uid, err := ut.AsUser()
  1842  	if err != nil {
  1843  		panic(err)
  1844  	}
  1845  	return uid
  1846  }
  1847  
  1848  func (ut UserOrTeamID) IsPublic() bool {
  1849  	if ut.IsUser() {
  1850  		return true
  1851  	}
  1852  	return ut.AsTeamOrBust().IsPublic()
  1853  }
  1854  
  1855  func (ut UserOrTeamID) AsTeam() (TeamID, error) {
  1856  	if !ut.IsTeamOrSubteam() {
  1857  		return TeamID(""), fmt.Errorf("ID is not a team ID (%s)", ut)
  1858  	}
  1859  	return TeamID(ut), nil
  1860  }
  1861  
  1862  func (ut UserOrTeamID) AsTeamOrBust() TeamID {
  1863  	tid, err := ut.AsTeam()
  1864  	if err != nil {
  1865  		panic(err)
  1866  	}
  1867  	return tid
  1868  }
  1869  
  1870  func (ut UserOrTeamID) Compare(ut2 UserOrTeamID) int {
  1871  	return strings.Compare(string(ut), string(ut2))
  1872  }
  1873  
  1874  func (ut UserOrTeamID) IsUser() bool {
  1875  	i := idSchema{
  1876  		length:        UID_LEN,
  1877  		magicSuffixes: map[byte]bool{UID_SUFFIX: true, UID_SUFFIX_2: true},
  1878  		typeHint:      "user id",
  1879  	}
  1880  	return i.check(string(ut)) == nil
  1881  }
  1882  
  1883  func (ut UserOrTeamID) IsTeam() bool {
  1884  	i := idSchema{
  1885  		length:        TEAMID_LEN,
  1886  		magicSuffixes: map[byte]bool{TEAMID_PRIVATE_SUFFIX: true, TEAMID_PUBLIC_SUFFIX: true},
  1887  		typeHint:      "team id",
  1888  	}
  1889  	return i.check(string(ut)) == nil
  1890  }
  1891  
  1892  func (ut UserOrTeamID) IsSubteam() bool {
  1893  	i := idSchema{
  1894  		length:        TEAMID_LEN,
  1895  		magicSuffixes: map[byte]bool{SUB_TEAMID_PRIVATE_SUFFIX: true, SUB_TEAMID_PUBLIC_SUFFIX: true},
  1896  		typeHint:      "subteam id",
  1897  	}
  1898  	return i.check(string(ut)) == nil
  1899  }
  1900  
  1901  func (ut UserOrTeamID) IsTeamOrSubteam() bool {
  1902  	return ut.IsTeam() || ut.IsSubteam()
  1903  }
  1904  
  1905  func (ut UserOrTeamID) IsValidID() bool {
  1906  	return ut.IsUser() || ut.IsTeamOrSubteam()
  1907  }
  1908  
  1909  // Preconditions:
  1910  //
  1911  //		-first four bits (in Little Endian) of UserOrTeamID are
  1912  //		 	independent and uniformly distributed
  1913  //		-UserOrTeamID must have an even number of bits, or this will always
  1914  //	  	return 0
  1915  //
  1916  // Returns a number in [0, shardCount) which can be treated as roughly
  1917  // uniformly distributed. Used for things that need to shard by user.
  1918  func (ut UserOrTeamID) GetShard(shardCount int) (int, error) {
  1919  	if !ut.IsValidID() {
  1920  		return 0, fmt.Errorf("Bad ID, does not match any known valid type")
  1921  	}
  1922  	bytes, err := hex.DecodeString(string(ut))
  1923  	if err != nil {
  1924  		return 0, err
  1925  	}
  1926  	// LittleEndian.Uint32 truncates to obtain 4 bytes from the buffer
  1927  	n := binary.LittleEndian.Uint32(bytes)
  1928  	return int(n % uint32(shardCount)), nil
  1929  }
  1930  
  1931  // Size implements the cache.Measurable interface.
  1932  func (ut UserOrTeamID) Size() int {
  1933  	return len(ut) + ptrSize
  1934  }
  1935  
  1936  func (m *MaskB64) UnmarshalJSON(b []byte) error {
  1937  	unquoted := UnquoteBytes(b)
  1938  	if len(unquoted) == 0 {
  1939  		return nil
  1940  	}
  1941  	dbuf := make([]byte, base64.StdEncoding.DecodedLen(len(unquoted)))
  1942  	n, err := base64.StdEncoding.Decode(dbuf, unquoted)
  1943  	if err != nil {
  1944  		return err
  1945  	}
  1946  	*m = MaskB64(dbuf[:n])
  1947  	return nil
  1948  }
  1949  
  1950  func (m *MaskB64) MarshalJSON() ([]byte, error) {
  1951  	s := Quote(base64.StdEncoding.EncodeToString([]byte(*m)))
  1952  	return s, nil
  1953  }
  1954  
  1955  func PublicKeyV1FromPGPKeyV2(keyV2 PublicKeyV2PGPSummary) PublicKey {
  1956  	return PublicKey{
  1957  		KID:            keyV2.Base.Kid,
  1958  		PGPFingerprint: hex.EncodeToString(keyV2.Fingerprint[:]),
  1959  		PGPIdentities:  keyV2.Identities,
  1960  		IsSibkey:       keyV2.Base.IsSibkey,
  1961  		IsEldest:       keyV2.Base.IsEldest,
  1962  		CTime:          keyV2.Base.CTime,
  1963  		ETime:          keyV2.Base.ETime,
  1964  		IsRevoked:      (keyV2.Base.Revocation != nil),
  1965  	}
  1966  }
  1967  
  1968  func PublicKeyV1FromDeviceKeyV2(keyV2 PublicKeyV2NaCl) PublicKey {
  1969  	parentID := ""
  1970  	if keyV2.Parent != nil {
  1971  		parentID = string(*keyV2.Parent)
  1972  	}
  1973  	return PublicKey{
  1974  		KID:               keyV2.Base.Kid,
  1975  		IsSibkey:          keyV2.Base.IsSibkey,
  1976  		IsEldest:          keyV2.Base.IsEldest,
  1977  		ParentID:          parentID,
  1978  		DeviceID:          keyV2.DeviceID,
  1979  		DeviceDescription: keyV2.DeviceDescription,
  1980  		DeviceType:        keyV2.DeviceType,
  1981  		CTime:             keyV2.Base.CTime,
  1982  		ETime:             keyV2.Base.ETime,
  1983  		IsRevoked:         (keyV2.Base.Revocation != nil),
  1984  	}
  1985  }
  1986  
  1987  const (
  1988  	DeviceTypeV2_NONE    DeviceTypeV2 = "none"
  1989  	DeviceTypeV2_PAPER   DeviceTypeV2 = "backup"
  1990  	DeviceTypeV2_DESKTOP DeviceTypeV2 = "desktop"
  1991  	DeviceTypeV2_MOBILE  DeviceTypeV2 = "mobile"
  1992  )
  1993  
  1994  func (d DeviceTypeV2) String() string {
  1995  	return string(d)
  1996  }
  1997  
  1998  func StringToDeviceTypeV2(s string) (d DeviceTypeV2, err error) {
  1999  	deviceType := DeviceTypeV2(s)
  2000  	switch deviceType {
  2001  	case DeviceTypeV2_NONE, DeviceTypeV2_DESKTOP, DeviceTypeV2_MOBILE, DeviceTypeV2_PAPER:
  2002  		// pass
  2003  	default:
  2004  		return DeviceTypeV2_NONE, fmt.Errorf("Unknown DeviceType: %s", deviceType)
  2005  	}
  2006  	return deviceType, nil
  2007  }
  2008  
  2009  // defaults to Desktop
  2010  func (dt *DeviceTypeV2) ToDeviceType() DeviceType {
  2011  	if *dt == DeviceTypeV2_MOBILE {
  2012  		return DeviceType_MOBILE
  2013  	}
  2014  	return DeviceType_DESKTOP
  2015  }
  2016  
  2017  func RevokedKeyV1FromDeviceKeyV2(keyV2 PublicKeyV2NaCl) RevokedKey {
  2018  	return RevokedKey{
  2019  		Key: PublicKeyV1FromDeviceKeyV2(keyV2),
  2020  		Time: KeybaseTime{
  2021  			Unix:  keyV2.Base.Revocation.Time,
  2022  			Chain: keyV2.Base.Revocation.PrevMerkleRootSigned.Seqno,
  2023  		},
  2024  		By: keyV2.Base.Revocation.SigningKID,
  2025  	}
  2026  }
  2027  
  2028  // UPKV2 should supersede UPAK eventually, but lots of older code requires
  2029  // UPAK. This is a simple converter function.
  2030  func UPAKFromUPKV2AI(uV2 UserPlusKeysV2AllIncarnations) UserPlusAllKeys {
  2031  	// Convert the PGP keys.
  2032  	var pgpKeysV1 []PublicKey
  2033  	for _, keyV2 := range uV2.Current.PGPKeys {
  2034  		pgpKeysV1 = append(pgpKeysV1, PublicKeyV1FromPGPKeyV2(keyV2))
  2035  	}
  2036  
  2037  	// Convert the device keys.
  2038  	var deviceKeysV1 []PublicKey
  2039  	var revokedDeviceKeysV1 []RevokedKey
  2040  	var resets []ResetSummary
  2041  	for _, keyV2 := range uV2.Current.DeviceKeys {
  2042  		if keyV2.Base.Revocation != nil {
  2043  			revokedDeviceKeysV1 = append(revokedDeviceKeysV1, RevokedKeyV1FromDeviceKeyV2(keyV2))
  2044  		} else {
  2045  			deviceKeysV1 = append(deviceKeysV1, PublicKeyV1FromDeviceKeyV2(keyV2))
  2046  		}
  2047  	}
  2048  	sort.Slice(deviceKeysV1, func(i, j int) bool { return deviceKeysV1[i].KID < deviceKeysV1[j].KID })
  2049  	sort.Slice(revokedDeviceKeysV1, func(i, j int) bool { return revokedDeviceKeysV1[i].Key.KID < revokedDeviceKeysV1[j].Key.KID })
  2050  
  2051  	// Assemble the deleted device keys from past incarnations.
  2052  	var deletedDeviceKeysV1 []PublicKey
  2053  	for _, incarnation := range uV2.PastIncarnations {
  2054  		for _, keyV2 := range incarnation.DeviceKeys {
  2055  			deletedDeviceKeysV1 = append(deletedDeviceKeysV1, PublicKeyV1FromDeviceKeyV2(keyV2))
  2056  		}
  2057  		if reset := incarnation.Reset; reset != nil {
  2058  			resets = append(resets, *reset)
  2059  		}
  2060  	}
  2061  	sort.Slice(deletedDeviceKeysV1, func(i, j int) bool { return deletedDeviceKeysV1[i].KID < deletedDeviceKeysV1[j].KID })
  2062  
  2063  	// List and sort the remote tracks. Note that they *must* be sorted.
  2064  	var remoteTracks []RemoteTrack
  2065  	for _, track := range uV2.Current.RemoteTracks {
  2066  		remoteTracks = append(remoteTracks, track)
  2067  	}
  2068  	sort.Slice(remoteTracks, func(i, j int) bool { return remoteTracks[i].Username < remoteTracks[j].Username })
  2069  
  2070  	// Apart from all the key mangling above, everything else is just naming
  2071  	// and layout changes. Assemble the final UPAK.
  2072  	return UserPlusAllKeys{
  2073  		Base: UserPlusKeys{
  2074  			Uid:               uV2.Current.Uid,
  2075  			Username:          uV2.Current.Username,
  2076  			EldestSeqno:       uV2.Current.EldestSeqno,
  2077  			Status:            uV2.Current.Status,
  2078  			DeviceKeys:        deviceKeysV1,
  2079  			RevokedDeviceKeys: revokedDeviceKeysV1,
  2080  			DeletedDeviceKeys: deletedDeviceKeysV1,
  2081  			PGPKeyCount:       len(pgpKeysV1),
  2082  			Uvv:               uV2.Uvv,
  2083  			PerUserKeys:       uV2.Current.PerUserKeys,
  2084  			Resets:            resets,
  2085  		},
  2086  		PGPKeys:      pgpKeysV1,
  2087  		RemoteTracks: remoteTracks,
  2088  	}
  2089  }
  2090  
  2091  func (u UserVersionPercentForm) String() string {
  2092  	return string(u)
  2093  }
  2094  
  2095  func NewUserVersion(uid UID, eldestSeqno Seqno) UserVersion {
  2096  	return UserVersion{
  2097  		Uid:         uid,
  2098  		EldestSeqno: eldestSeqno,
  2099  	}
  2100  }
  2101  
  2102  func (u UserVersion) PercentForm() UserVersionPercentForm {
  2103  	return UserVersionPercentForm(u.String())
  2104  }
  2105  
  2106  func (u UserVersion) String() string {
  2107  	return fmt.Sprintf("%s%%%d", u.Uid, u.EldestSeqno)
  2108  }
  2109  
  2110  func (u UserVersion) Eq(v UserVersion) bool {
  2111  	return u.Uid.Equal(v.Uid) && u.EldestSeqno.Eq(v.EldestSeqno)
  2112  }
  2113  
  2114  func (u UserVersion) TeamInviteName() TeamInviteName {
  2115  	return TeamInviteName(u.PercentForm())
  2116  }
  2117  
  2118  func (u UserVersion) IsNil() bool {
  2119  	return u.Uid.IsNil()
  2120  }
  2121  
  2122  type ByUserVersionID []UserVersion
  2123  
  2124  func (b ByUserVersionID) Len() int      { return len(b) }
  2125  func (b ByUserVersionID) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
  2126  func (b ByUserVersionID) Less(i, j int) bool {
  2127  	return b[i].String() < b[j].String()
  2128  }
  2129  
  2130  func (k CryptKey) Material() Bytes32 {
  2131  	return k.Key
  2132  }
  2133  
  2134  func (k CryptKey) Generation() int {
  2135  	return k.KeyGeneration
  2136  }
  2137  
  2138  func (k TeamApplicationKey) Material() Bytes32 {
  2139  	return k.Key
  2140  }
  2141  
  2142  func (k TeamApplicationKey) Generation() int {
  2143  	return int(k.KeyGeneration)
  2144  }
  2145  
  2146  func (t TeamMembers) AllUIDs() []UID {
  2147  	m := make(map[UID]bool)
  2148  	for _, u := range t.Owners {
  2149  		m[u.Uid] = true
  2150  	}
  2151  	for _, u := range t.Admins {
  2152  		m[u.Uid] = true
  2153  	}
  2154  	for _, u := range t.Writers {
  2155  		m[u.Uid] = true
  2156  	}
  2157  	for _, u := range t.Readers {
  2158  		m[u.Uid] = true
  2159  	}
  2160  	for _, u := range t.Bots {
  2161  		m[u.Uid] = true
  2162  	}
  2163  	for _, u := range t.RestrictedBots {
  2164  		m[u.Uid] = true
  2165  	}
  2166  	var all []UID
  2167  	for u := range m {
  2168  		all = append(all, u)
  2169  	}
  2170  	return all
  2171  }
  2172  
  2173  func (t TeamMembers) AllUserVersions() []UserVersion {
  2174  	m := make(map[UID]UserVersion)
  2175  	for _, u := range t.Owners {
  2176  		m[u.Uid] = u
  2177  	}
  2178  	for _, u := range t.Admins {
  2179  		m[u.Uid] = u
  2180  	}
  2181  	for _, u := range t.Writers {
  2182  		m[u.Uid] = u
  2183  	}
  2184  	for _, u := range t.Readers {
  2185  		m[u.Uid] = u
  2186  	}
  2187  	for _, u := range t.Bots {
  2188  		m[u.Uid] = u
  2189  	}
  2190  	for _, u := range t.RestrictedBots {
  2191  		m[u.Uid] = u
  2192  	}
  2193  	var all []UserVersion
  2194  	for _, uv := range m {
  2195  		all = append(all, uv)
  2196  	}
  2197  	return all
  2198  }
  2199  
  2200  func (s TeamMemberStatus) IsActive() bool {
  2201  	return s == TeamMemberStatus_ACTIVE
  2202  }
  2203  
  2204  func (s TeamMemberStatus) IsReset() bool {
  2205  	return s == TeamMemberStatus_RESET
  2206  }
  2207  
  2208  func (s TeamMemberStatus) IsDeleted() bool {
  2209  	return s == TeamMemberStatus_DELETED
  2210  }
  2211  
  2212  func FilterInactiveReadersWriters(arg []TeamMemberDetails) (ret []TeamMemberDetails) {
  2213  	for _, v := range arg {
  2214  		if v.Status.IsActive() || (v.Role != TeamRole_READER && v.Role != TeamRole_WRITER) {
  2215  			ret = append(ret, v)
  2216  		}
  2217  	}
  2218  	return ret
  2219  }
  2220  
  2221  func (t TeamName) IsNil() bool {
  2222  	return len(t.Parts) == 0
  2223  }
  2224  
  2225  // underscores allowed, just not first or doubled
  2226  var namePartRxx = regexp.MustCompile(`^([a-zA-Z0-9][a-zA-Z0-9_]?)+$`)
  2227  var implicitRxxString = fmt.Sprintf("^%s[0-9a-f]{%d}$", ImplicitTeamPrefix, ImplicitSuffixLengthBytes*2)
  2228  var implicitNameRxx = regexp.MustCompile(implicitRxxString)
  2229  
  2230  const ImplicitTeamPrefix = "__keybase_implicit_team__"
  2231  const ImplicitSuffixLengthBytes = 16
  2232  
  2233  func stringToTeamNamePart(s string) TeamNamePart {
  2234  	return TeamNamePart(strings.ToLower(s))
  2235  }
  2236  
  2237  func rootTeamNameFromString(s string) (TeamName, error) {
  2238  	if implicitNameRxx.MatchString(s) {
  2239  		return TeamName{Parts: []TeamNamePart{stringToTeamNamePart(s)}}, nil
  2240  	}
  2241  	if err := validatePart(s); err != nil {
  2242  		return TeamName{}, err
  2243  	}
  2244  	return TeamName{Parts: []TeamNamePart{stringToTeamNamePart(s)}}, nil
  2245  }
  2246  
  2247  func validatePart(s string) (err error) {
  2248  	if len(s) == 0 {
  2249  		return errors.New("team names cannot be empty")
  2250  	}
  2251  	if !(len(s) >= 2 && len(s) <= 16) {
  2252  		return errors.New("team names must be between 2 and 16 characters long")
  2253  	}
  2254  	if !namePartRxx.MatchString(s) {
  2255  		return errors.New("Keybase team names must be letters (a-z), numbers, and underscores. Also, they can't start with underscores or use double underscores, to avoid confusion.")
  2256  	}
  2257  	return nil
  2258  }
  2259  
  2260  func TeamNameFromString(s string) (TeamName, error) {
  2261  	ret := TeamName{}
  2262  
  2263  	s = strings.ToLower(s)
  2264  	parts := strings.Split(s, ".")
  2265  	if len(parts) == 0 {
  2266  		return ret, errors.New("team names cannot be empty")
  2267  	}
  2268  	if len(parts) == 1 {
  2269  		return rootTeamNameFromString(s)
  2270  	}
  2271  	tmp := make([]TeamNamePart, len(parts))
  2272  	for i, part := range parts {
  2273  		err := validatePart(part)
  2274  		if err != nil {
  2275  			return TeamName{}, fmt.Errorf("Could not parse name as team; bad name component %q: %s", part, err.Error())
  2276  		}
  2277  		tmp[i] = stringToTeamNamePart(part)
  2278  	}
  2279  	return TeamName{Parts: tmp}, nil
  2280  }
  2281  
  2282  func (p TeamNamePart) String() string {
  2283  	return string(p)
  2284  }
  2285  
  2286  func (t TeamName) AssertEqString(s string) error {
  2287  	tmp, err := TeamNameFromString(s)
  2288  	if err != nil {
  2289  		return err
  2290  	}
  2291  	if !t.Eq(tmp) {
  2292  		return fmt.Errorf("Team equality check failed: %s != %s", t.String(), s)
  2293  	}
  2294  	return nil
  2295  }
  2296  
  2297  func (t TeamName) String() string {
  2298  	tmp := make([]string, len(t.Parts))
  2299  	for i, p := range t.Parts {
  2300  		tmp[i] = strings.ToLower(string(p))
  2301  	}
  2302  	return strings.Join(tmp, ".")
  2303  }
  2304  
  2305  func (t TeamName) Eq(t2 TeamName) bool {
  2306  	return t.String() == t2.String()
  2307  }
  2308  
  2309  func (t TeamName) IsRootTeam() bool {
  2310  	return len(t.Parts) == 1
  2311  }
  2312  
  2313  func (t TeamName) ToPrivateTeamID() TeamID {
  2314  	return t.ToTeamID(false)
  2315  }
  2316  
  2317  func (t TeamName) ToPublicTeamID() TeamID {
  2318  	return t.ToTeamID(true)
  2319  }
  2320  
  2321  // Get the top level team id for this team name.
  2322  // Only makes sense for non-sub teams.
  2323  // The first 15 bytes of the sha256 of the lowercase team name,
  2324  // followed by the byte 0x24, encoded as hex.
  2325  func (t TeamName) ToTeamID(public bool) TeamID {
  2326  	low := strings.ToLower(t.String())
  2327  	sum := sha256.Sum256([]byte(low))
  2328  	var useSuffix byte = TEAMID_PRIVATE_SUFFIX
  2329  	if public {
  2330  		useSuffix = TEAMID_PUBLIC_SUFFIX
  2331  	}
  2332  	bs := append(sum[:15], useSuffix)
  2333  	res, err := TeamIDFromString(hex.EncodeToString(bs))
  2334  	if err != nil {
  2335  		panic(err)
  2336  	}
  2337  	return res
  2338  }
  2339  
  2340  // Return a new team name with the part added to the end.
  2341  // For example {foo.bar}.Append(baz) -> {foo.bar.baz}
  2342  func (t TeamName) Append(part string) (t3 TeamName, err error) {
  2343  	t2 := t.DeepCopy()
  2344  	t2.Parts = append(t2.Parts, TeamNamePart(part))
  2345  	t3, err = TeamNameFromString(t2.String())
  2346  	return t3, err
  2347  }
  2348  
  2349  func (t TeamName) LastPart() TeamNamePart {
  2350  	return t.Parts[len(t.Parts)-1]
  2351  }
  2352  
  2353  func (t TeamName) RootAncestorName() TeamName {
  2354  	if len(t.Parts) == 0 {
  2355  		// this should never happen
  2356  		return TeamName{}
  2357  	}
  2358  	return TeamName{
  2359  		Parts: t.Parts[:1],
  2360  	}
  2361  }
  2362  
  2363  func (t TeamName) RootID() TeamID {
  2364  	return t.RootAncestorName().ToTeamID(false)
  2365  }
  2366  
  2367  func (t TeamName) Parent() (TeamName, error) {
  2368  	if len(t.Parts) == 0 {
  2369  		return t, fmt.Errorf("empty team name")
  2370  	}
  2371  	if t.IsRootTeam() {
  2372  		return t, fmt.Errorf("root team has no parent")
  2373  	}
  2374  	return TeamName{
  2375  		Parts: t.Parts[:len(t.Parts)-1],
  2376  	}, nil
  2377  }
  2378  
  2379  func (t TeamName) SwapLastPart(newLast string) (TeamName, error) {
  2380  	parent, err := t.Parent()
  2381  	if err != nil {
  2382  		return t, err
  2383  	}
  2384  	return parent.Append(newLast)
  2385  }
  2386  
  2387  func (t TeamName) IsImplicit() bool {
  2388  	return strings.HasPrefix(t.String(), ImplicitTeamPrefix)
  2389  }
  2390  
  2391  // The number of parts in a team name.
  2392  // Root teams have 1.
  2393  func (t TeamName) Depth() int {
  2394  	return len(t.Parts)
  2395  }
  2396  
  2397  func (t TeamName) IsAncestorOf(other TeamName) bool {
  2398  	depth := t.Depth()
  2399  	if depth >= other.Depth() {
  2400  		return false
  2401  	}
  2402  
  2403  	for i := 0; i < depth; i++ {
  2404  		if !other.Parts[i].Eq(t.Parts[i]) {
  2405  			return false
  2406  		}
  2407  	}
  2408  
  2409  	return true
  2410  }
  2411  
  2412  func (t TeamNamePart) Eq(t2 TeamNamePart) bool {
  2413  	return string(t) == string(t2)
  2414  }
  2415  
  2416  func (u UserPlusKeys) ToUserVersion() UserVersion {
  2417  	return UserVersion{
  2418  		Uid:         u.Uid,
  2419  		EldestSeqno: u.EldestSeqno,
  2420  	}
  2421  }
  2422  
  2423  func (u UserPlusKeysV2) ToUserVersion() UserVersion {
  2424  	return UserVersion{
  2425  		Uid:         u.Uid,
  2426  		EldestSeqno: u.EldestSeqno,
  2427  	}
  2428  }
  2429  
  2430  func (u UserPlusKeysV2AllIncarnations) ToUserVersion() UserVersion {
  2431  	return u.Current.ToUserVersion()
  2432  }
  2433  
  2434  func (u UserPlusKeysV2AllIncarnations) GetPerUserKeyAtSeqno(uv UserVersion, seqno Seqno, merkleSeqno Seqno) (*PerUserKey, error) {
  2435  	incarnations := u.AllIncarnations()
  2436  	for _, incarnation := range incarnations {
  2437  		if incarnation.EldestSeqno == uv.EldestSeqno {
  2438  			if incarnation.Reset != nil && incarnation.Reset.MerkleRoot.Seqno <= merkleSeqno {
  2439  				return nil, nil
  2440  			}
  2441  			if len(incarnation.PerUserKeys) == 0 {
  2442  				return nil, nil
  2443  			}
  2444  			for i := range incarnation.PerUserKeys {
  2445  				perUserKey := incarnation.PerUserKeys[len(incarnation.PerUserKeys)-1-i]
  2446  				if perUserKey.Seqno <= seqno {
  2447  					return &perUserKey, nil
  2448  				}
  2449  			}
  2450  			return nil, fmt.Errorf("didn't find per user key at seqno %d for uv %v", seqno, uv)
  2451  		}
  2452  	}
  2453  	return nil, fmt.Errorf("didn't find uv %v in upak", uv)
  2454  }
  2455  
  2456  // Can return nil.
  2457  func (u UserPlusKeysV2) GetLatestPerUserKey() *PerUserKey {
  2458  	if len(u.PerUserKeys) > 0 {
  2459  		return &u.PerUserKeys[len(u.PerUserKeys)-1]
  2460  	}
  2461  	return nil
  2462  }
  2463  
  2464  // Can return nil.
  2465  func (u UserPlusKeysV2) GetPerUserKeyByGen(gen PerUserKeyGeneration) *PerUserKey {
  2466  	genint := int(gen)
  2467  	if genint <= 0 || genint > len(u.PerUserKeys) {
  2468  		return nil
  2469  	}
  2470  	puk := u.PerUserKeys[genint-1]
  2471  	if puk.Gen != genint {
  2472  		// The PerUserKeys field of this object is malformed
  2473  		return nil
  2474  	}
  2475  	return &puk
  2476  }
  2477  
  2478  func (s PerTeamKeySeed) ToBytes() []byte { return s[:] }
  2479  
  2480  func (s PerTeamKeySeed) IsZero() bool {
  2481  	var tmp PerTeamKeySeed
  2482  	return hmac.Equal(s[:], tmp[:])
  2483  }
  2484  
  2485  func PerTeamKeySeedFromBytes(b []byte) (PerTeamKeySeed, error) {
  2486  	var ret PerTeamKeySeed
  2487  	if len(b) != len(ret) {
  2488  		return PerTeamKeySeed{}, fmt.Errorf("decrypt yielded a bad-sized team secret: %d != %d", len(b), len(ret))
  2489  	}
  2490  	copy(ret[:], b)
  2491  	return ret, nil
  2492  }
  2493  
  2494  func (s SigChainLocation) Eq(s2 SigChainLocation) bool {
  2495  	return s.Seqno == s2.Seqno && s.SeqType == s2.SeqType
  2496  }
  2497  
  2498  func (s SigChainLocation) LessThanOrEqualTo(s2 SigChainLocation) bool {
  2499  	return s.SeqType == s2.SeqType && s.Seqno <= s2.Seqno
  2500  }
  2501  
  2502  func (s SigChainLocation) Comparable(s2 SigChainLocation) error {
  2503  	if s.SeqType != s2.SeqType {
  2504  		return fmt.Errorf("mismatched seqtypes: %v != %v", s.SeqType, s2.SeqType)
  2505  	}
  2506  	return nil
  2507  }
  2508  
  2509  func (s SigChainLocation) Sub1() SigChainLocation {
  2510  	return SigChainLocation{
  2511  		Seqno:   s.Seqno - 1,
  2512  		SeqType: s.SeqType,
  2513  	}
  2514  }
  2515  
  2516  func (r TeamRole) IsAdminOrAbove() bool {
  2517  	return r.IsOrAbove(TeamRole_ADMIN)
  2518  }
  2519  
  2520  func (r TeamRole) IsWriterOrAbove() bool {
  2521  	return r.IsOrAbove(TeamRole_WRITER)
  2522  }
  2523  
  2524  func (r TeamRole) IsReaderOrAbove() bool {
  2525  	return r.IsOrAbove(TeamRole_READER)
  2526  }
  2527  
  2528  func (r TeamRole) IsBotOrAbove() bool {
  2529  	return r.IsOrAbove(TeamRole_BOT)
  2530  }
  2531  
  2532  func (r TeamRole) IsRestrictedBotOrAbove() bool {
  2533  	return r.IsOrAbove(TeamRole_RESTRICTEDBOT)
  2534  }
  2535  
  2536  func (r TeamRole) IsBotLike() bool {
  2537  	switch r {
  2538  	case TeamRole_BOT, TeamRole_RESTRICTEDBOT:
  2539  		return true
  2540  	}
  2541  	return false
  2542  }
  2543  
  2544  func (r TeamRole) IsRestrictedBot() bool {
  2545  	return r == TeamRole_RESTRICTEDBOT
  2546  }
  2547  
  2548  func (r TeamRole) teamRoleForOrderingOnly() int {
  2549  	switch r {
  2550  	case TeamRole_NONE:
  2551  		return 0
  2552  	case TeamRole_RESTRICTEDBOT:
  2553  		return 1
  2554  	case TeamRole_BOT:
  2555  		return 2
  2556  	case TeamRole_READER,
  2557  		TeamRole_WRITER,
  2558  		TeamRole_ADMIN,
  2559  		TeamRole_OWNER:
  2560  		return int(r) + 2
  2561  	default:
  2562  		return 0
  2563  	}
  2564  }
  2565  
  2566  func (r TeamRole) IsOrAbove(min TeamRole) bool {
  2567  	return r.teamRoleForOrderingOnly() >= min.teamRoleForOrderingOnly()
  2568  }
  2569  
  2570  func (r TeamRole) HumanString() string {
  2571  	if r.IsRestrictedBot() {
  2572  		return "restricted bot"
  2573  	}
  2574  	return strings.ToLower(r.String())
  2575  }
  2576  
  2577  type idSchema struct {
  2578  	length        int
  2579  	magicSuffixes map[byte]bool
  2580  	typeHint      string
  2581  }
  2582  
  2583  func (i idSchema) check(s string) error {
  2584  	xs, err := hex.DecodeString(s)
  2585  	if err != nil {
  2586  		return err
  2587  	}
  2588  	if len(xs) != i.length {
  2589  		return fmt.Errorf("%s: Wrong ID length (got %d)", i.typeHint, len(xs))
  2590  	}
  2591  	suffix := xs[len(xs)-1]
  2592  	if !i.magicSuffixes[suffix] {
  2593  		return fmt.Errorf("%s: Incorrect suffix byte (got 0x%x)", i.typeHint, suffix)
  2594  	}
  2595  	return nil
  2596  }
  2597  
  2598  func TeamInviteIDFromString(s string) (TeamInviteID, error) {
  2599  	if err := (idSchema{16, map[byte]bool{0x27: true}, "team invite ID"}).check(s); err != nil {
  2600  		return TeamInviteID(""), err
  2601  	}
  2602  	return TeamInviteID(s), nil
  2603  }
  2604  
  2605  func (i TeamInviteID) Eq(i2 TeamInviteID) bool {
  2606  	return string(i) == string(i2)
  2607  }
  2608  
  2609  func (t TeamInviteType) String() (string, error) {
  2610  	c, err := t.C()
  2611  	if err != nil {
  2612  		return "", err
  2613  	}
  2614  	switch c {
  2615  	case TeamInviteCategory_KEYBASE:
  2616  		return "keybase", nil
  2617  	case TeamInviteCategory_EMAIL:
  2618  		return "email", nil
  2619  	case TeamInviteCategory_PHONE:
  2620  		return "phone", nil
  2621  	case TeamInviteCategory_SBS:
  2622  		return string(t.Sbs()), nil
  2623  	case TeamInviteCategory_SEITAN:
  2624  		return "seitan_invite_token", nil
  2625  	case TeamInviteCategory_UNKNOWN:
  2626  		return t.Unknown(), nil
  2627  	}
  2628  
  2629  	return "", nil
  2630  }
  2631  
  2632  func (a TeamInviteType) Eq(b TeamInviteType) bool {
  2633  	ac, err := a.C()
  2634  	if err != nil {
  2635  		return false
  2636  	}
  2637  	bc, err := b.C()
  2638  	if err != nil {
  2639  		return false
  2640  	}
  2641  	if ac != bc {
  2642  		return false
  2643  	}
  2644  
  2645  	switch ac {
  2646  	case TeamInviteCategory_KEYBASE:
  2647  		return true
  2648  	case TeamInviteCategory_EMAIL, TeamInviteCategory_PHONE:
  2649  		return true
  2650  	case TeamInviteCategory_SBS:
  2651  		return a.Sbs() == b.Sbs()
  2652  	case TeamInviteCategory_UNKNOWN:
  2653  		return a.Unknown() == b.Unknown()
  2654  	}
  2655  
  2656  	return false
  2657  }
  2658  
  2659  func (t TeamInvite) KeybaseUserVersion() (UserVersion, error) {
  2660  	category, err := t.Type.C()
  2661  	if err != nil {
  2662  		return UserVersion{}, err
  2663  	}
  2664  	if category != TeamInviteCategory_KEYBASE {
  2665  		return UserVersion{}, errors.New("KeybaseUserVersion: invalid invite category, must be keybase")
  2666  	}
  2667  
  2668  	return ParseUserVersion(UserVersionPercentForm(t.Name))
  2669  }
  2670  
  2671  // TeamMaxUsesInfinite is a value for max_uses field which makes team invite
  2672  // multiple use, with infinite number of uses.
  2673  const TeamMaxUsesInfinite = TeamInviteMaxUses(-1)
  2674  
  2675  func NewTeamInviteFiniteUses(maxUses int) (v TeamInviteMaxUses, err error) {
  2676  	if maxUses <= 0 {
  2677  		return v, errors.New("non-infinite uses with nonpositive maxUses")
  2678  	}
  2679  	return TeamInviteMaxUses(maxUses), nil
  2680  }
  2681  
  2682  func (e *TeamInviteMaxUses) IsNotNilAndValid() bool {
  2683  	return e != nil && (*e > 0 || *e == TeamMaxUsesInfinite)
  2684  }
  2685  
  2686  func max(a, b int) int {
  2687  	if a >= b {
  2688  		return a
  2689  	}
  2690  	return b
  2691  }
  2692  
  2693  func (ti TeamInvite) UsesLeftString(alreadyUsed int) string {
  2694  	if ti.IsInfiniteUses() {
  2695  		return "unlimited uses left"
  2696  	}
  2697  	var maxUses int
  2698  	if ti.MaxUses == nil {
  2699  		maxUses = 1
  2700  	} else {
  2701  		maxUses = int(*ti.MaxUses)
  2702  	}
  2703  	return formatItems("use", "uses", max(maxUses-alreadyUsed, 0))
  2704  }
  2705  
  2706  func (ti TeamInvite) IsInfiniteUses() bool {
  2707  	return ti.MaxUses != nil && *ti.MaxUses == TeamMaxUsesInfinite
  2708  }
  2709  
  2710  func (ti TeamInvite) IsUsedUp(alreadyUsed int) bool {
  2711  	maxUses := ti.MaxUses
  2712  	if maxUses == nil {
  2713  		return alreadyUsed >= 1
  2714  	}
  2715  	if *maxUses == TeamMaxUsesInfinite {
  2716  		return false
  2717  	}
  2718  	return alreadyUsed >= int(*maxUses)
  2719  }
  2720  
  2721  func (ti TeamInvite) IsExpired(now time.Time) bool {
  2722  	if ti.Etime == nil {
  2723  		return false
  2724  	}
  2725  	etime := FromUnixTime(*ti.Etime)
  2726  	return now.After(etime)
  2727  }
  2728  
  2729  func formatItems(singular string, plural string, count int) string {
  2730  	if count == 1 {
  2731  		return "1 " + singular
  2732  	}
  2733  	return fmt.Sprintf("%d %s", count, plural)
  2734  }
  2735  
  2736  // ComputeValidity is used for invitelinks, but is accurate for other invites as well.
  2737  // It computes whether the invite is still valid (i.e., if it can still be used),
  2738  // and a short description of when it was invalidated or under what conditions it can
  2739  // be later invalidated.
  2740  func (md TeamInviteMetadata) ComputeValidity(now time.Time,
  2741  	userLog map[UserVersion][]UserLogPoint) (isValid bool, validityDescription string) {
  2742  
  2743  	isInvalid := false
  2744  	invalidationAction := ""
  2745  	var invalidationTime *time.Time
  2746  	var usedInviteCount int
  2747  	code, _ := md.Status.Code()
  2748  	switch code {
  2749  	case TeamInviteMetadataStatusCode_ACTIVE:
  2750  		isExpired := md.Invite.IsExpired(now)
  2751  		if isExpired {
  2752  			expireTime := md.Invite.Etime.Time()
  2753  			invalidationTime = &expireTime
  2754  		}
  2755  		usedInvites := md.UsedInvites
  2756  		// If this is an old-style invite that was completed; it wouldn't be ACTIVE anymore,
  2757  		// so we can assume len(usedInvites) is correct, since it should be empty (implying
  2758  		// the invite is not UsedUp.
  2759  		isUsedUp := md.Invite.IsUsedUp(len(usedInvites))
  2760  		if isUsedUp {
  2761  			// implies usedInvites is nonempty
  2762  			usedInvites := md.UsedInvites
  2763  			teamUserLogPoint := usedInvites[len(usedInvites)-1]
  2764  			logPoint := userLog[teamUserLogPoint.Uv][teamUserLogPoint.LogPoint]
  2765  			usedUpTime := logPoint.SigMeta.Time.Time()
  2766  			if invalidationTime == nil || usedUpTime.Before(*invalidationTime) {
  2767  				invalidationTime = &usedUpTime
  2768  			}
  2769  		}
  2770  		if isExpired || isUsedUp {
  2771  			isInvalid = true
  2772  			invalidationAction = "Expired"
  2773  		}
  2774  		usedInviteCount = len(usedInvites)
  2775  	case TeamInviteMetadataStatusCode_OBSOLETE:
  2776  		isInvalid = true
  2777  		invalidationAction = "Obsoleted"
  2778  		// no invalidation time for obsoletes
  2779  		usedInviteCount = 0
  2780  	case TeamInviteMetadataStatusCode_CANCELLED:
  2781  		isInvalid = true
  2782  		invalidationAction = "Cancelled"
  2783  		cancelTime := md.Status.Cancelled().TeamSigMeta.SigMeta.Time.Time()
  2784  		invalidationTime = &cancelTime
  2785  		usedInviteCount = len(md.UsedInvites)
  2786  	case TeamInviteMetadataStatusCode_COMPLETED:
  2787  		isInvalid = true
  2788  		invalidationAction = "Completed"
  2789  		completeTime := md.Status.Completed().TeamSigMeta.SigMeta.Time.Time()
  2790  		invalidationTime = &completeTime
  2791  		usedInviteCount = 1
  2792  	default:
  2793  		return false, fmt.Sprintf("unknown invite status %v", code)
  2794  	}
  2795  
  2796  	if isInvalid {
  2797  		ret := ""
  2798  		ret += invalidationAction
  2799  		if invalidationTime != nil {
  2800  			invalidationDeltaFormatted := kbtime.RelTime(*invalidationTime, now, "", "")
  2801  			ret += " " + invalidationDeltaFormatted + " ago"
  2802  		}
  2803  		return false, ret
  2804  	}
  2805  
  2806  	if md.Invite.Etime == nil && md.Invite.IsInfiniteUses() {
  2807  		return true, "Does not expire"
  2808  	}
  2809  
  2810  	ret := "Expires"
  2811  	if md.Invite.Etime != nil {
  2812  		expirationTimeConverted := FromUnixTime(*md.Invite.Etime)
  2813  		expirationDeltaFormatted := kbtime.RelTime(expirationTimeConverted, now, "", "")
  2814  		ret += " in " + expirationDeltaFormatted
  2815  	}
  2816  	if md.Invite.Etime != nil && !md.Invite.IsInfiniteUses() {
  2817  		ret += " or"
  2818  	}
  2819  	if !md.Invite.IsInfiniteUses() {
  2820  		ret += " after " + md.Invite.UsesLeftString(usedInviteCount)
  2821  	}
  2822  	return true, ret
  2823  }
  2824  
  2825  func (m MemberInfo) TeamName() (TeamName, error) {
  2826  	return TeamNameFromString(m.FqName)
  2827  }
  2828  
  2829  func (i ImplicitTeamUserSet) NumTotalUsers() int {
  2830  	return len(i.KeybaseUsers) + len(i.UnresolvedUsers)
  2831  }
  2832  
  2833  func (i ImplicitTeamUserSet) List() string {
  2834  	var names []string
  2835  	names = append(names, i.KeybaseUsers...)
  2836  	for _, u := range i.UnresolvedUsers {
  2837  		names = append(names, u.String())
  2838  	}
  2839  	sort.Strings(names)
  2840  	return strings.Join(names, ",")
  2841  }
  2842  
  2843  func (n ImplicitTeamDisplayName) String() string {
  2844  	name := n.Writers.List()
  2845  
  2846  	if n.Readers.NumTotalUsers() > 0 {
  2847  		name += "#" + n.Readers.List()
  2848  	}
  2849  
  2850  	return name
  2851  }
  2852  
  2853  func (c *ImplicitTeamConflictInfo) IsConflict() bool {
  2854  	return c != nil && c.Generation > ConflictGeneration(0)
  2855  }
  2856  
  2857  const (
  2858  	// LockIDVersion0 is the first ever version for lock ID format.
  2859  	LockIDVersion0 byte = iota
  2860  )
  2861  
  2862  // LockIDFromBytes takes the first 8 bytes of the sha512 over data, overwrites
  2863  // first byte with the version byte, then interprets it as int64 using big
  2864  // endian, and returns the value as LockID.
  2865  func LockIDFromBytes(data []byte) LockID {
  2866  	sum := sha512.Sum512(data)
  2867  	sum[0] = LockIDVersion0
  2868  	return LockID(binary.BigEndian.Uint64(sum[:8]))
  2869  }
  2870  
  2871  // MDPriority is the type for the priority field of a metadata put. mdserver
  2872  // prioritizes MD writes with higher priority when multiple happen at the same
  2873  // time, for the same TLF.
  2874  const (
  2875  	// MDPriorityDefault is the priority of zero. It's implicitly used by all
  2876  	// old clients, and has lowest priority.
  2877  	MDPriorityDefault MDPriority = 0
  2878  	// MDPriorityNormal is the priority used for normal KBFS metadata writes.
  2879  	MDPriorityNormal = 8
  2880  	// MDPriorityGit is the priority used for metadata writes triggered by git
  2881  	// remote helpers.
  2882  	MDPriorityGit = 32
  2883  )
  2884  
  2885  // IsValid returns true is p is a valid MDPriority, or false otherwise.
  2886  func (p MDPriority) IsValid() bool {
  2887  	return p < 256 && p >= 0
  2888  }
  2889  
  2890  func (t TLFVisibility) Eq(r TLFVisibility) bool {
  2891  	return int(t) == int(r)
  2892  }
  2893  
  2894  func ParseUserVersion(s UserVersionPercentForm) (res UserVersion, err error) {
  2895  	parts := strings.Split(string(s), "%")
  2896  	if len(parts) == 1 {
  2897  		// NOTE: We have to keep it the way it is, even though we
  2898  		// never save UIDs without EldestSeqno anywhere. There may be
  2899  		// team chain which have UVs encoded with default eldest=1 in
  2900  		// the wild.
  2901  
  2902  		// default to seqno 1
  2903  		parts = append(parts, "1")
  2904  	}
  2905  	if len(parts) != 2 {
  2906  		return res, fmt.Errorf("invalid user version: %s", s)
  2907  	}
  2908  	uid, err := UIDFromString(parts[0])
  2909  	if err != nil {
  2910  		return res, err
  2911  	}
  2912  	eldestSeqno, err := strconv.ParseInt(parts[1], 10, 64)
  2913  	if err != nil {
  2914  		return res, fmt.Errorf("invalid eldest seqno: %s", err)
  2915  	}
  2916  	return UserVersion{
  2917  		Uid:         uid,
  2918  		EldestSeqno: Seqno(eldestSeqno),
  2919  	}, nil
  2920  }
  2921  
  2922  func (p StringKVPair) BoolValue() bool {
  2923  	i, err := strconv.ParseBool(p.Value)
  2924  	if err != nil {
  2925  		return false
  2926  	}
  2927  	return i
  2928  }
  2929  
  2930  func (p StringKVPair) IntValue() int {
  2931  	i, err := strconv.Atoi(p.Value)
  2932  	if err != nil {
  2933  		return 0
  2934  	}
  2935  	return i
  2936  }
  2937  
  2938  func (r *GitRepoResult) GetIfOk() (res GitRepoInfo, err error) {
  2939  	state, err := r.State()
  2940  	if err != nil {
  2941  		return res, err
  2942  	}
  2943  	switch state {
  2944  	case GitRepoResultState_ERR:
  2945  		return res, fmt.Errorf(r.Err())
  2946  	case GitRepoResultState_OK:
  2947  		return r.Ok(), nil
  2948  	}
  2949  	return res, fmt.Errorf("git repo unknown error")
  2950  }
  2951  
  2952  func (r GitRepoInfo) FullName() string {
  2953  	switch r.Folder.FolderType {
  2954  	case FolderType_PRIVATE:
  2955  		return string(r.LocalMetadata.RepoName)
  2956  	case FolderType_TEAM:
  2957  		return r.Folder.Name + "/" + string(r.LocalMetadata.RepoName)
  2958  	default:
  2959  		return "<repo type error>"
  2960  	}
  2961  }
  2962  
  2963  func (req *TeamChangeReq) AddUVWithRole(uv UserVersion, role TeamRole,
  2964  	botSettings *TeamBotSettings) error {
  2965  	if !role.IsRestrictedBot() && botSettings != nil {
  2966  		return fmt.Errorf("Unexpected botSettings for role %v", role)
  2967  	}
  2968  	switch role {
  2969  	case TeamRole_RESTRICTEDBOT:
  2970  		if botSettings == nil {
  2971  			return fmt.Errorf("Cannot add a RESTRICTEDBOT with nil TeamBotSettings")
  2972  		}
  2973  		if req.RestrictedBots == nil {
  2974  			req.RestrictedBots = make(map[UserVersion]TeamBotSettings)
  2975  		}
  2976  		req.RestrictedBots[uv] = *botSettings
  2977  	case TeamRole_BOT:
  2978  		req.Bots = append(req.Bots, uv)
  2979  	case TeamRole_READER:
  2980  		req.Readers = append(req.Readers, uv)
  2981  	case TeamRole_WRITER:
  2982  		req.Writers = append(req.Writers, uv)
  2983  	case TeamRole_ADMIN:
  2984  		req.Admins = append(req.Admins, uv)
  2985  	case TeamRole_OWNER:
  2986  		req.Owners = append(req.Owners, uv)
  2987  	default:
  2988  		return fmt.Errorf("Unexpected role: %v", role)
  2989  	}
  2990  	return nil
  2991  }
  2992  
  2993  func (req *TeamChangeReq) RestrictedBotUVs() (ret []UserVersion) {
  2994  	for uv := range req.RestrictedBots {
  2995  		ret = append(ret, uv)
  2996  	}
  2997  	return ret
  2998  }
  2999  
  3000  // CompleteInviteID adds to the `completed_invites` field, and signals that the
  3001  // invite can never be used again. It's used for SBS, Keybase, SeitanV1, and
  3002  // SeitanV2 invites.
  3003  func (req *TeamChangeReq) CompleteInviteID(inviteID TeamInviteID, uv UserVersionPercentForm) {
  3004  	if req.CompletedInvites == nil {
  3005  		req.CompletedInvites = make(map[TeamInviteID]UserVersionPercentForm)
  3006  	}
  3007  	req.CompletedInvites[inviteID] = uv
  3008  }
  3009  
  3010  // UseInviteID adds to the `used_invites` field. It is used for SeitanInvitelink invites,
  3011  // which can be used multiple times.
  3012  func (req *TeamChangeReq) UseInviteID(inviteID TeamInviteID, uv UserVersionPercentForm) {
  3013  	req.UsedInvites = append(req.UsedInvites, TeamUsedInvite{InviteID: inviteID, Uv: uv})
  3014  }
  3015  
  3016  func (req *TeamChangeReq) GetAllAdds() (ret []UserVersion) {
  3017  	ret = append(ret, req.RestrictedBotUVs()...)
  3018  	ret = append(ret, req.Bots...)
  3019  	ret = append(ret, req.Readers...)
  3020  	ret = append(ret, req.Writers...)
  3021  	ret = append(ret, req.Admins...)
  3022  	ret = append(ret, req.Owners...)
  3023  	return ret
  3024  }
  3025  
  3026  func TotalNumberOfCommits(refs []GitRefMetadata) (total int) {
  3027  	for _, ref := range refs {
  3028  		total += len(ref.Commits)
  3029  	}
  3030  	return total
  3031  }
  3032  
  3033  func RefNames(refs []GitRefMetadata) string {
  3034  	names := make([]string, len(refs))
  3035  	for i, ref := range refs {
  3036  		names[i] = ref.RefName
  3037  	}
  3038  	return strings.Join(names, ", ")
  3039  }
  3040  
  3041  func TeamEncryptedKBFSKeysetHashFromString(s string) TeamEncryptedKBFSKeysetHash {
  3042  	return TeamEncryptedKBFSKeysetHash(s)
  3043  }
  3044  
  3045  func TeamEncryptedKBFSKeysetHashFromBytes(s []byte) TeamEncryptedKBFSKeysetHash {
  3046  	return TeamEncryptedKBFSKeysetHashFromString(hex.EncodeToString(s))
  3047  }
  3048  
  3049  func (e TeamEncryptedKBFSKeysetHash) String() string {
  3050  	return string(e)
  3051  }
  3052  
  3053  func (e TeamEncryptedKBFSKeysetHash) Bytes() []byte {
  3054  	return []byte(e.String())
  3055  }
  3056  
  3057  func (e TeamEncryptedKBFSKeysetHash) SecureEqual(l TeamEncryptedKBFSKeysetHash) bool {
  3058  	return hmac.Equal(e.Bytes(), l.Bytes())
  3059  }
  3060  
  3061  func (r ResetLink) Summarize() ResetSummary {
  3062  	return ResetSummary{
  3063  		Ctime:      r.Ctime,
  3064  		MerkleRoot: r.MerkleRoot,
  3065  		ResetSeqno: r.ResetSeqno,
  3066  		Type:       r.Type,
  3067  	}
  3068  }
  3069  
  3070  func (f AvatarFormat) String() string {
  3071  	return string(f)
  3072  }
  3073  
  3074  func (u AvatarUrl) String() string {
  3075  	return string(u)
  3076  }
  3077  
  3078  func MakeAvatarURL(u string) AvatarUrl {
  3079  	return AvatarUrl(u)
  3080  }
  3081  
  3082  func (b Bytes32) IsBlank() bool {
  3083  	var blank Bytes32
  3084  	return (subtle.ConstantTimeCompare(b[:], blank[:]) == 1)
  3085  }
  3086  
  3087  func (i Identify2ResUPK2) ExportToV1() Identify2Res {
  3088  	return Identify2Res{
  3089  		Upk:          UPAKFromUPKV2AI(i.Upk).Base,
  3090  		IdentifiedAt: i.IdentifiedAt,
  3091  		TrackBreaks:  i.TrackBreaks,
  3092  	}
  3093  }
  3094  
  3095  func (path Path) String() string {
  3096  	pathType, err := path.PathType()
  3097  	if err != nil {
  3098  		return ""
  3099  	}
  3100  	switch pathType {
  3101  	case PathType_KBFS:
  3102  		return path.Kbfs().Path
  3103  	case PathType_KBFS_ARCHIVED:
  3104  		return path.KbfsArchived().Path
  3105  	case PathType_LOCAL:
  3106  		return path.Local()
  3107  	default:
  3108  		return ""
  3109  	}
  3110  }
  3111  
  3112  func (se *SelectorEntry) UnmarshalJSON(b []byte) error {
  3113  	if err := json.Unmarshal(b, &se.Index); err == nil {
  3114  		se.IsIndex = true
  3115  		return nil
  3116  	}
  3117  
  3118  	if err := json.Unmarshal(b, &se.Key); err == nil {
  3119  		se.IsKey = true
  3120  		return nil
  3121  	}
  3122  
  3123  	m := make(map[string]bool)
  3124  	if err := json.Unmarshal(b, &m); err != nil {
  3125  		return fmt.Errorf("invalid selector (not dict)")
  3126  	}
  3127  	ok1, ok2 := m["all"]
  3128  	if ok1 && ok2 {
  3129  		se.IsAll = true
  3130  		return nil
  3131  	}
  3132  	ok1, ok2 = m["contents"]
  3133  	if ok1 && ok2 {
  3134  		se.IsContents = true
  3135  		return nil
  3136  	}
  3137  	return fmt.Errorf("invalid selector (not recognized)")
  3138  }
  3139  
  3140  func (p PhoneNumber) String() string {
  3141  	return string(p)
  3142  }
  3143  
  3144  var nonDigits = regexp.MustCompile(`[^\d]`)
  3145  
  3146  func PhoneNumberToAssertionValue(phoneNumber string) string {
  3147  	return nonDigits.ReplaceAllString(phoneNumber, "")
  3148  }
  3149  
  3150  func (p PhoneNumber) AssertionValue() string {
  3151  	return PhoneNumberToAssertionValue(p.String())
  3152  }
  3153  
  3154  func (d TeamData) ID() TeamID {
  3155  	return d.Chain.Id
  3156  }
  3157  
  3158  func (d TeamData) IsPublic() bool {
  3159  	return d.Chain.Public
  3160  }
  3161  
  3162  func (d FastTeamData) ID() TeamID {
  3163  	return d.Chain.ID
  3164  }
  3165  
  3166  func (d FastTeamData) IsPublic() bool {
  3167  	return d.Chain.Public
  3168  }
  3169  
  3170  func (d HiddenTeamChain) ID() TeamID {
  3171  	return d.Id
  3172  }
  3173  
  3174  func (d HiddenTeamChain) IsPublic() bool {
  3175  	return d.Public
  3176  }
  3177  
  3178  func (d HiddenTeamChain) Summary() string {
  3179  	type pair struct {
  3180  		g       PerTeamKeyGeneration
  3181  		q       Seqno
  3182  		stubbed bool
  3183  	}
  3184  	var arr []pair
  3185  	for g, q := range d.ReaderPerTeamKeys {
  3186  		var full bool
  3187  		if d.Inner != nil {
  3188  			_, full = d.Inner[q]
  3189  		}
  3190  		arr = append(arr, pair{g: g, q: q, stubbed: !full})
  3191  	}
  3192  	sort.Slice(arr, func(i, j int) bool { return arr[i].g < arr[j].g })
  3193  	return fmt.Sprintf("{Team:%s, Last:%d, ReaderPerTeamKeys: %+v}", d.Id, d.Last, arr)
  3194  }
  3195  
  3196  func (f FullName) String() string {
  3197  	return string(f)
  3198  }
  3199  
  3200  func (h BoxSummaryHash) String() string {
  3201  	return string(h)
  3202  }
  3203  
  3204  func (r BoxAuditAttemptResult) IsOK() bool {
  3205  	switch r {
  3206  	case BoxAuditAttemptResult_OK_VERIFIED, BoxAuditAttemptResult_OK_NOT_ATTEMPTED_ROLE, BoxAuditAttemptResult_OK_NOT_ATTEMPTED_OPENTEAM, BoxAuditAttemptResult_OK_NOT_ATTEMPTED_SUBTEAM:
  3207  		return true
  3208  	default:
  3209  		return false
  3210  	}
  3211  }
  3212  
  3213  func (a BoxAuditAttempt) String() string {
  3214  	ret := a.Result.String()
  3215  	if a.Error != nil {
  3216  		ret += fmt.Sprintf("\t(error: %s)", *a.Error)
  3217  	}
  3218  	if a.Rotated {
  3219  		ret += "\t(team rotated)"
  3220  	}
  3221  	return ret
  3222  }
  3223  
  3224  func (c ContactComponent) ValueString() string {
  3225  	switch {
  3226  	case c.Email != nil:
  3227  		return string(*c.Email)
  3228  	case c.PhoneNumber != nil:
  3229  		return string(*c.PhoneNumber)
  3230  	default:
  3231  		return ""
  3232  	}
  3233  }
  3234  
  3235  func (c ContactComponent) AssertionType() string {
  3236  	switch {
  3237  	case c.Email != nil:
  3238  		return "email"
  3239  	case c.PhoneNumber != nil:
  3240  		return "phone"
  3241  	default:
  3242  		return ""
  3243  	}
  3244  }
  3245  
  3246  func (c ContactComponent) FormatDisplayLabel(addLabel bool) string {
  3247  	if addLabel && c.Label != "" {
  3248  		return fmt.Sprintf("%s (%s)", c.ValueString(), c.Label)
  3249  	}
  3250  	return c.ValueString()
  3251  }
  3252  
  3253  func (fct FolderConflictType) MarshalText() ([]byte, error) {
  3254  	switch fct {
  3255  	case FolderConflictType_NONE:
  3256  		return []byte("none"), nil
  3257  	case FolderConflictType_IN_CONFLICT:
  3258  		return []byte("in conflict"), nil
  3259  	case FolderConflictType_IN_CONFLICT_AND_STUCK:
  3260  		return []byte("in conflict and stuck"), nil
  3261  	default:
  3262  		return []byte(fmt.Sprintf("unknown conflict type: %d", fct)), nil
  3263  	}
  3264  }
  3265  
  3266  func (fct *FolderConflictType) UnmarshalText(text []byte) error {
  3267  	switch string(text) {
  3268  	case "none":
  3269  		*fct = FolderConflictType_NONE
  3270  	case "in conflict":
  3271  		*fct = FolderConflictType_IN_CONFLICT
  3272  	case "in conflict and stuck":
  3273  		*fct = FolderConflictType_IN_CONFLICT_AND_STUCK
  3274  	default:
  3275  		return fmt.Errorf("Unknown conflict type: %s", text)
  3276  	}
  3277  	return nil
  3278  }
  3279  
  3280  func (h *HiddenTeamChain) Tail() *HiddenTeamChainLink {
  3281  	last := h.Last
  3282  	if last == Seqno(0) {
  3283  		return nil
  3284  	}
  3285  	ret, ok := h.Inner[last]
  3286  	if !ok {
  3287  		return nil
  3288  	}
  3289  	return &ret
  3290  }
  3291  
  3292  func (h *HiddenTeamChain) TailTriple() *LinkTriple {
  3293  	last := h.Last
  3294  	if last == Seqno(0) {
  3295  		return nil
  3296  	}
  3297  	link, ok := h.Outer[last]
  3298  	if !ok {
  3299  		return nil
  3300  	}
  3301  	return &LinkTriple{
  3302  		Seqno:   last,
  3303  		LinkID:  link,
  3304  		SeqType: SeqType_TEAM_PRIVATE_HIDDEN,
  3305  	}
  3306  }
  3307  
  3308  func (s Signer) UserVersion() UserVersion {
  3309  	return UserVersion{
  3310  		Uid:         s.U,
  3311  		EldestSeqno: s.E,
  3312  	}
  3313  }
  3314  
  3315  func (p PerTeamSeedCheck) Hash() (*PerTeamSeedCheckPostImage, error) {
  3316  	if p.Version != PerTeamSeedCheckVersion_V1 {
  3317  		return nil, errors.New("can only handle PerTeamKeySeedCheck V1")
  3318  	}
  3319  	ret := sha256.Sum256(p.Value[:])
  3320  	return &PerTeamSeedCheckPostImage{
  3321  		Version: PerTeamSeedCheckVersion_V1,
  3322  		Value:   PerTeamSeedCheckValuePostImage(ret[:]),
  3323  	}, nil
  3324  }
  3325  
  3326  func (p PerTeamSeedCheckPostImage) Eq(p2 PerTeamSeedCheckPostImage) bool {
  3327  	return (p.Version == p2.Version) && hmac.Equal(p.Value[:], p2.Value[:])
  3328  }
  3329  
  3330  func (r HiddenTeamChainRatchetSet) Flat() []LinkTripleAndTime {
  3331  	if r.Ratchets == nil {
  3332  		return nil
  3333  	}
  3334  	var ret []LinkTripleAndTime
  3335  	for _, v := range r.Ratchets {
  3336  		ret = append(ret, v)
  3337  	}
  3338  	return ret
  3339  }
  3340  
  3341  func (r HiddenTeamChainRatchetSet) IsEmpty() bool {
  3342  	return r.Ratchets == nil || len(r.Ratchets) == 0
  3343  }
  3344  
  3345  func (r HiddenTeamChainRatchetSet) Max() Seqno {
  3346  	var ret Seqno
  3347  	if r.Ratchets == nil {
  3348  		return ret
  3349  	}
  3350  	for _, v := range r.Ratchets {
  3351  		if v.Triple.Seqno > ret {
  3352  			ret = v.Triple.Seqno
  3353  		}
  3354  	}
  3355  	return ret
  3356  }
  3357  
  3358  func (r HiddenTeamChainRatchetSet) MaxTriple() *LinkTriple {
  3359  	if r.Ratchets == nil {
  3360  		return nil
  3361  	}
  3362  	var out LinkTriple
  3363  	for _, v := range r.Ratchets {
  3364  		if v.Triple.Seqno > out.Seqno {
  3365  			out = v.Triple
  3366  		}
  3367  	}
  3368  	return &out
  3369  }
  3370  
  3371  func (r *HiddenTeamChain) MaxTriple() *LinkTriple {
  3372  	tail := r.TailTriple()
  3373  	rat := r.RatchetSet.MaxTriple()
  3374  	if rat == nil && tail == nil {
  3375  		return nil
  3376  	}
  3377  	if rat == nil {
  3378  		return tail
  3379  	}
  3380  	if tail == nil {
  3381  		return rat
  3382  	}
  3383  	if tail.Seqno > rat.Seqno {
  3384  		return tail
  3385  	}
  3386  	return rat
  3387  }
  3388  
  3389  func (r *HiddenTeamChainRatchetSet) init() {
  3390  	if r.Ratchets == nil {
  3391  		r.Ratchets = make(map[RatchetType]LinkTripleAndTime)
  3392  	}
  3393  }
  3394  
  3395  func (r *HiddenTeamChainRatchetSet) Merge(r2 HiddenTeamChainRatchetSet) (updated bool) {
  3396  	r.init()
  3397  	if r2.Ratchets == nil {
  3398  		return false
  3399  	}
  3400  	for k, v := range r2.Ratchets {
  3401  		if r.Add(k, v) {
  3402  			updated = true
  3403  		}
  3404  	}
  3405  	return updated
  3406  }
  3407  
  3408  func (r *HiddenTeamChainRatchetSet) Add(t RatchetType, v LinkTripleAndTime) (changed bool) {
  3409  	r.init()
  3410  	found, ok := r.Ratchets[t]
  3411  	if (v.Triple.SeqType == SeqType_TEAM_PRIVATE_HIDDEN) && (!ok || v.Triple.Seqno > found.Triple.Seqno) {
  3412  		r.Ratchets[t] = v
  3413  		changed = true
  3414  	}
  3415  	return changed
  3416  }
  3417  
  3418  func (r LinkTripleAndTime) Clashes(r2 LinkTripleAndTime) bool {
  3419  	l1 := r.Triple
  3420  	l2 := r2.Triple
  3421  	return (l1.Seqno == l2.Seqno && l1.SeqType == l2.SeqType && !l1.LinkID.Eq(l2.LinkID))
  3422  }
  3423  
  3424  func (r MerkleRootV2) Eq(s MerkleRootV2) bool {
  3425  	return r.Seqno == s.Seqno && r.HashMeta.Eq(s.HashMeta)
  3426  }
  3427  
  3428  func (d *HiddenTeamChain) GetLastCommittedSeqno() Seqno {
  3429  	if d == nil {
  3430  		return 0
  3431  	}
  3432  	return d.LastCommittedSeqno
  3433  }
  3434  
  3435  func (d *HiddenTeamChain) GetOuter() map[Seqno]LinkID {
  3436  	if d == nil {
  3437  		return nil
  3438  	}
  3439  	return d.Outer
  3440  }
  3441  
  3442  func (d *HiddenTeamChain) PopulateLastFull() {
  3443  	if d == nil {
  3444  		return
  3445  	}
  3446  	if d.LastFull != Seqno(0) {
  3447  		return
  3448  	}
  3449  	for i := Seqno(1); i <= d.Last; i++ {
  3450  		_, found := d.Inner[i]
  3451  		if !found {
  3452  			break
  3453  		}
  3454  		d.LastFull = i
  3455  	}
  3456  }
  3457  
  3458  func (d *HiddenTeamChain) LastFullPopulateIfUnset() Seqno {
  3459  	if d == nil {
  3460  		return Seqno(0)
  3461  	}
  3462  	if d.LastFull == Seqno(0) {
  3463  		d.PopulateLastFull()
  3464  	}
  3465  	return d.LastFull
  3466  }
  3467  
  3468  func (d *HiddenTeamChain) Merge(newData HiddenTeamChain) (updated bool, err error) {
  3469  
  3470  	for seqno, link := range newData.Outer {
  3471  		existing, ok := d.Outer[seqno]
  3472  		if ok && !existing.Eq(link) {
  3473  			return false, fmt.Errorf("bad merge since at seqno %d, link clash: %s != %s", seqno, existing, link)
  3474  		}
  3475  		if ok {
  3476  			continue
  3477  		}
  3478  		d.Outer[seqno] = link
  3479  		updated = true
  3480  		if seqno > d.Last {
  3481  			d.Last = seqno
  3482  		}
  3483  	}
  3484  
  3485  	for q, i := range newData.Inner {
  3486  		_, found := d.Inner[q]
  3487  		if found {
  3488  			continue
  3489  		}
  3490  		d.Inner[q] = i
  3491  		if ptk, ok := i.Ptk[PTKType_READER]; ok {
  3492  			d.ReaderPerTeamKeys[ptk.Ptk.Gen] = q
  3493  		}
  3494  
  3495  		// If we previously loaded full links up to d.LastFull, but this is d.LastFull+1,
  3496  		// then we can safely bump the pointer one foward.
  3497  		if q == d.LastFull+Seqno(1) {
  3498  			d.LastFull = q
  3499  		}
  3500  		updated = true
  3501  	}
  3502  	if newData.Last > d.Last {
  3503  		d.Last = newData.Last
  3504  	}
  3505  
  3506  	if newData.LastCommittedSeqno > d.LastCommittedSeqno {
  3507  		d.LastCommittedSeqno = newData.LastCommittedSeqno
  3508  		updated = true
  3509  	}
  3510  
  3511  	for k, v := range newData.LastPerTeamKeys {
  3512  		existing, ok := d.LastPerTeamKeys[k]
  3513  		if !ok || existing < v {
  3514  			d.LastPerTeamKeys[k] = v
  3515  		}
  3516  	}
  3517  
  3518  	for k, v := range newData.MerkleRoots {
  3519  		existing, ok := d.MerkleRoots[k]
  3520  		if ok && !existing.Eq(v) {
  3521  			return false, fmt.Errorf("bad merge since at seqno %d, merkle root clash: %+v != %+v", k, existing, v)
  3522  		}
  3523  		if ok {
  3524  			continue
  3525  		}
  3526  		d.MerkleRoots[k] = v
  3527  		updated = true
  3528  	}
  3529  
  3530  	if d.RatchetSet.Merge(newData.RatchetSet) {
  3531  		updated = true
  3532  	}
  3533  
  3534  	for k := range d.LinkReceiptTimes {
  3535  		if k <= newData.LastCommittedSeqno {
  3536  			// This link has been committed to the blind tree, no need to keep
  3537  			// track of it any more
  3538  			delete(d.LinkReceiptTimes, k)
  3539  			updated = true
  3540  		}
  3541  	}
  3542  
  3543  	for k, v := range newData.LinkReceiptTimes {
  3544  		if _, found := d.LinkReceiptTimes[k]; !found {
  3545  			if d.LinkReceiptTimes == nil {
  3546  				d.LinkReceiptTimes = make(map[Seqno]Time)
  3547  			}
  3548  			d.LinkReceiptTimes[k] = v
  3549  			updated = true
  3550  		}
  3551  	}
  3552  
  3553  	return updated, nil
  3554  }
  3555  
  3556  func (h HiddenTeamChain) HasSeqno(s Seqno) bool {
  3557  	_, found := h.Outer[s]
  3558  	return found
  3559  }
  3560  
  3561  func NewHiddenTeamChain(id TeamID) *HiddenTeamChain {
  3562  	return &HiddenTeamChain{
  3563  		Id:                id,
  3564  		Subversion:        1, // We are now on Version 1.1
  3565  		LastPerTeamKeys:   make(map[PTKType]Seqno),
  3566  		ReaderPerTeamKeys: make(map[PerTeamKeyGeneration]Seqno),
  3567  		Outer:             make(map[Seqno]LinkID),
  3568  		Inner:             make(map[Seqno]HiddenTeamChainLink),
  3569  		MerkleRoots:       make(map[Seqno]MerkleRootV2),
  3570  	}
  3571  }
  3572  
  3573  func (h *HiddenTeamChain) Tombstone() (changed bool) {
  3574  	if h.Tombstoned {
  3575  		return false
  3576  	}
  3577  	h.LastPerTeamKeys = make(map[PTKType]Seqno)
  3578  	h.ReaderPerTeamKeys = make(map[PerTeamKeyGeneration]Seqno)
  3579  	h.Outer = make(map[Seqno]LinkID)
  3580  	h.Inner = make(map[Seqno]HiddenTeamChainLink)
  3581  	h.Tombstoned = true
  3582  	return true
  3583  }
  3584  
  3585  func (h *HiddenTeamChain) Freeze() (changed bool) {
  3586  	if h.Frozen {
  3587  		return false
  3588  	}
  3589  	h.LastPerTeamKeys = make(map[PTKType]Seqno)
  3590  	h.ReaderPerTeamKeys = make(map[PerTeamKeyGeneration]Seqno)
  3591  	h.Inner = make(map[Seqno]HiddenTeamChainLink)
  3592  	newOuter := make(map[Seqno]LinkID)
  3593  	if h.Last != Seqno(0) {
  3594  		newOuter[h.Last] = h.Outer[h.Last]
  3595  	}
  3596  	h.Outer = newOuter
  3597  	h.Frozen = true
  3598  	return true
  3599  }
  3600  
  3601  func (h HiddenTeamChain) LastReaderPerTeamKeyLinkID() (ret LinkID) {
  3602  	seqno, ok := h.LastPerTeamKeys[PTKType_READER]
  3603  	if !ok {
  3604  		return ret
  3605  	}
  3606  	tmp, ok := h.Outer[seqno]
  3607  	if !ok {
  3608  		return ret
  3609  	}
  3610  	return tmp
  3611  }
  3612  
  3613  func (h *HiddenTeamChain) GetReaderPerTeamKeyAtGeneration(g PerTeamKeyGeneration) (ret PerTeamKey, found bool) {
  3614  	if h == nil {
  3615  		return ret, false
  3616  	}
  3617  	q, ok := h.ReaderPerTeamKeys[g]
  3618  	if !ok {
  3619  		return ret, false
  3620  	}
  3621  	inner, ok := h.Inner[q]
  3622  	if !ok {
  3623  		return ret, false
  3624  	}
  3625  	key, ok := inner.Ptk[PTKType_READER]
  3626  	if !ok {
  3627  		return ret, false
  3628  	}
  3629  	return key.Ptk, true
  3630  }
  3631  
  3632  func (h *HiddenTeamChain) MaxReaderPerTeamKey() *PerTeamKey {
  3633  	if h == nil {
  3634  		return nil
  3635  	}
  3636  	seqno, ok := h.LastPerTeamKeys[PTKType_READER]
  3637  	if !ok {
  3638  		return nil
  3639  	}
  3640  	inner, ok := h.Inner[seqno]
  3641  	if !ok {
  3642  		return nil
  3643  	}
  3644  	ptk, ok := inner.Ptk[PTKType_READER]
  3645  	if !ok {
  3646  		return nil
  3647  	}
  3648  	return &ptk.Ptk
  3649  }
  3650  
  3651  func (h *HiddenTeamChain) MaxReaderPerTeamKeyGeneration() PerTeamKeyGeneration {
  3652  	k := h.MaxReaderPerTeamKey()
  3653  	if k == nil {
  3654  		return PerTeamKeyGeneration(0)
  3655  	}
  3656  	return k.Gen
  3657  }
  3658  
  3659  func (h *HiddenTeamChain) KeySummary() string {
  3660  	if h == nil {
  3661  		return "Ø"
  3662  	}
  3663  	return fmt.Sprintf("{last:%d, lastPerTeamKeys:%+v, readerPerTeamKeys: %+v}", h.Last, h.LastPerTeamKeys, h.ReaderPerTeamKeys)
  3664  }
  3665  
  3666  func (h *HiddenTeamChain) LinkAndKeySummary() string {
  3667  	if h == nil {
  3668  		return "empty"
  3669  	}
  3670  	ks := h.KeySummary()
  3671  	return fmt.Sprintf("{nOuterlinks: %d, nInnerLinks:%d, keys:%s}", len(h.Outer), len(h.Inner), ks)
  3672  }
  3673  
  3674  func (h *TeamData) KeySummary() string {
  3675  	if h == nil {
  3676  		return "Ø"
  3677  	}
  3678  	var p []PerTeamKeyGeneration
  3679  	for k := range h.PerTeamKeySeedsUnverified {
  3680  		p = append(p, k)
  3681  	}
  3682  	m := make(map[PerTeamKeyGeneration]bool)
  3683  	for _, v := range h.ReaderKeyMasks {
  3684  		for k := range v {
  3685  			m[k] = true
  3686  		}
  3687  	}
  3688  	var r []PerTeamKeyGeneration
  3689  	for k := range m {
  3690  		r = append(r, k)
  3691  	}
  3692  	return fmt.Sprintf("{ptksu:%v, rkms:%v, sigchain:%s}", p, r, h.Chain.KeySummary())
  3693  }
  3694  
  3695  func (s TeamSigChainState) UserRole(user UserVersion) TeamRole {
  3696  	points := s.UserLog[user]
  3697  	if len(points) == 0 {
  3698  		return TeamRole_NONE
  3699  	}
  3700  	role := points[len(points)-1].Role
  3701  	return role
  3702  }
  3703  
  3704  func (s TeamSigChainState) GetUserLastJoinTime(user UserVersion) (time Time, err error) {
  3705  	if s.UserRole(user) == TeamRole_NONE {
  3706  		return 0, fmt.Errorf("In GetUserLastJoinTime: User %s is not a member of team %v", user.Uid, s.Id)
  3707  	}
  3708  	// Look for the latest join event, i.e. the latest transition from a role NONE to a different valid one.
  3709  	points := s.UserLog[user]
  3710  	for i := len(points) - 1; i > -1; i-- {
  3711  		if points[i].Role == TeamRole_NONE {
  3712  			// this is the last time in the sigchain this user has role none
  3713  			// (note that it cannot be the last link in the chain, otherwise the
  3714  			// user would have role NONE), so the link after this one is the one
  3715  			// where they joined the team last.
  3716  			return points[i+1].SigMeta.Time, nil
  3717  		}
  3718  	}
  3719  	// If the user never had role none, they joined at the time of their first
  3720  	// UserLog entry (they need to have at least one, else again their role would be
  3721  	// NONE).
  3722  	return points[0].SigMeta.Time, nil
  3723  }
  3724  
  3725  // GetUserLastRoleChangeTime returns the time of the last role change for user
  3726  // in team. If the user left the team as a last change, the time of such leave
  3727  // event is returned. If the user was never in the team, then this function
  3728  // returns time=0 and wasMember=false.
  3729  func (s TeamSigChainState) GetUserLastRoleChangeTime(user UserVersion) (time Time, wasMember bool) {
  3730  	points := s.UserLog[user]
  3731  	if len(points) == 0 {
  3732  		return 0, false
  3733  	}
  3734  	return points[len(points)-1].SigMeta.Time, true
  3735  }
  3736  
  3737  func (s TeamSigChainState) KeySummary() string {
  3738  	var v []PerTeamKeyGeneration
  3739  	for k := range s.PerTeamKeys {
  3740  		v = append(v, k)
  3741  	}
  3742  	return fmt.Sprintf("{maxPTK:%d, ptk:%v}", s.MaxPerTeamKeyGeneration, v)
  3743  }
  3744  
  3745  func (s TeamSigChainState) HasAnyStubbedLinks() bool {
  3746  	for _, v := range s.StubbedLinks {
  3747  		if v {
  3748  			return true
  3749  		}
  3750  	}
  3751  	return false
  3752  }
  3753  
  3754  func (s TeamSigChainState) ListSubteams() (res []TeamIDAndName) {
  3755  	type Entry struct {
  3756  		ID   TeamID
  3757  		Name TeamName
  3758  		// Seqno of the last cached rename of this team
  3759  		Seqno Seqno
  3760  	}
  3761  	// Use a map to deduplicate names. If there is a subteam name
  3762  	// collision, take the one with the latest (parent) seqno
  3763  	// modifying its name.
  3764  	// A collision could occur if you were removed from a team
  3765  	// and miss its renaming or deletion to stubbing.
  3766  	resMap := make(map[string] /*TeamName*/ Entry)
  3767  	for subteamID, points := range s.SubteamLog {
  3768  		if len(points) == 0 {
  3769  			// this should never happen
  3770  			continue
  3771  		}
  3772  		lastPoint := points[len(points)-1]
  3773  		if lastPoint.Name.IsNil() {
  3774  			// the subteam has been deleted
  3775  			continue
  3776  		}
  3777  		entry := Entry{
  3778  			ID:    subteamID,
  3779  			Name:  lastPoint.Name,
  3780  			Seqno: lastPoint.Seqno,
  3781  		}
  3782  		existing, ok := resMap[entry.Name.String()]
  3783  		replace := !ok || (entry.Seqno >= existing.Seqno)
  3784  		if replace {
  3785  			resMap[entry.Name.String()] = entry
  3786  		}
  3787  	}
  3788  	for _, entry := range resMap {
  3789  		res = append(res, TeamIDAndName{
  3790  			Id:   entry.ID,
  3791  			Name: entry.Name,
  3792  		})
  3793  	}
  3794  	return res
  3795  }
  3796  
  3797  func (s TeamSigChainState) GetAllUVs() (res []UserVersion) {
  3798  	for uv := range s.UserLog {
  3799  		if s.UserRole(uv) != TeamRole_NONE {
  3800  			res = append(res, uv)
  3801  		}
  3802  	}
  3803  	return res
  3804  }
  3805  
  3806  func (s TeamSigChainState) ActiveInvites() (ret []TeamInvite) {
  3807  	for _, md := range s.InviteMetadatas {
  3808  		if code, err := md.Status.Code(); err == nil &&
  3809  			code == TeamInviteMetadataStatusCode_ACTIVE {
  3810  			ret = append(ret, md.Invite)
  3811  		}
  3812  	}
  3813  	return ret
  3814  }
  3815  
  3816  func (h *HiddenTeamChain) IsStale() bool {
  3817  	if h == nil {
  3818  		return false
  3819  	}
  3820  	max := h.RatchetSet.Max()
  3821  	if max < h.LatestSeqnoHint {
  3822  		max = h.LatestSeqnoHint
  3823  	}
  3824  	if max == Seqno(0) {
  3825  		return false
  3826  	}
  3827  	_, fresh := h.Outer[max]
  3828  	return !fresh
  3829  }
  3830  
  3831  func (k TeamEphemeralKey) Ctime() Time {
  3832  	typ, err := k.KeyType()
  3833  	if err != nil {
  3834  		return 0
  3835  	}
  3836  	switch typ {
  3837  	case TeamEphemeralKeyType_TEAM:
  3838  		return k.Team().Metadata.Ctime
  3839  	case TeamEphemeralKeyType_TEAMBOT:
  3840  		return k.Teambot().Metadata.Ctime
  3841  	default:
  3842  		return 0
  3843  	}
  3844  }
  3845  
  3846  func (k TeamEphemeralKeyBoxed) Ctime() Time {
  3847  	typ, err := k.KeyType()
  3848  	if err != nil {
  3849  		return 0
  3850  	}
  3851  	switch typ {
  3852  	case TeamEphemeralKeyType_TEAM:
  3853  		return k.Team().Metadata.Ctime
  3854  	case TeamEphemeralKeyType_TEAMBOT:
  3855  		return k.Teambot().Metadata.Ctime
  3856  	default:
  3857  		return 0
  3858  	}
  3859  }
  3860  
  3861  func (k TeamEphemeralKey) Generation() EkGeneration {
  3862  	typ, err := k.KeyType()
  3863  	if err != nil {
  3864  		return 0
  3865  	}
  3866  	switch typ {
  3867  	case TeamEphemeralKeyType_TEAM:
  3868  		return k.Team().Metadata.Generation
  3869  	case TeamEphemeralKeyType_TEAMBOT:
  3870  		return k.Teambot().Metadata.Generation
  3871  	default:
  3872  		return 0
  3873  	}
  3874  }
  3875  
  3876  func (k TeamEphemeralKey) Material() Bytes32 {
  3877  	typ, err := k.KeyType()
  3878  	if err != nil {
  3879  		return [32]byte{}
  3880  	}
  3881  	switch typ {
  3882  	case TeamEphemeralKeyType_TEAM:
  3883  		return k.Team().Seed
  3884  	case TeamEphemeralKeyType_TEAMBOT:
  3885  		return k.Teambot().Seed
  3886  	default:
  3887  		return [32]byte{}
  3888  	}
  3889  }
  3890  
  3891  func (k TeamEphemeralKeyBoxed) Generation() EkGeneration {
  3892  	typ, err := k.KeyType()
  3893  	if err != nil {
  3894  		return 0
  3895  	}
  3896  	switch typ {
  3897  	case TeamEphemeralKeyType_TEAM:
  3898  		return k.Team().Metadata.Generation
  3899  	case TeamEphemeralKeyType_TEAMBOT:
  3900  		return k.Teambot().Metadata.Generation
  3901  	default:
  3902  		return 0
  3903  	}
  3904  }
  3905  
  3906  func (k TeamEphemeralKeyType) IsTeambot() bool {
  3907  	return k == TeamEphemeralKeyType_TEAMBOT
  3908  }
  3909  
  3910  func (k TeamEphemeralKeyType) IsTeam() bool {
  3911  	return k == TeamEphemeralKeyType_TEAM
  3912  }
  3913  
  3914  // IsLimited returns if the network is considered limited based on the type.
  3915  func (s MobileNetworkState) IsLimited() bool {
  3916  	switch s {
  3917  	case MobileNetworkState_WIFI, MobileNetworkState_NOTAVAILABLE:
  3918  		return false
  3919  	default:
  3920  		return true
  3921  	}
  3922  }
  3923  
  3924  func (k TeambotKey) Generation() int {
  3925  	return int(k.Metadata.Generation)
  3926  }
  3927  
  3928  func (k TeambotKey) Material() Bytes32 {
  3929  	return k.Seed
  3930  }
  3931  
  3932  func (r APIUserSearchResult) GetStringIDForCompare() string {
  3933  	switch {
  3934  	case r.Contact != nil:
  3935  		return fmt.Sprintf("%s%s", r.Contact.DisplayName, r.Contact.DisplayLabel)
  3936  	case r.Imptofu != nil:
  3937  		return fmt.Sprintf("%s%s", r.Imptofu.PrettyName, r.Imptofu.Label)
  3938  	case r.Keybase != nil:
  3939  		return r.Keybase.Username
  3940  	default:
  3941  		return ""
  3942  	}
  3943  }
  3944  
  3945  func NewPathWithKbfsPath(path string) Path {
  3946  	return NewPathWithKbfs(KBFSPath{Path: path})
  3947  }
  3948  
  3949  func (p PerTeamKey) Equal(q PerTeamKey) bool {
  3950  	return p.EncKID.Equal(q.EncKID) && p.SigKID.Equal(q.SigKID)
  3951  }
  3952  
  3953  func (b BotToken) IsNil() bool {
  3954  	return len(b) == 0
  3955  }
  3956  
  3957  func (b BotToken) Exists() bool {
  3958  	return !b.IsNil()
  3959  }
  3960  
  3961  func (b BotToken) String() string {
  3962  	return string(b)
  3963  }
  3964  
  3965  var botTokenRxx = regexp.MustCompile(`^[a-zA-Z0-9_-]{32}$`)
  3966  
  3967  func NewBotToken(s string) (BotToken, error) {
  3968  	if !botTokenRxx.MatchString(s) {
  3969  		return BotToken(""), errors.New("bad bot token")
  3970  	}
  3971  	return BotToken(s), nil
  3972  }
  3973  
  3974  func (b BadgeConversationInfo) IsEmpty() bool {
  3975  	return b.UnreadMessages == 0 && b.BadgeCount == 0
  3976  }
  3977  
  3978  func (s *TeamBotSettings) Eq(o *TeamBotSettings) bool {
  3979  	return reflect.DeepEqual(s, o)
  3980  }
  3981  
  3982  func (s *TeamBotSettings) ConvIDAllowed(strCID string) bool {
  3983  	if s == nil {
  3984  		return true
  3985  	}
  3986  	for _, strConvID := range s.Convs {
  3987  		if strCID == strConvID {
  3988  			return true
  3989  		}
  3990  	}
  3991  	return len(s.Convs) == 0
  3992  }
  3993  
  3994  func (b UserBlockedBody) Summarize() UserBlockedSummary {
  3995  	ret := UserBlockedSummary{
  3996  		Blocker: b.Username,
  3997  		Blocks:  make(map[string][]UserBlockState),
  3998  	}
  3999  	for _, block := range b.Blocks {
  4000  		if block.Chat != nil {
  4001  			ret.Blocks[block.Username] = append(ret.Blocks[block.Username], UserBlockState{UserBlockType_CHAT, *block.Chat})
  4002  		}
  4003  		if block.Follow != nil {
  4004  			ret.Blocks[block.Username] = append(ret.Blocks[block.Username], UserBlockState{UserBlockType_FOLLOW, *block.Follow})
  4005  		}
  4006  	}
  4007  	return ret
  4008  }
  4009  
  4010  func FilterMembersDetails(membMap map[string]struct{}, details []TeamMemberDetails) (res []TeamMemberDetails) {
  4011  	res = []TeamMemberDetails{}
  4012  	for _, member := range details {
  4013  		if _, ok := membMap[member.Username]; ok {
  4014  			res = append(res, member)
  4015  		}
  4016  	}
  4017  	return res
  4018  }
  4019  
  4020  func FilterTeamDetailsForMembers(usernames []string, details TeamDetails) TeamDetails {
  4021  	membMap := make(map[string]struct{})
  4022  	for _, username := range usernames {
  4023  		membMap[username] = struct{}{}
  4024  	}
  4025  	res := details.DeepCopy()
  4026  	res.Members.Owners = FilterMembersDetails(membMap, res.Members.Owners)
  4027  	res.Members.Admins = FilterMembersDetails(membMap, res.Members.Admins)
  4028  	res.Members.Writers = FilterMembersDetails(membMap, res.Members.Writers)
  4029  	res.Members.Readers = FilterMembersDetails(membMap, res.Members.Readers)
  4030  	res.Members.Bots = FilterMembersDetails(membMap, res.Members.Bots)
  4031  	res.Members.RestrictedBots = FilterMembersDetails(membMap, res.Members.RestrictedBots)
  4032  	return res
  4033  }
  4034  
  4035  func (b FeaturedBot) DisplayName() string {
  4036  	if b.BotAlias == "" {
  4037  		return b.BotUsername
  4038  	}
  4039  	return fmt.Sprintf("%s (%s)", b.BotAlias, b.BotUsername)
  4040  }
  4041  
  4042  func (b FeaturedBot) Owner() string {
  4043  	if b.OwnerTeam != nil {
  4044  		return *b.OwnerTeam
  4045  	}
  4046  	if b.OwnerUser != nil {
  4047  		return *b.OwnerUser
  4048  	}
  4049  	return ""
  4050  }
  4051  
  4052  func (b FeaturedBot) Eq(o FeaturedBot) bool {
  4053  	return b.BotAlias == o.BotAlias &&
  4054  		b.Description == o.Description &&
  4055  		b.ExtendedDescription == o.ExtendedDescription &&
  4056  		b.BotUsername == o.BotUsername &&
  4057  		b.Owner() == o.Owner()
  4058  }
  4059  
  4060  func (a SearchArg) String() string {
  4061  	// Don't leak user's query string
  4062  	return fmt.Sprintf("Limit: %d, Offset: %d", a.Limit, a.Offset)
  4063  }
  4064  func (a SearchLocalArg) String() string {
  4065  	// Don't leak user's query string
  4066  	return fmt.Sprintf("Limit: %d, SkipCache: %v", a.Limit, a.SkipCache)
  4067  }
  4068  
  4069  func (b FeaturedBotsRes) Eq(o FeaturedBotsRes) bool {
  4070  	if len(b.Bots) != len(o.Bots) {
  4071  		return false
  4072  	}
  4073  	for i, bot := range b.Bots {
  4074  		if !bot.Eq(o.Bots[i]) {
  4075  			return false
  4076  		}
  4077  	}
  4078  	return true
  4079  }
  4080  
  4081  // Redact modifies the given ClientDetails struct
  4082  func (d *ClientDetails) Redact() {
  4083  	tmp := fmt.Sprintf("%v", d.Argv)
  4084  	re := regexp.MustCompile(`\b(chat|fs|encrypt|git|accept-invite|wallet\s+send|wallet\s+import|passphrase\s+check)\b`)
  4085  	if mtch := re.FindString(tmp); len(mtch) > 0 {
  4086  		d.Argv = []string{d.Argv[0], mtch, redactedReplacer}
  4087  	}
  4088  
  4089  	for i, arg := range d.Argv {
  4090  		if strings.Contains(arg, "paperkey") && i+1 < len(d.Argv) && !strings.HasPrefix(d.Argv[i+1], "-") {
  4091  			d.Argv[i+1] = redactedReplacer
  4092  		}
  4093  	}
  4094  }
  4095  
  4096  func (s UserSummarySet) Usernames() (ret []string) {
  4097  	for _, x := range s.Users {
  4098  		ret = append(ret, x.Username)
  4099  	}
  4100  	return ret
  4101  }
  4102  
  4103  func (x InstrumentationStat) AppendStat(y InstrumentationStat) InstrumentationStat {
  4104  	x.Mtime = ToTime(time.Now())
  4105  	x.NumCalls += y.NumCalls
  4106  	x.TotalDur += y.TotalDur
  4107  	if y.MaxDur > x.MaxDur {
  4108  		x.MaxDur = y.MaxDur
  4109  	}
  4110  	if y.MinDur < x.MinDur {
  4111  		x.MinDur = y.MinDur
  4112  	}
  4113  
  4114  	x.TotalSize += y.TotalSize
  4115  	if y.MaxSize > x.MaxSize {
  4116  		x.MaxSize = y.MaxSize
  4117  	}
  4118  	if y.MinSize < x.MinSize {
  4119  		x.MinSize = y.MinSize
  4120  	}
  4121  
  4122  	x.AvgDur = x.TotalDur / DurationMsec(x.NumCalls)
  4123  	x.AvgSize = x.TotalSize / int64(x.NumCalls)
  4124  	return x
  4125  }
  4126  
  4127  func (e TeamSearchExport) Hash() string {
  4128  	l := make([]TeamSearchItem, 0, len(e.Items))
  4129  	for _, item := range e.Items {
  4130  		l = append(l, item)
  4131  	}
  4132  	sort.Slice(l, func(i, j int) bool {
  4133  		return l[i].Id.Less(l[j].Id)
  4134  	})
  4135  	hasher := sha256.New()
  4136  	for _, team := range l {
  4137  		log := math.Floor(math.Log10(float64(team.MemberCount)))
  4138  		rounder := int(math.Pow(10, log))
  4139  		value := (team.MemberCount / rounder) * rounder
  4140  		hasher.Write(team.Id.ToBytes())
  4141  		hasher.Write([]byte(fmt.Sprintf("%d", value)))
  4142  	}
  4143  	for _, id := range e.Suggested {
  4144  		hasher.Write(id.ToBytes())
  4145  	}
  4146  	return hex.EncodeToString(hasher.Sum(nil))
  4147  }
  4148  
  4149  // web-of-trust
  4150  // In order of descending quality.
  4151  // Keep in sync with:
  4152  // - server helpers/wot.ts
  4153  // - gui WebOfTrustVerificationType
  4154  const (
  4155  	UsernameVerificationType_IN_PERSON  = "in_person"
  4156  	UsernameVerificationType_VIDEO      = "video"
  4157  	UsernameVerificationType_AUDIO      = "audio"
  4158  	UsernameVerificationType_PROOFS     = "proofs"
  4159  	UsernameVerificationType_OTHER_CHAT = "other_chat"
  4160  	UsernameVerificationType_FAMILIAR   = "familiar"
  4161  	UsernameVerificationType_OTHER      = "other"
  4162  )
  4163  
  4164  var UsernameVerificationTypeMap = map[string]UsernameVerificationType{
  4165  	"in_person":  UsernameVerificationType_IN_PERSON,
  4166  	"proofs":     UsernameVerificationType_PROOFS,
  4167  	"video":      UsernameVerificationType_VIDEO,
  4168  	"audio":      UsernameVerificationType_AUDIO,
  4169  	"other_chat": UsernameVerificationType_OTHER_CHAT,
  4170  	"familiar":   UsernameVerificationType_FAMILIAR,
  4171  	"other":      UsernameVerificationType_OTHER,
  4172  }
  4173  
  4174  func (fsc FolderSyncConfig) Equal(other FolderSyncConfig) bool {
  4175  	if fsc.Mode != other.Mode {
  4176  		return false
  4177  	}
  4178  	if len(fsc.Paths) != len(other.Paths) {
  4179  		return false
  4180  	}
  4181  	for i, p := range fsc.Paths {
  4182  		if p != other.Paths[i] {
  4183  			return false
  4184  		}
  4185  	}
  4186  	return true
  4187  }
  4188  
  4189  func (t SeitanIKeyInvitelink) String() string {
  4190  	return string(t)
  4191  }
  4192  
  4193  // UserRolePairsHaveOwner check if a list of UserRolePair has user with role
  4194  // OWNER.
  4195  func UserRolePairsHaveOwner(users []UserRolePair) bool {
  4196  	for _, urp := range users {
  4197  		if urp.Role == TeamRole_OWNER {
  4198  			return true
  4199  		}
  4200  	}
  4201  	return false
  4202  }
  4203  
  4204  func (e EmailAddress) String() string {
  4205  	return string(e)
  4206  }
  4207  
  4208  func NewTeamSigMeta(sigMeta SignatureMetadata, uv UserVersion) TeamSignatureMetadata {
  4209  	return TeamSignatureMetadata{SigMeta: sigMeta, Uv: uv}
  4210  }
  4211  
  4212  func NewTeamInviteMetadata(invite TeamInvite, teamSigMeta TeamSignatureMetadata) TeamInviteMetadata {
  4213  	return TeamInviteMetadata{
  4214  		Invite:      invite,
  4215  		TeamSigMeta: teamSigMeta,
  4216  		Status:      NewTeamInviteMetadataStatusWithActive(),
  4217  	}
  4218  }
  4219  
  4220  func (a AnnotatedTeam) ToLegacyTeamDetails() TeamDetails {
  4221  	var members TeamMembersDetails
  4222  	for _, member := range a.Members {
  4223  		switch member.Role {
  4224  		case TeamRole_RESTRICTEDBOT:
  4225  			members.RestrictedBots = append(members.RestrictedBots, member)
  4226  		case TeamRole_BOT:
  4227  			members.Bots = append(members.Bots, member)
  4228  		case TeamRole_READER:
  4229  			members.Readers = append(members.Readers, member)
  4230  		case TeamRole_WRITER:
  4231  			members.Writers = append(members.Writers, member)
  4232  		case TeamRole_ADMIN:
  4233  			members.Admins = append(members.Admins, member)
  4234  		case TeamRole_OWNER:
  4235  			members.Owners = append(members.Owners, member)
  4236  		}
  4237  	}
  4238  
  4239  	annotatedActiveInvites := make(map[TeamInviteID]AnnotatedTeamInvite)
  4240  	for _, annotatedInvite := range a.Invites {
  4241  		code, _ := annotatedInvite.InviteMetadata.Status.Code()
  4242  		if code != TeamInviteMetadataStatusCode_ACTIVE {
  4243  			continue
  4244  		}
  4245  		annotatedActiveInvites[annotatedInvite.InviteMetadata.Invite.Id] = annotatedInvite
  4246  	}
  4247  
  4248  	return TeamDetails{
  4249  		Name:                   a.Name,
  4250  		Members:                members,
  4251  		KeyGeneration:          a.KeyGeneration,
  4252  		AnnotatedActiveInvites: annotatedActiveInvites,
  4253  		Settings:               a.Settings,
  4254  		Showcase:               a.Showcase,
  4255  	}
  4256  }