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 11 "github.com/keybase/client/go/kbfs/kbfscodec" 12 "github.com/keybase/client/go/kbfs/kbfshash" 13 "github.com/pkg/errors" 14) 15 16// ID is the content-based ID for a metadata block. 17type ID struct { 18 h kbfshash.Hash 19} 20 21var _ encoding.BinaryMarshaler = ID{} 22var _ encoding.BinaryUnmarshaler = (*ID)(nil) 23 24var _ encoding.TextMarshaler = ID{} 25var _ encoding.TextUnmarshaler = (*ID)(nil) 26 27// MakeID creates a new ID from the given RootMetadata object. 28func MakeID(codec kbfscodec.Codec, md RootMetadata) (ID, error) { 29 // Make sure that the serialized metadata is set; otherwise we 30 // won't get the right ID. 31 if md.GetSerializedPrivateMetadata() == nil { 32 return ID{}, errors.WithStack(MissingDataError{md.TlfID()}) 33 } 34 35 buf, err := codec.Encode(md) 36 if err != nil { 37 return ID{}, err 38 } 39 40 h, err := kbfshash.DefaultHash(buf) 41 if err != nil { 42 return ID{}, err 43 } 44 45 return ID{h}, nil 46} 47 48// FakeID returns an ID derived from the given byte, suitable for 49// testing. 50func FakeID(b byte) ID { 51 dh := kbfshash.RawDefaultHash{b} 52 h, err := kbfshash.HashFromRaw(kbfshash.DefaultHashType, dh[:]) 53 if err != nil { 54 panic(err) 55 } 56 return ID{h} 57} 58 59// Bytes returns the bytes of the MDID. 60func (id ID) Bytes() []byte { 61 return id.h.Bytes() 62} 63 64func (id ID) String() string { 65 return id.h.String() 66} 67 68// MarshalBinary implements the encoding.BinaryMarshaler interface for 69// ID. Returns an error if the ID is invalid and not the zero 70// ID. 71func (id ID) MarshalBinary() (data []byte, err error) { 72 return id.h.MarshalBinary() 73} 74 75// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 76// for ID. Returns an error if the given byte array is non-empty and 77// the ID is invalid. 78func (id *ID) UnmarshalBinary(data []byte) error { 79 return id.h.UnmarshalBinary(data) 80} 81 82// MarshalText implements the encoding.TextMarshaler interface for ID. 83func (id ID) MarshalText() ([]byte, error) { 84 bytes, err := id.MarshalBinary() 85 if err != nil { 86 return nil, err 87 } 88 return []byte(hex.EncodeToString(bytes)), nil 89} 90 91// UnmarshalText implements the encoding.TextUnmarshaler interface for 92// ID. 93func (id *ID) UnmarshalText(buf []byte) error { 94 s := string(buf) 95 bytes, err := hex.DecodeString(s) 96 if err != nil { 97 return errors.WithStack(InvalidIDError{s}) 98 } 99 return id.UnmarshalBinary(bytes) 100} 101 102// IsValid returns whether the ID is valid. 103func (id ID) IsValid() bool { 104 return id.h.IsValid() 105} 106 107// ParseID parses a hex encoded ID. Returns ID{} and an InvalidIDError 108// on failure. 109func ParseID(s string) (ID, error) { 110 var id ID 111 err := id.UnmarshalText([]byte(s)) 112 if err != nil { 113 return ID{}, err 114 } 115 return id, nil 116} 117