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