github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/tlf/id.go (about)

     1  // Copyright 2016 Keybase Inc. All rights reserved.
     2  // Use of this source code is governed by a BSD
     3  // license that can be found in the LICENSE file.
     4  
     5  package tlf
     6  
     7  import (
     8  	"bytes"
     9  	"encoding"
    10  	"encoding/hex"
    11  	"fmt"
    12  	"strings"
    13  
    14  	"github.com/keybase/client/go/kbfs/kbfscrypto"
    15  	"github.com/keybase/client/go/protocol/keybase1"
    16  	"github.com/pkg/errors"
    17  )
    18  
    19  const (
    20  	// idByteLen is the number of bytes in a top-level folder ID
    21  	idByteLen = 16
    22  	// idSuffix is the last byte of a private top-level folder ID
    23  	idSuffix = 0x16
    24  	// pubIDSuffix is the last byte of a public top-level folder ID
    25  	pubIDSuffix = 0x17
    26  	// singleTeamIDSuffix is the last byte of a single-team top-level
    27  	// folder ID
    28  	singleTeamIDSuffix = 0x26
    29  )
    30  
    31  // Type is the type of TLF represented by a particular ID (e.g.,
    32  // public, private, etc.)
    33  type Type int
    34  
    35  const (
    36  	// Unknown is a placeholder type for when TLF type information is not
    37  	// available. It is the zero value of the type Type.
    38  	Unknown Type = iota
    39  	// Private represents a private TLF between one or more individual users.
    40  	Private
    41  	// Public represents a public TLF for one or more individual users.
    42  	Public
    43  	// SingleTeam represents a private TLF for a single Keybase team.
    44  	SingleTeam
    45  )
    46  
    47  const (
    48  	strPrivate    = "private"
    49  	strPublic     = "public"
    50  	strSingleTeam = "singleTeam"
    51  	strTeam       = "team"
    52  )
    53  
    54  func (t Type) String() string {
    55  	switch t {
    56  	case Private:
    57  		return strPrivate
    58  	case Public:
    59  		return strPublic
    60  	case SingleTeam:
    61  		return strSingleTeam
    62  	default:
    63  		return fmt.Sprintf("Unknown TLF type: %d", t)
    64  	}
    65  }
    66  
    67  // MarshalText implements the encoding.TextMarshaler interface for Type.
    68  func (t Type) MarshalText() ([]byte, error) {
    69  	return []byte(t.String()), nil
    70  }
    71  
    72  // PathString returns the string representation of t, when they are used in a
    73  // KBFS path. This is different from String() where this one returns 'team'
    74  // instead of 'singleTeam' for SingleTeam.
    75  func (t Type) PathString() string {
    76  	switch t {
    77  	case Private:
    78  		return strPrivate
    79  	case Public:
    80  		return strPublic
    81  	case SingleTeam:
    82  		return strTeam
    83  	default:
    84  		return fmt.Sprintf("Unknown TLF type: %d", t)
    85  	}
    86  }
    87  
    88  // FolderType returns the keybase1.FolderType corresponding to the
    89  // given TLF type.
    90  func (t Type) FolderType() keybase1.FolderType {
    91  	switch t {
    92  	case Private:
    93  		return keybase1.FolderType_PRIVATE
    94  	case Public:
    95  		return keybase1.FolderType_PUBLIC
    96  	case SingleTeam:
    97  		return keybase1.FolderType_TEAM
    98  	default:
    99  		return keybase1.FolderType_UNKNOWN
   100  	}
   101  }
   102  
   103  // ErrUnknownTLFType is returned by ParseTlfType when an unknown TLF type
   104  // string is provided.
   105  type ErrUnknownTLFType struct {
   106  	unknownType string
   107  }
   108  
   109  // Error implements the error interface.
   110  func (e ErrUnknownTLFType) Error() string {
   111  	return "unknown TLF type: " + e.unknownType
   112  }
   113  
   114  // ParseTlfTypeFromPath parses str into a Type.
   115  func ParseTlfTypeFromPath(str string) (Type, error) {
   116  	switch strings.ToLower(str) {
   117  	case strPrivate:
   118  		return Private, nil
   119  	case strPublic:
   120  		return Public, nil
   121  	case strTeam:
   122  		return SingleTeam, nil
   123  	default:
   124  		return Unknown, ErrUnknownTLFType{unknownType: str}
   125  	}
   126  }
   127  
   128  // TypeFromFolderType returns the Type corresponding to the given
   129  // keybase1.FolderType.
   130  func TypeFromFolderType(ft keybase1.FolderType) Type {
   131  	switch ft {
   132  	case keybase1.FolderType_PRIVATE:
   133  		return Private
   134  	case keybase1.FolderType_PUBLIC:
   135  		return Public
   136  	case keybase1.FolderType_TEAM:
   137  		return SingleTeam
   138  	default:
   139  		return Unknown
   140  	}
   141  }
   142  
   143  // KeyingType represents a TLF keying mode. It normally have the same values
   144  // as Type.
   145  type KeyingType Type
   146  
   147  const (
   148  	// UnknownKeying is a placeholder type for when TLF keying mode is unknown.
   149  	UnknownKeying = KeyingType(Unknown)
   150  	// PrivateKeying specifies the TLF keying mode used in classic private TLFs.
   151  	PrivateKeying = KeyingType(Private)
   152  	// PublicKeying specifies the TLF keying mode used in classic public TLFs.
   153  	PublicKeying = KeyingType(Public)
   154  	// TeamKeying specifies the TLF keying mode used for SingleTeam or
   155  	// implicit team backed TLFs.
   156  	TeamKeying = KeyingType(SingleTeam)
   157  )
   158  
   159  // ToKeyingType converts Type t into a KeyingType.
   160  func (t Type) ToKeyingType() KeyingType {
   161  	return KeyingType(t)
   162  }
   163  
   164  // String implements the fmt.Stringer interface.
   165  func (t KeyingType) String() string {
   166  	switch t {
   167  	case PrivateKeying:
   168  		return "private keying"
   169  	case PublicKeying:
   170  		return "public keying"
   171  	case TeamKeying:
   172  		return "team keying"
   173  	default:
   174  		return fmt.Sprintf("Unknown TLF keying type: %d", t)
   175  	}
   176  }
   177  
   178  // ID is a top-level folder ID
   179  type ID struct {
   180  	id [idByteLen]byte
   181  }
   182  
   183  var _ encoding.BinaryMarshaler = ID{}
   184  var _ encoding.BinaryUnmarshaler = (*ID)(nil)
   185  
   186  var _ encoding.TextMarshaler = ID{}
   187  var _ encoding.TextUnmarshaler = (*ID)(nil)
   188  
   189  // NullID is an empty ID
   190  var NullID = ID{}
   191  
   192  // Bytes returns the bytes of the TLF ID.
   193  func (id ID) Bytes() []byte {
   194  	return id.id[:]
   195  }
   196  
   197  // String implements the fmt.Stringer interface for ID.
   198  func (id ID) String() string {
   199  	return hex.EncodeToString(id.id[:])
   200  }
   201  
   202  // MarshalBinary implements the encoding.BinaryMarshaler interface for ID.
   203  func (id ID) MarshalBinary() (data []byte, err error) {
   204  	suffix := id.id[idByteLen-1]
   205  	if suffix != idSuffix && suffix != pubIDSuffix &&
   206  		suffix != singleTeamIDSuffix {
   207  		return nil, errors.WithStack(InvalidIDError{id.String()})
   208  	}
   209  	return id.id[:], nil
   210  }
   211  
   212  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
   213  // for ID.
   214  func (id *ID) UnmarshalBinary(data []byte) error {
   215  	if len(data) != idByteLen {
   216  		return errors.WithStack(
   217  			InvalidIDError{hex.EncodeToString(data)})
   218  	}
   219  	suffix := data[idByteLen-1]
   220  	if suffix != idSuffix && suffix != pubIDSuffix &&
   221  		suffix != singleTeamIDSuffix {
   222  		return errors.WithStack(
   223  			InvalidIDError{hex.EncodeToString(data)})
   224  	}
   225  	copy(id.id[:], data)
   226  	return nil
   227  }
   228  
   229  // MarshalText implements the encoding.TextMarshaler interface for ID.
   230  func (id ID) MarshalText() ([]byte, error) {
   231  	bytes, err := id.MarshalBinary()
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  	return []byte(hex.EncodeToString(bytes)), nil
   236  }
   237  
   238  // UnmarshalText implements the encoding.TextUnmarshaler interface for
   239  // ID.
   240  func (id *ID) UnmarshalText(buf []byte) error {
   241  	s := string(buf)
   242  	bytes, err := hex.DecodeString(s)
   243  	if err != nil {
   244  		return errors.WithStack(InvalidIDError{s})
   245  	}
   246  	return id.UnmarshalBinary(bytes)
   247  }
   248  
   249  // SafeType returns the type of TLF represented by this ID.  If the ID
   250  // isn't valid, it returns tlf.Unknown along with an error.
   251  func (id ID) SafeType() (Type, error) {
   252  	switch id.id[idByteLen-1] {
   253  	case idSuffix:
   254  		return Private, nil
   255  	case pubIDSuffix:
   256  		return Public, nil
   257  	case singleTeamIDSuffix:
   258  		return SingleTeam, nil
   259  	default:
   260  		return Unknown, fmt.Errorf("Unknown ID suffix  %x", id.id[idByteLen-1])
   261  	}
   262  }
   263  
   264  // Type returns the type of TLF represented by this ID.
   265  //
   266  // Note that this function panics if the ID suffix is unknown, rather than
   267  // returning tlf.Unknown.
   268  func (id ID) Type() Type {
   269  	t, err := id.SafeType()
   270  	if err != nil {
   271  		panic(err)
   272  	}
   273  	return t
   274  }
   275  
   276  // ParseID parses a hex encoded ID. Returns NullID and an
   277  // InvalidIDError on failure.
   278  func ParseID(s string) (ID, error) {
   279  	var id ID
   280  	err := id.UnmarshalText([]byte(s))
   281  	if err != nil {
   282  		return ID{}, err
   283  	}
   284  	return id, nil
   285  }
   286  
   287  // MakeRandomID makes a random ID using a cryptographically secure
   288  // RNG. Returns NullID on failure.
   289  func MakeRandomID(t Type) (ID, error) {
   290  	var idBytes [idByteLen]byte
   291  	err := kbfscrypto.RandRead(idBytes[:])
   292  	if err != nil {
   293  		return NullID, err
   294  	}
   295  	switch t {
   296  	case Private:
   297  		idBytes[idByteLen-1] = idSuffix
   298  	case Public:
   299  		idBytes[idByteLen-1] = pubIDSuffix
   300  	case SingleTeam:
   301  		idBytes[idByteLen-1] = singleTeamIDSuffix
   302  	default:
   303  		panic(fmt.Sprintf("Unknown TLF type %d", t))
   304  	}
   305  	var id ID
   306  	err = id.UnmarshalBinary(idBytes[:])
   307  	if err != nil {
   308  		return NullID, err
   309  	}
   310  	return id, nil
   311  }
   312  
   313  // MakeIDFromTeam makes a deterministic TLF ID from a team ID and an epoch
   314  // representing how many times a new TLF has been needed for this
   315  // team.  Returns NullID on failure.
   316  func MakeIDFromTeam(t Type, tid keybase1.TeamID, epoch byte) (ID, error) {
   317  	idBytes := tid.ToBytes()
   318  	if len(idBytes) != idByteLen {
   319  		return NullID, errors.Errorf(
   320  			"The length of team ID %s doesn't match that of a TLF ID", tid)
   321  	}
   322  
   323  	idBytes[idByteLen-2] = epoch
   324  
   325  	switch t {
   326  	case Private:
   327  		if tid.IsPublic() {
   328  			return NullID, errors.Errorf(
   329  				"Cannot make a private TLF for a public team ID %s", tid)
   330  		}
   331  		idBytes[idByteLen-1] = idSuffix
   332  	case Public:
   333  		if !tid.IsPublic() {
   334  			return NullID, errors.Errorf(
   335  				"Cannot make a public TLF for a private team ID %s", tid)
   336  		}
   337  		idBytes[idByteLen-1] = pubIDSuffix
   338  	case SingleTeam:
   339  		if tid.IsPublic() {
   340  			return NullID, errors.Errorf(
   341  				"Cannot make a single-team TLF for a public team ID %s", tid)
   342  		}
   343  		idBytes[idByteLen-1] = singleTeamIDSuffix
   344  	default:
   345  		panic(fmt.Sprintf("Unknown TLF type %d", t))
   346  	}
   347  	var id ID
   348  	err := id.UnmarshalBinary(idBytes)
   349  	if err != nil {
   350  		return NullID, err
   351  	}
   352  	return id, nil
   353  }
   354  
   355  // GetEpochFromTeamTLF returns 1) whether this ID matches the given
   356  // team TID, and 2) if so, which epoch it is.
   357  func (id ID) GetEpochFromTeamTLF(tid keybase1.TeamID) (
   358  	matches bool, epoch byte, err error) {
   359  	tidBytes := tid.ToBytes()
   360  	if len(tidBytes) != idByteLen {
   361  		return false, 0, errors.Errorf(
   362  			"The length of team ID %s doesn't match that of a TLF ID", tid)
   363  	}
   364  
   365  	epochIndex := idByteLen - 2
   366  	if !bytes.Equal(tidBytes[:epochIndex], id.id[:epochIndex]) {
   367  		return false, 0, nil
   368  	}
   369  
   370  	return true, id.id[epochIndex], nil
   371  }