summaryrefslogtreecommitdiff
path: root/vendor/github.com/authzed/spicedb/pkg/zedtoken/zedtoken.go
blob: 7cefa1b816de4008e56283b97a31ca7735ab24c4 (plain)
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
102
103
104
105
106
107
package zedtoken

import (
	"encoding/base64"
	"errors"
	"fmt"

	v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"

	"github.com/authzed/spicedb/pkg/datastore"
	zedtoken "github.com/authzed/spicedb/pkg/proto/impl/v1"
)

// Public facing errors
const (
	errEncodeError = "error encoding zedtoken: %w"
	errDecodeError = "error decoding zedtoken: %w"
)

// ErrNilZedToken is returned as the base error when nil is provided as the
// zedtoken argument to Decode
var ErrNilZedToken = errors.New("zedtoken pointer was nil")

// MustNewFromRevision generates an encoded zedtoken from an integral revision.
func MustNewFromRevision(revision datastore.Revision) *v1.ZedToken {
	encoded, err := NewFromRevision(revision)
	if err != nil {
		panic(err)
	}
	return encoded
}

// NewFromRevision generates an encoded zedtoken from an integral revision.
func NewFromRevision(revision datastore.Revision) (*v1.ZedToken, error) {
	toEncode := &zedtoken.DecodedZedToken{
		VersionOneof: &zedtoken.DecodedZedToken_V1{
			V1: &zedtoken.DecodedZedToken_V1ZedToken{
				Revision: revision.String(),
			},
		},
	}
	encoded, err := Encode(toEncode)
	if err != nil {
		return nil, fmt.Errorf(errEncodeError, err)
	}

	return encoded, nil
}

// Encode converts a decoded zedtoken to its opaque version.
func Encode(decoded *zedtoken.DecodedZedToken) (*v1.ZedToken, error) {
	marshalled, err := decoded.MarshalVT()
	if err != nil {
		return nil, fmt.Errorf(errEncodeError, err)
	}
	return &v1.ZedToken{
		Token: base64.StdEncoding.EncodeToString(marshalled),
	}, nil
}

// Decode converts an encoded zedtoken to its decoded version.
func Decode(encoded *v1.ZedToken) (*zedtoken.DecodedZedToken, error) {
	if encoded == nil {
		return nil, fmt.Errorf(errDecodeError, ErrNilZedToken)
	}

	decodedBytes, err := base64.StdEncoding.DecodeString(encoded.Token)
	if err != nil {
		return nil, fmt.Errorf(errDecodeError, err)
	}
	decoded := &zedtoken.DecodedZedToken{}
	if err := decoded.UnmarshalVT(decodedBytes); err != nil {
		return nil, fmt.Errorf(errDecodeError, err)
	}
	return decoded, nil
}

// DecodeRevision converts and extracts the revision from a zedtoken or legacy zookie.
func DecodeRevision(encoded *v1.ZedToken, ds revisionDecoder) (datastore.Revision, error) {
	decoded, err := Decode(encoded)
	if err != nil {
		return datastore.NoRevision, err
	}

	switch ver := decoded.VersionOneof.(type) {
	case *zedtoken.DecodedZedToken_DeprecatedV1Zookie:
		revString := fmt.Sprintf("%d", ver.DeprecatedV1Zookie.Revision)
		parsed, err := ds.RevisionFromString(revString)
		if err != nil {
			return datastore.NoRevision, fmt.Errorf(errDecodeError, err)
		}
		return parsed, nil

	case *zedtoken.DecodedZedToken_V1:
		parsed, err := ds.RevisionFromString(ver.V1.Revision)
		if err != nil {
			return datastore.NoRevision, fmt.Errorf(errDecodeError, err)
		}
		return parsed, nil
	default:
		return datastore.NoRevision, fmt.Errorf(errDecodeError, fmt.Errorf("unknown zookie version: %T", decoded.VersionOneof))
	}
}

type revisionDecoder interface {
	RevisionFromString(string) (datastore.Revision, error)
}