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 }