github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/kbfsmd/branch_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 kbfsmd
     6  
     7  import (
     8  	"encoding"
     9  	"encoding/hex"
    10  	"errors"
    11  
    12  	"github.com/keybase/client/go/kbfs/kbfscrypto"
    13  )
    14  
    15  const (
    16  	// BranchIDByteLen is the number of bytes in a per-device per-TLF branch ID.
    17  	BranchIDByteLen = 16
    18  	// BranchIDStringLen is the number of characters in the string
    19  	// representation of a per-device per-TLF branch ID.
    20  	BranchIDStringLen = 2 * BranchIDByteLen
    21  )
    22  
    23  // BranchID encapsulates a per-device per-TLF branch ID.
    24  type BranchID struct {
    25  	id [BranchIDByteLen]byte
    26  }
    27  
    28  var _ encoding.BinaryMarshaler = (*BranchID)(nil)
    29  var _ encoding.BinaryUnmarshaler = (*BranchID)(nil)
    30  
    31  // NullBranchID is an empty BranchID
    32  var NullBranchID = BranchID{}
    33  
    34  // PendingLocalSquashBranchID indicates a local branch that is not in known
    35  // conflict with the master branch, but just needs to be squashed locally.
    36  var PendingLocalSquashBranchID = BranchID{
    37  	[BranchIDByteLen]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}
    38  
    39  // Bytes returns the bytes of the BranchID.
    40  func (id BranchID) Bytes() []byte {
    41  	return id.id[:]
    42  }
    43  
    44  // String implements the Stringer interface for BranchID.
    45  func (id BranchID) String() string {
    46  	return hex.EncodeToString(id.id[:])
    47  }
    48  
    49  // MarshalBinary implements the encoding.BinaryMarshaler interface for BranchID.
    50  func (id BranchID) MarshalBinary() (data []byte, err error) {
    51  	return id.id[:], nil
    52  }
    53  
    54  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
    55  // for BranchID.
    56  func (id *BranchID) UnmarshalBinary(data []byte) error {
    57  	if len(data) != BranchIDByteLen {
    58  		return errors.New("invalid BranchID")
    59  	}
    60  	copy(id.id[:], data)
    61  	return nil
    62  }
    63  
    64  // ParseBranchID parses a hex encoded BranchID. Returns NullBranchID
    65  // and an InvalidBranchID on falire.
    66  func ParseBranchID(s string) (BranchID, error) {
    67  	if len(s) != BranchIDStringLen {
    68  		return NullBranchID, InvalidBranchID{s}
    69  	}
    70  	bytes, err := hex.DecodeString(s)
    71  	if err != nil {
    72  		return NullBranchID, InvalidBranchID{s}
    73  	}
    74  	var id BranchID
    75  	err = id.UnmarshalBinary(bytes)
    76  	if err != nil {
    77  		return NullBranchID, InvalidBranchID{s}
    78  	}
    79  	return id, nil
    80  }
    81  
    82  // MakeRandomBranchID generates a per-device branch ID using a CSPRNG.
    83  // It will not return LocalSquashBranchID or NullBranchID.
    84  func MakeRandomBranchID() (BranchID, error) {
    85  	var id BranchID
    86  	// Loop just in case we randomly pick the null or local squash
    87  	// branch IDs.
    88  	for id == NullBranchID || id == PendingLocalSquashBranchID {
    89  		err := kbfscrypto.RandRead(id.id[:])
    90  		if err != nil {
    91  			return BranchID{}, err
    92  		}
    93  	}
    94  	return id, nil
    95  }
    96  
    97  // FakeBranchID creates a fake branch ID from the given byte.
    98  func FakeBranchID(b byte) BranchID {
    99  	bytes := [BranchIDByteLen]byte{b}
   100  	return BranchID{bytes}
   101  }