github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/zedtoken/zedtoken.go (about)

     1  // Package zedtoken converts decimal.Decimal to zedtoken and vice versa
     2  package zedtoken
     3  
     4  import (
     5  	"encoding/base64"
     6  	"errors"
     7  	"fmt"
     8  
     9  	v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
    10  
    11  	"github.com/authzed/spicedb/pkg/datastore"
    12  	zedtoken "github.com/authzed/spicedb/pkg/proto/impl/v1"
    13  )
    14  
    15  // Public facing errors
    16  const (
    17  	errEncodeError = "error encoding zedtoken: %w"
    18  	errDecodeError = "error decoding zedtoken: %w"
    19  )
    20  
    21  // ErrNilZedToken is returned as the base error when nil is provided as the
    22  // zedtoken argument to Decode
    23  var ErrNilZedToken = errors.New("zedtoken pointer was nil")
    24  
    25  // MustNewFromRevision generates an encoded zedtoken from an integral revision.
    26  func MustNewFromRevision(revision datastore.Revision) *v1.ZedToken {
    27  	encoded, err := NewFromRevision(revision)
    28  	if err != nil {
    29  		panic(err)
    30  	}
    31  	return encoded
    32  }
    33  
    34  // NewFromRevision generates an encoded zedtoken from an integral revision.
    35  func NewFromRevision(revision datastore.Revision) (*v1.ZedToken, error) {
    36  	toEncode := &zedtoken.DecodedZedToken{
    37  		VersionOneof: &zedtoken.DecodedZedToken_V1{
    38  			V1: &zedtoken.DecodedZedToken_V1ZedToken{
    39  				Revision: revision.String(),
    40  			},
    41  		},
    42  	}
    43  	encoded, err := Encode(toEncode)
    44  	if err != nil {
    45  		return nil, fmt.Errorf(errEncodeError, err)
    46  	}
    47  
    48  	return encoded, nil
    49  }
    50  
    51  // Encode converts a decoded zedtoken to its opaque version.
    52  func Encode(decoded *zedtoken.DecodedZedToken) (*v1.ZedToken, error) {
    53  	marshalled, err := decoded.MarshalVT()
    54  	if err != nil {
    55  		return nil, fmt.Errorf(errEncodeError, err)
    56  	}
    57  	return &v1.ZedToken{
    58  		Token: base64.StdEncoding.EncodeToString(marshalled),
    59  	}, nil
    60  }
    61  
    62  // Decode converts an encoded zedtoken to its decoded version.
    63  func Decode(encoded *v1.ZedToken) (*zedtoken.DecodedZedToken, error) {
    64  	if encoded == nil {
    65  		return nil, fmt.Errorf(errDecodeError, ErrNilZedToken)
    66  	}
    67  
    68  	decodedBytes, err := base64.StdEncoding.DecodeString(encoded.Token)
    69  	if err != nil {
    70  		return nil, fmt.Errorf(errDecodeError, err)
    71  	}
    72  	decoded := &zedtoken.DecodedZedToken{}
    73  	if err := decoded.UnmarshalVT(decodedBytes); err != nil {
    74  		return nil, fmt.Errorf(errDecodeError, err)
    75  	}
    76  	return decoded, nil
    77  }
    78  
    79  // DecodeRevision converts and extracts the revision from a zedtoken or legacy zookie.
    80  func DecodeRevision(encoded *v1.ZedToken, ds revisionDecoder) (datastore.Revision, error) {
    81  	decoded, err := Decode(encoded)
    82  	if err != nil {
    83  		return datastore.NoRevision, err
    84  	}
    85  
    86  	switch ver := decoded.VersionOneof.(type) {
    87  	case *zedtoken.DecodedZedToken_DeprecatedV1Zookie:
    88  		revString := fmt.Sprintf("%d", ver.DeprecatedV1Zookie.Revision)
    89  		parsed, err := ds.RevisionFromString(revString)
    90  		if err != nil {
    91  			return datastore.NoRevision, fmt.Errorf(errDecodeError, err)
    92  		}
    93  		return parsed, nil
    94  
    95  	case *zedtoken.DecodedZedToken_V1:
    96  		parsed, err := ds.RevisionFromString(ver.V1.Revision)
    97  		if err != nil {
    98  			return datastore.NoRevision, fmt.Errorf(errDecodeError, err)
    99  		}
   100  		return parsed, nil
   101  	default:
   102  		return datastore.NoRevision, fmt.Errorf(errDecodeError, fmt.Errorf("unknown zookie version: %T", decoded.VersionOneof))
   103  	}
   104  }
   105  
   106  type revisionDecoder interface {
   107  	RevisionFromString(string) (datastore.Revision, error)
   108  }