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 5package kbfsmd 6 7import ( 8 "encoding" 9 "encoding/hex" 10 "errors" 11 12 "github.com/keybase/client/go/kbfs/kbfscrypto" 13) 14 15const ( 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. 24type BranchID struct { 25 id [BranchIDByteLen]byte 26} 27 28var _ encoding.BinaryMarshaler = (*BranchID)(nil) 29var _ encoding.BinaryUnmarshaler = (*BranchID)(nil) 30 31// NullBranchID is an empty BranchID 32var 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. 36var 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. 40func (id BranchID) Bytes() []byte { 41 return id.id[:] 42} 43 44// String implements the Stringer interface for BranchID. 45func (id BranchID) String() string { 46 return hex.EncodeToString(id.id[:]) 47} 48 49// MarshalBinary implements the encoding.BinaryMarshaler interface for BranchID. 50func (id BranchID) MarshalBinary() (data []byte, err error) { 51 return id.id[:], nil 52} 53 54// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 55// for BranchID. 56func (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. 66func 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. 84func 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. 98func FakeBranchID(b byte) BranchID { 99 bytes := [BranchIDByteLen]byte{b} 100 return BranchID{bytes} 101} 102