github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/kbfsmd/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  
    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.
    17  type ID struct {
    18  	h kbfshash.Hash
    19  }
    20  
    21  var _ encoding.BinaryMarshaler = ID{}
    22  var _ encoding.BinaryUnmarshaler = (*ID)(nil)
    23  
    24  var _ encoding.TextMarshaler = ID{}
    25  var _ encoding.TextUnmarshaler = (*ID)(nil)
    26  
    27  // MakeID creates a new ID from the given RootMetadata object.
    28  func 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.
    50  func 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.
    60  func (id ID) Bytes() []byte {
    61  	return id.h.Bytes()
    62  }
    63  
    64  func (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.
    71  func (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.
    78  func (id *ID) UnmarshalBinary(data []byte) error {
    79  	return id.h.UnmarshalBinary(data)
    80  }
    81  
    82  // MarshalText implements the encoding.TextMarshaler interface for ID.
    83  func (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.
    93  func (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.
   103  func (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.
   109  func 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  }